I’m pretty sure that last mile is supposed to be walked

As little as I like to admit it, LLMs are taking over software development (event though it doesn’t seem to be going well). Now there’s a push to automate every single step of the way, because us meatbags1 are just too slow at…everything. These days, we have people running agents to create tickets, do the coding, do the peer review, and the merging, which kicks off the pipeline to push to where things need to go. There are even places that have agents listening to logs for errors to create tickets, that then get automatically worked. The idea, and the push, is to have agents do everything, occasionally have the humans input things they want, and do some review (I’m not 100% sure how much of this based on the idea that agents need oversight, and how much of that is so the companies have human to blame for bugs). And sure, code generation is faster than code typing, but slower still is the thinking, understanding, and mental modeling that goes into solving the problem in the first place. This is the thing LLM-driven development activists like to like to really emphasize as the primary selling point – now even that is fast. But I’m increasingly convinced it shouldn’t be. In fact, that’s the place to put the humans, even if a clanker ultimately ends up “typing” all the code that goes into the codebase anyways.

Now, before anyone starts whining about “teh boilerplatez,” I have worked in Java for over 10 years – I get it. I’ve seen a lot of boilerplate. I’ve done coding in Java for so long I remember being excited during college when Java 5 came out and introduced using generics to set types in List. I was born in the boilerplate, molded by it.2 I absolutely appreciate the idea of having something get POJOs defined, and wire up Spring @Resources, but there comes a point where you have to start do actually processing computation. That’s where humans need to start doing something, even if it’s just working through the problem and planning it out as TODO comments in both the code and tests for the LLM to flesh out later. But the important thing is that the human needs to be doing the actual thinking. That’s how they build the understanding for what the software does (even if they don’t pay attention to how it was implemented), what tradeoffs had to be made, and why the decisions got made the way they did.

The point is to force us to wrestle with constraints, complexity, and the awkwardness of taking something that’s easy to describe in a sentence and turning it into proper instructions for solving a problem. I get that’s the first thing people want to give to the clankers, because it’s hard, time-consuming, and takes effort, all the things we were promised “AI” would render moot for us. But wresting with that is how we make breakthroughs on architecture, find which code smells are actual problems, and actually zero in on the things that actually drive software quality. LLMs just keep generating more and more code, and the “fix” is to either rely on humans who are increasingly disconnected from the codebase, or just have another LLM try to check it and tell the first what to do.

All of this can also be described as “problem solving.” You know, what we’re fundamentally supposed to be doing. It’s supposed to be our core competency, and you never, ever, outsource your core competencies. “But ‘AI’ is so much better/faster at it.” No, it’s a hard regression to the mean, which is handy when you’re talking about code that’s pretty much always going to look the same no matter who does it, and ends poorly whenever there’s a real quality bar. “Fast, good, and cheap – you can pick any 2” didn’t go away when the clankers started “typing,” as a lot of executives are learning the hard way. No prompt or harness is ever going to change the fact that real problem solving isn’t done by token prediction, but by people marinating in an issue and getting in the weeds of it to understand it well enough to have a solution.

“But but but…individuals are using AI to ship multiple apps in a week.” Yeah – now ask yourself, how often do you hear about people doing that, and how many of these apps/services do you actually remember? I’m better the first answer is considerably larger than the second. That’s my whole point – we’re not actually achieving anything with these human-less loops. We’re publishing a lot of stuff, that’s doing a lot of nothing on account of nobody’s actually using this slop.

Refusing to spend manual time on the space between “boilerplate” and “implemented” is driving the current trend of enshittification. Rather than putting in the time to actually get it done, we’ve increasingly shoved the important parts off to to LLMs and assuming that anything is good enough, instead of saying “here’s the part where the engineering needs to happen, so I’ll step in here.” And it’s showing up in production incidents. This is why it’s important to spend time working on the actual logic, thinking about edge and failure cases, and working out how to handle them. It’s not just doing the design and implementation of the Cool New Thing(TM) but also doing the plumbing work to keep things running without user-facing problems.

Here’s the thing, I don’t think I’m saying something outrageous. It seems like the rumblings amongst developers is that they’re tired of the “just have the clankers do everything” approach. They’re not rejecting LLMs outright, but rather wanting to keep the parts where it does the setup and then they get to actually come in and work on the “hard” parts. The problem is management who thinks LLMs means “tickets go right fast,” and that “more LLMs means more go right fast.” Sure, we can make that happen, but it’s not going to make the code better, and it’s manifesting in a demoralizing effect on developers. On the plus side, it’s going to encourage a lot of side projects (just so people can keep coding), hopefully some of which end up being really cool.

I’m willing to concede there’s simple, straightforward, coding tasks that LLMs can speed up for us, but the push to just have it do everything just because it can generate that code eliminates the value having developers run the agents gives you, doesn’t improve code quality, and just makes developers check out. Software developer still exists as a job for a reason, and no, “AI” can’t completely automate that away, at least not the parts that are actually problem-solving. You don’t necessarily have to hand-code everything, but you should at least be getting into the code yourself, and working through the steps of the algorithm, figuring out the data flow within the code, understanding the interactions, seeing where problems could come up. At that point, it really doesn’t matter how the code gets written, so long as you now understand what the solution should look like. We’re still the problem-solvers, and you don’t problem solve by asking an autocomplete to guess what the most popular answer would be.

  1. If you are unfamiliar with the reference, here’s an explanation. ↩︎
  2. Here’s the explanation for those who didn’t get that reference. ↩︎