contents/articles/design-patterns-in-ruby-review.html
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 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
----- title: "Book Review: Design Patterns in Ruby" content-type: article timestamp: 1207885260 tags: "ruby|review|books" ----- <p>I finally got my hands on a shiny new copy of <em>Design Patterns in Ruby<sup class="footnote" id="fnr1"><a href="#fn1">1</a></sup></em>. 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.</p> <p>To my surprise, the book is a hardcover edition, which makes it look more professional and more durable than the average programming book<sup class="footnote" id="fnr2"><a href="#fn2">2</a></sup>. It's also smaller and shorter than the average programming book<sup class="footnote" id="fnr2"><a href="#fn2">2</a></sup> (340 pages), which makes it much easier to carry around and less intimidating to read. It's also <em>not</em> 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.</p> <p>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 <em>plenty</em> of examples of real code. When I say <em>real code</em> 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.<br /> OK well, there's an exception perhaps: Russ <em>did</em> 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.</p> <p>Anyhow, let's start from the beginning…</p> <h3>Part I: Patters and Ruby</h3> <p>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. </p> <p>Personally I really liked <strong>Chapter 1</strong> though, “Building better Programs with Patterns”, in which Russ does a great job in summarizing the original GoF book<sup class="footnote" id="fnr3"><a href="#fn3">3</a></sup> into four points:</p> <p style="float:right;"><img src="/images/design_patterns_in_ruby.jpg" alt="" /></p> <ul> <li><em>Separate our the things that change from those that stay the same.</em></li> <li><em>Program to an interface, not an implementation.</em></li> <li><em>Prefer composition over inheritance.</em></li> <li><em>Delegate, delegate, delegate.</em></li> </ul> <p>Also, although it does not come from the Design Patterns book but from building real systems, the author adds the <span class="caps">YAGNI</span> (You Ain't Gonna Need It) principle<sup class="footnote" id="fnr4"><a href="#fn4">4</a></sup> as a reminder to resist the temptation of implementing things which <em>may</em> be needed <em>later on</em>, even if they are not needed right now.<br /> 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 <span class="caps">III</span>, as a special treat. </p> <p><strong>Chapter 2</strong> (<em>Getting started with Ruby</em>) feels perhaps a bit out of place. As others pointed out<sup class="footnote" id="fnr5"><a href="#fn5">5</a></sup>, 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<sup class="footnote" id="fnr6"><a href="#fn6">6</a></sup>:</p> <blockquote> <p>“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.<br /> 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 — it’s not really that kind of introductory book.<br /> 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.”</p> </blockquote> <p>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 .<span class="caps">NET</span>/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:</p> <blockquote> <p>The slightly strange-looking syntax in this code is actually a tip-off something deep and important: In Ruby, everythng — and I mean <em>everything</em> — is an object.</p> </blockquote> <p>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 <em>wickedly powerful</em>. </p> <h3>Part II: Patterns in Ruby</h3> <p>Part II constitutes the bulk of the book, describing 14 GoF patterns in 220 pages. The patterns covered are the following:</p> <ul> <li>Template Method</li> <li>Strategy</li> <li>Observer</li> <li>Composite</li> <li>Iterator</li> <li>Command</li> <li>Adapter</li> <li>Proxy</li> <li>Decorator</li> <li>Singleton</li> <li>Factory Method</li> <li>Abstract Factory Method</li> <li>Builder</li> <li>Interpreter</li> </ul> <p>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 <em>unnatural</em> to the average Rubyist: how many times did you ever think about using an External Iterator when <code>each</code> is normally available as default internal iterator for any Array-like class?</p> <p>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.</p> <h4>Introduction and Personal Anecdotes</h4> <p>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):</p> <blockquote> <p>“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.</p> </blockquote> <p>This was used to introduce the Builder pattern, and how to use it to configure objects which include different logical parts.<br /> 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. <br /> The anecdote is then followed by the description of the actual programming problem for which the specific pattern will be used.</p> <h4>Description of the Pattern and Initial Implementation</h4> <p>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 <span class="caps">UML</span> diagram.<br /> 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.</p> <h4>A More Rubyfied Version of the Pattern</h4> <p>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, <code>Proc</code> 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.</p> <p>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.</p> <h4>Using and Abusing <Pattern></h4> <p>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 <em>every</em> chapter of part II an <span class="caps">III</span>) examines the pitfalls of the pattern and the most common mistakes developer make when applying it.<br /> 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 <em>every</em> pattern has its own inherent flaws and dangers, and that it is far from being a Silver Bullet. Even when you're <em>supposed</em> to use a pattern to accomplish something, be aware that <em>something nasty</em> can happen unless you're extra careful: this, perhaps, is the true Golden Rule conveyed throughout the whole book. </p> <h4><Pattern>s in the Wild</h4> <p>This is another very interesting section which is included in every chapter of part II and <span class="caps">III</span>. After describing what a pattern does, how it <em>can</em> be used and how it <em>should</em> be used, you'll finally find some interesting examples taken from real world applications.<br /> By “real world application” I mean something like ActiveRecord<sup class="footnote" id="fnr7"><a href="#fn7">7</a></sup> (Observer, Command, Adapter, …), DRb<sup class="footnote" id="fnr8"><a href="#fn8">8</a></sup> (Proxy) or FXRuby<sup class="footnote" id="fnr9"><a href="#fn9">9</a></sup> (Composite), for example, i.e. important programs and libraries which are used in production environments.<br /> 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. </p> <h4>Wrapping it Up</h4> <p>“Wrapping it Up” is the title of the last section of each chapter of Part II and <span class="caps">III</span>. 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.</p> <h3>Part <span class="caps">III</span>: Patterns for Ruby</h3> <p>By the time you get to Part <span class="caps">III</span> you'll definitely feel that Ruby can do <em>more_. Some of the Ruby implementation of certain patterns described in the book make extensive use of blocks and Proc objects, and the @method</em>missing@ method (although potentially dangerous unless extra care is taken) gives us a more immediate way to obtain delegation, for example when creating Proxies. <br /> 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 <em>liberal</em> than Ruby when it comes to dynamic features<sup class="footnote" id="fnr10"><a href="#fn10">10</a></sup>.</p> <p>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:</p> <ul> <li>Internal Domain-Specific Languages</li> <li>Meta-Programming</li> <li>Convention Over Configuration</li> </ul> <p>These are just examples, of course some may complain because the Active Record or <span class="caps">ORM</span> pattern are missing, but this is understandable as it may be considered too specific compared to the others. <br /> Each pattern is examined in detail, and I particularly like way the <span class="caps">DSL</span> pattern was described: Chapter 16 explains how to develop a simple but effective Ruby <span class="caps">DSL</span> 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.</p> <p>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).</p> <p>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<sup class="footnote" id="fnr11"><a href="#fn11">11</a></sup> which introduces <em>eleven</em> 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 <em>properly detailed</em> chapter about meta-programming in Ruby could easily take up over forty pages!</p> <h3>The Verdict</h3> <p>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, <em>useful</em> tools which can truly improve the way you code.</p> <p>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.</p> <p>OK, I would have loved to see Part <span class="caps">III</span> 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…</p> <p>Definitely a worthwhile read, I just hope to see more books like this, or even a second edition of this one soon!</p> <h3>Notes</h3> <p class="footnote" id="fn1"><a href="#fnr1"><sup>1</sup></a> <a href="http://www.informit.com/store/product.aspx?isbn=0321490452">Design Patterns in Ruby</a> by Russ Olsen, Addison Wesley Professional, 2007.</p> <p class="footnote" id="fn2"><a href="#fnr2"><sup>2</sup></a> Think of <a href="http://www.pragprog.com/titles/ruby">Programming Ruby: The Pragmatic Programmer's Guide, 2nd Ed.</a> by Dave Thomas with Chad Fowler and Andy Hunt, Pragmatic Programmers, 2004.</p> <p class="footnote" id="fn3"><a href="#fnr3"><sup>3</sup></a> <a href="http://www.informit.com/store/product.aspx?isbn=0201633612">Design Patterns: Elements of Reusable Object-Oriented Software</a>, by By Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides (a.k.a. the <em>Gang of Four</em>), Addison Wesley Professional, 1994. </p> <p class="footnote" id="fn4"><a href="#fnr4"><sup>4</sup></a> For more information on the <span class="caps">YAGNI</span> principle, visit <a href="http://www.xprogramming.com/Practices/PracNotNeed.html">You're <span class="caps">NOT</span> gonna need it</a>, Ronald E Jeffries.</p> <p class="footnote" id="fn5"><a href="#fnr5"><sup>5</sup></a> See <a href="http://on-ruby.blogspot.com/2007/12/design-patterns-in-ruby-review.html">Design Patterns in Ruby, a review</a>, <em>On Ruby</em>blog.</p> <p class="footnote" id="fn6"><a href="#fnr6"><sup>6</sup></a> See <a href="http://on-ruby.blogspot.com/2008/01/russ-olsen-interview.html">Russ Olsen Interview</a>, <em>On Ruby</em>blog.</p> <p class="footnote" id="fn7"><a href="#fnr7"><sup>7</sup></a> <a href="http://ar.rubyonrails.com/">ActiveRecord</a> is an implementation of the Object-Relational Mapping (<span class="caps">ORM</span>) pattern used by the Ruby on Rails framework.</p> <p class="footnote" id="fn8"><a href="#fnr8"><sup>8</sup></a> Distributed Ruby, see <a href="http://chadfowler.com/ruby/drb.html">Intro to DRb</a> by Chad Fowler.</p> <p class="footnote" id="fn9"><a href="#fnr9"><sup>9</sup></a> <a href="http://www.fxruby.org/">FXRuby</a>, a graphical toolkit written in Ruby.</p> <p class="footnote" id="fn10"><a href="#fnr10"><sup>10</sup></a> 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.</p> <p class="footnote" id="fn11"><a href="#fnr11"><sup>11</sup></a> <a href="http://ola-bini.blogspot.com/2006/09/ruby-metaprogramming-techniques.html">Ruby Metaprogramming Techniques</a>, Ola Bini: Programming Language Synchronicity.</p> |