What is Rewrite trap?

Engineering culture

Rewrite trap is the recurring belief that the quickest way to improve a struggling software system is to throw it away and build a clean replacement. The trap is that new code starts with less real world knowledge, fewer embedded bug fixes, and a long period where the team is recreating old capability instead of shipping new value. Rewrites can be justified, but they are rarer and riskier than the first pitch usually suggests.

What this means

The old system feels slow, ugly, and exhausting to work in. A blank repository feels clean, hopeful, and full of modern tools. That emotional contrast is powerful. It is also deeply misleading. A fresh start is easier to admire than to finish.

The trap works because the early phase of a rewrite feels fast. Of course it does. The new system has not yet rediscovered obscure integrations, weird customer behaviour, historical data problems, and all the unglamorous bug fixes living inside the old code. For a while, the team mistakes "small" for "better".

Why it matters

This matters because whole engineering roadmaps have been sunk by the promise of a clean slate. When a rewrite freezes feature delivery, splits the team between old and new systems, and burns months rebuilding already known behaviour, the cost is not only technical. It hits customers, confidence, hiring, morale, and competitive pace.

It also matters because rewrite language often sounds sensible in meetings. People say the old stack no longer scales, nobody understands the code, or developer productivity is collapsing. Those may all be true. The trap is assuming those facts automatically imply a full restart, when many of the real blockers are more specific and can often be addressed more gradually.

How it works

Why rewrites are so tempting

Programmers are builders. Given a messy building, many instinctively want to knock it flat and erect something elegant. Joel Spolsky put that temptation memorably years ago. Reading old code is hard, writing new code is exciting, and the human brain is very good at mistaking personal excitement for strategic wisdom.

Old systems also make their own case badly. Their hard won knowledge is buried in conditionals, migrations, comments, production incidents, and forgotten workarounds. Meanwhile the imagined new system exists as diagrams and intentions. One side looks ugly because it is real. The other looks beautiful because it is still mostly fiction.

What gets lost in a rewrite

The first thing that gets lost is time. While the team rebuilds existing behaviour, competitors and customers continue living in the present. The second thing is feedback. A rewrite often creates a long stretch where the team cannot ship meaningful slices because too much foundation is still missing.

The third loss is embedded knowledge. Old code contains bug fixes that do not announce themselves as wisdom. A gnarly bit of FTP handling, a strange import path, a bizarre payment validation rule, all may exist because somebody learned the hard way what real systems do in the wild. When you rewrite, you do not delete complexity, you often defer your rediscovery of it.

There is also an organisational split. Someone must keep the old system running while the new one is built. That tends to create two classes of work, the glamorous future and the unloved present. The people who stay with the old system may feel stranded, and the people building the new one may gradually lose touch with what users actually need today.

When a rewrite is reasonable, and what is safer than a big bang

A rewrite is not always foolish. Sometimes the platform is truly obsolete, legal or operational constraints are severe, data models have become unworkable, or the architecture blocks a strategic shift that incremental change cannot realistically reach. But a justified rewrite still needs to earn its keep. It needs a migration plan, a coexistence plan, clear slices of value, and a sober account of what the old system already knows.

That is why experienced teams prefer gradual replacement patterns when they can. The strangler fig approach replaces parts of a legacy system over time rather than betting the whole transition on one dramatic cutover. Branch by abstraction creates a layer that lets old and new implementations coexist while the system still builds and ships. Transitional architecture acknowledges an uncomfortable truth, that you may need temporary scaffolding you fully intend to throw away later.

There is also a less theatrical alternative that leaders often forget, the deliberate scrub. Joel described this in work on FogBugz years after warning against whole system rewrites. Instead of scrapping everything, he spent a short, bounded period reshaping the internal structure while keeping the software continuously working. The key idea was not glamour. It was preserving behaviour and optionality.

The rewrite trap, then, is not "rewrites are banned". It is "rewriting feels simpler than understanding". As soon as a proposal starts promising that the new system will finally be clean, fast to build, easy to test, easier to hire for, cloud native, more scalable, and somehow quicker than careful evolution as well, the trapdoor is already creaking.

Examples

A team maintaining a large internal application decides to rebuild it in a fashionable language because the current stack feels embarrassing. Six months in, the new code handles the easy cases beautifully. Meanwhile the old application still holds the awkward workflows that actually matter, so both systems need staffing.

A product group wants to move from a single large application to many smaller services. The migration is framed as a rewrite because that sounds cleaner than admitting there are several separate problems, deployment speed, testing boundaries, ownership, and scaling concerns. By bundling them together, the team creates a project too large to learn from quickly.

An executive approves a "parity rewrite", meaning the new system will do everything the old one does, only on better technology. That phrase sounds safe and sensible. In practice it often hides the hardest possible brief, reproduce years of behaviour exactly, while delivering no obvious customer gain until the very end.

Common misunderstandings

People sometimes hear "rewrite trap" and conclude that rewrites should never happen. That is too absolute. Some replacements are necessary. The real issue is whether the team is confronting the migration honestly.

Another misunderstanding is that early speed proves the rewrite was the right call. Early speed often just means the new system is still missing the awkward parts that slowed the old one down.

It is also wrong to think refactoring means preserving everything forever. Careful evolution can still involve replacing large sections of code, changing architecture, or exiting dead technologies. The difference is that value and knowledge are moved in slices rather than in one heroic leap.

And feature parity is not a modest goal. It is often the most treacherous one, because it asks a new system to relearn everything the old one already knows before the business sees much benefit.

Risks and boundaries

The phrase can become its own dogma. Teams do sometimes cling to painful systems far too long because "rewrites always fail" has become an article of faith. That can be as blinding as the opposite error. Pragmatism matters more than slogans.

Still, leaders should notice how often rewrite talk is really a plea for relief. Engineers may be trying to say that tests are too weak, architecture is too tangled, build times are too long, or ownership is too blurred. If you answer that whole cluster of pain with only "new stack", you are treating the mood and neglecting the diagnosis.

What to do next

If a rewrite proposal lands on your desk, ask what specific constraint it removes that cannot be addressed another way. Ask what real behaviour the old system contains, how users and data will migrate, who keeps the present system healthy, and what can be delivered in the first thin slice. If nobody can answer those questions, you are looking at desire more than a plan.

Prefer gradual replacement where possible. Fund seams, stronger tests, abstractions that allow old and new paths to coexist, and a sequence of visible milestones. Big promises are not a migration strategy.

Most of all, do not reward novelty alone. Teams that know they will be praised only for greenfield work will keep trying to escape hard systems instead of improving them. Maintenance, careful displacement, and unglamorous simplification should count as senior engineering achievements.

FAQs

Is a rewrite always a mistake?

No. Some systems do need replacement. The mistake is treating replacement as automatically cleaner, cheaper, or quicker than careful evolution.

What is the difference between a rewrite and a refactor?

A rewrite recreates behaviour in a new codebase or major new implementation. A refactor changes structure while aiming to preserve behaviour in place.

Why do rewrites feel fast at first?

Because the new system begins small and has not yet rediscovered the awkward edge cases, integrations, and data history that burden the old one.

What is a strangler fig approach?

It is a gradual replacement pattern where new capability grows around and through the old system until the old parts can be retired piece by piece.

Can a startup rewrite safely?

Sometimes, yes, especially if the product is still small and behaviour is limited. The more users, data, integrations, and compliance history you carry, the riskier it gets.

What is the first warning sign of the trap?

Usually a proposal that bundles many complaints into one magical answer, new language, new architecture, new productivity, and a promise that all of it will be quicker.

Sources