A tweet went around saying: "No human will ever write code better than LLMs. Accept this fact, stop pretending, and move on."
Here is my reply.
...
For further actions, you may consider blocking this person and/or reporting abuse
I remember StackOverflow used to discourage asking for "best practices" and "best" solutions back in it's "better" days, for the exact reasons that you mentioned. Better at what? Better for whom?
Apart from questioning requirements and apparent best practices, and anticipating edge cases as experienced senior developers who take responsibility, we could even still write better (or worse) lines of code. Maintainability, readability, security, standards-compliance, code style etc. Developers have been arguing about ditching code comments in favor of descriptive naming, refraining form over-optimizing compact code-golf idioms in favor of the former goals. Many of those principles have been documented and standardized already. Still, AI keeps mixing idioms, styles and strategies and it keeps stating the obvious redundantly in abundant lines of comments, as if AI was a living in the 1990s and getting paid per line of output.
Thanks for sharing, and especially thanks for mentioning maintainability and questioning assumptions!
Thanks Ingo. Excellent second question, “better for whom?”
I also like the StackOverflow point. Your comment about AI often generating comments that just repeat the code is spot on. It’s just the lines-per-minute metric all over again, as if it gets paid by the line.
Nice write-up. Whoever said "No human will ever write code better than LLMs" probably doesn't spend much time reviewing AI-generated code or maintaining a real codebase. 😅
I have multiple examples from just the last few weeks where AI made wrong assumptions or introduced unnecessary complexity.
GPT Sol 6.1, last week, was supposed to implement a feature in an existing codebase. The generated code was readable, but it introduced unnecessary database reads and made the whole feature far more complex than it needed to be.
GPT Astra 6.1, in the same week, was asked to refactor some code. The result was actually beautiful, readable code, something I'd expect from a senior engineer. But it also made assumptions and implemented functionality that wasn't needed. And as we know, dead code in a codebase is poison.
I could write about my battles with AI every single week, and I haven't even started talking about code ownership and responsibility. 🤣
Thanks for the feedback, Daniel. I actually think your examples illustrate my point. It’s possible to write code that is perfectly readable but performs additional, unnecessary DB reads. It’s also possible to write code that will someday become a maintenance issue because somebody else will have to figure out what it’s doing and won’t know that it’s safe to remove.
It’s just that the model isn’t aware of these things, so it does the best it can to solve the problem as it sees it. Maybe I should write a post about those too.
Such a nuanced and necessary take! Outputting lines per minute is easy, but knowing what not to build and designing for long-term maintainability is where real software engineering happens. Great posts as always Daniel!
Thank you Maame, you did a great summary of my article. It is easy to measure output but hard to measure what not to include. I am happy that this helped you.
"No human will ever write code better than LLMs" - yeah that's a ridiculous statement to make, even when it's just a tweet aimed at generating clicks & views - a statement this absolute (and devoid of context) is meaningless ...
Thanks. This is such an absolute statement that it sounds cool. However, it doesn’t really address the issue I was getting at in the original post... which was, “better at what?”
Yeah, define "better" :P
Not worth a debate rather a place for clarity. Strong & hard may be synonymous buh 🙄 "better than"? Totally off for me 😅.well a typewriter does neater than a pen maybe 😉
Thank you, Ekong. You used a very good example with the typewriter: it’s tidier than a pen, but that doesn’t necessarily mean that it’s superior. Again: “better at what?”
The retry_on_timeout payment example is the one that makes the hierarchy concrete — plausible code that silently turns a timeout into a free order is worse than no code at all. I'd argue the hierarchy needs one more rung below "not building": not shipping what you can't explain when it fails, since the payment case only surfaced because someone traced the None. Do you think the "courage to not build" test should apply to generated code the team can't yet debug, or is that bar too high for shipping velocity?
Thanks! I like the extra step: Don’t ship code that you can’t debug. I think it should be extended to generated code. If you can’t debug it, you don’t own it. I code alone, and I don’t ship things I don’t understand. It’s cheaper to check than to have an incident.
"If you can't debug it, you don't own it" is the sharper version of my rung — it turns a shipping rule into an ownership test. Coding alone makes it enforceable, since you're the one who pays at 2am either way. The harder case is a team, where the person who generated it isn't the person who debugs it: does the bar then become "someone on the team can debug it," or does the generator have to stay the owner until it's understood?
“Better” needs a workload and a responsibility model. Generating a plausible patch is different from recovering a production incident, negotiating an ambiguous product constraint, or deciding whether evidence is sufficient to release. The useful benchmark is not keystrokes produced, but verified outcomes under realistic ownership and failure conditions.
Thanks, Alex. It is more useful to measure success and failure under actual ownership rather than keystrokes.
Adding the question of a responsibility model to "better at what" is valuable.
Exactly: “better” needs ownership, environment, and time horizon. A model may win at producing a candidate patch, while the engineer still owns requirements, integration, rollback, and the consequences of a plausible but wrong change.
The payment example is where I’d make the comparison concrete. I’d take a ledger design problem and review what happens when the payment succeeds but the response disappears. Generating the handler quickly doesn’t settle whether a retry is safe or how to confirm the outcome. That seems a much more useful benchmark than counting the lines it produced.
Thanks, Emily. This is a very difficult edge case to test. When you generate a handler very fast, you don’t know if it is safe to re-request.
You need to be able to verify what happened. Something like an idempotency key. Daniel Balcarek (@gramli) has a similar article that tests that kind of retry. I agree it is more of a valid metric than lines of code.
I have to admit that AI agents, especially Claude Code, write code better than I do. They know a lot about syntax, technologies, programming languages, technical solutions, etc.
But you mentioned that
and that’s true. I like this AI era because I can shift from being busy writing code to developing features or doing actual engineering work.
Thanks for the thoughtful comment.
It's important to stress that the models are good at syntactic stuff, languages and technical solutions. You nailed it: the idea is that we write less code and engineer more.
Breaking "better" into separate axes is the useful move here. Lines per minute is the axis where models clearly win, and it is also the one clients care about least once something breaks in production.
The retry_on_timeout example makes the point better than any argument. A decorator that returns None and gets read as a successful zero dollar charge looks fine in review and passes most tests. Kartik's story of a wrapper that returned the failed attempt is the same bug in different clothes.
Alex Shev's verification budget is a good name for where the cost has moved. Generation got cheap, so the real price of a feature is now the time someone spends proving it does what it claims.
The point about keeping a record of decisions not to build is underrated. On fixed scope work, the features we talked a client out of are often worth more than the ones we shipped. Do you write those down anywhere the next engineer will find them?
Thanks. A concise way to put it is that the cost of a feature is the time to verify it.
In many cases I agree that it’s the features you’ve talked clients out of developing that are most valuable.
The honest answer is: not as a formal process yet, but I think I ought to after your question.
"Better" needs a task and a verification budget attached to it. Generating a plausible implementation is different from choosing the right constraint, noticing a missing requirement, or owning the consequences of a deploy. The useful comparison is often human-plus-model versus an explicit baseline, not human versus model in isolation.
Thanks, Alex. I like the term “verification budget.” You’re right that the comparison should be human + model against some reasonable benchmark.
Models can’t choose the appropriate constraint or own the consequences of a deploy (though they can help!)
The "courage to not build it" rung is the one I keep coming back to — lines per minute is easy to measure, which is exactly why it wins arguments it shouldn't. Your payment retry example is the scary version of that: code that passes its tests and still silently gives stuff away for free. Do you think teams ever actually reward the not-building decision, or does it only ever show up as the absence of a launch?
It is true, thanks Paul. If you don’t ship it, you can’t see it.
Most teams measure success by the things they can measure.
It is probably helpful to keep an explicit record of the positive things that resulted from not doing something (saving time, effort, bugs, maintenance, etc.), so that your “no” is recorded. Has anyone done this successfully?
Adding my 2 cents here... The sooner we accept that coding as we know it is dead, the better. I just accepted it and moved on, started building stuff, bringing to life ideas I sat on for years.
LLMs are still in their infancy. Two years ago we couldn't even imagine what happens today. What will happen in another 2 years? 5 years? 10?
Thanks for your comment, Marius. I appreciate knowing you are actually putting into practice some of the ideas you’ve held for years.
This is a good thing. As you say, these kinds of models will get better, but the question is what will they get better at? Someone will still be the creator, the owner.
“Better” needs a failure model, not a single benchmark. Generating a locally plausible function, preserving an architectural boundary, diagnosing an incident from partial evidence, and taking responsibility for the trade-offs are different jobs. The useful future is not a scoreboard of humans versus models; it is systems where the model’s speed is paired with evidence, review, and clear ownership.
the
retry_on_timeoutdecorator that returns None and gets read as a zero dollar charge is the failure that scares me most, because nothing throws. the pass or fail reward point explains why models reach for a try/catch first. one cheap guard that has helped is making the payment path return a typed result with an explicit failed variant, so a swallowed exception cannot look like success.do you have a lint or review rule that flags catch blocks returning a default value in money paths?
Thank you! You are right: the most terrifying kind of failure is a silent one where nothing is throwing at all.
Providing a typed return value with an explicit error variant is a good defense against that. If an error is swallowed it can never masquerade as a successful value.
I don’t have a lint rule for this yet, but given your question I am thinking it would be good to add one.
The dimension I never see in these lists: ownership cost when the code breaks. LLM code fails confidently in the middle - not at the edges its author knew were shaky - so whoever debugs the payment pipeline at 2am is reading code nobody on the team can explain. That is vendor code without a support contract. Practical bar: tests pinning the spec plus one human who can narrate every module before it ships; otherwise the lines-per-minute gains get paid back in incident review.
Thanks - good point to expand on, the expense of ownership. I like your particular case - “vendor code without a support contract”.
You have clear and unambiguous criteria - the tests pin the spec, and there must be one person who understands every single module (in my case, me).
The funny part is, the person who wrote that, clearly doesnt understand how LLMs work.
LLMs arent all that complex, they're pattern machines. Think of the toddler toy, fit a square block into a square hole, round block into round hole, etc. If the pattern matches, apply it.
So who taught it the pattern? Training data. Where does the training data come from? Uhm, pause for dramatic effect... Humans. LLMs do nothing more, than store human knowledge and apply it systematically where the pattern matches.
That means, when 'LLMs write better code' is said, what's meant is 'LLMs prove that someone wrote the code better than you', well what if you're the person who fed the training data? Guess what, you are. Unless since day 1, you've been on an enterprise, zero-data-training plan, (if you were, poor you, that probably drained your bank account quite hard) then you've been contributing to training the latest and greatest LLMs, whether through your code (yes, reading your existing codebase contributes too), or simply your judgement and reasoning, you've helped LLMs become as smart as you (and by proxy, smarter than you).
So 'better' is a pretty bold statement, while true for 99.999% of the time, that .001% is when you correct it and make the next version as good. A LLM cant write better code than humans, because we taught it all it knows. It just 'infers' what's the right pattern to apply to the problem. That's it, no massive existential crisis, a simple 'does this fit' algorithm. That's why LLMs still make mistakes (big shocker), because we still make mistakes too and it gets trained on those mistakes! Which is why it makes even more mistakes, because there's no right answer, just 'the most common' answer, which is what it applies. That's not rocket science, that's turning stack overflow into an executable pipeline.
So next time someone tells you LLMs are better than humans at anything, remind them who taught that LLM. It might be smarter in some things, but every individual is an expert at something and that single thing they know best, is exactly what LLMs dont know. Chances are, you dont even know it yourself, because we dont actively compare our every action to everyone else, for all you know, you have perfect the efficiency of walking? Sounds stupid, but it's a quantifiable metric, that exactly 1 individual in the entire world possesses. So at best, a LLM can learn from you and like WASM is to native, it'll get 99.999% of the way there, but it'll never truly be optimal, because for every truly exceptional data point, there's 8 billion others that are sub-optimal, that dilute it. You think getting 8 billion people to agree is a tough task? Try 8 billion parameters, across petabytes of data... That's frontier LLM scale. It's simply not feasible for LLMs with the current architecture to ever be perfect at anything.
Exactly. It is not if they can beat us, but at what cost? A machine can write a thousand summaries while you are writing one well-crafted paragraph, but what if every tenth one slightly misstates an important fact? Someone then needs to read, correct, and take responsibility for the end product. It is a human judgment call. The question, then, is: “What are we better at?” They are better at volume, at raw recall, but we are better at the subtle decision-making that makes the final product reliable. The final judgment to say, “This is good to go and I will put my name on it” is still a human role.
So true. Generating code fast means nothing if it breaks edge cases in automated die-cut workflows. At The Printing World, we value simple, maintainable software over volume every time to keep our press runs error-free.
Thanks, Peter. I agree, it’s easier to rely on simpler, maintainable code, and good enough is not good enough when it has real press runs at stake.
Better code isn't just code written faster. It's code that solves the right problem, handles edge cases, and lasts.
Thanks, Jacob. I agree!
Being able to solve the right problem and remain relevant are 2 things that typing speed doesn't measure.
That retry_on_timeout decorator returning None is close to a bug I wrote up from my own agent, where a retry wrapper handed back the third failed attempt as an ordinary result and the trace stayed green. Nothing raised, so nothing looked wrong. The pass or fail reward Dex describes explains why the model keeps reaching for it, since a try/catch makes the test pass.
Thank you, Kartik. Your example perfectly illustrates the point. The wrapper, when faced with three failures, returns the third one as a successful output, which means the log remains green and nobody will investigate it.
It's much easier to deal with a very loud fail than with a silent incorrect output. Do you have a write-up on this topic? I'd love to read it.
"better" with no yardstick is just a slogan. plausible lines are cheap. knowing when not to add another layer still isn't.
A retry decorator that swallows the exception and returns None is a bug with good manners.
✝️🧿🪬
So true.