Emmanuel Bett, engineer
Home

The method

How I work when nobody is checking

This is a process rather than a personality trait, which is the point: it is written down, so it travels to a stack I have not used yet.

Most of what I have built was built in a small team where the review that catches a mistake is not guaranteed to arrive. That constraint shaped every step below. When there may be nobody to catch it, the process has to do the job a second pair of eyes would have done.

Six steps, in order. The order carries more weight than any single step, because most of the failures below come from doing the right thing at the wrong point.

  1. 01

    Read the data before the code

    I start at the schema and a few real rows, not at the controller. What the table actually contains tells me what the system believes, and that is usually different from what the code implies it believes.

    This is the habit that came from data work, and it is the one that has saved me the most time. Most bugs I have chased were a wrong assumption about the shape of the data, held confidently by everyone.

  2. 02

    Reproduce it before I touch anything

    A bug I cannot trigger on demand is a bug I cannot prove I fixed. I get to a reliable reproduction first, even when that takes longer than the fix will.

    Skipping this is how you ship a change that correlates with the symptom disappearing and get the same ticket back in three weeks.

  3. 03

    Write the failing test first

    The test goes in before the fix and I watch it fail. If it passes against the broken code it is testing something other than what I think, and I would rather find that out now than trust it later.

    PHPUnit for the unit and integration layer, Cypress for the paths a user actually walks. The end to end tests are the ones that catch the failures fixtures are too kind to produce.

  4. 04

    Measure before optimising

    Slow gets explained before it gets rewritten. Query plan, index usage, N+1 counts, response timings under something like real load. Then I change one thing and measure again.

    On the tenders portal the answer was usually an index or a cache, not an architecture. Rewriting first would have cost weeks and moved nothing.

  5. 05

    Follow the standard, even when mine is nicer

    SOLID and the PSR conventions in PHP, the framework's idiom in Vue. Consistency across the codebase beats local elegance, because the next person reading it is optimising for recognition rather than admiration.

    The exception is when the standard is actively wrong for the case. Then it gets broken deliberately and the reason gets written next to it.

  6. 06

    Leave it explainable

    Work ends when someone else could pick it up: what the decision was, what I tried that did not work, and where the traps are. Not a description of the code, which they can read.

    I write this for myself six months out as much as for anybody else, because by then I have forgotten every constraint that made the obvious approach wrong.

Worked example

The dashboard was slow, and the profiler pointed at the wrong thing

A listing screen took several seconds to paint. The obvious suspect was the volume of records, and the obvious fix was pagination, which had already been tried and had not helped enough to notice.

Read the data before the code. I ran the page with query logging on and counted, rather than reasoning about what the ORM ought to be doing. One request was issuing hundreds of queries: a relationship was being resolved per row inside the render loop, so every row the page displayed cost a round trip.

Measure before optimising. Eager loading the relationship collapsed the query count to a handful and the page returned in a fraction of the time. No architecture changed, no cache was added, and the pagination that had been blamed was never the problem.

Leave it explainable. The lasting fix was not the eager load, it was writing down that a query count is a thing to check on any list view, because the code reads identically whether it issues two queries or two hundred.

What this shows: the profiler said the page was slow, which everyone already knew. Counting the queries said why. The gap between those two is the part worth hiring for.

Working with AI

I use it daily, and it makes the steps above matter more

These tools are part of my routine. They have not replaced anything on this page, they have raised the cost of skipping it, because they increase two things at once: how much code I can produce, and how convincing that code looks when it is wrong.

So the rule is the same rule, applied to more material: I do not ship what I could not have written myself and cannot explain line by line. I am the one who gets called when it breaks at an inconvenient hour.

Where I let it work

  • Getting oriented in an unfamiliar codebase quickly, to find where to look rather than to be told the answer.
  • Boilerplate I have written many times: migrations, factories, test scaffolding, form validation.
  • Arguing against a design before I commit to it, which is the nearest thing to a second opinion when working alone.
  • The tedious test I was tempted to skip. This one is a real gain in quality.

Where I do not

  • Anything touching money, permissions or tenant data goes through the same verification as if I had typed it, because it did not know it was guessing.
  • A claim about how the system behaves. That gets checked against the actual output, every time.
  • A number. It will give me one, confidently, and it will be wrong in a way that reads as correct.
  • The decision itself. It argues either side equally well, which makes it useless as the thing that decides.

Questions

The ones people actually ask

What happens when you are handed a system you have never seen?
I go to the database first and read the schema and some real rows, then find the entry point for one feature and follow it end to end. Two hours of that answers more than a week of reading files in alphabetical order. Then I pick the smallest real ticket and ship it, because nothing exposes what you have misunderstood faster than trying to change something.
You work in Laravel and Vue. What if my stack is different?
The loop does not change: read the data, reproduce it, write the failing test, measure before rewriting. Syntax is the fastest part to pick up and the smallest part of the problem. What transfers is knowing what to be suspicious of, and an N+1 query looks the same in Django as it does in Laravel.
How does the data background actually help?
It changes where I look first. Cleaning datasets and building forecasts teaches you that the data is almost never shaped the way the documentation says, and that a confident average can hide the case that is actually hurting people. I bring both of those instincts to application work.
What do you do about testing when the deadline is real?
The end to end test for the path that loses money or blocks a user stays, and it is non-negotiable. What gets deferred is breadth: exhaustive unit coverage of code that is not load bearing yet. I would rather have four tests that would genuinely fail than a coverage number.
Do you use AI to write code?
Daily, and it has made the process on this page more necessary rather than less. These tools raise both output volume and how plausible that output looks when wrong, which are exactly the conditions where unverified work does damage. Same verification, more material. I do not ship what I could not have written myself.

This is the part that transfers

The frameworks on my CV are the smallest thing you would be hiring. The loop above works the same whether the code is Laravel, Django or something I have never opened.