In this series, there are many excerpts from the book, all of which I think are worth sharing. Of course, there will also be personal reflections, as a learning record and simple to share.

Be short & do only one thing

Each function should be as short as possible so that the logic of each function is not too complicated and the cost of reading and maintenance is small. Short functions force each function to do one thing, and doing one thing at a time also forces the function to be as short as possible, so I put the two together. Imagine trying to read a function only to find that it’s hundreds of lines long. Then you force yourself to try to understand the code and realize that the logic is intertwined, a logical call to line 68 points to line 145, a logical call to line 148 points to line 47… Finally, you read through the code, worked all day, and it was worse than what I described, and you gave up trying to understand it. If the person who wrote the code followed the rule of being short and doing one thing only, this obscure function would probably become ten or more clear and concise functions.

One level of abstraction per function

What is a hierarchy of abstraction? I understand it as granularity of code logic or functionality. For example, the development process of a project is roughly as follows:

  1. project
  2. Demand for output
  3. Programming to realize
  4. release

They are all at the same level of process and are relatively easy to understand from the top down, making sense of the whole process that might be understood differently if there were other granular processes in the process.

  1. project
  2. Demand for output
  3. Programming to realize
    1. The UI determines the dominant tone
    2. To build database
    3. Front-end technology selection
    4. Create a database table
    5. The UI determines the design style
    6. Back-end technology selection

    .

As you can see, the logic is getting a little messy before we get to the development stage, but what if this is a piece of code logic? What if you nested a more fine-grained process? Therefore, ensuring that the logic within each function is a level of abstraction is essential for code understanding and maintenance. Functions with different levels of abstraction are often confusing, and readers may not be able to tell whether an expression is a basic concept or a detail. Worse, like a broken window, once the details get mixed up with the underlying concept, more details get tangled up in the function.

Down the rules

A downward rule makes code read from top to bottom, with each function followed by a function at the next level of abstraction, so that when looking at a list of functions, you can look down the abstraction level. The reader is free to choose whether to understand the main logic at the highest level of abstraction first, or to see only one part of the complete logic in isolation, and the choice is simple and without fear of getting lost.

Function parameters

The author says that the optimal number of parameters is 0, followed by 1 and 2, and 3 should be avoided as far as possible. Metrics are tricky, they are too conceptual. The meaning of parameters is not always easy to understand, and the reader needs to understand the meaning of parameters as well as the context. From a testing standpoint, metrics are even more difficult. Think about how hard it is to write test cases that ensure that the various combinations of parameters work. If there are no parameters, it’s a piece of cake. It’s not too difficult if you only have one parameter. With two parameters, the problem is much more complicated. With more than two parameters, testing to cover all possible combinations of values can be daunting. Output parameters are harder to understand than input parameters. When we read a function, we tend to think of information as input through the parameter function and output through the return value from the function. We don’t expect information to be output through the parameter. So output parameters tend to be hard to figure out.

No side effect

A side effect is a lie. A function promises to do one thing, but still does something else that is hidden. For example, wrap logic for setting global variables or page-jumping in login functions. For example, in the function to query whether a user is logged in, the package determines that the user is not logged in, and then clears the user information logic. This is risky for the caller of the function, who is probably unaware of the side effects of the function. Short at the same time it also violates the function and rules of the only do one thing, if you do so, remember to put the function name renamed loginAndSetUserInfo checkLoginAndClearUserInfo, but try not to do so.

Don’t repeat yourself

If a method or piece of logic is called in more than one place, it needs to be pulled out, reducing the size of the code and, more importantly, increasing the maintainability of the code. When the logic needs to be modified, we only need to modify the extracted function without having to change any more positions, thus avoiding the risk of forgetting to change something.

How do you write a function like that

Writing code is a lot like writing anything else. When writing a paper or essay, you write what you think first and then polish it. Your first draft may be rough and unorganized, but you can refine it until you get what you want. When I write functions, they start out long and complicated, with too many indentations and nested loops, and too long argument lists. The names are arbitrary, and there will be duplicate code, but I’ll cover every ugly line with a set of unit tests. Then I polished the code, decomposed the functions, changed the names, and eliminated duplication. I shorten and relocate the method. Sometimes I take apart classes while keeping the tests passing. Finally, FOLLOWING the rules outlined in this chapter, I assembled these functions. I didn’t write functions by the rules from the beginning, I don’t think anyone could.

Here the author describes how he wrote the code, but the whole process is the concept of refactoring, implementing the features first and using unit tests to ensure the stability of the features. The code is then refactored. It is not practical to start by following the rules of this chapter, or simply write clean code. Good code is the product of constant refactoring.

conclusion

This chapter is a systematic introduction to how to organize code logic and how to split functions, and proposes a series of rules that should be followed when writing functions, which I think is very valuable. Master programmers tell systems as stories, not as programs. They use the tools provided by the chosen programming language to build a richer and more expressive language to tell that story. By following the rules for functions in this chapter, the functions will be nicely put together and then neatly pieced together into a precise and clear language that will help you tell your story. I have a long way to go before I can tell the story, so from now on, write every function! 💪