Programming Style Guide by Lee S. Koh
( Other Style-Related Material )
(C/C++ Oriented)
( Syle-Related Q&A )
( Let's Code "in Style" )
( PUTSE )

Regardless of the language that is used, source code should be correct, readable, and understandable. Of these three properties, correctness is obviously the most important. No matter which of the other qualities a piece of code has - is well structured, is well documented, looks nice, and so on - it is worthless if it does not produce correct and reliable results. Code testing is therefore an important step in software development.
It is often difficult for some students to appreciate the importance of the other two characteristics mentioned above and of developing good programming habits that lead to code that is readable and understandable. The difficulty often arises because programs developed in an academic environment are quite different from those developed in real-world situations, in which programming style and form assume greater importance. Student programs, subprograms, and libraries are usually quite small (perhaps less than a few hundred lines of code), are executed and modified only a few times (almost never, once they have been turned in), are rarely examined in detail by anyone other than the student and the instructor, and are not developed within the context of budget constraints. Real-world software, on the other hand, may be very large (perhaps several hundreds of thousands of lines of code), may be developed by teams of programmers, is commonly used for long periods of time and thus requires maintenance if it is to be kept current and correct, and often is maintained by someone other than the original programmer(s). As hardware costs continue to decrease and programming costs increase (a known trend that is disconcerting to the many that are negatively affected), the importance of reducing software maintenance cost and the corresponding importance of writing code that can be easily read and understood by others continues to increase. The following quote from a published programming style guide underlines the cost-saving significance of writing readable and understandable code: "A good rule of thumb is that 10% of the cost of a software project goes into writing code, while more than 50% is spent on maintaining the software. Think about the trade-offs between ease of programming now versus ease of maintenance for the next five to ten years when you consider the rules presented here."
General programming principles that contribute to the development of correct, readable and understandable code include (1) programs and subprograms should be well structured, (2) all source code should be well documented, and (3) all source code should be formatted in a style that enhances readability. To help you in cultivating good programming habits and following good programming practices, some specific guidelines are provided below.



Good list of BAD style/practice that you should avoid: How To Write Unmaintainable Code



Use a modular approach. Rather than write one large subprogram or program, write individual subprograms that solve parts of the problem and that are relatively short and self-contained.
Use the basic control structures when developing each code segment. Studies have shown that any program unit can be written using only the sequential, selection, and repetition structures. These structures should be combined to form nested blocks of code that are entered only at the top and normally have only one exit.

IN PARTICULAR: The goto statement may not be used in the programs you write for this class unless you have sought my prior approval for its use - you will have to convince me that your particular situation warrants such use.
Use local variables within subprograms. Variables used only within a subprogram should be declared within that subprogram.
Use parameters to pass information to and from subprograms. Avoid using global variables to share information between subprograms because such use destroys their independence. It can be difficult to determine the value of a global variable at some point in the program because it may have been changed by any of the program units.

IN PARTICULAR: Global variables may not be used in the programs you write for this class unless you have sought my prior approval for their use - you will have to convince me that your particular situation warrants such use.

NOTE: Do not confuse global variables with global constants - the use of the latter is encouraged.
To protect parameters that should not be modified by a subprogram, declare the corresponding parameters to be value parameters or const reference parameters rather than reference parameters. Otherwise, the subprogram may unexpectedly change the value of a parameter in the originating (calling) program unit. This is a case of programming defensively. (This is often called the principle of least privilege.)
Don't use 'magic numbers.' For example, the following statement violates what has been termed the "Houdini principle" because it allows numbers to arise suddenly without explanation, almost as if by magic:


popChange = (0.1758 - 0.1257) * population;

The literals 0.1758 and 0.1257 should be replaced by constant identifiers (or variables whose values are read or assigned during execution), as in


const double BIRTH_RATE = 0.1758,
             DEATH_RATE = 0.1257;


popChange = (BIRTH_RATE - DEATH_RATE) * population;

The second assignment statement is more readable than the first. Also, if these numbers must be changed, one need only change the definitions of BIRTH_RATE and DEATH_RATE rather than conduct an exhaustive search of the program to locate all their occurrences.

Similarly, using a constant identifier such as INT_MAX (defined in the climits library) rather than some machine-dependent constant such as 32767 will increase portability.

Another example is the use of EXIT_SUCCESS and EXIT_FAILURE (defined in the cstdlib library) rather than 0 and 1 as "status-of-execution" indicators.
Strive for simplicity and clarity. Clever programming tricks intended only to demonstrate the programmer's ingenuity or to produce code that executes only slightly more efficiently, at the expense of simplicity and clarity, should be avoided.
Identify any preconditions and postconditions a subprogram has.

Preconditions describe what must be true before the subprogram is executed. Typically, these are assumptions made about the subprogram, often one or more restrictions on what comprises a valid input or received value.

Postconditions, on the other hand, describe what will be true after the subprogram is executed.
Have all applicable preconditions checked for conformance (unless such checking is not possible) first and foremost when implementing a subprogram.

If a violation of any precondition is detected, the violation should be handled in some acceptable way.


NOTE 1: For simplicity in this class, handle any violations of preconditions by first displaying an informative error message and then terminating the program.



The assert() function (provided by the cassert library), which evaluates a Boolean expression and terminates execution if the expression evaluates to false, can be used as a simple (and crude) way for checking and handling violations of preconditions.




For example, the following statement uses assert() to check and handle the preconditions that score (an integer) should be greater than or equal to MIN_SCORE and less than or equal to MAX_SCORE for any further processing to be relevant:






assert(score >= MIN_SCORE);
assert(score <= MAX_SCORE);





If the expression (score >= MIN_SCORE) && (score <= MAX_SCORE) evaluates to false, assert() will display a standard "assertion failed" message (which varies somewhat from compiler to compiler). 



By using a simple if statement and the exit() function provided by the cstdlib library, the same effect (and a customized "violation detected" message) can be obtained as illustrated below:





if ( (score < MIN_SCORE) || (score > MAX_SCORE) )
{
   cerr << "Invalid test score " << score << " encountered." << endl; 
   cerr << "A valid test score must be in the range [" << MIN_SCORE
        << ", " << MAX_SCORE << "]." << endl;
   cerr << "Program will be terminated." << endl;
   exit(EXIT_FAILURE);
}


NOTE 2: To avoid cluttering and detracting from our focus on key concepts, we will not be using the exception handling facility of C++ in this class.

Checking preconditions is another case of programming defensively.
For understandability (by others), include the following for programs or subprograms (functions) that are of one's own origin:

Each program should include opening documentation. Comments should be included at the beginning of the program to explain what it does, how it works, any special algorithms it implements, and so on, and may also include a summary of the problem's specification, assumptions, and other items of information such as the name of the file, the name of the programmer, the date the program was written, when it was last modified, and references to books and manuals that give additional information about the program.

Each subprogram should include leading documentation. Comments should be included at the beginning of a subprogram to describe what it does (i.e., its purpose or intent), what (if anything) it receives, what (if anything) it returns, any input or output, and applicable preconditions and postconditions.
Comments should be used to explain key code segments and/or segments whose purpose or design is not obvious. However, don't clutter the code with needless comments, as in


++counter; // add 1 to counter
Use meaningful identifiers. For example,


wages = hoursWorked * hourlyRate;

is clearer than


w = h * r;

or


z7 = alpha * x;
Don't use "skimpy" abbreviations just to save a few keystrokes when entering the source code. Also, follow what has been called the "Shirley Temple principle" and avoid "cute" identifiers, as in


bacon_brought_home = hoursWasted * pittance;
In general, use proper indentation, alignment and spacing to maximize readability. It is difficult to list all possible situations but the few specific examples given in this guide should give you a good idea.

NOTE 1: Use of three spaces per indentation level is to me a good compromise between providing good indentation effect and not wasting too much coding space.

NOTE 2: Avoid using the tab key for indentation, otherwise your source code may look unexpectedly and disastrously different when printed or viewed on a different platform because there is no standardized way of how a tab should be handled.


If you see me using the tab key that's because I have customized it to represent three spaces (say) in an editor that allows such customization.

NOTE 3: Limit each line of code to no more than about 70 characters long (counting any indenting spaces and trailing comments) so that it will not wrap around (or be truncated or require scrolling) when printed or viewed.


Line wraps will most certainly cause your code to be very unreadable and negatively affect its grading.
Put each statement of the program on a separate line.
Indent if, for, while and do-while as shown below:

if (temperature > 98.6)
   cout << "You have a fever!\n";
else
   cout << "You don't have a fever.\n";

if (temperature > 98.6)
{
   cout << "You have a fever!\n";
   cout << "Drink lots of fluids and go to bed!\n";
}
else
{
   cout << "You don't have a fever.\n";
   cout << "Do your homework.\n";
}

for (i = 1; i <= n; i++)
   s = s + i;

for (i = 1; i <= n; i++)
{
   s = s + i;
   cout << "Don't panic!\n";
}

while (i > 0)
   cout << --i << endl;

while (i > 0)
{
   i = i - 1;
   cout << i << endl;
}

do
{
   cout << --i << endl;
}
while (i > 0);

do
{
   i = i - 1;
   cout << i << endl;
}
while (i > 0);
Use uppercase and lowercase letters in a way that contributes to program's readability.

IN PARTICULAR 1: Put identifiers that are variables in lowercase, capitalizing the first letter of each word after the first as in totalHoursWorked (this is called the camelBack style).


For a multi-word variable, it is also acceptable to have every word in lowercase and separate the words with underscores, as in total_hours_worked.

IN PARTICULAR 2: Put identifiers that are constants in all uppercase, as in PI.


For a multi-word constant, separate the words with underscores, as in LOW_CUTOFF_SCORE.

IN PARTICULAR 3: Put identifiers that are functions in lowercase, but capitalizing the first letter of each word or for each word after the first as in DisplayInfo() or displayInfo().


Although not popular, but to have every word in a multi-word function name in lowercase and separate the words with underscores, as in display_info(), is also acceptable.

IN PARTICULAR 4: Put identifiers that are programmer-defined types in lowercase, but capitalizing the first letter of each word as in BigInt.
Put each { and } on separate lines.
Align each { and its corresponding }. Indent the statements enclosed by { and }.
When a statement is continued from one line to another, indent the continued line(s).
Align the identifiers in each constant and variable declaration, placing each on a separate line. Three examples follow:

const double TAX_RATE = 0.1963,
             INTEREST_RATE = 0.185;

int employeeNumber;

double hours,
       rate,
       wages;
Use blank lines to separate logical sections of code within a program unit (function) and to separate different program units (functions) contained within the same file - this will improve readability because it helps reveal the intended logical and organizational separation to the reader.

For instance, blank lines should be used to separate into groups the following types of statements: declarations, input, different kinds of processing, and output.

Don't go overboard in using blank lines, however - a good rule of thumb is to use only one blank line to separate two logical sections of code within a program unit (function), and use more blank lines (perhaps three) to separate two program units (functions) contained within the same file.


Overuse of blank lines (such as using more than one blank line to separate two logical sections of code within a program unit) does not give any additional beneficial effect but instead wastes space and reduces the compactness of the code.
Separate the operators and operands in an expression with spaces to make the expression easy to read. For example,


mass = volume * density;

and not


mass=volume*density;
Avoid inserting space(s) between an array name and its index. For example,


cout << score[i] << endl;

is more readable and preferred compared to


cout << score [i] << endl;

or


cout << score [ i ] << endl;
Declare constants at the beginning of a function. Declare variables near their first use. This makes it easy to find constants when they must be modified. It also reduces the tendency to declare unused variables, since declarations are deferred until they are needed.
Label all output produced by a program. For example,


cout << "Employee # " << employeeNumber
     << " Wages = $" << employeeWages;

produces more informative output than


cout << employeeNumber << ' ' << employeeWages;
Last but not least, be consistent with the style you use. Inconsistencies invite confusion!