Nov 14 2008
My Seven Rules of Coding
Many of you frequently ask me why it is that I am so fast in programming. Some of it is of course extensive background and experience, but I think that most of the reason is that I try to apply certain code patterns that help to avoid errors even during writing the code, before they can occur in practice. Because later, it always costs you more time to find and fix the bug than it costs you to add a few more standard lines while writing.
I tried to assemble these patterns in 7 rules (now called the “KiWi Coding Patterns”, you may of course also call them “Sebastians stupid misconceptions on programming”). Each of these rules is really easy to adopt and doesn’t take much time and planning from you (just minor changes in your programming style), so they should be really easy to adopt and put into practice. The rules are – with examples – written down below.
What you find below are therefore not really big issues. Each of the rules only takes a small amount of time to realise, which pays off later 100 times. You should adapt each of the rules as a general pattern that you always apply without even thinking about it.
Rule 1: Comment Your Code!
Writing comments is extremely important. A typical scenario: someone checks in a new piece of code which contains an unexpected error that someone else discovers and could easily fix. However, since the code is so complicated and undocumented, it is not easy to find out what the right behaviour would be (writing a log entry, returning a default value, …). In this situation it is absolutely necessary that the code is commented.
Another scenario: a new developer wants to write a KiWi plugin, but he has no idea how to use a certain method. A Javadoc comment at the beginning of each method could help.
Commenting not only helps others. It also helps YOU. Both, afterwards when fixing bugs, and also immediately when writing the code, because it helps you think about how your code is supposed to perform.
Here are some common commenting patterns:
- JavaDoc comment in front of each method; in the Javadoc comment, describe at least what the method is supposed to do, which arguments it takes and what values these might have, and what return values can be expected. A nice plus, particularly for complicated methods, would also be to describe how the method is expected to work like (algorithm …) so that someone else can more easily fix bugs.
- 1-line comment in front of each variable declaration; this comment should briefly describe what values this variable will hold and what it will be used for – particularly for generic types like “Object” or “List”.
- 1-line comment in front of each for- or while-loop; this comment should briefly describe what the loop does
- 1-line comment in each branch of an if-then-else or switch; this comment should briefly describe what the case is (declaratively!) and what is supposed to happen in that case
large comment in front of each “algorithm” or functional block; e.g. if you are writing a method that issues several queries and merges the results afterwards, describe before each query in several lines what the code is going to do.
Rule 2: Check your Arguments
Most bugs (I would guess 80%) stem from not properly checking all possible values of a variable (especially arguments passed in from somewhere else) when writing the code. Sometimes this is not easy or not even possible, but most of the time it is just laziness which costs 100 times the time afterwards when trying to fix the bug.
So the general rule is: when doing something with a variable, consider all values that variable might have. For values that you consider errors, write some error handling code. If you don’t know how to handle the error, at least write an explanatory message to the log file!
A little anecdote is from the Linux kernel. For many years, it contained a logging statement that said “warning: printer is on fire”. It was issued upon a certain signal from the parallel port that could in principle occur (so a possible variable state), but actually never did (it was meant for 1970s printers who actually could start burning!). The message is: the kernel programmer did a good job because he considered a case that could occur even though he did not really know when it would occur.
Typical scenarios when this happens is when working with collections, when working with strings, and when working with objects that might or might not be null. Examples:
- You have some object passed as argument (or worse: injected into the component), e.g. a User, and you want to print out the first and last name (or call any other method). In this case you should always take into account that the value of the parameter might also be null. Example: Instead of
public void printName(User u) {
System.out.println(u.getFirstName() + " " + u.getLastName());
}
you should always (few exceptions!) write:
public void printName(User u) {
if(u != null) {
System.out.println(u.getFirstName() + " " + u.getLastName());
} else {
System.out.println("unknown user");
}
}
- You have a list, e.g. passed as argument and want to get one of its elements. For example, a method could look as follows:
public void processList(List list) {
Object o = list.get(0);
}
The problem here is that you do not know whether the list contains an element at all, even if it does in your test cases! So when working with lists, always do the following pattern (adapt as necessary):
public void processList(List list) {
if(list != null && list.size() > 0) {
Object o = list.get(0);
} else {
log.error("processList: list was empty");
}
}
- You have a string that you need for further processing. In this case you would often check both, whether the string is null and whether it is empty. The common pattern is
if(s != null && !s.equals("")) {
...
}
Rule 3: Write Self-Documenting Code
Even when comments are there it is still necessary to keep your code readable and as self-explanatory as possible. Sub-rules are therefore:
Rule 3a: keep code as simple as possible
because simple is easier to understand and less error-prone; always try to find a simple and nice-looking solution as early as possible
Rule 3b: modularize your code if it is too complex
because several functional modules are easier to understand
Rule 3c: properly name your variables and methods
a variable named “result” is always better than a variable named “x” apply a common naming convention, and adopt the Java conventions when writing Java code
Rule 3d: use formatting and indenting to make your code readable
written by others.
Practically, this means: don’t add connecting code to someone else’s methods if it is not strictly necessary and could be solved by other means.
Rule 5: Consider and Test All Cases
As programmers, we tend to test only with cases that seem sensible to US. But be aware that non-programmers don’t have the same sense of “sensible”. When programming, you often adopt a certain set of test cases that you always run, but sometimes open your mind and try something else,
something “naive”.
Example: in a project we had to implement a search engine for a news website, and it ran well in all search tests. The problem was, that every test was done with very specific search criteria (e.g. searching for the
name of a person), but as soon as you searched something more general (like “Salzburg”) the performance broke down to the point where it was unacceptable – simply because the search returned so many results that even sorting them would take too long.
The message is thus: always consider and test all cases, even if you think that they will never occur. Make an informed choice: try to think about situations where your algorithm will fail and test them.
Rule 6: Use Logging Extensively
Modern Java frameworks provide really simple and very efficient and fine-grained ways to send debugging, information, warning, or error output to either the console or to some logfile. Make use of it extensively, because it helps others to figure out what is happening, and use sensible logging messages.
Logging can be configured in certain configuration files. Learn how to use them to get fine-grained control over what is logged and where it is logged. Most frameworks let you configure logging to the class level, so I can say that I want debugging messages for a certain class, but only warnings for all other code.
Use logging correctly so that it provides no performance penalties. Many frameworks (like Seam) make this very easy, because they provide parameter substitutions. Remember that Java uses eager evaluation for method parameters, so a logging statement like
log.debug(“processed object “+object.toString()+” in ” + (System.currentTimeMillis() – start) + “ms “);
is computationally expensive even when it is not shown because debugging is turned off. The reason is that String concatenations are still calculated even if the method debug() does not do anything. In many frameworks (like Seam) you can instead use:
log.debug(“processed object #0 in #1ms”, object.toString(), System.currentTimeMillis() – start);
to avoid expensive computations. Most logging frameworks also allow to pass Exceptions as arguments, which causes the exception to be properly printed to the logfile.
Rule 6a: A corrollary to the rule is: don’t use System.out.println when it is not strictly necessary (because no logging is available). Compared to logging, System.out.println is not configurable and plainly annoying, because it cannot be turned off.
Rule 7: Learn what your Framework can do for you
When programming Java, you are always surrounded by and using many frameworks. At the very least, it means the Java API, which already contains an abundance of functionality that can help you achieve things more easily. Often, you can also make use of many additional frameworks like Apache commons, Java EE,
Seam, Hibernate, …
Learn your frameworks in-and-out, because many things have already been solved by others. Have a good overview over the Java API and look there whether certain core functionality (collections, string manipulation,
concurrency, etc) are already provided. Personally, I always have my browser open pointing to the API docs of the frameworks I am using.
Particularly, have a look at the different Java collections (in java.util) and learn their different properties (read and update performance, memory consumption).
In KiWi, it also means that you should read the “Seam in Action” book until the end, just to get an idea what Seam can already do for you.
No responses yet

