Design Patterns in Ruby
- Author: Russ Olsen
- Publisher: Addison-Wesley Professional Ruby Series
- ISBN 10: 0321490452
- ISBN-13: 9780321490452
- Reviewer: Edwin W. Meyer
A “design pattern” is a general schema for coupling two or more code modules according to best practices that is widely applicable to many types of software systems. Design patterns were first popularized in the 1995 best seller Design Patterns: Elements of Reusable Object-Oriented Software, a collaboration of four authors informally known as the “Gang of Four” (GoF). Design Patterns in Ruby by Russ Olsen presents 14 of the 23 design patterns originally described by GoF (plus 3 new patterns) as adapted to the Ruby language. A valuable bonus is his review of some important features of the language.
The author’s chapter on Ruby basics is clear and quite useful for those new to Ruby. Reading his section on the relation between object instance variables and getter and setter methods would have cleared up some earlier confusion on my part. And I found the section on Ruby procs and blocks very valuable. A block — a section of code between a "do and “end” set or curly braces that is attached to a method invocation — is a much misunderstood technique for composing two different code sections. Many books present the Ruby block before presenting the proc construct, because blocks appear much more frequently than procs in Ruby code. However, this is a mistake, because a block really is a shorthand representation of a proc object. The whole concept is much easier to grasp if procs are presented first, which Olsen does in a clear manner. It’s only 4 pages of the book, but still very valuable if you’re having difficulty understanding blocks.
The author distills the principles embodied in the original GoF design patterns book into four maxims:
- Separate code which changes from that which will likely stay the same. If your design embodies this, you will have a greater chance of coping with a new requirement and there will be less code to change.
- Program to an interface, not an to implementation of that interface. (I.e., to a specification of what a code module should be doing, but not its internal details.) This requires more up-front thinking, but it will help localize changes and bug fixes.
- Prefer composition over inheritance. Thinking of an object as composed of multiple independent features models the real world better than a more rigid “is a kind of” inheritance hierarchy.
- Delegate responsibility. If a code module performs an action that is similar to actions performed by other code modules, have a common module perform it. Very closely related to composition.
Of these maxims, I think the most important and least obvious is the first. The design patterns all embody this principle, as does the composition of a block with a Ruby method. A method such as “each” or “sort” — defined for a collection of objects — is a standard library implementation which is used over and over again in many different places. However, the block attached to it is an often unique code section which does something using each collection element or specifies a specific sort order.
While I have had “good intentions” of learning more about design patterns for years, it wasn’t until I picked up Olsen’s book that I delved deeply into the topic. I must confess that I am left with an “Is that all there is?” feeling after finishing the book. Most of the patterns presented are rather straightforward and not at all unobvious. A few, such as the Interpreter pattern, are likely to be only infrequently used. Moreover, a design pattern is a general description of a relationship between modules, not a template which directly generates code.
Still, knowing about design patterns is useful for a number of reasons. Obvious or not, a design pattern is an abstraction of a common programming paradigm. A ready familiarity with the patterns presented by GoF, Olsen and other authors:
- Assists decision-making during the design process,
- Provides a way of conceptualizing code in larger “chunk” sizes, and
- Promotes concise description of a subsystem design and discussion with others.
Then too, there is the ability to handle the job interview question that Olsen presents in the foreword: “What is your favorite design pattern?” Knowledge of them ensures that you won’t immediately be shown the door.
If you are a Ruby developer and have little to no prior experience with design patterns, I recommend this book — doubly so if your Ruby experience is limited. Reading it might just help you get your next job, but it certainly will assist you in making software design decisions and discussing them with your colleagues.
