Seven principles of legacy modernisation without downtime
How to replace a legacy system while it keeps running: strangler-fig migration, reversible steps, and the seven principles that keep the business online.
The hard part of replacing a legacy system is not the new system. It is that the old one has to keep running while you build it — processing orders, paying people, serving customers — because a mid-market company cannot stop trading for a rewrite.
That constraint rules out the approach most teams reach for first, and it shapes everything below.
1 · Replace in parts, never in one move
The full rewrite with a cutover date is the most common plan and the most common failure. It fails for a structural reason: the effort is spent before any value arrives, and the risk concentrates entirely on one day.
The alternative — strangler fig — routes traffic through a layer that can send each request either to the old system or to a new component. You replace one capability at a time. The old system shrinks until it is doing nothing, and then it is switched off without ceremony.
Each step is small, shipped, and reversible.
We ran exactly this on the Palisis Backoffice: the Google Web Toolkit frontend and its Angular replacement ran live in production at the same time, module by module, until the last GWT screen was gone. How that migration was sequenced.
2 · Every step must be reversible
A migration step that cannot be undone is a bet. In a system the business depends on daily, you want no bets.
Practically: the routing layer can send traffic back to the old path, the data can still be read by the old system, and the switch is a configuration change rather than a deployment. If undoing a step requires a release, it is not reversible enough.
3 · Move behaviour before data
Data migration is the riskiest part of any modernisation, so it should happen when you understand the new system best — which is after you have built some of it, not before.
Start by putting new behaviour in front of old data. The new component reads from the legacy store, serves the new interface, and proves itself. Only then does the data move, and by that point you know exactly what shape it needs to be in.
4 · Find the seams, not the modules
Legacy systems rarely divide along the lines their code suggests. The useful boundary is a business capability with a clear input and output — “produce an invoice”, “check credit”, “schedule a delivery” — not a package name.
Look for where data crosses a boundary and where a different team owns the outcome. Those are the seams. Cut there and the pieces separate cleanly; cut along module boundaries and everything stays entangled.
5 · Tests before changes
Legacy systems usually have poor test coverage and excellent institutional knowledge, held by two people. Modernisation moves the knowledge into code, and you cannot do that safely without a way to tell whether behaviour changed.
Characterisation tests — tests that record what the system currently does, correct or not — are the tool. They are not about correctness. They are about detecting difference.
6 · Keep both systems honest with the same inputs
While a capability exists in both systems, run both and compare. Send the same request to old and new, log both answers, and investigate every divergence before switching traffic over.
This surfaces the undocumented behaviour that no specification contains — the rounding rule, the special case for one customer, the date handling that was wrong but consistent. Every legacy system has several.
7 · The old system leaves on a date, and the date is enforced
Half-migrated systems are the worst outcome: two codebases, two deployment paths, two sets of bugs, and a team maintaining both indefinitely. It happens when the last 10% has no deadline, because the pain has already been relieved.
Set the decommission date when the migration starts. Treat the remaining capabilities as a countdown. A modernisation that never finishes costs more than the legacy system it was meant to replace.
What this looks like in practice
For a Swiss mid-market company the sequence is usually: a routing layer in front of the existing system, one low-risk capability moved and proven, a comparison period, then progressively larger capabilities as confidence builds. Data moves in the middle, not at the start. The legacy system is switched off on a date agreed at the beginning.
No step requires a maintenance window. No step is irreversible. Nobody has to stop trading.
If an aging system is limiting what the business can do, the first useful question is where its seams are — not which framework replaces it. Our application modernisation work starts there, and a conversation is non-binding.