Some constants are not meant to be used outside of their class/module… make it clear for your fellow programmers.

Ruby Opinions: Using private_constant

Błażej Kosmowski
3 min readJul 3, 2018

--

I find private_constant to be a very underused tool in most of the ruby projects I’ve dealt with so far. This inclined me to specify a few rules for myself that would help me in deciding whether given constant should be kept private or not.

Configuration consts

Something I refer to as “configuration const” is one of the most common types of consts I use every day. Those consts represent values that affect the way in which the algorithms I implement work. This can be a START_DATE from which I should calculate some results, or it can be some THRESHOLD that controls what range of values I should take into account etc. If I know that such value can change a lot, I often decide to use ENV variable instead, but If I find such value well-known beforehand and it is not subjected to frequent changes, it ends up as a const. I treat such consts as class/module public interface, test how those consts affect code execution and even write a separate test to check their expected values (such values can be calculated during runtime after all). Therefore, I prefer to keep this kind of consts public.

Value-exposing consts

The purpose of some const’s is to share a value across an app (or namespace). This can be for instance, an external id of an object we want to treat in a special way. Obviously, if we are after making something shared, we cannot make it private. Hence these kind of consts remain public.

Refactoring-driven consts

The Introduction of some consts happens during refactoring — those might be configuration consts or value-exposing consts as well, but those two kinds are usually introduced earlier and driven by corresponding tests. Consts introduced during the refactoring phase are very unlikely to change and often represent values that have no (or should have no) use outside of scope they were defined within. Those can represent some well-known constants (like PI number approximation or default file permissions), may help in mapping enums returned from external API and so on. Most of the time, introducing such consts is either a result of DRYing up a code by removing duplicate values that represent the same thing or making values more meaningful by giving them names (in form of consts). As those consts are neither dedicated to control code execution nor for sharing, I prefer to mark them as private.

Internal classes (yes, classes are consts as well)

When refactoring a code, many times we extract it to a private interface. This code is not meant to be used outside of class scope as it might be a subject for frequent changes or removal — private interface should only be used indirectly by means of the public one. That is clear for methods, but it should be as clear for classes. When extracting a class we need to decide if it is allowed to be used outside of the scope we refactor — in many situations it should not, as such use would only introduce strong coupling we were not after at the beginning. By marking such class as private constant we can clearly state, that one should not use it directly.

Summary

To sum up — if a const was introduced only as an effect of refactoring, it does not represent any value usable outside of scope it was defined within and does not control the execution of any particular algorithm as configuration const, we should indicate that by classifying it as private. The same applies to classes or subclasses that act only as internal utility classes.

As mentioned in the title, this is only an opinion concerning the use of private_constant and it may or may not apply to your context / environment. This being said, I think using private_constant consciously in many circumstances can prevent tight-coupling, makes code more expressive and easier to change or refactor along the way.

--

--

Błażej Kosmowski

CTO, Leadership and Communication consultant, EPC Coach. Former CEO, project manager and software developer.