Practice 5. Design Patterns
Design patterns [Gamma et al 1995] are an invaluable resource for software developers. They are essentially a catalogue of solutions to frequently encountered software development problems. Unfortunately, many developers have never heard of design patterns, and others feel that simple design means they should not use patterns because using a design pattern seems like up-front design. But if you are trying to solve a known problem, why reinvent the wheel? The most common design patterns were not just invented, they were observed by some clever and experienced software developers as solutions that worked time and again in different software projects and over time. Patterns are known to work, they are tested, and they have a known behavior.
The value of design patterns as a common vocabulary should not be underestimated. For example, I was in a design discussion one day with my team. One of my teammates started describing a solution in a message-passing system where a message was passed to a number of classes in turn until one of the classes was able to deal with the message. This design provided the greatest amount of flexibility because it allowed the message-handling classes to change independent of the message sources. There was a lot of confusion within the team about how this would work in detail, until I realized that what was being proposed was the Chain of Responsibility pattern. As soon as I pointed this out, the tone of the conversation completely changed. The confusion disappeared because everyone knew what this pattern did. The discussion then switched to how the pattern could be extended to meet the needs of prioritized messages and other detailed, not philosophical, problems. Hence, our common vocabulary of a design pattern as a higher level concept allowed us to have a productive and focused conversation on solving the real problems.
Design patterns can be abused just like any other practice. But just because they have problems doesn't mean they should be ignored. They are too valuable to be ignored, as long as you understand what can go wrong. The most commonly cited problems with design patterns are:
They are often overzealously used. Many examples can be found on the Internet, in software development papers, or in books of projects where it seems like every line of code cleverly employs some design pattern. The software that results from such projects is often unnecessarily hard to understand and modify due to the complex relationships between classes. These projects have sacrificed the rule of simple design for being clever.
Design patterns are often used to solve problems where a much simpler solution is possible. If you use design patterns a lot, you'll find that they're extremely reliable. They solve problems. However, once you get to the point where you know patterns will work the majority of the time, it's often too easy to think about how a design pattern can be used for all problems and forget that sometimes a more ad-hoc solution that involves a small bit of code is even better because it's simpler! The mistake in this case is thinking of design patterns before simplicity.
There are too many different ways to code a pattern. Since design patterns only provide an outline for implementation, it is still possible to have implementations of patterns that are too complex.
The use of design patterns can lead to an unhealthy emphasis on up-front design. I have been on projects where people spent too much time trying to analyze a problem so they could try to identify what design patterns would apply. If you aren't sure, don't use a pattern. Simplicity, as always, should be the primary goal. Chances are, if there is a pattern, there it will emerge. You can always refactor to it later, as in [Kerievsky 2004].
If you don't know design patterns, the code can appear to be overly complex. This really can't be helped except through education. However, it is a very real problem when new developers join a project where patterns are used.
The Expected Behavior of Design Patterns
One of the problems with design patterns is that once you are used to them, you expect a certain behavior. I have been surprised on occasion when I look at some code and think, "Ahh, this is implementing the xx pattern," when in fact it is very close to the pattern but has slightly different behavior.
I have encountered a number of cases where the mistaken identification of a pattern has led to wasted time when trying to find a problem or understand the code. I highly recommend documenting the code with the name of the pattern. Also, ensure that everyone on a team understands patterns.
To be consistent with simple design, you don't need to implement all the interfaces if you don't need them, and the simple knowledge that the code is indeed a pattern means that other developers can quickly add the interfaces they need at a later time with full confidence that the expected behavior of the pattern will not be altered.
In summary, design patterns are valuable and they shouldn't be ignored. They do have problems, but as pointed out in the Simple Design practice, teamwork, experience, knowledge, and collaboration are the best way to minimize the risks in software design while maximizing the potential returns. It also helps to recognize that making mistakes is human and part of software development. Fix your mistakes as quickly as possible, learn from them, and move on.