I use AI coding assistants every day, and I'm not going to pretend otherwise or pretend they're overhyped. They genuinely save hours on the kind of work that used to eat a whole afternoon — boilerplate, test scaffolding, explaining an unfamiliar chunk of code, drafting a first pass at something I already know how to build.
They also make it very easy to ship code you don't fully understand, at a pace that outruns your ability to catch it. Both things are true at once, and pretending otherwise is how teams end up with either "AI is banned here" or "nobody reviews anything closely anymore" — two equally bad outcomes.
Where AI assistants are genuinely good
Boilerplate and repetitive patterns. Form components, API route scaffolding, test file setup — anything where the shape is well-established and the risk of a subtle bug is low.
Explaining unfamiliar code. Dropped into a legacy codebase, asking "what does this function do and why" is faster than tracing it by hand, and I still verify the explanation against the actual code rather than trusting it outright.
A first draft to react to. It's often faster to critique a generated first pass than to produce one from a blank file, even when I end up rewriting half of it.
Catching the obvious stuff in review. Pointing out an unhandled null case or a missing dependency in a useEffect array — the mechanical checks that used to eat review time.
Where it quietly hurts you
Confidently wrong is the default failure mode, not obviously broken. AI-generated code rarely fails to compile. It fails in the specific edge case nobody tested, using a pattern that looked reasonable and wasn't.
It reaches for outdated or mismatched patterns more often than you'd expect — a class component pattern in a hooks-only codebase, a library version that doesn't match what's actually installed.
It will confidently make architectural decisions you didn't ask it to make — state management choice, error handling strategy — if your prompt doesn't constrain it. Left unconstrained, it optimizes for "looks like reasonable code," not "fits this codebase's conventions."
The actual workflow
- I decide the architecture before I open the assistant. Where state lives, what the component boundaries are, what the error handling strategy is. AI fills in implementation inside decisions I've already made — it doesn't make the decisions.
- I generate in small pieces, not whole features. A single function or component I can actually read in full, not 300 lines I'm tempted to skim.
- I read every line before it goes in, the same as I'd review a junior engineer's PR. Not "does this look plausible" — does this actually do what I think it does, in this specific codebase, with these specific edge cases.
- I ask it to explain its own choice when something looks off, rather than either blindly accepting or blindly rewriting. Often the explanation reveals it made an assumption my prompt didn't rule out.
- Tests still get written by me, or at minimum reviewed line-by-line if generated — a test suite that passes against buggy code is worse than no test suite, because it creates false confidence.
The line I try not to cross
AI can write syntax faster than I can. It can't own the judgment call about whether this is the right approach for this codebase, this team, this constraint — that's the part of the job tutorials (and now AI) can't replace, and it's the whole reason to go beyond just knowing the syntax in the first place.