ITKarma picture


The proper naming of variables, functions, methods, and classes is one of the most important features of elegant and clean code. A code that clearly and clearly conveys the intentions of the programmer and does not tolerate assumptions about what was meant.


In this article we will talk about the code, which is the exact opposite of the one described above - about code that was written in a hurry to write, irresponsibly and thoughtlessly. This article is a small confession, because I, like any other programmer, have also written such code. This is nothing terrible as long as we understand that this is bad and we need to work on it.


In order not to leave those who expect a deeper analysis, disappointed, I will leave at the end of the article a list of literature that will be useful to read in order to understand the importance of this topic and dive deeper into its study, but already relying on sources written by such professionals that we all strive to become.


We will not delay and, perhaps, we will begin.


Variables


One of the most annoying kinds of variables is variables that give a false impression of the nature of the data they store. These are scam variables.


The library CDMY0CDMY is extremely popular among Python developers, and if you have ever looked for something related to CDMY1CDMY, you probably came across a similar code:


import requests req=requests.get('https://api.example.org/endpoint') req.json() 

Whenever I see this, I feel annoyed and not so much because of the abbreviated record, but because the name of the variable does not criminally correspond to what is stored in this variable.


When you make a request (CDMY2CDMY), then get a response (CDMY3CDMY), so reflect this in your code:


response=requests.get('https://api.example.org/endpoint') response.json() 

Not CDMY4CDMY, not CDMY5CDMY, not CDMY6CDMY, and certainly not CDMY7CDMY, namely CDMY8CDMY. CDMY9CDMY, CDMY10CDMY, CDMY11CDMY (I am completely silent about CDMY12CDMY) - these are all variables whose contents can be understood only by looking at their announcement, but why jump to the announcement when you can initially give a suitable name?


Let's look at another example, but now from Django:


users_list=User.objects.filter(age__gte=22) 

When you see somewhere in the CDMY13CDMY code, you quite rightly expect that you can do this:


users_list.append(User.objects.get(pk=3)) 

But no, you cannot do this, since CDMY14CDMY returns CDMY15CDMY, and CDMY16CDMY is far from CDMY17CDMY:


Traceback (most recent call last): #... #... AttributeError: 'QuerySet' object has no attribute 'append' 

If it is very important for you to indicate a suffix, then at least specify one that corresponds to reality:


users_queryset=User.objects.all() users_queryset.order_by('-age') 

If you really want to write exactly CDMY18CDMY, then please take care that the list really gets into the variable:


users_list=list(User.objects.all()) 

Binding a variable name to the type of data stored in it is often a bad idea, especially when working with dynamic languages. In cases when it is very necessary to note that the object is a container data type, it is enough to simply indicate the name of the variable in the plural:


users=User.objects.all() 

or, if you really don’t like it at all and you intend to use suffixes in any case, then it is better to add the suffix CDMY19CDMY (the lesser of evils) to note that this is a sequence:


users_seq=[1, 2, 3] # или users_seq=(1, 2, 3) # или users_seq={1, 2, 3} 

This way you will know that the sequence is stored in the variable and that it can be iterated over it, but you will not make assumptions about other properties and methods of the object.


Another kind of annoying variable is one with a short name.


Let's go back to CDMY20CDMY and look at this code:


s=requests.Session() #... #... s.close() 

This is a prime example of a completely unjustified abbreviation for a variable name. This is a terrible practice, and its horrors become even more apparent when such code takes up more than 10-15 lines of code.


Specifically, in the case of CDMY21CDMY gritting your teeth, you can forgive such a reduction, when the code takes no more than 5-10 lines and is written like this:


with requests.Session() as s: #... #... s.get('https://api.example.org/endpoint') 

Here, the context manager allows you to additionally select an ambient block for the variable CDMY22CDMY.


But it’s much better to write it as it is, namely:


session=requests.Session() #... #... session.get('https://api.example.org/endpoint') #... #... session.close() 

or


with requests.Session() as session: session.get('https://api.example.org/endpoint') 

You may argue that this is a more verbose option, but I will answer you that it pays off when you read the code and immediately understand that CDMY23CDMY is CDMY24CDMY. Do you understand this by the variable CDMY25CDMY without looking at its definition?


Let's look at another example:


info_dict={'name': 'Isaak', 'age': 25} #... #... info_dict=list(info_dict) #... #... 

You see CDMY26CDMY and you might want to do this:


for key, value in info_dict.items(): print(key, value) 

But instead, get an error, because you were misled, and you will understand this only if you go to the ad and read the entire code from top to bottom, right down to the section from which you started the jump to the ad — such is the price of such variables.


Thus, when you specify the type of data stored in the variable name, you essentially guarantee that this variable must contain the specified data type at any time during the execution of the program. Why should we take this responsibility if it is the direct responsibility of the interpreter or compiler? It’s better to spend time thinking of a good variable name than trying to figure out why variables do not behave as you expect.


In the above example, the choice of a variable is rather unsuccessful, and you could give a name that more accurately expresses the context (you don’t have to be afraid to use names related to the subject area), but even in this case, you could make this code better:


info_dict={'name': 'Isaak', 'age': 25} #... #... info_keys=list(info_dict) #... #... 

or even so, which is more idiomatic:


info_dict={'name': 'Isaak', 'age': 25} #... #... info_keys=info_dict.keys() #... #... 

Comments-caps


Comments are something that can both ruin your code and make it better. A good comment takes time to think and write, and therefore most often we all come across disgusting comments that are nothing but visual garbage.


Take a small example from JavaScript:


//Remove first five letters const errorCode=errorText.substr(5) 

The first thing that flashes in your head when you see this is "Thank you, cap!". Why describe what is already clear without comment? Why duplicate the information that the code already tells us? This distinguishes a good comment from a bad one - a good comment makes you feel grateful to the person who wrote it, and a bad comment only annoys you.


Let's try to make this comment useful:


//Remove "net::" from error text const errorCode=errorText.substr(5) 

Better yet, take a more declarative approach and get rid of the comment at all:


const errorCode=errorText.replace('net::', '') 

Speaking of comments, one can't help but mention the dead code. The dead code is perhaps more annoying than useless comments, since you also have to figure out if the code was commented out temporarily (to debug some parts of the system) or did the developer just forget to delete it?


Be that as it may, the dead code has no place in the modules and it must be deleted! If it suddenly turns out that this was something important, then you can simply roll back to the correct version (unless, of course, you are an Amish programmer that does not use the version control system).


Methods


Smart naming of functions and methods is something that comes only with experience in designing an API, and therefore you can often find cases where methods do not behave as we expect.


Consider an example with a method:


>>> person=Person() >>> person.has_publications() ['Post 1', 'Post 2', 'Post 3'] 

In the code, we expressed a very clear question: "Does this person have publications?", but what kind of answer did we get?


We did not ask what kind of person has publications.The name of this method implies that the return value must be of Boolean type, namely CDMY27CDMY or CDMY28CDMY:


>>> person=Person() >>> person.has_publications() True 

And to get posts you can use a more appropriate name:


>>> person.get_publications() ['Post 1', 'Post 2', 'Post 3'] 

or


>>> person.publications() ['Post 1', 'Post 2', 'Post 3'] 

We often like to call programming a creative activity, and it really is. However, if you write code that only you can read, and then justify it with “creativity”, then I have bad news for you.


References for studying the issue


As promised, I leave a list of outstanding relevant literature written by well-known professionals in the field. Most of the books below have been translated into Russian.


  1. Robert Martin - Clean Code
  2. Robert Martin - Clean Architecture
  3. Robert Martin - The Clean Coder: A Code of Conduct for Professional Programmers
  4. Martin Fowler - Refactoring: Improving the Design of Existing Code
  5. Colin J. Neill - Antipatterns: Managing Software Organizations and People
.

Source