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.
That's a lot of implicit "better" in that question. LLMs are trained to be plausible, not right. You can get as elegant/idiomatic/smooth-sounding as you want, and still miss the real constraints that matter (existing systems, team patterns, business considerations, failure modes, not-yet-real features).
Senior-level engineering is not just about "writing" code. It's knowing when not to. It's about recognizing real edge cases and not-baked-yet abstractions, knowing when a problem could be more simply solved, or not solved at all. That kind of judgment is hard to quantify, hard to prompt, and often non-obvious in a generated solution.
So yes, LLMs can be a handy tool, but not even close to the level of a real human expert.
The word that bothers me most in that tweet is "better". So I wrote down what it means.
"Better" is a word that we treat like a scalar value. In other words, there is one value that defines better. However, when you ask "better" at what are you measuring it? Lines per minute? Correctness? Maintainability? The courage to not build it? You quickly realize "better" means different things depending on the dimension you are measuring it along.
The productivity metric is lines per minute. It's a nice, simple metric, and it's easy to measure. There's a lot of momentum in this metric because it feels like improvement. However, it is only a measure of typing. It doesn't mean the resulting program is better.
A thousand lines of wrong code is worse than no code at all. A thousand lines of code that crumbles the second you look at it are even worse than that. So, instead we look at correctness. We want our code to be better because it's correct. It has the correct functionality, and it meets the spec. It passes the test. This is an improvement. But, that's not enough.
The real nightmare is that the LLM-generated code works until it doesn't, and it doesn't make sense to you. You'll get reasonable-looking code that somehow finds its way to production, and your payment pipeline will suddenly start silently discarding transactions because the model just decided to add a retry_on_timeout decorator to your transaction handler function that will catch the exception, log a WARNING, and return None. The code down the line will take the None and read it as a zero-dollar successful charge, so now your customers are getting the things they ordered for free.
Gramli tested a case like this in To Retry or Not to Retry. In one scenario, a payment request returned a 503 with a Retry-After header and no idempotency key. Most of the 8 models followed the header and said to retry. Only two said no.
Dex from HumanLayer explains why this happens in his talk "Harness Engineering Is Not Enough and Why Software Factories Fail". Many coding benchmarks give the model a pass or fail reward. The model wins when the tests pass, and nothing penalizes it for bad design. So it learns to add a try/catch or a type cast, because those make the test pass.
We can have a perfectly good piece of software that's unchangeable. This is the opposite of what we want. This is legacy code, and it is bad. We need to be able to make changes without pain.
So we improve it by making it maintainable. Maintainable code is readable, simple code, it's code that doesn't make anyone else want to burn down the office. It doesn't break as time goes on. Maintainable software just works. It meets new requirements and changes without breaking.
The last option is the best of all. It's the metric of wisdom. The "better" that allows us to say "no we shouldn't do that". It's better because it's less, but necessary.
In other words, code is a liability, it is something that we should keep at a minimum. This "better" is the most difficult to practice. It requires saying no to pressure, to budget, to a stakeholder who thinks they have a great idea. It is a less is more metric. However, the compounding interest it pays by not building something keeps growing.
So, "better" is not one thing. It's multiple things. It's a hierarchy, and it changes as we gain experience. We go from lines per minute to correctness to maintainability to not building.
Top comments (10)
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?”
A retry decorator that swallows the exception and returns None is a bug with good manners.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.