An article to talk about the readability of code

Expression of opinion

In the code above, do you think the implementation on the left is better or the implementation on the right is better? Is your code more like the left or the right? First of all, let me say that this example is not very good, but I think it is quite good, because this example is not extreme enough, but it can be more clear to elaborate on such a case; my point of view, which is also the point of view that continues in this article, is to tend to On the right, of course in this example, you may think that the code on the right is a bit unnecessarily complicated, while the code on the left is very concise and clear. Here is the thinking behind the point of view:

a. The code on the right is more scalable, with clear boundaries of responsibilities and rich layers ;

b. The code on the right is more popular and closer to human language ;

c. The code on the right can let you know the intention of the method faster (I will talk about it here, because the example is simple, you may think that the code on the left can also get the intention quickly, let me talk about it here 1. If the method implementation is a little more complicated, The left side is a little more difficult to understand; 2. From a glance, the intention on the right side is more direct, although the example here may be a few seconds) Although there may be some differences of opinion just after looking at it, but I think this proposition itself is still open-ended. If it is a closed-ended question, the relevant books should have clearly defined how to code it. I hope everyone can continue to read it dialectically and analyze doubts;

readability comprehension

Before talking about readability and understanding, let’s talk about refactoring first. We often do refactoring, which can take as little as a month or as long as a year. We do refactoring mainly for the following goals: 1. Let The code runs faster; 2. Make the code cleaner and more streamlined; 3. Abstract some methods and use some patterns to make the code more reusable and scalable; 4. Make the code read more smoothly; say At this point, I want to ask everyone another question. Among the above goals, which one do you think has the highest priority?

Personally speaking, when I refactored in the past, for the sake of performance, there were not many scenarios, and I didn’t refactor for the sake of simplicity. Simplification was more of an incidental gift during the reconstruction process, and it was more about the adjustment of the model. The abstraction and precipitation of methods, the sorting out of call levels, the familiar hierarchical structure: DAO layer, model layer, manager layer, biz layer and service layer. In addition, there is basically no refactoring purely for the sake of better code;

At this moment, from the development perspective of a business technical team, readability is the first priority requirement of the code;

Readability is the code’s aptitude for communicating its intent. This means that if we assume the code works as intended, it is very easy to figure out what the code does.

[Readability means that the maintainer can well see the intention of the code, and the actual code execution logic is indeed executed according to the intention that the maintainer intuitively feels]

In the past, when compilers were not so complete and intelligent, we would still consider what kind of code, what kind of syntax and calls could maximize the execution speed of the code. At that time, we really enjoyed studying it. To get some small improvements like this, I feel very "professional", but with the development of such professionalism, basically the compiler can currently do better than us, so we are more focused on how to get along with the machine. On good topics, and being completely taken over by the compiler, at this time, what we need to do more is how to communicate with the reader behind the code (it may be you or someone else);

When we iterate on development requirements now, most of the time we spend is not on writing code, but on understanding the code and the upstream and downstream code logic of this code. In the process of understanding, we may even make some curses, and then subconsciously Go check out the author ~

A word we talk about a lot, maintainability, can be reflected in how much upstream and downstream or related code we need to read when making a change. The wider the coverage, the more likely it is that we will make mistakes or miss some potential changes. The higher the probability, the lower the maintainability; from another perspective, if we make a change, the worse the readability of the code and the longer it takes, the lower the maintainability of this part of the function or module. ;

Therefore, readability is a key factor related to efficiency and stability for maintenance and iteration;

How to improve readability

When showing the point of view, we have already mentioned three aspects of the advantages of readability: language that is closer to people (popular expression), the intention of the method (clear intention), and hierarchy (hierarchy);

1. Popular expression

I think the most popular expression is that we used to have a habit of writing pseudocode before writing code. Pseudocode is a very co-worker-friendly expression in the form of code. Take a look at the following example ( Found from existing project code).

From this example, which is the most popular expression? It should be the comments 1-9, followed by the naming of the methods under each comment (because the Chinese-English translation may not be so authentic);

The most user-friendly thing in our code is the remark (but sometimes there will be accidents, if the remark is expired). The corresponding method name under the remark may not necessarily be so friendly to people. One reason is that we are not familiar with Chinese. Translating to English, how to translate it accurately and authentically is actually not easy to do, because sometimes when our translation ability is limited, we mix Pinyin + English; another reason is that when we define the method name, we do not describe the method in place. What was done was either only half-described, or the description was very abstract, and it seemed as if something had been gained, and it seemed as if one had seen but not seen;

The premise of popular expression is to have layers, abstractions, and encapsulation. Let’s talk about this in detail. You can experience this example:

Is this code considered popular? Maybe you can understand the meaning of each line, but as a whole, I don’t know what this if determines. (Of course, I cleverly gave you the annotation. In fact, the English name of this annotation is The best definition of the method that this if statement condition is abstracted into)

The definition of popular expression here covers two aspects: 1. Friendly enough so that people who read your code later can understand it, and it is intuitive and smooth to understand; 2. Accurate enough to describe what this method does. ;Furthermore, following conventions, reasonable naming of variables/methods/classes, well-defined file names, standardized formats, use of spaces and blank lines, remarks, etc. can all help others to easily read your code later. And clearly control your intentions;

2. Make your intentions clear

Clear intention is essentially a match between reality and expectations : 1. Reality: the code author is writing the specific implementation of this method; 2. Expectation: the realization that people who read the code expect in their minds when they see this method; how are the two? If it matches, then we define this code as having clear intentions and no side effects;

Side effect is a side effect, which can also be understood as whether there is entrainment behavior under a clearly defined method. This kind of thing is actually committed a lot in the code, and it is something that everyone thinks should not be committed, but more or less people do it when writing. I didn’t notice it subconsciously. Look at this example, it’s very typical:

Because we use cache and tair more often, the conventional update strategy for tair is to write back after tracing the source after the read miss, and then the name can ensure that more than 90% of them are getXXXFromCache, but the update is done inside. But coming back to this matter, if the entire team reaches a consensus, if such a consensus becomes an agreement, it may not be included in the scope of side effect, but here I am just giving an example;

The above-mentioned category belongs to the category where the name of the method does not clearly express the internal implementation of the method. There is another category, which actually belongs to the category of Functional Programming (FP itself is another field, so I will not go into details here). In FP, there are A strict requirement and specification is that the input parameters cannot be changed, and the results after multiple executions must be consistent (the process-oriented programming method based on context transfer in the framework implementation is not included in this list), take a look at the following example:

The code is relatively long, so I deleted other codes. This modification of the input parameters is relatively invisible, but it essentially violates the principles of FP. At the same time, people who will iterate later do not know this logic, and it is very easy to get into trouble, because The members of the request that are changed here may become important processing objects in the subsequent process, but if the later iteration student expects that this member variable should be consistent with the interface input parameters, he will be confused. I found that the situation was a bit beyond my imagination. At this time, I either arthas or debug;

The biggest problem with side effects is greater than inertia of mistakes, because we all believe in the design, intention and structure of the previous generation of authors when doing subsequent iterations of requirements. At this time, miscommunication of intentions will lead to exceptions and even failures. At the same time, this The problem is still very difficult to troubleshoot, because this loophole exists under the cover of inertial thinking;

3. Hierarchy

The hierarchical structure mentioned here is the code hierarchy within complex methods, not the hierarchical structure of application layers that we talked about more before. Let’s start with an example:

This method is implemented internally in freeTieClip and calls two encapsulated methods, namely make_item and add_item. Before this method, there is a traversal of shopping cart items. In fact, array_index and for loop should not belong to the same method as the latter two method calls. Level of abstraction, because the first two are direct pass through calls (can be understood as calling through .), and the latter belongs to function call, so the correct level description is as follows:

The hierarchical structure optimization method for this freeTieClip method is also very simple, which is to encapsulate a method for the first two pass through calls:

Next, if we want to add a method remove_item_by_name to delete an item from the shopping cart by name, the general logic is as follows:

So which hierarchical structure should this method be in? The possible outcomes are as follows:

From the business semantics of method naming, neither the new layer above nor the top layer are suitable. Intuitively speaking, the bottom layer should be more suitable, because the new layer below belongs to base is implemented; the final hierarchy is as follows:

The layered method described in the example can be used as a reference in practice. It does not need to be done so strictly. However, this idea is still very useful for reference. At least it gives a vague and difficult-to-define readability. Design and implementation provide a methodology;

Suggestions during implementation

The above gives some definitions and a layered method, but part of it depends on understanding, and the other part relies on practice to slowly understand and become proficient. None of them can be applied immediately, so how to quickly do something readable in practice To improve readability and identify code that needs to be improved in readability, here are a few tips, which are purely for practical operation. There may not necessarily be a theory behind them that can be endorsed;

1.Five Lines

a. Direct explanation, the method implementation should not exceed 5 lines, which is a very extreme requirement, but instead of following this specification, using this standard can identify potential code that can be optimized and help you smell the bad smell;

2.Either call or pass

a. This is similar to the layering mentioned above, but it is not as logically rigorous as layering. It is just a bottom-line identifiable logic. In Java, you can use . symbol call as the basic operation, and call specific methods, which are regarded as advanced operations. Next As shown in the figure, try to avoid two calling methods in the same method;

3.Use pure conditions

a. Pure conditions means that the operation of the condition has no additional impact. This is consistent with the requirements of fp. If you run this condition judgment multiple times, 1. the result is idempotent, 2. there is no other implicit behavior, pure judgment; no side effect;

4.if only at the start

a. If there is an if statement in the method, try to put it at the beginning of the method. If it is in the middle of the method body, then the entire if statement needs to be split into a method;

5.Stay Away From Comments

a. Staying away from comments (non-method declaration comments) is an idealistic requirement, but the logic derived from these tips is: 1. Good code can show its own role very directly; 2. Comments are time-sensitive and will change with time. It loses maintenance due to the iteration of the code, is out of date, and is incorrect; 3. A misleading and incorrect comment will have a relatively large subsequent impact;

b. Similarly, you can re-examine the annotated code blocks to see if there is room for optimization;

Combining code generation

Refactoring for readability is actually a reorganization of the code structure to make the method more cohesive and the hierarchy more reasonable. Currently, the most commonly used code generation tool in the industry is github copilot. The underlying code generation tool is based on GPT3. The strength is actually in the so-called basic method generation category. The generation of business methods should be more difficult than direct use, because the generation of business code requires an understanding of business and business. This takes into account the current various types of copilot training data sets. Say, it’s basically impossible to accomplish;

From the division of the hierarchical structure above, in fact, Copilot should be able to generate corresponding codes relatively well for the methods in the "Basic Shopping Cart Operation Layer" and "Basic Product Operation Layer" above, and it should have better capabilities. code acceptance rate, and this type of method is relatively easy to ensure the correctness of the implementation through single testing;

Based on the above, I personally feel that the coding method of the subsequent business team will produce such changes: Business technology students implement the conversion of business semantics to popular programming language semantics, which mainly includes the definition of methods (including the responsibilities of methods and the definition of functions to be implemented), the definition of methods The calling sequence (mainly oriented to business rules and requirements), method call failure or exception handling, etc., and then the internal implementation of specific sub-methods can be carried out through various code generation tools, and the corresponding single tests can be generated through the tools, maybe Going one step further later, when business products define the code execution process, technical students do not need to do programming, they only need to do debugging work to verify whether the generated code is correct.

Conclusion

As programmers, we have several requirements for the code we write: 1. Our code can run normally and meet business requirements; 2. The structure of the code you write must comply with the specifications and specifications of the current application or current architecture. Constraints, such as package specifications, naming specifications, format specifications, nesting cannot exceed 3 levels, and a single method cannot exceed 10 lines. 3. The code you write must have relatively high readability, and other programmers Can read your code very straightforwardly (this does not mean reading line by line and then guessing the business logic expressed by your code, but it is very intuitive to get the logic and design intention of your code);

Although writing highly readable code is a skill, it depends more on the atmosphere and soil, because essentially everyone should be able to write highly readable code. Sometimes it is because they do not actively realize it. , sometimes it is inertia to follow the "style" in the original system. What I personally recommend here is to implement the code for the first time and complete the self-test to meet the business requirements, then go back and immediately reconstruct your own code for readability. This The cost is relatively small and the effect is very good. If the scope of reconstruction can be slightly extended to a certain range of upstream and downstream related codes, that would be better for reference; everyone is welcome to give suggestions based on the above expressions.

Author | Jiang Danyang

Original link

This article is original content from Alibaba Cloud and may not be reproduced without permission.

OpenAI opens ChatGPT Voice Vite 5 for free to all users. It is officially released . Operator's magic operation: disconnecting the network in the background, deactivating broadband accounts, forcing users to change optical modems. Microsoft open source Terminal Chat programmers tampered with ETC balances and embezzled more than 2.6 million yuan a year. Used by the father of Redis Pure C language code implements the Telegram Bot framework. If you are an open source project maintainer, how far can you endure this kind of reply? Microsoft Copilot Web AI will be officially launched on December 1, supporting Chinese OpenAI. Former CEO and President Sam Altman & Greg Brockman joined Microsoft. Broadcom announced the successful acquisition of VMware.
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/yunqi/blog/10150848