How to improve code taste

We can discuss it in the comments

While most of the time writing code is manual work, it does, admittedly, require a little taste. I used to think that code quality was important, but then I wrote a lot of business, and I felt that if I couldn’t get the code right, I wouldn’t care about code quality. Then I came to realize that it is hard to have bug-free code in the world, and when bugs occur, good code is much easier to change than bad code. Today we will discuss what is good code, after all, a person who does not know what is good code can not write good code with the help of god. To write code, you can search, copy and paste three sticks, but to write good code must be deliberately practiced.

What is writing code

I think there are two parts to writing code:

  • Structural design, including module division, module interaction, interface design
  • Function realization, involving specific language features and code style

The structure design

Structural design does not necessarily mean drawing an architectural diagram or writing a departmental document. Structural design and functional implementation spiral through the whole process of writing code. When we are ready to complete a requirement, we divide the requirement into several functions. If these functions are independent of each other, they do not involve interaction, otherwise they need to communicate with each other, whether it is direct invocation, whether it is sending messages, whether it is listening for changes, whether it is polling for results, etc. Once you’ve split up the functionality, you need to implement one of those functionality, and then recursively do the same thing again until you write lines of code. Some students may think that this top-down process is too macro, and it takes too much time in the early stage. I will pick a function and write the code first. That’s ok, and most people do it. But it’s also about structural design, the function that you’re going to implement first, that you’ve subconsciously isolated from the whole system, just the rest of the system for the time being. Module partitioning is a terrible topic, but it is the essence of software engineering. It is important to understand that there is a limit to the ability of people to manage complexity, and that when large chunks of code are dislodged, even if the code is of the highest quality and the most well-commented, it will cause physical discomfort. This discomfort is most likely to happen when you’re trying to change a small feature and you can’t find the code for a long time. Once you split it up, even if it’s a bunch of bad code, and you change only one file, the rest of the code is out of sight and out of mind.

How are modules divided? There are some general principles, such as high cohesion and low coupling, the single responsibility principle, the open closed principle, and so on, but these things feel too obvious and insincere to begin with. I personally think there are two very important principles:

  • Review your code structure as you develop it
  • After carefully

When it comes to rethinking code structure, the most important thing is of course your own thinking. Don’t be superstitious about other people’s design for you, and don’t be superstitious about your own design.

  • At the beginning, I divided two modules, and I wrote that I found that one of the modules was very large, so I saw if I could continue to divide
  • I started with four or five modules, and then I started writing and I realized that two of them interacted so much that they had to work together to achieve a complete function, so I put them together (high cohesion)
  • In the process of iteration, I found that although the two modules are independent of each other, the interaction logic is very dead, and the dependency relationship is very direct. If one module is modified, the other must also be changed, so modify their dependency and interaction, and try to do not affect each other (loose coupling).
  • During iteration, if you find parts of the two modules that can be shared, pull them out (DRY)
  • If you find that a section of code in a module changes frequently during iteration, isolate that section (encapsulate the changes)
  • .

Of course, the list goes on and on, but the team can actually set some hard criteria to help module division, such as a maximum of 300 lines for a file, a maximum of 70 lines for a function, etc., in Lint rules. We have a lot of conventional “unspoken rules” actually have its logic behind, for example, before every day said MVC and MVVM two modes, the main difference between them is not module division, but the interaction between modules, in the division they are committed to make UI and logic separate, why? Because UI is cheap, UI will be overthrown and replaced by designers every once in a while, but logic and data are relatively stable, so if they are separated, UI iteration will involve less change. Why do React/Vue frameworks advocate so-called components, which seem to integrate UI and logic? In fact, it is not, the component is a small granularity module, it is relatively independent, with high cohesion, the “logic” in the component should be more UI-related interaction logic, rather than those relatively low level logic, we should still pull out the relatively stable logic into the lower level.

About naming, many students may not care, think that the code can run on the line, what is the name of the relationship, do not understand me to add comments. This is a very bad habit, because the naming process is a generalization of your code. If you have a function named xxxAndxxx that should be split into two functions, it clearly violates the single responsibility principle. Anything from a business module to a helper function that you don’t feel comfortable naming is a sign that the code is doing too many things that you can’t summarize in just a few words.

Function implementation

Now let’s talk about how to reflect code taste when implementing code. I think there are two main points to improve:

  • Be proficient in your programming language
  • Improve your logical ability
  • Focus on code Style

There is a widely held belief that programming ideas matter most, and that languages are only tools. At first glance, programming languages seem trivial. If it’s just a one-shot deal, writing a piece of code to implement a feature, writing it and leaving it, then the language doesn’t matter. I believe most of the digital agriculture can quickly learn a new language, because in order to achieve a function may only need some of the core features of the general to the C language, know function/loop statement/statement/string array/hash the use of these things is enough to develop daily demand, and these features the truth chase small variations in C language. But if you want to write good code, you have to work toward mastering the language. Some features you can write a bunch of crappy code to do just fine, but with a feature, a few lines of snappy code will do the trick. I hate the idea that, in order for everyone on the team to understand it, only basic features of the language are encouraged to be used, and advanced or less common features are not allowed to be used. To take an extreme example, if else is more readable than a ternary expression and is encouraged to use only if else. Such “readability” seems to me to be pandering to mediocre programmers. Some language features do have advantages and disadvantages, some even only disadvantages (JS is very common), that try not to use, or according to the actual scene to make a choice. It should be the scene, not the person, that counts. What is a suitable scenario? Take a ternary expression for example:

const data1 = a > b ? 100-200; const data2 = a > b ? 300-400;Copy the code

This code is only two lines long, but the condition a > B should be judged twice, and we don’t care about the performance (a > B is just an example, the actual condition may be more complicated). At least it has been repeated, write twice when writing, and read twice

let data1 = 200;
let data2 = 400;
if (a > b) {
    data1 = 100;
    data2 = 300;
}
Copy the code

(This optimization is not for performance, because some language compilers do optimizations like this at compile time, but mainly for readability.)

const condition = a > b; const data1 = condition ? 100-200; const data2 = condition ? 300-400;Copy the code

Code should be concise, but not short (fewer lines of code). Concise means clear logic and no redundant information. Another scenario I’ve seen students use nested ternary expressions instead of multiple if and else operations is really unreadable. Don’t do that.

There are some specific techniques for this, such as my personal preference for using hash tables instead of branching statements:

// if (key === 'x') return 'xxx';
// if (key === 'y') return 'yyy';
// if (key === 'z') return func;

const xxxMap = {
    x: 'xxx',
    y: 'yyy',
    z: func
};
return xxxMap(key);
Copy the code

This approach seems to have a name called “table driven design”, this has a lot of advantages, code simplicity is one point, this xxxMap is actually a configuration table, can be pulled out in a separate place, or even on the server to configure, you can easily achieve some dynamic requirements. More extension open to speak, can configure the things as far as possible are configured, convenient later expansion function.

Words matter. What about ideas? Of course. In our daily life, people with clear logic can hit the nail on the head in a few words, while people with confused logic can go round and round in a cloud or a fog. The same goes for code. Some bad code is bad, and it may have to do two or three different things about what it can do. In this way, the idea is not concise, write out the code is not concise, can only try to improve their logical ability.

The rest of the code style is also very important. Good looking people are privileged, so is good looking code. Take a look at the official or large factory Style Guide, usually pay more attention to the space newline indent naming Style and so on, install a good formatting plug-in.

Almost so first, taste is not good or bad, but there are high and low, mutual encouragement.