I love this post. It’s also interesting to revisit in the age of agents.
Using the language of the article, I’d say “push all your innovation tokens into agents” is probably a good move. This means the tech your agents work with should all be boring tech.
Another way of saying this is “use in-distribution technology”. If agents are substantially better at Rust than Zig, probably you should use Rust, even if Zig is “better”. The amount that Zig is better is going to get swamped by the amount that in-distribution agents are better.
(This is not a claim that Rust actually is better, just a hypothetical fact pattern for discussion.)
It's a total tangent but AI being so good at developing rust means that my first impression of seeing a rust project has totally changed.
4 or 5 years ago if I had to weigh up two options and one was written in rust it was almost a sure thing that the program was snappy, fast, reliable and that the author was competant.
Now it's a sure fire sign that the project was probably vibe coded. Not saying it can't still be good, I just have a different first impression now
> Now it's a sure fire sign that the project was probably vibe coded.
Groan. That's sad.
Compare to what happened to Python. That will cheer you up!
Hey, at least python is now extremely consistent: it's an unpleasant tarpit regardless of whether it's human or AI generated. Ruby, too, rip my native programming language.
I remember in the pre-AI era I was doing a quick sample contract employment with a company that had >200 columns in their user table and was manually enumerating them in every query, multiple times. They were using SELECT $1,$2,...$184,$185 from tablename with an enormous list of columns referenced only by offset. That's not python's fault, but I've weirdly seen it more often in python codebases.
That's a different tarpit. That's the problem with object-relation mapping, which is trying to deal with the mismatch between structs in languages and rows in SQL. There are a huge number of such schemes, and they range from somewhat annoying to awful. They're bad across a broad range of programming languages.
This is an area where LLMs might actually help. Or make things worse. We'll have to see.
I think the difference I see is with things like Prisma, where there's a type system to lean on and proper nomenclature, or Rails which, despite all the magic, more or less maps columns straightforwardly based on the labels instead of having to $123 and later in the file ensure that $123 is what you think.
One thing I learned about AI is that, e.g., if you're making websites you're much better off going for php/ruby/elixir, even if you don't like the languages much.
Pipelines and deploys gets much easier and faster than the very common TypeScript monorepo, and so does communication between server and client.
And I say that as a TypeScript and Effect aficionado who has no particular love for neither php or ruby, but they are extremely solid choices to move fast, well, and get excellent performance and tooling out of the box.
Great point! I'd also add that Django's another solid choice for boring tech that LLM agents will know very well and will very likely continue to do so. A fair bit of SWE Bench and other Python benchmarks are Django related tests, which the LLM vendors care very deeply about keeping their scores up. Also, Django's docs are excellent, so strategically pointing an LLM to them in a prompt can often produce great results.
Django is the only thing I've used where I've vibe-coded an app, then looked at the code and not been appalled.
PHP has had a lot of conventions so the training data is all over the place. Ruby is a nightmare in that regard. Can't speak to Elixir but I'm surprised to hear someone say LLMs producing good code in either language.
On the other hand, Go code from 2012 and Go code from 2026 looks virtually the same. Conventions are respected, go fmt is the one single formatter, "use the stdlib" is a popular mantra and the code is readable by design.
If I were to codegen a project I wouldn't use anything but Go at this point.
I've been using elixir professionally and for hobby work for the past 7 years now. Language models are damn good at it, and have been for some time.
The language isn't huge, the documentation has always been very good, and the patterns extremely consistently across the community. I almost wonder whether it's smaller community has been a benefit, as LLMs have been trained on a tighter set of code samples.
I can't speak for Ruby or PHP.
I also like Elixir, and I've used it for a handful of projects, the language may not be huge, but is conversely bloated by macros.
I dislike macros and languages allowing developers to get creative with their own DSLs.
> Pipelines and deploys gets much easier and faster than the very common TypeScript monorepo
Can you elaborate more on the slowness you've seen with deploying TypeScript codebases? My experience is that it's improved significantly over the past decade or so. tsc is still kinda slow for large projects, but the rewrite to Go should improve things significantly. Pre-install/post-install scripts can also be slow, but I've always disabled those and haven't yet run into issues. The JS-written bundlers can also be slow, but I use the non-JS ones (esbuild, parcel, bun, etc.) and they're fast enough for me to not care. The main build bottleneck I can think of for a modern TypeScript project would be build plugins, since those are still written in JS/TS.
The willingness to reshape society for the benefit of AI rather than shaping AI around humanity paints a very dire picture of the coming decade.
Is that what's happening in this example, though? Ditching TypeScript in favor of PHP seems to be a net positive in favor of having a reliable, performant tech stack. From certain perspectives, TypeScript is itself a form of technical debt: writing code in one language just to transpile it into another interpreted language just to add type safety to correct for human error seems like a heavy layer of complexity just to make development teams work faster.
If we get to the point where AI tools are able to consistently able to produce desired results within strict performance and security constraints, without having to make the same tradeoff between delivery velocity and final quality, why would we not have them target the lowest level feasible for implementation, and cut out all of the middleware cruft that makes everything slow and take up ten times the RAM it actually needs to?
I think you're completely misreading what I wrote.
PHP (lets use this as an example) brings already many benefits over a common solution like a TypeScript monorepo mostly operational simplicity. That was already true before AI.
It's boring, very fast and easy to deploy, offers straightforward horizontal scaling, no need to orchestrate containers and/or multiple runtime processes, has excellent html rendering (nothing in JS-land really does), and has very solid framework solutions like Laravel where everything works out of the box.
Those merits existed before AI already.
The issue was that you had to buy into PHP as a language, which was a horrible experience.
But if AI writes most of the code? Suddenly PHP becomes an excellent candidate to choose for many use cases.
If anything, AI makes the choice of programming and languages and software about finding the right tool for the job. Somehow the industry instead keeps vomiting React/Tailwind slop which are the right tool for 1% of the jobs.
I hope to have cleared the concept.
[dead]
To a point I agree, but also, I think if code is easy to read, write and maintain by LLMs it's easy to read, write and maintain by humans.
To just yeet in a software engineering wisdom (replace debugging with maintaining, extending, reading, etc as you will):
> Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.
I disagree. We've been doing this for two decades already. A lot of monoliths were rewritten in a way that best fit the AWS pricing model of the time with the software itself seemingly being an after afterthought. (I'm not here to discuss whether monoliths or micro services are better, I'm just saying the choice of how they were rewritten was too often mostly for AWS pricing)
Alternatively, if AI is doing most of the work, why not pick a platform that performs? If the cost of the code (and preferences of the developers) are factored out of the equation, pick based on operational cost.
Serving traffic with Ruby and Python is significantly more expensive than serving traffic with Java or Go.
It's pragmatism vs... the other bit. I think complex environments like TS can work if the problem, organization and context is complex. But it's likely overkill for a weekend project.
I admit I have a hard time following this logic. If an agent has a baseline intelligence, you can... instead of using boring technology, just DIY/NIH the simplest custom solution which fulfills your requirements. And you'll usually do a better job than a general-purpose software library.
Even if in the other approach, the LLM knows the stack better, you're just going to push the complexity into your client code, so it's not like it's a huge gain to use boring tech stack.
That’s definitely not true, and I’ll give two incredibly common examples:
1: arraylist. A library will probably do better than you. It’s already written and common.
2: webservers. Sure, you can write one yourself with sockets and a bunch of buffers and string management… or, you could use one of the 100s of existing ones. Which one? Probably a stable and established one.
1. This isn't true whatsoever. You can easily do better than std::vector (trivial relocation support, non-inlined grow), better than C# List<T> (ref T accessor, batch add API, maybe even an add-uninitialised API or in-place constructing specific things), better than a Python list (this one is obvious), etc.
2. This is a better point but depending on your workload, I don't think this is unheard of. Or at the very least, if your workload is simple, you can grab one off the top of the benchmarks, point AI at it to customise it a bit then you're good. But to be fair this one's a bigger structural investment so I do see your point. For smaller utilities the tradeoff is pretty clear.
Is it obvious? Those existing APIs have known performance characteristics and deep integration into several other libraries. The moment you custom-roll your own root library, you break integration with all existing other libraries that depend on the defaults. To add, your LLM has to think about your new custom version rather than looking at the billions of lines of examples using the one it already knows works from decades of historical data.
If you really, really need some ultra-micro-optimization, you’re obviously not the target of this; but unless you’re doing HFT or the most inner loop of a game engine, the standard library and all its deep integration and battle-testedness is worth the 1% perf hit.
How many times has the stable and established X surprised you with some unexpected behavior?
Once upon a time I wanted a URL /like/this/with%2Fslashes/ where a path parameter could, in rare cases, contain an encoded slash. Legit according to every RFC I checked. Works fine in browsers. But I couldn't get the web server to not convert it to a / before hitting my code. And woe betide thee who wants to make nginx return a custom error code 444.
How many times have existing APIs made by experts in their fields had bugs.
How many of those are you willing to let your own services and your customers’ data be hit by whole classes of bugs that battle-hardened APIs have already fixed?
You sure you can get an LLM to handle every single one of them on first pass? Would you stake your company reputation and the PII of all your customers on it?
See now, we keep assuming without evidence that the old thing is actually better.
Sometimes it's true. I don't trust myself to write a non-trivial DBMS. I reach for Postgres. And there are some things I just don't want to do - like any kind of cryptography or compression. (I also wouldn't trust myself to avoid cryptography side channels.)
But existing APIs tend to do a lot more than you want, and that brings its own bugs. Consider the sqlite WAL-reset bug that Tailscale found when it corrupted several tailnets' control plane data. They were using a separate database file per network and a custom backup system too clever for its own good. How much control plane data do they have in a network? I'd imagine under a megabyte. They could have written the entire thing in JSON and committed with an atomic rename, and not had the bug. (On the other hand they could've used a single large Postgres.) I don't fault them for the corruption as sqlite is normally extremely reliable, but it just shows how adding things to a system can make it worse.
Or any reverse proxy when you do an HTTP Request Smuggling attack. If you hadn't used a reverse proxy, you wouldn't have been vulnerable because the attack is only relevant to reverse proxies (and forward proxies). Do you need a reverse proxy? Sometimes yes but other times no. You can also prevent that attack by using SCGI, FastCGI or WSGI instead of HTTP as your backend protocol.
I bet there's at least one vulnerability caused by X-Accel-Redirect processing, too.
Remember Log4Shell? The Log4J library had too many features, and some of them could be combined in an unintended way to cause remote code execution. Code worked exactly as intended, it just had too many features. You don't want that.
Remember Heartbleed? The old "battle tested" system turned out not to be.
RFC 3986 treats %2F as a reserved character that behavior becomes app specific.
Agents can’t one-shot the problems that boring technology solves. So I think your first premise is mistaken. There is no trivial “just DIY” option for Postgres or Django or Kubernetes.
> I’d say “push all your innovation tokens into agents” is probably a good move
Or better yet, just don't use agents, deliver something better with all the stability and boringness that you have. There's never been a better time than now to produce software that actually seems to work and march along steadily; your competitors are all flailing wildly like morons.
That's where the human factor comes in though: boring tech makes for boring work makes for bored people, and bored people quit (or worse, introduce complexity for the sake of it).
LLMs are better at churning out boring stuff, and you can see a lot of bored people perk up in the age of AI - they can now fire up half a dozen agents so they can express their ideas and see them made reality, instead of leaving their ideas to be ideas because implementing them is boring.
I see what you're saying, but making things less boring by essentially gambling on the implementation of it is a pretty strange thing to do, in my opinion.
Sure, some people legitimately work on things that middle schoolers can put together, and for those things I suppose using LLMs as a way of just getting them done is a less risky prospect. For those cases I don't really see the point of tossing it over the hedge to LLMs because what exactly are you doing beyond that? These types of projects have almost nothing to actually do beyond the grunt work of wiring together MVC stuff.
It's not as if you're going to now have time for interesting things, as they tend to not exist at all in those types of projects, and they're rarely important or big enough to warrant much thought in terms of distributed systems design and so on.
I guess I can see a situation where someone instead finds time to work on actually interesting side projects because they've basically stopped doing their work manually because it's not something worth doing manually. Personally I don't think I could stand that type of situation because it would feel bad on a moral level as well as on a personal stimulation level.
I find agents default to popular which heavily overlaps with boring although you could steer them more boring for sure.
I don't agree about the overlap, as popular is new and shiny and stimulating, whereas boring is old and proven and, well, boring.
I wouldn't leave technology choices up to LLMs anyway unless you give them all the context and requirements. And this is where experienced software developers come in, who know and / or have experienced the short and long-term effect of technology choices (whether they were boring or not). LLMs can mainly go by what they read on the internet, both hype and sales pitches and (more boring and less frequently posted) retrospectives if you don't give them enough context.
I mean popular as in by actual usage rather than emotion/hype. It is usually boring that is popular from what I see.
Agree about LLM not choosing tech. Although that could mean dictating upfront or let it choose then review/steer.