I finally started writing technical articles.

First of all, I would like to thank “one program pot” and “Labuladong” for their direct and indirect help to me.

Why is it fried chicken

I actually wanted to write the design pattern at the beginning, and wrote a certain amount of accumulation. Although I also want to write more advanced algorithms, data structures, even AI stuff. But I have no choice. I can’t write now.

But in the process of writing code, I gradually found a problem, not only in the study or work.

A lot of people’s code, myself included, is poorly readable. Forget about the larger aspects of code organization and design patterns. A single variable, a function’s name, and a specification of comments are not helpful to understand, making people confused.

At least that’s how I look at my own code, but after a few months, I don’t.

Code writing specifications are rarely paid attention to, and my main program recently asked me to read a book called the Art of Writing Readable Code that hit the nail on the head, so I decided to write about it.

Hopefully, through this series of fried chicken, you and I can make some progress in code readability.

The premise to prepare

Before reading this article, understand some principles.

Basic readability theorem

Code should be written to be understood in the shortest time possible. Understanding means fully understanding and being able to locate problems, fix problems, and see how this code relates to other code.

Demands on yourself

Ask yourself, is this code really easy to understand? Imagine another person looking at your code, or a like-minded person joining your project team, even if it’s just one person. Does he take over reading the code with a furrowed brow, or an unfurled brow?


All right, let’s get started.

Naming needs to add more information

Let’s start with the easiest thing to change, which is naming. In general, a lot of people write programs when naming is more distressed, write programs half of the time thinking about naming. Or sometimes, just for convenience, I’ll write the names arbitrarily.

And since this code was written by itself, within a day or two, you’ll still be able to browse through all of these named variables, functions, and so on, and see what they mean.

But after a while, you’ll get confused, and the code will be very unreadable.

Therefore, the name should express more information.

Use more specific words

In order to express more information, naming words need to be more specific, we should use more specific words to do the naming.

Let’s take a look at the following code, which is a class that describes a text file.

class Text
{
public:
    Text();
    ~Text();
. int size(a); }; Copy the code

The use of size can be described as a disaster area, at first glance, there is no problem. But there are some problems with this size:

  1. Size names attributes so much that it can confuse the reader as to whether this is a function call or a public attribute.
  2. The meaning of size is unclear. Does this represent the size of the file, or the length of the contents of the file, or the number of words?
  3. Size If it is a function, it returns the current file size, the file limit size, the current size of the file contents, or… .

See how an obscure name can cause reading comprehension problems.

If we use getCurrentBytes(), we can most likely read:

Function to get the size of this file.

If we use countWordNum(), we can probably read:

A function that calculates the number of words to get the contents of a file.

Therefore, when naming words to choose a clear meaning, can accurately express the role and purpose of the word.

Rich words

In order to express a clearer meaning, our English vocabulary should be sufficient.

This requires us to use more translation software, a lot of accumulated vocabulary.

An example is provided in the book, which I will list.

General words Richer and more meaningful words
send deliver, dispatch, announce, distribute, route
find search, extract, locate, recover
start launch, create, begin, open
make create, set up, build, generate, compose, add, new

Avoid vague, broad terms

As we know from the above, naming should be more specific and choose more accurate words.

Therefore, we should not only be able to choose, but also to avoid.

Avoid words that don’t make sense.

Note that this meaning is ambiguous and applies to situations where a lot of information needs to be expressed.

Take, for example, two worst-hit areas

1. Return value.

So let’s look at this code.

local ret = Calculator:calculate(1.2)
Copy the code

Ret, we all recognize it as a return value. But that’s too little information to make sense.

If I were using IRET, this would give the reader an additional datatype of information that would tell the reader:

This is the return value of an integer.

If multiplyRet is used, this sums up the calculate logic and tells the reader:

Use multiplication to get the result.

2. tmp

Again, let’s look at some code.

tmp = ""
tmp += 'name:'
tmp += '\t{}\n'.format('dogge')
tmp += 'age:'
tmp += '\t{}\n'.format(122)
tmp += 'email:' tmp += '\t{}\n'.format('[email protected]') tmp += 'address:' tmp += '\t{}\n'.format('the earth') Copy the code

Obviously, TMP only represents a staging variable for its own string concatenation. But based on the results, it would be more appropriate to call it userInfo. When the reader sees this name, he or she not only learns more information, but also doesn’t have to read so many lines to figure out what the variable means.

But as mentioned earlier, if you only need to express a single meaning, such as TMP is only used for temporary variables. So, TMP is an appropriate name.

Ambiguity of loop iteration

The most classical names for the iterated variables are I, j, k.

Let’s take a look at the following code, the code function is to traverse each grade of each class of each student’s name.

for (int i = 0; i < grades.size(); i++)
    for (int j = 0; j < grades[i].class.size(); j++)
        for (int k = 0; k < classMember.size(); k++)
            cout << classMember[k].name << endl;
Copy the code

As you can see, if the loop logic is complex, I, J, k use each other in different nesting, it’s very complicated. The people who write this code have to be careful if I, j, k are used incorrectly, and the reader has to read more difficult.

Therefore, loop variables should not be broad and vague, but also add more information.

Change I, j, k to grade_i, class_j, member_k. Modify the code as follows:

for (int grade_i = 0; grade_i < grades.size(); grade_i++)
    for (int class_j = 0; class_j < grades[grade_i].class.size(); class_j++)
        for (int member_k = 0; member_k < classMember.size(); member_k++)
            cout << classMember[member_k].name << endl;
Copy the code

In this way, readers do not need to memorize the data of I, J and K, and it is easier to locate the wrong grades[class_j] variables.

Accurate > broad

This usually happens with function naming. Sometimes our function names tend to generalize, making the names too broad.

The following code is an example where the writer thinks the server is ready by simply checking to see if the port is occupied.

bool serverIsReady(a)
{
    // Check whether the port is occupied
.}
 Copy the code

This function returns true when called, but the server fails to start due to an IP problem. The reader looks at the name and wonders, isn’t the server ready?

if (serverIsReady())
{
launchServer(); / / fail}
Copy the code

This is the result of naming the function too loosely. We changed the function name to canListenPort, which accurately describes the function. As the reader will know, this only checks port occupancy, IP and other environments are not checked. Also convenient for readers to do certain packaging and modification.

What information can be added to a name

They keep talking about naming more information, how to add more information.

So let’s talk about what information we can add.

unit

To be honest, when I saw this, IT kind of clicked. Before writing some logic related to time, will be confused.

local starttime = os.clock(a)
.
local elapse = os.clock(a)print(elapse) 1 - Copy the code

So that’s one ms, one US, one s? Of course, you could say I’m not familiar with Lua’s os.clock. What if the function is wrapped by the writer himself?

local starttime_ms = myClock()

.
local elapse_ms = myClock() - starttime_ms
Copy the code

So similarly, if you’re measuring a property, it’s good to add units.

Here are some examples from the book.

No units in use Use the unit
Start(int delay ) Delay – delay_secs
CreateCache(int size ) Size – size_mb
ThrottleDownload(float limit) The limit – max_kbps
Rotate(float angle) The Angle – degrees_cw

Important attributes

What are the important attributes? Important information that must be read. For example, in your logic, you need a string. But the string content is a hexadecimal string.

If you just look at a STR, you can’t express this information.

local str
Copy the code

So we can change it to:

local hex_str
Copy the code

Consider another scenario where the received password is processed in the background. However, the input code is required to be UTF8, and the plaintext password. One password, obviously, doesn’t tell you much.

Let’s try this:

local plaintext_utf8_password
Copy the code

conclusion

The fried chicken is mainly for the lack of naming information, from two aspects to describe the solution for reference.

  1. Naming how to add more information.
  2. Name what information to add.

In terms of 1, naming needs to be specific. So the 1 expansion has two parts.

  1. Since naming needs to be concrete, words need to accurately and concretely describe variable/function functions and logic.
  2. Now that you know to be specific, avoid using broad words.

We’re going to start with 2

  1. To measure type variables, add units
  2. An important property of a variable that needs to be named.

The resources

The Art of Readable Code

Finally sing


This article is formatted using MDNICE