Private Is For Humans

??? words · ??? min read

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 used 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 private_constant.

The interviewer had correctly identified that the FIZZ and BUZZ constants were still publicly accessible. In Ruby, private does not affect constants.

# constants are accessible from outside the class
FizzBuzz::FIZZ #=> 3

Class methods are also not affected by private, but can be made private using private_class_method or 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 private

Let’s start by looking at the purpose of private.

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 #send and #instance_exec. Private constants can be accessed with #const_get.

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 Ruby, private is more about communication than enforcement1.

How 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 case.

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 private?

With all that in mind, is it wrong to put constants under private, 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 private is 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 private. 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.


Footnotes

  1. 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.

Got questions? Comments? Milk?

Shoot an email to [email protected] or hit me up on Twitter (@tom_dalling).

← Previously: My Beef With RuboCop

Join The Pigeonhole

Don't miss the next post! Subscribe to Ruby Pigeon mailing list and get the next post sent straight to your inbox.