Beautify java code, starting with reasonable comments

Time:2020-2-12

Please stop code comment

“Clean code should be like written prose” – Robert C. Martin

The common problem with bad code is that there are many comments. This is the most obvious sign of messy source code.

The goal of every programmer should be to write clean and expressive code to avoid code comments. The purpose of each variable, function, and class should be implied in its name and structure.

When others read your code, they should not read comments to understand what your code is doing. Well named classes and functions should guide the reader through your code, just like a well written novel. When readers see a new class or function, they should not be confused about what they see in it.

Keep in mind that developers spend less time writing code and much more time reading and understanding code.

Notes cover up mistakes

Naming in code is very important. You should spend a lot of effort naming each piece of code accurately and precisely so that other developers can understand your code.

//Find employees by status
List<Employee> find(Status status) {
...
}

In this example, the name find is not descriptive enough, so the author of this function needs to leave a descriptive comment describing the function’s functionality. When we see the find function called from another module, its role is a mystery. What does it find? What do you mean? Did it return what it found? How to find what it found? As Uncle Bob said in his book clean code, if you need to write comments, you can’t express your real intention through code.

We don’t want to check the comments above each function to see what it does.


List<Employee> getEmployeesByStatus(Status status) {
...
}

Now it’s obvious what this function does, which makes annotations redundant. This reminds me of the next way to comment poorly.

Redundant notes

It’s confusing your code. It’s totally unnecessary.

//This function sends an email
void sendEmail() {
...
}
//This function sends an email
public class Employee {
...
}
/ **
*Title of @ param Title CD
*@ param author CD author
*Number of tracks on @ param track CD
* /
public void addCd(String title, String author, int tracks) {
...
}

In most cases, redundancy is mandatory. Many companies require this for each function and category. If your boss asks, ask them not to.

Wrong abstraction

If you have a long function or need to record what part of the code has done, you may be violating these rules:

1. Function should do one thing.

2. The function should be very small.

This is an example

//This function calculates the price and compares it with the sales volume
//Promotion, check if the price is valid, and then
//Send promotional email to users
public void doSomeThings(){
//Calculate price
...
...
...

//Add the calculated price and promotion activity to the
...
...
...

//Check if the calculated price is valid
...
...
...

//Send promotional information to users
...
...
...
}

When you successfully encapsulate each part of the logic into a separate function, the code should behave as it does without comments.

The refactoring is as follows:


public void sendPromotionEmailToUsers(){
calculatePrices();
compareCalculatedPricesWithSalesPromotions();
checkIfCalculatedPricesAreValid();
sendPromotionEmail();
}

Instead of annotating every part of the code, each logical block should be well encapsulated in its own functions.

First of all, it improvesReadability。 Each code block does not have to be read line by line. We can simply read the auxiliary function name and understand its function. If we want to know more about the inner details of each function, we can see the specific implementation.

Second, it improvesTestability。 In the example above, we can unit test each function separately. Without encapsulating these individual functions, it is difficult to test each part of the larger function sendpromotionemailtousers(). Functions that perform multiple functions are difficult to test.

In the end, it improvesReconfigurability。 By encapsulating each part of the logic into its own functions, future changes are easier to maintain, and functions with separate functions are isolated to change only the behavior of that function. When we use the long function of local variable to persist in the whole function, it is difficult to reconstruct the function without causing other changes due to the tight coupling of the function.

Commented out code

Commented out code should be considered roadkill. Don’t look at it, don’t smell it, don’t ask where it comes from, just get rid of it. The longer you keep it, the longer the rest of the code smells


/ *
public void oldFunction(){
noOneRemembersWhyIAmHere();
tryToUnCommentMe();
iWillProbablyCauseABuildFailure();
HAHAHA();
}
* /

Although delete you do not delete others are more afraid to delete. If you need it later, you can check the version control system at any time, because you must have used VCs, right? (if not when I didn’t say it)

TODO notes

Don’t write todo comments, not just… Did it? Most of the time these comments are forgotten and may become irrelevant or erroneous later. When another programmer sees the todo comment later, how do they know if they need to do it again?

But occasionally todo comments are good if you’re waiting for another teammate to merge (usually not too long). You can do this until you can fix it and submit it.

“When you think it’s necessary to write comments, first try to refactor the code so that any comments become redundant.” – Martin Fowler

The lies of annotation

When Jimmy commented on the new features he wrote, he thought he was helping any future developer who saw his code. In fact, what he is really doing is to set a trap. His note could be that the whopper (no pun intention) stayed dormant for months or years without being touched, just waiting to become a nasty trap. Then one day, in one of hundreds of refactorings and requirements changes, his comments failed from some remote modules, but still led countless takeovers by mistake.

When you change a line of code, how do you know if the code you change will invalidate comments elsewhere? There’s no way to know

public class User {
...
//It contains the user's first and last names
String name;
...
}

Then, the requirements change, and they want to split the names into firstname and LastName.

public class User {
...

//It contains the user's first and last names
String firstName;
String lastName;

...
}

The comment is now wrong. You can update comments to reflect changes, but do you really want to maintain all comments manually after each change? You’re a developer, not a document.

But the comment is easy to notice and there are no problems to change. But it’s hard to guarantee that the parameter name is the user’s first name and last name in other parts of the program. Changing a small piece of code can invalidate many code comments.

Let’s take another example:

//Process employees according to status
void processEmployees(){
...
List < Employee > employees = findEmployees(statusList);
...
}

//This looks for employees by status list
List < Employee > findEmployees(List < String > statusList){
...
}

Someone was then asked to change the function findemployees to find employees through the name list instead of the status list.

//Process employees according to status
void processEmployees(){
...
List < Employee > employees = findEmployees(statusList);
...
}

//This looks for employees by status list
List < Employee > findEmployees(List < String > nameList){
...
}

First, the above comment findemployees is no longer valid and needs to be changed. No problem, right? Wrong.

The comments above processemployees are also invalid, so they need to be changed as well. How many other comments have been invalidated by this small refactoring? How many comment lies did this change create in the source code?

Alternatives:


void processEmployees(){
...
List < Employee > employees = findEmployeesByName(nameList);
...
}

List < Employee > findEmployeesByName(List < Name > nameList){
...
}

If you name your functions accurately and accurately, you don’t need comments, and you don’t spread lies in your code.

“Code will never lie, comments will.” -Ron Jeffries

When do I need comments

I know a lot of developers are hard core supporters of code annotation, and for them, I have to admit that sometimes annotations are OK. But every paragraph you write should have a good reason

complex expression

If you have complex SQL or regular expression statements, continue to write comments. It can be difficult to express such statements cleanly in code. Adding comments to these expressions can help other developers better understand your code.

//Format matching KK: mm: SS EEE, mmm DD, YYY
Pattern timePattern = Pattern.compile("\d*:\d*:\d* \w*, \w*, \d*, \d*");

Annotation warning

If you need to warn other developers of possible bugs in this code, you can leave comments near this code. These comments can act as a harbinger of mysterious behavior in your code and add value to your code.

Intention to clarify

If you’re a real name waster, take responsibility for your inability to write expressive code, and write comments that indicate your intention.

If you have to write a comment, make sure it’s local. Non local comments far away from their references are bound to fail and become lies. Comments that reference functions or variables should be directly above them. A warning comment can be above or next to the code it references. If your ide supports highlighting comments, make your warning comments stand out from the rest of the code.

Last

I’ve developed a sense of code annotation. I despise them, but I know sometimes they need it.

So stop writing so many comments.

This article is about the author’s comments on twitter by Brian Noland, a great God of foreign countries, who thinks that they should be modified and shared after translation. I hope my code will be as elegant as prose in the future.