Skip to main content

Posts

#12. Always keep correctness in mind

Bertrand Meyer starts the first chapter of his book Object Oriented Software Construction, 2nd Edition with the following sentence:
Engineering seeks quality; software engineering is the production of quality software. He goes on to analyze the concept of software quality throughout the chapter. He defines it as a combination of several factors, some external (observable by the users of the software) and other internal (observable only by those who have access to its source code).

External software quality factors are correctness, robustness, extendibility, reusability, compatibility, efficiency, portability, ease of use, functionality and timeliness. All of these are important and should be balanced one against the other. But one clearly stands out among them: correctness. Quoting [Meyer 1997] again:
Correctness is the ability of software products to perform their exact tasks, as defined by their specification. If a software is not correct, everything else matters little. Correctnes…
Recent posts

#11. Don't use syntactic overloading

Syntactic overloading (or function overloading) is a C++ feature which allows a class to have several functions with the same name, but with different parameters. To say "Don't use syntactic overloading" is the same as to say "Don't give the same name to different functions".

class C
{
    ...
    void add(int i);
    void add(double d);
    void add(C other);
    ....
}

When you write this client code:

C c;
c.add(x);

The compiler will call the appropiate version of the funcion add, depending on the type of x.

This is what syntactic overloading is. It is called syntactic overloading to distinguish it from semantic overloading 8more properly called dynamic binding), which is the one that happens when you use inheritance and polymorphism.

Syntactic overloading may seem useful at first sight, but it has lots of drawbacks for no real advantage. It just can go wrong in too many ways.

Code is more readable without syntactic overloading. One name for each thing, different n…

#10. Choosing the right loop structure

C++ has three loop instructions: for, while and do ... while. To choose wisely among them, you need to know what their differences are.
1) for A for loop makes sense when you repeat an action for a known number of times, or for all the elements of a known set.

This is the syntax of a forloop:

for (initialization; condition; expression)
{
    statement
}

statement is actually a compound statement, that is, a block of code. This is called the body of the loop. In contrast, the initialization, condition and expression together are called the header of the loop. The initialization is a single statement which ends at the semicolon I wrote after it. The condition is a boolean expression. The expression is a statement. It should be a single statement which modifies one variable which is involved in the condition (see #guideline #5).

The initialization is performed. Then, the condition is evaluated. Then, two things can happen. If the condition is false, the code jumps right after the for statemen…

#9. Keep functions short and cohesive

A function should have one specific purpose. And it should achieve its purpose by means of a cohesive structure.

A function can be structured in one of these ways:
A sequence of actions.A condition.A repetition of certain actions. These control flow structures can be combined to form more sophisticated units. For example, a function may be a sequence of actions, with some of them being executed only under some conditions, and some other being loops. A certain degree of composition may be useful, but if you're not very strict, you'll soon find yourself writing 50-line functions which lack any structure.

Software scientists have long attempted to measure the complexity of code. Cyclomatic complexity measures the number of linearly independent paths through a program's source code. The higher cyclomatic complexity a function has, the harder it is to test.

If your function is a condition, you may need to test it in two different scenarios (paths): when the condition is true, an…

#8. Define variables as close as possible to where they are used

Define variables as close as possible to their first use. Prefer variables with the most local scope as possible.

Inside a function body, at run time, a variable begins to exist once the code execution reaches the point where it is defined - not the point where it is only declared. (The Stack Overflow question What is the difference between a definition and a declaration? will help you understand the difference between a variable declaration and a variable definition. See the Answer by sbi.)

It benefits the readability of your code that you keep functions short and well structured. To achieve this, It is a key factor that every concept is limited to the exact scope where it belongs to. Define, initialize and use each variable exactly where it is needed, not any earlier. By following this simple guideline you will write code which is more readable, contains less defects, and is easier to debug.

Refactoring a function body is one of the most common tasks in software engineering. What wa…

#7. Always initialize variables

Variables should be initialized with a known and meaningful value as soon as they are created. A variable should never begin to exist without having a known value.

The most common sign I've found that someone is a novice C++ programmer are uninitialized variables. You look at a function body and you see the definitions of many uninitialized variables, usually grouped at the beginning of the function. Sometimes they are assigned a value later; sometimes they aren't used at all; and sometimes they are used without having been initialized, causing unpredictable behaviour.

This is bad. Very bad. It hurts readability and it is error prone. The risk of using the value of an uninitialized variable is never worth taking. Don't do it. Always initialize variables.
Bibliography[McConnell 2004]
Steve McConnell: Code Complete, 2nd Edition, Microsoft Press, 2004.

This book discusses the initialization of variables in Section 10.3, "Guidelines for initializing variables".

[Sutte…

#6. Ensure entry and exit conditions in loops

There are at least two questions you should always ask yourself while you're writing code for a loop - and ask yourself again after writing it. Here they are:
Will the loop body be entered at least once?Will the loop ever be exited? If your loop is a do .. while, the first question has an obvious answer: yes. It will be entered at least once (as long as the execution point reaches it, of course). That's why you chose that structure in the first place. If it is a while or a for, you should pay more attention to that. Review the loop condition thoroughly and think about the possibility of it being false at the very beginning of the loop. In that case, the loop body would not be executed. Is that scenario correct your design, or is it something to avoid? If the latter is true, then you should write the specific code to handle that.

About the second question, the loop will be exited whenever its condition is evaluated to false. The condition is evaluated once for each iteration. Wi…