What AI actually changed about writing software
Generating code stopped being the slow part, which moved the bottleneck to verification. That is a bigger change to the job than it sounds, and we learned it the humiliating way.
We use AI heavily and we are unromantic about it. It has genuinely changed how much a small team can carry. It has not changed what makes software correct, and confusing those two things is where teams get hurt.
The short version: producing code stopped being the expensive step, so the expensive step is now proving the code is right. Everything else follows from that.
The bottleneck moved
Before, the sequence was think, type, test. Typing was slow enough that it rate-limited everything, which had a hidden benefit: you thought while you typed, and you produced small enough amounts of code that reviewing it was tractable.
Now a correct-looking implementation of almost anything arrives in seconds. The constraint is no longer "can we write this" but "can we tell whether this is right". If you do not upgrade your verification to match your new output rate, you have simply built a faster way to produce unreviewed code, and you will find out about it later, at a worse time.
In practice this means the work has shifted towards things that used to feel like overhead:
- Tests that actually run, quickly, and fail loudly.
- Types that make wrong states unrepresentable rather than merely documented.
- Small diffs, because a diff you cannot hold in your head is a diff you are approving on vibes.
- Being able to run the real thing and look at it.
None of that is new advice. What is new is that it went from good practice to the thing the whole method rests on.
Where it fails, specifically
The failure mode is not gibberish. Gibberish would be easy. It is plausible code with one wrong assumption inside it, written with complete confidence, in a house style that matches the surrounding file.
Some recurring shapes we watch for:
- Code that handles the case in front of it and quietly assumes the shape of data it has not seen.
- Confident explanations of why something works that are reasonable, fluent, and not what the code does.
- A fix for the symptom you described rather than the cause you did not.
- Silent narrowing: asked to handle a list, it handles the first element correctly and the rest by accident.
The counter-discipline is a single rule that we apply without exception: never accept output you cannot verify. Not "output that looks right". Output where there is a specific thing you can run, read or measure that would fail if it were wrong.
The mistake that taught us the most
A test suite started failing. Different tests each run, mostly timeouts, on code that had not changed. We concluded the suite had outgrown the machine and that a clean run was no longer obtainable, and we wrote that down as a finding.
It was wrong. The suite was fine.
The failures were contention, and the main source of the contention was us: running the test suite at the same time as builds and other heavy jobs on the same machine. The load average looked deceptively acceptable while the CPU was saturated. On a quiet machine, the same code ran fully green, twice.
Two lessons came out of that, and the second is the important one.
The first is mundane: check what else the machine is doing before you believe a timing-sensitive test result.
The second is that we had drawn a confident structural conclusion from a measurement taken through a broken instrument. The reasoning was sound. The data was garbage. And nothing about the reasoning could reveal that, because the problem was upstream of the reasoning entirely.
That failure mode is the one to watch for when working quickly with AI, because AI is extremely good at constructing a coherent explanation for whatever data you hand it. If the measurement is wrong, you get a fluent, well-argued, completely wrong conclusion — and it arrives faster than it used to, with better prose.
We now treat a surprising measurement as a claim about the instrument until proven otherwise. The first question is not "why is the system behaving this way" but "am I actually measuring what I think I am measuring".
What we tell clients
AI is why a studio our size can run the number of products we run and still take on new work. That is a real, material advantage and we are not shy about it.
But nobody should buy software because of how it was typed. What a client is buying is that it works, that it keeps working, and that someone competent understands it well enough to change it in a year. AI moves the first of those along faster. It does not supply the last one.
The engineers decide what ships. That is not a hedge or a comforting line for a website — it is the specific control that makes the speed safe, and the moment it stops being true the speed stops being worth having.