A friend told me a tale about a technical job interview from years
ago. The feedback he received from the interviewer was that he had
private incorrectly. The code was something like this:
class FizzBuzz def generate # ... end private FIZZ = 3 BUZZ = 5 # ... end
Constants can be made private using
The interviewer had correctly identified that the
constants were still publicly accessible. In Ruby,
private does not
# constants are accessible from outside the class FizzBuzz::FIZZ #=> 3
Class methods are also not affected by
private, but can be made
class << self syntax.
Even so, this usage of
private is not “incorrect”. What the
interviewer failed to identify is that
private is for humans.
Let’s look at why, on today’s episode of This Ain’t It, Chief.
The Purpose Of
Let’s start by looking at the purpose of
In a nutshell, the purpose of
private is to communicate stability
and safety. It discourages developers from using certain bits of code
that are likely to have breaking changes in the future — or perhaps
that have nasty, non-obvious side effects. This helps to prevent bugs
and facilitates refactoring.
Private methods can be accessed with
Private constants can be accessed with
I say it “discourages” instead of “prevents”, because Ruby can not
guarantee that private things are not accessed from outside of the
class. On the contrary, Ruby provides built-in metaprogramming
functionality that makes it trivial to access private things. In
private is more about communication than enforcement1.
private Achieves Its Purpose
While writing code,
private communicates information to the
developer in two ways.
private communicates information programmatically too, via Ruby’s
metaprogramming functionality, but this is a comparatively rare use
Firstly, it acts as a label. Developers can see whether something is private while reading code or documentation. It is a written warning.
Secondly, it causes errors to be raised when private methods/constants are accessed from outside the class. Developers can use these errors as feedback instead of reading code or documentation, while in a REPL (like IRB, Pry, or Byebug), or while writing tests in a TDD-like workflow.
Is It Wrong To Put Constants Under
With all that in mind, is it wrong to put constants under
despite the fact that they will not raise errors when accessed?
I think that this use of
private has achieved its intended purpose.
It communicates to developers that the constant should not be relied
upon, regardless of whether it raises an error when accessed.
To say that it is wrong implies that the only benefit of
enforcement not communication — that it’s pointless unless it
raises an error. That’s not the case. And since the errors are trivial
to bypass, if enforcement is high on your list of priorities then
you’re probably using the wrong programming language.
It is possible for a developer to use one of these pseudo-private constants accidentally. If they guess the constant name without reading the file it comes from, and everything works during testing, then they might be unaware that the constant was intended to be private. But looking at it pragmatically, this scenario is more or less imaginary. Developers don’t write code that way. If I asked a bunch of Rubyists whether they are concerned about the quality of their codebase being negatively affected by the accidental use of constants which were intended to be private, I’m guessing the most common answer would be “… what?”.
So no, it is not incorrect to place constants underneath
It’s good enough for most purposes. And because the theoretical
negative consequences don’t happen in practice, to insist otherwise is
pedantry. Private is for humans, not for computers.
Some people are even of the opinion that public methods should be considered to be private in certain circumstances.
In Practical Object-Oriented Design in Ruby, Sandi Metz says:
If the illusion of control is a comfort, feel free to use the keywords. However, many perfectly competent Ruby programmers omit them and instead use comments or a special method naming convention (Ruby on Rails, for example, adds a leading ‘_’ to private methods) to indicate the public and private parts of interfaces. These strategies are perfectly acceptable and sometimes even preferable. They supply information about method stability without imposing visibility restrictions.
TomDoc is another example of this:
Instead of assuming that all classes and methods are intended for public consumption, TomDoc makes the Public API opt-in. To denote that something is public, all you have to do is preface the main description with “Public:”. By forcing you to explicitly state that a class or method is intended for public consumption, a deliberate and thoughtful Public API is automatically constructed that can inform disciplined version changes according to the tenets of Semantic Versioning.