This is the 16th day of my participation in Gwen Challenge


This is a list of key notes I took after reading The Art of Writing Readable Code. Many of the points I made are useful and clear enough to help you develop good code habits on a daily basis.

First of all, what is “readability”? The author believes that the basic theorem of readability is:

Code should be written in such a way that it takes minimal time for others to understand it.

Even if there is no “someone else” on a project, just the developer, that “someone else” could be me six months from now. I think many of you have looked back at your code once in a while and thought it was strange. And we never know if someone else will join the project.

Therefore, the preparation of readable code is a necessary basic skills, but also a good professional quality of programmers.

(Some examples from the P.S. book are rewritten in JavaScript.)

First, surface level improvement

1. Put the information in the name

  • Choose professional/more expressive words
The word More choice
Get Fetch, Download
Stop Kill, Pause
Send Deliver, Dispatch, Announce, Distribute, Route
Find Search, Extract, Locate, Recover
Strat Launch, Create, Begin, Open
Make Create, SetUp, Build, Generate, Compose, Add, New
  • Avoid using imagestmpandretvalSuch a generic name

    Do not abuse TMP, it should only be used for short-term existence, providing temporary storage:

if (right > left) {
    tmp = right;
    right = left;
    left = tmp;
}
Copy the code

Retval is so vague that a more precise name should have been chosen:

// 👎 I am a return value
retval += v[i] * v[i];

// 👍 I am a sum of squares
sumSquares += v[i] * v[i];
Copy the code
  • More precise naming of loop iterators

    We usually name iterators with I, j, and k for brevity, but in more complex loops, more precise names are clearer and easier to spot.

for(let i = 0; i < orders.length; i++)
    for(let j = 0; j < orders[i].items.length; j++)
        for(let k = 0; k < services.length; k++)
            if (orders[i].items[k].services == services[j])
Copy the code

In this case, the j and K ends up wrong, but it’s not easy to spot the problem at a glance. If we use oi (orders_i), II (Items_i), si (services_I), it is more readable and less error-prone.

for (left oi = 0; oi < orders.length; oi++)
    for(let ii = 0; ii < orders[oi].items.length; ii++)
        for(let si = 0; si < services.length; si++)
            if (orders[oi].items[si].services == services[ii])
Copy the code
  • Attach more information to the name
var start = (new Date()).getTime(); .var elapsed = (new Date()).getTime() - start;
document.writeIn("Load time was: " + elapsed + " seconds";
Copy the code

This is an example of calculating the page load time, and because there is no unit, it is easy to mistake seconds and milliseconds. This problem can be avoided by adding units to the naming:

var start_ms = (new Date()).getTime(); .var elapsed_ms = (new Date()).getTime() - start_ms;
document.writeIn("Load time was: " + elapsed_ms / 1000 + " seconds";
Copy the code
  • How long should the name be

Sometimes long names are written to make sense, but this can be a pain:

newNavigationControllerWrappingViewContrllerForDataSourceOfClass

For example, a variable can be named one of three ways:

  • d
  • days
  • daysSinceLastUpdate

What kind of length is appropriate?

  • Short names can be used in small scopes, but large scopes should contain enough information to avoid confusion.

    For example, if the scope of a variable is within 10 lines, you can clearly see its type, initial value, etc., and there is no misunderstanding with simple names. But if it’s a global variable, it’s hard to understand.

  • Avoid unfamiliar acronyms. The rule can be: Will new members of your team understand the name?

    For example: doc instead of document is easy to understand, BEManager instead of BackEndManager may be a little difficult.

  • When there are more than three units in the name of the hump, the reading experience is affected

    For example, userFriendsInfoModel memoryCacheCalculateTool

  • Drop Useless words: Sometimes certain words from a name can be removed without losing any information.

    For example, convertToString can be omitted to toString

  • Purposefully use case, underline, and so on

    For example, $Content represents a Jquery variable, _getLast() represents a private property that cannot be called externally, and CONSTANT_NAME represents a constant

2. A name that can’t be misunderstood

How do you choose a name that won’t be misunderstood?

  • Ask yourself several times: “Can this name be interpreted in any other way?”
  • Recommend to useminandmaxTo express (contain) the limit, better than usinglimit
  • Recommend to usefirstandlastTo indicate the scope of inclusion, better than usingstartandstop
  • Recommend to usebeginandendTo indicate the include/exclude scope
  • useis,has,canSuch a word to make it clear that it is a Boolean. Avoid using antisense words
  • Match user expectations, for examplegetIt is generally considered a lightweight accessor

3. The aesthetic

There are also a few things you need to pay attention to when it comes to keeping your code aesthetically pleasing.

Three principles
  • Use a consistent layout so that the reader quickly gets used to the style
  • Make similar code look similar
  • Group related lines of code into code blocks
methods
  • Rearrange line feeds to keep them consistent and compact
  • Use methods to sort out irregularities
  • Use column alignment when needed
nameLabel.text    = model.name;
sexLabel.text     = model.sex;
addressLabel.text = model.address;
Copy the code
  • Pick an order that makes sense and use it consistently:

    • Let the order of variables correspond to the HTML formThe order of the fields matches
    • From “most important” to “least important.
    • Sort in alphabetical order
  • Organize declarations into blocks and break code into “paragraphs”

BigFunction {
    // step1: xxx.// step2: xxx.// step3: xxx. }Copy the code
  • Personal Style and Consistency: Consistent style is more important than the “right” style

4. What kind of comment should I make

Key idea: The purpose of annotations is to help the reader learn as much as possible about the author.

What doesn’t need a comment
  • Don’t comment for facts that can be quickly inferred from the code itself
  • Don’t comment for comment’s sake
  • Don’t comment bad names (crutches) — change the name to good (good code > bad code + Good comment)
What should be a comment
  • Record your valuable insights into the code

    Many times the code itself does not express these thoughts, so it may be necessary to comment your thoughts to let the reader know what the thoughts were and why the code was written.

tag Common meaning
TODO: Business to be dealt with
FIXME: Known problem code
HACK: A crude AD hoc approach to a problem
XXX: Danger! There are important questions here
  • Write comments for flaws in your code

    Temporary solutions, written defects, alternatives that are not yet thought of, or that are thought of but cannot be implemented due to time or ability.

// This scheme has an easy to overlook trap: XXX
// There is a performance bottleneck in the xx function
// The performance of this scheme may not be the best, but it would be much better if such and such algorithm were used
Copy the code
  • Comment constants
image_quality = 0.72; // Optimal size/quanlity ratio
retry_limit = 4; // The maximum number of request retries allowed by server performance
Copy the code
  • The whole picture

    Such as organizational structure, how classes interact with each other, how data is stored and flows, and entry points for modules. Think of it as introducing new people to the code.

// This file contains helper functions that provide a convenient interface for a business
Copy the code
Specification of annotations (see Airbnb specification)
  • Keep comments compact and accurately describe the behavior of the function
  • withInput/outputTo illustrate a particular situation
  • use/ * *... * /As a multi-line comment. Contains descriptions, types and values specifying all parameters, and return values.

Simplify loops and logic

1. Make control flow easy to read

Make conditions, loops, and other changes to control flow as “natural” as possible

Find a way to keep readers from stopping to reread your code

The order of arguments in a conditional statement

The order of parameters in a conditional statement can be as follows:

// code 1
if(length > 10)

// code 2
if(10 < length)

// code 3
if(received_number < standard_number)

// code 4
if(standard_number < received_number)
Copy the code

The first and third orders are preferred, as follows:

  • On the left side of the comparison: usually put the “asked” expression, its value is generally changing;
  • The right-hand side of a comparison: usually used to “compare” an expression with a constant value.
Order of if/else statement blocks
  • Deal with positive logic first, not negative logic
  • Let’s get rid of the simple cases
  • Deal with interesting or suspicious situations first
? : conditional expression
  • If /else is clearer by default, and conditional expressions are used only in the simplest cases.
var a.b = new c(a.d ? a.e(1) : a.f(1));

if (a.d) {
    var a.b = new c(a.e(1));
} else {
    var a.b = new c(a.f(0));
}
Copy the code
Avoid do/while loops (logic upside down is hard to read)
Return early from a function (handle exceptions, reduce nesting)
Add parentheses appropriately (logic is clearer)
/ / easy to && and | | priority of temptation
(a + b > c && a - b < c || a > b > c)

// Better readability after order optimization
((a + b > c) && ((a - b < c) || (a > b > c))

Copy the code

2. Break up long expressions

Long expressions are often difficult to understand, so we need to split some variables. The following types of variables are better for splitting separately:

Variables used as explanations

The easiest way to break up an expression is to introduce an extra variable that represents a smaller subexpression.

// 👎 extremely long expressions are difficult to understand
if (ListeningStateChangedEvent.split(':') [0].strip() === 'root') {}// 👍 split username according to the meaning
username = line.split(':') [0].strip();
if (username === "root") {}Copy the code
Conclusion the variable

The purpose of summarizing variables is simply to replace a chunk of code with a much shorter name that is easier to manage and think about.

/ / 👎
if (request.user.id === document.owner_id) {
  // user can edit this document...
}

/ / 👍
let user_owns_document = (request.user.id === document.owner_id);
if (user_owns_document) {
  // user can edit this document...
}
Copy the code
Use de Morgan’s theorem

The principle of de Morgan’s theorem is: “invert respectively, convert and or”. Sometimes you can use this rule to make Boolean expressions more readable.

Not (a or B or c) is equivalent to (not a) and (not b) and (not c).

Not (a and B and c) is equivalent to (not a) or (not b) or (not c)

// Use de Morgan's theorem before conversion
if(! (file_exists && ! is_protected)) {}// Use de Morgan's theorem after conversion
if(! file_exists || is_protected) { }Copy the code

3. Variables and readability

Reducing the variable
  • Temporary variables with no value: not breaking up any complex expressions, not doing any more clarification, only used once
  • Reduce intermediate results: Handle intermediate variables that hold temporary results by having code return early
Reduce the scope of a variable
  • Large files are split into smaller files, and large functions are split into smaller functions, independent of each other
  • Make a global variable that only one function will use private
  • Use const for all references and let instead of var

Reorganize your code

1. Extract irrelevant sub-questions

  • Extract pure tool code
  • Extract small modules for multiple reuse
  • Create lots of generic code: for example, the code in util
  • Project-specific capabilities: To isolate code specific to the business
  • Simplifying existing interfaces: for exampledocument.cookieProvides strings that can be read easily by functions
The benefits of this:
  • Improve code readability:

Replacing the function call with the original complex implementation allows the reader of the code to quickly understand the purpose of the sublogic, allowing them to focus on the higher-level main logic without being affected by the (often complex and uninteresting) implementation of the logic.

  • Easy to modify and debug:

Because this sublogic may be called many times in a project (calculating distances, calculating exchange rates, reserving decimal points), it only needs to be changed at this point when business requirements change, and it is easy to debug.

  • Easy to test:

Similarly, because it can be called multiple times, it is more targeted when testing.

2. Do one thing at a time

  • List all the “tasks” your code does: Tasks can be small, such as checking data formats.

  • Try to break this task down into different functions, or at least into different sections of code.

The benefits of this:
  • We can clearly see how this functionality is done step by step, and the smaller functions that are split out may be useful in other ways as well.

  • If you encounter code that is difficult to read, try listing all the tasks it does. You may soon find that some of these tasks can be converted into separate functions or classes. The rest can simply be a logical paragraph in a function.

3. Turn ideas into code

“If you can’t explain something to your grandmother, you don’t really understand it.”

Before designing a solution, it helps if you can explain the problem in natural language. Because if you go directly from the idea in your head to code, you might lose something. But if you can articulate the whole question and idea, you may discover problems that you didn’t think of before. This will improve your thinking and design.

Try the following:

  • What do you do if you want to describe your code in natural language as if it were a colleague
  • Pay attention to key words and phrases used in the description
  • Write the code that matches the description

Write less code

  • Question and divide your needs

    Not all programs need to be fast, 100% accurate, and able to handle all input. If you really examine your requirements carefully, sometimes you can whittle it down to a simple problem that requires less code.

  • Keep your code base small

    Create as much “utility” code as possible to reduce code duplication

    Keep your projects as separate subprojects

  • Familiarize yourself with the libraries around you

    Every once in a while, take 15 minutes to read the names of all the functions/modules/types in the standard library.

Reference content:

The Art of Writing Readable Code

Writing Quality Code: 188 Suggestions for Improving JavaScript Applications

Airbnb JavaScript Code Specification (ES6)