Exploring the Lands of Public and Private Interfaces
Let’s talk about interfaces (and possibly spaghetti)!!
Interface can mean a bunch of things in different contexts, but in this post I’ll be referring to it as anything that is contained within a Class. Lately, I’ve been reading Sandy Metz’s book, Practical Object Oriented Design in Ruby (affectionately called “POODR”) and I came across an interesting chapter about designing flexible interfaces. Although I have been using Public and Private methods in my code, I never really looked into “why” there should be a distinction between methods in a Class (at the time I also didn’t know what was meant by “interface”).
All Classes implement methods that are meant to be used by others (usually more general methods) and methods only designed to be used inside the Class. The methods that are intended to be used by others are part of what’s called the Public interface. These methods reveal just enough information about the Class to be useful, they should be unsurprising, dependable and reveal the intentions of the Class they belong to. If a Class reveals too much of itself, consequently, it will end up knowing too much of it’s neighbors. This leads to a highly coupled design (in other words: Spaghetti Code).
So how can we avoid the terrors of Spaghetti Code??
One way we can combat the evils of Spaghetti Code is to explicitly classify certain method under the Private interface (which basically means “Do not touch or else!”). The Private interface will contain any methods that are not intended to be used by others, cannot be trusted or depended on, they might also handle implementation details and/or can change for any reason.
Let’s explore what Private means in Ruby!
If I use the method Private in a Class I would expect any method after it (unless I specifically want it Public) to be “uncallable” from outside of the Class. In Ruby this is not true (not sure if this applies to other languages as well). What Private means in Ruby is that a method cannot be called with an explicit receiver.
For example, this will throw an error because I have an explicit receiver calling private_method_here (I will also get an error if I call private_method_here directly).
However, if I call private_method_here with an implicit receiver then no error is thrown!
There are also a few other ways to gain access to private_method_here.
It seems that Private in Ruby acts more like a suggestion rather than being strictly enforced.