Fix, Refactor or Rewrite: What to Do With an Inherited App
Pavlo Rubanovskyi
· 6 min read

Keep what works, fix local bugs, refactor what slows every change, and rewrite only what is cheaper to replace than to repair — decided part by part after reading the code, not for the whole app at once. Most inherited apps need several of these in different places. Rewriting everything is the exception, not the starting point.
The four verdicts, side by side
| Verdict | Fits when | Risk |
|---|---|---|
| Keep — leave the part as it is | It works, and changes in it stay local | None — nothing changes |
| Fix — change what is broken, keep the structure | The design is sound and the problems are local | Low |
| Refactor — restructure the code, users see no change | Every change is slow or breaks something else | Medium — write tests around the area first |
| Rewrite — replace a part with new code | Repairing it costs more than replacing it | High — everything the old code knew must be rediscovered |
The key word is *part*: these are decisions about parts of an app, not labels for the whole thing. A payment flow can need a rewrite while the onboarding next to it needs nothing at all.
Signs a part should be kept and fixed
- It does what users need, and the bugs are specific: a crash on one screen, a wrong calculation, a layout issue on one device.
- The code is readable enough that someone new can find where a change belongs.
- Changes in it stay in it — fixing one thing does not break two others.
- It builds with current build tools (the toolchain), or can after routine upgrades.
Most of a typical inherited app lands here. Old does not mean bad, and unfamiliar does not mean wrong.
Signs it needs a refactor
- Every small change takes days, because logic is spread across screens, widgets and services.
- The same business rule is implemented in three places and they disagree.
- State — the data a screen shows and changes — is managed several different ways in the same app, layered on top of each other.
- Nobody dares to touch a file, because the last person who did broke checkout.
A refactor keeps behaviour identical while making the next change cheap. It is safest done in small steps, each released, with tests written around the area *before* it is restructured — so you can prove nothing changed for users.
Signs a rewrite is cheaper
A rewrite of a part is justified when one or more of these is true:
1. It cannot be made safe. The logic is tangled with the UI, there are no tests, and the part handles money, authentication or personal data. 2. The foundations are gone. It depends on a framework or package that is abandoned and blocks updating everything else. 3. The product changed underneath it. The part was built for a flow that no longer exists, and is being bent into a new one. 4. It is small. Replacing a few screens is cheaper than learning their history.
Even then, the rewrite should be scoped to the part, priced on its own, and released on its own.
Why "rewrite everything" is the wrong first answer
A new team proposing a full rewrite before reading the code is describing its preferences, not your app. The risks are well known — Joel Spolsky's essay Things You Should Never Do is still the classic account — and they apply to mobile apps as much as anywhere:
- Old code holds knowledge. Each odd-looking condition is usually a bug someone fixed for a real user on a real device.
- Matching every old feature (feature parity) takes longer than anyone remembers. Edge cases, settings, migrations of stored data, push flows, deep links.
- You pay twice. The old app still needs fixes while the new one is being built.
- Nothing ships for a long time. Users and investors see no progress until the new version is complete.
DriveCode builds iOS & Android apps, Flutter-first. When we take over an app, our default is to keep what works and replace only what a review shows is cheaper to replace.
Deciding, part by part
These questions, asked of each area of the app, usually settle it:
| Question | If yes | If no |
|---|---|---|
| Does it do what users need today? | Keep or fix | Rewrite may be cheaper |
| Can a change in it be made without breaking something else? | Fix | Refactor first |
| Is it covered by tests, or can it be before we touch it? | Refactor safely | Add tests, or treat it as a rewrite candidate |
| Does it build with current tools after routine upgrades? | Fix | Check whether its dependencies can be replaced |
| Would replacing it take less time than understanding it? | Rewrite | Keep |
The answers go into a written verdict for each part — keep, fix, refactor or rewrite, and why — and the work is split into modules with a fixed price for each. What we look at to get there is in what we check before taking over an app.
If the app is native: moving to Flutter is a different decision
Moving a native iOS and Android app to Flutter is a rewrite by definition, but it is a planned one with its own reasons: one codebase instead of two, one team instead of two. It is not a verdict on the quality of the native code.
We do it core first: the Flutter core ships as an MVP while the native apps keep shipping; the rest follows in regular updates, most-used first. More in how to migrate a native app to Flutter without a feature freeze, what the move costs, and on the migration service page.
Keep shipping while you decide
Whatever the verdict, releases should not stop. In practice the first module of work is often the least glamorous: getting the app to a state where a routine update can be built and published from your own accounts. After that, fixes and refactors ship as regular updates, and any rewrite of a part is released when that part is ready — not when the whole app is.
Questions people ask
Is a full rewrite ever the right call? Yes, when the app is small, when nearly every part fails the questions above, or when the product has changed so much that little of the old app still applies. It should be a conclusion from reading the code, not an opening offer.
How do I know a team isn't just selling me a rewrite? Ask for the verdict part by part, with reasons. A team that has read your code can name specific files and flows; one that has not will talk about "technical debt" in general.
Can we refactor and add features at the same time? Yes, in different parts of the app, or by refactoring an area right before a feature is added to it. What you should avoid is a long refactor with no releases.
How much does each option cost? It depends on the size of each part, which is why we set a fixed price per module after we review your app. Projects start from $10K.