Skip to content
← All writing

I stopped writing code and started writing specifications

14 Jul 20262 min

Draft — written from notes, not yet reviewed. Rewrite this in your own voice, then delete draft: true from the frontmatter.

Every repository I keep now opens the same way. A blueprint that says how the thing is built. A build plan that says what gets built next. A design ledger so the interface can't drift. The code comes last, and increasingly it isn't me who types it.

That sounds like process for its own sake. It isn't. It's the only reason one person can run two products in production, around a full-time job, while rebuilding a third from the foundations.

The constraint was never typing speed

I used to think the limit on how much software I could ship alone was how fast I could write it. It wasn't. The limit was how much of a system I could hold in my head at once — and that number is small, and it gets smaller the longer you're away from a file.

A written system doesn't need to be held. That's the whole insight. Once the architecture lives in a document rather than in my memory, picking a project back up after three weeks costs a read, not a re-derivation.

What actually goes in the files

Three documents, and they do different jobs:

  • The blueprint describes how the system is put together — the layers, what may import what, where side effects are allowed to live. It changes rarely.
  • The build plan is an ordered list of the next changes, each small enough to finish and verify in one sitting. It changes constantly.
  • The design ledger records every visual decision that's already been made, so the fortieth component looks like the first.

None of them are long. The blueprint for my largest project is under two pages.

Gates, not vibes

A specification nothing enforces is a wish. So each project has checks that run before a commit lands: types, tests, a dependency-graph check that fails if a module imports across a boundary the blueprint forbids, and a design check that fails if a component invents a colour that isn't in the ledger.

This is the part people skip, and it's the part that makes the rest work. Agents are good at producing plausible code. Gates are what turn plausible into correct — they give the loop something to fail against that isn't my attention.

What changed in practice

The work split into two modes that feel completely different. There's thinking time, which is slow and mostly writing prose. And there's execution, which is fast and mostly reviewing diffs.

I'm better at the first than I expected and worse at the second — reviewing a large correct-looking diff is genuinely harder than writing the code was. That's the real cost of this way of working, and I don't think it's talked about enough.

Where it breaks

It breaks when the spec is wrong in a way the gates can't see. You get a beautifully implemented version of the wrong idea, quickly, and the speed that felt like an advantage becomes the problem — you've now got a lot of code committed to a bad decision.

The mitigation is boring: make the build plan steps small enough that a wrong one costs an afternoon, not a fortnight.