Catching up with Dominus
Written by Piers Cawley on , updated
Several years ago, Mark Jason Dominus gave a lightning talk entitled ‘Design Patterns’ Aren’t. I didn’t see the talk, but I did come across his writeup not long after I first discovered the Gang of Four’s Design Patterns book. In that talk, Mark put his finger on an issue that had almost subliminally bothered me: many (possibly all) the patterns in that book weren’t really patterns. At least, not in the way Christopher Alexander - the architect who invented the form - described them.
Several years ago, Mark Jason Dominus gave a lightning talk entitled ‘Design Patterns’ Aren’t. I didn’t see the talk, but I did come across his writeup not long after I first discovered the Gang of Four’s Design Patterns book. In that talk, Mark put his finger on an issue that had almost subliminally bothered me: many (possibly all) the patterns in that book weren’t really patterns. At least, not in the way Christopher Alexander - the architect who invented the form - described them. Alexander asserts that:
… no pattern is an isolated entity. Each pattern can exist in the world, only to the extent that it is supported by other patterns: The larger patterns in which it is embedded, the patterns of the same size that surround it, and the smaller patterns which are embedded in it.
For Alexander, patterns only make sense as part of a pattern language. Reading A Pattern Language it becomes apparent that a great deal of thought has gone into selecting the patterns described and the presentation and ordering of the language so that pattern appears in an appropriate context. Throughout, Alexander stresses that these are no mere boilerplates; in one section he talks about the poetry of the language:
In an ordinary English sentence, each word has one meaning, and the sentence too has one simple meaning. In a poem, the meaning is far more dense. Each word carries several meanings; and the sentence as a whole carries an enormous density of interlocking meanings, which together illuminate the whole.
The same is true for pattern languages. It is possible to make buildings by stringing together patterns, in a rather loose way. A building made like this, is an assembly of patterns. It is not dense. It is not profound. But it is also possible to put patterns in such a way that many many patterns overlap in the same physical space: the building is very dense; it has many meanings captured in a small space; and through this density, it becomes profound.
Patterns also only make sense if they have ’the quality without a name’, a quality they share the artefacts they are written to generate, the language in which they are embedded. In one chapter of Patterns of Software, Richard Gabriel grapples with what it means to say that software has the quality without a name and ends up taking a page (p42 if you’ve downloaded the PDF, and you really should, Gabriel has thought deeply and writes well about this stuff) to list some aspects of it. Paul Lynch, an old NeXT programmer friend of mine, reckons that this is because the quality without a name is the Tao and ‘The Tao which can be spoken of is not the true Tao.’ It doesn’t stop us trying though, but it does make it hard.
Looked at in the light of the quality without a name, many of the patterns in the Gang of Four book simply don’t have this quality. Dominus is particularly hard on the Iterator pattern, pointing out that it simply isn’t a universal solution to the problem of doing something with all members of a collection - it’s a workaround for weakness in static languages. In a more dynamic language like Perl, Ruby, Smalltalk and others, the language (or its standard library, the two are essentially the same thing) solves the problem with syntax like foreach
or methods like each
. There simply isn’t the need to build the infrastructure needed to kluge around the problem; it’s already solved in generic fashion which can be extended as appropriate (#inject
, #map
, #reflection_on_all_associations
, …).
Another problem with the GoF book is that it’s not a pattern language but a collection of patterns (a problem which is acknowledged by the authors). In A Pattern Language Alexander and his team present their patterns with plenty of reference to the larger patterns which employ a pattern and the ‘smaller’ patterns it makes use of and this network of relationships reinforces and contextualises the individual patterns as they are discussed. Many of the patterns in Design Patterns are presented in isolation, or with an inconsistent set of motivations. Which is getting away from Dominus’s point and onto one of my own hobby horses. Sorry.
In Design Patterns of 1972, Dominus strengthens his earlier assertion. He claims that “Patterns are signs of weakness in programming languages” and uses the hypothetical Subroutine Pattern from 1972 and the way in which frameworks like Ruby on Rails and Subway have managed to internalize the Model/View/Controller pattern to make his case. He argues that identifying and documenting a pattern shouldn’t be the end of the story. Rather, we should have the long term goal of trying to understand how to improve the language so that the pattern becomes invisible or unnecessary.
Except, Rails hasn’t internalised the MVC pattern, it’s just made it easier to do the Right Thing. If you don’t have some understanding of the pattern, then the Rails Way is going to be bewildering to you.
Martin Fowler Refactoring can be seen as a pattern language - if you become fluent in the language, you’ll find it easier to improve the quality of your code. The thing is, many of the refactorings Fowler describes have been implemented as semi-automated tools. The book is useful even if you have access to a Refactoring Browser because the patterns are presented as a coherent language; the discussion of each refactoring and its motivation teaches you the why of the tool as well as the what. Without the why, the what is often virtually useless.
Kent Beck presents another pattern language in Smalltalk Best Practice Patterns, a book I’ve raved about before and will no doubt rave about again. Beck concentrates on the ’tactics’ of programming in a fashion that makes your intent clear. His utterly humane patterns concentrate on matters like choosing good names for variables, methods, and classes, the appropriate use of Smalltalk Collections. Each pattern carries with it a clearly defined rationale, relating it to other relevant patterns. It seems that concentrating on writing a language has helped infuse the book with the quality without a name; the ‘grammar’ of it reinforces the individual patterns by tying them into a larger entity.
Both Refactoring and Smalltalk Best Practice Patterns present patterns that depend on the programmer adapting them to the particular circumstances in which they are used. It’s exceedingly unlikely that the Composed Method pattern, for instance, will ever be rendered invisible by a language feature - even if we end up using some other programming paradigm, it seems likely that there will still be a need to express our intent by decomposing functional units into well named, smaller, functional units. (Beck does have one pattern that addresses a language limitation - if your language has multimethods, you’re not going to need double dispatch). Many of the refactorings have already been implemented as tools, but they can be used to do awful things to code as well as to improve them. If you lack good taste and integrity, you’re stuffed.
In the end, I think Dominus is mostly right. Patterns are often signs of weaknesses in programming languages. But it seems obvious (though possibly in the same retroactively obvious way that great scientific discoveries seem obvious) that a pattern isn’t the end point. It’s a stop along the way; once you have a pattern it’s time to start looking at whether it’s a pointer to a language/library fix.