Design patterns are a key aspect of modern software development. The (re-)use of known patterns is almost universally accepted as a sign of a well-designed system. Resources ranging from community forums and blogs, to magazine articles, to official development guidance promotes their use.
So why do so many software developers continue to develop applications without them?
There is probably not one single answer to that question, but I suspect the problem is mostly due to a simple lack of understanding about patterns and their usage. By that, I partly mean that many developers still don't know what patterns are, or what they are called. But even once that hurdle is overcome, there is still a lack of awareness of the best way to use a given pattern. And using a pattern incorrectly can often be worse than simply cooking up your own solution to a problem.
By their very nature, patterns are language-agnostic. Most discussion and information about them is written in terms of their broad goals, their design philosophy, and their abstract behaviors. Instead of doing more of that, I'd starting what (I hope will be) a recurring series on the practical application of design patterns, specifically in applications written in C#, using WCF and WPF, for .NET 4.5, in Visual Studio 11. (I'll try to avoid too many .NET 4.5isms, or at least point them out when they show up.)
For this first post, though, I thought I'd start with a brief introduction to patterns as a concept. This won't be anything too ground-breaking; if you've read the Gang of Four book then you will probably find this post somewhat repetitive. If you have no idea what the Gang of Four book is, keep reading.
Design Pattern Basics
At some level, all software development is the application of patterns. High level languages define keywords and operators that represent patterns of machine operations, and data types that represent patterns of bits. Abstract data structures, like trees and linked lists, are patterns of data types and operations that act on them. Design patterns are one more level of abstraction in this chain, and they serve much the same purpose: to provide reusable chunks of software that we can drop into our application whenever we need it.
The first key aspect to understand about design patterns is that they do not solve business problems. There are no design patterns that explain how to calculate income tax, or format a word processor document, or download and display an RSS feed. These are domain-specific problems -- in line-of-business applications, we call these "business requirements", but whatever they're called, they're the reason that our applications exist. In many cases there are domain-specific patterns, for solving these problems, but those are not design patterns.
Design patterns exist to solve another class of problems, domain-agnostic problems. Regardless of the business domain for an application, its design will likely have much in common with any other well-designed application. The design needs to account for things like controlling access to shared resources, or managing creation of related objects, or conveying information between components. This is where design patterns shine: they provide proven, well-understood solutions to these problems.
If we were engineers designing, say, a better hot water heater, we would need to know things like the volume of water it can hold, and how much heat it takes to heat that water. Those are problems that are not specific to hot water heaters, and they are also problems that are already solved (in some cases millenia ago). We would look up those formulas, plug them in to our design, and move on to focus on the unique problems (how to apply more heat while using less energy.)
That is what design patterns do for software developers: they give us answers to already solved problems, allowing us to focus on the new, unique problems our software is really meant to solve.
Why Not Patterns?
I discovered software patterns relatively early in my professional career, which luckily came soon after the publication of Design Patterns. Though the patterns described in the book were not new, their formal definition and cataloging was. The book, and its follows ups, produced a wave of interest in learning and understanding them better. It did not take long for developers to accept the huge benefits these patterns provided, and make them a standard part of our design toolkit.
Now, fifteen years later, you would expect patterns to be as ubiquitous as arrays. But too often you find developers continuing to solve these same problems, over and over, often is less-effective ways. Why is it that these developers aren't using such a key tool in their designs? The problem, I think, ultimately boils down to simply not understanding how useful patterns can be. There is an unfortunate confluence of factors that seem to product this effect.
First, patterns are simply not taught in programming courses. It has been quite a while since my last formal college course on development, and back then, design patterns were simply not part of the program. (Not surprising, since Design Patterns hadn't been published yet.) We learned data structures, and algorithms, but very little in terms of practical use of those things.
These days, I had assumed that design patterns were part of every 100-level programming course, and ingrained into developers from the start. Talking to a few friends and colleagues with much more recent college experience, though, seems to indicate that we haven't made much progress at all in the past decades. Programming courses have evolved from teaching theoretical concepts using Scheme and C to teaching theoretical concepts using C++ and Java, but still very little practical knowledge. (One recent graduate told me that one of their programming professors considered actually writing code a necessary evil of teaching software development!)
So, new developers come out of school knowing little about design patterns. If you're lucky, you may have heard of them, and been told to go learn about them on your own. But when you do that, most of what you find assumes you already know about them! Beyond that, you are continually being direct to a books where half of the sample code is written in Smalltalk. These books were written for people who already had a good foundation of proper object oriented design, and built onto that. In fact, most published material about design patterns assumes that you either a) are well-versed in object-oriented programming in some language, and are trying to learn about patterns, or b) are well-versed in using design patterns, and want to apply them to a new language.
This leads to many developers, when learning to apply design patterns, doing so improperly. They copy and paste complex object models into their application and struggle to hook them up properly. They choose patterns that don't really meet their design needs because its "what everyone is using". This leads to bad experiences with using patterns, which produces a reluctance to use them again next time.
One final factor, which I think may be the most important of all, is that developers who already grok patterns tend to ignore the fact that they are not free. Patterns save us a lot of time, effort, and stress over the lifecycle of our application, but early on, they require extra work to understand (at least the first time) and implement. The Gang of Four explicitly recognized this aspect of pattern use in their book, where they discuss the "Consequences" of using each pattern. But those consequences are often lost when talking about how awesome patterns are.
Understanding The Tradeoff
Of course, we are still aware, at some level, that there are costs to using a pattern. We have simply accepted those costs as being more than worth it, because we know the long-term benefits will more than compensate. But someone new to patterns, looking at the Repository, and thinking about how much extra work they are in for, may be less enthusiastic.
This is a large part of what I hope this article series will help correct. First, by understanding up front what additional time and effort is going to come with the adaptation of a pattern. Some are relatively cheap; in many cases, that cost has already been borne by the developers of the frameworks we use. (WCF and WPF, for example, are teeming with patterns that we can take advantage of.) Others require an up-front commitment, which in turn requires a clear understanding of what that commitment entails and why its important.
Once we understand the costs, we can look for ways to reduce them. Again, the tools and frameworks we have available will help a lot here. Implementing an observer pattern in WPF should be almost no-cost, because there are at least two different implementations built in! And the templating support that is built in to Visual Studio is a huge time-saver when implementing some complex patterns.
I already have the next few posts planned out, but if you have a particular favorite pattern you want to see, of which gives you problems, just drop me a note in the comments. In the mean time, I'll start simple, with an extremely common (but deceptively tricky) design patterns -- the Singleton. Stay tuned.