Spelling Mistakes In Clean Code By albro

Spelling Mistakes

In this section I'd like to examine some common naming mistakes. The first common mistake that developers make is that they choose names that are too descriptive and try to describe everything inside that variable. For example:

userWithNameAndAge = User('albro', 27)

Apart from the fact that choosing long names for variables makes the code heavier and also makes it crowded, the provided information (name and age) is clear without choosing such a name. The first argument (albro) is a name, and since it is the name of the User class, it is likely that the second argument is the age, so we have not helped the readability of the code. Imagine if the User class also took more arguments like "entertainment" and "access level" and "interests". In this case, the names of the variables will be too long.

I told you that the name of the variables should be descriptive and give us an overview of the content inside it, but this has a limit. The purpose of descriptive writing of variable names is to understand the role of that variable, not to provide a complete map of its contents. If developers want to understand the details of that object, they should go to the class definition and study it. The appropriate name for such an object will be user or newUser or loggedInUser and the like.

The second common mistake is that developers use strange acronyms or lesser-known terms. If you take a look at GitHub you will see that in some cases developers even use street terms and weird jokes for naming. For example, using product.diePlease or user.facePalm is wrong. Although these phrases are jokes and may be funny to you, if other developers read your code, they will have to spend more time identifying these properties and methods. Instead of these two names, we can use correct names such as product.remove and user.sendErrorMessage.

We have the same rule for abbreviated names. If your shorthand is clear to all developers, there's no problem using it. For example, everyone knows what REST is (even though it is an acronym), but if you made up the acronym yourself, you should avoid it. Consider the following two examples:

message(n)
ymdt = '20210121CET'

We don't know the meaning of letter n or the meaning of ymdt here so we have to take time to understand it. Probably, ymdt means something like Year Month Day Time, but it is not necessarily clear. The correct and better name for these values will be as follows:

message(newUser)
dataWithTimezone = '20210121CET'

In the next step, we have the issue of false information. Sometimes the names appear to be correct but convey the wrong information. Consider the following two examples:

userList = { u1: ... , u2: ... }
allAccounts = accounts.filter()

In the first example, we have named the variable userList, but this is wrong because we have an object, not a list! We know that in programming languages, list has a special meaning and it is the same as array (Arrray), so using the word list may mislead other developers. In the second example, we have chosen the name allAccounts, but this is also wrong. allAccounts means "all accounts" if we have called the filter method on the accounts and left some of them aside. In this way, we do not have "all the accounts", but we have some of them. Better names for these two examples are as follows:

userMap = { u1: ... , u2: ... }
filteredAccounts = accounts.filter()

I have used the name filteredAccounts here, which is a generic name. You can change this name based on the program you wrote. For example, on what basis do we filter the accounts in this code? If it is based on VIP users we can name the variable VIPAccounts or if it is based on users who have paid accounts we can choose the name paidAccounts.

The next problem is using names that are similar to each other. If you want to improve the quality and readability of your code, you should choose "distinguishable" names, that is, if someone looks at your code, he can distinguish between different variables or methods. For example, suppose you have a class called Analytics, which contains various methods for working with your website statistics. Using methods like the following methods has a fundamental problem:

analytics.getDailyData(day)
analytics.getDayData(day)
analytics.getRawDailyData(day)
analytics.getParsedDailyData(day)

These methods are not separable, that is, for someone who reads them for the first time, it is not at all clear which method to use, so we have to check the definitions of each method to find out which of these methods is suitable for work. is us Note that since the working field of these methods is the same, naturally any name you choose will be somewhat similar to other methods, but the problem is choosing a name that can be distinguished as much as possible.

Better names for this example are:

analytics.getDailyReport(day)
analytics.getDataForToday(day)
analytics.getRawDailyData(day)
analytics.getParsedDailyData(day)

The name getDailyReport stands for Get Daily Report, so we know we want to download a PDF file that contains our daily statistics report. The getDataForToday method is more obvious than getDayData because it obviously gives us today's information. By correcting these two names, the names getRawDailyData and getParsedDailyData are also automatically distinguished because they are not combined with a method like getDailyData and don't cause confusion.

The last common problem seen in user code is the lack of "coherence" in the source code. Suppose you want to define a method to get users. The name of this method can be getUsers or fetchUsers or retrieveUsers. All three names are completely readable and have no problems, but whichever you choose, you must use the same name throughout the source code. what does it mean? Pay attention to the following code:

database = Database()
database.get_users()
database.get_products()
database.fetch_products()

If we want to use get as the word "receive", we must use get in all the source code, but in the above code we have a get_products and then there is also a fetch_products. What is the difference between the two? Is there a particular difference between get and fetch in your program or do both methods do almost the same thing?

Solve the exercise!

Now that we are familiar with the theoretical issues in this post, it is time to solve the exercise. I will solve the first exercise for you, but try to solve the exercises after that by yourself. Pay attention to the Python code below:

from datetime import datetime






class Entity:
def __init__(self, title, description, ymdhm):
self.title = title
self.description = description
self.ymdhm = ymdhm






def output(item):
print('Title: ' + item.title)
print('Description: ' + item.description)
print('Published: ' + item.ymdhm)






summary = 'Clean Code Is Great!'
desc = 'Actually, writing Clean Code can be pretty fun. You\'ll see!'
new_date = datetime.now()
publish = new_date.strftime('%Y-%m-%d %H:%M')



item = Entity(summary, desc, publish)



output(item)

In this code, we have a class called entity that defines three attributes: title, description, and ymdhm. Next we have a function (not a method, outside the class) that prints these properties. Finally, we have defined the required date and values and instantiated it from the entity class. I want you to assume that the entity is a blog post (a simple post). Based on this, we can write the above code in a much better way. First, we change the name of the class from entity to blog post:

from datetime import datetime




class BlogPost:
def __init__(self, title, description, date_published):
self.title = title
self.description = description
self.date_published = date_published

In addition to changing the name of the class, we have also changed the name of ymdhm to date_published to make it clearer. In the next step, it is better to change the name of the output function to print_blog_post, because it is descriptive and clearly defines what the function is. The word output or general words like that (such as print_data) are not good names because they are general, so someone may think that their job is to print any type of data, while the output method looks for the properties of the blogPost object, and if this If the properties are not found, our code will encounter an error.

def print_blog_post(blog_post):
print('Title: ' + blog_post.title)
print('Description: ' + blog_post.description)
print('Published: ' + blog_post.date_published

I've also renamed the parameter to blog_post to make it clearer. Finally, we have the variable summary, which is not a good name at all, because summary is actually the title of the post, so we must use the word title:

title = 'Clean Code Is Great!'
description = 'Actually, writing Clean Code can be pretty fun. You\'ll see!'
now = datetime.now()
formatted_date = now.strftime('%Y-%m-%d %H:%M')



blog_post = BlogPost(title, description, formatted_date)



print_blog_post(blog_post)

I have modified this code in a few other parts as well. First, we had the desc variable, which is an abbreviation and has a clear meaning for many developers, but I prefer not to write its name as an abbreviation and have used description. In the next step, we had the new_date variable, which is not a bad name, but it is not descriptive and clear either, so it is better to name it now because we have received the current date. Finally, we had the publish variable, which is not a proper name at all, and I have changed it to formatted_date. Now, when we want to create an instance of the BlogPost class, we must store it in a variable named blog_post. The previous name (item) is a very general name and does not specify what the content of this variable will be. We have been able to make our code readable and high-quality in this simple way, but I would like to emphasize again that this is not the only possible way to correct this code; You may have corrected the codes based on your taste so that they are different from mine. It is important that if someone reads your code for the first time, they understand how it works.

The code that we corrected in this section has no problem and the code is considered clean, but we can still write it better. how about The code above will technically work, but it's a bit fragmented, meaning that parts of it don't work together but are separated. We should write our codes as integrated and coherent as possible. I will correct these codes again and provide you with them. All we have to do is rewrite the print_blog_post function as a method:

from datetime import datetime



class BlogPost:
def __init__(self, title, description, date_published):
self.title = title
self.description = description
self.date_published = date_published



def print(self):
print('Title: ' + self.title)
print('Description: ' + self.description)
print('Published: ' + self.date_published)





title = 'Clean Code Is Great!'
description = 'Actually, writing Clean Code can be pretty fun. You\'ll see!'
now = datetime.now()
formatted_date = now.strftime('%Y-%m-%d %H:%M')



blog_post = BlogPost(title, description, formatted_date)
blog_post.print()

Now our codes are much cleaner than before. I brought you this example to show you that the problem is not always about rewriting the names, but sometimes you have to change the structure of the codes. By defining the print method, we no longer need to call it print_blog_post because print will be executed on the BlogPost object, so it will be clear what we are printing. You may have other ways to improve the quality of this code, so do them as well.

A challenge for you

I have prepared a code for you which is of low quality and is not readable at all. This code is written in Python. I would like you to rewrite it and make it more readable.

class Point:
def __init__(self, coordX, coordY):
self.coordX = coordX
self.coordY = coordY




class Rectangle:
def __init__(self, starting_point, broad, high):
self.starting_point = starting_point
self.broad = broad
self.high = high



def area(self):
return self.broad * self.high



def end_points(self):
top_right = self.starting_point.coordX + self.broad
bottom_left = self.starting_point.coordY + self.high
print('Starting Point (X)): ' + str(self.starting_point.coordX))
print('Starting Point (Y)): ' + str(self.starting_point.coordY))
print('End Point X-Axis (Top Right): ' + str(top_right))
print('End Point Y-Axis (Bottom Left): ' + str(bottom_left))




def build_stuff():
main_point = Point(50, 100)
rect = Rectangle(main_point, 90, 10)



return rect





my_rect = build_stuff()



print(my_rect.area())
my_rect.end_points()

As you can see, this code has a class for creating point (X and Y axis points) and a class for creating rectangle. Try rewriting this code yourself and then look at my answer.

In the first part of this code, we have the points of the X and Y axes, which are designated by the names coordX and coordY. These names are not bad but they have extra information. The name of our class is point, so it is clear that X and Y are horizontal and vertical points, and there is no need to mention coord (abbreviation of coordinate). So we can act as follows:

class Point:
def __init__(self, x, y):
self.x = x
self.y = y

In the next step, we reach the rectangle class. The first parameter is named starting_point, which is a good name and does not need to be changed. starting_point is the point from which the drawing of the rectangle will start. However, I personally prefer a simple name like origin, so I'll change starting_point to that. The next parameters are broad and high, which are not good names at all and must be changed. I use width and height instead of these two names.

class Rectangle:
def __init__(self, origin, width, height):
self.origin = origin
self.width = width
self.height = height

In the next section, we have a method called area. If this method only returns a boolean, this name could be suitable, but this method calculates the area, so the better name is getArea or calculateArea. Naturally, by changing the name of the properties (width and height), we must also change these properties in the next methods. In my opinion, there is no bad name in the end_points method. This method specifies and prints the different points of the rectangle, and names like top_right are descriptive and good names, so I won't change anything in it, but the name end_points itself is a bit dumb. This method is responsible for printing the different points of the rectangle, so in my opinion the name print_coordinates is much better.

Finally, we have the build_stuff method, which is a very bad name. This method is responsible for building a rectangle, so it should be named build_rectangle. The main_point variable in this method is also not a very good name (although not bad either), so I prefer to change it to rectangle_origin to indicate that this point is the starting point of the rectangle. Finally, we have the rect variable, which is an abbreviated expression, but there is no reason to do this, so I change it to rectangle. Naturally, my_rectangle is also a very bad name and we change it to rectangle. With this in mind, our completed code will look like this:

class Point:
def __init__(self, x, y):
self.x = x
self.y = y





class Rectangle:
def __init__(self, origin, width, height):
self.origin = origin
self.width = width
self.height = height



def get_area(self):
return self.width * self.height



def print_coordinates(self):
top_right = self.origin.x + self.width
bottom_left = self.origin.y + self.height
print('Starting Point (X)): ' + str(self.origin.x))
print('Starting Point (Y)): ' + str(self.origin.y))
print('End Point X-Axis (Top Right): ' + str(top_right))
print('End Point Y-Axis (Bottom Left): ' + str(bottom_left))




def build_rectangle():
rectangle_origin = Point(50, 100)
rectangle = Rectangle(rectangle_origin, 90, 10)



return rectangle






rectangle = build_rectangle()



print(rectangle.getArea())
rectangle.print_coordinates()

Again, there are many ways to rewrite and the names I chose are not the only correct names.