Book review: Practical Object-Oriented Design
Practical Object-Oriented Design by Sandi Metz: A well-paced, well-structured, and well-written introduction to the concepts of object-oriented design.
Software design, step-by-step
Being a self-taught programmer (as many scientists are), I’ve always felt that one aspect of software development in which I could improve was software design. Although many of the concepts this book presents were already familiar to me from other books and resources,1 I found it good to have a refresher and a new perspective.
The book presents the concepts as a cohesive whole, with a cogent, clear path from beginning to end. It provides a well-paced and well-structured introduction to object-oriented design, giving the most benefit to software design newcomers. Yet, more experienced professionals looking for a compact refresher will also learn something.
The author covers design-related concepts by introducing and building upon each within the context of building an example application for a bicycle touring company. I liked the way that the book introduces simpler concepts first and then slowly builds upon them to introduce more complex design concepts later. The reader not only takes part in the step-by-step construction of an example application but also builds their knowledge incrementally along the way.
Design concepts
As the subtitle An agile primer using Ruby implies, this is an introductory text and it is paced as such. The book guides the reader on a path covering the single responsibility principle, coupling, interface design, the Law of Demeter, duck typing, inheritance, roles, and composition. The text is rounded off with a discussion of how to design good tests.
Although I recommend you to read the text for yourself, here are some ideas that stood out for me.
Single responsibility principle
Extracting code into methods of single responsibility helps reveal the underlying design and thus helps show where the methods belong; in other words, on what class(es) the methods belong.
One can also isolate responsibilities within a class. This is in contrast to focusing only on the responsibilities of the classes themselves. Methods, as well as classes, have responsibilities and thus one can also use the single responsibility principle on methods.
Dependencies and coupling
One should isolate dependencies in classes as much as possible. Dependencies are like foreign invaders that represent vulnerabilities. Thus, they should be concise, explicit, and isolated.
Injecting dependencies into classes reduces coupling between classes.
Programming with a focus on messages and designing with intent
When writing a new app, one should form an intention about the objects and the messages needed for the use cases in the application. Having a focus on messages can highlight objects that aren’t obvious from focusing only on the nouns in the domain. One should focus on questions such as: “I need to send this message, who should respond to it?”. This then helps to identify the objects needed for the application. A message-based design perspective yields more flexible apps than a class-based perspective.
Sequence diagrams allow one to experiment with objects and messages in an initial design.
When designing an application, one should seek to minimise the context a class needs to do its job. One should also think deeply about interfaces and create them with intent.
Inheritance
Inheritance is a mechanism for automatic message delegation (an interesting perspective and not traditionally taught when introducing inheritance). Inheritance defines a forwarding path for not-understood messages. I.e. a message which isn’t understood in a specific class can redirect the message to a more general class which might be able to handle the message.
One can use the template method pattern to separate the abstract from the concrete in inheritance hierarchies.
Testing
The author advises that test doubles should be tested to ensure they adhere to the interface of the role that they represent. To me, this sounded like “testing the tests”, which goes against common wisdom. Yet, I think this is good advice: tests should nail down behaviour as much as possible so that the application is built upon a solid foundation.
More ideas
The choice to use Ruby was a good one: the language has a clear, simple syntax with a minimum of boilerplate. Thus anyone can follow and understand the code examples even if they aren’t familiar with it.
The text provides good guidance and advice on how to structure an application and manage its dependencies so that it remains flexible in the face of change. After all, as mentioned in the book,
The purpose of object-oriented design is to reduce the cost of change.
which is something to be reminded of periodically.
I liked the natural way the author talked about objects sending messages to one another as being the way that objects communicate.2 I learned about this concept only a few years ago, having learned the more “classical” explanation of object orientation as “objects encapsulate data and functionality”. According to Alan Kay, the person who coined the term object orientation, objects sending messages to one another was a fundamental concept of object orientation.3 Thus it’s great to have a text which discusses messages between objects so normally.
The advice about the design process itself was something that I found particularly good. Instead of presenting the concepts and expecting the reader to know how to use them–as has been my experience with other books on programming design–the author advised how to use the concepts in a program’s design.
There was also an emphasis on thinking about what one is doing and working with intent. For instance, the reader is advised to form an intention about the objects and the messages an app will need when designing it.
This is an application of the “slow down, you’ll go faster” philosophy. In other words, if one takes the time to consider how to proceed, the long-term speed will be higher than if one simply dives in and rashly starts implementing things. Program design is an exercise in managing various trade-offs at different levels of abstraction while also implementing that design in code.
Conclusion
I found the book to be very well written and the author’s descriptions and arguments often to be very elegant. I haven’t seen words like “bevvy” and “aplomb” in a technical book before and it was very refreshing to see a wider range of language used in such a context.
If you’re looking for a gentle introduction to software design or simply want to brush up on your design skills, this is a book I would recommend.
-
After all, I’m very interested in software development as a topic in itself and am always looking for ways to improve and extend my knowledge and experience. ↩
-
This is in contrast to the common practice of talking about calling methods on an object, when in fact a method call is a message sent to an object. ↩
-
Alan Kay specifically says that “the big idea is messaging”. ↩
Support
If you liked this post and want to see more like this, please buy me a coffee!