Bug-free development: Source code readability
Source code readability is important. Even nobody else will read your source code in the future, you will read it one day. Dirty code provides good shield for bugs for they become harder to find. Dirty code may also mislead other programmers to think they find a bug, and by “fixing” it, they create a real bug.
Indention
One good reason I like Python is, no matter the programmer is amateur or professional, at the first glance, the source code is so clean. If the source code is not properly indented, then it may not run at all. Well-indented source code helps the reading speed, and makes the bugs easy to reveal.
There are many code beautifiers that standardize the code style. For example, in UNIX there is a command called “cb” (C Beautifier), and in Visual Studio, there are shortcuts standardizing the code format as well. When I programmed in C, I always ran the “cb” command and compared the output with my source code, and made sure no differences were found between the two. Call me obsession, but once I got used to it, it became very natural to write well formatted code at typing.
Explicitness
Being explicit means, for example, if part of the code is supposed to do nothing, then, instead of writing nothing, do put some code or comments to speak out: “I am here to tell you, nothing should be done. I did not forget to consider this case.”
Here is an alarm clock program. It used to work before but is not working now. Instead of triggering the alarm by the desired time, it does the inverse logic – keep ringing the alarm until the time is reached. The investigation shows that the latest version is like this:
for (time() < desiredTime)
puts(“wake up”);
Then no surprise why it keeps sending the alarm. Why the code is like this? One week ago Susan read the code and discovered that the code was like:
for (time() < desiredTime);
puts(“wake up”);
and she thought that the “;” at the end of the “for” statement was a typo, so she removed the “;” wrongly, and this “fix” ultimately reserved the logic.
To avoid this misunderstanding, Mike, the author of the previous version, should have written his code as below, so if Susan saw this code, she would have been thought twice, or picked up her phone to quickly confirm with Mike, before applying the “typo correction”.
for (time() < desiredTime)
;
puts(“wake up!”);
A even more explicit code is like this. The “NULL” statement does not generate any extra code, but it explicitly tells the audience “I mean to do nothing here.”
for (time() < desiredTime)
NULL;
puts(“wake up!”);
Other examples: The NULL statement in the “else” block makes explicit that no actions should be taken if neither A nor B is met. The “fall through” comment in the “switch” block makes explicit that the “break” statement is not forgotten here, but the programmer intends to execute do_this() and do_that() when a equals to 0.
if (A)
do_this();
else if (B)
do_that();
else
NULL;
switch (a) {
case 0:
do_this();
// fall through;
case 1:
do_that();
break;
case 3:
do_other();
break;
default:
NULL;
}
Easy code
Easy code helps others (and yourself!) understand your code, without reading the reference manual of a programming language.
Consider the code below on the left side, at a glance, can you tell it is the famous “strcpy” function? Can you easily tell whether is works at all? Which operation executes first: “++” or “*”? The “=” is a single equal sign, is this a bug? If you cannot figure out these easily, then why not be kind to your audience, and write the code like the right side.
Short but difficult code | Easy code |
---|---|
while (*to++ = *from++) ; |
while (*from != ‘\0’) { *to = *from; from++; to++; } |
Look at the code below, can you easily remember the details of automatic variables – is the 3 assigned to i once at compiling? or i is assigned 3 every time the program enters function foo()? If you are not sure, then why not write the code as “int i; i = 3;”?
void foo()
{
int i = 3;
:
:
}
The code below really puzzled me in the past. In industrial control, the sensor returned a byte containing some on/off bits, and when I wrote the first version of the bit detection, the program never printed the “hello” statement even if status was exactly 0x03! Finally I discovered that in C language, “==” has higher priority than “&”, so the program first compared 0x0F against 0x03, then performed the bit AND operation between “status” and zero. The fix is easy: put a pair of parenthesis around “status & 0x0F”, so “(status & 0x0F) == 0x03” is both easy and explicit.
if (status & 0x0F == 0x03)
puts(“hello”);
Many C/C++ programmers like writing code in one line. I do not say the codes are wrong, but they are perfect nutrition for bugs:
(a == b) ? do_this() : do_that();
(a == b) && do_this();
(a == b) || do_that();
Note: When I said “easy code”, I was not criticizing algorithms. The algorithms are the souls of computing, and poor coding farmers are just producing stuffs.
Art | Stuff |
---|---|
double Power(double a, unsigned n) { double factor; if (n == 0) |
double Power(double a, unsigned n) { double result; result = 1.0; |