Code quality layer 3 - readable code!

Introduction | Tencent cloud plus community boutique content column "cloud recommend big coffee", specially invites industry leaders to focus on the landing and theoretical practice of cutting-edge technologies, continue to interpret hot technologies in the cloud era for you, and explore new opportunities for industry development.

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.

Here is an unreadable piece of 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?.viewif(!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.

The famous code styles in the front-end industry include Airbnb JavaScript Style Guide and JavaScript Standard Style. If you don't 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. You can use the tool: husky( ). For large projects, checking the whole project is too slow. Using 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".

(1) Good naming

It has the following characteristics:

  • Straightforward and meaningful

Good naming is easy to understand, that is, straightforward and meaningful. For example: fetchUserInfo.

Recommendation: naming method of the Forbidden City (extracting the key features of the target object to name it)

Recommended naming tool: 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 checker: 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.

(2) Bad naming

It 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
// badfunction async getUserName (userId) {  const userName = await fetchUser(userId)  return userName}
// goodfunction 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.

(1) 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.

(2) 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.

  • 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)    )  ))
  • 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 === 0const isBetween = num => num > 1 && num < 100const isDivisible = num => num % 3 === 0 && num % 5 ===  0
if (isEvenNum(num)) { // Is an even number if (isbetween (Num)) {/ / between 1 and 100 if (isdivisable (Num)) {/ / can be divided by 3 and 5 return true} return false} 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)
  • 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: serve fry(/ / step 3: scramble eggs handle(/ / step 2: beat eggs buy(20) / / step 1: buy eggs))
  • 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)      )    )  ))
  • 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:

4, 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 for improving code readability, I recommend rolling out the rules of ESLint( ). The next level of code quality is reusable code. It will be introduced in the next article.

Added by numerical25 on Fri, 14 Jan 2022 10:10:43 +0200