Arch-Engineer
Software Design in the Age of AI
It's been a while since I've written here. When we managed to compress years of live-teaching experience into the self-service Advanced Software Design course, it freed us to impact software engineering at greater scale by building a venture-backed company. I'm pleased to share that today is the 1.0 release of Command Center (Hacker News, website, Discord), the AI coding environment for people who care about quality. One alum and user calls it "like having a fresh Advanced Software Design alum working for me."
And this is a great occasion to reflect: in the age of AIs writing software, what is the use of software design skills?
My answer is that: as low-level implementation skills become automated, high-level design skills have become the core advantage held by human engineers.
Back in the ChatGPT and Copilot era of AI coding, many decried the "Revenge of the junior developer", where commodity access to vast pools of knowledge would diminish the advantages of experience. And yet the opposite has occurred, with demand for senior engineers rising while talented grads go jobless. The future has instead become closer to Microsoft billionaire Charles Simonyi's vision of having one central programmer of quick mind and sharp taste, the "meta-programmer," do all the design while an army of peons does the dirty work of implementing small pieces.
But will they not replace the meta-programmer as well? I have watched the AIs go from barely getting 1/5 questions on our Software Design Quiz when OpenAI o1 was released, to comfortably getting 3-4 by last December — and, if you prompt Claude to act like the grug brained developer, it gets all 5. We've left behind the days when I would directly tell Copilot to split up a single function and it just couldn't. And yet I still spent too much of my yesterday yelling at Claude that, when I told it to replace one data type with another, it needs to replace all references and not simply add conversions all over the place – no please look at all the callers GODDAMN IT WHY CAN'T YOU FOLLOW INSTRUCTIONS?
An AI's training runs deep, and they learn minimally from your instructions. So long as most of the code out there is crafted with a median design skill, the AI's designs will not be very good. Command Center's refactoring agents improve greatly on the state of the art – the already-released one maybe 1.5-2x, our internal one more like 3-5x. The 1000x interventions — ways to simplify an entire codebase that take the same amount of cleverness as being the first to invent async/await programming — are, of course, still the provenance of humans.
And yet what it means to have good code is changing. Good practices derive from a combination of first principles and environmental idiosyncrasies. Ancient advice like "Every function should have one exit point" and "You should step through all your code in a debugger at least once" came from an era before commonplace syntax highlighting and unit testing.
How does this play out in AI? Having a simple API that's hard to misuse (taught in Unit 3 of our course) is becoming less important. The AIs are very good at using the most treacherous public APIs flawlessly, for they have already read countless correct uses and fixes to bugs stemming from incorrect usage. Is it important for your own code's APIs to be hard to misuse? I do not know, for I have not risked the experiment of letting my AIs get away with their ordinary design flaws.
On the other hand, eliminating hidden coupling — pieces of code that must be changed in tandem and yet do not result in compile errors when they fall out of synch (taught in Unit 2 of our course) — is becoming more important. The ability for code to become intertwined far outpaces the model's ability to read and think through large codebases, and they lack even the feeble human memory to track such secret dependences. Though I and many others have experienced nasty bugs caused by AI-induced hidden coupling, this is something that I (knock on wood) do not see changing at the model level. Our refactoring agent improves a lot – but as hidden coupling is fundamentally about understanding design intent, preventing it still needs a knowledgeable human in the driver's seat, one using Command Center's understandability and walkthrough features more than the refactoring features.
The upshot of all this: when one of our contractors switched to a company of lesser code quality, he found the effectiveness of his Claude Code dropped tremendously. And we've been working on a set of benchmarks that measure code quality by the amount of work needed and bugs produced by AIs doing follow-on work.
And so I can go on through all of our teachings and principles and estimate which have become more or less important. Avoiding hidden preconditions and "action at a distance" requirements? More important in relative terms, even if some of the consequences that once required hundreds of hours of debugging can be investigated by AI. Breaking apart functions or merging conditionals until you have the simplest configuration? Less – you may still feel a need to look at the slop, but another intelligence is dealing with it. Designing file formats and database schemas in ways that are easy to extend? Unclear – maybe it's now okay to have a folder of hundreds of compatibility shims for an incompatible history of old formats, or maybe that's the gateway to a deeper level of buggy Hell.
What is clear though is that, as the ladder of opportunities to gain on-the-job experience gets raised, the need for deliberate practice vessels such as the Advanced Software Design Course is rising.
Of course, there are many who say that design is dead. There are even reports of big companies instructing their engineers to stop reading code or worrying about design at all.
Cedric Chin of Commoncog writes that there are three attitudes towards AI: the "never AI" camp that finds it useless, the "pragmatic engineer" camp that believes it's a useful tool but still needs to be controlled by a human following conventional engineering practices, and the "software dark factory" camp who preach the ineffable shipping velocity of AIs that control AIs without human intervention. Each camp has its own dataframe, a set of mental models that they interpret all evidence through, which makes it difficult for each to absorb the perspective and experiences of the other camps.
Unsurprisingly, I solidly inhabit the middle camp, which has this to say about the dark factory folks:
When I first started building software to accelerate codebase learning, we recruited many software engineers – around 1% of the readers of this newsletter – to try onboarding onto a codebase with either a chatbot or a structured tutorial to help them (see paper). We found that, the more time people spent talking to the chatbot, the worse they did, and conjectured that many of the chatbot users would have done better with no support at all. The latency from mind to fingers to AI and back is astronomical compared to the speed of thought. And that's why automating oneself out of the loop can be a pathway to sluggishness.
For around 15 years, I've been convinced that building an artificial mind more intelligent than humans was a risky endeavor that could be as dangerous for us as humans have been for the prosperity of chimpanzees and dodos, the belief sometimes pejoratively referred to as "doomerism." I am one of the signatories to the Pause AI letter. Yet I still put a lot of chips on the hope that we'll enter a future with incredible labor automation still ruled by humans. Of this future, it used to be said that "software engineering will be the last thing to be automated, for we automate everything else first."
Though AI coders have come early in the AI revolution, I still think there's a lot of truth to that retro vision of the future. Though centering a div may be readily machine-learnable, the last to be automated shall be those who master the new tools and reach the higher level of skill to spawn enduring systems.