close

How I work

What my day-to-day would look like on your team.

A CV says what someone shipped. It doesn't say how. This page answers that.

Getting into code I don't know

I start by walking through it, not by reading it.

In the first days on an unfamiliar codebase, I don't read at random. I pick a feature I can run and follow it end to end: the route, the controller, the model, the query, the render. One complete pass teaches more than ten files skimmed.

Then I look for where the code hurts, by reading the history rather than the code. The most-changed files are the ones the team dreads: those are the ones to understand first, and the ones to move through slowly.

My first contribution is deliberately small, because a small pull request validates everything else: that I understood the conventions, that I can run the tests, that deployment goes through. Only then do I take on larger work.

And I don't rewrite what I don't yet understand. An odd line often has a reason that is no longer in the code but in someone's head. I ask before deleting.

Looking for a cause, not a culprit

I state the method before writing a line.

Faced with a slowdown or an inexplicable behaviour, I first write down how I'm going to look: what I instrument, what I compare, and what would confirm or rule out the hypothesis. It costs ten minutes, and it stops me chasing the first plausible lead. A hypothesis is not a finding.

Two weeks after joining, on my own initiative: of the forty-four seconds an export took, more than 42 were spent in the application, before the call to the service that itself took just over a second. Cascading queries fixed.

Later, on a slowdown affecting the largest accounts, picked up from scratch: instrumentation on both sides, then isolating the bottleneck by comparing three account sizes. The trade-off: fix the cascading queries rather than put a cache on top. The backend fix shipped to production, along with a survey of the other entry points exposed to the same flaw.

The best outcome of that work isn't a fix, it's a change of subject: a display defect turned out to be a business rule being bypassed, and the decisive argument fitted in one sentence: no screen in the application lets you create that state by hand. The decision moved up a level. And when I dig and I was wrong, I correct my hypothesis where I published it: that's what separates what belongs to the product from what belongs to the configuration.

Working with agents

I treat them as untrusted code: closed scope, verified output.

I use assistant tools daily, and I've built some. The most complete is a read-only monitoring agent: it cross-references technical discussions with a skills map derived from my own git history, finds the answer in the source, and produces a sourced draft I approve or reject. Out of two hundred and three threads analysed, I keep 9.4%: most of the work is what I throw away.

What interests me in these tools isn't the speed gain, it's how you contain them. On that agent: an allowlist of twelve read tools against a denylist of fifteen write tools, enforced at process launch - it physically cannot send a message or write a file. An anti-injection section in the prompt. A mandatory adversarial pass before every output.

On another tool, a review-material generator, the rule is that no code block ships unless it comes from the real diff, and a validator blocks rendering until it passes.

The principle is the same as for a third-party dependency: you don't trust it, you contain it. That's what lets you move fast without bringing code nobody has read into the repository.

My pull requests

Short, single-purpose, and the description says why.

I ship small and often: my pull requests are two to five files at the median. A PR that touches three subjects doesn't get reviewed, it gets approved out of fatigue. I'd rather open three.

I break a large piece of work into readable steps: the helper, then the interface, then wiring the data, then the tests.

The description says what changes and why, not what the diff already shows. If there's a debatable decision, I write it in the PR rather than waiting for someone to find it.

From a review, I want the decisions discussed, not the syntax: formatting is a tool's job, not a reviewer's.

And I review roughly twice as many pull requests as I open. That's where you learn a codebase, and where you're useful to a team.

Tests

I test what breaks: business logic and risky areas.

I systematically test pure logic and risky areas: my helpers, hooks and transformations ship with their test file alongside. On the back end, I cover controllers, jobs and exporters.

I put the effort where it pays: edge cases and critical paths are covered. For purely visual components I lean on interactive documentation, which catches an interface regression better than a test frozen on last month's mockup.

And I align with the testing strategy of the team I join: its definition of done becomes mine from the first pull request.

Before writing code

If I can't describe the outcome in one sentence, it isn't ready to be built.

Before writing code, I check that I can describe the expected outcome in one sentence. If I can't, it isn't ready to be built - it's ready to be discussed.

That doesn't mean specifying everything. It means not starting with the easy part and hoping the rest becomes clear along the way.

Shipping to production

Three environments, nothing moves without review, and I watch afterwards.

Dev, staging, production, and nothing moves without a pull request. CI runs on every PR: if it's red, nothing advances.

After a release, I watch. Errors, response times, the path I just touched. A deployment isn't done when the pipeline is green, it's done when nothing moved in the metrics.

Communicating

When a topic dies for lack of the right audience, I carry it elsewhere.

I flag a blocker early and in writing, not at the tipping point. An estimate that slips gets said the day I see it, not the day it's due.

When a spec is vague, I don't guess and I don't wait either: I write down the interpretation I'm going to follow and get it confirmed in one line. It costs two minutes and saves redoing a week.

And when a topic dies because it wasn't raised in the right place, I move it. I once raised publicly a problem many were quietly living with; a lead replied that design needed to weigh in. Rather than let the thread die, I reframed it in the product channel with a message suited to that audience. The same day, another developer opened the pull request.

If you want to dig into any of these points, that's exactly what I'd like to talk about in an interview.

Back to home