Worked Example — The Rewrite That Never Shipped
A worked example of a two-year rewrite abandoned at 80% — why it could never catch up, what the incremental approach that followed actually did, and the numbers that should have stopped it on day one.
This is an illustrative example. The company, timeline and figures are invented. The mechanism — a rewrite that cannot catch a moving target — is the same every time it happens.
The situation#
A logistics company's order management system. Eight years old, 280,000 lines, and universally described as a mess. Changes were slow, defects were frequent, and every estimate carried the phrase "because of the legacy system".
The proposal was a rewrite: a clean implementation of the same functionality on a modern stack, 18 months, five engineers. It was approved, and the reasoning was one sentence everyone agreed with — the old system was too tangled to improve incrementally.
What happened#
Months 1–6. Rapid progress. The core order model was rebuilt in weeks. Demonstrations were impressive. Everyone was pleased.
Months 7–12. Progress slowed. The demonstrations had covered the common path; what remained was everything else. Fourteen customer-specific pricing rules. Two integrations with customs systems, one of which used a protocol nobody could find documentation for. A batch job whose output a customer had been reconciling against for six years and which had to match exactly, including its rounding behaviour.
Months 13–18. The old system continued to be developed, because the business could not stop for 18 months. Eleven substantive features shipped into it during this period, and each one had to be built again in the new system. The rewrite was now chasing a target moving at roughly a third of its own speed.
Months 19–24. Estimates stopped changing. Six months from complete, in month 19, in month 21, and in month 23. The estimate was not dishonest; each time it was made, six months of known work remained, and each month of building surfaced another month of undiscovered behaviour.
Month 24. Cancelled. Roughly 80% complete against a definition of complete that had never been written down.
The cost#
| Engineer-months | 120 |
| Direct cost | ~£1.4M |
| Features shipped to customers from the rewrite | 0 |
| Improvements to the old system during the period | Minimal — the team was elsewhere |
| Engineers who left citing the project | 3 |
The last row was the most damaging. Two years on something that never shipped is a difficult thing to have on a CV, and the people who felt that most acutely were the ones with options.
Why it could not have worked#
Three reasons, all visible before the project started.
The old system's behaviour was not documented anywhere except the old system. Eight years of specific decisions — a rounding rule, an exception for one customer, a workaround for a supplier's broken interface — existed only as code. The rewrite could only discover them by building something that behaved differently and waiting for someone to notice.
The business could not stop. Eighteen months of feature freeze was never actually agreed; it was assumed. Once features continued shipping into the old system, the rewrite had to build each one twice, and the finish line moved away as it was approached.
"Complete" was never defined. There was no list of behaviours that constituted done. In its absence, complete meant "behaves the same as the old system in every case", which is a specification only the old system satisfies.
What was done instead#
The incremental approach, started in month 25, took 14 months and shipped continuously.
A boundary was drawn around the worst part. Analysis of change history showed pricing was 9% of the code, 34% of the changes and 41% of the defects. Nothing else came close.
The old pricing code was wrapped, not replaced. A clear interface was placed in front of it. No behaviour changed and nothing improved yet — this step took six weeks and delivered nothing visible, which required explaining more than once.
Both implementations ran side by side. A new pricing implementation ran behind the interface, in parallel, with the old one still authoritative. Every difference was logged.
The differences were the specification nobody had. Over eleven weeks, 340 discrepancies were logged. Two hundred and ninety were the new implementation being wrong. Fifty were the old system being wrong — including two rounding defects that had been quietly costing money for years. This is the artefact the rewrite could never have produced: a precise, complete list of the behaviour that actually mattered, generated by production traffic rather than by archaeology.
Traffic moved over gradually. One per cent, then ten, then fifty, then all of it, with the old path retained for a month.
Then the next boundary, chosen the same way from the same history.
The result#
| Rewrite | Incremental | |
|---|---|---|
| Elapsed | 24 months | 14 months |
| Engineer-months | 120 | 62 |
| Shipped to customers | Nothing | Continuously from week 8 |
| Reversible at any point | No | Yes — every step |
| Behaviour discovered | By eventual complaint | By logged difference in parallel |
| Old-system defects found | — | 50 |
| Modules replaced | 0 | 4 of 6 |
Two modules remain on the old implementation. Both are stable, rarely changed and cause nothing — the reporting module's equivalent. There is no plan to replace them, and that is the outcome rather than an unfinished task.
What was learned#
A rewrite races a moving target. The old system keeps being developed because the business keeps needing things, and every feature added is built twice. The rewrite must be faster than the team feeding the thing it is replacing.
The behaviour that matters is undocumented by definition. If it were written down, the system would be easier to change and would not need replacing. Running both and logging the differences is the only reliable way to extract it, and it also finds the places where the old system was wrong.
Never take a step that cannot be reversed. Every stage of the incremental work could be rolled back to the previous one in minutes. The rewrite had exactly one moment of reversal — cancellation, after two years.
Choose the boundary from history, not from opinion. Pricing was chosen because it carried 41% of defects. Every engineer asked before the analysis named a different module, and most named the one that turned out to cost nothing.