Pay attention, this article teaches you how to write code that your colleagues can’t maintain! Author: xybaby, original: https://www.cnblogs.com/xybaby/p/11335829.html

Write clean code, is the pursuit of every programmer. Clean Code points out that in order to write good code, you first need to know what is dirty code and what is clean code. Then it takes a lot of deliberate practice to really write clean code.

WTF/ MIN is the only measure of code quality, and Uncle Bob calls bad code wading in his book, which only highlights that we are victims of bad code. There is a more appropriate domestic term: shechan, which is less elegant but more objective, in which programmers are both victims and perpetrators.

Here’s what the masters say about clean code:

  • Bjarne Stroustrup: elegant and efficient; Be direct; Reduce dependence; Do one thing well

  • Grady Booch: Simple and direct

  • Dave Thomas: Readable, maintainable, unit tested

  • Ron Jeffries: No repetition, single responsibility, Expressiveness

My favorite description is Expressiveness, which seems to express what good code is all about: a straightforward depiction of the code’s function, no more, no less.

The Art of Naming

Naming is, frankly, a hard thing to do, and it takes a lot of work to come up with a name that’s just right, especially since our native language isn’t the programming language of English. But it’s worth it. Good naming makes your code more intuitive and expressive.

Good naming should have the following characteristics:

Worthy of the name

A good variable name tells you: what is it, why it exists, and how to use it

If a variable needs to be explained through comments, then it’s not worthy of the name first.

To avoid misleading

  • Don’t cry crow and sell crow

  • Do not overwrite idiomatic abbreviations

I have to make fun of the code I saw two days ago that uses L as the variable name. What’s more, user is a list.

Meaningful distinction

Code is written for machine execution as well as human reading, so concepts must be differentiated.

  • Use spoken words

If you can’t pronounce the name, you’ll be talking like a silly bird

  • Use names that are searchable

The name length should correspond to its scope size

  • Avoid mental mapping

Write temp in your code, for example, and the reader will have to translate the word into its true meaning every time he sees it

annotation

Expressive code doesn’t need comments.

The proper use of comments is to compensate for our failure to express ourself in code.

The proper role of comments is to make up for our failure to express intent in code, which sounds frustrating, but it’s true. The truth is in The code. Comments are only second-hand information. The biggest problem with comments is that they are not synchronized or not equivalent.

The book gives a very good example of this: use code, not comments

bad
// check to see if the employee is eligible for full benefit
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))

good
if (employee.isEligibleForFullBenefits()) Copy the code

So, when you want to add comments, think about whether you can show the intent of the code by changing the name, or by changing the abstraction level of the function (code).

Of course, one should not give up eating for fear of choking, and the book points out some good notes

  1. Legal information

  2. Comments on intentions, why do they do that

  3. warning

  4. TODO comment

  5. Magnify the importance of the seemingly irrational

Among them, I agree with the second and fifth points most. It is easy to name what to do, but why to do it is not intuitive, especially when it involves expertise and algorithms.

In addition, some code that at first feels “less elegant” may have a particular desire, and such code should be annotated to explain why it is so, such as that readability may be sacrificed in order to improve critical path performance. 7 Tips to write elegant Java code! You can also read this one.

The worst comments are outdated or wrong, which is a huge disservice to the maintainer of your code (and perhaps to yourself in a few months), but there is no easy way to keep your code in sync with comments other than code review.

function

The single responsibility of the function

A function should only do one thing, and that should be clear from the name of the function. The way to determine this is simple: see if the function can take apart another function.

A function either does something do_sth or queries something query_sth. The nasty thing is that the function name says it only knows query_STH, but it actually knows do_STH, which causes the function to have a side effect. Take the example in the book

public class UserValidator {
    private Cryptographer cryptographer;
    public boolean checkPassword(String userName, String password) {
        User user = UserGateway.findByName(userName);
        if(user ! = User.NULL) { String codedPhrase = user.getPhraseEncodedByPassword();  String phrase = cryptographer.decrypt(codedPhrase, password);  if ("Valid Password".equals(phrase)) {  Session.initialize();  return true;  }  }  return false;  } } Copy the code

The level of abstraction of a function

Each function has one level of abstraction. Statements in a function must be at the same level of abstraction. Different levels of abstraction cannot be grouped together. For example, if we wanted to put an elephant in the refrigerator, it would look like this:

def pushElephantIntoRefrige():
    openRefrige()
    pushElephant()
    closeRefrige()
Copy the code

The three lines of code inside the function describe three sequentially related steps at the same level (height) to complete the task of putting the elephant in the refrigerator. Obviously, the pushElephant step might have a number of sub-steps, but at the pushElephantIntoRefrige level, you don’t need to know much about the details.

When we want to learn about a new project by reading the code, we typically take a breadth-first approach, reading the code from the top down, first understanding the overall structure, then delving into the details that interest us.

If the implementation details are not well abstracted (and condensed into a function worthy of the name), the reader can easily get lost in the details.

In a way, this is similar to the pyramid principle

Each level is designed to support the ideas of the next level; Multiple arguments at the same level need to be sorted by some logical relationship. PushElephantIntoRefrige is the central argument, which needs to be supported by multiple sub-steps and a logical sequence of these sub-steps.

Function parameters

The more arguments a function has, the more input situations it can combine, the more test cases it needs, and the more likely it is to have problems.

Output parameters are hard to understand compared to return values, so output parameters are very unintuitive. From the point of view of the function caller, the return value is obvious at a glance, but the output parameters are difficult to identify. Output parameters often force the caller to check the function signature, which is really unfriendly.

It’s usually not a good idea to pass a Boolean (called a Flag Argument in the book) to a function. Especially if the behavior after passing True or False is not two sides of the same thing, but two different things. This clearly violates the function’s single responsibility constraint, and the solution is simply to use two functions.

Dont repear yourself

At the function level, where reuse is easiest and most intuitive, many ides have trouble refactoring a piece of code into a function.

In practice, however, it is possible for a piece of code to be used in multiple methods, but not exactly the same, and if it is abstracted to a generic function, then arguments and if else distinctions are required. It’s a little awkward, it’s refactoring, but it’s not perfect.

Part of the problem is that the code also violates the single responsibility principle and does more than one thing, which makes it difficult to reuse. The solution is to subdivide the method to make it easier to reuse. You can also consider the Template method to handle the differences.

test

It’s a shame that I’ve been on projects where testing (especially unit testing) has not been given enough attention and TDD has not been tried. Because of the absence, a good test is all the more valuable.

We often say that good code needs to be readable, maintainable, and extensible, and good code and architecture needs to be constantly refactoring and iterating, but automated testing is the basis for all of this. Without high coverage, automated unit testing, and regression testing, no one will be able to change the code, leaving it to rot.

Even when unit tests are written for core modules, they are generally considered to be test code, not production code, as long as they work. This leads to poor readability and maintainability of the test code, which in turn makes it difficult for the test code to update and evolve along with the production code, which in turn makes the test code invalid. So, a dirty test — is the same as — no test.

Therefore, test the three elements of code: readability, readability, readability.

The principles and guidelines for testing are as follows:

  • You are not allowed to write any production code unless it is to make a failing unit test pass. Don’t write any functional code without first testing it

  • You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures. Write only the test code that reflects exactly one failure

  • You are not allowed to write any more production code than is sufficient to pass the one failing unit test. Only write functional code that just happens to pass the test

FIRST criteria for testing:

  1. Fast, “Fast,” tests should be Fast enough to be automated.

  2. Tests should be Independent. Don’t rely on each other

  3. Repeatable tests should be Repeatable on any environment.

  4. Self-validating tests should have bool output. Do not look at the log as an inefficient way to determine whether a test has passed

  5. Tests should be written in time, before their corresponding production code