Tech News
← Back to articles

Writing software is an act of learning. Don’t automate it.

read original related products more articles

Software development has always resisted the idea that it can be turned into an assembly line. Even as our tools become smarter, faster, and more capable, the essential act remains the same: we learn by doing.

An Assembly Line is a poor metaphor for software development

In most mature engineering disciplines, the process is clear: a few experts design the system, and less specialized workers execute the plan. This separation between design and implementation depends on stable, predictable laws of physics and repeatable patterns of construction. Software doesn't work like that. There are repetitive parts that can be automated, yes, but the very assumption that design can be completed before implementation doesn't work. In software, design emerges through implementation. We often need to write code before we can even understand the right design. The feedback from code is our primary guide. Much of this cannot be done in isolation. Software creation involves constant interaction—between developers, product owners, users, and other stakeholders—each bringing their own insights. Our processes must reflect this dynamic. The people writing code aren't just 'implementers'; they are central to discovering the right design.

LLMs are reintroducing the assembly line metaphor

Agile practices recognized this over two decades ago, and what we learnt from Agile should not be forgotten. Today, with the rise of large language models (LLMs), we're once again tempted to see code generation as something done in isolation after the design structure is well thought through. But that view ignores the true nature of software development.

I learned to use LLMs judiciously as brainstorming partners

I recently developed a framework for building distributed systems—based on the patterns I describe in my book. I experimented heavily with LLMs. They helped in brainstorming, naming, and generating boilerplate. But just as often, they produced code that was subtly wrong or misaligned with the deeper intent. I had to throw away large sections and start from scratch. Eventually, I learned to use LLMs more judiciously: as brainstorming partners for ideas, not as autonomous builders. That experience helped me think through the nature of software development, most importantly that writing software is fundamentally an act of learning, and that we cannot escape the need to learn just because we have LLM agents at our disposal.

LLMs lower the threshold for experimentation

Before we can begin any meaningful work, there's one crucial step: getting things set-up to get going. Setting up the environment—installing dependencies, choosing the right compiler or interpreter, resolving version mismatches, and wiring up runtime libraries—is sometimes the most frustrating and necessary first hurdle. There's a reason the “Hello, World” program is legendary. It's not just tradition; it marks the moment when imagination meets execution. That first successful output closes the loop—the tools are in place, the system responds, and we can now think through code. This setup phase is where LLMs mostly shine. They're incredibly useful for helping you overcoming that initial friction—drafting the initial build file, finding the right flags, suggesting dependency versions, or generating small snippets to bootstrap a project. They remove friction from the starting line and lower the threshold for experimentation. But once the “hello world” code compiles and runs, the real work begins.

There is a learning loop that is fundamental to our work

... continue reading