Code quality layer 3 - readable code

click One click subscription to the column of "cloud recommended coffee" , get the official recommended high-quality content and don't get lost in learning technology!

Readable code can greatly improve development efficiency. In the process of development, I spend a lot of time reading code. Readable code, easy to understand and easy to change. On the contrary, unreadable code is in a bad mood to read and easy to make mistakes to change.

The following is a non readable code:

const user = ...
const foo = (cb) => ...
const bar = (list, cb) => ...
const other = (list1, list2) => ...

if(user ? user.isAdmin : ((user.permission && user.permission.view) ? user.permission.view === true :  false)) {
  foo((res) => {
    if(res && res.ok && res.list && res.list.length > 0) {
      bar(res.list, (res2) => {
        if(res2 && res2.ok && res2.list && res2.list.length > 0) {
          other(res.list, res2.list)
        }
      })
    }
  })
}

The above code has these problems:

  • The name of the function does not match the function.
  • if conditions are too complex and deeply nested.
  • Callback functions are deeply nested.

Change the above code to readable code:

const user = ...
const fetchChannel = () => ...
const fetchArticle = (list) => ...
const render = (channelList, articleList) => ...

const hasViewPermission = user.isAdmin || user.permission?.view
if(!hasViewPermission) {
  return
}

const { ok, list: channelList} = await fetchChannel()
if (!(ok && channelList?.length > 0)) {
  return
}

const { ok: fetchArticleOk, articleList } = await fetchArticle(channelList)

if (!(fetchArticleOk && articleList.length > 0)) {
  return
}
render(channelList, articleList)

In summary, readable code mainly has the following characteristics:

  • Consistent code style.
  • Reasonable naming.
  • Necessary notes.
  • There are no large files.
  • No deeply nested code.

How to write readable code?

Write readable code to meet the characteristics mentioned above.

1, Consistent code style

Consistent code style means that spaces, indents, naming styles (humps, dashes, etc.) are consistent throughout the project. A consistent code style that looks neat can also reduce the cost of understanding. In a project, it doesn't matter what style of code you use. It is important that the style be consistent.
Famous code styles in the front-end industry include: Airbnb JavaScript Style Guide and JavaScript Standard Style . Do not want to toss, you can use JavaScript Standard Style . Features of JavaScript Standard Style:

No configuration required. The most convenient way to unify the code style in history.
Automatic code formatting. Just run standard --fix and say goodbye to the dirty code.
Identify style and procedure problems in advance. Reduce the repeated modification process in the code review process and save time.

After determining the code style, you can use the inspection tool ESLint To ensure the unity of code style. Before each code submission, check it with the following tools: husky . For large projects, checking the whole project is too slow. use lint-staged Check only the files with this change.

2, Reasonable naming

There are only two hard things in Computer Science: cache invalidation and naming things. There are only two things that are difficult in Computer Science: cache invalidation and naming-- Phil Karlton

A good name is "see its name and know its meaning". Specifically, good naming has the following characteristics:

Straightforward and meaningful
Good naming is easy to understand, that is, straightforward and meaningful. For example: fetchUserInfo.
recommend: Nomenclature of the Forbidden City
Extract the key features of the target object to name it.
Recommended naming tools: CODELF . It helps you search Github, GitLab and other websites for different names of the content you want to find.
Be careful not to misspell the words in the naming. Recommended word spelling tools: Code Spell Checker.

Follow industry practice
Good naming should also follow the customary practices of the industry. For example, it is industry practice to name the id as a unique identifier instead of an identifier. i. j and k are used to name the loop count variables.

Conform to code style
Good naming should conform to the code style of the current project. Such as hump style, etc.

Bad naming has the following characteristics:
Meaningless name
Meaningless names, such as foo, bar, var1, fun1.

Too abstract a name
Names that are too abstract, such as data, res, temp, and tools.

Ambiguous abbreviations
Ambiguous abbreviations, such as mod. You may not be able to confirm whether it is mode or module.

Unnecessary context information

// bad
function async getUserName (userId) {
  const userName = await fetchUser(userId)
  return userName
}

// good
function async getUserName (id) {
  const name = await fetchUser(id)
  return name
}

Too long name
It's too long to understand. For example: fetchgrantyungestboyname. Optimization method: omit unimportant contents. If changed to: fetchBoyName.

3, Necessary notes

Comments are the explanation and explanation of the code. Good code is self explanatory. For uncomplicated code, no comments are required. If the comments written only explain what the code has done, they will not only waste the reader's time, but also mislead the reader (when the comments and code functions are inconsistent).

Scenarios requiring comments:

  • When the code itself cannot clearly state the author's intention.
  • The logic is complicated.

4, No large files

Large file refers to a file with a large number of lines of code (more than 1000 lines). Large files mean that the code does a lot of things and it is difficult to track what happened.

You can use the max lines rule in ESLine to find large files.
Optimization scheme: split large files into several small files according to functions.

5, No deeply nested code

Deeply nested code has poor readability, which makes people feel "awe". For example:

fetchData1(data1 =>
  fetchData2(data2 =>
    fetchData3(data3 =>
      fetchData4(data4 =>
        fetchData5(data5 =>
          fetchData6(data6 =>
            fetchData7(data7 =>
              done(data1, data2, data3, dat4, data5, data6, data7)
            )
          )
        )
      )
    )
  )
)

Here are several common deeply nested scenarios.
1. Callback hell
Using callback function to handle multiple serial asynchronous operations will cause deep nesting. Commonly known as "hell". For example:

fetchData1(data1 =>
  fetchData2(data2 =>
    fetchData3(data3 =>
      done(data1, data2, data3)
    )
  )
)

2.if nested deeply
In conditional statements, if there are many judgment conditions, there will be deep nesting or long judgment conditions. For example, judge whether a value is an even number between 1 and 100 that can be divided by 3 and 5. It says:

const isEvenNum = num => Number.isInteger(num) && num % 2 === 0
const isBetween = num => num > 1 && num < 100
const isDivisible = num => num % 3 === 0 && num % 5 ===  0

if (isEvenNum(num)) { // It's an even number
  if(isBetween(num)) { // Between 1 and 100
    if(isDivisible(num)) { // Can be divided by 3 and 5
        return true
    }
    return false
  }
  return false
}
return false

Ternary expressions can also be deeply nested:

a > 0 ? (b < 5 > ? (c ? d : e) : (f ? g : h)) : (i ? j : k)

3. Function call nesting
Execute multiple function calls, and the output of each function is the input of the next function, resulting in deep nesting. For example:

// Simulate the process of scrambled eggs: buy eggs - > beat eggs - > scrambled eggs - > serve.
toTable( // Step 4: on the table
  fry( // Step 3: scrambled eggs
    handle( // Step 2: beat eggs
      buy(20) // Step 1: buy eggs
    )
  )
)

4.React high-level component nesting
In the application written by React, a component will be wrapped by many high-level components (HOC), resulting in deep nesting. For example:

class Comp extends React.Component {...}

Wrapper5(
  Wrapper4(
    Wrapper3(
      Wrapper2(
        Wrapper1(Comp)
      )
    )
  )
)

5.React Context nesting
In the application written by React, Context can be used to manage the data sharing among sub components. If there are many shared data and different types, it is easy to cause the top component Context to be deeply nested. For example:

<PageContext.Provider
  value={...}
>
  <User.Provider
    value={...}
  >
    <Project.Provider
      value={...}
    >
      <ChildComp />
    </Project.Provider>
  </User.Provider>
</PageContext.Provider>

The optimization scheme is shown in: here.

summary

The readability of code that conforms to the characteristics of readable code mentioned in this article will not be poor. Of course, there are many techniques that can improve the readability of code. For example:

  • Limit the number of arguments to the function.
  • Limit the cyclomatic complexity of a function.
  • Disable the with statement.
    To learn more tips to improve code readability, it is recommended to roll it again Rules for ESLint.

The next level of code quality is reusable code, which will be introduced in the next article.

Jin Weiqiang's previous wonderful articles recommend:

Talk about code quality - Preface to "learning and copying methods to improve front-end code quality"
Code quality layer 5 - only functions are implemented**
Code quality layer 4 - robust code

"Cloud recommendation" is a boutique content column of Tencent cloud plus community. The cloud sponsor specially invites industry leaders to focus on the landing of cutting-edge technologies and theoretical practice, continue to interpret hot technologies in the cloud era and explore new opportunities for industry development. click One click subscription , we will regularly push premium content for you.

Keywords: Java Javascript Front-end

Added by El_Dudereno on Thu, 13 Jan 2022 08:09:13 +0200