How to name things in code

How to name things in code

I was looking for an article to recommend to my junior colleagues about naming things and I found a lot of great ones, but I couldn't decide which was the most suitable.

No one contained all and only the things I consider important, so I decided to write my own.

"There are only two hard things in Computer Science: cache invalidation and naming things."

— Phil Karlton

As developers, we are constantly rushing to meet deadlines, there are always a lot of features to add and bugs to fix, and our clients are impatient.

In such a hurry it is easy to overlook code quality to get things done in the illusion of saving time. As a result, the code grows in a messy way, and the complexity increases. Choosing good names could help us to deal with and reduce this complexity.

Have you ever thought that the names of variables, classes, and functions are a major part of programs’ source code? They serve as implicit documentation and are essential for program comprehension.

And have you ever thought also that code obfuscation is a technique used to protect intellectual property to prevent an attacker from reverse engineering code, and bad code is in some way a code that has been unconsciously obfuscated?

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."

— Martin Fowler

Writing code is a lot easier than reading code

Drawings by @tina_pep3

It’s proven that we spend more time reading code than we do writing it, so you can be sure that good naming, even if takes time and effort, will pay off in the future.

I can’t count how many hours took me to understand badly written code. When I'm facing this type of code, my approach consists in renaming things up as my understanding grows, so in a number of little interactions, gradually the whole meaning becomes clear.

Using good names makes your code better and cleaner. It helps you to intuitively identify what are the responsibilities of each part of the code. It makes your application easier to read in the future by other developers, as well as by yourself.

You actually get to map human language with machine language, but more importantly, you are also expressing even the most difficult concepts or ideas by telling a story.

// self-driving car
if(isGoingToCrash()) {
  dont();
}

It is just a joke but it's true in a way.

And now that we know the value of good names, I will give you some practical advice to improve your “naming skills”.

It's not easy, it's almost an art, but, as we do in art, we can say that practice makes perfect. You can start with small improvements and then move on to more complex ones.

Soon it'll become a habit, and it'll almost annoy you to see poorly chosen names, often a red flag for bad software design, or “selfish coding”.

At this point, you could absolutely define yourself as a naming ninja.

All the examples are written in Java, but the advice is still valid regardless of the language you use.

Let's start!

Use nouns for variables and class names

Classes are a blueprint for creating objects, variables hold primitive data or objects, classes, and variables aren't actions (classes delegate action to methods) so their name should be a noun.

Bad

class OrderOrchestrate

Good

class OrderOrchestrator

Use verbs or verb+noun for functions and class methods

When you create a function, you are doing something in that function. It could be updating a variable value, fetching some data, saving some data, etc. Whatever it is, it’s an action, name it with a verb.

Bad

public void orderApproval(Order order)

Good

public void approveOrder(Order order)

Use singular names for classes

A class is a blueprint for creating instances of an object, the code is more readable if you use singular.

Bad

var user = new Users();

Good

var user = new User();

Case matters

In programming we can't use spaces when dealing with names that have more than one word, but we can use cases.

Some of the most famous are camelCase, kebab-case, and snake_case. It’s a good idea to discuss this with your team and choose one.

If the language has already a naming convention then use it; when new developers will join the project it is likely they will already be familiar with the convention

Stick to a case, don’t mix up cases. What you can do is use one case, let’s say kebab-case, for naming files, upper CamelCase for classes, and camelCase for variables and functions, but don’t name some variables in one case and others in another case.

You can use linters for automatically identifying out-of-standard names.

Consistency over choosing the perfect convention

If you are in a position to change or influence the syntax rules you are using so that they are more consistent or saner, do it.

Otherwise, deal with it and write your code so that it looks like all the other code in the project. A codebase should be written in a single, consistent style, no matter what (or how stupid) it is.

Avoid not pronounceable names

If you use a name that is difficult to pronounce nobody will use it when speaking.

Avoid using abbreviations, acronyms, or neologisms

There is no guarantee of whether another programmer will understand what a particular abbreviation means.

Bad

var at = session.getAT();

What does AT stand for? Is impossible to guess unless you're intimately familiar with this code base already.

Instead, get rid of the abbreviation and write out the words that the abbreviation is hiding:

Good

var accessToken = session.getAccessToken();

Now we have a much better grasp on what is going on here, and we don't need to go digging further into the code to understand what information this variable holds.

It's ok to use abbreviations only if the scope is very small and the meaning is obvious.

Good

for(var u : users){  
  doSomething(u); 
}

Be professional

Avoid mySomething, tmpSomething, those prefixes are meaningless.

Or worse: using stupid or bad words... no comment, please don't.

Choose the right human language

Use English as the first choice, use another language only if the terminology is specific to a country and has no simple translation in English (e.g.: laws).

Check spelling

The name should be in correct English (or other languages). Modern IDE's highlights typos for you.

Name booleans positively

Sometimes, we use booleans to represent the state of an action. For example isValid, isEnabled, and so on. It’s always better to name booleans positively. Whenever you want the inverse of it, you use can use the negation operator.

Instead, if you name the boolean negatively then the positive looks weird:

Bad

!isNotCompleted

Prefer active voice

In a sentence written using active voice, the thing doing the action is the subject of that sentence. Active voice shows that an action is being done by an object.

Bad

public void setApproved()

Good

public void approve()

No magic numbers

Avoid using numbers without a meaning, use constants and enums to provide semantics and self-documentation.

Bad

if (order.getStatus() == 3)

Good

if (OrderStatus.CLOSED.equals(order.getStatus())

Avoid including type as a prefix

Also known as don't use Hungarian Notation.

Adding a type or prefix of any kind (especially if it is abbreviated) generally increases the length of the name without also imparting additional meaning. In many languages (and IDEs, and environments, and so on) the type will be obvious from the usage or declaration, and the IDE helps you to go quickly to the declaration, so including type in our names is just extra noise we must mentally filter out.

Avoid comments after names

If a name requires a comment, it's a sign that the name does not reveal its intent.

Each thing has only one name

Choose a name and use the same name in whole the codebase.

If you choose Permission don't call it Right or Authorization.

This rule also applies to verbs. If you choose 'search' as the prefix for methods that search entities in the database then use it in whole the codebase.

Bad

List<Order> findOrders(OrderSearchParams params);
List<Customer> fetchCustomers(CustomerSearchParams params);
List<Product> searchProducts(ProductSearchParams params);

Good

List<Order> searchOrders(OrderSearchParams params);
List<Customer> searchCustomers(CustomerSearchParams params);
List<Product> searchProducts(ProductSearchParams params);

It’s okay to use long names

Use descriptive names, it’s okay if they are long. A long and descriptive name is better than a short and meaningless name.

Let’s say you named a variable a, and after some 3 months you revisit that code and you see a. Now, you are looking at it and thinking what the hell is a.

If you would have named it better, for example, 'availableItems' then looking at the code, you will have an idea of what is going on just by the name.

Avoid technical details

As a general rule, remove from names technical details that don't add meaning. For example avoid adding as a suffix the name of the pattern you use, unless this helps to communicate the roles different elements play.

Bad

var userList = searchUsers(params); // The word List doesn't add meaning
class OrderStatusEnum // The order status is an Enum, that's implicit
class LoggerSingleton // Singleton is the design pattern used to implement, don't communicate additional meaning
class GroupSqlRepository // SQL says how is implemented, not what the function does

Good

var users = searchUsers(params);
class OrderStatus
class Logger
class GroupRepository

Names should reveal intention. Be specific but concise.

We cannot convey the correct meaning without being specific.

Bad

class User {
  String name;
  ...
}

What kind of name is this? A first name, a last name, a full name, a username, or something else?

Good

class User {
  String fullName; 
  ...
}

Don't go overboard on being specific, though. There's no reason to include words that don't directly add meaning to the name, they're just noise.

Bad

class User {
  String loginAndDisplayUsername;
  ...
}

Well, that sure is specific. But username is not only used for login and display. The words 'login' and 'display' could be considered extra, so we could reduce the name down. Prefer short-and-descriptive rather than long-and-descriptive names.

Good

class User {
  String username;
  ...
}

Avoid ambiguity

Names help to understand the logic. They need to be distinguishable.

Bad

Double total = price * quantity;
Double total2 = total * taxRate;
Double total3 = accountCredit + couponValue;
if (total3 > total2) { // Completely unclear what we are comparing 
  processOrder();
}

Good

Double payableTotal = price * quantity * taxRate;
Double availableFunds = accountFunds + couponValue;
if (availableAmount > payableTotal) {  
  processOrder();
}

Try to find a precise name. Sometimes it requires some vocabulary research, but it’s an investment well worth.

Double total2 = 0;                // Very bad, don't do this.
Double amountTotal = 0;           // Mmmh.
Double orderTotalWithTax = 0;     // Eh, a bit too long.
Double payableTotal = 0;          // Yes, finally clear!

Assign to the variables the same name of the class as the first choice

Modern IDEs in most cases, when it is obvious, find the right name for you, you can simply accept the suggestion.

Bad

var grp = new Group();

Good

var group = new Group(); // IDE suggested 'group'

Naming is easier if you give things a single responsibility

Every module or class or variable should be responsible for only one thing. This is known as Single-responsibility principle, the term was introduced by Robert C. Martin in his article The Principles of OOD as part of his Principles of Object Oriented Design. It’s simply easier to name an element that has only one function.

One of the techniques that help to build a better architecture is splitting every part of your task into small pieces.

Let’s say that we have to describe a car. It’s difficult to name every functionality in one class, but if we split it into many smaller pieces, it turns out, that we can make steering wheel, tire, engine,... These smaller components are easy to name and their purposes are easy to specify.

If you’re having a hard time naming a class, check if it’s not hiding some kind of code smell: the class may lack cohesion (it might be doing unrelated things or doing too much).

Bad

class RequestManager

The name above is just a way to ignore the challenges of selecting a descriptive name. No one really understands what is inside this class. Avoid these names, and arrange your code better.

Good

class OrderController;
class OrderService;
class OrderRepository;
...

Reducing scope provides meaning

When the scope (visibility) of something is higher than needed, the reader is forced to think about where it might be used and may even be afraid to change the code.

Define variables as close as possible to where they’re needed, naming is easier if the scope is small. If the variable is used only once, consider inlining it — unless its existence is acting as documentation itself.

Bad

@Service
class Maintenance {
  List<User> inactiveUsersForSendingReminder = new ArrayList<User>(); 
  // what is the meaning of inactive? where is used? Could I change it?
  @Autowired
  private UserRepository userRepository;
public void doMonthlyMaintenance() {
sendReminderToInactiveUsers();
...
}
private void sendReminderToInactiveUsers() {
inactiveUsersForSendingReminder = userRepository.findUsersWithLastLoginBefore(...);
sendReminderToInactiveUsers();
}
private void sendReminderToInactiveUsers() {
for(var user : inactiveUsersForSendingReminder){
// send reminder
}
}
}

Good

@Service
class Maintenance {
@Autowired
private UserRepository userRepository;
public void doMonthlyMaintenance() {
sendReminderToInactiveUsers();
...
}
private void sendReminderToInactiveUsers() {
List<User> inactiveUsers = userRepository.findUsersWithLastLoginBefore(...);
// now inactive users scope is limited to this function, the name is smaller
// and is clear that inactive means last login before a given date...
sendReminder(inactiveUsers);
}
private void sendReminder(List<User> users) {
// This function is more reusable, can send a reminder to a generic list of user
// The name of the function is smaller
for(var user : users){
// send reminder
}
}
}

Use variables to avoid repetitions

Use variables with meaningful names to avoid repetitions, and the code becomes more concise and readable.

Bad

if (request.getUser().getAuth().getPermissions().contains(Permission.READ)){
}
if (request.getUser().getAuth().getPermissions().contains(Permission.WRITE)){
}

Good

var userPermissions = request.getUser().getAuth().getPermissions();
if (userPermissions.contains(Permission.READ)){
}
if (userPermissions.contains(Permission.WRITE)){
}

Don’t mix levels of abstraction

Good names reduce the need for extensive comments and documentation. Most of the code comments within functions could be turned into private functions.

If you have to spend effort looking at a fragment of code to figure out what it’s doing, then you should extract it into a function and name the function after that “what”. That way when you read it again, the purpose of the function leaps right out at you, and most of the time you won’t need to care about how the function fulfills its purpose, which is the body of the function.

This is known as the principle of the single level of abstraction, which tells us to not mix different levels of abstraction in the same function.

Bad

void withdraw(accountNumber,amount) {
  // Get account by account number
  Connection conn = null;
  try {
    conn = DBUtils.getConnection();
    PreparedStatement pstmt = conn.prepareStatement("Select * from accounts where account_number = ?");
    pstmt.setString(1, source.getAccountNumber());
    ResultSet rs = pstmt.executeQuery();
    Account sourceAccount = null;
    if(rs.next()) {
     sourceAccount = new Account();
     // populate account properties from ResultSet
  }
  ....
account.withdraw(amount);
}

This approach is full of technical details and resorts to comments to explain what is going on.

Good

Account getAccountByNumber(String accountNumber) {
  Connection conn = null;
  try {
    conn = DBUtils.getConnection();
    PreparedStatement pstmt = conn.prepareStatement("Select * from accounts where account_number = ?");
    pstmt.setString(1, accountNumber);
    ResultSet rs = pstmt.executeQuery();
    Account sourceAccount = null;
    if(rs.next()) {
      sourceAccount = new Account();
    //populate account properties from ResultSet
   }
   ....
}
void withdraw(accountNumber,amount) {
Account acount = getAccountByNumber(accountNumber);
account.withdraw(amount);
}

This approach makes the intent clear by separating the what (intent/purpose) from the how (implementation details).

Delegating details to functions creates a high-level language that is closer to the spoken language. You can scan the code reading “do this, then do that, finally that…” without having to grasp the implementation details at the same time.

As a general rule, whenever you feel like writing a comment, ask if you could express it in the names of variables, functions, or classes.

Ubiquitous language

The ubiquitous language, a term from domain-driven design (Eric Evans), is a vocabulary shared by everyone involved in a project, from domain experts to stakeholders, to project managers, to developers. This language should be used in documentation, conversations, tickets, meeting invites, and code, including names of files, folders, classes, functions, and variables. The goal is to reduce the ambiguity of communication. Refactoring should be done to reflect changes in the ubiquitous language that occurs every time the team's understanding of the domain grows.

Little duck grows

If your model grows and you realize that a name is no more suitable because it has become ambiguous or you have a better understanding of the concept, find a better name and change it in the whole codebase.

Conclusions

Those are the rules that I follow in my daily work and they work fine for me.

Did you find them helpful or do you use other rules? Please, let me know your feedback by leaving a comment.

Quack.

Drawings by @tina_pep3

Those are the articles where I started from:

https://exceptionnotfound.net/ten-commandments-for-naming-your-code/

https://hilton.org.uk/presentations/naming

https://levelup.gitconnected.com/a-guide-for-naming-things-in-programming-2dc2d74879f8#:~:text=Use%20singular%20names,might%20sound%20a%20bit%20weird.

https://medium.com/codex/towards-self-documenting-code-371364bdccbb

https://medium.com/wix-engineering/naming-convention-8-basic-rules-for-any-piece-of-code-c4c5f65b0c09

https://nickjanetakis.com/blog/2-ways-to-name-things-better-in-programming

https://javascript.plainenglish.io/the-ultimate-guide-to-writing-self-documenting-code-998ea9a38bd3

https://www.codementor.io/@tanakamutakwa/writing-clean-code-naming-1msxn728ht

https://www.elpassion.com/blog/naming-101-programmers-guide-on-how-to-name-things

https://www.namingthings.co/

Did you find this article valuable?

Support Claudia Chersin by becoming a sponsor. Any amount is appreciated!