A short list of language independent tips to make your coding life easier. And that of everyone working with you.
Every tip is meant to be just that: a tip. This is neither a rule book nor a style guide.
If you disagree with something, that's fine. But please challenge your convictions. Why do you disagree? How is your way superior? And as soon as you can phrase it, please don't keep it to yourself. We're all never to experienced to learn something new.
- Always Comply to the Existing Code Style
- Always Be Consistent
- Choose Clear and Simple Semantics
- Prefer Many Short Functions Over a lot of Indent
- Don't Try to Foresee the Future
- Comment Only What The Code Cannot Say
- Write Documentation
- Break Lines at ~80 Columns
- Test
- Write Good Commit Messages
Code style is how code is formatted.
And that matters because it delicately affects how understandable source code is. After all, we write code for humans. Not for machines.
Now, there happen to be many (for the purpose of this document) equally good ways to format source code.
The important thing is to always be consistent and stick to the one you chose or encounter.
Mixing different styles quickly leads to chaos. To keep things in good shape, take the time to understand the chosen naming conventions, white space, brace style, and so on before making changes.
For example, look at this snippet:
public class ArgumentsCrossSum {
private static int crossSum( String s )
{
int sum = 0;
for( int i = 0, l = s.length(); i < l; ++i )
{
sum += (int)s.charAt( i );
}
return sum;
}
public static void main(String[] args) {
int sum = 0;
for (int i = args.length; i-- > 0;) {
sum += crossSum(args[i]);
}
System.out.println(sum);
}
}
Do you see the problem?
While the class and main() is formatted in 1TB style (the opening curly brace is at the end of a line) using a tab character to indent, crossSum() uses the Allman style (where the opening curly brace is at the beginning of a line) with 2 spaces indent.
Now, where would you put the opening brace if you were to extend this program? And what will the next maintainer do? What will this code look like after many changes?
If you don't care and put in code with your favorite style ignoring whatever is there, you're simply sabotaging the understandability of a project. Don't do that.
Sticking to a typographic convention improves readability.
Reading source code means following thoughts. Using different conventions for the same thing breaks focus and makes understanding harder.
For example, if a project uses camelCase, don't use underscores:
public class ArgumentsCrossSum {
private static int cross_sum(String s) {
int sum = 0;
for (int i = 0, l = s.length(); i < l; ++i) {
sum += (int)s.charAt(i);
}
return sum;
}
public static void main(String[] args) {
int sum = 0;
for (int i = args.length; i-- > 0;) {
sum += cross_sum(args[i]);
}
System.out.println(sum);
}
}
What naming convention would you use for the next method here? And what will that program look like after a couple of people contributed to it?
For more profound arguments about consistency please have a look at Notes on Programming in C.
The more public a symbol is, the more verbose it should be.
This is bad:
public class AXSum {
private static int cs(String s) {
int sum = 0;
for (int i = 0, l = s.length(); i < l; ++i) {
sum += (int)s.charAt(i);
}
return sum;
}
public static void main(String[] args) {
int sum = 0;
for (int i = args.length; i-- > 0;) {
sum += cs(args[i]);
}
System.out.println(sum);
}
}
Do you think you know what AXSum and cs() stands for in a year from now?
It's best to design functions and methods, even when private, as if they were an API.
Finding semantic names is very important. Take the time to really pin it down. Yes, it will be hard. But it's worth the effort.
Don't use meaningless names such as MyClass, myVar, CustomClass and things like that. Always use descriptive names. What is this object for? What does this function return?
And please use english only. Using any other language will make your names and your code inaccessible to someone. All the syntax is in english. Don't mix in foreign names.
It's always better to break a problem into many small parts. Small parts can be reused, isolated, combined and separately tested.
Choosing a few, big functions makes a solution also prone to side effects from higher level structures. Look at that:
public class ArgumentsCrossSum {
public static void main(String[] args) {
int sum = 0;
for (int i = args.length; i-- > 0;) {
int argSum = 0;
for (int c = 0, l = args[i].length(); c < l; ++c) {
sum += (int)s.charAt(c);
}
sum += argSum;
}
System.out.println(sum);
}
}
The innermost loop not only knows its own counter variable c but also that of the enclosing loop i. As we have seen in previous examples, that is neither necessary nor desirable. It's a lot more easy to make a mistake and mess with i.
So, as a rule of thumb, if you need more than 3 levels of indent in a function, you should think about breaking up your code into smaller functions.
Trying to foresee the future can lead to very complex programs. Almost always unnecessarily complex for the task at hand. And eventually, not as flexible as intended.
Don't try to do too much. Just solve the problem at hand.
The simplest approach is always the best to start with. Focus on data structures and write simple code.
For example, would ArgumentsCrossSum benefit from using a public CrossSum class instead of just a private static method?
public class CrossSum {
public int sum(String s) {
int sum = 0;
for (int i = 0, l = s.length(); i < l; ++i) {
sum += (int)s.charAt(i);
}
return sum;
}
}
public class ArgumentsCrossSum {
public static void main(String[] args) {
CrossSum crossSum = new CrossSum();
int sum = 0;
for (int i = args.length; i-- > 0;) {
sum += crossSum.sum(args[i]);
}
System.out.println(sum);
}
}
Now one can derive other variants of the CrossSum algorithm without touching ArgumentsCrossSum. Fine, but what are the chances we're going to need that?
Don't make things more complex than they really need to be.
Every dependency and everything that's beyond the simplest solution is a burden of your project.
Write clear and readable code. Use semantic names. And explain what you think cannot be immediately clear to someone else.
Add few, but meaningful comments.
Don't explain the obvious:
// add 1 to i
i = i + 1;
Explain intent, not action.
Try to be as sharp as you can. Give context. And use English only. Using any other language will add unnecessary constraints.
A bad example:
/**
* my class
*/
public class ArgumentsCrossSum {
/** crossSum */
private static int crossSum(String s) {
// initialize sum to zero
int sum = 0;
// add up all characters in string s
for (int i = 0, l = s.length(); i < l; ++i) {
sum += (int)s.charAt(i);
}
// 返回字符的总和
return sum;
}
public static void main(String[] args) {
// initialize sum to zero
int sum = 0;
// run crossSum for every argument
for (int i = args.length; i-- > 0;) {
// add cross sum to general sum
sum += crossSum(args[i]);
}
// print sum to system out
System.out.println(sum);
}
}
That's obviously a lot of clutter that doesn't make the program easier to understand. There's no information the code doesn't already tell.
This post contains a good example.
Another common misconception is, that comments are best displayed grayed out. If we use comments for important information only, we would like that information highlighted instead of tuned down.
Describing your application or interface puts you in the shoes of a user.
You'll quickly realize what's the best design for your specific problem. From a user's perspective.
For this reason, it's a good idea, to write the documentation first.
At the very least you should always write a README file that says what your code does, how to use it and how to install it.
And don't forget to give samples.
Very long lines make a reader loose context between long and short lines.
So instead of something like this:
System.out.println("Line #"+line+" "+name+":"+module+" "+shortMessage+" ("+longMessage+")");
Prefer this:
System.out.println( "Line #"+
line+" "+
name+":"+
module+" "+
shortMessage+" ("+
longMessage+")");
Here, a glance is enough to see what's going on. Don't be afraid to add lines. The code is there in any case and packing it into fewer lines won't make it more readable.
But why wrap at around 80 columns?
80 columns are common ground. 80 columns fit (almost) everywhere. On a web page, in a forum, on most screens, even small ones, like smartphones (you've probably heard mobile is a thing right now), and also in your super fancy IDE with all its side pannels open.
Takeaway: Not breaking lines simply makes your code harder to follow.
The universe will make anything fail you did not test. True story.
Commit messages are part of a history. Messages like
did something
are completely meaningless. Imagine browsing through a commit history with commits like that. Would that be useful?
So take the time to write what you changed. Think of yourself going to your project's history. Would that message tell you what you have changed? A year from now?
Unfortunately, it seems to be a good kept secret, that commit messages do actually have a format.