This is a review of the second edition of “Practical Object-Oriented Design: An Agile Primer Using Ruby”, by Sandi Metz.
Object-oriented (OO) software design, meaning the idea to model software as encapsulated “objects” with properties and code, has been the most popular approach for the last few decades. However, it has gotten a bad rap in recent years; “the future is functional!” claim its detractors.
After all, when an OO codebase grows, it frequently takes too much time to get things done. “Where once we felt productive, fast, and happy; now we feel thwarted, slow, and frustrated,” writes Sandi. But maybe the source of the problem is not the paradigm (procedural, object-oriented, functional, etc.) but how it is (mis)applied. This book will help you avoid falling into that chaos.
As a Python programmer, I confess I dismissed this book for too long because I thought it was “a Ruby book” (in my defense, it is right there in the title!), but that was a big mistake. Although it uses Ruby for the code examples, you can read it like pseudo-code and it is straightforward to translate the concepts to the language of your choice.
This is a book about how to apply object-oriented design to arrange software to be productive today and to remain so next month and next year. It shows how to write code that brings you joy. It is practical instead of academic, but also surprisingly timeless as so few technical books are. Honestly, my biggest complaint is that it is not sold as a hardcover.
It is practical instead of academic, but also surprisingly timeless as so few technical books are.
The book was written to be accessible to novices with some object-oriented experience, but for more experienced programmers, it will at minimum offer new things to think about and new points of view to consider, even if you disagree in the end with some of its suggestions.
Chapter 1 is the only one with just theory. It explains the whys, whens, and wherefores of object-oriented design, and sets the theme of the book: Applications that are easy to change are “a pleasure to write and a joy to extend”. Applications that resist that change are the opposite.
The rest of the chapters progressively explains object-oriented design using the SOLID design principles and design patterns, each one building on the concepts and code of the last.
It starts with designing classes with a single responsibility. Classes that do one thing isolate that thing from the rest of your application and allow it to change.
Chapter 3 deals with dependencies in terms of how much one object needs to know about another to send it a message (meaning calling one of its methods), and how to recognize, remove or reverse those dependencies.
Next, we consider the role of interfaces and how they should expose “what” a method does instead of “how” it does it. A whole chapter dedicated to “duck typing” — if it walks like a duck and quacks like a duck, just call it a duck — follows it.
Chapters 6 through 8 discuss how to share behavior with classical inheritance, “modules” (often called “mixins” in the Python world), or composition; and provide guidelines for recognizing antipatterns and choosing one technique over another.
Finally, it closes with a chapter concentrated on the design of tests, illustrated using code for the earlier chapters of the book.
The author is the first to admit that the ideas in the book are not hers but belong to the entire object-oriented design community; she “is merely a translator”. If that is so, she does a fantastic job at it. With its clear writing style and great explanations, the book was a joy to read. I finished the book loving object-oriented design as never before.