Quick answer: Refactor when the system still does the right job and the problems are in how the code is organised, how fast it runs or how hard it is to change. Rebuild when the business has outgrown what the system was designed to do, when the underlying technology is unsupported, or when every change breaks something else. In most cases the safest path is a gradual one: replace the system piece by piece while the old one keeps running.
Most businesses that have been around for more than a few years have at least one system everyone is slightly afraid of. It might be a custom order management tool written in 2006, an intranet built on an old version of PHP, or a database application that only one person truly understands. It works, mostly. But changes are slow, bugs keep returning, and nobody wants to touch it before a busy season.
Legacy system modernization is the work of bringing that kind of system up to date. The hard part is not the code. It is deciding how far to go.
What makes a system “legacy”
Age alone does not make software a problem. A ten year old system that is well written, documented and running on supported technology can be perfectly healthy. A system becomes a legacy problem when some of these are true:
- The platform is unsupported. For example, it runs on a PHP version that no longer gets security fixes (PHP 5.4 reached end of life in September 2015), an old Windows Server release, or a framework whose developers have moved on.
- Knowledge is concentrated. One developer, or one departed contractor, understands how it works.
- Changes are expensive. Small requests take weeks because every change has side effects.
- It does not connect to anything. The business has moved to cloud tools, but the old system cannot share data except through manual exports.
- It cannot run on modern devices. Staff need to use it on a phone or tablet, and it was built for a desktop browser of its time.
- Hosting is fragile. It depends on one specific server that nobody dares to upgrade.
If two or three of these sound familiar, it is time to plan, even if nothing is broken today.
The three main options
1. Refactor
Refactoring means improving the internal structure of the code without changing what it does for users. Typical refactoring work includes:
- Splitting large, tangled files into smaller, clearer parts
- Removing duplicated logic
- Adding automated tests around important features
- Updating libraries and the language version
- Moving configuration and passwords out of the code
- Cleaning up the database, adding indexes and removing unused tables
When refactoring makes sense:
- The system still matches how the business works
- The core data model is sound
- The technology stack is still supported, or can be upgraded in place
- The main complaints are speed, stability and the cost of changes
Refactoring is lower risk because the system keeps running throughout and users notice little change. The downside is that it rarely fixes deep design problems. If the original design assumed one warehouse and you now have four, tidying the code will not solve that.
2. Rebuild
A rebuild means writing a new system that replaces the old one, usually with a fresh design and modern technology. This is the option people instinctively reach for, because it promises a clean start.
When a rebuild makes sense:
- The business model has changed and the old system fights it at every step
- The platform is obsolete and upgrading is effectively a rewrite anyway
- Security problems are built into the design
- The data model is wrong for how you work now
- You need capabilities, such as an API for other systems, that the old design cannot support
The risk with a full rebuild is well known among developers. Old systems contain years of small business rules that nobody wrote down: a discount that applies only to one customer group, a rounding rule for VAT, an exception for orders placed on a Sunday. A rebuild that misses them causes real problems after launch. Rebuilds also tend to take longer than planned, and the old system still needs maintaining in the meantime.
3. Replace with an existing product
Sometimes the right answer is to stop running custom software at all. If an off the shelf product or a hosted service now does what your system was built for, moving to it may be cheaper over time. The trade-off is that you adapt your process to the product rather than the other way round. We cover that decision in more detail in custom software vs off the shelf.
A middle path: replace it piece by piece
For many businesses, the best answer is neither a big refactor nor a big rebuild. It is a gradual replacement, sometimes called the strangler pattern, a term the software writer Martin Fowler made popular.
The idea is simple:
- Put a layer in front of the old system, such as a new web front end or an API, that receives requests.
- Build one new module, for example customer records or quoting, in the new system.
- Route requests for that feature to the new module, while everything else still goes to the old system.
- Repeat, one area at a time, until the old system handles nothing and can be switched off.
This approach has real advantages:
- The business gets value early, from the first module, rather than waiting for a big launch
- Each step is small enough to test properly
- If a new module has a problem, you can route traffic back to the old one
- Hidden business rules surface one area at a time, not all at once on launch day
It does need a way for the old and new systems to share data during the transition. That usually means building an API around the old database or setting up a regular sync. If APIs are new to you, our explainer on what an API is is a good starting point.
How to decide: questions to ask
Before choosing, get honest answers to these questions.
How well does the system match the business today?
List the main processes the system supports. For each, ask whether it still matches how staff actually work. If people keep spreadsheets alongside the system to get their jobs done, that is a sign of drift.
What is the state of the code and data?
Ask a developer who did not write the system to review it. They should look at code structure, test coverage, dependencies, database design and security. An outside view is valuable because the original authors are often too close to it.
Is the platform supported?
Check the versions of the language, framework, database and operating system against their official support dates. PHP 7.0 arrived in December 2015 with large speed gains, but older applications often need work before they run on it. Unsupported software is a security risk, and that alone can force the decision.
What does it cost to keep things as they are?
Count the hidden costs: hours spent on workarounds, manual data entry between systems, lost sales from downtime, and developer time spent on fixes rather than improvements. This number is often larger than people expect, and it is the real comparison for any modernization budget.
What happens if it fails?
A system that handles payroll or orders carries more risk than an internal reporting tool. Higher risk usually favours gradual change over a big switch.
Planning the work
Whichever route you take, a few practices reduce risk.
Document the business rules first
Interview the people who use the system every day. Ask what it does in unusual cases. Record every rule you find. This document is valuable even if you only refactor.
Add tests before changing anything
Automated tests that capture current behaviour let developers change the code with confidence. Even a modest set covering the most important workflows is far better than none.
Clean and map the data early
Data migration is usually the hardest part of a rebuild. Old databases often contain duplicates, inconsistent formats and fields used for purposes they were never meant for. Start cleaning and mapping early, and run trial migrations well before launch.
Run old and new in parallel
Where possible, run the new system or module alongside the old one for a period and compare the results. Differences reveal missed rules.
Plan for training
Staff who have used a system for years have built habits around it. Involve them in testing and give them time to learn the new tools.
Warning signs that you are on the wrong path
- The rebuild has been “nearly finished” for many months
- Nobody can explain which features the new system must have on day one
- The old system is still being extended while the new one is being built
- The new system copies the old one screen for screen, including its problems
- Refactoring keeps uncovering design issues that cannot be fixed without a rewrite
If you see these, stop and reassess. Changing course midway is cheaper than finishing the wrong project.
FAQ
Is it always cheaper to refactor than rebuild?
Not always. Refactoring is cheaper per step, but if the design is fundamentally wrong you can spend a lot improving something that still does not fit. A short technical review usually makes the answer clear.
How long does a legacy rebuild take?
It depends entirely on the size of the system and how much hidden logic it contains. Breaking the work into modules gives you a more reliable estimate for each stage.
Can we move a legacy system to the cloud without rewriting it?
Often, yes. Moving the existing application to cloud servers as it is can improve reliability and backups. It does not fix the code, but it can buy time while you plan the next step.
Talk it through
Deciding how to modernise an ageing system is easier with an outside view. If you want an honest review of your options, see our custom development services.