Most organisations have a system that is critical, poorly understood and frightening to change. The instinctive response is to rewrite it. That is usually the highest-risk path available, and it fails for a consistent reason: the existing system encodes years of accumulated business rules that nobody has documented, and the rewrite discovers them one production incident at a time.

Understand before you touch anything

Documentation for old systems is unreliable — it describes what someone intended years ago. Actual behaviour is authoritative, so we establish it empirically: reading the code paths that matter, examining the data for patterns the code does not explain, and watching how people actually use it, including the workarounds.

Workarounds are particularly informative. They mark where the system fails its users, and they are often the requirements nobody thought to state.

Get a safety net first

Before changing behaviour, get tests around it. Not comprehensive coverage — that is not realistic on a large legacy codebase — but characterisation tests around the paths you intend to touch, capturing what the system currently does, including its bugs.

The point is not that the current behaviour is correct. It is that you will know when you have changed it.

Wrap it in an interface

Rather than modifying the old system, put an API layer in front of it. New applications integrate with the interface, not the legacy internals. This immediately stops the problem getting worse, because new work no longer adds dependencies on the old structure.

It also creates the seam that makes incremental replacement possible later.

Move functionality out one piece at a time

With the interface in place, functionality can be migrated behind it. Route a single capability to a new implementation while everything else continues against the old system. Verify in production, then move the next piece.

Progress is slower than a rewrite on paper. It is also reversible at every step, which is the entire point — a failed increment costs days, a failed rewrite costs the project.

Let the old system shrink

Over time the legacy system handles less and less. Eventually what remains is small enough to replace safely, or small enough that leaving it running is genuinely fine.

The latter outcome is underrated. Not every legacy system needs to die. One that has been reduced to a well-understood component behind a clean interface has stopped being a problem.

When a rewrite is justified

Occasionally it is the right call — when the platform is genuinely unsupportable, when a security posture cannot be remediated, or when the system is small enough that a rewrite is a matter of weeks. The test is whether you can describe the existing behaviour completely. If you cannot, a rewrite is a bet on discovering it under pressure.

Legacy Architecture Refactoring