Book Review: Elemental Design Patterns 129
jkauzlar writes "Believe it or not, it's been 18 years since Design Patterns by Gamma, et al, first began to hit the desks of programmers world-wide. This was a work of undeniable influence and usefulness, but there is criticism however that pattern-abuse has lead to over-architected software. This failure is perhaps due to wide-spread use of patterns as templates instead of understanding their underlying 'grammar' of this language such that it may be applied gracefully to the problem at hand. What's been missing until now is a sufficiently authoritative study of design patterns at this 'grammatical' level of abstraction. Jason McC. Smith, through a surprisingly captivating series of analytic twists and turns, has developed a theory of Elemental Design Patterns that may yet rejuvenate this aging topic." Keep reading for the rest of Joe's review.
Much as developing a large taxonomy of star-types in astronomy lead to and enabled theories of star formation, or a classification of organic life lead to studies of genetics, it makes sense that the large volumes of collected object-oriented design patterns should somehow lead to a generic understanding of them. Smith actually approached this in an attempt to solve a very practical problem: given the variety of ways a particular pattern can be implemented, how can one be recognized programmatically with a degree of certainty?
Elemental Design Patterns | |
author | Jason McC. Smith |
pages | 368 |
publisher | Addison-Wesley Professional |
rating | 9/10 |
reviewer | Joe Kauzlarich |
ISBN | 978-0321711922 |
summary | Software Design |
What's most fascinating about Elemental Design Patterns is the analysis performed in working out a solution to the question of how a pattern may be defined in a way that's language-agnostic and flexible to differing implementations. This was a success: his resulting pattern recognition tool even found unintentional usages of well-known design patterns in a large legacy code base, which could then be refactored from the ugly 'accidental usage' to transform apparent chaos into maintainable order.
The basic idea is that every pattern is composed of elemental patterns. For example, the 'Factory Method' pattern may be decomposed into four EDPs (elemental design patterns): 'Create Object', 'Fulfill Method', 'Conglomeration' and 'Retrieve'. The 'Pattern Instance Notation', introduced in this book, and which serves as an extension to UML, helps visualize the relationships between the four sub-patterns and the larger pattern. No doubt readers will find the notation useful in their own work.
This premise's success or failure hinges on two questions: are the set of patterns really elemental? and can the set of patterns be complete? Oddly, the patterns listed in the book are NOT complete: "this book touches on only one-quarter, at best, of the possible EDPs that exist" (p. 107). The fact that this book (which defines 16 patterns in depth) is only the beginning of a project is not well-communicated. Those who might benefit from a complete listing of EDPs (i.e. analysis tool makers) might be puzzled at how to immediately put this book to use if it's not complete. After all, Smith insists in the Preface that "this book is meant to be used." To me, this implies it should serve as more than a basis for research or design-skills edification.
As for them being elemental, in the sense that all possible 'macro-patterns' may be built from them, Smith backs up this claim with the help of a mathematical formal system called rho-calculus, which is introduced in some depth in the appendix, but avoided in the body of the text for readability's sake. Readers wanting a full mathematical treatment are referred to Smith's Ph.D thesis.
What makes the book worth reading and re-reading is in the methods employed to analytically derive EDPs. As dull as I probably make it sound, Smith gives the entertaining first half of the book an almost 'novelistic', first-person quality in which the reader is engaged to experience Smith's insights first-hand. In a sense, the EDPs are 'unfolded' from simple concepts like the degrees of method or object similarity in a method-call relationship.
Understanding this point is important to understanding EDPs: a method call is not just a method call from a 'micro-patterns' perspective. Calling a very different method on the same object is semantically distinct from calling a very similar method on a very different object. The first is described by the EDP 'Conglomeration' (breaking larger tasks into subtasks); the second, by the EDP 'Redirection' (redirecting a process to another object). Of course, the terms 'similar' and 'different' are fuzzy qualifiers to programmers and there's bound to be some debate on how these terms are applied. Smith, in order to make this distinction, puts faith in the developer's ability to name classes and methods. But anyway, such 'semantic' relationships are the real building-blocks of the higher-level patterns. Once other object-oriented principles are considered, like inheritance, the EDP list grows.
The importance of Elemental Design Patterns from a designer's perspective should now be more clear. I kept stressing the word 'semantic' in the last paragraph because what this book strives to do is provide a *language* for describing object-oriented structure that, first of all, doesn't rely on the OO language itself (C++, Smalltalk, Java, Javascript, etc), and more notably, which takes into account the designer's purpose for employing simple devices like method calls and class extension. As I said earlier, a method call is not just a method call. There may be a dozen or so 'structural' reasons to call a method, and each reason is given it's own 'word' (i.e. EDP) in Smith's language. It stands to reason that a designer with a firmer grasp on his own intentions is a more effective designer.
You can purchase Elemental Design Patterns from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Re:That was painful (Score:5, Informative)
Re:Patterns over hyped? (Score:4, Informative)
I am a senior developer at a large publicly traded company. We have some pretty high volume systems, and I have yet to really use any other patterns besides MVC in my daily activities. I have also worked at several smaller consultant firms and never used them much before my current place. Maybe it's just because the type of problems I have been working on aren't complicated enough?
I would guess that you do in fact use other patterns, but you actually do so without knowing. That isn't a bad thing, because ultimately what really counts is getting stuff done, and not write some kind of whitepaper announcing to the world that your company's current work is the result of an academically perfect implementation of a wide variety of design patterns.
Nonetheless, I find design patterns to be very important and extremely helpful, mainly because they can be seen as a set of pre-defined solutions to a set of well-known problems. In other words, they represent building blocks which have been adequately studied and therefore provide important properties that are already known beforehand.
Knowing these properties is extremely helpful when designing an application, because it lets you minimize the amount of work you will need to do to add some features, or even completely avoid it. By knowing design patterns you are able to come up with solutions to potential problems simply by identifying them and adopting the adequate design patterns to side-step it.
As an example, let's imagine we were developing some sort of 3D modelling application. We could start by defining that the application would consist of a database component, which stores all the information regarding the model, and a GUI component.
As you are already familiar with the MVC pattern [wikipedia.org], we could design the database component with as a model and implement any representation of the 3D model as a different view. But let's go a bit beyond that.
In a 3D modelling application, we can expect that for each database component we might have multiple views. In addition, we might have an indeterminate number of components which might need to be aware of any information stored in the database. A nice way to pull this off is to design the database component as an observer pattern [wikipedia.org]. By doing this, you are free to extend the 3D modelling any time in the future to add a new component without any trouble at all. In addition, you are also able to completely replace other components by simply taking them off and plug in a replacement.
A 3D modelling application also needs to provide the user with a way to operate on the 3D model. Yet, more often than not we don't know everything the user wants to do and how he wants to do it. This means that it is a good idea to implement these operators in a way that you are free to add them in the future without being forced to rummage through half the source code tree. A good way to do this is to implement these modelling operators as a visitor pattern [wikipedia.org]. By doing this, you've just defined a generic interface for every operator you might need, and basically you only need to add a single class to implement any extra feature for the 3D modeller. In addition, if you also make sure you also include the inverse operator for every operator then an undo system will pretty much write itself.
The list goes on and on. You can implement your scene graph by employing a composite pattern [wikipedia.org], you might implement the components to import models from an assorted list of data formats by writing each component as a strategy pattern [wikipedia.org], you may implement a series of UI animations and input states around a state pattern [wikipedia.org], etc
Singleton (Score:4, Informative)
Well, singleton is useful, if only because it is the only way to implement the application object right. Doing it as a singleton allows access from outside the object, handles constructor exceptions, and ensures the destructor always gets called. Making the app object into anything else is bad:
If the app object is a global variable, you can not have exceptions in its constructor; terminate always gets called. Also, you do not get to control initialization order, so if you have any other global objects, they may or may not be initialized before it.
If the app object is a local variable in main, you can not get a pointer to it from anywhere else (and you commonly need to). The second problem is that the destructor will not be called if someone uses exit() (signal handler) or terminate() (some EH problem), causing many problems of resource leaks if the app object is the root of your object tree, as is often the case.
If the app object is a static variable in main, that solves the exit() problem, but you still need to set a global pointer to access it.
Making the app object a singleton, first called from main in a try block, avoids all of the above problems.