1. Introduction
In this tutorial, we’re going to take a look into naming. Naming is a crucial and daily task for developers in any programming language. It can either make code very hard to understand or if done well, easy to comprehend. Every detail of code that we write has a name, the functions, classes, variables, etc. Let’s start by looking deeper into the goals of naming. After that, we’ll explore some dos and don’ts.
2. Goal
Names are mainly used by developers. These names could be internal, but also part of an API. In that case, the audience is even broader. Also note that for any commercial project, even the internal developers are likely to include a broad range of individuals during the lifetime of the software.
There could be a huge variance in seniority but also a difference in cultural background. We should always keep that in mind while picking new names.
We use names to aid the code to tell its story. When we leave out relevant names, it becomes hard to tell what the following piece of code is actually doing:
function applies(e: Evnt) {
if (e.d == 6 || e.d == 0) {
return false;
} else {
return (e.t.h >= 8 && e.t.h < 18);
}
}
Without taking too much time, we see what the code does, but why does it do it? What does it mean? Let’s now take a look at the same fragment of code. However, this example has better names:
function isDuringWorkingHours(event: Event) {
if (event.dayOfWeek == DayOfWeek.SATURDAY || event.dayOfWeek == DayOfWeek.SUNDAY) {
return false;
} else {
return (event.time.hour >= WORKING_DAY_START && event.time.hour < WORKING_DAY_END);
}
}
Let’s go over the changes we made. First, we started by giving the method a more explanatory name. Secondly, we replaced the field d, which could mean everything to the more distinctive term dayOfWeek. Next, we extracted constants representing the day of the week. Finally, we made similar changes at line 5.
Looking back at this example, we can see that proper names help us to understand the meaning of the code. In the next section, we’ll take a look at some best practices regarding naming.
3. Aim
Names must be clear and understandable. We should also focus on the principle of least surprise. Thus, we aim to create the code which other people would expect and try not to surprise them. In that way, the next person might easily guess where things can be found and what they mean.
We already discussed that the names we choose are targeted towards developers. Consequently, this means that we can safely assume that others also have an idea of what a Singleton is or what the Visitor pattern is. Therefore we generally prefer to use concepts from the solution domain when they apply. This will make communication much easier.
If no clear and distinctive names exist in our own domain, the second-best is to use the business domain. So instead of making up a name for a process, use an existing one from the business. This improves both the communication between developers, but also between developers and the business.
3.1. Searchable
Like we already showed in the section about goals using very short names will hurt the readability of our code. Another drawback is that short names are harder to search for in the code. The same holds for the use of constants.
Consider when we’d need to update the code from the previous section, to include Saturday as a working day. In the example where we can search for SATURDAY, it’ll give us less false positives. Or, using an IDE, we’d even inspect usages for the SATURDAY constant.
3.2. One Thing – One Word
Make sure to re-use the same terms when referring to the same thing/action. So when choosing for the name address for one field, that same name should be used for the same concept in the whole application. The same holds for methods. For example, when we’re adding elements to different kinds of objects and it’s the same operation, then we’d make sure to use the same name consistently.
However, this doesn’t mean that name is set in stone. Whenever we find a better matching name which can be consequently applied, that could be a moment to refactor.
Note that, however, when two things aren’t completely the same, we should make sure to distinct them properly with their own names.
3.3. Pronounceable
Naming is all about communication. Consequently, it is likely that we’ve to pronounce the names we choose. This could be because of mentoring someone, a code review, or because we’re tracing a nasty bug.
However, if during that moment we can’t communicate because of the name we choose, we failed to do our job. So always aim to use names which we can communicate about.
3.4. Follow Naming Standards
Finally, there are some generally accepted standards. First, we should use nouns for class names, e.g., Car or Duck. On the other hand, for methods, we should use verbs or verb phrases, because in a lot of cases, a single verb won’t be sufficient to express to ourselves. Examples of that are applyRegulations or calculateTaxes.
4. Avoid
In the previous section, we suggested some things we aim for. In this section, we’ll focus on some practices which we rather avoid.
4.1. Disinformation
Disinformation comes in many flavors, mostly non-intentional. For example, as a consequence of minor refactorings, our code might end up providing disinformation.
See, for example, the following fragment:
Set<Address> addressList = person.getAddresses();
While the name of the variable above contains List, it is actually a Set. For people from different language backgrounds, the consequence is that duplicate entries will be ignored, so some add operations won’t perform what we expect purely based on the name. In this case, it might make the most sense to leave out the word List and just call it addresses.
Other forms of disinformation could be noise words in variables. Words like data, processor, table, information are so commonly used that they don’t provide useful distinctions because most methods or variables have something to do with information or the processing of it.
4.2. Avoid Encodings
Earlier programming languages or their best-practices required hints about exact types. However, programming languages now a day don’t require those type hints. So let’s leave them out because our compiler/IDE will take care of this for us. It also commonly happens that types are refactored later on, so it would be a pity when our code propagates misinformation, like the following fragment:
ZipCode zipCodeString = new ZipCode("1974XA")
Other encodings could include specific names for variables or similar encodings. Whenever this isn’t required or common practice in the language, we’d advise against it. In that case, we’d always advise keeping the name neutral and functional.
4.3. Slang
Aim to be as clear as possible without requiring too much additional context. Especially using slang or jokes won’t benefit us in the long run. A buttonSmashHandler might be fun the first time we see it, but we’d be better off just calling it a buttonClickHandler.
4.4. Avoid Mental Mapping
We aim not to surprise readers of our code. This means that single-letter variables are allowed but only in specific places. So it wouldn’t surprise anyone to use i or j for a loop-variable. However, we better not use those names in other contexts.
We already explained that we prefer to use names from the solution domain, i.e., our software domain. However, this means that we should be careful when using names or acronyms which also have a different meaning. So better reconsider calling an object a Visitor when we’re modeling a user who’s a customer. This also applies to acronyms, when we’d use id to refer to the inside diameter, we’ll confuse a lot of developers.
4.5. One Word – One Thing
We already emphasized the importance of using the same word for things that are the same. However, the opposite might even be more important. Don’t use the same word when we aren’t referring to the same concept. So when an application would be matching wooden matches, we might spend some extra time to make it extra clear when we’re talking about the process of matching, a successful match, and a wooden match.
A more common scenario is when a lot of methods already have an add method. When we also append an item here but with different characteristics, e.g., adding on a specific location or potentially replacing or overwriting existing data. Then, it’s crucial to make it clear that it is another operation, and it must have its own name.
4.6. Names Shouldn’t Need Comments
As already addressed in our article on comments, names shouldn’t need comments. Instead, they should be used to eliminate the need for a comment. Let’s compare the following two lines of code, one with a comment and the other one with an improved name:
int timeout = 5; // timeout in seconds
When we end up adding trivial comments, always spend a minute reflecting on alternatives for adding it.
4.7. Be Cautious With Acronyms
As already mentioned before, we should be careful when using acronyms as names. Not only can they have different meanings. Moreover, they could make our code harder to understand for people with a different primary language or different cultural background. Therefore, only use acronyms when they’re very common, and the alternative would be inadequate. But in general, prefer to just spell out the acronym.
5. Conclusion
In this article, we looked at some best practices for naming and some practices you should rather avoid. We’ve seen that naming isn’t only a big part of our daily job but also a very important task, it can make code average or good.