Crafting well-designed software artifacts is tremendously difficult. As for most engineering activities, making the right choices is best achieved with the help of a wise and insightful guide. This book is exactly such a guide.
The book smoothly brings the reader into the realm of software design using Ruby, a dynamically typed object-oriented programming language. It motivates and illustrates a fair number of programming design rules, and innovates on essentially two points. First, it largely discusses the benefits of using a dynamically typed language. It presents duck typing as a valuable asset to reduce development cost. Second, it highlights how Ruby’s module nicely complements single-class inheritance for better productivity.
Unit testing is presented at the end of the book, in the last chapter. In my opinion, testing could have been introduced much earlier since most of the examples given in the book come with an expression to illustrate the intended behavior of the code. Such an expression can be perfectly embedded in an assert statement, turning an ad hoc expression into an automatic and repeatable scenario. In addition, unit testing is a wonderful tool for identifying the right interface for objects, especially when compared with unified modeling language (UML) sequence diagrams.
Ruby, as well as most programming languages, offers a reflective mechanism that includes keywords such as kind_of?, is_a?, and responds_to? It is widely known that using these introspective facilities reflects a fragile programming style. Although the author does not particularly advocate for their use, information on how to avoid using them is hidden behind the notion of polymorphism without being more precise. The double dispatch design pattern addresses exactly that point by favoring a proper distribution of responsibilities rather than relying on object identities. I wish Metz had emphasized this point.
Leaving these two critiques aside, the book is well written. The chapters are well balanced, with the right amount of examples, experiences, and theory. The writing style is entertaining, easy to follow, and accessible (here, I am specifically thinking about non-native English readers).
Although primarily written for Ruby programmers, fans of other programming languages will find valuable material in this book. Aside from chapter 7, which is about sharing role behavior using Ruby modules, the chapters of the book are loosely tied to Ruby.
The book does not target people who wish to learn Ruby. Instead, it focuses on seasoned programmers who want to fine-tune their design skills. It will nicely complement a reference on design patterns.