The "if it works, ship it" trap, and the one habit that actually prevents it

by

There's a specific moment that happens with almost every project: the agent produces code, it passes your tests, everything's green, and there's a real pull to just move on to the next thing. Totally understandable, the whole appeal of this workflow is speed.

But there's a gap between "this works" and "I understand why this works," and that gap is where the real risk hides. Not because the code is wrong, most of the time it isn't, but because the next time something breaks nearby, you're debugging code you never actually read closely the first time.

during the BC (before ChatGPT) era, this gap barely existed. You wrote it, so you understood it, mostly by necessity. Now understanding is a separate step you have to choose to take, not something that comes free with writing the code yourself.

One habit that closes that gap fast: before merging anything non-trivial, ask the agent to explain its own implementation back to you, line by line, in plain language. Not as a formality, actually read the explanation. Two things tend to happen. Either it confirms your understanding and takes thirty seconds, or it surfaces an assumption you didn't know was baked in, which is usually the more valuable outcome.

This becomes especially important with anything touching auth, state management, or async logic, the categories where "it worked in my test" and "it's actually correct" diverge the most.

Curious what habits others have built for this. Do you have a personal checklist before merging AI-generated code, or a specific type of change you never let through without reading line by line, regardless of how confident the tests looked?

136 views

Add a comment

Replies

Best

I really agree with this. These days I spend a minute asking the AI to walk me through the logic before I merge anything important. It has caught a few things I would have missed.

 I like this perspective. AI can write code quickly, but I still think understanding the implementation is part of my responsibility.

good practice indeed. We may learn a few things for the next time too.

 Another thing I find useful is asking the AI why it chose this solution instead of a different one. The comparison gives me a much clearer picture.

I agree with this.

For me, passing tests is just one checkpoint, not the finish line. I always try to understand the overall flow before merging, especially for authentication, payments, or anything security-related. Spending a few extra minutes there can save hours of debugging later.

That's the takeaway! "spending a few extra minutes can save hours of debugging" That is indeed the primary reason why we should understand the codebase as a whole and the changes we made.

This is a great point. I’d add that with AI-generated code, “understanding” should go one step further than asking the AI to explain itself.

The real habit I’d build is: ask, verify, then own the decision.

AI can explain its reasoning convincingly, even when the underlying assumption is wrong. So the skill we need to develop isn't just reading AI-generated code, but knowing which assumptions to challenge and which behaviors to verify.

“Works” is a technical state.
“Understood” is a human responsibility.

That distinction is becoming increasingly important as AI takes over more of the coding process.

 'works is a technical state, understood is a human responsibility' is worth pinning somewhere. and the ask, verify, own sequence fixes the exact gap the other comment pointed out too, the explanation coming from the same context that wrote the code. verifying against something outside that context, an actual run, an actual assumption you independently check, is what makes 'owning the decision' mean something instead of just being a formality you did after the fact.

 Exactly. The key is that verification has to introduce an independent signal, not just another explanation from the same AI context. That’s what turns understanding into actual ownership.

The explanation comes from the same context that wrote the code, so it can only tell you what it meant to do. If the assumption was wrong when it wrote it, it is wrong in the explanation too, and it reads perfectly.

Same thing on my side with support replies. A draft grounded in the wrong order reads better than one that is right, because nothing in the text is off. Reading it more carefully does not catch it. Comparing it against the record does.

So the version I trust is when the explanation says something checkable. It claims this runs after the token refresh, then go and see that it does. Do you ever check the explanation against a run, or is reading it usually enough?

 That's the real failure mode, the explanation isn't lying, it's just as blind as the code was. Checkable claims fix that because you're no longer trusting the narrative, you're verifying a fact. I mostly read closely and only trace against a run when something touches auth or ordering, but your point makes me think that's backwards, the stuff that reads cleanest is exactly what won't get caught by reading.

There is huge technical debt creeping up when you just vibe code your product. You have to spend more time understanding it. 99 percent of your code can be written by ai but that 1 percent creates confidence

 That 1 percent is dangerous specifically because it's too small to feel worth double checking. Technical debt from vibecoding rarely looks like bad code, it looks like code nobody fully read because it passed and moved fast. The confidence is the debt."

The cheapest independent signal I've found for the auth slice is to stop reading the diff and re-send the same request as a second account that shouldn't see anything. The explanation and the code share a context; the second account doesn't. If the row comes back, the assumption was wrong no matter how well the explanation read. Do you keep that as a test that stays in the suite, or run it as a one-off check while you're reviewing?

 keeping it in the suite, definitely, since a one-off check only proves the assumption held the day you thought to run it. the whole value here is that the second account doesn't share context with the explanation, so it needs to keep not sharing context on every future change too, not just the one that prompted you to think of it. otherwise you're back to trusting a read instead of a result.

 How do you keep the second account current as the schema grows? Upkeep is where it gets fiddly for me - every new table or route is one more thing it has to stay outside of.

I totally agree, I tries to build an auth system with Firebase and I used AI for a small bug. After that, I just couldn't understand my code anymore. That's why I never delete chats with AI, so they can explain me the changes. Sorry for my lack of english, I'm french.

Great topic. Agree. It's almost like a "cognitive debt" that can accumulate.

This is an attitude I have encountered:
If the AI writes the code, and also debugs the code, why do I need to understand the code? Said differently, why can't AI code just be a "black box" that translates inputs into outcomes? Why do we need to know or understand what's in the black box?

How would you all respond?

The habit is solid, but I'd separate two different things sitting under "understand it": what's in your head right now, and what the next person opening this file gets. Explaining it back to yourself closes the first gap well. It does nothing for the second one unless that explanation gets written down somewhere the codebase actually keeps, a comment, a decision log, anything more durable than the chat window it happened in. Understanding that stays personal expires the moment you're not the one debugging it.

That’s what dev schemas are for. You don’t build outside of that so a few things go in the backlog.
12
Next