The Low Code Factory Discuss an Engagement

Home/Insights/Modernization without a rewrite

Modernization12 min read

How to plan a legacy modernization without a risky rewrite

Most modernization programmes are cancelled rather than completed. The reason is almost always structural: the benefit was deferred to a cutover that never arrived, while the risk was carried from the first week.

The reason legacy systems persist is not inertia, and it is not that nobody has noticed them. It is that they work. They encode years of accumulated business rules that exist nowhere else, they are trusted by the people who depend on them, and the risk of replacing them is concentrated and immediate while the benefit is diffuse and gradual.

That asymmetry is the entire problem. A rewrite asks an organization to accept a large, near-term risk in exchange for a benefit that will be realised slowly and is difficult to quantify in advance. Sponsors change. Budgets are reviewed. Priorities move. Two years into a three-year programme, somebody senior asks what has been delivered, and the honest answer is "nothing yet, but we are close" — which is the answer that gets programmes cancelled.

When that happens, the organization has paid for the rewrite and received none of it. It is the worst available outcome, and it is more common than either successful modernization or outright technical failure.

The rule that follows from this

A modernization programme should be designed so that it can be stopped at any point without leaving the organization worse off than when it started. That single constraint eliminates most of the ways these programmes go wrong, and it is a design property rather than a project management technique.

It means every stage must deliver value on its own. It means the old and new systems must be able to coexist, indefinitely if necessary. It means the migration must be incremental and reversible. And it means the sequence of work is determined by where the risk and the value are, rather than by what is architecturally tidy.

A programme built this way survives a change of sponsor, because at any moment somebody can look at what has been delivered and see that it has already paid for itself. A programme built around a cutover cannot make that argument until the cutover, which is exactly when it is most likely to be asked to.

Start by finding out what the system actually does

The first and most underestimated phase of a modernization is discovering the behaviour of the system you are replacing. Not the documented behaviour. The actual behaviour.

Legacy systems accumulate rules that were never written down: an exception for one customer, a rounding convention that matters at year end, a batch that must run before another or the figures are wrong, a special case introduced during an acquisition eleven years ago. The people who introduced them have gone. The code is a statement of what happens rather than what was intended, and reading it will tell you the former but not the latter.

There is no shortcut here, and attempting one is how modernizations acquire their reputation. The most reliable technique is to run the two systems side by side against live data and investigate every disagreement, treating each as a defect in your understanding rather than as noise. It is slower than it looks and it is not optional. That comparison period is not a delay in the project. In a replacement of any consequential system, it is the project.

Sequence by risk and value, not by architecture

The instinct of a good engineer is to modernize the foundation first: replace the data layer, then the services, then the interface. It is architecturally coherent and it is usually the wrong sequence, because it produces no visible value for a long time and concentrates all the risk at the point where everything is finally connected.

A better sequence asks two questions of every component. What is the cost of it failing tomorrow, and what is the value of modernizing it? Work on the components where both are high. Leave alone the parts that are ugly but stable, unless they are blocking something.

This is uncomfortable because it means living with a hybrid estate, sometimes for years — a new interface calling an old service, a modern component writing to a legacy schema, an adapter that everybody agrees is temporary. That hybrid is not a failure of the programme. It is the programme working as intended: at every stage the business is better off than it was, and at no stage has it accepted a large irreversible risk.

Design the coexistence explicitly

If old and new must run together, the seam between them deserves as much design attention as either side.

Decide which system is the source of truth for each piece of data, and make that decision explicit rather than emergent. Decide how data flows between them and what happens when that flow fails. Decide how a record that exists in both is reconciled, and who wins. Decide how long the coexistence is expected to last, and then plan for it to last longer, because it invariably does.

The most common failure in coexistence is dual-write: both systems accept changes, both propagate them to the other, and eventually they disagree. Recovering from that disagreement is far harder than preventing it. In almost every case the right answer is a single writer per data domain, with the other system reading, however inconvenient that is for the transition plan.

When an estate is large and repetitive, build the tool

There is a specific situation where a different approach becomes available. Where an estate consists of many similar things — hundreds of forms, dozens of near-identical screens, a large body of reports — hand-porting each one is not just slow. It is inconsistent, because no two developers will interpret the same legacy artifact identically, and the inconsistency only becomes visible in testing.

In that situation it is usually cheaper, and always more consistent, to build a converter: something that reads the legacy definition and emits the modern equivalent, deterministically, so the same input produces the same output every time. The economics change dramatically. Work that was a headcount decision becomes a schedule.

But a converter is only trustworthy if it is honest about its limits. The rule that matters is that nothing may be silently dropped. A tool that translates what it recognises and quietly skips what it does not is worse than no tool at all, because the gap surfaces in user acceptance testing or in production, and by then the whole output is suspect.

The correct design captures everything from the source, translates what it can, and produces an explicit, counted report of what it could not — flagged for a person to complete, with the original in front of them. That report is the artifact that makes the programme governable, because it turns "roughly done" into a number a programme owner can take to a steering committee.

Do not modernize what should be retired

A meaningful proportion of any legacy estate is dead. Reports nobody reads. Screens used by one person who left. Interfaces to systems that no longer exist. Batch jobs whose output goes nowhere.

Migrating those forward is pure cost, and it happens constantly, because establishing that something is genuinely unused is tedious and nobody wants to be the person who deleted something that mattered. Instrument first if you can. Log usage for a quarter. The results are usually startling, and every component that can be retired rather than rebuilt is the cheapest possible win the programme will get.

Decide what "done" means before you start

Modernization programmes drift because the objective is stated as a technology outcome rather than a business one. "Move off the legacy platform" is not an objective; it is a task list. It offers no way to decide whether an individual piece of work is worth doing, and no way to know when to stop.

The objectives that actually govern a programme are things like: eliminate the licence renewal in eighteen months, remove the key-person dependency on the last engineer who understands the batch scheduler, make it possible to onboard a new business unit in a week rather than a quarter, or satisfy an audit finding. Each of those tells you what to prioritise, what to leave alone, and when you are finished.

The short version Design the programme so it can be stopped at any point without leaving the organization worse off. Recover the undocumented behaviour by running old and new in parallel and investigating every disagreement. Sequence by risk and value rather than architectural tidiness. Where the estate is large and repetitive, build a converter — and require it to report, exactly, what it could not translate.