I code review everything that Claude produces, and I'd estimate about 90-95% of the time, my reaction is WOW it works but too much code dude, let's take 3 hours to handhold you through simplifying it until nothing more can be removed.
I code review everything that Claude produces, and I'd estimate about 90-95% of the time, my reaction is WOW it works but too much code dude, let's take 3 hours to handhold you through simplifying it until nothing more can be removed.
> let's take 3 hours to handhold you through simplifying it until nothing more can be removed.
This is why I'm unconvinced that AI code makes me faster. Sure, I could produce a million lines an hour but are we running a sprint or a marathon? I don't know about you but I can't sprint a marathon.I think much of the world of software has become incredibly myopic. I get it, it's a lot harder to win a war than it is to win a battle but just usually taking the easy way out is just deferring the costs to your future. Problem is that those costs accrue interest... Personally? I'm lazy and a cheapskate.
When did programmers stop becoming lazy and start becoming lazy? More importantly, why?
This sums up my thoughts perfectly lately, that is a great way to put it all.
Programmers have never been any good at measuring or estimating their own productivity, there is no reason to assume that has changed (one could argue theres ample reason to assume the opposite).
Part of the problem as well is that there is some unseen/unnamable "spaghettiness"/"sloppiness"/"whatever" factor, that scales very very poorly. At the beginning it can seem fine, especially when you have some constant speed multiplier like an LLM spitting out code - but the larger exponent of the function that results from this factor being "worse" will eventually outpace that constant multiplier. You will only see it once its too late, or will never see it all because of our myopia as you say.
I think I need to work up a Claude skill named marie-kondo, so that when it breathlessly presents its triumphant solution, I can go “yes, but does it spark joy?” And have it go into an aggressive refactor loop with me.
—
But this is never the problem. Claude WILL NOT abstract and WILL NOT use your abstractions. It finds them all “ceremonial” and the idea that you could add something that might seem indirect that actually dramatically reduces the problem space is almost impossible to convey.
You can watch this in action for any API whose design you’re familiar with in a domain you understand well. If you attempt to design the same API with Claude, your will invariably get a mess of flat, insane types and no reuse. I’m talking an array of tuples of maps of set to map type insanity.
What has been helping is a mandatory pass of “Claudisms”, but even then it can only find the problem and never the solution.
It is so frustrating.
I just removed an entire graphql endpoint - 500 lines of front and back-end code. I may need to be hosed down.
The reason we aimed for minimal "accidental complexity" up to now was directly related to the cost/pain of changing and maintaining that code. Hasn't the economics of maintenance and change shifted so much that accidental complexity isn't actually all that expensive/painful?
I think a bit of refactoring, renaming and restructuring has been helpful for maintainability but recently I've been a little less inclined to worry about the easy readability of function bodies and fine implementation details. It still feels wrong but I can't justify the effort anymore.
Not while context windows cause decay and larger bills.
The AI's max cognitive load C is larger than a human's, but if codebase size grows unbounded the minimum context needed for a change will eventually surpass C.
It is also a bad idea to let your codebase become only readable by a machine when we are still in the dark about the role machines and people will take in the future. What if you have to go back to manual dev in a now gargantuan codebase?
The answer to your question is really obvious. The high-effort manually coded projects stick around and the low-effort vibe-coded projects are forgotten about quickly. In the end LLM-driven programming is always going to bring you to a dead-end. There's certain things where I can predict that they're going to fail because it's going to involve certain kinds of complexity they can't and will never be able to deal with. The code gets so bad that even if an expert programmer wanted to make changes it either wouldn't be possible or worth it. A lot of the time the vibecoders are so high off the low-effort sense of empowerment that they don't even realize what they made is completely broken.
Well written software has staying power because it can be understood and built upon. Understanding a problem deeply enough to devise an elegant solution even leads to new possibilities and ideas that will never be conceived with a more superficial understanding.
I sincerely believe that extensive accidental complexity will ALSO be bad for AI agents. Their quality will diminish as their context windows get filled up with endless amounts of spaghetti and accidental complexity. I feel like we won't fully start feeling those effects for another year or so.
This unused code gets further modified as time goes on: new functionality is wired in, or it gets further refactored. Usually it’ll still have tests that cover it. It gives the impression of being live code, but it’s not: it’s zombified.
So you get situations where it gets wired up to something and then that something doesn’t work and you wonder why and so you start digging about and you discover it’s because it has been wired into a path that is never executed.
The fog of relatively recent changes sometimes makes it hard to figure out if the code should be unused or if someone just forgot to hook it in as part of a bigger piece of work. Then you find nobody else is really sure either.
So that extra complexity comes at a cost. It can slow you down or trip you up; catch you by surprise.
> it's worth asking whether lots of relatively straightforward verbose code is actually significantly worse than the least code necessary for the problem.
The question is wrong because reality isn't binary. "We've" never aimed for minimal, except maybe in the very early days or some real edge casesIf you're writing the minimal code you're either writing something very compact/simple[0], or you're wasting too much time and not balancing things.
If you're rewriting everything then you're wasting too much time and introducing too much complexity[1].
You can't write good code by slapping together a bunch of libraries but that doesn't mean you shouldn't use libraries either.
[0] "simple" is an overloaded term. If you're upset by me saying "simple", I'm using the other definition
[1] sed -i [0] "s/simple/complex/g"
For example I have a game I've been working on for a few years, I do stuff like "implement this simple psuedo physics system to make the bot follow the character like so...etc"
After some planning and back and forth.
It returns mostly working code a little odd on some edge case.
But as I've hand coded this thing for years. I could easily look at it. Laugh my ass off, it had multiple classes and around 1k lines of code, all kinds of crazy non performant crap.
The exact thing I needed, I reprogrammed in around 5 lines of very simple code that did exactly what I needed with no edge case weirdness.
Now the vibe coders actually ship that shit. I like to read vibe code games now and again, and there is no possible way those guys are ever shipping a real game, as every single decision is verbose along with the worst performance decisions over and over everywhere.
Sure it can get you some cute little toy projects, but it will absolutely fall apart if you are trying to make real games.
Don't know about saas apps or whatever. Maybe that stuff doesn't matter at all.
Abstractions are like the structural elements of a house, security is like plumbing or electrical, but individual features are like carpet and paint. When it's working on the superficial stuff, who cares what it gets wrong? Just go rip up the carpet and do it again if you have to.
They have, but not in the way you mean.
AI knows nothing about software engineering. AI is a technical debt generator.
You can mitigate this somewhat if you put an actual software engineer at the helm with lots of prompting, but at some point the technical debt accrues enough that neither humans nor AI can fix anything.
As an example, this is what happened to OpenClaw. (And why you suddenly stopped reading hype about it.) OpenAI paid millions for literal trash.
A good human developer might see that the better way to address the review is to backtrack and pick a different approach. The ai agents seem more prone to getting stuck down bad branches of the decision tree.
I don't buy it. I think a much more likely reason it leans towards adding code is because deleting code carries inherent risk: it can break things in major ways or minor ways or very visibly or invisibly. Adding new code, on the other hand, is a lot safer: the only parts that can break are those the AI touched inside its own working context. So it doesn't have to go down rabbit holes and potentially create bigger and bigger messes.
You can also tell it to periodically summarize the "lessons learned" from the recent session(s)
You can certainly steer them a bit to reduce the issue parent talks about, but they still go into that direction whenever they can, adding stuff on top of stuff, piling hacks/shim on top of other hacks/shims, just like many human developers :)
Restrict that data to just the best of the best, the tersest of the tersest, and we’d see better output. I don’t think people are sharing that kinda stuff (Jane Street’s gems stay locked up), and even if they did my presumption is that it’d be too narrow and demanding for general audiences.
Big hopes for the long future, damned to some degree of mediocrity in the near term mass product.
Tell it "Do not change any files yet, just listen." Then we discuss the problem. Then I have it write to a file it's understanding of the change.
I review that carefully. Then I let it implement. I approve each change after manually looking at it. I already know what it should be doing.
Make smaller changes and check each one carefully before and after.
For me what throws me off most of the time is the structure on the mid-level. It usually makes sense in the loc and maybe project level, but on the file and folder level it just loses reference on what it already has or what it does not need to be too verbose about.
That’s not really how it works. An agent wouldn’t get halfway through _any_ implementation and just stop abruptly - it’s not as simple as rolling the dice until you land on “stop”.
It will stop when it believes, for whatever reason, the output has achieved whatever task was laid out. You’re welcome to refine what the definition of that task may be, or you can let it go off.
Then I only have to spend one hour handholding the clanker to get it perfect. I usually do a lot of manual refactoring as well during that time.
Try Deepseek or Xiaomi's Mimo. They produce very lean code.
Claude -> specialized sub agents peer review -> specialized sub agents peer review -> repeat as many times as needed
It’s not worth your time until you’ve run through such a pipeline.
I end most of my pre-plan prompts with "KISS - Keep it simple" to keep it mostly under control.
I also keep each file under 1000 lines and do a full scan of code and docs for cruft every 20-30 task cycles.
Been working on the same project for six montha and glad to say there is minimal bloat.
Look at the doc hub pattern if your {agent}.md file is getting more than ~100 lines.
What to do if you're just one dev in an org of 50? Who are all pushing more and more code every PR? I'm gonna have to leave aren't I :(