Most organisations have one: the system that runs the business, that nobody fully understands, that everyone is afraid to touch. The instinct is to rewrite it. We have been part of a rewrite that was cancelled after a year with nothing shipped, and part of several incremental modernisations that finished. This post is about the difference, and about where AI tools genuinely helped in the second kind of project and where they were a distraction.

The rewrite that did not ship

A client's order-management system was fifteen years old, written in a stack nobody was hiring for, with business rules nobody had documented. A rewrite was approved: new stack, new data model, feature parity, then cut over. A year in, the new system did most of what the old one did, but "most" was the problem. The undocumented rules kept surfacing, each one delaying parity, and the business could not cut over to a system that handled ninety percent of orders. The project was stopped.

A legacy system is a pile of decisions nobody wrote down. A rewrite has to rediscover all of them before it delivers anything.

The incremental path

The approach that worked, on that system and others since, is to modernise around the edges and move inward: put a facade in front of the old system, route new capabilities and then existing ones through it piece by piece, and retire the old system when nothing calls it any more. Each step ships something. Each step is reversible. The undocumented rules are discovered one bounded area at a time, when that area is moved, rather than all at once.

The incremental path: a facade in front, capabilities moved one bounded area at a time, the old system retired when nothing depends on it.
The incremental path: a facade in front, capabilities moved one bounded area at a time, the old system retired when nothing depends on it.

The order of moves matters. We start with the area that changes most often, because that is where the old system's cost is highest, and with the area that is best understood, because that is where the risk is lowest. Reporting is often first: read-only, valuable, and it forces the data model to be understood without touching the transactions.

Where AI actually helped

Language models are useful in modernisation in three specific ways, and unhelpful in one popular way.

Understanding the code. Explaining what a legacy module does, in prose, from its source, was the single biggest time saver. Engineers used it to build a map of the system in weeks rather than months, and every explanation was checked against behaviour before being trusted.

Recovering the rules. Given a module and the data it touches, the model drafted the business rules it appeared to implement, as a list an analyst could verify with the business. Most were right. The ones that were wrong were wrong in ways the business immediately recognised, which was the point: a draft to argue with.

Generating the boring parts. Data-mapping code between the old and new models, test fixtures from real records, and characterisation tests that captured current behaviour before it was changed. All reviewed, all run, but produced in a fraction of the time.

Where it was a distraction. "Translate the whole system to the new language" produced code that compiled, mirrored the old structure, carried every old defect, and understood none of the intent. It was a faster way to build the rewrite that does not ship.

Where language models sped the work up, and the one use that recreated the rewrite's failure.
Where language models sped the work up, and the one use that recreated the rewrite's failure.

Characterisation tests: the safety net

Before any area is moved, its current behaviour is captured in tests: for these inputs, the old system produces these outputs, including the strange ones. The new implementation must produce the same outputs, or a deliberately changed output with a documented reason. This is what makes the incremental path safe, and it is where model-generated fixtures and test scaffolding paid for themselves.

Security, which legacy systems rarely had

Modernisation is the moment to add the controls the old system never had. The facade is a natural place for authentication, authorisation, rate limits, audit logging and input validation that the old system trusted its callers to do. Data moved to the new model gets classification and access rules. And the AI tools used during the work need their own care: source code and production data are sensitive, so the models used for understanding and generation run under terms that do not retain the inputs, or inside the client's own boundary, and real records used as fixtures are anonymised first.

Purposeful modernisation

The goal is not a new system. It is a business that can change its software again. The incremental path delivers that from the first step. The rewrite delivers it only at the end, if the end arrives. And AI tools, used for understanding, recovery and the boring parts, make the incremental path faster without changing what makes it safe.

  1. Put a facade in front; move one bounded area at a time.
  2. Start with what changes most and what is understood best.
  3. Capture current behaviour in tests before changing it.
  4. Use models to explain code, draft rules and generate mappings and fixtures, all verified.
  5. Do not translate the whole system; that is the rewrite in disguise.
  6. Add the security controls at the facade and in the new data model.