Welcome to the first part of the clean code series. This series will be highly inspired by and sometimes embarrassingly copied from the Clean Code book by Robert C. Martin (Uncle Bob). I highly recommend reading the book. This series is nowhere near to the original book.
The book has a lot of code examples, and most of them are provided in Java. I will not go through all the code examples, but if I do use some, I will translate or make examples using Python.
What Is Clean Code?
Clean code should have:
- Full test coverage
- Complete error handling
- No duplications
- High expressiveness
- A minimal number of entities such as class, function, methods, and …
- Performance close to optimal
- Minimal dependencies on third parties
Meaningful Names
Names are the smallest building block of code. Names are everywhere: Function, class, file, component, and container all have names. Names are also the basic building blocks of clean code. There are some hard and fast rules to a good name.
Use intention-revealing names
A good name should answer only three questions.
I know it sounds simple, but it takes a lot of time to get a good name. However, it will save more than that in the long run.
A name should not have comments to express its intentions. Look at this example:
# Dirty Code d = 100 # elapsed time in days
# Clean Code elapsed_time_in_days = 100
In the first case, you need to go through the comment. That’s okay for one time. But whenever you use the variable d
, you will have to come to the initialization to get the intention of the variable. But the second case, elapsed_time_in_days
, is expressive on its own.
Don’t give your variable a one-letter name. One-letter names are never expressive. They fail to reveal their intention. There are some exceptions, like the letters i, j, and k in the for
loop. However, never use a small letter l (el), a capital letter I (eye), or a capital letter O (oh) as a name because programmers tend to confuse them with one and zero, respectively.
Avoid disinformation
Avoid names that are platform-specific, like htop
andhp
.
Don’t use names with small changes like dataset_generator_for_cat_with_user_mobile_1
and dataset_generator_for_cat_with_user_mobile_2
. In this case, you don’t get the difference until the last letter, and most of the time, you’ll ignore that difference.
Make meaningful distinctions
There should be enough distinctions in the variable naming. Don’t just append a number if you have a variable with the same name in the scope: a1
, a2
is the opposite of intention-revealing.
Don’t use names with similar meanings. For instance, product_data
and product_info
do not have a proper distinction. Just by looking at the name, you can’t assume the intentions of these two variables. These are called noise words. Some of the other noise words are a
, an
, and the
.
Don’t append variable type to the variable name. Make the variable name so expressive that you can understand the type uniquely by the name alone. For instance, account_name
can never be a floating-point number. It must and should be a string. There are some exceptions, like id
, which can be a string or a number. But then that convention should be followed all over the project so the programmer working on that project will know if the id
is a number, a string, or something else.
Use pronounceable names
If you can’t pronounce it, you can’t discuss it without sounding like an idiot.
Sometimes a short example is better than a lot of text:
# Poor Name gen_ymdhms = "1591442356268" # Generation year, month, date, hour, min, sec
# Good Name
genration_timestamp = "1591442356268"
Use searchable names
Avoid using one-letter names as much as possible. If you need to use a one-letter name, use it only within a local scope rather than over a global scope.
Avoid using common words like sum
, temp
, or flag
as they seem to be used by a lot of methods and classes and are thus not search-friendly names.
Avoid encodings
Avoid using encodings like Hungarian Notation or Member Prefixes. They were used before when the IDE was not as smart as it is now. Current IDEs are smart enough to give us suggestions about the type or the member variable of a class. We don’t want to clutter our brains with more information.
On the other hand, language-specific encodings should be maintained throughout the project, such as snake_case in Python and camel case in JavaScript.
Avoid mental mapping
Programmers indeed are really smart. But code is not a place to show off your smartness. You can obviously remember that r
is the variable name for a URL with the host and scheme removed. But the person who will be reading your code would not know that mental mapping. Use names that properly express the intention of the variable.
Class name
Class name should be a noun or noun phrase. By design, classes are an encapsulation of the same type methods and variables, thus they should have a common name. Classes should not be a verb in any way.
Function/method name
Functions should be a verb or verb phrase. By design, a function should have only one responsibility. If the name is anything other than a verb, then either you are naming it wrong or there are some problems in the architecture.
Pick one word per concept
Avoid using different but similar words to define the same concepts. For instance, don’t use fetch
, get
and retrieve
in the same project for the same responsibility.
Don’t use the same word for different concepts
Avoid using the same word for totally different concepts. When you are intending to follow the previous rule, you will end up with a lot of variables with the same name. Perhaps add
is used throughout the project to add or concatenate two existing values. But if we use it to append a new value to an existing variable, it would be confusing. append
seems a more reasonable name for this method.
Use solution domain names
Your code will be read and maintained by programmers, so it’s okay to use solution domain names. For example, in the machine learning context, data_generator
is a good name. Whoever sees this name will know that it’s a data generator that is an iterator to loop on.
Use problem domain names
If there are no solution domain names available, then use a domain-specific name. In that case, the programmer can ask a domain expert about the meaning.
Add meaningful context
As a programmer, our first duty is to choose names that are as expressive as they can be. But sometimes it’s not possible to give context with a variable name. In that case, first try to enclose the variables in a meaningful class or function. For example, name
, city
, and district
should be enclosed in a class name Address
. If that’s not possible at all, prefix the variable with the name of the context. But remember, that is a last resort, so use it after meticulous thinking.
I know that’s a lot of dos and don’ts for a simple thing. But trust me, this is the toughest problem I’ve faced in my small software engineering career.