
Published by ANAWAZ
Choose a modernisation approach by diagnosing the constraint first. A system with unsupported infrastructure, one with tangled code and one with obsolete business rules need different treatments. Refactoring, replatforming and rewriting are tools; none is a complete strategy without migration, operational ownership and acceptance criteria.
A practical decision guide
| Situation | Starting point | What to verify |
|---|---|---|
| Sound behaviour, obsolete hosting | Replatform | Test compatibility, performance and recovery. |
| Useful system, difficult change | Refactor | Add characterisation tests and improve high-value boundaries. |
| Fundamental mismatch | Rewrite or staged replacement | Budget for business-rule discovery and data migration. |
Diagnose before you choose
Four questions separate the cases, and they are worth answering with evidence rather than opinion.
Is the business logic still correct? Not elegant — correct. Does the system still encode how the organisation operates, including the exceptions and edge cases that took years to get right? If yes, that logic is an asset and throwing it away is expensive. If the business changed direction three years ago and the software never followed, you are maintaining a model of a company that no longer exists.
Is the platform still supported? Runtime versions, frameworks, database engines, operating systems, hardware. Unsupported means no security patches, and that converts a technical concern into a risk that belongs on the risk register. It also determines urgency independently of everything else.
Can the code be changed safely? The practical test: how long does it take to make a small change and be confident it broke nothing? If a one-line change takes two weeks because nobody can predict its blast radius, the problem is changeability, and changeability is what refactoring addresses.
Is the data model still true? Data outlives applications. If the schema still describes your entities sensibly, you have a foundation. If it has been bent for a decade — fields repurposed, meanings drifted, a column called status_2 that four departments read differently — then the data model is the real project, and no amount of new front-end will fix it.
Answer those four and the treatment usually picks itself.
What the three options mean
Refactor in place
Keep the system, the platform and the data. Improve the internal structure: break up the parts that resist change, add tests, remove dead paths, extract the tangled areas into something with clear boundaries. Behaviour stays the same by definition — if behaviour changes, it is not refactoring, it is a change with the safety net removed.
Refactoring produces no visible difference to users. That is its strength and its political weakness: it is the cheapest option and the hardest to fund, because the deliverable is “the same thing, but now we can change it”.
Replatform
Move the system to a supported, better-operated foundation with limited changes to the application itself. New runtime version, containerised deployment, managed database, modern CI, proper observability. The code is largely the same code; where it must change, it changes because the platform demands it, not because someone wanted to improve it.
This is the option most often skipped and most often correct. It removes the urgent risk — unsupported components, fragile deployment, no visibility into failures — without betting the business on a multi-year programme.
Rewrite
Build a replacement. New codebase, usually new architecture, often new data model. The old system runs until the new one takes over, which means for a long stretch you fund and staff both.
A rewrite is the only option that lets you change the fundamental shape of the system. It is also the only one where you can end up, after eighteen months, with nothing in production and a competitor who shipped.
How total rewrites fail
They rarely fail through incompetence. They fail through a small number of predictable mechanisms.
The knowledge is in the code, not in anyone’s head. Twenty years of accumulated conditionals encode real decisions: a regulatory requirement, a major customer’s contractual exception, a workaround for a supplier’s broken file format. Most are undocumented and the people who added them have left. A rewrite that specifies from current documentation reproduces the documented system, and the undocumented one is the one the business runs on.
The old system does not stand still. Regulation changes, a tax rate moves, a partner changes their API. Those changes must be made to the live system, and then made again in the replacement. The target moves for the entire duration of the project, and the longer the project, the more of its budget goes on catching up.
Nothing ships until everything ships. Value arrives only at cutover, so every month before that is pure cost with no feedback. You do not find out whether the new architecture works under real load, with real data, in the hands of real users, until you have spent most of the money.
Scope grows because it is new. Every stakeholder has a list of things the old system never did. A rewrite feels like the moment to include them. The replacement is now not a replacement, and the comparison baseline is gone.
Two systems, one team. Whoever knows the old system best is needed to specify the new one and to keep the old one alive. In practice they do neither well.
None of this makes rewrites wrong. It makes an unstaged rewrite of a large, live, business-critical system a poor bet. The staged alternative is covered in our piece on the strangler pattern versus a full rewrite.
When refactoring in place wins
Refactor when the logic is right, the platform is supported, and the problem is that change has become slow and frightening. The symptoms are specific: estimates inflate for small changes, the same modules break repeatedly, releases require a weekend, and new developers take months to become useful.
The order matters. Add characterisation tests around the area you intend to change first — tests that assert what the system currently does, not what it should do. Without them you have no way to tell a refactor from a regression. Then restructure behind those tests, one area at a time, prioritised by where the change requests land rather than by which code offends most.
Refactoring works badly as a standalone programme with its own budget and end date. It works well as a standing allowance attached to feature work: every change to a bad area leaves it slightly better.
When replatforming is the honest middle
Replatform when the application is fine but the ground under it is not: an out-of-support database, a server nobody dares reboot, a deployment process that lives in one person’s memory, no logging worth the name.
The discipline that makes replatforming succeed is refusing to improve the application at the same time. Move it, prove it behaves identically, then decide what to change. Teams that bundle “and while we are in there” into a platform migration lose the one property that makes it safe: when something breaks, you know it was the platform, because nothing else changed.
Replatforming also buys information. Running the system with real observability for a few months tells you which parts are hot, which code is never executed, and where the real constraints are. That evidence makes any subsequent rewrite decision far better informed than a decision made from the current state of anxiety.
When a rewrite is right
There are honest cases:
- The platform is dead. No supported runtime, no available skills, no path forward at any price. Replatforming has nowhere to go.
- The business model changed. The system encodes a way of operating the organisation has abandoned. You are not replacing software, you are building different software.
- The system is small. A few months of work with a well-understood scope carries little of the risk described above.
- The data model is the problem. When the schema itself is wrong, incremental fixes propagate through every layer above it and are often larger than a rebuild.
Even in these cases, stage the delivery. “Rewrite” describes where you end up, not how you get there.
The factors that decide it
- Business risk of downtime. If an hour offline stops revenue or breaches an obligation, options requiring a hard cutover cost far more than their build estimate suggests.
- Test coverage. Meaningful automated tests make refactoring viable. Their absence makes every option slower, and building them is often the correct first project regardless of which route you choose.
- Domain knowledge locked in code. The more behaviour exists only as code, the more a rewrite is really an archaeology project with a software deliverable attached.
- Team capacity. Can you staff a replacement without starving the system that pays the bills? If not, the honest answer is a smaller intervention.
- Data gravity. Volume, history, retention obligations and the number of downstream consumers all determine how hard it is to move. Data is usually the thing that fixes your options, not the code.
- Regulatory exposure. Audit trails, retention rules and validation requirements constrain how you may migrate and how much you must prove before switching.
A short decision checklist
- Which components are out of support, and what is the deadline?
- How long does a small change take today, from request to production?
- Where do change requests land in the codebase?
- What behaviour exists only in code, with nobody alive who can explain it?
- Does the data model still describe the business correctly?
- What downtime can the business absorb, and at what cost per hour?
- Can we fund two systems at once for the realistic duration, not the estimated one?
- What is the smallest change that removes the largest risk?
That last question is the one worth returning to. It frequently produces a different answer from the one the programme was named after, and it is closely related to the build versus buy question, which deserves asking again for any capability that has become commodity since the system was written.
Worked example
An internal application may be reliable but tied to an unsupported server. A hosting and runtime upgrade could address that risk without a rewrite. If the same application cannot represent today’s approval rules, moving it to the cloud leaves the business problem intact. Diagnose both the operating risk and the behaviour gap before choosing a route.
This is an illustrative planning scenario, not a client case study.
Turn the decision into a plan
Write down the outcome you need, the evidence that would show success, the unresolved risks and the person responsible for the next decision. Use a bounded first step to test the difficult assumptions before committing to a larger programme.
ANAWAZ can help you scope the engineering work through our Legacy application modernization. Tell us about your current systems and the result you want to achieve.
