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.