Having recently graduated from the Flatiron School, I am working my way through programming-related reading, beginning with Sandi Metz’s “Practical Object-Oriented Design in Ruby”. Click here for more posts about POODR.
What you see above are two very different communication patterns. Metz describes them as follows:
In the first application, the messages have no apparent pattern. […] In the second application, the messages have a clearly defined pattern. […] The design issue in the first application is not necessarily a failure of dependency injection or single responsibility. Those techniques, while necessary, are not enough to prevent the construction of an application whose design causes you pain. The roots of this new problem lie not in what each class does but with what it reveals.”
Welcome to public and private interfaces. As Metz explains, we can separate out the methods that we expose and reveal (that is, the public interface) from those that we keep private (known as the—wait for it—private interface). A couple other definitions of public and private interfaces:
Public Interfaces | Private Interfaces |
---|---|
The methods that make up the public interface of your class comprise the face it presents to the world. They:
|
All other methods in the class are part of its private interface. They:
|
What does that actually mean? POODR provides a helpful example of a restaurant kitchen: a customer should simply order their meal and have it served to them—the menu constitutes the public interface—without needing to go behind-the-scenes into the kitchen.
Awesome. Let’s look at a real life example: Tender (Github repo here). The image below depicts the main interface for the user: she is given options of sending or requesting bitcoin, typing a message, and designating an amount. This is the user’s “menu”, her public interface, the graphic at right at the top of this post. Of course, there’s a private interface as well, the kitchen to this menu, the interwoven left graphic.
How does this play out in code? Like this:
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 |
|
Without getting into the details of each method, what this structure demonstrates is a public interface that exposes just the send_bitcoin
and request_bitcoin
methods. This is all the menu that the User needs. Of course, behind the scenes there are lots of private methods being called, to say nothing of the controller actions delegating those methods, but the user only needs these two.
It comes down to creating explicit interfaces. As Metz argues,
Your goal is to write code that works today, that can easily be reused, and that can be adapted for unexpected use in the future. Other people will invoke your methods; it is your obligation to communicate which ones are dependable.
Every time you create a class, declare its interfaces. Methods in the public
interface should
- Be explicitly identified as such
- Be more about what than how
- Have names that, insofar as you can anticipate, will not change
- Take a hash as an options parameter
The code in the User model above was my attempt to do these things and thus apply practical techniques of object-oriented design.