The received wisdom on incremental development runs something like:

  • Build a little, learn a little, keep the cost of change low.
  • Commit to nothing you cannot afford to revisit.
  • Let the design emerge from the work rather than trying to specify it upfront.

The assumption underneath this was always that code is expensive to write. You deferred because you could not afford to be wrong. AI has made code cheap.

So does the received wisdom still hold?

Partly. The assumption was half right, and understanding which half is what matters now.

What Incrementalism Was Actually For

Incremental development was never just about the cost of writing code. It was about the cost of being wrong. Build small so that when you discover you have misunderstood the domain, the requirement, or the user, you have not committed too deeply. Keep the blast radius of any single mistake small. The cheapness of code was the mechanism. Keeping the cost of mistakes low was the goal.

These are not the same thing, and conflating them is what leads many teams astray in the age of AI.

What AI Made Cheap

Code generation is now fast and cheap. Given a clear model and a good test harness, an AI can produce a solid implementation in a fraction of the time a developer working alone would have needed. Refactoring an implementation against a new spec is similarly cheap. Rewriting a module, even a large one, is no longer the multi-day undertaking it once was.

What AI has not made cheap:

Getting the domain model right. Understanding what the core models and structures are, what states they move through, what transitions are valid: this requires understanding the problem. That is a human constraint, not a coding constraint. It has not changed.

Identifying where the seams go. The interfaces between components, the boundaries between concerns, the question of what belongs together and what does not: these decisions are as hard as they ever were. AI will implement whatever seams you give it. It will not tell you they are wrong.

Deciding what the system should do. The thinking upstream of generation determines the quality of what gets generated. A vague model produces a coherent-looking implementation of the wrong thing.

The Amplification

Here is what has changed. When code was expensive, misalignment surfaced slowly. A bad model produced slow, painful code. You felt the wrongness before it compounded far. The friction was a signal.

With AI generation, that signal is gone. You can build five coherent-looking layers on a bad model in a day. Each layer assumes the validity of the one beneath it. The dependency graph grows fast, and it grows quietly.

Day 1        Day 3              Day 7
             
[Model]      [Model]            [Model]
             [Layer A]          [Layer A]
             [Layer B]          [Layer B]
                                [Layer C]
                                [Layer D]
                                [Layer E]
             
             Looks fine.        Still looks fine.

By the time the misalignment surfaces, you are not unwinding one bad decision. You are unwinding the decision plus everything that grew on top of it: the integrations, the tests, the callers, the assumptions baked into each subsequent layer.

Worse: the output is self-concealing. AI-generated code tends to be internally consistent even when it is consistently wrong. You do not get the usual signal of accumulating mess. It looks clean. It looks well-structured. The wrongness is in the direction, not the surface, and direction is harder to see.

The Exponential

The cost of correction is not linear in the depth of wrong-direction code. Each layer added in the wrong direction brings its own integrations, its own tests, its own callers. Unwinding it means unwinding all of that too. The correction cost compounds.

With hand-written code, the practical cap on how far wrong you could go was time. You could only build so fast before the friction of misalignment slowed you down and surfaced the problem. That was an accidental safety mechanism.

With AI generation, that cap is gone. The rate of wrong-direction accretion is now limited by how long it takes you to notice, not how long it takes to write. And because the output looks coherent, you notice later. Much later.

The Methodology Becomes the Trap

This is where a slavish devotion to incremental development stops being the solution and starts being the problem.

Incrementalism works by committing you to small steps. That is its virtue: each decision is cheap, each mistake is contained. But when the direction is wrong, that same commitment works against you.

The fix for misaligned direction is not a small step. It is a correction to the model: the types, the state machine, the seams. By definition it touches everything built on top of it. In an incremental methodology, that correction never fits the next sprint. It is always too large, always deferred, always "after we ship this". And because each sprint adds more code on top of the wrong model, the correction needed grows. The gap between what can be done incrementally and what it would actually take to fix the direction widens permanently.

The real fix does not just feel out of reach. It is out of reach, by the logic of the methodology you have adopted. The system keeps moving. Each step is locally rational. The direction problem is never addressed because addressing it was never going to be a small step.

This is the trap: the discipline that was supposed to keep decisions cheap can make one wrong decision permanently unaffordable.

The Discipline Shift

Incrementalism does not die. The unit changes.

Before AI, the advice was: defer everything. Code is expensive to write, so write as little as possible until you have to. Let the design emerge.

After AI, the advice is: defer implementation, but invest early in the model and the interfaces. Get the types right. Get the state machine right. Get the seams right. These are the things that do not get cheaper when code gets cheaper. They are the skeleton that all the generated code will integrate against. If the skeleton is wrong, everything attached to it is wrong, and generation will compound that problem fast.

What you are still deferring is the implementation detail: exactly how a module works internally, which third-party library sits behind an interface, how a migration runs. These are cheap to change. Defer them freely.

What you are no longer deferring is the model. Because the cost of getting it wrong has gone up, not down.

The Signals

The misalignment shows up early if you are looking for it.

The interfaces feel wrong. You keep passing things that feel incidental to a function. Parameters that are there because something needed them somewhere. Seams that cut across concerns rather than between them.

The state machine resists description. You cannot explain the lifecycle of your core entity cleanly. States are implicit; state transitions are scattered across the codebase rather than named and centralised. You struggle to say what the valid next state is from any given point.

Tests feel like they are testing the wrong thing. Coverage looks reasonable but confidence feels low. The tests describe what the code does, not what the system should do. Passing feels like an accident.

These are not signals to note and move on from. They are signals to stop and act on. The longer you wait, the more the correction is not just fixing a model: it is fixing a model plus its blast radius.

Where This Leads

Incrementalism gave teams a discipline for managing uncertainty. It still does. But in the age of AI, uncertainty about the domain is not managed by deferring everything. It is managed by being precise about what you are certain of and deferring only what you are not.

The core model: as certain as you can make it, as early as possible. The implementation: defer, iterate, regenerate cheaply.

That distinction, between what is load-bearing and what is interchangeable, is what the next article is about. Building the harness that holds the model stable while generation does its work.