← Blog
July 20, 20257 minvibe-coding

What I learned from a year of vibe coding — and what I'm embarrassed about

A year ago I thought programming wasn't needed anymore. Then I spent a week debugging code the model had generated in fifteen minutes. A personal reckoning.


In June of last year I built my first "serious" product in vibe mode. It was an internal tool for one client — a bot that pulled emails from a mailbox, summarised them, and dropped the summary into a spreadsheet. I built it in a Saturday. Sixteen hours, not counting food and one walk with the dog. On Sunday I looked at it, decided it worked, and went to bed pleased.

On Monday the client called to say the bot was "behaving a bit strangely." Mostly — it had started adding facts to its summaries that weren't in the emails. The bot hallucinated, like a good first-year philosophy student.

I sat down to debug. Over the next five days I understood fourteen things that the model had not told me while it was writing the code. Chief among them: I didn't actually know what I was building. I knew I wanted it to work. Those, it turns out, are not the same thing.


People write about vibe coding in roughly two registers. First — the enthusiasts: "I now ship in a weekend what used to take me a month!" Second — the disappointed: "it's all fiction, AI can't do anything, we're still paying real programmers, all is well." Both, I think, miss the point.

The point is that vibe coding doesn't remove programming. It removes the mechanical part of programming. Typing loops. Parsing boilerplate JSON. Writing your tenth lifetime pagination. If you thought a developer's job was mostly typing, you get an enormous boost. If you thought a developer's job was making decisions, the model is not a helper — it's an interlocutor. And, honestly, not a very smart one. It knows how to do; it doesn't know why.


That summer bot is a classic example. I formulated tasks like "make a function that fetches emails from Gmail API and returns an array". The model made it. Worked. Then "summarise each email". The model made it. Also worked.

The problem was that I hadn't specified any correctness criterion for summarisation. I assumed "summarise" meant "extract key moments without distortion." The model assumed "summarise" meant "rephrase so it's shorter." Those overlap. Not entirely.

By Friday I realised what needed rewriting wasn't the code, but the prompt inside the summariser model. I rephrased it in a way that couldn't be read two ways: "Extract facts from the email. A fact = a statement with a subject, verb and object. Don't add anything that wasn't in the email. If in doubt, write 'not mentioned'." The hallucinations went away. The code stayed the same. The prompt solved it.

And that's what I learned over a year. Vibe coding works when you can formulate. Not when you can program. Not when you can prompt. But when you can frame the task so that it can't be answered incorrectly.

(Although "can't" is a bit of a hyperbole. Models are inventive.)


Over the same year I built roughly twelve things in vibe mode. Of those:

Four — prototypes for clients that went to prod without rewriting. Landing pages, small admin panels, internal tools. They still work. Vibe coding for this kind of task is the ideal tool. I wouldn't go back to writing it by hand. That's one of those cases where "traditional development" becomes domestic evil.

Three — integrations. Take input from one API, do something, send to another API. In 2026 this is often one prompt, not a sprint. For integrations the model is strong, because the context of public APIs is what it was trained on.

Two — refactors. I hand the model someone else's code, describe what I want, it proposes, I accept. This is my favourite application, because here the model works like a patient junior colleague with zero ego.

Two — complete failures. Attempts to build things I didn't quite understand myself. One was a complex backend with async queues and distributed locks. The model wrote code that compiled, looked right, and contained a subtle race condition at the Redis lock level that I found only in production, when two users ordered the same thing simultaneously. The model doesn't catch that because it doesn't see causality in distributed systems. It sees code. The code looks right.

The other — an attempt to build a custom SDK with unique business logic that has no internet analogue. The model filled in with industry-average logic, and what I got was "a typical SDK for a typical task," not my specific one. I rewrote it by hand afterwards. Would have been faster to start there.


Three rules I've ended up with over the year, if I may indulge in brevity.

First. Specify the result, not the code. "Add a POST /orders endpoint that accepts { id, items[], total }, validates, writes to DB, returns 201" is a request. "Make orders work" is a prayer. Between those is 80% of success.

Second. Test by hand every iteration. Not after five prompts. After each one. I have a harsh personal rule: if I haven't verified the code works, I don't accept the next prompt. Otherwise the model builds a tower of assumptions, each next one resting on the prior, and when it falls — it falls whole.

Third. Read the code, don't just accept it. If lines 40–60 are opaque — ask the model. If the model can't explain them so you understand, you're not ready to put them in prod. This isn't about distrust. It's about the fact that your job is now review. Reviewing someone else's code, even when the someone else is a language model, requires understanding.


People who say developers aren't needed anymore have either never fixed someone else's code at 3 AM or are selling a $500 course. (I've written this somewhere before. I like the formulation because it's accurate.)

The model is a lever. A lever without a fulcrum snaps on the first serious job. The fulcrum is you, the person who knows what is being built, why, and what happens when it breaks.

In June last year I thought programming wasn't needed anymore. In June this year I think programming is needed more — just not with hands. With the head.

Mike Fluff← Blog