Fixing a Vibe-Coded MVP Costs More Than Rewriting It

An MVP that holds up in a demo with three users isn't an MVP that holds up in production. Plaintext data, broken permissions, a fix that broke five others — what I found opening a codebase built fast with an AI coding tool, and the rule I use now before deciding whether to patch it or rip it out and start over.

Simone Negro, Backend & AI Engineer
4 min read

In the demo, everything looked like it worked. Login, dashboard, the main flow — click after click, it looked like a product that was nearly done. Then I opened the code.

Thousands of duplicated lines. Data sitting in plaintext, no encryption at rest. Permissions that half-worked. A single page firing 100 API calls a second. A real mess.

The same validation logic and the same style got reused, copy-pasted over and over with tiny variations — components doing the same thing with slight differences that, a little at a time, add up to the whole thing quietly falling apart.

No abstraction anywhere. Just lines of code written with no logic behind them.

What had actually broken

The team that built this MVP had used an AI coding tool to move fast — and to some extent it worked: the features were there, the product was demo-able to an investor, the MVP existed. But “existing” and “actually working” are two different things. Under the surface, the code hadn’t been written to be read by a human later — it had been generated to pass whatever check was closest, one prompt at a time, with nobody holding the overall picture in their head.

It’s not the tool’s fault, and it’s not entirely the fault of whoever used it either. The problem comes from what’s floating around out there: that AI is going to replace developers’ jobs, that a handful of prompts is enough to get to an MVP. To actually use these tools well, you need intelligence of your own on top, and real experience — we are nowhere near the point where a programming language has become plain English. A clear example of this is exactly what I wrote about in Skills Are Not for Writing the Code. They Are for Knowing What to Ask. The tool may have been fine at writing the code, but without understanding what it wrote, you can’t actually govern an AI that spits out code at random, with no human logic behind it.

What I assumed

My first instinct looking at that code was: “fixing this will cost less than rewriting it — it already works, it just needs cleanup.” It seemed like a reasonable trade-off: the core features ran, the UI looked acceptable, the project structure looked fine too. It wasn’t until I actually read the code that I realized what I’d opened was a real Pandora’s box.

Why that assumption was wrong

The duplication isn’t the problem — it’s the symptom. Every time I fixed one piece of logic, the same logic in its slightly-different copies didn’t get fixed along with it. Worse: fixing one critical bug in one place broke five other things elsewhere — a cascading disaster that’s genuinely complex and costly to untangle. I mentioned the UI looked fine on desktop. Looking at the same pages on tablet or mobile gave me actual chills: what I was looking at wasn’t an MVP, it was a full-blown disaster.

Fixing a bug didn’t mean writing three lines. It meant first rebuilding, by hand, the map of what the code was supposed to do — because that map didn’t exist anywhere except in the head of whoever wrote it (and sometimes not even there).

What it actually cost

The real bill was never the bug I was fixing — it was everything attached to it. A broken permission isn’t “a permission to fix” when sensitive data is sitting in plaintext with no encryption at rest: it’s a security problem you have to solve before you can even think about anything else, because as long as it’s open, everything else is wasted effort. 100 API calls a second on a single page isn’t “something to optimize later”: it’s the reason the system holds up in a demo with three users and falls over the moment real traffic hits it.

Then there’s the cascade. You fix one thing, five others break — and you don’t find out by reading the code, you find out when it happens, because that dependency was written down nowhere except in the head of whoever built it the first time. Every fix turns into a blind treasure hunt: fix, test, discover what else broke, repeat. Whatever time you thought you were saving by “patching instead of rewriting” disappears right there, multiplied by every hidden variant you didn’t know existed.

The rule I use now

I stopped asking “how long will this take to fix” and started asking “how many things break if I touch this.” If the honest answer is “I don’t actually know” — and with duplicated code and zero abstraction, that’s almost always the answer — then it isn’t a bug to fix, it’s a module to rewrite from scratch, isolated, with real tests around it before touching the logic at all.

This isn’t a rule against using AI tools to write code fast. It’s a rule about when to stop trusting that “looks nearly done” means anything.

Get new posts by email

No hype, unsubscribe anytime. · Powered by Buttondown

Or follow along

Shorter takes, half-finished ideas, and whatever I'm building or breaking this week.