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
- The Code Clean Way – chapter 17