Legacy Software Modernization
The system still works. That is the problem: it cannot be switched off, and it cannot be changed. Modernization is the route between those two facts.
- Typical duration
- Nine to twenty-four months
- Team shape
- Three to six senior engineers
- Starts with
- A four-week assessment

A rewrite is the plan that sounds bravest and fails most often
The appeal is obvious: start clean, build it properly, switch over. The failure is equally consistent — the old system keeps changing while the new one is built, the switchover date moves, and eighteen months in there are two systems to maintain and no way back.
We work the other way. The old system stays live and stays authoritative while functionality moves out of it a slice at a time, each slice reconciled against the original before the next is scoped. It is slower to describe and considerably faster to finish, and at every point there is a working system and a route back.
What usually goes wrong, and what we do instead
The technical problem is rarely the hard part. The sequencing is.
Where modernization programmes fail
- A rewrite scoped against a specification nobody has verified against the code
- A freeze on the old system that the business cannot actually honour
- Business rules that exist only as behaviour, discovered on cutover
- A single switchover date, with no way back once it passes
- Data migrated once, at the end, with no reconciliation until after
How we run it instead
- Behaviour characterised from the running system before anything moves
- The old system stays live and stays authoritative throughout
- One slice at a time, each reconciled against the original
- Every slice individually reversible, so there is always a route back
- Data moved and reconciled continuously, not in a final weekend
What changes, in practice
Not a technology list. The things that are different for the people who use and run the system.
The system today
Working, and expensive to touch.
- A change takes weeks, most of it spent establishing what might break
- Releases happen rarely, and are attended by everyone
- Business rules live in code nobody has read recently
- Reporting is a copy of the database and a spreadsheet
- One or two people can safely make changes, and both are busy
- There is no test suite, so confidence comes from experience
The system after
Same behaviour, changeable.
- A change takes days, and the tests say what it affected
- Releases are routine and individually reversible
- Rules are characterised in tests, so they can be read and changed
- Reporting reads from a defined interface rather than the tables
- Any engineer on the team can make a change safely
- Behaviour is pinned by tests written from the original system
What the work involves
Modernization is mostly four activities, in a deliberate order.
Characterisation
Tests written against the existing system's real behaviour, including the parts that are technically bugs but are now depended on.
Seams and strangling
A boundary put in front of the old system so traffic can be moved slice by slice rather than all at once.
Data migration
Moved continuously and reconciled continuously, so divergence is found the day it happens.
Integration preservation
The systems that depend on this one keep working, including the ones nobody currently owns.
Operability
Logs, traces and alerts on the new path, so the first incident is diagnosable.
Reversibility
Every slice can be routed back to the old system, and that path is tested rather than assumed.
How the programme runs
The same five stages as every engagement, applied to a system that cannot stop.
Diagnose
What the system actually does, what depends on it, and which slice is both valuable and safe to move first.
Decide
The seam, the slice order and the reconciliation approach, written down with what each one risks.
Prove
One slice moved end to end in production, with traffic switched, reconciled and switched back once to prove the route.
Deliver
Slices moved in sequence, each reconciled and stable before the next is scoped.
Hand over
Your team runs it with us watching, then without us — and the old system is decommissioned only once nothing calls it.
What we work with
Modernization is mostly determined by what is already there. This is the range we move systems into.
Target platform
- TypeScript
- Node.js
- Java
- Spring Boot
- Python
Seams
- REST
- GraphQL
- Kafka
- Temporal
Data
- PostgreSQL
- MySQL
- MongoDB
- Elasticsearch
Platform
- AWS
- Azure
- Docker
- Kubernetes
- Terraform
- Datadog
What you get, and when
Handed over as it is produced, not assembled at the end.
- What the system does, characterised from the running system
- The dependency map, including integrations nobody documented
- A slice order with the reasoning, and what would change it
- Source in repositories you own
- Characterisation tests pinning the original behaviour
- A reconciliation report against the system it replaced
- A tested route back to the old system per slice
- Dashboards and alerts on the new path
- A decommissioning record for what has been retired
The rest of our web work
Most web engagements touch two or three of these. If you are not sure which, the consultation is the way in.
Related work
Engagements where the system could not stop while it changed.
What we work towards
ILLUSTRATIVE, pending sign-off. These are the measures a modernization is judged on and the direction they should move — not results from a named engagement. They will carry real figures or be removed before launch.
Time to make a small change
Releases per month
Engineers who can change it safely
Behaviour covered by tests
Rollback for a bad release
Questions about modernization
The ones we are asked most often before a first conversation.
Why not just rewrite it?
How long will this take?
Nobody knows what the system does. Is that fatal?
Can the business keep releasing changes during this?
What happens to the data?
When does the old system get switched off?
Stuck with a system you cannot change or switch off?
Tell us what it does and what depends on it. We will tell you where the first slice is.

