Spec-Driven Development Is an Anti-Pattern

Spec-driven development is an anti-pattern.

A perfect specification is called code.

Everything else is an approximation.

The Spec Is Not the Feature

Over the last few months, I’ve stopped writing feature specs. Not because planning isn’t important or because I expect AI to magically understand what I want, but because writing a specification before writing the code increasingly feels like solving the wrong problem.

A sufficiently good specification is already code. Anything less is an approximation: it may capture the intent, but it cannot capture every interaction, dependency, edge case and observable behavior. Whatever it leaves out is where the agent gets to interpret—and often misinterpret—what you meant.

A few days ago, I was implementing a feature with an agent, including its component tests. Those tests were supposed to mock the external dependencies while testing the code that was actually part of the feature. Instead, the agent mocked two dependencies that belonged to the feature itself.

The component tests passed, while the end-to-end test failed.

A Markdown specification would not have prevented this. The spec could have looked perfectly correct while the implementation remained wrong, because the failure happened while translating my intention into code.

That is why I prefer to work directly on the feature with the agent. I inspect what it actually builds, run the tests and keep iterating until the implementation behaves the way I intended. I don’t need another artifact in the middle describing what the code should eventually become.

The code is the specification.

The Code Is the Context

This also makes starting a new agent session simple. I don’t need to give the new agent a Markdown document explaining the work so far; I ask it to read the branch and diff it against main.

That diff is the feature. It contains the production code, the tests and every decision that survived implementation. Why give the agent a less precise description of something it can already read directly?

The Token Economy

This workflow probably uses more tokens than writing a spec once and asking the agent to implement it. Tokens aren’t free, and they won’t become free anytime soon, but I think much of the industry is looking at the token economy the wrong way.

I’m fortunate enough to work at AWS, where I can mostly ignore token usage during development. I joke with my teammates that I’m trying to token-max rather than token-minimize. I’m not deliberately wasting tokens, but I’m also not designing my workflow around the cost of inference today.

I try to work as though I’m already two years into the future.

Game developers used to target the hardware people would own by the time their games shipped, not only the hardware already sitting in people’s homes. I think the same logic applies here. Inference will get cheaper, models will improve, and they’ll become more efficient at doing the same work.

Optimizing an engineering workflow around today’s token prices feels shortsighted. Efficiency matters, but minimizing token usage is not the efficiency I care most about.

I care about making the code easier to understand and change correctly.

Refactoring Has Become Cheap

One of the best things AI has given me is much cheaper refactoring.

I work with a package that has been touched by many developers and redesigned several times. Like most mature code, parts of it are not structured the way I would structure them today.

Previously, I would often notice that and leave it alone. Large refactors take time, create merge conflicts and become especially painful when several developers are working on nearby branches. Either they have to rebase on top of the refactor or the refactor has to be rebased on top of their work, and both options can be unpleasant.

Now I mostly just do the refactor. The agent handles much of the mechanical work, and it can also help with the rebases and merge conflicts afterwards.

The requirement is good tests: unit tests, component tests and end-to-end tests. Tests were always valuable, but now they’re mandatory. They are what make large automated changes safe.

With enough test coverage, I can refactor aggressively and gradually turn a legacy codebase into something cleaner, more modular and easier to reason about.

Good Code Is Better Documentation

So what documentation does an agent need? Mostly, better code: readable, modular and easy to reason about.

For years, we’ve said that comments should explain why, not what, because the code should already explain what it does. The same principle applies to Markdown.

Markdown is useful for business context, architectural trade-offs, operational procedures and anything else that cannot be expressed in the implementation. But when a Markdown document exists mainly to explain what the software does, it is the wrong artifact.

The implementation already does that.

A perfect specification is called code.