Legacy modernisation without a big-bang rewrite
A rewrite asks a team to rebuild years of accumulated behaviour while the original keeps changing, then swap everything at once. Replacing the system piece by piece behind a routing layer is slower to start and far more likely to finish.
The instinct when inheriting a legacy system is to rewrite it. The code is unpleasant, the framework is out of support, nobody understands the edge cases, and a clean build looks faster than untangling what exists. It rarely is, and the reason is not technical skill.
Why rewrites fail
A working system encodes years of decisions nobody wrote down: the tax rule for one state, the customer whose invoices need a different format, the batch job that must run before the other one. None of it is in the specification, because there is no specification — the system is the specification.
A rewrite has to rediscover all of it while the original keeps changing, because the business does not stop. So you maintain two systems, and the target keeps moving. The failure mode is not a bad rewrite; it is a rewrite that never finishes, funded until patience runs out.
Then there is the cutover. Everything switches at once, on a date, and if it goes wrong you roll back to a system that has been neglected for eighteen months.
Strangle it instead
The pattern — usually called strangler-fig — puts a routing layer in front of the legacy system, then moves functionality behind it one piece at a time.
Traffic hits the router. Initially it forwards everything to the old system. You pick one capability, build it fresh, and switch that route to the new implementation. Repeat. The old system shrinks until nothing routes to it, and you delete it.
Every step is independently valuable, independently testable, and independently reversible. There is no cutover weekend because there is no cutover.
Sequencing: what to move first
Pick the first slice for learning value, not business value. Something real enough to exercise the pattern end to end — auth, deployment, data access, monitoring — but small enough that getting it wrong costs a week.
After that, prioritise by change frequency, not by how unpleasant the code is. The parts being modified constantly are where new architecture pays back immediately. A gnarly module nobody has touched in four years is stable by revealed preference; it can wait, possibly forever.
Move the parts with the highest defect rate next. Then the parts blocking work you want to do.
The data problem is the hard part
Routing requests is straightforward. Sharing data between old and new systems during a transition is where these projects actually get difficult.
Three workable approaches, roughly in order of preference:
Shared database, separated over time. Both systems read the same tables initially; you carve out ownership incrementally. Simplest to start, requires discipline to avoid permanent coupling.
New system owns its data, syncs back. The new implementation is authoritative for its slice and publishes changes the legacy system consumes. Cleaner boundary, needs reliable event delivery.
Dual write with reconciliation. Both systems write, a job compares and alerts on drift. Use when you cannot yet decide ownership. Treat it as temporary — it is a scaffold, not an architecture.
Whichever you choose, write down which system owns which entity, and keep it current. Ambiguous ownership is how you end up with two sources of truth and no way to decide which is right.
What to keep
Not everything needs replacing. A stable batch process that runs nightly and has not failed in three years is not a liability just because it is old. The question is not "is this modern" but "does this cost us anything" — in outages, in change velocity, in security exposure, in hiring.
If the answer is no, leave it. Modernisation budgets are finite and are better spent where the friction actually is.
What it means for timelines
Strangling looks slower on a plan because value arrives incrementally rather than in one release. It finishes more often. If the choice is a rewrite that might ship in eighteen months or a migration delivering improvements every sprint, the second is easier to fund and far easier to stop safely if priorities change.
We modernise systems in production without cutover weekends, and we say plainly when a component should be left alone. See our software engineering work, our technical due diligence service, or ask us to assess what you have.
- legacy
- modernisation
- architecture
- strangler-fig
- migration