Unico Connect
Rebuild vs refactor decision framework and scorecard for founders
Back to Blog
EngineeringJuly 6, 202616 min read

Rebuild vs Refactor, How to Decide

Vasim Gujrati

Vasim Gujrati

Solutions Architect, AI & Platforms, Unico Connect

In this article

Every growing product reaches the moment where someone says the codebase is holding us back and we should just rewrite it. Sometimes that is right. Far more often it is the most expensive mistake a team can make. This guide gives you the framework engineers actually use to decide, and a scorecard you can fill in for your own product.

Quick Answer

Refactor by default, and rebuild only when the foundation itself is wrong. Refactoring improves the code you have in small, safe steps without changing what the software does. A rebuild throws that away and starts over, which forfeits years of accumulated bug fixes and hard won knowledge. The evidence is clear that big bang rewrites for feature parity usually fail, while rewrites that run in parallel or replace the old system piece by piece tend to succeed. When the answer is genuinely somewhere in between, the strangler fig pattern lets you replace an old system gradually while it keeps running.

What is the difference between refactoring and rebuilding?

They are not two settings of the same dial. Refactoring, as Martin Fowler defines it, changes the internal structure of code without changing its observable behaviour, done in small steps each backed by tests. The software does the same thing, it is just cleaner inside. A rebuild or rewrite replaces the code and usually changes the architecture and behaviour along the way. Refactoring is low risk and continuous. A rebuild is a large bet that the new version will be better than the one you already shipped.

Why does Joel Spolsky call a full rewrite the single worst strategic mistake?

In his 2000 essay Things You Should Never Do, Joel Spolsky argued that throwing away a working codebase and starting from scratch is the single worst strategic mistake that any software company can make. His reasoning still holds up. Code is harder to read than to write, so old code looks worse than it is. The ugly parts are often accumulated fixes that each encode a real bug someone hit in the field, and a rewrite quietly discards all of them. Software does not rot on its own. And while you spend two or three years rebuilding what you already had, your competitors keep shipping. Netscape rewriting its browser is the classic cautionary tale of a company that handed away its lead by starting over.

If rewrites are so dangerous, why do some of them succeed?

Because the successful ones are not big bang rewrites. When Herb Caudill studied six well known software rewrites, the pattern was consistent. The rewrites that worked ran the new product alongside the old one, or targeted a market the old product could never serve, and never switched everything off overnight. The ones that failed tried to rebuild the whole thing to feature parity and flip a switch. Fred Brooks named the trap decades ago as the second system effect, where the ambitious successor collapses under every feature the first version wisely left out. A rewrite can be right. A rewrite that stops the world to reach parity almost never is.

The winners tend to follow one of two shapes. The first is a parallel product rather than an in place replacement. Microsoft did not rewrite Visual Studio into Visual Studio Code, it built a new lightweight editor alongside it, and that new product went on to lead its market. Basecamp rewrote its app but kept the old versions running for existing customers rather than forcing everyone across on a launch date. The second shape is building something the old product structurally could not become. Fog Creek did not rewrite its bug tracker FogBugz, it built the new horizontal product Trello, which grew past 19 million registered users and was acquired by Atlassian for around 425 million dollars in January 2017. The lesson for a founder weighing a rewrite is to copy these shapes. Run the new thing in parallel, keep the old one alive until the new one is proven, and never turn the business off to chase feature parity.

When does refactoring in place win?

Refactoring wins when the foundation is sound and the pain is local. If the architecture still fits where the business is going, if the team that knows the code is still around, and if the problems are messy modules rather than a broken core, you can almost always improve your way out in small steps while continuing to ship. This is the default for a reason. It carries the least risk, it never stops delivery, and it preserves the knowledge baked into the existing system.

When is a rebuild actually the right call?

A rebuild earns its risk when the foundation itself is the problem. The signals worth taking seriously are a data model or architecture that fights every new feature, a platform or stack that is at end of life or cannot be hired for, a no-code or AI generated base that has hit a hard ceiling on control, cost, or compliance, and a codebase nobody understands because the people who wrote it are gone and there are no tests. When several of these are true at once, incremental change stops paying off and a planned replacement becomes the cheaper path. Even then, the goal is a phased replacement, not a big bang.

How do you rewrite without a big bang cutover?

You use the strangler fig pattern, described by Martin Fowler and endorsed in both Microsoft Azure and AWS architecture guidance. You put a facade in front of the old system, then build the new system behind it one capability at a time. Traffic for each migrated feature routes to the new code while everything else keeps hitting the old system, and you delete the old parts only once the new ones are proven. The product stays live the entire time, risk is spread across many small cutovers instead of one terrifying launch, and you can stop or reverse at any point. Its in codebase cousin, branch by abstraction, does the same thing for a module inside a single application.

In practice the mechanics matter as much as the pattern. Slice the work into thin vertical slices that each still deliver something a user or the business can see, rather than rebuilding a whole layer before anything ships. Where you can, run the old and new paths in parallel for a while and compare their outputs, so you catch a difference before customers do. Shift real traffic gradually, a small percentage first, then more, watching the error rate at each step, so a problem shows up at five percent of users rather than all of them. Give the new service its own data and keep the two in sync during the transition, and make sure every slice has its own rollback path so any single cutover can be reversed on its own. This is how a replacement stays boring, which is exactly what you want from one.

Can you rewrite just one part instead of the whole thing?

Usually yes, and it is the option founders forget. Rebuild versus refactor is not the only choice, because there is a middle ground the industry calls rearchitecting or replatforming. You can lift one painful module onto a new foundation while leaving the rest alone, move a workload to managed infrastructure without rewriting its logic, or use the strangler fig pattern to replace the single hot part of the system that causes most of the pain. Most of the time the honest answer to should we rebuild is rebuild the one part that is actually broken, and refactor the rest. Reserving a full ground up rebuild for the rare case where the entire foundation is wrong is what keeps the risk proportional to the problem.

How do you measure technical debt before you decide?

Pull a few numbers before anyone argues from opinion, because a rebuild decision made on gut feel is how teams talk themselves into the expensive mistake. Three measures do most of the work. The technical debt ratio, from the SQALE method, expresses the cost to fix the code as a percentage of the cost to build it, and a ratio creeping past roughly twenty percent is a signal that the debt is systemic rather than local. Code churn, how often the same files are rewritten between releases, points at the unstable areas that a rebuild would need to get right. Defect density, the rate of bugs in a given area, shows where the code is actually failing users rather than merely looking untidy. Static analysis of cyclomatic complexity and duplication rounds out the picture. None of these decides for you, but together they turn a shouting match into a conversation about evidence, and they tell you whether the problem is one module or the whole foundation.

Why do AI built and no-code MVPs hit this wall so fast?

Tools like Lovable, Bolt, v0, Cursor, and Bubble get a product in front of users remarkably fast, and that speed is real value. The catch is the debt they accumulate quietly. Business rules get duplicated across screens, authentication becomes code nobody dares touch, the data model starts fighting every new feature, and no-code platforms hit performance and pricing ceilings that only show up at scale. Industry reports suggest AI generated code carries meaningfully higher defect and vulnerability rates than hand written code, though the exact multipliers vary by study and should be treated as directional rather than precise. The practical point is that the wall is usually hidden debt rather than the tool being bad, and the decision to rebuild should be made on the signals below, not on a reflex against no-code.

How do you score your own codebase?

Give each factor a score from 1 to 5. Score it a 1 when your situation looks like the middle column, which leans toward refactoring, and a 5 when it looks like the right column, which leans toward a rebuild. Use 2 to 4 for anything in between, then add the scores up. The bands below are guidance, not a verdict.

FactorScore 1, leans refactorScore 5, leans rebuild
Business model fitStill serves the businessBuilt for a dead model or one lost customer
Tech debt severityIsolated, messy areasSystemic and actively blocking the business
Change velocity trendFeature time is predictableVelocity drops monthly, changes ripple everywhere
Architecture fitAbsorbs where you are goingFundamental mismatch, wrong data model
Test and safety netMeaningful tests existNone, you cannot change anything safely
Team and tribal knowledgeAuthors still aroundGone, nobody understands the code
Platform viabilityMainstream and hireableNo-code ceiling, dead stack, or unmaintainable AI code
Security and data integrityHandled deliberatelyBolted on, with known vulnerabilities
Capacity to do itCan only improve incrementallyYou have the budget, team, and time for a phased rebuild
Migration feasibilityIncremental cutover works cleanlyStanding still is riskier than moving

Roughly 10 to 20 points means refactor in place. Around 21 to 35 means incremental replacement with the strangler fig pattern. Around 36 to 50 means a phased rebuild is worth planning. The single most useful question to ask over the score is simple. If we keep building on this for six more months, what gets easier and what gets harder.

How do you explain a rebuild decision to stakeholders?

Frame it in the language of the business, not the codebase. A board or an investor does not care that the cyclomatic complexity is high, they care that shipping the next three features will take twice as long and cost twice as much on the current foundation. Lead with the conclusion and one number that matters, such as the months of runway the decision buys or the feature velocity it restores, then show the total cost and the payback period, and tie it to revenue or risk rather than code quality. Present the safe path explicitly, that you will keep the product live and migrate incrementally rather than stop the world, because the fear a stakeholder has about the word rebuild is the Netscape story whether they can name it or not. The scorecard helps here too, because a tallied score reads as a considered decision rather than an engineer wanting to start over.

Frequently Asked Questions

Is it ever a good idea to rewrite software from scratch?

Yes, but rarely as a big bang. Rewrites that run in parallel with the old product or replace it incrementally tend to succeed. Rewrites that try to rebuild everything to feature parity and switch over in one launch tend to fail, which is the Netscape pattern Joel Spolsky warned about.

What is the difference between refactoring and rewriting?

Refactoring improves the internal structure of code without changing what it does, in small steps backed by tests. Rewriting replaces the code and usually changes its behaviour and architecture. Refactoring is continuous and low risk. Rewriting is a large bet.

What is the strangler fig pattern?

It is an incremental replacement strategy. You put a facade in front of the old system and rebuild it one capability at a time behind that facade, routing traffic to each new piece as it is proven, until the old system can be deleted. The product stays live throughout, so risk is spread across many small cutovers.

My MVP was built with Lovable or Bubble and it is breaking. Do I rebuild?

Not automatically. Rebuild only if the data model, security, or ripple effects of every change have genuinely failed. If the real problem is product direction rather than code, redesign first. Often the right move is to refactor the worst parts or migrate them incrementally rather than start over.

How much riskier is AI generated code?

Industry reports suggest it carries higher defect and vulnerability rates than hand written code, but the specific numbers vary widely between studies, so treat them as directional. The bigger practical risk is hidden debt such as duplicated logic and untested authentication rather than any single headline figure.

How do I decide without going on gut feel?

Score the ten factors in the scorecard above from 1 to 5 and add them up. A low total points to refactoring, a middle total to incremental replacement with the strangler fig pattern, and a high total to a planned phased rebuild.

Can I rewrite just one part of my application?

Usually yes, and it is often the right answer. You can rearchitect or replatform a single painful module, or use the strangler fig pattern to replace the one hot part of the system that causes most of the pain, while refactoring the rest. Reserve a full ground up rebuild for the rare case where the whole foundation is wrong.

How do I measure technical debt before deciding?

Pull three numbers first. The technical debt ratio, the cost to fix expressed as a percentage of the cost to build, where past roughly twenty percent signals systemic debt. Code churn, how often the same files are rewritten, which shows the unstable areas. And defect density, which shows where the code actually fails users. Together they tell you whether the problem is one module or the whole foundation.

How do I explain a rebuild to investors or stakeholders?

Lead with the business conclusion and one number that matters, such as restored feature velocity or runway, show the cost and payback, and tie it to revenue or risk rather than code quality. Make clear you will keep the product live and migrate incrementally, because the real fear behind the word rebuild is a company going quiet for two years.

Where Unico Connect fits

Deciding is one thing. Executing a safe migration while the business keeps running is another. We do both. If you are weighing this call on an MVP that outgrew its foundation, or on an app built with Lovable or another no-code stack, we audit the real state first, then either refactor in place or run a strangler fig migration onto a system you own. If the honest answer is that you inherited the code and do not yet know what you have, start with our guide on taking over an existing codebase.

Keep reading

Latest Blogs & Articles

View all