How to rescue a half-built application
The instinct is to rewrite. It's usually wrong. A method for assessing what you have and deciding what to actually do with it.
7 min read · Yatin Growth Labs
The moment someone looks at a stalled application, the instinct is almost always the same: burn it down and start clean. It feels faster than untangling someone else's decisions, and it's the wrong call more often than it's the right one. A rewrite throws away the part of the project that's actually expensive to redo — the accumulated knowledge of what the product needs to do, encoded in code that mostly works.
The alternative is an assessment before a decision, not the other way around. Here's the method, in the order it actually has to happen.
Step one: run it before you read it
Before opening a single file, get the application running — locally, with real (or realistic) data, exercising the actual user flows. Reading code first creates a mental model that's often wrong; running it first tells you what's true. Note every place it's slow, every error that surfaces, every workflow that doesn't complete.
This step alone eliminates a category of expensive mistakes: assuming something is broken when it isn't, or assuming something works when it silently doesn't. Half-built applications frequently have both.
Step two: separate blocking from merely offensive
Every non-trivial codebase has code a senior engineer would wince at. Almost none of that actually blocks launch. The audit's real job is triage: what stops this from going live safely, versus what's ugly but survivable for now.
- Blocking: credentials reachable from the client, authorisation that only exists in the UI, no error handling on payment or auth flows, data loss risk on common operations.
- Survivable for now: inconsistent naming, a component that's grown too large, missing tests on stable code paths, a slightly awkward folder structure.
- Context-dependent: performance issues (blocking if the product is unusable, survivable if it's merely not optimal yet), missing monitoring (blocking for anything handling money or user data, deferrable for a low-stakes internal tool).
The question isn't 'is this code good?' — it's 'does this specific thing stop us from shipping safely?'
Step three: map the architecture as it actually is
Not as it was intended, not as the original developer described it in a handover call — as it actually exists in the repository today. Trace how data flows from input to storage to output. Find where business logic lives (often scattered across the frontend, a symptom of a project that grew faster than its architecture). Identify the load-bearing walls: the two or three components that, if they're wrong, everything downstream inherits the problem.
This map is what makes the rebuild-or-repair decision defensible rather than a gut call. If the load-bearing walls are sound, repair. If the load-bearing walls are the problem — data modelling that can't represent the product's actual rules, an architecture that fundamentally can't scale past its current usage — a rebuild of that specific layer, not the whole system, is usually the honest answer.
Step four: price the two paths, not just one
A rewrite quote in isolation always looks clean — no legacy, no compromises, a fresh estimate for known scope. It also always underestimates, because it prices the parts of the product everyone remembers and skips the edge cases, the weird client requirement from month four, the bug fix nobody wrote down. A repair estimate has the opposite bias: it can look messy and specific because it's grounded in what's actually there.
Price both against the same standard — production-ready, not demo-ready — and the comparison gets much more honest. Repair is very often cheaper and faster than a rewrite believes it will be, precisely because a rewrite has to rediscover everything the original build already learned.
The honest exception
Sometimes the rebuild is correct. If the data model can't represent what the product needs, if the framework choice makes the required features structurally difficult, or if there's simply not enough of a working system to call it a repair — say so. The point of the method isn't to always save the existing code. It's to make that call from evidence instead of instinct, in either direction.
Want this method run against your actual codebase?
See what the assessment coversWritten by
Yatin Growth Labs — an AI product and consulting studio. The examples in this article come from products we built and shipped ourselves: FitRas and InstaBrain.