ABAkash Bansal

Home / Notes

Guide · Tech choices & rescues

Rewrite vs refactor: how a founder should decide when the code is slowing everything down

Rewrite vs refactor for founders: a scorecard to decide, why full rewrites stall, the strangler fig middle path, and the questions to ask your developer.

Short answer

Refactor by default: improve the code in small steps while the product keeps shipping. Replace one part at a time when a component is wrong but the rest works. Rewrite only when the data model, the platform or the core architecture is wrong for the business, and even then rebuild in slices behind the live app instead of freezing features for months.

Rewrite or refactor: what's the actual choice?

Refactoring means improving the code's structure without changing what the app does, in small steps, while you keep shipping. Rewriting means replacing the code with new code, usually starting again, while the old app keeps running until the new one can take over. There's a third option most founders aren't offered: replace one part at a time, behind the live app, until the old part can be switched off.

The choice matters because it's mostly a business decision dressed up as a technical one. A rewrite stops feature work for weeks or months. A refactor keeps you moving but may not fix a foundation that's wrong. This guide gives you a way to tell which you're facing, and the questions to ask whoever is proposing it.

My background for this: about six years building and running production software, including five years as Head of Technology at Urban Culture, an at-home salon marketplace with four apps and 500K registered users. Running the same products for years teaches you which problems go away with a cleanup and which ones are in the foundations.

Why is a full rewrite so risky?

A full rewrite is risky because you throw away knowledge you can't see. The old code holds years of small fixes: the edge case for customers with two accounts, the timezone bug that only shows up during a holiday sale, the payment retry that support asked for. None of that is in the spec. The new version has to rediscover each one, usually from angry users.

The classic warning is Joel Spolsky's essay "Things You Should Never Do, Part I". He describes Netscape's decision to rewrite its browser from scratch as "the single worst strategic mistake that any software company can make", because it left almost three years between major releases while competitors moved. The details are from 2000, but the shape repeats in startups today: the team stops shipping, the old app gets no improvements, and the new one is always "a few weeks away".

There's also a human bias. Reading code is harder than writing it, so every developer finds someone else's code worse than it is. "This code is a mess" is often true and still not a reason to start over.

When is refactoring the right call?

Refactor when the app does the right things in a messy way. Martin Fowler, who wrote the standard book on it, defines refactoring as changing a program's internal structure without changing its observable behaviour. In practice that looks like:

Refactoring is cheap to start, easy to stop, and you keep shipping features alongside it. That's why it's the default. Signs it will be enough: the data model matches how your business works, users mostly get what they need, and the pain is speed of change, not capability.

When do you actually need a rewrite?

Rewrite when the foundation is wrong for the business, because everything sits on it. The clear cases:

Even then, a rewrite rarely means rewriting everything. The screens, copy, flows and lessons from real users usually carry over. Often it's the backend and data model that get rebuilt, and the old frontend becomes the specification.

The rewrite vs refactor scorecard

Score your app honestly against each row. If most of your answers are in the first column, refactor. If any answer in the last column is about data or ownership, plan a rebuild.

QuestionRefactorReplace one partRewrite or rebuild
Does the data model match the business?YesYes, except one areaNo, a core concept is missing or wrong
What's the main pain?Changes are slow or scaryOne component is costly, slow or limitedYou can't build what customers need
Can you add tests?YesAround that component, yesNot without restructuring everything
Is the platform the limit?NoOne service or vendor isYes, the whole platform is
Do you own and control the code?YesYesNo, or not in usable form
Can the business pause features?Not neededBriefly, for that areaMust, unless you rebuild in slices

The middle path: replace the app one piece at a time

The safest way to do most "rewrites" is to never do a big-bang switch. Fowler calls this the strangler fig approach, after a vine that slowly grows around a tree: you build new parts around the old system, route traffic to them one area at a time, and switch the old parts off as they're replaced. A related technique, branch by abstraction, does the same inside one codebase.

Replacing an app one piece at a time Three stages. First, the old app handles everything. Second, a router sends one area, such as payments, to a new service while the old app handles the rest. Third, most areas run on new code and the old app is switched off. Month 0 Month 2 Month 5 Old app Old app New: payments Old: retired New: core New: payments
Each step ships to real users, so you learn early and can stop at any point. The months are illustrative.

A real example from my own work: at Urban Culture we replaced Google's Distance Matrix and geocoding calls with our own geolocation service. We didn't rewrite the marketplace to do it. One component was replaced, the rest of the apps kept running, and the result was about 80% lower cost for that piece with accuracy held. The full write-up covers the techniques, including how to compare old and new results before switching. The same thinking applies to reporting: the Firestore → BigQuery pipeline gave the business SQL reporting without moving the apps off Firestore.

The rules that make this work:

  1. Pick the part with the clearest pain and the cleanest edges first (payments, search, notifications, reporting).
  2. Run the new part alongside the old one and compare results before you switch traffic.
  3. Keep a switch to send traffic back to the old part for a while.
  4. Delete the old part once nothing uses it. A replacement that leaves both running forever doubles your maintenance.

What about vibe-coded apps?

Vibe-coded apps feel like rewrite candidates more often than they are. When an app built with Lovable, Bolt or Cursor hits a wall, the usual causes are missing security rules, no tests and duplicated code, and all three can be fixed in place. The real rewrite trigger is the same as for any app: a data model that doesn't fit the business.

Before deciding, run the security checks first, because those are urgent either way. The full checklist and a scorecard for "keep prompting, rescue or rebuild" are in the vibe-coded app guide. If you're still choosing tools, Lovable vs Claude Code vs Cursor covers when each one stops being enough.

Questions to ask a developer who proposes a rewrite

A good engineer welcomes these. Vague answers are a signal to get a second opinion.

  1. What specifically can't we do with the current code, in business terms?
  2. Is the problem the data model, the platform, or the code's structure? Show me.
  3. What would a refactor of the worst area look like, and why isn't it enough?
  4. Can we replace one part first and ship it to users? Which part?
  5. What do we stop shipping during the work, and for how long?
  6. How will we know the new version handles everything the old one did?
  7. Will everything stay in our repository and our cloud accounts?

More questions for evaluating any developer are in how to vet a developer.

A simple decision checklist

If you'd like an outside engineer to look before you commit, I start with a written diagnosis of what's wrong, what's risky and what's fine, then a fixed quote for whichever path makes sense. Here's how I work. If the diagnosis says a refactor will do, that's the answer you'll get.

Questions founders ask

What is the difference between refactoring and rewriting code?

Refactoring changes how code is structured without changing what it does, in small steps that keep the app working. Rewriting replaces the code with new code, usually from scratch, and the old version keeps running until the new one can take over. Refactoring is lower risk; rewriting can fix deeper problems but freezes progress while it happens.

How do I know if my app needs a rewrite?

Look at the foundations, not the mess. A rewrite is justified when the data model doesn't match how the business works, the platform can't do what you need, or the code can't be tested or changed safely at all. Messy code, old libraries or a developer's dislike of the previous developer's style are reasons to refactor, not rewrite.

How long does a software rewrite take?

Longer than the estimate, almost always, because the old app holds years of small fixes nobody wrote down. A rewrite of an MVP-sized product is typically weeks to a few months of focused work; a mature product can take much longer. Rebuilding in slices behind the live app keeps you shipping and limits the damage if it runs over.

Should I rewrite my vibe-coded app?

Only if its data model is wrong for the business. Most vibe-coded apps that feel broken have fixable problems: missing security rules, no tests and duplicated code. Fix those in place first. If a core concept is missing, such as teams when you sell to teams, rebuild the backend and keep the screens and copy as the spec.

Why do developers always want to rewrite?

Reading someone else's code is harder than writing your own, so old code looks worse than it is. Joel Spolsky made this point in his well-known essay on Netscape's rewrite. A good engineer can explain, in business terms, what a rewrite fixes that refactoring can't. If they can't, ask for a second opinion.