Home > Web Front-end > JS Tutorial > The Importance of Writing Code That Humans Can Read

The Importance of Writing Code That Humans Can Read

Lisa Kudrow
Release: 2025-02-18 10:52:10
Original
481 people have browsed it

The Importance of Writing Code That Humans Can Read

Key Points

  • Cleverness first: Highly readable code improves maintainability and collaboration, and writing code that is easy to understand and modify is crucial.
  • Function and File Management: Use functions to encapsulate reusable code and split large files into smaller, more manageable parts to simplify navigation and understanding.
  • Naming Convention: Choose clear and descriptive names for functions and variables to improve readability and reduce the need for additional comments.
  • Avoid over-optimization: Although concise and optimized code is attractive, readability should be prioritized when performance impact is not significant, because modern JavaScript engines are in code optimization Very efficient.
  • Careful comments: Use comments to explain "why" do this, rather than "what to do", and keep the comments relevant and up-to-date to help understand non-obvious code logic.

This article was reviewed by Matt Burnett, Simon Codrington and Nilson Jacques. Thanks to all SitePoint peer reviewers for getting SitePoint content to its best!

Have you ever completed a project in one run at a time without having to look at the code again? Neither I. When working on old projects, you may want to spend very little or no time figuring out how the code works. Readable code is essential to keep the product maintained and satisfy you and your colleagues or collaborators.

Exaggerated examples of hard-to-read code can be found in the JS1k competition, with the goal of writing the best JavaScript application in 1024 characters or less, as well as JSF*ck (NSFW by the way), which is a A profound programming style, using only six different characters to write JavaScript code. Checking the code on these sites will make you wonder what's going on. Imagine writing code like this and trying to fix the error after a few months.

If you browse the internet regularly or build interfaces, you may know that it is easier to exit a large, bulky form than to exit a simple and small form. The same goes for the code. People may prefer using it when considered easier to read and use. At least it will prevent you from throwing away your computer from being frustrated.

In this article, I will explore tips and tricks for making the code easier to read, as well as pitfalls to avoid.

Code segmentation

Persist in form analogies, the form is sometimes divided into parts, making it less difficult. The code can do the same. By dividing it into sections, readers can jump to the sections related to them instead of struggling to browse the jungle.

Cross-file

For many years, we have been optimizing all kinds of things for the network. JavaScript files are no exception. Thinking about minifying and pre-HTTP/2, we save on HTTP requests by combining scripts into one. Today, we can work as we wish and use task runners like Gulp or Grunt to process our files. It is safe to say that we can program the way we like and leave optimizations (such as connections) to the tool.

// 从 API 加载用户数据
var getUsersRequest = new XMLHttpRequest();
getUsersRequest.open('GET', '/api/users', true);
getUsersRequest.addEventListener('load', function() {
    // 对用户执行某些操作
});

getUsersRequest.send();

//---------------------------------------------------
// 不同的功能从这里开始。也许
// 这是一个分成文件的时机。
//---------------------------------------------------

// 从 API 加载帖子数据
var getPostsRequest = new XMLHttpRequest();
getPostsRequest.open('GET', '/api/posts', true);
getPostsRequest.addEventListener('load', function() {
    // 对帖子执行某些操作
});

getPostsRequest.send();
Copy after login
Copy after login
Copy after login

Function

The

function allows us to create reusable code blocks. Generally, the contents of a function are indented, so it is easy to see the start and end positions of the function. A good habit is to keep the function small - 10 rows or less. It is also easy to understand what happens when the function is called when the function is named correctly. We will introduce the naming convention later.

// 从 API 加载用户数据
function getUsers(callback) {
    var getUsersRequest = new XMLHttpRequest();
    getUsersRequest.open('GET', '/api/users', true);
    getUsersRequest.addEventListener('load', function() {
        callback(JSON.parse(getUsersRequest.responseText));
    });

    getUsersRequest.send();
}

// 从 API 加载帖子数据
function getPosts(callback) {
    var getPostsRequest = new XMLHttpRequest();
    getPostsRequest.open('GET', '/api/posts', true);
    getPostsRequest.addEventListener('load', function() {
        callback(JSON.parse(getPostsRequest.responseText));
    });

    getPostsRequest.send();
}

// 由于命名正确,因此无需阅读实际函数即可轻松理解此代码
// getUsers(function(users) {
//     // 对用户执行某些操作
// });
// getPosts(function(posts) {
//     // 对帖子执行某些操作
// });
Copy after login
Copy after login
Copy after login

We can simplify the above code. Note that these two functions are almost exactly the same? We can apply the "Don't Repeat Yourself" (DRY) principle. This prevents confusion.

function fetchJson(url, callback) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.addEventListener('load', function() {
        callback(JSON.parse(request.responseText));
    });

    request.send();
}

// 下面的代码仍然很容易理解
// 无需阅读上面的函数
fetchJson('/api/users', function(users) {
    // 对用户执行某些操作
});
fetchJson('/api/posts', function(posts) {
    // 对帖子执行某些操作
});
Copy after login
Copy after login
Copy after login

What if we want to create a new user through a POST request? At this point, one option is to add optional parameters to the function, thereby introducing new logic to the function, making it too complex to become a function. Another option is to create a new function specifically for POST requests, which will cause code duplication.

We can get the advantages of both through object-oriented programming, allowing us to create a configurable single-use object while maintaining its maintainability.

Note: If you need a beginner in object-oriented JavaScript, I recommend this video: The authoritative guide to object-oriented JavaScript

Object-Oriented Programming

Consider objects, commonly called classes, which are a set of context-aware functions. An object is ideal for putting in a dedicated file. In our example, we can build a basic wrapper for XMLHttpRequest.

HttpRequest.js

function HttpRequest(url) {
    this.request = new XMLHttpRequest();

    this.body = undefined;
    this.method = HttpRequest.METHOD_GET;
    this.url = url;

    this.responseParser = undefined;
}

HttpRequest.METHOD_GET = 'GET';
HttpRequest.METHOD_POST = 'POST';

HttpRequest.prototype.setMethod = function(method) {
    this.method = method;
    return this;
};

HttpRequest.prototype.setBody = function(body) {
    if (typeof body === 'object') {
        body = JSON.stringify(body);
    }

    this.body = body;
    return this;
};

HttpRequest.prototype.setResponseParser = function(responseParser) {
    if (typeof responseParser !== 'function') return;

    this.responseParser = responseParser;
    return this;
};

HttpRequest.prototype.send = function(callback) {
    this.request.addEventListener('load', function() {
        if (this.responseParser) {
            callback(this.responseParser(this.request.responseText));
        } else {
            callback(this.request.responseText);
        }
    }, false);

    this.request.open(this.method, this.url, true);
    this.request.send(this.body);
    return this;
};
Copy after login
Copy after login
Copy after login

app.js

new HttpRequest('/users')
    .setResponseParser(JSON.parse)
    .send(function(users) {
        // 对用户执行某些操作
    });

new HttpRequest('/posts')
    .setResponseParser(JSON.parse)
    .send(function(posts) {
        // 对帖子执行某些操作
    });

// 创建一个新用户
new HttpRequest('/user')
    .setMethod(HttpRequest.METHOD_POST)
    .setBody({
        name: 'Tim',
        email: 'info@example.com'
    })
    .setResponseParser(JSON.parse)
    .send(function(user) {
        // 对新用户执行某些操作
    });
Copy after login
Copy after login
Copy after login

The HttpRequest class created above is now very configurable and can be applied to many of our API calls. Although the implementation (a series of chain method calls) is more complex, the functionality of the class is easy to maintain. Balance between implementation and reusability can be difficult and project-specific.

Design pattern is a great addition when using OOP. While they won't improve readability by themselves, consistency will!

Artificial grammar

Files, functions, objects, these are just rough lines. They make your code easy to scan . Making the code easier to read is a more meticulous art. The slightest details can have a significant impact. For example, limiting your line length to 80 characters is an easy solution, usually enforced by the editor via vertical lines. But there are more! Name

Proper naming can lead to instant recognition without finding what the value is or the function's role.

Functions usually use camel nomenclature. It usually helps to start with a verb and then the subject.

// 从 API 加载用户数据
var getUsersRequest = new XMLHttpRequest();
getUsersRequest.open('GET', '/api/users', true);
getUsersRequest.addEventListener('load', function() {
    // 对用户执行某些操作
});

getUsersRequest.send();

//---------------------------------------------------
// 不同的功能从这里开始。也许
// 这是一个分成文件的时机。
//---------------------------------------------------

// 从 API 加载帖子数据
var getPostsRequest = new XMLHttpRequest();
getPostsRequest.open('GET', '/api/posts', true);
getPostsRequest.addEventListener('load', function() {
    // 对帖子执行某些操作
});

getPostsRequest.send();
Copy after login
Copy after login
Copy after login

For variable names, try to apply the inverted pyramid method. The topic is placed in front and the attributes are placed in back.

// 从 API 加载用户数据
function getUsers(callback) {
    var getUsersRequest = new XMLHttpRequest();
    getUsersRequest.open('GET', '/api/users', true);
    getUsersRequest.addEventListener('load', function() {
        callback(JSON.parse(getUsersRequest.responseText));
    });

    getUsersRequest.send();
}

// 从 API 加载帖子数据
function getPosts(callback) {
    var getPostsRequest = new XMLHttpRequest();
    getPostsRequest.open('GET', '/api/posts', true);
    getPostsRequest.addEventListener('load', function() {
        callback(JSON.parse(getPostsRequest.responseText));
    });

    getPostsRequest.send();
}

// 由于命名正确,因此无需阅读实际函数即可轻松理解此代码
// getUsers(function(users) {
//     // 对用户执行某些操作
// });
// getPosts(function(posts) {
//     // 对帖子执行某些操作
// });
Copy after login
Copy after login
Copy after login

It is also important to be able to distinguish between ordinary and special variables. For example, the names of constants are usually written in capital letters and underlined.

function fetchJson(url, callback) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.addEventListener('load', function() {
        callback(JSON.parse(request.responseText));
    });

    request.send();
}

// 下面的代码仍然很容易理解
// 无需阅读上面的函数
fetchJson('/api/users', function(users) {
    // 对用户执行某些操作
});
fetchJson('/api/posts', function(posts) {
    // 对帖子执行某些操作
});
Copy after login
Copy after login
Copy after login

Classes usually use camel nomenclature, starting with capital letters.

function HttpRequest(url) {
    this.request = new XMLHttpRequest();

    this.body = undefined;
    this.method = HttpRequest.METHOD_GET;
    this.url = url;

    this.responseParser = undefined;
}

HttpRequest.METHOD_GET = 'GET';
HttpRequest.METHOD_POST = 'POST';

HttpRequest.prototype.setMethod = function(method) {
    this.method = method;
    return this;
};

HttpRequest.prototype.setBody = function(body) {
    if (typeof body === 'object') {
        body = JSON.stringify(body);
    }

    this.body = body;
    return this;
};

HttpRequest.prototype.setResponseParser = function(responseParser) {
    if (typeof responseParser !== 'function') return;

    this.responseParser = responseParser;
    return this;
};

HttpRequest.prototype.send = function(callback) {
    this.request.addEventListener('load', function() {
        if (this.responseParser) {
            callback(this.responseParser(this.request.responseText));
        } else {
            callback(this.request.responseText);
        }
    }, false);

    this.request.open(this.method, this.url, true);
    this.request.send(this.body);
    return this;
};
Copy after login
Copy after login
Copy after login

A small detail is the abbreviation. Some choose to capitalize the abbreviation, while others choose to stick to the camel nomenclature. Using the former may make it more difficult to identify subsequent abbreviations.

Simplicity and optimization

In many code bases, you may encounter some "special" code to reduce the number of characters or improve the performance of your algorithm.

Single-line code is an example of concise code. Unfortunately, they usually rely on tricks or obscure syntax. The nested ternary operators seen below are a common example. Although it is concise, it may also take one or two seconds to understand its effect compared to a normal if statement. Be careful with syntax shortcuts.

new HttpRequest('/users')
    .setResponseParser(JSON.parse)
    .send(function(users) {
        // 对用户执行某些操作
    });

new HttpRequest('/posts')
    .setResponseParser(JSON.parse)
    .send(function(posts) {
        // 对帖子执行某些操作
    });

// 创建一个新用户
new HttpRequest('/user')
    .setMethod(HttpRequest.METHOD_POST)
    .setBody({
        name: 'Tim',
        email: 'info@example.com'
    })
    .setResponseParser(JSON.parse)
    .send(function(user) {
        // 对新用户执行某些操作
    });
Copy after login
Copy after login
Copy after login

Micro-optimization is performance optimization and usually has little impact. In most cases, they are not as easy to read as lower-performance equivalents.

function getApiUrl() { /* ... */ }
function setRequestMethod() { /* ... */ }
function findItemsById(n) { /* ... */ }
function hideSearchForm() { /* ... */ }
Copy after login
Copy after login

JavaScript compilers are very good at optimizing code for us, and they are constantly improving. Unless the difference between unoptimized code and optimized code is obvious (usually after thousands or millions of operations), it is recommended to choose a code that is easier to read.

Non-code

This is ironic, but a better way to keep the code readable is to add syntax that won't be executed. Let's call it non-code.

Space

I'm pretty sure every developer has had other developers providing it, or checking the compressed code for a certain website - code where most of the spaces are removed. It may be quite surprising to encounter this for the first time. In different fields of visual arts, such as design and typography, blank spaces are as important as fill. You need to find a delicate balance between the two. Perceptions of this balance vary by company, team, and developers. Fortunately, there are some rules that are generally recognized by :

One expression per line,
  • The content of the indented block,
  • Additional line breaks can be used to separate the code sections.
  • Any other rules should be discussed with anyone you work with. Regardless of which code style you agree with, consistency is key.

Comments
var element = document.getElementById('body'),
    elementChildren = element.children,
    elementChildrenCount = elementChildren.length;

// 定义一组颜色时,我在变量前加“color”前缀
var colorBackground = 0xFAFAFA,
    colorPrimary = 0x663399;

// 定义一组背景属性时,我使用 background 作为基准
var backgroundColor = 0xFAFAFA,
    backgroundImages = ['foo.png', 'bar.png'];

// 上下文可以改变一切
var headerBackgroundColor = 0xFAFAFA,
    headerTextColor = 0x663399;
Copy after login

Like spaces, comments can be a great way to provide some space for your code and also allow you to add details to your code. Be sure to add a comment to display:

Interpretation and argumentation of non-obvious codes,
  • Fixed the resolved errors or exceptions and available sources.
Not all fixes are obvious. Adding additional information can clarify a lot:
var URI_ROOT = window.location.href;
Copy after login
// 从 API 加载用户数据
var getUsersRequest = new XMLHttpRequest();
getUsersRequest.open('GET', '/api/users', true);
getUsersRequest.addEventListener('load', function() {
    // 对用户执行某些操作
});

getUsersRequest.send();

//---------------------------------------------------
// 不同的功能从这里开始。也许
// 这是一个分成文件的时机。
//---------------------------------------------------

// 从 API 加载帖子数据
var getPostsRequest = new XMLHttpRequest();
getPostsRequest.open('GET', '/api/posts', true);
getPostsRequest.addEventListener('load', function() {
    // 对帖子执行某些操作
});

getPostsRequest.send();
Copy after login
Copy after login
Copy after login

Inline Document

When writing object-oriented software, inline documents, like ordinary comments, can provide some breathing space for the code. They also help clarify the purpose and details of an attribute or method. Many IDEs use them for prompts, and the generated document tools use them too! Whatever the reason, writing a document is an excellent practice.

// 从 API 加载用户数据
function getUsers(callback) {
    var getUsersRequest = new XMLHttpRequest();
    getUsersRequest.open('GET', '/api/users', true);
    getUsersRequest.addEventListener('load', function() {
        callback(JSON.parse(getUsersRequest.responseText));
    });

    getUsersRequest.send();
}

// 从 API 加载帖子数据
function getPosts(callback) {
    var getPostsRequest = new XMLHttpRequest();
    getPostsRequest.open('GET', '/api/posts', true);
    getPostsRequest.addEventListener('load', function() {
        callback(JSON.parse(getPostsRequest.responseText));
    });

    getPostsRequest.send();
}

// 由于命名正确,因此无需阅读实际函数即可轻松理解此代码
// getUsers(function(users) {
//     // 对用户执行某些操作
// });
// getPosts(function(posts) {
//     // 对帖子执行某些操作
// });
Copy after login
Copy after login
Copy after login

Callback Problem

Events and asynchronous calls are powerful features of JavaScript, but it usually makes the code harder to read.

Asynchronous calls are usually provided using callbacks. Sometimes you want to run them in order, or wait for all the asynchronous calls to be ready.

function fetchJson(url, callback) {
    var request = new XMLHttpRequest();
    request.open('GET', url, true);
    request.addEventListener('load', function() {
        callback(JSON.parse(request.responseText));
    });

    request.send();
}

// 下面的代码仍然很容易理解
// 无需阅读上面的函数
fetchJson('/api/users', function(users) {
    // 对用户执行某些操作
});
fetchJson('/api/posts', function(posts) {
    // 对帖子执行某些操作
});
Copy after login
Copy after login
Copy after login

Promise object was introduced in ES2015 (also known as ES6) to solve both problems. It allows you to flatten nested asynchronous requests.

function HttpRequest(url) {
    this.request = new XMLHttpRequest();

    this.body = undefined;
    this.method = HttpRequest.METHOD_GET;
    this.url = url;

    this.responseParser = undefined;
}

HttpRequest.METHOD_GET = 'GET';
HttpRequest.METHOD_POST = 'POST';

HttpRequest.prototype.setMethod = function(method) {
    this.method = method;
    return this;
};

HttpRequest.prototype.setBody = function(body) {
    if (typeof body === 'object') {
        body = JSON.stringify(body);
    }

    this.body = body;
    return this;
};

HttpRequest.prototype.setResponseParser = function(responseParser) {
    if (typeof responseParser !== 'function') return;

    this.responseParser = responseParser;
    return this;
};

HttpRequest.prototype.send = function(callback) {
    this.request.addEventListener('load', function() {
        if (this.responseParser) {
            callback(this.responseParser(this.request.responseText));
        } else {
            callback(this.request.responseText);
        }
    }, false);

    this.request.open(this.method, this.url, true);
    this.request.send(this.body);
    return this;
};
Copy after login
Copy after login
Copy after login

Although we introduced other code, this is easier to explain correctly. You can read more about Promise here: JavaScript becomes asynchronous (and great)

ES6/ES2015

If you understand the ES2015 specification, you may have noticed that all the code examples in this article are older versions (except Promise objects). Although ES6 provides us with powerful features, there are still some issues with readability.

Fat arrow syntax defines a function that inherits the value of this from its parent scope. At least, that's why it was designed. It is also tempting to use it to define regular functions.

new HttpRequest('/users')
    .setResponseParser(JSON.parse)
    .send(function(users) {
        // 对用户执行某些操作
    });

new HttpRequest('/posts')
    .setResponseParser(JSON.parse)
    .send(function(posts) {
        // 对帖子执行某些操作
    });

// 创建一个新用户
new HttpRequest('/user')
    .setMethod(HttpRequest.METHOD_POST)
    .setBody({
        name: 'Tim',
        email: 'info@example.com'
    })
    .setResponseParser(JSON.parse)
    .send(function(user) {
        // 对新用户执行某些操作
    });
Copy after login
Copy after login
Copy after login

Another example is the rest and spread syntax.

function getApiUrl() { /* ... */ }
function setRequestMethod() { /* ... */ }
function findItemsById(n) { /* ... */ }
function hideSearchForm() { /* ... */ }
Copy after login
Copy after login

I mean, the ES2015 specification introduces many useful but obscure, sometimes confusing syntaxes, which make it easy to be misused in single-line code. I don't want to prevent these features from being used. I hope to encourage caution to use them.

Conclusion

At every stage of the project, remember to keep the code readable and maintainable. Everything from file systems to tiny syntax choices is important. Especially in a team, it is difficult to always enforce all rules. Code review can help, but there is still room for human error. Fortunately, there are some tools that can help you do this!

  • JSHint - A JavaScript language checker to keep code error-free
  • Idiomatic – a popular code style standard, but you can deviate from
  • EditorConfig – Defines code style across editors

In addition to code quality and style tools, there are tools that can make any code easier to read. Try different syntax highlighting themes, or try using a minimap to see a top-down overview of the script (Atom, Brackets).

What do you think about writing readable and maintainable code? I would love to hear your thoughts in the comments below.

FAQs about readable code

Why must code be easy to read for humans?

The readability of the code is crucial for the following reasons. First, it makes the code easier to understand, debug and maintain. When the code is readable, it is easier for other developers to understand the role of the code, which is especially important in collaborative environments. Secondly, highly readable code is more likely to be correct. If developers can easily understand the code, it is unlikely that they will introduce errors when modifying the code. Finally, highly readable code is easier to test. If the code is clear and concise, it is easier to determine what needs to be tested and how to test it.

What makes programming languages ​​easy to read?

The language is considered easy to read if it has a clear and concise syntax, uses meaningful identifiers, and contains comments that explain the effect of the code. High-level languages ​​like Python and Ruby are often considered easy to read because they use English-like syntax and allow for clear, descriptive variable names. However, it is also possible to improve the readability of low-level languages ​​like C or Java through good coding practices such as consistent indentation, use of spaces, and comprehensive annotations.

How does the function reduce the amount of code?

The

function can significantly reduce the amount of code by allowing developers to reuse it. Instead of writing the same code multiple times, write a function once and then call it when you need to perform a specific task. This not only makes the code shorter and easier to read, but also makes the code easier to maintain and debug, as any changes only need to be made in one place.

What is the difference between machine code and high-level languages?

Machine code is the lowest-level programming language consisting of binary code that can be executed directly by a computer's central processor (CPU). High-level languages, on the other hand, are closer to human languages ​​and require that they are converted into machine code by a compiler or interpreter before execution. High-level languages ​​are often easier to read and write, and they provide more abstraction with hardware, making them easier to port between different types of machines.

How do interpreters and compilers work?

Interpreters and compilers are tools for converting high-level languages ​​into machine code. The interpreter translates and executes code line by line, which allows interactive encoding and debugging. However, this may be slower than compiling the code. On the other hand, the compiler converts the entire program into machine code before execution, which can increase execution speed. However, any code errors can only be discovered after the entire program is compiled.

What is assembly language?

Assembly language is a low-level programming language that uses mnemonic code to represent machine code instructions. Each assembly language is specific to a specific computer architecture. While it's easier to read than machine code, it's still harder to read and write than high-level languages. However, it allows direct control of the hardware, which is very useful in some cases.

How to improve the readability of the code?

There are several ways to improve the readability of the code. These methods include using meaningful variables and function names, indenting the code consistently, separating different parts of the code with spaces, and containing comments that explain the code's role. It is also important to follow the conventions and best practices of the programming language you are using.

What role does annotations play in making code readable?

Comments play a crucial role in making the code readable. They provide an explanation of the function of the code, the reasons why certain decisions are made, and how complex code parts work. This can be very helpful for other developers who need to understand and use your code. However, it is important to make comments concise and relevant and update them when the code changes.

How does highly readable code affect collaboration?

Highly readable code greatly facilitates collaboration. When the code is easy to read, it is easier for other developers to understand and engage in contributions. This is especially important in large projects where multiple developers are working on different parts of the code base. Readable code also makes it easier to get new team members into the group because they can quickly understand what the code does and how it works.

How does highly readable code affect the quality of the software?

Highly readable code can significantly improve the quality of the software. When the code is easy to read, it is easier to spot and fix errors and make sure that the code is doing what it should do. It also makes it easier to maintain and enhance the software over time, as it clearly illustrates the role of each part of the code. This can lead to more reliable, efficient and more powerful software.

The above is the detailed content of The Importance of Writing Code That Humans Can Read. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template