Saturday, August 02, 2008

The most misunderstood book in CS

After reading yet another blog post which got it totally wrong, I decided to write a bit about design patterns. In my opinion, the 'GOF' book 'Design Patterns' is probably the most misunderstood book in computer science.

The main misunderstandings are:
  • The authors of the book thought they invented the patterns
  • The book says that you have to use the patterns from the book to write good software.
  • The book says that the patterns in the book are the only and most important design patterns
All this is totally, absolutely, completely, outright and utterly wrong. The intent of the book was totally different than many people seem to think today.

To make my point clear, let me quote directly from the book:

"The purpose of this book is to record experience in designing object-oriented software as design patterns. Each design pattern systematically names, explains, and evaluates an important and recurring design in object-oriented systems. Our goal is to capture design experience in a form that people can use effectively. To this end we have documented some of the most important design patterns and present them as a catalog."

So it was obviously known to Gamma et al, that they haven't invented the patterns. They simply collected and named them. Also they explicitly stated that they used patterns from "design in object-oriented systems". They never talked about functional, procedural or logic programming. The book is explicitly about OOP and its stated right in the introduction.

Another quote:

"We all know the value of design experience. How many times have you had design déjà-vu—that feeling that you've solved a problem before but not knowing exactly where or how? If you could remember the details of the previous problem and how you solved it, then you could reuse the experience instead of rediscovering it."

Thats the reason why the authors thought that collecting the patterns was a good idea. They simply wanted to show some successful ways to solve certain problems to teach novices in the field the concepts they have to discover later them self. In no way this means that programmers are required to use certain pattern! The intent was vice versa: Because you nonetheless stumble over the patterns soon enough, why not easy the way and show them right ahead?

And one more:

"Despite the book's size, the design patterns in it capture only a fraction of what an expert might know."

This should remove the notion that the authors thought that the presented patterns are exhaustive.

So what was the real intent and achievement of the book? Mainly two things:

  • Collect frequently used 'patterns' and give them names to make communications between developers easier.

    Programming already have names for certain concepts. "Procedures", "variables", "statements" etc. But before the book there were no names for higher level constructs. For example if we use a wrapper object to lazy create and maintain a single instance of another object, we can now simply say "We use a singleton". Thats the main advantage of giving things names: Make communication easier by using a short name instead of having blurt out lengthy descriptions. This says NOTHING about the question if using Singletons is a good idea or not. But obviously programmers have used this pattern, so the book gave it a name.

  • Present newbies the 'intuitive' knowledge of experienced programmers by making it explicit.

    The presented patterns where common knowledge for most experienced programmers already. When I read the book first more than 10 years ago I quickly recognized most of the presented patterns from by previous experience in OOP. But the nice and exciting thing of the book was that the patterns where presented extracted and isolated from the program they're used in. Most books at this time concentrated on concrete solutions and algorithms and you had to extract the implicitly used patterns by yourself intuitively. By doing this extraction work, Gamma et al were the first who described (for a wider audience) high-level concepts in a easy to understand and also abstract way. There simply wasn't anything like this before. Today all this may seem rather boring because the concept introduced in the book is common knowledge today. But at that time, it was truly revolutionary.

Another common mistake is to think that design patterns are only present in languages like Java. But in fact patterns are everywhere. In every language, in every paradigm. The book just concentrated on OO-design! It primarily used C++ for code examples, because C++ was the 'next big thing' then. C++ doesn't became as successful as expected, but a rather similar language (Java) did. And so it's no surprise, that the presented patterns are now commonly used in Java.

Norvig once wrote that the existence of design patterns is a sign of weakness in a language. I think he was wrong there. Sure, certain patterns are only necessary because a language don't allow to archive a certain goal directly by some build-in concept. But if you build it in, you would quickly discover other patterns 'a level above' instead of getting rid of those pesky design patterns. So we always have patterns, it's simply unadvoidable.

A concrete example: Java uses the "Iterator pattern" quite frequently. Now in functional programming this pattern is quite useless. We simply write map and fold functions and don't need no "iterator". Hah! But hey, isn't "writing a map and a fold function" not also a design pattern? All we need to do is to call it the "map and fold"-pattern. Using this pattern is common knowledge for every user of functional programming languages - so it's good to teach this pattern novices in functional programming right from the beginning. And give it a name to talk about it. And exactly this was the intent of the book. Nothing more, nothing less.

There are lots of other patterns. A small list:
  • Lisp for example often uses the 'macro-pattern' (move often used code into macros instead of repeating it). CommonLisp uses a certain pattern ('gensym') to make macros safe (which lead to Schemes 'hygienic macros' as a way to make this explicit pattern unnecessary).
  • In Haskell we have the 'monad-pattern' which was so successful that they even gave it syntactic support (similar to Java which later got syntactic support for the iterator-pattern). Especially the 'parameter-function'-pattern is quite commonly used in functional programming (it's also known as 'higher-order-functions).
  • From Smalltalk we have the famous 'MVS' (model-view-controller) pattern, which is now very commonly used in other languages too (think of Ruby on Rails for example).
  • In web-programming we have the 'REST-pattern' and the 'Ajax'-pattern.
  • And in Javascript we use various patterns to create modules and classes.
This could go on and on and on... but I hope you see my point

So please stop misunderstanding the rather important step in the history of software design this book was. With this I not only talk about certain authors of certain blog posts (who should read at least the introduction of the book before starting bashing it). I also talk about programmers who think that the presented patterns are the pinnacle and sole tool for writing programs!

The authors of the book wrote in the conclusion "be a critical consumer" and "look for patterns you use, and write them down". Patterns are everywhere, but they change with time, language and application. So don't limit yourself to the patterns in the book! And only use them where they are really useful (and not because you think it makes good design to use them over and over and over again). The intent of the book was to make people observant of the higher-level concepts they use. To show that there is more to programming than algorithms and data-structures. To discover and name structure which was always there, right before our eyes - but without really noticing it. Now we notice - and that was the main achievement of the book.


Andrew said...

Here's my favorite quote which clearly shows that they knew these design patterns were focused on OOP:

"The choice of programming language is important because it influences one's point of view. Our patterns assume Smalltalk/C++-level language features, and that choice determines what can and cannot be implemented easily. If we assumed procedural languages, we might have included design patterns called "Inheritance," "Encapsulation," and "Polymorphism." Similarly, some of our patterns are supported directly by the less common object-oriented languages. CLOS has multi-methods, for example, which lessen the need for a pattern such as Visitor (page 331). In fact, there are enough differences between Smalltalk and C++ to mean that some patterns can be expressed more easily in one language than the other. (See Iterator (257) for an example.)"

Andrew Binstock said...

"the famous 'MVS' (model-view-controller) pattern"

might want to correct that acronym. (Comment not intended for posting.)

I'll post a separate comment for public use.

Andrew Binstock said...

Agreed with your overarching point, but not some of the details.

One confusion that is legitimate and you don't address is the authors' use of the term "Design" patterns. These are not design patterns, but implementation patterns.

Re your additional comments, I think it's a stretch to call Ajax a pattern. I don't want to get into a whole semantic thread, but it is clearly not akin to the other patterns.

Anonymous said...

I mostly agree with you. However, I have one problem with the book: the authors made up names for certain patterns which already had names. The point of having named patterns is ease of communication between programmers. Having two names for the same pattern is contrary to this goal.

The prime example is the visitor pattern. It already had a name: "map". True, the name "map" comes from functional programming while the authors were writing about OOP. That doesn't mean there's any substantial difference between map and visitor. There was simply no good reason to make up a new name.

The fact that the authors created new names where they weren't needed suggests that they wanted to seem more innovative than they actually were.

Anonymous said...

Do you not find it interesting that many of the patterns in the GOF book only exist because of the language limitations inherent to Java and C++ ?

One example is the Singleton pattern and it's use in Java. Only Classes are globally visible in Java and so the reason for the Singleton pattern. Not to mention the long list of problems memory management problems that this leads to in C++ and Java.

good luck !

Anonymous said...

I've been reading through design patterns on my own, since I've developed an interest in learning more about OO outside what they teach in class. I think it's very sobering to keep in mind that though DP encompasses a large amount of very practical information, there's still a lot to learn about it. I feel that DP (or at least parts of it) should be required reading for higher level software engineering courses.

Anonymous said...

In LISP there's only "use higher-level macro to eliminate pattern" pattern :)

Anonymous said...

[quote]C++ doesn't became as successful as expected, but a rather similar language (Java) did. And so it's no surprise, that the presented patterns are now commonly used in Java.[/quote]

Really? Grammar error aside, I guess you live in the confortable world of enterprisiness and programmer incompetency ?

Java is really only used there ;-) C++ is everywhere (including there :D, of course)

Other than this, I entirely agree with your essay. I couldn't have said it better myself.

Anonymous said...

You seem to forget yourself that Java and C++ are not really the best school playground to get an understanding about OO.

Many pattern described in the book are kind of irrelevant in some well-known OO languages (Smalltalk, Io, Javascript, Python, Ruby, Lisp, Perl, Scala, ...).

I am amongst the ones that believe that many patterns described in the book (which is a horrible read IMHO) are rather specific to C++ or Java.

grant rettke said...

Your plea to programmers everywhere to stop misunderstanding is apropos; understanding is in short supply nearly everywhere today!

Unknown said...

I wrote something similar a year ago: "Yes, design patterns are".
One of the greatest contributions of the book also is to show the value and popularize the pattern format, allowing a community to capture their knowledge in a easy to use way...

Jim said...

Another misconception is that design patterns have anything to do with CS. Design patterns are used in software development, quite distinct from CS in most respects (though both pursuits occasionally require computer programming).

Unknown said...

I've read that book many times and I can't agree with you more. I was getting tired of hearing posts of people putting them down. Yes, they have their place. It makes sense to use them in many cases, but it's not the only way to do things nor is required to be a good programmer.

Anonymous said...

I found the GOF book a little dry and incomplete to go through on its own. What I did to engage the OO pattern topic is that I primarily read the Head First Design Patterns book (the one with the babe on front) a chapter at a time, each immediately followed by reading the corresponding pattern in the GOF book. The Head First book has a lot of other useful OO programming pearls besides patterns. It also has a lot of frills (puzzles and such) that you can simply skip. It becomes a pretty quick read if you do this. The combination of the two books served well in bringing the whole topic home for me.

Anonymous said...

The only practical purpose the book has is to assign names to techniques that are painfully obvious to anyone who has a basic understanding of OOP. You can sleep at night knowing that you spent time and money, and all you go out of it was (among other just-as-useful bits of knowledge) that "[using] a wrapper object to lazy create and maintain a single instance of another object" is called a singleton?

Everything in the book could be summed up on a wikipedia page that is flagged as something that should be merged into the "Object Oriented Programming" article because it doesn't warrant its own page.

Anonymous said...

The design patterns people talk about are a sign that the language has deficiencies, e.g. in Smalltalk the only patterns I see come up a lot are double-dispatch patterns (e.g. visitor) and this is because Smalltalk lacks multi-dispatch.

Calling everything under the sun a "pattern" is just ridiculous (e.g. "calling a function is a pattern! see? Here the author has used the 'call a function' pattern 10,000 times!") and illustrates how ridiculous your point is.

Presence of [what any sensible person would call] a "pattern" means absence of a way of abstracting away this "pattern".

This is why Lisp has no patterns what-so-ever. If anything occurs twice then a function/macro will be made to deal with it. CLOS users wont even use the "pattern" of overriding a method and then calling super. They abstracted this common behavior into :before/:after methods at a saving of, at most, one line of code per use.