I said I knew nothing about testing. My repo had 342 of them. · ziv-ai<br>A comment thread went by the other day, and the consensus was brutal: AI writes garbage code, so anything built with AI is stuck at the MVP stage — it can’t ship for real, can’t carry a real business.
I’m exactly the person those comments are pointing at. No engineering background, a pure vibe coder — the AI writes every line and I can’t read any of it. My honest reaction to the pile-on was: as long as the thing actually works when it ships, what’s the problem? Clean code, messy code — why is that my concern?
Then two things happened. First, I sat down and had a long conversation about what “spaghetti code” actually means, until the word finally clicked. Second, I went back and opened the repo for the project I’d just finished — and found 342 automated tests sitting inside it. This was days after I had said, out loud, “testing is something I really have no concept of.”
This piece is me working through both. If you also ship with AI and can’t read code, this might be the shortest path between you and that word everyone keeps throwing around.
1. In plain words: what “spaghetti code” actually is
Spaghetti code — legacy rot, technical debt, whatever you want to call it — is code that has piled up over years until nobody dares touch it. The key word is piled. It’s never written badly in one shot; it accumulates:
The first person is racing a deadline and writes something that works but is rough. The second person needs to add a feature, can’t follow the first person’s logic, is afraid to change it, and smears a new layer on top to route around it. The third person fixes a bug, discovers that touching A breaks B, and slaps a patch over the symptom instead of the cause. A few years and a few dozen people later, no single person understands the whole mountain.
The counterintuitive part: this stuff usually runs fine. Some of the most critical systems on earth — banks, airline booking — run on exactly this kind of code. Precisely because it still runs and nobody understands it, “don’t touch it” becomes the most rational choice available.
So the cost of bad code was never in running it. It’s in changing it. A messy product can ship today and work great today — no problem at all. The problem shows up three months later when you want to add one feature: changing A breaks B, fixing B takes down C, and each edit costs more than the last, until rewriting is cheaper than repairing. Bad code isn’t a quality problem, it’s debt. You don’t feel it while you’re carrying it. The day you have to move, you pay principal plus interest, all at once.
Once that lands, you can see exactly where my “it works, so it’s fine” went wrong: I answered a charge about whether you can change it with a claim about whether it runs. Wrong question.
But my instinct wasn’t entirely off, either. The AI era added a new variable: the cost of a rewrite has collapsed. It used to take person-months to rebuild a system, so you had to maintain the mess. Now regenerating it might take an afternoon. For a one-person-plus-AI project, code starts to look a bit like a disposable fork — use it, toss it, make a new one when you need one. Fussing over whether it’s “clean” misses the point. From that angle, holding a solo AI project to a big-company team-collaboration standard is fighting the last war.
There is one exception that breaks the comfort, though. Once a project grows too big for the AI to hold in its “head” at once, the AI starts flailing at its own mess too — ask it to fix one bug and it introduces three. At that moment you can’t read the code to fix it yourself, and the AI can’t untangle it either. That’s when the project actually dies. That is the real threshold for a vibe coder — not “can it ship.”
2. I’d already been bitten once. I just didn’t know it.
The project I just finished is an automation tool for discovering influencers and running campaign delivery. Two months, a hundred-odd commits, grown from a little scraping script into a full pipeline that ended up live on the public internet.
Along the way there was one data incident. A batch of influencer IDs got corrupted — the data was wrong, but the program kept running fine and kept producing output. I figured it was trivial: I’d already located the ID in the page structure, so surely the rest was just a matter of extracting it?
That “just extract it” turned into a war of attrition. The AI I was using kept writing me diagnostic tools, swapping in different logic each time, one after another — there are still four such tools sitting in that repo, fossils of the fight. At one point I was so fed up I nearly told it to wipe the whole data store and re-scrape everything from scratch, just to be done. In the end I only found the root cause by switching to a different AI. And reading the docs afterward, I found the scarier detail: one of those repair tools had a bug of its own that nearly overwrote the correct data with...