The Art of Design Patterns
This article first appeared on the O’Reily Radar to promote the new report titled An Engineering Manager’s Guide to Design Patterns. You can download a free copy of An Engineering Manager’s Guide to Design Patterns directly from O’Reilly.
If you haven’t had the pleasure of viewing Hal Abelson & Gerald Sussman’s 1986 MIT introductory computer science course, you owe it to yourself to set aside a few hours to view it. “1986?”, you say — “Could that really be relevant to my work today?” Unless you came through MIT or a similar program that teaches from their seminal book The Structure and Interpretation of Computer Programs, I’d bet you are most likely going to learn a few new things (even if you consider yourself a seasoned software developer).
Play the video, and right away you might be surprised, as Abelson, in the first five minutes of the class, states that not only is computer science not a science, it doesn’t have all that much to do with computers. Rather, Abelson suggests, computer science is more of an engineering discipline, or perhaps even an art; and, rather than being concerned with computers, computer science is more an exercise in creating imperative knowledge and managing complexity.
Anyone who has ever been late on a software development project (who hasn’t?) can relate to this. Software development starts to feel more like an art or craft when the best you can do is roughly estimate the size and scope of a job and then cross your fingers and hope for the best — certainly, it is at times like these when our field doesn’t feel like much of a science. And, for anyone who has worked on a project of moderate size, at some point you find complexity staring you in the face. All too often our first designs, and our code, turn into the dreaded big ball of mud (yes, that is a technical term).
The first line of defense against the ball of mud is typically what we think of as good object-oriented (OO) design. While OO wasn’t the focus of Ableson and Sussman’s work back in the late 80s, we did see a movement toward OO development during that period. The great promise of OO was that it would solve our complexity problems. In fact, we were taught that if we just modeled our classes correctly, and made heavy use of OO techniques like subclassing and inheritance for code reuse, we’d get our code under control. Unfortunately, in many cases, this is poor advice, and we’re right back where we started: with a code base of moderate complexity, the traditional OO approach turns into a mess.
There is a happy ending to this story because there we have object-oriented design principles (not to be confused with design patterns) to guide us in good software design. It just turns out, however, they aren’t often taught to those learning OO. Let’s take one design principle from the definitive Design Patterns text from the Gang of Four (Gamma, Helm, Johnson, and Vlissides):
Favor object composition over class inheritance.
This pithy design principle (again, not to be confused with a design pattern, which we will get to in a bit) is one of the fundamental principles of OO system design. While explaining it in detail would require an article of its own, the gist of this principle is that to achieve polymorphic behavior, we don’t always have to do it through subclassing. If we instead reuse behavior by moving that behavior into objects that can be composed together, we end up with systems that are much more flexible and extensible (we can even change behavior at run time, but that topic is for another article).
Favoring composition over inheritance seems to go against what many of us are taught when learning OO. It’s not uncommon to find posts on the Web questioning this principle; after all, inheritance is the foundation of OO programing, right? How could composition be better? This is where the art of software development comes in: no matter what your pre-existing beliefs about OO design, favoring composition over inheritance has shown itself, over and over, to be a more appropriate way to approach your design — so much so, that if you take a look at well-designed OO frameworks you’ll see the principle commonly used.
Before we move on from the topic of this particular design principle, read it again — the principle is arguably one of the most fundamental OO design principles, but does it read like a theory or law from a scientific discipline? Just the opposite; it reads like a guideline from someone skilled in the art of OO development.
Now, if the topic of OO design principles (beyond the standard inheritance, polymorphism, encapsulation principles) is new to you, you’ve got a wonderful world of design principles waiting to be explored; here are a few more principles to whet your appetite:
- Encapsulate what varies.
- Program to interfaces not implementations.
- Strive for loose coupling between objects that interact.
- Classes should be open for extension and closed for modification.
- Depend on abstractions, not concrete classes.
- Only talk to your friends.
- Don’t call us; we’ll call you.
- A class should only have one reason to change.
Knowing design principles can help you get a long way toward creating OO systems that are more maintainable, extensible, and resilient to change. Those are all qualities that allow us to ship software on time and deal with new features or change orders more quickly. Incorporating these principles into our development thinking also helps us become better artists, artists who create systems that are a joy to work on, use, and extend. These principles are like a craftsman’s tool set that you can pull out anytime you need to design an OO system.
Returning to Abelson’s point on managing complexity, it turns out there are OO design problems that are complex enough that we need more than simple design principles — I’m not talking about proprietary, one-off problems; I’m talking about timeless problems that recur often in many software development efforts. The only path to finding solutions for these complex problems is through extensive trail and error, and, ultimately, experience. The solutions aren’t so much invented as they are discovered, and we call them “design patterns.” You can think of them as the art of OO design.
An important thing to know about design patterns up front is that they aren’t code; rather, they are OO patterns — design guidelines — for solving your problems. “But wait,” you say — “what about all those design patterns I’ve seen in Java, or Objective C, or (name your favorite environment)?” That’s a good question, but specific solutions in a specific language aren’t design patterns. They are the application of design patterns to a problem. Design patterns are high-level design — they tell you how to approach a problem, but they don’t give you a library of code with a solution already implemented for you because the pattern needs to be factored into your OO design.
Ultimately, design patterns represent our best effort in the art of OO design. There’s never going to be a scientific proof that these patterns are the most optimal or efficient design, but there are thousands of hours and many thousands of lines of code that have helped hone these patterns into reusable solutions. While you could go it alone in your OO design, why not reuse the hard work of other, seasoned developers?
Design patterns are yours for the taking; all that’s required is a basic understanding of how patterns work, some experience with how they can be applied, and a working knowledge of the common patterns (along with knowing how to read a pattern’s catalog to find less common patterns). After you’re up to speed on patterns, you’re going to find they benefit not only you, but also your team, because once a team understands patterns, team members can communicate more efficiently, concisely, and accurately.
If you’d like to take your knowledge of design patterns further, Elisabeth Robson and I have created a short O’Reilly report called An Engineering Managers’ Guide to Design Patterns that O’Reilly is making freely available. Based on our best-selling book Head First Design Patterns, this report takes you through what patterns are, along with an example of how they are actually applied. It also covers many of the benefits to you and your organization, should you choose to embark on the study and use of design patterns.