Skip to content

Instantly share code, notes, and snippets.

@markusfisch
Last active June 29, 2019 00:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save markusfisch/ead39700f8a2c79e3e30 to your computer and use it in GitHub Desktop.
Save markusfisch/ead39700f8a2c79e3e30 to your computer and use it in GitHub Desktop.
Practical Coding Tips

Practical Coding Tips

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.

In a nutshell

Always Comply to the Existing Code Style

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.

Always Be Consistent

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.

Choose Clear and Simple Semantics

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.

Prefer Many Short Functions Over a lot of Indent

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.

Don't Try to Foresee the Future

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.

Comment Only What The Code Cannot Say

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.

Write Documentation

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.

Break Lines at ~80 Columns

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.

Test

The universe will make anything fail you did not test. True story.

Write Good Commit Messages

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment