Services

Legacy System Modernization

The system still runs the business and nobody wants to touch it. Work that moves it onto something maintainable a piece at a time, with behaviour proven unchanged at each step.

Somewhere in your estate is a system everyone works around. It has not been replaced because the person who understood it left, the vendor stopped answering the phone, and the rules that keep the invoices correct live only in code. A rewrite sounds clean until you cost the parallel run and the freeze it needs. The quieter route is to establish what the thing really does, pin that down in tests, and move capabilities out one at a time while it keeps running.

Two ways through

The choice is when you take the risk.

Big-bang rewrite

Build the replacement alongside, in full, then switch over on a chosen date. It is honest about the end state and easy to fund as one project.

  • A clean design, unconstrained by the old system's shape
  • One budget, one plan, one date the board understands
  • The old system must be frozen while the new one catches up
  • Everything is unproven until the single day it all matters

Incremental replacement

A stable interface goes in front of the old system, then capabilities move behind it one at a time, with both paths live until the new one is trusted.

  • Each slice reaches production and can be rolled back alone
  • The business keeps releasing while the migration runs
  • Behaviour is compared against the old path before it is retired
  • It takes longer on paper and the interface costs real work

Four routes, and one that is doing nothing

Modernisation is a decision per capability. A system is rarely uniform: the pricing engine may be worth rebuilding while the batch that posts the ledger should be left exactly as it is. So the route gets chosen per capability rather than for the whole estate, and a single programme usually runs two or three of them at once.

Some systems should be left alone, and it is worth saying what one looks like. It is stable, the rate of change against it is close to zero, it runs on hardware and an operating system that are still patched, and the cost of its existence is a licence rather than a queue of blocked work. A system like that is a paid-off asset rather than technical debt, and touching it buys you nothing.

The four routes

What each route is for

Encapsulate, re-host, re-architect, rebuild. The choice between them is mostly economics: how often the capability changes, how well anyone understands its behaviour, and what the business would lose in the hours it was unavailable.

Encapsulate

Wrap it in an API and leave it

The system stays where it is and a documented interface goes in front of it, so everything new talks to that rather than to its internals. This is the right call when the code is stable but nothing can reach it. You buy integration and time, not maintainability.

Re-host

Move it, change as little as possible

Same code, newer place: a supported runtime, a current database version, hardware that is still sold. It is the cheapest route with the clearest end date, and it fixes nothing about the code. Worth doing when the deadline is a vendor's end-of-support notice rather than a business need.

Re-architect

Strangle it module by module

New code takes over one capability at a time behind a routing layer; the old path stays live until the new one has proven itself. The most work of the four, and the only route that keeps delivering to users throughout. It needs a seam a router can sit on.

Rebuild

Write the capability again

Sometimes the old behaviour is the problem. When a capability has drifted from what the business now needs, reproducing it faithfully is wasted effort and it should be specified afresh. This route has the longest gap before anything ships, so it suits a bounded capability rather than a whole system.

How the work runs

The order matters more than the tooling. Nothing moves until the current behaviour can be demonstrated, because a migration you cannot check is a rewrite with extra steps.

  1. 01

    Read it

    We work through the code, the schema, the jobs and the traffic it serves, separating what is used from what merely exists. You end up with a map of the system and a list of the behaviours any replacement has to reproduce.

  2. 02

    Pin the behaviour

    Characterisation tests capture what the system does today, correct or not, so a change in behaviour later shows up as a failing test rather than a support call. You review the suite and mark which behaviours are deliberate and which are bugs you live with.

  3. 03

    Cut the seams

    Before anything moves, the system needs places where traffic can be redirected and compared: an interface at the boundary, routing in front of it, and enough logging to tell the two paths apart. This is where the architecture decisions get written down, alternatives included.

  4. 04

    Migrate a capability

    One capability moves at a time. Both paths run against real traffic until the new one matches, then the old is switched off and its code deleted rather than left to rot as a fallback. Each slice ships and reverses on its own.

  5. 05

    Hand it over

    The last slice is not the end of the job. Runbooks, dashboards and on-call procedures ship with the system, and the people who built it are the ones who write them. You finish holding something your own team can run without us in the room.

Questions worth asking first

Most of it. The incremental route exists because a freeze long enough to rewrite a working system is rarely something a business can afford. New features land in whichever path already owns that capability, which does mean some work gets built twice in the overlap. That cost is real and we would rather name it than pretend the overlap is free.

Not sure which one you need?

Describe the problem in a paragraph and we will tell you which service applies.