Why big-bang rewrites go wrong
A full rewrite means building a second version of the system while the first one keeps changing. The new system delivers no value until it is complete, the requirements are buried in old code that nobody fully understands, and the switch-over happens all at once, with every risk concentrated in a single day. Many rewrites are abandoned halfway, after the budget has been spent and the old system has kept evolving without them.
There is a safer path, which replaces the system one piece at a time while the business keeps running.
The strangler fig pattern
The name, coined by Martin Fowler, comes from a tropical fig that grows around a host tree until it can stand on its own. Applied to software, the idea is simple:
- Place a routing layer in front of the legacy system — a proxy, an API gateway, or a façade in the user interface. At first it forwards everything to the old system.
- Build one capability in the new system — for example, customer lookup, or the generation of a specific document.
- Route that capability to the new system. Everything else continues to go to the old one.
- Repeat, capability by capability, until the old system no longer handles anything and can be switched off.
Each step is small, delivers value as soon as it is live, and can be reversed by changing a route.
Choosing what to move first
A good first slice combines visible value with limited risk:
- A capability with clear boundaries — few dependencies on the rest of the system.
- Real pain — slow, error-prone or impossible to change in the current system.
- Measurable outcome — users, response times, error rates or processing time that can be compared before and after.
Avoid starting with the core transaction engine. Start at the edges, learn how the old system really behaves, and work inwards.
Supporting techniques
Anti-corruption layer
The new system should not inherit the old one's data model and quirks. An anti-corruption layer translates between the two, so that the new code is designed around today's business concepts, not around tables named in 2005.
Data: the hardest part
While both systems are live, they often need the same data. The options, from simplest to most robust:
- the new component reads the legacy database directly, temporarily, read-only;
- data is synchronised between the two, through change data capture or events;
- ownership of a data set moves to the new system, and the old one reads from it.
Decide explicitly which system is the owner of each piece of data at each stage. Two systems writing the same records is where most incidents come from.
Parallel run and feature flags
For critical calculations, run old and new side by side on the same inputs and compare outputs before switching. Feature flags let you route a share of users or a single business unit to the new path first, and roll back without a release.
Tests that capture current behaviour
Before changing anything, write characterisation tests: tests that record what the legacy system does today, including behaviours that look odd. They protect you from removing a rule that turns out to matter. A reliable CI/CD pipeline runs them on every change.
Integration is half the work
Legacy systems are rarely isolated: they exchange files with accounting, receive orders from a web shop, feed reports. Each of these flows has to be preserved or redirected as capabilities move. Replacing point-to-point file transfers with documented APIs during the modernisation pays off twice — see our notes on system integration.
Where the cloud fits
Modernisation and cloud migration are often combined: the legacy system is first rehosted as is, then strangled in the cloud, with new components built on managed services. The order depends on what is more urgent — leaving a data centre, or unlocking change in the application.
Keep the old system healthy meanwhile
A strangler programme can take months or years for a large system. During that time the legacy application still runs the business and must be maintained: security patches, small fixes, regulatory changes. Planning that maintenance alongside the modernisation, rather than freezing the old system, avoids building pressure for a rushed switch-over.
Where to start
Map the system's capabilities and their dependencies, choose a first slice at the edge, and put the routing layer in place. Our application management service keeps the existing system running while we modernise it step by step, with one team accountable for both.