all repos — h3rald @ 85abf5c629c64f65112928c2737db6a27e82129e

The sources of https://h3rald.com

content/articles/design-patterns-in-ruby-review.textile

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
----- 
permalink: design-patterns-in-ruby-review
filters_pre: 
- redcloth
title: "Book Review: Design Patterns in Ruby"
comments: 
- :date: 2008-04-16 02:54:41 +02:00
  :author: kint1@libero.it
  :url: ""
  :id: 231
  :body: "ASSOLUTAMENTE OT: se solo fossero arrivati prima a questo: http://logs.cakephp.nu/cakephp/chat.log.2008-04-16 forse cakephp sarebbe da un'altra parte. Ciao e buon lavoro"
date: 2008-04-11 05:41:00 +02:00
tags: 
- ruby
- review
- books
type: article
toc: true
-----

I finally got my hands on a shiny new copy of _Design Patterns in Ruby[1]_. The book itself is not brand new and it was already widely praised by many different people online, so I wanted to take a look for myself.

To my surprise, the book is a hardcover edition, which makes it look more professional and more durable than the average programming book[2]. It's also smaller and shorter than the average programming book[2] (340 pages), which makes it much easier to carry around and less intimidating to read. It's also _not_ meant to be a reference book, so it is actually pleasant an easy to read all in one go, as you'll soon find out.

What is it about? — well, design patters in the Ruby language of course. But it's not the usual brainwash of programming theory you would expect by a typical book on patters, it has _plenty_ of examples of real code. When I say _real code_ I don't mean the usual Dog/Cat/Horse/<insert animal here> classes or juke-box simulations which don't work at all etc. etc., I mean actual snippets from well known Ruby applications, like RubyGems, FXRuby and, of course, Rails.
OK well, there's an exception perhaps: Russ _did_ include a few wild life simulations (ponds with frogs and similar), but it's only for your own good, and for the sake of tradition.

Anyhow, let's start from the beginning...

h3. Part I: Patters and Ruby

The first part of the book serves as a general introduction to the other two parts. If you know the basics of both design patterns and Ruby, you can safely skip this as you won't find anything of overwhelming interest here. 

Personally I really liked *Chapter 1* though, "Building better Programs with Patterns", in which Russ does a great job in summarizing the original GoF book[3] into four points:

!>/files/design_patterns_in_ruby.jpg! 

* _Separate our the things that change from those that stay the same._
* _Program to an interface, not an implementation._
* _Prefer composition over inheritance._
* _Delegate, delegate, delegate._

Also, although it does not come from the Design Patterns book but from building real systems, the author adds the YAGNI (You Ain't Gonna Need It) principle[4] as a reminder to resist the temptation of implementing things which _may_ be needed _later on_, even if they are not needed right now.
The chapter ends with an outline of the patterns which will be presented throughout the book: 14 out of the original 23 patterns by the Gand of Four will be discussed in Part II and 3 bonus "Ruby-only" patterns will be examined in Part III, as a special treat.

*Chapter 2* (_Getting started with Ruby_) feels perhaps a bit out of place. As others pointed out[5], why does a book on advanced Ruby programming techniques include a 35-page-long introduction on the Ruby language? The answer was given by Russ himself in an interview[6]:

<blockquote>
"The reason that I included the introductory chapter about Ruby in there was to make the book accessible to folks with little or no Ruby background.
Now honestly, I don’t think that you could come to my book with no background in Ruby and walk away from it an expert Ruby programmer &mdash; it’s not really that kind of introductory book.
But I do think that someone with experience in other languages could read my book and come away knowing about Ruby, understanding what all the shouting is about."
</blockquote>

I admit, I skipped this chapter during my first reading because I was eager to move on to the main part of the book, but I did read it afterwards (I had to write this review after all!). It's quite a nice introduction aimed at the average .NET/Java developer: Russ provides a step-by-step presentation of the main features of the language while holding the reader by hand when something weird or scary comes about:

<blockquote>
The slightly strange-looking syntax in this code is actually a tip-off something deep and important: In Ruby, everythng &mdash; and I mean _everything_ &mdash; is an object.
</blockquote>

Of course Chapter 2 won't turn you into a Ruby guru, but it definitely fulfills one of the author's goals: bringing developers of other languages closer to Ruby, and give them a tiny taste of how Ruby can be _wickedly powerful_.

h3. Part II: Patterns in Ruby

Part II constitutes the bulk of the book, describing 14 GoF patterns in 220 pages. The patterns covered are the following:

* Template Method
* Strategy
* Observer
* Composite
* Iterator
* Command
* Adapter
* Proxy
* Decorator
* Singleton
* Factory Method
* Abstract Factory Method
* Builder
* Interpreter

Why not covering all 23? Well, because to be honest, they are rarely used in Ruby. Furthermore, in some cases some of the ones examined in the book may feel a bit _unnatural_ to the average Rubyist: how many times did you ever think about using an External Iterator when @each@ is normally available as default internal iterator for any Array-like class?

Each chapter in this part is devoted to a particular pattern and it is organized in more or less the same way, as outlined in the following sections.

h4. Introduction and Personal Anecdotes

Most chapters start with a personal anecdote involving the author: it may be a memory related to his first job at the local grocery store (Chapter 8), or about the day he decided to buy his son a bike (Chapter 14):

<blockquote>
"I remember the day we bought my son his first bike." [...] I spent hours trying to pull together a minor junkiard of parts according to instructions that would have baffled the entire National Security Agency. As it turned out, picking the bike was the easy part: putting it together was the real challenge.
</blockquote>

This was used to introduce the Builder pattern, and how to use it to configure objects which include different logical parts.
Personally I find this technique particularly useful to introduce a particular problem from a different, more mundane prospective instead of starting off with an abstract theorethical description of the pattern itself. 
The anecdote is then followed by the description of the actual programming problem for which the specific pattern will be used.

h4. Description of the Pattern and Initial Implementation

An initial implementation of the pattern in Ruby will be provided more or less immediately after the introduction of each chapter, often accompanied by a simple UML diagram.
This implementation normally has quite a few conceptual flaws, which are then examined and corrected step-by-step the chapter to obtain a more "Ruby-friendly" solution.

h4. A More Rubyfied Version of the Pattern

The final implementation of each pattern is often very different from the initial attempt, and it may contain quite a lot of Ruby-specific code. The author does an excellent job in suggesting pattern implementations which often use blocks, @Proc@ objects or method redefinitions when needed, to make the code more succint and more readable at the same time, as all Ruby code should be.

By doing so, even people who are still learning Ruby will understand how to use some very useful Ruby idioms which can be a bit difficult to grasp otherwise.   

h4. Using and Abusing &lt;Pattern&gt;

Patterns are often overused and misused, and some people normally end up wondering if they should be used at all, after all. This section (present as a matter of fact in _every_ chapter of part II an III) examines the pitfalls of the pattern and the most common mistakes developer make when applying it.
It is by far the most useful section of each chapter, and that's what I'll be reading and re-reading every time I'm thinking about using a particular pattern in my code. As a matter of fact, these sections make you realize that _every_ pattern has its own inherent flaws and dangers, and that it is far from being a Silver Bullet. Even when you're _supposed_ to use a pattern to accomplish something, be aware that _something nasty_ can happen unless you're extra careful: this, perhaps, is the true Golden Rule conveyed throughout the whole book.

h4. &lt;Pattern&gt;s in the Wild

This is another very interesting section which is included in every chapter of part II and III. After describing what a pattern does, how it _can_ be used and how it _should_ be used, you'll finally find some interesting examples taken from real world applications.
By "real world application" I mean something like ActiveRecord[7] (Observer, Command, Adapter, ...), DRb[8] (Proxy) or FXRuby[9] (Composite), for example, i.e. important programs and libraries which are used in production environments.
Personally, I was really glad to find such examples in this book: it definitely helps you feeling design patterns as something more practical and useful than pure software architecture theories.

h4. Wrapping it Up

"Wrapping it Up" is the title of the last section of each chapter of Part II and III. It's basically a summary of the whole chapter and thus a useful way to recap the most important concepts. I found this section particularly useful when using the book as a design pattern reference, after reading it for the first time: this section provides a quick and essential overview of each pattern -- and the most important DOs and DON'Ts, too. 

h3. Part III: Patterns for Ruby  

By the time you get to Part III you'll definitely feel that Ruby can do _more_. Some of the Ruby implementation of certain patterns described in the book make extensive use of blocks and Proc objects, and the @method_missing@ method (although potentially dangerous unless extra care is taken) gives us a more immediate way to obtain delegation, for example when creating Proxies. 
Also the fact that objects can be modified at runtime by adding and removing methods "as needed" seems quite an underused feature in traditional patterns, simply because those patterns were first conceived for languages which are very different from Ruby and are perhaps less _liberal_ than Ruby when it comes to dynamic features[10].

These particular Ruby features can be used (and abused, of course) to implement more Ruby-esque patterns, such as the ones included in this part of the book:

* Internal Domain-Specific Languages
* Meta-Programming
* Convention Over Configuration

These are just examples, of course some may complain because the Active Record or ORM pattern are missing, but this is understandable as it may be considered too specific compared to the others. 
Each pattern is examined in detail, and I particularly like way the DSL pattern was described: Chapter 16 explains how to develop a simple but effective Ruby DSL from scratch for creating file backups. This can be particularly useful for people who never tried creating DSLs before, but also for developers who tried, but want to improve their skills.

Chapter 18 (Convention Over Configuration) is sufficiently clear and detailed, perhaps even too much if you already know how Rails was developed (and all the hype which follwed). 

On the other hand, I was a bit disappointed by Chapter 17 (Meta-Programming). Maybe it's because I built up extremely high expectations about it while reading the rest of the book, but it just felt too short and not detailed enough for my liking. If I had to write such a chapter (which would have been actually very hard), I would have started from an excellent post by Ola Bini[11] which introduces _eleven_ meta-programming techniques, and built up content and examples from there. The only reason why -- I think -- Russ didn't do it in his book was length/balance constraint: a _properly detailed_ chapter about meta-programming in Ruby could easily take up over forty pages!

h3. The Verdict

As I said in the beginning: this is not meant to be a complete, in-depth, reference book on everything you may want to know about design patterns in Ruby. That's why, as a matter of fact, you can actually read this book all the way through without getting utterly bored. Russ uses an informal, yet appropriate style to turn potentially complex, theorethical computer science principles into easy-to-understand, _useful_ tools which can truly improve the way you code. 

The whole book flows very very nicely. I actually recommend reading this book in sequence, without skipping chapters, because each pattern is described in a way that is somehow linked to the following ones, so that you can understand and learn about the pros and cons of each one in a more natural and useful way.

OK, I would have loved to see Part III as long as Part II, probably, but overall I'm very, very satisfied of what the book taught me. The only problem is that it also made me suddenly realize all the naive design mistakes I've been making when coding in Ruby, so I'll now feel compelled to fix at least some of them...

Definitely a worthwhile read, I just hope to see more books like this, or even a second edition of this one soon!

h3. Notes

fn1. "Design Patterns in Ruby":http://www.informit.com/store/product.aspx?isbn=0321490452 by Russ Olsen, Addison Wesley Professional, 2007.

fn2. Think of "Programming Ruby: The Pragmatic Programmer's Guide, 2nd Ed.":http://www.pragprog.com/titles/ruby by Dave Thomas with Chad Fowler and Andy Hunt, Pragmatic Programmers, 2004.

fn3. "Design Patterns: Elements of Reusable Object-Oriented Software":http://www.informit.com/store/product.aspx?isbn=0201633612, by By Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides (a.k.a. the _Gang of Four_), Addison Wesley Professional, 1994.

fn4. For more information on the YAGNI principle, visit "You're NOT gonna need it":http://www.xprogramming.com/Practices/PracNotNeed.html, Ronald E Jeffries.

fn5. See "Design Patterns in Ruby, a review":http://on-ruby.blogspot.com/2007/12/design-patterns-in-ruby-review.html, _On Ruby_blog.

fn6. See "Russ Olsen Interview":http://on-ruby.blogspot.com/2008/01/russ-olsen-interview.html, _On Ruby_blog.

fn7. "ActiveRecord":http://ar.rubyonrails.com/ is an implementation of the Object-Relational Mapping (ORM) pattern used by the Ruby on Rails framework.

fn8. Distributed Ruby, see "Intro to DRb":http://chadfowler.com/ruby/drb.html by Chad Fowler.

fn9. "FXRuby":http://www.fxruby.org/, a graphical toolkit written in Ruby.

fn10. This can be a good or bad thing depending on the way you look at it, and what you want to use the language for. The fact that Ruby is dynamically typed makes it easier to do things which are totally impossible in C++ or Java, but it also introduces a whole new set of potential dangers.

fn11. "Ruby Metaprogramming Techniques":http://ola-bini.blogspot.com/2006/09/ruby-metaprogramming-techniques.html, Ola Bini: Programming Language Synchronicity.