Book Review: Head First Design Patterns
January 15, 2013 Leave a comment
So I understand now why java developers are often accused of spending more time doing mental gymnastics then writing working code. I am working through Head First Design Patterns as sort of a break from the projects I have been coding (on the advice of Steve Suing) and I am running into some interesting questions.
First, I like how the authors have taken the Gang Of Four patterns and made them much more accessible. Not that I like running through academic-prose and small talk examples (I don’t) like in Design Patterns, but the way the Head First books deliver content is great.
Second, the examples they pick for a given pattern are really well thought-out. Faster than your can say “Liskov Substitution Principle”, the first chapters explanation of the limitations of inheritance using ducks was spot on.
Third (notice 2 nice things before 1 not-nice? They teach that at the positive coaching alliance), I am disappointed that their idea of a “test harness” is a console app. The next version of the book should use unit tests.
Finally, some code. I was working though the examples when I got to chapter 3 (I am using C# and not java because I value secure software):
Base Class:
public abstract class Beverage { public Beverage() { Description = "Unknown Beverage"; } public String Description { get; internal set; } public abstract double Cost(); }
(I changed the Description from a field and getter method to a property. The IL effect is the same, I believe)
The Decorator:
public abstract class CondimentDecorator: Beverage { public new abstract String Description { get; } }
And example Beverage:
public class Espresso: Beverage { public Espresso() { this.Description = this.GetType().Name; } public override double Cost() { return 1.99; } }
(I changed the Description setter from a hard-coded string to a method assuming the class name is the same. And yes, ToString() should be overridden also)
And Example Condiment:
public class Mocha: CondimentDecorator { Beverage _beverage; public Mocha(Beverage beverage) { _beverage = beverage; } public override string Description { get { return _beverage.Description + ", " + this.GetType().Name; } } public override double Cost() { return .20 + _beverage.Cost(); } }
So what is wrong? Well, are you asking or telling Mocha? If you are asking, then the method should be CalcualteCost(). If you are asking, then you should call GetCost() or its syntactical equivalent Cost{Get;} so you really have a POCO. And if you are doing a calculation in a POCO, you are doing something wrong. So the method should be CalculateCost(). Syntax aside, that means that the Description should be CalculateDescription(). So this looks like a clear violation of command/query separation. Is this violations the pattern’s fault or the authors? I don’t know. I don’t really care. I guess I “get” the decorator pattern enough so I can have this conversation:
Jamie: Hey, how would you architect an application that needs pluggable components?
Some architect: What about using the Decorator Pattern?
Jamie: Have you ever implemented that, like, for real?
Some architect: Oh, I don’t implement. I just design. Want to see the UML?
Jamie: No Thanks.
This brings me to the next part of the book that I am still thinking whether I like or not. As Bob Martin explains, software has 2 values: the primary value and the secondary value. The primary is how well the software changes, the secondary is how well it meets the current requirements. Quite often I see line developers with immediate deadlines looking to solve the secondary value talking to the architect who is interested in the primary. Who is right? Does it matter? Until technical debt is put on the balance sheet, I fear that secondary will always be put in the back-seat. I guess code re-work is good for consultants.
Finally, the one thing I really disagree with the book are these captions:
I disagree that they put in this global assumption that is a hold-over from the mainframe programming days. Duplicate code is better than code that has to be changed. With modern source control and refactoring tools used correctly, duplicate code is not bad. In fact, if you duplicate code to make sure your follow the Single Responsibility Principle, that is OK. If you want to refactor later to consolidate, that is fine as long as the unit tests still run green.
And I think that is the conclusion that I have to my 1st sentence. Design Patterns are not the end of themselves (most people agree in theory). They are not even the beginning (Too many architects that I know disagree with that). Patterns are what you back into and refactor to, not the other way around. Not really this books fault – after all it is a book about design patterns – not writing working software. To this end, I think you need to look at Refactoring to Patterns.
Thanks to this clip which I listened to 5 times repeatedly when doing this blog post):