Keeping your code maintainable when the AI wrote it
A thousand lines in three minutes is a genuine rush — and it's earned, it's one of the superpowers of coding with AI. The bill comes later: six months on, a bug surfaces in code nobody ever really read, the AI that wrote it remembers nothing, and you may have switched models in the meantime. The fix isn't writing less AI code. It's making it legible as it's born — and, nice surprise, legible code is also the fastest to change.
The real cost isn't writing, it's understanding
Generating has become free; understanding hasn't. And that's the whole trap: you pay for legibility later, at the worst moment, when you have to change something you never read.
Remember how the AI works: each session, it starts with no memory of what it wrote before. Six months from now, your code will be the only record of how your app works — neither the AI nor you will have the history in your head. If that code is clear, any model (or future-you) picks it up in five minutes. If it's unreadable, everyone struggles, human and machine alike.
That's why legibility is nothing like a moral duty: it's plain self-interest. A thousand-line tangle of a file saturates the context window, confuses the model, triggers the endless loops. Clean code, the AI navigates it, changes the right thing, breaks less. Maintainable isn't the opposite of fast — it's what keeps you fast.
A structure and names you can follow
Two levers cost almost nothing and pay off hugely: where things live, and what they're called.
Structure. One responsibility per file, predictable folders. The simple test: "where would a newcomer look for this?" — that's where it belongs. The AI has a reflex, though: dump everything into the file it's already looking at. Without you to redirect it, one component ends up doing ten things. When a file swells, ask for it to be split by responsibility. Bonus: the AI then only has to load the relevant file, not the whole mess — cheaper, more accurate.
Names. It's the cheapest documentation in the world. calculateMonthlyTotal tells you what the function does without reading its body; calc, handleData or temp2 don't. Half of "unreadable code" is just bad naming. The AI names things well when you let it — but it'll also accept your vague names without a peep. The moment you see data, info or thing2, rename it (or ask). Small rules, big effect: a boolean states what's true (isLoading), a function is a verb, a collection is plural.
Small functions, comments that earn their place
One function, one job. If you can read it top to bottom without scrolling and sum up what it does in a sentence, it's healthy. If you can't, it's doing too much — ask the AI to split it. Three-hundred-line functions are where bugs hide and where the model gets lost. As a bonus, small pieces are testable, and a bug stays local instead of smearing everywhere.
Comments. Here's the nuance pros know: a good comment explains the why, not the what. The code already says what it does; a comment earns its place by capturing the reason or the trap ("we retry twice, the payment API is flaky"). The AI, for its part, loves to over-comment — a // increment i above an i++ is noise, and worse: when the code changes, those comments start lying. Ask it to comment the intent and the gotchas, not the obvious. Fewer comments, but real ones.
Technical debt: a loan, not a sin
Let's drop the guilt: technical debt isn't a fault, it's a loan. Sometimes you take it on purpose — ship the prototype now, clean up later — and that's perfectly legitimate as long as it's a visible choice. The real problem is accidental debt nobody decided on and nobody can see.
So make it visible: a short list of the shortcuts you knowingly took (a // TODO: in the code, a TODO.md file), so future-you — or the AI — trips over them. Naming the debt is half of managing it.
And to pay it down, forget the grand "rewrite weekend" that never comes: clean as you go, the function you're touching today. Good news, the AI is an excellent refactoring tool — point it at a messy file, ask it to clarify without changing behavior, and run the tests to prove it. Making code clean has never been this cheap.
The reflex that changes everything: demand legibility up front
All of this becomes automatic when you don't have to ask for it every time. Put your conventions in a rules file (CLAUDE.md, .cursor/rules): "small functions, explicit names, one responsibility per file, comment the why." The AI then generates legible code by default, and you stop playing traffic cop.
That leaves the most important move, and the one you keep for yourself: read what comes out. Not every line — enough to keep a mental map of your app. The day you no longer understand your own code is the day you've lost control of it. And you get it back not by reading a thousand lines at once, but by asking the AI to explain a file, and by keeping the code simple enough to skim. You stay the architect; the AI is the fast pair of hands.
In short
The code the AI generates is your code — better make it legible, because you (and the next model) are the ones who'll pick it back up. Clear structure, explicit names, small functions, comments that say the why, and debt you take on purpose instead of inheriting by accident: nothing preachy in there, just what keeps your app — and your vibecoding — fast over time. Coding for your six-months-from-now self: that's exactly what vibecoding like a pro looks like.