It’s proven that we spend more time reading code than we do writing it, so you can be sure that good naming will pay off in the future.
One of the most common problems of developers is naming. I can’t count, how many hours I’ve spent thinking how to name things and how many hours it took me to understand code containing bad names. It doesn’t matter if it was an object, method, class or anything else. It’s proven that we spend more time reading code than we do writing it, so good naming always pays off in the future.
Using good names makes your code better and cleaner. It helps you to intuitively identify what are the responsibilities of each part of code. It makes your application easy to read in the future by other developers, as well as by yourself.
In next few minutes I‘d like to explain the importance of good naming and share some useful tips for finding good names.
Level of Abstraction
Methods and variables should be named after what they mean. Before giving a name, consider what is the responsibility of that piece of code.
Let’s consider the case with method returning string with the distance between Warsaw and Paris.
It’s simple and seems to work right, but what if we change the requirements a little bit? Now I want to have the possibility to show the sentence in two different ways: in kilometers and miles. To do that I need to introduce a variable to the class. This variable will be used to replace word km in to_s method.
The new variable should be named at one level of abstraction higher than its values. It means that we need to think about the purpose of the variable first. It will help us to give it a more general name, which shouldn’t be too fuzzy at the same time. Summing up this point, the name needs to suggest the purpose of the variable, but not its possible values.
So what is the responsibility of our new variable? It’s supposed to introduce km or mi words to the object. So the name could be: kilometers_or_miles, but this is exactly the same level of abstraction that its values. If we wanted to add the possibility of using other unit (for example days), the name kilometers_or_miles would be wrong. We should consider something more general. Kilometers and miles are units of measure, so good name would be unit. It’s at one level of abstraction higher (more general), than the variable’s responsibility. Therefore the new class implementation looks as below:
The second thing is that the distance between Warsaw and Paris is 1591 kilometers indeed, but it’s 988 miles as well. So it’s time to implement a method returning the right value. The rule is the same as with the unit variable. Let’s think about the meaning first. The new method is expected to return values 1591 or 988 representing the distance between Warsaw and Paris. It doesn’t matter how the method will do its job. We could name it distance_warsaw_paris, but it’s on the same level of abstraction as the returned value. It means that the name of the method suggests possible returned values. This way of naming is too detailed.
In the future, the cities can be changed to others, for example: New York and London. Therefore the name distance_warsaw_paris will become deprecated and changing it in every place will result in high costs. The best solution is to name it distance. It‘s exactly what we wanted — one level of abstraction higher than body of method.
After this procedure our two methods look as below:
Level of Abstraction And Class Names
Methods and variables should be named at one level of abstraction higher than its body, but naming classes is a different story. When creating a class, we don’t have to anticipate the future. The name of a class should be based on its contemporary assumptions. We don’t expect a car to acquire features of a boat. Therefore, if current app requirements state that there is a need for a car, the class name should be Car instead of Vehicle.
Child classes should be named in the same way. Having the Car class we can add a more specific version, for example CarPickup for a special type of Car that has bigger loading space.
This implies that the rule of naming things at one level of abstraction higher than its content concerns is applicable to methods and variables, but not to classes.
Single Responsibility Principle
One of the SOLID principles says, that every module or a class should be responsible for only one thing. It’s simply easier to name an element that has only one function.
For example, the only responsibility of a bottle is being a container for a liquids. We shouldn’t give a bottle module the possibility to move around or do any other things that are not a simple bottle’s responsibility (in the app). How would you name a container for liquids that can move?
It’s quite difficult and bottle is only a simple example. Instead of coming up with walking (and then possibly dancing, running and speaking) bottles, it’s better to use the single responsibility rule. Create one class for a liquids container, name it Bottle and another one for a moving bottle, name it BottleCarrier.
Single responsibility rule concerns variables too. Every variable should have only one responsibility, no matter if it’s a variable of a method, class or some other kind of variable. As with class naming it’s just easier to name variable that has only one responsibility.
Consider Domain As a Set Of Smaller Pieces
Good architecture is paired with good naming. It’s easier to name things, when you understand the problems they solve. One of the technics, that helps to build a better architecture, is splitting every part of your task into small pieces. It will make naming quicker and easier.
Just think about it, isn’t it better to give names to modules or objects, when you know what’s their purpose? 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 Wheel, Tire, steeringWheel classes together with other classes dedicated to all other pieces that a car may contain. These smaller components are easy to name and their purposes are easy to specify. That’s why, if your components are difficult to name, it may mean, that you have some troubles with app architecture.
Every good name given to a variable, method, object or class, will pay you off, sooner or later. In my article I showed some simple techniques that will help you in giving good names:
Go one level of abstraction higher than body (all except class names)
The name should describe the class’ responsibility
Respect single responsibility (one of the SOLID rules)
Divide problems into smaller pieces
Good naming doesn’t have to be difficult. It’s really worth it, to spend some time on naming things in the right way. Using the tips listed above, it will make that process faster.
This article was inspired by the book “99 Bottles of OOP”, written by Sandi Metz & Katrina Owen. I encourage you to read it. Besides how to name things, you will learn about good practices of code refactoring.