In his article on the JDJ website, Alan Williamson talks about his recent run-in with a potential author and his reaction to the author’s attempt to “show off their superior knowledge by dazzling our editors with fancy acronyms and big words.”
I’m not going to stand here and try to defend this nameless would-be author. Instead, I want to try and raise an issue that’s been bugging me for a number of years now, pretty much ever since the canonical patterns book, “Design Patterns” (also referred to by us design patterns snobs as the “GOF”, or “Gang of Four” book–referring to the four authors that contributed to it) shipped back in 1995. Specifically, I want to address the huge misunderstanding that emerged through the industry about what design patterns are, what they were intended to do, and why they’re still important, all hopefully without any trace of snobbery.
All references to Christopher Alexander and his work within architecture aside, a pattern is essentially a tuple of four things:
- A Problem This is intuitively one of the easiest parts to understand: what obstacle is in the way of producing an efficient/elegant/powerful/whatever design?
- Forces or Context surrounding the Problem No Problem exists in a vacuum, however–there is always a surrounding context or set of constraints that make Problems different within different environments. For example, a problem might be to “construct an object without directly invoking its constructor”. However, the context varies wildly–who should be driving the construction, the user of the object, or the framework surrounding the object itself? Are there constraints on invocation (such as memory or time)? Is there a particular need (such as runtime compositionability, also common referred to as “plugins”)? This is quite possibly the most important part of the pattern definition, even more so than the problem itself.
- A Solution Simply defining a problem without a proposed solution is called “whining”, and isn’t very useful in the long run, except as an immediate transitory state to creating a Solution. :-)
- Consequences yielding from that Solution Again, this is critical to understanding the patterns community’s goals for patterns. We don’t want to pretend that a given solution will be a one-size-fits-all solution. “Every action yields an equal and opposite reaction”–this is true for programming as well as physics. Optimize for speed? Take a hit in memory footprint. Optimize for space? Take a hit in speed. Trying to optimze for both? Take a HUGE hit in maintainability. Understanding the consequences of a particular pattern, both positive AND negative, is key to understanding of the pattern in question helps solve your particular problem.
Nothing more, nothing less. But, as with many things simple, the result is quite powerful.
This isn’t to say that patterns are set in stone, however–far from it. A given pattern can (and should!) always be tailored to take into account the context in which the problem shows up. For example, the classic Factory Method (ask a method to build an object for you so you remain entirely decoupled from the actual object type constructed) shows up in a couple of varieties, one of which has the caller pass an argument in to help identify criteria or an opaque identifier to help the Factory Method determine which type of object to build. For those who did COM, this was most easily seen with CoCreateInstance(): pass the CLSID of the kind of object you wanted, and the appropriate type (of the appropriate version of that type) would be constructed and handed back. The Factory Method as displayed in the GOF book doesn’t use this–but it doesn’t change the pattern, whether the parameter is there or not.
In of itself, so far, patterns don’t sound particularly useful–there’s no mention of “reusability” or “reusable code”, there’s nothing tangible I can put my hands on and use immediately, and it’s a fair criticism of the patterns community that we could never quite figure out what to DO with all these patterns we’d cataloged. It’s not like I could put the GOF book into the hands of junior programmer and suddenly make them a better programmer. Instead, the GOF book seemed (at least in my experience) to resonate most deeply with those programmers who’d “been there” once or twice before, found a few patterns they recognized, and
were able to even refine their code based on some of the consequences they hadn’t realized they’d accepted when building it. Once they’d done that, they were hooked–they suddenly started devouring the book and seeing patterns show up everywhere. They could recognize when they’d seen this problem/context before, and could evaluate which pattern to apply to the situation. On top of this, we now had a language, a lexicon, of new terms to help us describe systems at a higher level (which Williamson points out in his article).
What happened, however, was that many newcomers to the concept of patterns saw only code listings and assumed that patterns were just objects writ large. They started looking for “reusability” at a code level, rather than at a design level. Alan falls prey to this somewhat himself, likening “patterns” to “data structures”. On one level, he’s right–a pattern typically isn’t something we “invent”, but “mine” or “discover” lurking in the code. It’s an attempt to codify something so that by giving it a name, we can define it and get to understand it better. (If this sounds very Zen-like, it is–several noted patterns gurus started getting into a very abstract and philosophical space that tended to lose any but the most dedicated patterns enthusiast. Personally, while I applaud their willingness to try and understand all this at a deeper level, I try to keep my patterns usage more concrete.)
But where Alan falls short is to recognize that it’s not the *code* that’s important, but the understanding of the context and consequences of using that code. He cites the Singleton as an example of a pattern that we’ve all probably used numerous times. But what’s the difference between a Singleton object and static methods on a class? Why use the Singleton? Or, in other words, what are the consequences, positive and negative, of using the Singleton as opposed to “regular” static methods on the class? That’s where the power of the pattern comes in.
Coupled with that, tremendous amounts of information can now be carried intuitively with a single word. I can tell you, “Oh, we wanted our thread pool manager to be a Singleton”, and you can immediately infer some knowledge of our design goals, constraints, and the design itself based on knowledge of that pattern, and can in turn suggest or question the design, not the code. We’re communicating at a higher level of abstraction, not reusing code.
Alan goes on to point out that “They’re just repackaging the stuff you’ve been doing for years in a format that can be openly discussed…. I would guess that 9 times out of 10 you’ve used [a pattern] many times and didn’t even realize you were a design pattern follower!” Yes! Precisely! He’s absolutely right. Having said that, though, it feels like this misses the point again–by giving the thing a name, we can describe it and discuss it and codify it. It’s not just a way of pointing out the code–it’s a way of allowing us to see past the code to see the higher-level abstractions within the design.
I don’t want to seem like I’m bashing Alan or his level of expertise or experience. It’s an absolute truth that some have held the idea of patterns as a hatchet over people’s heads for some time now, leading many to believe that patterns are this mystical cult or exclusive club that only those born with the right birthmark can get into. I’ve met several of those design patterns snobs, and he’s right: they just make your skin crawl with their condescending attitudes and lip-curling sneers of disdain. When I find one, I usually take great delight in drilling him on the excrutiating details of pattern after pattern after pattern. :-) Of course, I’ve also met my share of EJB snobs, COM+ snobs, and even container-classes snobs (”We wrote our own, HIGHLY-tuned, HIGHLY-efficient set of collection classes, and it only took us two years to do it…..”). Snobs in general suck.
What truly makes this story worse, however, was that just as the patterns world was starting to build some critical mass, the marketing folks got hold of the name, and diluted the idea of what a pattern was back into “code reusability”. Worse yet, patterns began to be misused and misinterpreted–quite probably the worst offender here was Sun, with their “design patterns” in JavaBeans (sorry, guys, using get/set method names to define a property isn’t a pattern) and their “Model-View-Controller” pattern in JSP/servlets.
As a result, expectations that patterns would cut development time by outrageous percentages were set, and since patterns really had little to do with development time (patterns influence design time, not development/implementation), the expectations weren’t met and yet another interesting thing in Computer Science fell by the wayside. Today, patterns are relegated to the dustbin of “passe technologies”. Mention that you’re interested in using patterns or use a pattern by name as part of your discussion, and suddenly you’re a “design pattern snob”.
Patterns are still important, because all marketing hype and failed expectations aside, they’re still useful as a means of communicating design elements between software architects and developers. The JavaBean event notification system is one giant exercise in the Observer pattern. EJB uses Interception to provide its runtime services. The Comparable and Comparator classes are two variants of Strategy. And so on. As is typical in this industry, it’s easy to dismiss something after it’s been “passed by” in the media. Doing so here would be a mistake.
I heartily invite ANYONE, regardless of language or environment, to go pick up the GOF book. In particular, however, I’m going to point people the first 50 pages of the book, not the catalog of patterns that form the rest of the material. That first 50 pages explains the “Zen” of what patterns were trying to accomplish, and how knowledge of patterns can be used on a real-world project. The catalog of patterns is interesting, certainly, but numerous catalogs have sprung up since. Understanding the how and what of patterns is far more fundamental.
(And Alan, if you’re reading this, next time somebody tries to play the design patterns snob, ask them to describe the intent of the Folded Pizza pattern.)
 Certainly, the formerly-named “Model 2″ design described by the old JSP spec is a pattern–it’s just not MVC. In fact, the GOF book broke MVC down into a simpler pattern, the Observer pattern, based on the idea that MVC provided updates to the Views whenever an update was made to the Model. Making a change to the Model in turn told the Controller to update the View. In the world of HTTP, changes to the Model (the JavaBean) aren’t seen in the View (the rendered JSP output) until it’s explicitly requested. Model 2 is more accurately analogous to the “Presentation/Abstraction/Controller” pattern from “Pattern Oriented Software Architecture, Volume 1″.
 Interception is described in “Pattern Oriented Software Architecture, Volume 2″.
Let the flaming begin!