Agile teams are under pressure to deliver working, tested code at the end of each iteration. They are also available to their customers for potentially radical requirements changes at any point in the project. They and their code must be capable of turning on a dime at any moment. So agile teams place enormous value on the extensibility of their code: the extent to which they can easily maintain and extend it. Elsewhere we discuss how important refactoring is to keeping code extensible. The other key component of extensibility is code design simplicity. Extensibility seems to be inversely proportional to design complexity.
The Art of What Suffices
In any agile context, simple design means, to paraphrase the poet Wallace Stevens, "the art of what suffices." It means coding for today's specified requirements, and no more. It means doing more with less. But this is not necessarily a natural inclination for us programmers.
We are surrounded by technologies that are supposed to assist us with scalability, performance, security, concurrency, etc. Many mainstream shops seem primarily concerned with our knowledge of specific technologies: database technologies, application server technologies, framework technologies, meta languages and scripting languages, and on and on. Each day these technologies grow in number, complexity, and sometimes sheer bloat. We work in vast oceans of these technologies.
So we can be forgiven if we are more than occasionally tempted to introduce some of this complexity into our designs in an anticipatory way, or if we kid ourselves about the true necessity of these additions. It is sometimes easier to introduce a known gizmo than to experiment with making the design work without it. It is the devil we know. Sometimes we even have such technology choices dictated to us by executives or customers. And sometimes the introduction of a little more complexity, a layer of abstraction in the form of a design pattern, for example, actually does make the code more extensible.
"You Aren't Gonna Need It"
But the truth about design complexity of all kinds is that we often find that the extra abstractions or technologies do not become wings that free us, but instead shackles that bind us. Whatever extra stuff we add, we are indeed clamping to our legs, to lug around thereafter from feature to feature, from iteration to iteration, and from release to release. In Extreme Programming, the saying is "You Aren't Gonna Need It" (YAGNI). There are mountains of painful old lessons behind this maxim.
Agile shops are often willing to trade expertise in specific technologies for expertise in the craft of extensibility, which often boils down to expertise in unit testing, refactoring, and design simplicity. Agile shops tend to wait until a current requirement (a requirement for the current iteration) fairly hollers for an extra layer of complexity before introducing it. So by mainstream standards, agile codebases tend to be lean per function point, measured in numbers of classes, or in lines of code.
Many if not most systems eventually require drastic changes. We cannot anticipate them all, so perhaps we should stop trying to anticipate any of them. If we code for today, and keep our code and our team agile, we keeps ourselves most capable of turning on a dime as the customer requires. These are the agile wages of simple design.