← Back to blog

8 Point Rubric to Decide Rewrite or Refactor for Founders & Engineers

September 3, 2026
8 Point Rubric to Decide Rewrite or Refactor for Founders & Engineers

Refactor is the default. Rewrite the system only when the abstractions are wrong, the platform is unsupported, or a compliance requirement makes the current architecture untenable. Everything else, including "the code is ugly" or "I didn't write it," is a refactor problem, not a rewrite problem. The decision framework below gives you the checklist to confirm which one applies before you commit budget to either path.


TL;DR:

  • Rewrites should be treated as projects with clear scope, deadlines, and pilot modules to avoid scope creep and project failure.
  • Refactoring is safer and more cost-effective when the architecture is fundamentally sound but messy, using incremental improvements and targeted file refactors.
  • Use measurable signals like hot files and bug trends, alongside cost analysis, to decide whether to refactor or rebuild instead of relying on gut feeling.
  • Staffing for two systems during migration and continuous parity checks are crucial to avoid costly regressions and project delays.
  • Always consider refactoring first unless a critical system failure or obsolescence force a full rewrite.

Table of Contents

Rewrite vs Refactor: What Each Term Actually Means

People use "rewrite" and "refactor" loosely, and that looseness is where budgets get destroyed. A refactor changes internal structure without changing external behavior. You reorganize, rename, extract functions, and simplify data flow, but the system does the same thing it did yesterday, just with cleaner internals. Refactoring carries lower risk because behavior stays fixed while structure improves, which is why it's slower to show dramatic results but rarely breaks production overnight.

A rewrite replaces the system. You're targeting feature parity (mostly) with a different stack, different data model, or different architecture underneath. Rewrites are faster to feel dramatic and slower to actually finish.

Between those two poles sit hybrid approaches that most teams underuse:

  • Incremental rewrite: new features built in the new stack while the old system keeps running the rest.
  • Strangler Fig pattern: routing traffic module by module from old system to new until the old one has nothing left to do.
  • Branch by abstraction: inserting an interface layer so you can swap implementations behind it without a flag day.

Most successful modernizations I've seen use one of these three, not a clean binary choice.

The Decision Framework: Score Before You Commit

Score each question 0, 1, or 2. Add them up. The total maps to a recommendation at the bottom. This mirrors the scoring approach used in decision frameworks built specifically for this choice, adapted for teams making the call without a consultant in the room.

  1. Revenue dependence. Does this system generate revenue directly today? (0 = yes, critical path; 2 = no, internal tool)
  2. Runway tolerance. Can the business survive a 6 to 12 week feature freeze on this system? (0 = no; 2 = yes, comfortably)
  3. Test coverage. Do you have automated tests covering core business logic? (0 = none; 2 = solid coverage)
  4. Architecture correctness. Are the current abstractions fundamentally sound, just messy? (0 = fundamentally wrong; 2 = sound but dirty)
  5. Data model health. Can the current schema support next year's features without a redesign? (0 = no; 2 = yes)
  6. Institutional knowledge. Does someone on the team understand why the system was built this way? (0 = nobody knows; 2 = fully documented)
  7. Team execution history. Has this team shipped a rewrite or major migration before? (0 = never; 2 = yes, successfully)
  8. Platform support. Is the underlying runtime or framework still supported and hireable? (0 = dead platform; 2 = current and easy to hire for)

Scoring: 12 to 16 points, refactor in place. 6 to 11, strangler fig or incremental rewrite. 0 to 5, you likely need a full rewrite, and you should plan for it properly rather than starting quietly and hoping it stays small.

Pro Tip: Run this scoring exercise with your whole engineering team separately, then compare answers before discussing. The gap between the most optimistic and most pessimistic scorer tells you more about your actual risk than the average does.

The Decision Framework: Score Before You Commit — overview diagram

The Metrics That Actually Tell You Which Way to Go

Opinions about "how bad the code is" are unreliable. Numbers aren't. Start with the honest version of the cost comparison: annual maintenance cost of the current system (engineer hours spent on bugs, workarounds, and slow features) against the realistic cost of a rewrite, multiplied upward, because rewrite estimates routinely run under actual cost and industry guidance recommends applying a multiplier for optimistic bias before comparing the two numbers honestly.

Beyond that comparison, a handful of measurable signals tell you more than a gut check:

SignalWhat it measuresThreshold worth worrying about
Hot filesgit log --since=6.months --name-only | sort | uniq -c | sort -rnSame file touched in most recent commits
Change lead timeTime from PR open to production deployTrending up over 3+ months
Bug rateRegressions per releaseRising while feature velocity flattens
CI stabilityFlaky test rateAbove 5% flaky on main branch
Hiring difficultyTime to fill a role requiring the current stackMonths, not weeks

Red flags that override the scoring rubric entirely: a runtime vendor has announced end of life, a regulator now requires an architecture the system can't support, or the data model has drifted so far from reality that no query returns a trustworthy answer. Any one of those forces a rewrite conversation regardless of how the other scores land.

The Refactor Playbook: Step-by-Step Patterns and Guardrails

If the scoring rubric points to refactor, here's the sequence that actually works in practice, not the sequence that sounds good in a planning meeting.

  1. Adopt the Boy Scout rule at the PR level. Every pull request leaves the touched code slightly better than it found it. Not a rewrite of the file, one small improvement: a renamed variable, an extracted function, a removed dead branch.
  2. Find your hot files before guessing. Run git log --since=6.months --name-only --pretty=format: | sort | uniq -c | sort -rn | head -20 to find the files changed most often. Those are where refactoring effort pays off fastest, because they're the files everyone touches and everyone fears.
  3. Track lead time and bug rate weekly, not quarterly. If refactoring is working, lead time should trend down within 4 to 6 weeks. If it isn't moving, you're refactoring the wrong files.
  4. Ship behind feature flags. Wrap risky changes so you can disable them instantly without a rollback deploy.
  5. Roll out with canary releases, exposing the refactored path to a small percentage of traffic before full cutover.
  6. Work in vertical slices. Refactor one complete user flow at a time rather than one layer across the whole system. A half-refactored data layer under a half-refactored API is worse than either extreme.

LLM-assisted transformation tools now handle a meaningful share of repetitive refactors safely when paired with static analysis and a real test suite, which changes the economics of large mechanical cleanups. Program-transformation systems like Refazer have demonstrated learning the intended edit from a handful of examples in the large majority of studied cases, which is worth knowing before you assume a repetitive refactor has to be done by hand.

Pro Tip: Don't refactor and add features in the same pull request. Reviewers can verify "this is safe" or "this does something new," but almost nobody can verify both at once, and that's exactly where regressions hide.

The Rewrite Playbook: Surviving a Full Replacement

If the scoring rubric points to a rewrite, treat it as a project with a name, a budget, and an end date, not an open-ended background task.

  1. Pick one module to pilot first. Not the biggest, not the smallest. Choose something real enough to prove the new stack works, contained enough that failure doesn't sink the quarter.
  2. Set a kill date before you start, and mean it. If the pilot module isn't in production and stable by that date, you stop and reassess rather than sliding the deadline quietly.
  3. Ship in vertical slices, one complete workflow at a time, not one architectural layer across everything.
  4. Freeze features on the old system for whatever's actively being migrated. Running two moving targets at once is how migrations never finish. Strangler-pattern migrations that convert the rewrite into an experiment with measurable checkpoints avoid the endless scope creep that kills most big-bang attempts.
  5. Run the new system in shadow mode first. Send it real traffic, compare its output against the old system's output, and don't cut over until the comparison is clean for a sustained period.

The rules that keep a rewrite alive:

  • Old system gets bug fixes only, never new features, once migration starts.
  • New system doesn't get new features beyond parity until the old system is fully retired.
  • Every data model change gets a written migration plan with dual-write, backfill, and reconciliation steps, budgeted as its own line item rather than folded into general rewrite time.
  • Nobody promises a completion date before the pilot module has shipped and proven the estimate.

Case studies across the industry consistently show rewrites failing when teams chase full feature parity and let scope expand mid-project, while the ones that succeed usually shipped an imperfect but working slice early and iterated from there. A rewrite that quietly becomes "rewrite everything, then cut over" is the failure mode, not the plan.

Where Rewrites and Refactors Actually Go Wrong

The most expensive mistake in either path is running two full systems and staffing only one. If you're migrating, budget for a team that can maintain the old system's critical fixes while building the new one, even if that means slower rewrite progress. Understaffing this is how six-month rewrites become eighteen-month rewrites.

Regression and parity risk is the second failure mode. Mitigate it with the same three tools every time: comparison runs between old and new outputs, shadow traffic before cutover, and targeted (not big-bang) data migration with reconciliation checks built in from day one.

A quieter risk: teams that can't explain why a file was written a certain way tend to introduce regressions when they refactor it, because the missing knowledge was often encoding a business rule nobody wrote down. Before touching inherited code with no institutional memory attached, write down what it does in plain language and add tests that pin that behavior down. That five-minute step catches more disasters than any code review checklist.

  • Two-system overhead: budget separate staffing, don't assume one team can do both well.
  • Parity risk: comparison runs and shadow traffic, not manual QA alone.
  • Knowledge gaps: capture behavior in tests before refactoring unfamiliar code.
  • Cost blindness: apply a realistic multiplier and track the opportunity cost of the team not shipping other work.

Rewrites that skip the multiplier step tend to run past their budget by a wide margin once real data migration and edge cases surface, which is a large part of why so many get abandoned halfway.

My Take: Ten Years of Rebuilds Rooted in This Exact Choice

I've spent ten years in engineering, including systems work for Deutsche Bahn, BMW, and BRZ, before running my own one-person practice from Vienna. Most of what I do now falls into three buckets: rescuing a prototype that hit a wall, building the first real version of something that only existed as a Figma file, or turning one painful manual workflow into a working internal tool.

What I will take on: a system where the prototype is the spec, the scope gets frozen at kickoff, and the client owns the code from the first commit. What I won't take on: an open-ended "make it better" engagement with no defined finish line. That's not how a fixed-price, weeks-not-months build works, and pretending otherwise sets both sides up to fail.

Every client gets one name on the contract and every line written by me, no juniors. That constraint is also the honesty check: if I can't scope it in a conversation, it's not ready to build yet.

Why the "Just Rewrite It" Instinct Is Usually Wrong

The instinct to rewrite is almost always about morale, not architecture. Nobody feels proud maintaining someone else's messy code, and a rewrite promises a clean slate. That's a real feeling, but it's a terrible reason to greenlight months of parallel-system risk.

The scoring rubric above exists because gut feel consistently overweights code aesthetics and underweights institutional knowledge loss and two-system staffing cost. I'd rather see a team run the eight questions and land on strangler fig than skip straight to "let's rewrite it in [new framework]" because that's what feels motivating this quarter.

What the evidence actually supports: refactor first, always, unless a specific and namable blocker exists. Automation tooling for mechanical refactors keeps improving, which lowers the cost of the safe path further every year. Prioritize writing down what the system does before you touch it. That single step prevents more failed migrations than any framework choice ever will.

— Hanad Kubat

If the Scoring Says Rebuild, Here's How I Work

If your rubric landed at 0 to 5, or your prototype from Lovable, Bolt, Replit, or Bubble validated the idea but can't survive real users or a due-diligence review, that's rescue-and-rebuild territory: the prototype becomes the specification, and I rebuild it as real, maintainable code.

Hanad Kubat

I offer a fixed-price Prototype Audit at €1,500, three to five days, credited against the build if you move forward. It tells you honestly whether you're looking at a refactor, a targeted rebuild, or a fuller rewrite, before you commit real budget. Full builds start at €12,000, and rescue rebuilds typically run €12,000 to €20,000, delivered in weeks, not months, with a scope frozen at kickoff so there are no surprise invoices partway through. No agency overhead, no project-manager layer, no offshore markup: one name on the contract, and every line written by me.

Before reaching out, have your prototype or repository ready to share and a rough list of what breaks under real users. Start with the Hanadkubat and I'll tell you straight whether a rebuild is actually what you need.

Sources

FAQ

What's the difference between replatforming and refactoring?

Refactoring changes internal code structure without touching external behavior or the underlying platform. Replatforming moves the system to a new runtime, framework, or infrastructure, which usually means at least a partial rewrite even if the business logic stays similar.

What does it mean to refactor code?

Refactoring means restructuring existing code to improve readability, reduce complexity, or make future changes easier, without altering what the software does for its users. It's the lower-risk path compared to a rewrite, because behavior stays fixed while only the internal structure changes.

Is there another term for refactoring?

"Code cleanup," "restructuring," and "technical debt paydown" are common informal synonyms, though "refactoring" is the standard industry term and the one most engineering teams use in planning discussions.

What is the rule of three in refactoring?

The rule of three says you tolerate duplicated code the first time, note it the second time, and refactor it into a shared abstraction the third time you see the same pattern. It prevents premature abstraction while still catching real duplication before it spreads.

Is refactoring always necessary before a rewrite?

Not always, but it's worth ruling out first. If your scoring rubric shows sound architecture with just messy execution, refactoring solves the problem for a fraction of the cost and risk of a full rewrite, and a short audit is usually enough to tell you which situation you're in.