Readability Beats Debugging
September 22, 2020
Blog
When writing code, your first priority should be readability. A lot of time is spent debugging and maintaining code, often far more than was spent writing it in the first place.
When writing code, your first priority should be readability. A lot of time is spent debugging and maintaining code, often far more than was spent writing it in the first place. So, making that process efficient is essential. Considering the needs of the human reader in the future (who might be you, of course!) is more important than trying to make the code “efficient” – that job can mainly be left to a modern compiler.
This consideration means that the code should be formatted and aligned very carefully, and language constructs should be as simple and transparent as possible. There are many published guidelines that help with these matters. However, creating readable code does not end there.
When you compile code, the programming language is translated into machine instructions. That is obvious. However, what the compiler actually receives is a stream of characters; some is actual code, but there may be chunks that are not intended to be translated and other text may be for human consumption only:
- Documentation – comments in the code
- Temporarily removed code – part of the debugging process, but it may persist
- Special debugging/tracing code
Implementation of each of these has some influence on readability.
Documentation
Everyone knows that comments are a good idea, but most of us get lazy. However, some effort is very worthwhile. The old-style /*...*/ comment notation was acceptable, but the newer end-of-line //... form is clearer. Care is still needed. For example:
int number; // input count
char c; // single character buffer
char buffer[99]; // the input line
is so hard to follow. Alignment is everything:
int number; // input count
char c; // single character buffer
char buffer[99]; // the input line
And do not use tabs; they are not portable.
Temporary code removal
During software development, it is not uncommon to want to “hide” parts of the code from the compiler – to switch it off. The traditional way to do this was “commenting out” – putting a /* before the code and */ after. Although quick to do, it can easily be ineffective, as comment nesting is not necessarily supported by compilers. The newer // notation is a little better, but it is tedious to apply and remove and can still be error prone.
The best way to achieve this result is by using pre-processor directives, thus:
#if 0
#endif
Debug/Trace code
A particular kind of temporarily visible code is instrumentation – extra code added for debugging and/or tracing. Although modern debuggers and tracing tools can do a remarkable job, sometimes instrumenting the code is the only way to glean visibility and figure out exactly what is happening.
The usual way to accommodate this need is using pre-processor directives, as before, but using a symbol to switch them on and off:
#ifdef DEBUG_TRACE
#endif
So, when the symbol DEBUG_TRACE is defined, the debug code is included.
A slightly different approach is to code it like this:
#ifndef NDEBUG
#endif
Although this double negative does seem confusing, some consistency is introduced, as this symbol is used to enable the standard assert() macro. The symbol needs to be defined to suppress debug mode.