Every legacy system was once someone's good decision. The fifteen-year-old monolith processing your orders exists because it worked, well enough to carry the business to the point where its limitations matter. That history deserves respect, because it's also the reason rewrites are so dangerous: the old system encodes years of business rules nobody fully remembers agreeing to.
We've been called into enough modernization efforts, some as builders, some as rescuers, to have strong opinions about what works.
Why big-bang rewrites fail
The pattern is depressingly consistent. A rewrite is scoped at eighteen months. Around month twelve, the team discovers the old system handles forty edge cases nobody documented. The business keeps changing while the rewrite chases a moving target. At month twenty-four there are two systems: the old one still running production, and the new one perpetually six months from ready. Eventually a leadership change cancels the project, and the surviving artifact is organizational scar tissue that blocks the next modernization attempt.
The root cause isn't engineering skill. It's that a total rewrite makes the riskiest possible bet, everything at once, with value delivered only at the end, against a system whose full behavior nobody can specify.
The staged alternative
The approach that works is incremental, and it front-loads learning instead of code:
1. Stabilize first. Before changing anything, make the current system observable and deployable: version control hygiene, a repeatable build, basic monitoring, and characterization tests that pin down what the system actually does (as opposed to what the docs claim). This step is unglamorous and pays for itself within months. Modern AI tooling has made it dramatically cheaper: models are remarkably good at reading old code and drafting the characterization tests humans never had time to write.
2. Carve at the seams. Identify the boundaries where the system naturally splits, usually where data ownership changes hands. Introduce explicit interfaces at those seams while behavior stays identical. No user-visible change; enormous strategic change.
3. Replace by strangling, highest-pain first. Route one seam at a time to a new implementation, run old and new side by side, compare outputs, then cut over. Each replacement ships value on its own and teaches you about the next one. If priorities shift mid-journey, you stop at a coherent point, not in the middle of a half-built cathedral.
Choosing what not to modernize
Not every component earns replacement. A stable batch job that runs monthly and never changes can stay on its ancient runtime for years. Wrap it, monitor it, move on. Modernization budgets are finite; spend them where change frequency and business pressure are highest. A blunt scoring of components on change frequency × pain usually reveals that 20% of the system generates 80% of the grief.
The AI-era angle
There's a new reason modernization is climbing priority lists: legacy systems are where AI initiatives go to die. Retrieval over your data, workflow automation, AI-assisted operations, all of it assumes systems with accessible APIs and coherent data. "Get the data out of the mainframe" has quietly become step zero of most AI roadmaps. Modernization and AI enablement aren't competing priorities; the first is the on-ramp to the second.
If you're staring at a system that everyone is afraid to touch, an experienced outside assessment is the cheapest possible first step: a few weeks of work that turns fear into a sequenced plan. That's a conversation we're glad to have.