As always, history plays a role. In the case of Design Patterns, history shows us a kind of slingshot acceleration of adoption by developers, starting in the late 1980s, with an exponential growth in the 1990s, followed by the freefall of mass adoption in the 2000s. Here’s a potted version:
In 1977, the architect Christopher Alexander published the book A Pattern Language, containing over 250 suggestions for folks designing spaces. Each pattern was a context followed by a suggested solution and a discussion. For example, pattern 159 starts
When they have a choice, people will always gravitate to those rooms which have light on two sides, and leave the rooms which are lit only from one side unused and empty.
Therefore:
Locate each room so that it has outdoor space outside it on at least two sides, and then place windows in these outdoor walls so that natural light falls into every room from more than one direction.
This pattern, perhaps more than any other single pattern, determines the success or failure of a room. The arrangement of daylight in a room, and the presence of windows on two sides, is fundamental. If you build a room with light on one side only, …
Ten years later, Ward Cunningham and Kent Beck cowrote the paper Using Pattern Languages for Object-Oriented Programs, which suggested Alexander’s approach might also work for code. They continued to work on this, and in 1994 Ward invented the wiki in order to create a place where people could discuss patterns.
That same year, Gang of Four1 published Design Patterns; Elements of Reusable Object Oriented Software. Their intent was to isolate and name various structures that people used in particular situations; if two or more people had address a particular issue in the same way, they’d name it and describe it. In their case, they were looking at code written in C++, and many of the patterns exist to overcome constraints imposed by that language.
The crowd went wild. For the next 8 or 9 years, Ward’s wiki was the place the cool kids hung out. If a thing moved, someone would write a pattern language describing how. There are thousands of published patterns for software development.
And every single one of them is used incorrectly.2
The Title is to Blame
I don’t know why the GoF gave Design Patterns the subtitle they did, but Elements of Reusable Object Oriented Software sent a subtle but damaging message. The word reusable implies that they are presenting you with some kind of plug-and-play component library. Do you need to create instances of different classes depending on some value? Then you need a Factory! And, for a limited time, we’re throwing in the code and a UML diagram at no extra cost!!
And that’s what happened. People jumped on the idea of patterns being building blocks of design. Suddenly you couldn’t write a class unless it’s name ended with the name of a pattern: UserFactory
, ConfigSingleton
, PrintDecorator
. What’s worse, people then implemented these classes by transcribing the C++ code from Design Patterns into their language du jour, line for line.
And this is really, really dumb.
Patterns are not reusable chunks of code. They are not components.
Patterns are descriptions of techniques that might be useful in a particular context. They are not recipes; Alexander called them hypotheses.
Time for a bad analogy.
How To Paint, A Pattern Language
Through a miracle of engineering, scientists bring the painter Rembrandt van Rijn back to life. Before he dies for a second time, they want to capture his knowledge and expertise as a artist. He decides to document what he knows as a pattern language.
He sets to work, writing patterns such as “Capturing soft light on the forehead”, “The nose of a drunk,” and “The disdainful eyebrow.” When finished, the book is a global phenomenon. Artists everywhere hail it as the new way to construct a painting: apply each of the patterns as needed as you traverse the canvas, and you’re guaranteed a masterpiece.
We end up with pictures like this:
This is what happens when you say “I need a nose here and a forehead there”, go to Rembrandt’s patterns book, and copy his implementations onto your canvas.
Clearly, that’s not how Rembrandt’s patterns should be used. They should be studied for technique and for insight, and then reinterpreted by the hand holding the brush.
For Example
Search for “factory pattern ruby” and you’ll find examples such as this.
This is the programming language equivalent of the Monty Python fish license, but rather than being a dog license with the word “dog” replaced with the word “cat”, it’s C++ (or Java, or …) code with the syntax replaced with Ruby.
On top of that, it doesn’t actually show a factory method: it’s just two unnecessary levels of delegation.
Why pick on this code? I’d rather not, but it’s all like that, and this was the least obnoxious. Rather than ask themselves “what do I need to achieve?”, the implementors of these online exemplars made the decision “I need a factory",” looked it up, and transcribed what they found into Ruby.
Let’s convert this example to use an actual factory method, and write it based on need, and not some pattern.
We need to simulate one of n machines. Which one we chose depends on the value of an external parameter. Every machine is a class, and each implements an operate
method.
Still pretty ugly. We can tidy it a little by replacing code with data (my current mantra).
It still has those strange Machine1
and Machine2
classes though. This is where sample code breaks down, because we don’t know what they do in real life. If they are simply stateless wrappers for the functions they contain, then they should be modules, and not classes.
If instead they have behavior in common, and the operate
method is the difference between being a machine1
and a machine2
, then we have some options.
The option that you probably shouldn’t take is the one that everyone uses: create an abstract base class containing the shared behavior and make Machine1
and Machine2
subclasses. In a strongly typed OO language you are forced to do this to get polymorphic behavior. But in languages such as Ruby and JavaScript, there’s no need, and adding class hierarchies increases coupling.
So if we assume that the external interface to all machines is a do_something
method, which in turn calls the machine-specific operate
method, we could use mixins:
An alternative is to remove the polymorphism altogether, and instead inject the appropriate method at runtime:
This code assumes that the machine object do_something
functions can be called multiple times. If that wasn’t the case, there’s no need for a separate StandardMachine class: we can just pass the operation
to the do_something
method.
Don’t Design Before You Need To
In last week’s article I talked about the evils of premature design. This article is really just a continuation of that. The only difference is that when you use a design pattern, that design predates your need by at least 30 years.
My personal take: design patterns are a convenient way of describing code that you already wrote. Don’t use them as recipes.
Postscript
Whenever I meet an architect, I make a point of asking what they think of Christopher Alexander and his idea of patterns. I’m well past my tenth, and none of them has heard of him.
There’s more of this kind of old-man-fist-waving-at-clouds in my new book, simplicity…
Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides
Slight exaggeration.
It is funny that you compare and contrast design patterns and recipes. Most great cooking by my wife, is based on a written down recipe card that she did not follow and I have to ask what she changed so I can get close to not ruining the dinner which I am attempting to cook.