Skip to content
cirlume.
Menu
← All insights

Software engineering · · 6 min read · By the Cirlume studio

Rebuild or refactor: modernising a legacy system safely

How to decide between rewriting a legacy system and replacing it piece by piece, and how to move data safely.

An old beige desktop computer and a modern laptop side by side, joined by a coral cable

Every organisation that has run software for long enough has a system people are afraid to touch. It works, mostly. It holds years of data and rules nobody fully remembers. Changes take weeks, the people who built it have moved on, and the technology it runs on is getting harder to host and hire for.

The tempting answer is to start again. A clean rewrite promises to fix everything at once. Sometimes it is the right call. More often, the safer route is to replace the old system one piece at a time while it keeps running. This article covers how to tell the difference and how the gradual approach works in practice.

Why full rewrites go wrong

A rewrite looks simpler than it is because the old system’s behaviour is mostly invisible. Years of small fixes encode decisions about edge cases, odd customers and regulatory changes. Most of them are not written down anywhere except the code.

The usual problems:

  • The target keeps moving. The business can’t stop for a year while the new system is built. Changes go into the old system, and the new one has to catch up.
  • Nothing is delivered until everything is. Users see no benefit until the switch, so the project is judged on promises for most of its life.
  • The switch is one large risk. Data migration, retraining and every new bug arrive on the same day.
  • Hidden behaviour is found late. Someone discovers in the final weeks that a report or an overnight job depended on something the new system doesn’t do.

None of this makes rewrites impossible. It makes them expensive to get right, and harder to stop halfway if they go badly.

The strangler fig pattern

Martin Fowler named this approach after the strangler fig, a plant that grows around a host tree until it can stand on its own. In software, a new system grows around the old one. Parts of the old system are replaced one at a time until nothing is left of it, or what remains is small enough to leave alone.

The core idea is that the old system keeps running throughout. At each step, a defined piece of behaviour moves to the new system, and users get the benefit then rather than at the end.

This needs some temporary code: routing that decides which system handles a request, and syncing that keeps data consistent between them. That work is thrown away eventually. It is the price of lower risk and earlier value, and it should be budgeted for rather than treated as waste.

Old chest of drawers with two drawers replaced by new ones (illustration)

Carve out one workflow at a time

Choose pieces by workflow, not by technical layer. Rewriting “the database layer” or “the front end” delivers nothing on its own. Moving “raising and approving a purchase order” to the new system gives a team something better to use.

A good first workflow is:

  • Valuable. It is used often, or it is where the old system causes the most pain.
  • Reasonably self-contained. It reads and writes a limited set of data, with clear edges.
  • Not the hardest part. Leave the most tangled logic, often billing or scheduling, until the team understands the old system better.

Before moving a workflow, write down what it actually does today. Watch people use it, read the code paths, check scheduled jobs and reports that depend on its data. This is slow, and it is where most of the surprises turn up while they are still cheap to deal with.

Running old and new side by side

There are a few ways to route work between the two systems:

  • At the front. A proxy or gateway sends some requests or screens to the new system and the rest to the old one. Users may see two interfaces for a while.
  • Through an API layer. Put an API in front of the old system first, then point new clients at it. Behind the API, individual operations move to the new system without the clients knowing.
  • By group. Move one team, region or customer type at a time. This limits the effect of mistakes and gives you a group of real users to learn from.

For risky logic, such as calculations, you can run both systems on the same input and compare the results before the new one is trusted. Differences point to either a bug in the new code or a rule nobody knew about. Both are worth finding before the switch.

Plan each step so it can be reversed. If a moved workflow goes wrong, routing it back to the old system should be a configuration change, not an emergency.

Data migration

Data is usually the hardest part, and it deserves its own plan.

  • Decide who owns each piece of data at each stage. At any moment, one system should be the source of truth for a given record. Two systems both accepting edits to the same data, with sync in both directions, is where corruption starts.
  • Profile the data early. Run queries against a copy of the old data to find duplicates, missing values, free text where structure was expected and records that break today’s rules. Decide with the business how each case is handled.
  • Make migration repeatable. Write it as a script that can be run many times against fresh copies, not a one-off. Rehearse it until it runs cleanly and you know how long it takes.
  • Reconcile after every run. Count records, total key figures and spot-check individual cases in both systems. Sign-off should rest on these checks, not on the script finishing without errors.
  • Keep the old data readable. Even after the old system is retired, someone will need to look up a historical record. Archive it in a form that can still be queried.

When a rewrite is justified

A full rewrite is a reasonable choice in some situations:

  • The system is small. If it can be rebuilt in a few months by a team that understands it, the overhead of gradual replacement may cost more than it saves.
  • The platform is ending. If the old system can’t be hosted, secured or supported for much longer, there may not be time to replace it piece by piece. Even then, moving data and workflows in stages is often possible.
  • The business has changed. If the way the organisation works has moved far from what the system models, carrying its structure forward may be the wrong goal.
  • There is nothing to route around. Some systems are a single block with no clear seams and no way to intercept requests. Creating those seams can be more work than starting again.

If you do rewrite, take what you can from the gradual approach. Document existing behaviour first, migrate data in rehearsed runs, and release to one group before everyone.

The trade-offs

Gradual replacement takes longer to finish than a rewrite promises to. You run two systems for a time, with the hosting, support and temporary code that involves. It needs discipline to keep going once the most painful parts are fixed, or you end up with two half-systems permanently.

In exchange, each step delivers something, each risk is smaller, and the project can stop at any point with the organisation better off than before.

When to bring in help

If you have a system the business depends on and nobody wants to change, the first step is usually an assessment: what it does, where the seams are and which workflow to move first. We can help map the existing behaviour, put an API layer in front of it, plan and rehearse the data migration, and move workflows across one at a time while the old system keeps running.

Sources

What’s changing

Shifts to plan for.

Dates that affect software engineering work, checked against the official sources.

  1. August 2026

    Google Play targets Android 16

    New apps and updates for phones and tablets must target API level 36. Extensions can be requested until 1 November 2026.

  2. April 2026

    Node.js 20 reaches end of life

    The Node.js project stopped security fixes for version 20 on 30 April 2026, so services still on it need a move to 22 or 24.

  3. April 2026

    App Store requires the iOS 26 SDK

    Since 28 April 2026, uploads must be built with Xcode 26. Apps can still support older iOS versions; only the build tools changed.