Skip to content
← All writing

The job was never the code

6 min read
.md
Cover illustration for The job was never the code

Coding was the medium, not the work. The work was deciding what to build, how it should fail, and what happens at scale. Agents handle the medium well and the judgement badly, which is why an experienced engineer directing one beats a beginner prompting the same tool.

I opened a pull request last week for a rate limiter. Fifteen files, tests, the lot. I typed almost none of it.

Ten years ago that sentence would have embarrassed me. The typing was the craft. You learned the language, you learned the framework, you got fast, and being fast was most of what made you good.

Then I looked at what I actually spent that day doing. Deciding the limiter belonged at the tenant boundary and not the route. Working out what happens when the counter store is briefly unavailable, and choosing to fail open because a locked-out paying customer is worse than a few free requests. Writing down the invariant that made the whole thing safe.

The agent wrote every line. I made every decision that mattered.

Nobody is typing much any more

This is not a prediction. Stack Overflow’s 2025 developer survey put AI tool use among professional developers well past the point where it is a minority habit, and the tooling has moved on twice since then. Agents like Claude Code do not autocomplete a line; they read the repository, plan, edit across files and run the tests.

My own split is roughly ninety per cent agent-written by volume. What went up was not my typing speed. It was the number of problems I could carry at once.

And there is a wrinkle worth sitting with. METR ran a randomised trial with experienced open source maintainers on their own repositories and found them 19% slower with AI tools, while the same developers believed they had been faster. If your mental model is “AI types for me so I finish sooner”, the evidence does not back you up.

The gain shows up somewhere else. Not in finishing one task faster, but in how many things you can hold, and how much of your attention is left for the parts a model cannot do.

What was the job, before we called it coding?

Think about what you were actually paid for on your best day.

Not the syntax. Someone described a problem badly, you asked the question that reframed it, and the feature turned out to be a third of the size everyone assumed. Or a system fell over at 3am and you found the cause in twenty minutes because you knew where the seams were.

Neither of those is typing. Both of them are the job.

Code was always the medium, the way a manuscript is the medium of a novel. Nobody thinks a novelist’s skill lives in their handwriting. We confused the two in software because for forty years the medium was expensive enough to be a real constraint. You could not test an idea without paying for the implementation, so the ability to pay quickly looked like the skill itself.

The implementation got cheap. What was underneath is still there, and it is now most of what separates one engineer from another.

The race

Here is the thought experiment I keep coming back to, because it settles the vibe coding argument faster than any principle.

Two people get the same brief: build a booking system for a clinic. Same agent, same model, same week. One has shipped software for a decade. The other has never worked in a codebase and is going to describe what they want and accept whatever comes back, which is roughly what Andrej Karpathy meant when he coined vibe coding: forget the code exists, and go with the vibes.

On Friday, both demos work. Both book appointments. The vibe-coded one might look better, because that person spent their time on the interface while the engineer was busy with things you cannot see.

Now you are the clinic owner and you have to pick one. So ask a different set of questions.

What you should askWhere the answers diverge
What happens when two receptionists book the same slot at the same moment?One has a uniqueness constraint and a tested race. The other has never seen the race, because it does not happen when one person clicks slowly
Where are patient records stored, and who can read them?One knows, and can show you. The other knows what the agent chose
It is Sunday and bookings are failing. What now?One reads the trace. The other opens a chat window and starts describing the symptom
We want SMS reminders next month. How long?One knows what it touches. The other finds out by trying

Not one of those questions is about code quality. They are all about whether a person understands the thing they handed you.

That is what you are buying when you hire an engineer, and it is exactly what vibe coding skips. The research bears it out: a study of how experience shapes AI-assisted practice found that experienced developers verify continuously while beginners accept and move on, and work separating vibe coding from agentic engineering puts the distinction in the same place. It is not the tool. It is whether anyone is checking.

The distinction that actually matters

Two people can use the identical agent and be doing unrelated jobs.

Vibe coding is describing an outcome and accepting the result. Agentic engineering is directing a tool while keeping the architecture, the failure modes and the responsibility. A 2025 study of professional practice found professionals overwhelmingly in the second camp, and the title said it plainly: they do not vibe, they control.

The difference shows up in what happens when something is wrong. If the answer is always “describe the symptom to the model again”, nobody owns the system. And ownership is not a moral position. It is the practical ability to fix a thing on a Sunday.

I am not against beginners using these tools. They are the best learning environment we have ever had, if you read what comes back and ask why. The failure mode is not being new. It is shipping something to other people while nobody has ever understood it.

What I do now instead

Roughly in order of how much time each takes.

  1. Decide what to build, and more often what not to. The agent has no opinion on whether the feature should exist.
  2. Set the boundaries. Where does state live, what is the unit of consistency, which parts are allowed to fail. Get this wrong and no amount of clean code saves you.
  3. Name the failure modes before writing anything. What breaks under load, what happens on a partial write, what a retry does twice.
  4. Read everything that comes back. Not skim. This is the step people drop first and it is the one that makes the rest true.
  5. Write the tests that encode the invariants, because those are the sentences the next person will trust when they change it.

Step four is where the discipline lives. It is also where the METR result stops being surprising. Reviewing carefully is slower than typing confidently, and it is the difference between software you can stand behind and software you are merely holding.

The typing is over. I do not miss it. The part I liked was always the other part, and there is more room for it now than there has ever been.

Sources

Written by Elson Tan, Head of Technology and co-founder at Nedex Group, working on AI harness and agent infrastructure.

AboutRSS
  • 4 min read

    One Durable Object per agent

    Why I gave every AI agent its own Durable Object with a SQLite task ledger, and what that bought in state, concurrency and debuggability.

  • 4 min read

    Sandboxing code an agent wrote for you

    Once an agent writes and runs code, you are executing untrusted input on your infrastructure. The isolation question has known answers. The harder problems are quotas, cancellation and getting results out.

  • 4 min read

    Metering tokens when the bill is the product

    Billing per message is easy and wrong: one user sends a sentence, another uploads a report. Metering the tokens you actually spend is harder, and the hard parts are idempotency, allowance checks and what to do mid-conversation.

Get in touch

Tell me who you are and what you are working on.

Your details are used only to reply to this message.