Months of daily use (mine and my team) have given me a bunch of lessons that I believe are quite useful for product development teams to consider.
Only use AI for code you could write yourself
If you don’t understand what you’re building, AI will confidently produce something that looks plausible but isn’t. I only ask Claude to help with Rust because I know Rust. When the output is wrong, I catch it. When it’s right, I understand why. The people who get burned are those using AI to work in unfamiliar territory.
When you skip the "could write yourself" part, you end up building on foundations you don’t understand. I’ve seen this play out: someone ships a feature using patterns they couldn’t explain if asked, and then when it breaks (or needs to change), they’re stuck. They can’t debug it because they never understood how it worked. They just prompt again and hope for the best.
On the flip side, and I think it’s important: AI can be a genuinely good learning tool if you approach it deliberately. When I’m exploring an unfamiliar corner of Rust’s type system, I’ll ask Claude to explain its reasoning, not just give me the answer. I’ll ask for multiple approaches and compare them, and I’ll intentionally break things to see what happens. My belief is that doing so helps build skill, or at the very least prevent its atrophy.
|
Note |
There’s an entire blog post I’d like to write about how to onboard and grow junior engineers, who in my opinion are in a bit of a precarious position if they don’t know how to use these tools effectively. For now: if you’re early in your career, use AI to accelerate your learning, not to skip it. |
Keep tasks small enough to review completely
Using Claude Code on acdc, I’m moving through
implementation at a pace that would have seemed unreasonable two years ago. Not because AI
writes perfect code, which it doesn’t. I do my best to keep each task focused: error
handling for this function, test scaffolding for that module, refactoring across a few
specific files. Small enough that I can verify every line. The only exception to this was
vibe coding a LSP [2] for AsciiDoc, which I did as an experiment. A
successful one mind you, and I use this LSP every day now (even with its many
shortcomings).
Review AI code more strictly than code written by a colleague
This sounds harsh, but it’s fairly practical. A person working in a given app/repository has context about the codebase, understands the constraints, and will defend their choices (sometimes too much). AI doesn’t quite have enough of the "human-like" pushback. It produces plausible code that might miss subtle requirements that a person would catch easily. I like to treat code that a LLM has given me as if it was from someone who’s never seen my codebase before.
Watch for when it goes off the rails
AI will quietly make changes you didn’t ask for. This is as frustrating as it is entertaining.
It will also attempt the same fix repeatedly when stuck. It will abandon work partway through without telling you. It struggles to admit uncertainty.
Claude Code is getting better but still does a fair amount of this in my experience.
Don’t fear refactors (and rewrites)
Remember when we all used to procrastinate around refactors? When a refactor meant potentially weeks of design work, or trial and error explorations? I don’t know a lot of people that like doing it. Some of us don’t mind. But most do. AI has pretty much made these free. Have an idea for a rewrite? Have a half hour conversation with Claude Code and then wait 10 minutes and you might have a rewrite done that would have taken you days or even weeks.
Use LLMs responsibly
I strongly recommend reading Oxide Computer Company’s RFD 576: "Using LLMs at Oxide". I pretty much agree with all of it. Definitely go read it. There’s one concept in there that is super interesting: the social contract between writers and readers.
The idea is straightforward. When you read someone’s code or document, there’s an implicit agreement: the writer has done more intellectual work than the reader. You trust that the person who wrote it understands it, because they’re the one who produced the body of work. LLMs break this contract. The writer may not have done the intellectual heavy lifting at all, and the reader can no longer assume the author understands their own output. The RFD has a name for this: 'LLM-induced cognitive dissonance', and honestly I think it captures it well.
For code review specifically, I think this has real consequences. If I put up a PR with LLM-generated code that I haven’t reviewed and understood myself, I’m basically asking a colleague to do work I didn’t do. That’s not a fair trade at all. And then, if review comments get addressed by re-generation rather than fixes out of collaboration and discussion, you’re just re-rolling dice (I’m being slightly pessimistic to make the point).
What makes this framing useful to me is that it shifts the question from "is it OK to use AI?" (obviously yes) to "what do you owe the person reading your output?".
Just because a machine did the typing doesn’t mean you don’t have a responsibility. If anything, the responsibility to doing right by the reader increases, because the default trust is lower (at least at this point in time).
A final note on using LLMs with responsibility: AI isn’t accountable, humans are.
If you put up a pull request thinking that "if this goes wrong, AI did it" you’re about to have a wake up call. This is one that both me and Pete (CTO at incident.io) are very aligned on. AI isn’t accountable. You are. Act like it.

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.