Legacy Modernization Without a Big-Bang Rewrite
Software

Legacy Modernization Without a Big-Bang Rewrite

Serve Innovate 8 min read

The proposal is familiar: the old system is unmaintainable, nobody understands it, so we rebuild it properly and switch over. Two years later the replacement is incomplete, the original is still in production, and both are being maintained.

Why big-bang rewrites fail so reliably

The failure is structural rather than a matter of execution quality.

  • The old system encodes years of undocumented business rules. The peculiar handling of a particular customer category exists because of a contract signed in 2014. Nobody remembers, and it is not written down anywhere but the code.
  • The business does not stop. While the replacement is built, the original keeps acquiring features — so the target moves for the entire duration of the project.
  • Nothing ships until everything ships. No feedback, no value delivered, and no way to demonstrate progress except a percentage-complete figure that means very little.
  • Two systems must be maintained from the moment work begins, dividing the team’s attention exactly when it can least afford it.

The pattern generalises: the risk grows with the square of the scope, while the benefit grows linearly.

The strangler fig pattern

The alternative is to replace the system gradually while it remains in production. A routing layer sits in front of the legacy application; each piece of functionality is rebuilt and the router is switched to send that traffic to the new implementation. The old system shrinks until it can be removed.

The properties that make this work:

  1. Value ships continuously. Each migrated slice is live and useful on its own.
  2. Risk is bounded per slice. A failed migration affects one capability and can be routed back in minutes.
  3. Business rules are discovered incrementally, in the context of the specific feature being moved, rather than all at once as an archaeology exercise.
  4. The project can stop at any point and still have delivered value — which matters, because these programmes frequently lose funding partway through.

Choosing the first slice

The first migration establishes whether the approach is viable and whether stakeholders will keep funding it, so choose for learning rather than for impact.

Good first candidates share three traits: clear boundaries with few dependencies on the rest of the system, low blast radius if something breaks, and enough real usage to prove the routing and data paths under load. Reporting, notifications, search and file handling are frequently good choices.

Bad first candidates: anything touching payments, anything on the critical path of the primary transaction, and anything that reads and writes a large share of the shared data model. These are usually migrated last, not first.

The first slice is a test of the migration mechanism, not of the team’s ambition.

The database is the hard part

Application code can be replaced in slices with reasonable confidence. The shared database is where incremental migration becomes genuinely difficult, because both systems need consistent access to the same data during the transition.

The workable approaches, roughly in order of preference:

  • Shared database, clear ownership. Both systems read the same tables, but exactly one system may write to each table. Simple and effective, provided ownership is enforced rather than merely agreed.
  • Change data capture. The new system maintains its own store, kept in sync by streaming changes from the legacy database. More infrastructure, but it decouples the schemas — usually worth it for longer migrations.
  • Dual writes. Write to both systems on every change. Straightforward to describe and difficult to make correct, because partial failures leave the two stores divergent. Use only with reconciliation in place.

Whichever is chosen, decide early which system is authoritative for each entity and write it down. Ambiguity there produces data-integrity incidents that cost more than the migration.

When a rewrite is actually justified

Incremental modernisation is the default, not a rule. A full rewrite is defensible in a small number of situations:

  • The platform is genuinely end-of-life — an unsupported runtime with no upgrade path and open security exposure.
  • The system is small enough to rebuild in a few months, where the coordination cost of incremental migration exceeds the risk of replacement.
  • The business model has changed such that the old system solves a problem the company no longer has.
  • The legacy system cannot be instrumented or tested at all, making incremental verification impossible.

Note that “the code is bad” and “the team dislikes the technology” are not on this list. Both are real costs, and neither justifies the risk on its own.

The short version

Put a routing layer in front of the legacy system, migrate a low-risk capability first to prove the mechanism, decide database ownership explicitly, and keep shipping slices until the old system is small enough to retire.

It is slower than a rewrite on paper and faster in practice, for the simple reason that it does not require the organisation to stop and wait for two years to find out whether it worked.

Serve Innovate

We design, build, market and scale digital experiences — e-learning, websites, campaigns and custom software — for organizations that want one accountable partner rather than four.

Work with us

Frequently asked

What is the strangler fig pattern?
An incremental modernisation approach in which a routing layer sits in front of a legacy system and individual capabilities are rebuilt one at a time, with traffic switched to each new implementation as it becomes ready. The legacy system shrinks until it can be retired. Its advantage is that value ships continuously and risk stays bounded to one capability at a time.
Is it cheaper to rewrite or modernise a legacy system?
Incremental modernisation is usually cheaper in total cost despite appearing slower, because a rewrite requires maintaining two systems for its entire duration while delivering nothing until it completes. Rewrites also routinely overrun, since the old system encodes undocumented business rules that are only discovered when something breaks after cutover.
How do you handle the database during incremental migration?
The most reliable approach is a shared database with strictly enforced write ownership — both systems read the same tables, but exactly one may write to each. Change data capture is the better option for longer migrations because it decouples the schemas. Dual writes are simple to describe and hard to make correct, since partial failures leave the two stores divergent.
Which part of a legacy system should be migrated first?
A capability with clear boundaries, few dependencies, a small blast radius if it fails, and enough real traffic to exercise the routing and data paths properly. Reporting, notifications, search and file handling are common choices. Payments and the primary transaction path are migrated late, once the mechanism is proven.
When is a full rewrite the right decision?
When the platform is genuinely end-of-life with no upgrade path and open security exposure, when the system is small enough to rebuild in a few months, when the business model has changed so the system solves a problem you no longer have, or when the code cannot be instrumented or tested at all. Disliking the codebase or the technology is a real cost but not sufficient justification on its own.
Read next

Ready to build something remarkable?

Tell us what you are trying to achieve. We will come back within one business day with a clear, honest view of how to get there.