The introduction

The more code I wrote, the more I wrote, the more I wrote, the more I wrote, the more I wrote, the more I wrote, the more I wrote, the more I wrote, the more I wrote, the more I wrote, the more I wrote.

So after reading this book “code clean way”, found a lot of benefit, the book in the last chapter of the enlightenment posted, used to remind myself of the future coding requirements ~


Revelation (Rules of engagement)


Reduce the presence of multiple languages in a source file

This problem should exist in the past JSP development, now are generally separated from the front and back end, back-end code, there is basically no front-end code


To implement the behavior corresponding to the function name

Following The Principle of Least Surprise, a function or class should behave as it can reasonably be expected.


Be explicit about boundary behavior

Trace each boundary condition and write tests. All code is required to have unit tests. This condition is very strict. The main thing to pay attention to should be in production code, pay attention to business boundaries, avoid NPE, array out of bounds errors, etc.


Don’t neglect safety

Security is not just about boundaries and unit testing, but also about infinite loops and thread safety.


Avoid duplicate code

This is what we call glue code, where we copy a copy to another place. Every time you see duplicate code, you’re missing an abstraction.

Repetitive code can be abstracted to a higher level, or encapsulated as a public method, used in many places, as a static method of a utility class, and so on.

Learned design patterns, chains of responsibility, templates, abstract factories, and so on can be used to eliminate duplicate code


Code at the right level of abstraction

Create abstract classes to hold higher-level concepts and derived classes to hold lower-level concepts.

At the same time, it should be noted that lower and higher level concepts should not be mixed and the separation should be complete.


Base classes should not depend on derived classes

The most common reason for splitting concepts into base and derived classes is that higher-level concepts can be independent of lower-level derived class concepts. (That is, the base class should know nothing about the derived class and not mention its name).


Avoid information overload

Well-designed modules keep interfaces simple.

Limit the number of interfaces exposed in a class or template, reduce the number of methods in a class, and reduce the number of variables in a function. (Of course, if the business is complex, simple variables may increase, in this case, a new parameter class should be created to encapsulate the parameters).

Keep the interface as compact as possible and control the coupling degree by limiting the information.


Delete dead code

Some methods may not be called after code changes, and the path will not be reached. Now it is very convenient for the IDE to see if the method is called. When you see code that will never run, consider removing it


Vertical separation

Variables and functions should be defined close to where they are used.

Local variables should be named exactly where they were first used, with a short vertical distance.

Private functions should be defined just below where they are used.


Be consistent

All the time. Choose conventions carefully, and once selected, follow them carefully.

For example, if HttpServletRequest Request is selected, all parameters are named according to Request, making the code easier to read and modify.


Reduce artificial coupling

Things that are not interdependent should not be coupled.

Do not couple two modules that have no immediate purpose, such as putting variables, constants, or functions in the wrong place. Ordinary enUms should not be in special classes.


Reducing feature dependencies

Methods of a class should be interested only in the variables and functions of the class they belong to, not in the variables and functions of other classes.

When a method operates on the internal data of another object through its accessors and modifiers, it is attached to the scope of the object’s class. (Of course, in business development, it is common to encounter conditional judgments and then modify the value of an object’s attribute. I think this scenario is normal, but the following example should be avoided.)

Bad Example: In class B methods, you basically rely on class A attributes

public class HourlyPayCalculator {
    public Money calculateWeeklyPay(HourlyEmployee e) {
        int tenthRate = e.getTenthRate().getPennins();
        int tenthsWorked = e.getTenthsWorkeds()
        int straightTime = Math.min(400, tenthsWorked);
        int overTime = Math.max(0, tenthsWorked - straightTime);
        int straightPay = straightTime * tenthRate;
        int overtimePay = (int) Math.round(overTime * tenthRate * 1.5)
        return newMoney(straightPay + overtimePay); }}Copy the code

As you can see, the salary calculation method of the HourlyPayCalculator class above intrudes into the scope of the hourly worker class E.

It now seems more likely that this method should be sunk into the HourlyEmployee class and allowed to operate on properties in its own class (although this didn’t feel wrong before, it will change later).


Avoid selector functions at the end of a function

Personally, it should be to divide the complex selection operator function into multiple sub-functions, and then make the intention of the function clearer by combining calls.


Avoid obscure intentions

Code should be as expressive as possible.

When I was writing Android code, I saw Hungarian markup syntax and row notation, such as m_/f_ prefixes. Now I think these prefixes are a bit redundant, and I also need to reduce the magic number. After all, if YOU write a number 5, no one except the developer will be able to understand the actual meaning of the 5


Use explanatory variables

An example will help you understand:

Matcher match = headerPattern.matcher(line);
if (match.find()) {
    String key = match.group(1);
    String value = match.group(2);
    headers.put(key.toLowerCase(), value);
}
Copy the code

Do feel variables speak? Key and value make sense at first glance, in which case there is no need to comment


A function name should express its behavior

The following should be eliminated:

Date newDate = date.add(5);
Copy the code

Function name add(int), can not express its meaning, is the day or month increment by 5, so these ambiguous function names should be eliminated.


Understand the algorithm

The algorithm here is to make sure that you understand how the function works, and based on that, modify or refactor it.


Replace If/Else or Switch/Case with polymorphism

If/Else~ (^o^)/~) If/Else~ (^o^)


Replace magic numbers with named constants

To avoid hard-coding numbers in your code, write a constant number in a static variable at the top of the class, or abstract an enumeration to explain what the number means.


Encapsulation condition

Encapsulate the judgment in the if expression (which is easy to slack off on condition =-=) :

For example: if (shouldBeDeleted(timer)) is better than if (timer.hasexpired () &&! timer.isRecurrent())


Avoid negative conditions

For example: if (buffer.shouldCompact()) is better than if (! buffer.shouldNotCompact())


The function should only do one thing

A function that does only one thing is a bit difficult. You can split a function into several smaller functions, such as the payroll function. You can split a large method into three smaller methods, such as getting people, calculating wages, and sending money to a bank account, so that these small methods can be reused by other methods.


Masking timing coupling

It is often necessary to use temporal coupling, where the results of the previous step are handed over to the next step, and the timing between them should not be obscured.

Such as:

public class MovieDiver {
    Gradient gradient;
    List<Spline> splines;
    
    public void dive(String reason) { saturateGradient(); reticulateSplines(); diveForMoog(reason); }...}Copy the code

The code for the Dive () method does not emphasize sequential coupling, and if other developers transpose the execution order, the Dive method will not execute properly.

It can be updated to the following form:

public void dive(String reason) {
    Gradient gradient = saturateGradient();
    List<Spline> splines = reticulateSplines(gradient);
    diveForMoog(reason);
}
Copy the code

This exposes sequential coupling by creating sequential queues.


Package boundary condition

This rule is similar to encapsulating judgment conditions, but it also applies to encapsulating variables: for example, encapsulating level + 1 that occurs twice into a variable

int nextLevel = level + 1;
if (nextLevel < tags.length) {
    parts = new Parse(body, tags, nextLevel, offset + endTag);
    body = null;
}
Copy the code

Place configurable data at a higher level

Variables are defined at the beginning of the class. Do not define common variables after functions.


Function names should indicate function side effects

Such as:

public ObjectOutputStream getOos(a) throws IOException {
    if (oss == null) {
        oos = new ObjectOutputStream(socket.getOutputStream());
    }
    return oos;
}
Copy the code

This method name just says get output stream, but it doesn’t say that it will create a new output stream if the output stream doesn’t exist, so the function name should be createOrReturnOos.


Avoid passing Tours

For example, if there are three classes A, B, and C, the following behavior should be prohibited:

a.getB().getC().doSomething();
Copy the code

The right thing to do is:

myCollaborator.doSomething();
Copy the code

Let our direct collaborators provide all required services ~~


Reference books

  1. The Code Clean Way – chapter 17