13 June 2020
Naming things is easy. Abstraction is much harder.
One of the more pervasive myths in software development is that naming things is hard. This is summed up by an often-quoted and much riffed-on quip originally credited to Phil Karlton, i.e. "There are only two hard things in Computer Science: cache invalidation and naming things."
This has had the (unintended) effect of encouraging teams to regard naming as an arcane puzzle that can only be unlocked through hours of tortured analysis.
Naming things does not have to be that hard.
Naming is a function of the quality of your abstractions. If you have well defined responsibilities and neatly separated concerns, the naming of things tends to fall out naturally. In this sense, naming is a litmus test. If you are struggling to figure out what to call things, then your underlying abstractions may need sharpening.
Time spent on trying to label indistinct items is time wasted. Naming has developed a reputation for difficulty mainly because a lot of time has been wasted in the losing game of debating how to name fuzzy objects.
Common naming smells
There are number of smells that can creep into naming. Developers are not always the most linguistically creative people, but the quality of the underlying design is usually the root cause. For example, long names imply that you have too many responsibilities in scope. Excessive commenting may be a sign that the naming isn't clear enough to stand on its own.
Fuzzy abstractions often lead to the use of vague nouns. You can often fine things called "SomethingManager" or "SomethingHelper" popping up in monolithic Java or .Net apps where the code has solidified into murky layers. These “generic buckets off stuff” have vague associations that encourage the creation of dumping grounds for stray logic and poorly designed responsibilities.
Variable names are often the scene of many naming crimes. It can be easy to settle into meaningless names that lack precision. The tens of millions of instances of "foo" on GitHub show how often developers succumb to this. Abstract names such as "data" and "object" are not much more meaningful, neither is appending a number onto something – i.e. "Product2".
You should ensure a direct association between a name and what the item does. If you need to decode or map it in any way, then the naming is not doing its job. You have created indirection that adds overhead to understanding the context.
Keeping names in check over time can be difficult. Responsibilities tend to evolve over time, new features get bolted on and you can find that a name no longer reflects the current reality. This kind of naming drift is technical debt in a true sense as it illustrates how the design of a system has failed to keep up with our understanding of the requirements.
Falling back on acronyms is particularly dangerous. Acronyms may provide brevity, but they are an indistinct way of communicating. They clutter text, hinder reading flow and can be cumbersome to pronounce. More importantly, acronyms tend to give rise to a cold and impersonal language where everyday speech is peppered with technical terms. This style of language is impenetrable to outsiders or newcomers who will need a glossary to understand any concepts.
If you need overtly technical language to describe a system, it implies either contrived complexity or a lack of genuine understanding. Remember that names are first and foremost assigned for the benefit of other people.
Mind your (ubiquitous) language
Eric Evan’s used the term "ubiquitous language" to describe the practice of building up a common language that can be shared between developers and users. This was described in the context of Domain Driven Design, a technique that manages complexity by dividing domains into self-contained “bounded contexts”, each with their own, separate internal language.
This bakes in the idea that you cannot find a meaningful and consistent language to describe the entire domain. Splitting it up into smaller abstractions allows you to establish clearer abstractions and therefore more meaningful names for things.
It is slightly ironic that a term that is meant to convey clarity needs careful explanation, but the idea is a valuable one. Building up a ubiquitous language should be an on-going collaborative effort within a clearly defined scope.
Names should be grounded in terms that are widely understood by everybody. You should be able to build a simple glossary that can be integrated into the daily rhythm of development. This can help to set the tone in terms of embracing simplicity and establishing inclusive language.