Key Components of Software Design

10 min read Original article ↗

With the expansion of AI and Agentic coding, programming has become more accessible than ever. But are we really in a golden age of programming, or are we laying the seeds of our own demise?

Everyone is a programmer now. You used to need C++, Python... Now you just talk to the AI.

- Jensen Huang, 2025

Yes, anyone can say a few sentences to an AI and make an App. But is that really programming? Can this user, speaking to their AI, support that App over the next several years it will be used? Will it break with the next OS Update? What do you do then?

It’s very easy for what I am saying here to come off as elitist; I don’t want that. I think it’s amazing that the barrier of entry to programming has come down as much as it has. If you are someone making Apps, without ever having had any experience coding, I salute you.

With that said, as someone that has been coding for close to 20 years now (ouch), I have been through a pretty significant school of hard knocks. I have made decisions and lived with their consequences. One thing I will tell you is this, the teams that build on a foundation of Good Code will outlast the ones that don’t. Making software is a marathon, not a sprint, and you need your software to last through that marathon.

For the purposes of this article, I’m considering Good Code as code which is maintainable, correct, and meets or exceeds some bar of performance. This can be a pretty inexact target and includes some amount of developer preference. To some extent Good Code is in the Eye of the Beholder, but anyone that has ever worked in a large, legacy code base can tell you horror stories about having to maintain bad code.

So what can we do to make sure we are making Good Code? That the businesses and tools we are building can survive, grow and thrive as the marathon stretches on?

Humans have been making Software for close to (or depending on your definition, more than) a century. In that time we have learned a lot about how to structure code so that it is easier to work with, change and modify. Just because code is easier to create, doesn’t mean there isn’t skill in knowing WHAT to create, or more importantly, what NOT to create.

Something to remember is all code requires maintenance as the world around that code changes. This is why you will hear experienced engineers talk about code being a liability to the business. The more code you have, the more APIs you depend on, the more vulnerable you are to your code breaking and needing modifications.

Of course, you can mitigate some of that risk by having resilient, well designed code. Code which expects the world to change around it and makes educated guesses about how the world will change, so that it can easily adapt to that new world. The AI you use to write that code doesn’t have this context. Even an AI that reasons well doesn’t know where you plan to take your business or product.

It is in this place that we can use AI to apply the Software Design lessons of the past. Where the experience of Software Developers shines. It’s that seasoned developers’ experience which guides them to tell the AI the high volume query pattern so the AI can create the right database index. The experience of knowing that Bubble Sort IS the right answer when you have a small number of items.

In my last article, I talked about AI being Replicators. They will replicate whatever patterns they see in the code or have been trained on. They don’t know the difference between Design Patterns and Anti-Patterns. It takes experience to know when a code structure is actually an Anti-Pattern which should be avoided.

Anyone that has worked at a large company, or on a sufficiently experienced object-oriented team has heard about Software Design Patterns. They might even have nightmares about the AbstractFactoryGeneratorFactory they had to implement.

But what is a Design Pattern really? The modern interpretation of Software Design Patterns started with the book “Design Patterns: Elements of Reusable Object-Oriented Software” by Gamma,Helm,Johnson,Vlissides (affectionately referred to as “The Gang of 4”). This is the book that really brought Software Design patterns into the mainstream; they existed before it, but didn’t have strong definitions.

Design Patterns: Elements of Reusable Object-Oriented Software

In the Gang of 4, they use Christopher Alexander’s definition of Design patterns from the city planning domain.

Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to the problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. [Design Patterns, 1.1, p2]

(Yes, I’m quoting a quote, because I have the Gang of 4 book, but don’t have “A Pattern Language” by Alexander)

Design patterns can be very abstract, but they solve real issues that we encounter in Software Development. They also solve these issues in time-tested ways that are proven to be maintainable.

I can easily say that Design Patterns are both under- and over-utilized. They can quickly be bastardized to create extreme complexity. But when used by a tempered hand, they also produce some of the most elegant solutions you have ever seen.

From my experience using AI, they won’t reach for design patterns unless you tell them to. This means that you need to understand these patterns, including when and how to utilize them, in order to get the most out of your designs, even when using AI.

Are you having issues in your program with memory fragmentation, maybe you need to have the AI code up an Object Pool. Or maybe the memory fragmentation issue is actually because you’re making complex objects and throwing away the intermediate steps, in this case you might need a Builder pattern.

Which solution you use to solve the exact problem you are having is going to come first from an understanding of the problem, and then an understanding of common solutions (read patterns) to that problem. Maybe the AI can one-shot it without instructions, or maybe the problem exists because you tried to get the AI to one-shot it without thinking through the consequences or truly understanding the problem first.

Algorithms live at the core of Software Development. I’m not sure any significant piece of software exists that doesn’t have to sort, search, or organize some kind of data. This is what computers were made to do! If you think your business can get by without using some kind of algorithm, you might take a good hard look in the mirror to see if it’s really a business worth pursuing (at least in the software domain).

All algorithms have tradeoffs, either in terms of compute, memory usage or complexity. Translation - one size fits all algorithms don’t exist, so you need to choose which one is right for your use case. This also means that you need to be able to identify algorithms when they are in software or being proposed for inclusion. It doesn’t matter if the algorithm was coded by an AI or a human, an exponential runtime is an exponential runtime. Will it do the job, sure, eventually, but is that really the bar you want to have? Is that the experience you want your users to have with your software?

Algorithms aren’t archaic knowledge, passed down from Senior dev to Junior on stone tablets or hidden away in a vault to be protected (like Social Networks seem to want to do with their feed algorithms). They exist across software from Game Render layers, to document layout, to the sort button on your spreadsheet. If you are going to be making software, you are going to run up against algorithms, and to make good software, you are going to need to pick the right algorithm for your use case.

Software is complex, there is no getting around that. You don’t solve The Traveling Salesman to limit the number of miles a UPS truck drives without writing some complex code.

Part of the job of designing software systems is to find ways to manage this complexity. It is through this process of breaking software down into manageable pieces that we can build systems which become something we can understand.

This is just as important in the post-AI era, as it was pre-AI. Yes, AI is very helpful at working through the complexities of software systems. I would even say it is more capable at this than humans are. But that is a double edged sword.

When the AI makes something that is so complex, humans can’t unravel it, we also can’t unravel if it works well or even does what we expect it to do. The AI will happily write 1000 line functions with a forest’s worth of branches. Ask any software dev, from a Junior to your most senior Architect, you can’t test or reason about a function like that. AI Agents still code bugs, and if you can’t test the code these agents create, at least some of those bugs are going to slip through.

The other risk with letting the AI run unchecked on complexity, is what you do when the AI isn’t available. I firmly believe we are living in an AI Summer, where GPUs spin wildly in fields of lilac and the token costs don’t matter! But this period of unchecked AI growth won’t last forever, we are already seeing cracks in its foundation as Hyper-Scalers try to reign in their spending. Much like the cloud compute transition in the early 2010s, eventually the datacenters have to make money too.

Even if the available compute can keep up with demand, AI Agents can have outages. What will you as a developer do when you are hit with one of these information brown outs and you can’t reason about how your code works?

Having a system which is resilient to these risks means keeping complexity in check, and keeping your coding chops up to snuff as well.

In much the same way that fashion trends from 30 years ago seem to keep coming back in style (or so I’m told, I know little to nothing about fashion), I believe the idea of truly designing software systems is going to come back as well. AI gets smarter every day, and as they do they become more capable. But as of yet I haven’t seen these capabilities bridge the divide to make them actually creative.

Human Creativity is a wild thing! Our ability to come up with novel ideas and solutions, to apply learning’s from unrelated fields, and to discern when those solutions, ideas or learning’s don’t apply is unmatched. It is when we apply these skills to new tools that innovation actually happens.

I think there is a bright future in humans using AI as a tool to bring Software into a new frontier. But to do that, we will also need to build on the foundations of our past.

Discussion about this post

Ready for more?