Joel Spolsky’s classic warning against rewriting software from scratch argues that old code embodies years of bug fixes and real-world knowledge. Netscape, Borland, and a discontinued Microsoft Word project illustrate the commercial danger: while a replacement is rebuilt, competitors move and customers remain on a product that cannot evolve. The essay’s defense of incremental refactoring remains an essential correction to developers’ attraction to clean slates.
“Never,” however, makes a risk judgment sound like a law. Old code stores knowledge, but it also stores obsolete assumptions. A system designed around an unsupported platform, unsafe memory model, discontinued vendor, inaccessible interface, or regulatory requirement may not permit indefinite renovation. Some constraints are not ugly functions that can be moved one at a time; they are contracts embedded across the whole product.
The essay treats accumulated fixes as assets that a rewrite discards. That is true when the only record of behavior is the implementation. It is also an indictment of missing tests, specifications, observability, and domain documentation. Preserving code forever because nobody knows what it does protects knowledge in its least transferable form. The practical task is to extract that knowledge before replacing anything.
Incremental migration is not free of strategic risk either. Running old and new paths together adds synchronization, duplicated work, compatibility layers, and years of temporary architecture that can become permanent. Teams can spend so much effort keeping every historical behavior that they never remove the constraint blocking the new product. A strangler migration often lowers release risk, but it can raise operational complexity.
The Netscape example also bundles technical and managerial failure. A multi-year gap without a shippable path is not the inevitable result of new code; it is a portfolio decision. A rewrite with narrow scope, explicit parity boundaries, progressive traffic, and continued investment in the existing product is different from placing the company behind one all-or-nothing launch.
The better rule is evidentiary. Inventory the behaviors users depend on, measure maintenance and incident costs, identify constraints that refactoring can and cannot remove, and compare migration options. Preserve old code until replacement paths demonstrate correctness under real traffic. Stop a rewrite when its assumptions fail, just as readily as stopping endless renovation.
The addendum is that code should not be discarded because it is unpleasant to read, but neither should age be confused with wisdom. The asset is verified behavior and domain knowledge. Keep the implementation when it remains the safest carrier of those assets; replace it when the old structure makes preserving them more dangerous than migration.