Guide to a Successful Programming Style

Good style is like touch typing: it may seem counter-productive at first, but the initial effort will pay enormous dividends. After a little while, the elements of good style will be second nature. In addition to all the previously mentioned attributes that accrue from using good style, you will find that utilizing good (consistent) programming style will assist you in creating error-free programs.

Readability

There are a number of stylistic elements which can make a program more readable, including the use of horizontal and vertical spacing, the conventions used in declarations, etc. Each of these elements will be discussed in turn.

Keep in mind that once a program (function) is written, it is seldom read from top to bottom. Programmers in correcting or modifying a program often skip large blocks of text/code in order to find what they are looking for.

A good analogy can be made to a dictionary. Imagine if the words in a dictionary were written in normal English run-on (stream) prose style, as this handout is. What if the dictionary were not alphabetized? What if the words being defined did not appear in boldface?

As a good programmer you should strive to enhance the visual appearance of the code you write. The effort you put into this will begin to pay dividends as you eliminate errors from your code.

Indentation

Indentation is used to enable a reader to determine the statement nesting level at a glance. In order to be useful, indentation must be consistent, the number of spaces used per indentation level should be either 3, 4, or 5 spaces, and the same style of indentation should be used throughout the program. Proper indentation makes your program much easier to debug.

Fortunately the C++ emacs programming environment automatically handles indentation for us. For good examples of the use of indentation, the interested reader is referred to the sample lab solutions placed on the dept. server. (i.e. perfectNums.C)

Spaces

Normally in programming, the minimum acceptable standard for the use of spaces is that you follow normal English rules. This means that most of the basic symbols in C++ (e.g., ``*'', ``+'', etc.) should have at least one space before and one space after them, with the exceptions being that no space appears before a comma. More than one space may be used if you are aligning things on adjacent lines.

Blank Lines

Blank lines should be used to separate long, logically related blocks. This means that the variable initialization, module documentation, and main code sections should be separated by at least one blank line. Functions should be separated by at least two blank lines. Similarly, within a long function body, groups of related statements may be separated from other groups by a blank line. To be effective as an element of style, blank lines should be used consistently.

Statements

Each statement should appear on a separate line; with very long lines continued on the next line indented appropriately.

Declarations

Variables should by accompanied by a documenting comment describing its use. These comments should appear on the same line as the initial variable initializing assignment statement.

Comments

In the real world both maintenance programmers and other members of a programming team rely on comments to explain the program, function or code fragment that they are reading. The comments should be brief, accurate and very precise. If a comment and the code disagree, the comment is presumed to be correct, and the code incorrect. Comments are used primarily to state what the code is doing (its purpose), while the code itself describes how you are doing it. Thus, it is only common sense that you should write the comment first (i.e., define what you are doing) before you write the code.

Comments should always start and end on the same line. This makes it easier to tell if a statement is commented out, and removes the problem of unclosed comments. Also, never put a comment in the middle of a statement or declaration unless you are commenting out a part of the statement or declaration.

Comments fall into one of the following groups:

  1. Program prologue comments.
  2. Function prologue comments.
  3. Declaration comments.
  4. Code or statement comments.
Each of these will be discussed in turn.

Program Prologue

The main goal of a program prologue is to explain the purpose of the program/class. A program prologue is similar to a function prologue and includes the following sections (the first three are particular to student projects):
  1. Your name.
  2. Date (or semester and year).
  3. Class and professor's name.
  4. Purpose of the program/class, i.e., an explanation of what the program/class does.
  5. Program input.
  6. Program output.
  7. A description of what data structures are used. This section is optional, depending on need.
  8. Algorithm: a general description or outline of the processing done. This section is optional, depending on need.
  9. Limitations or restrictions: what assumptions are made about the input data; under what conditions the program or unit fails to operate properly, etc.
  10. Modification history: who has modified the program, when, and why. This section is normally started once the program or unit goes into production; thus it seldom appears in student programs.

Function Prologue

The major reason for a function prologue is to explain the purpose of the function. A prologue should normally include the following sections:
  1. Explanation of parameters: these normally appear immediately after the parameter names or in the function prologue .
  2. Purpose of the function: i.e., what the function does.
  3. Algorithm: i.e., how the function does what it does. If a standard algorithm such as Quicksort is used, a reference rather than an explanation is preferred.
  4. Limitations or restrictions: what assumptions the subprogram makes about its data; under what conditions the subprogram fails to operate properly, etc. (A precise description of the preconditions and postconditions for the subprogram.)


void PrintMembers (int memberList[], int noOfMembers) {
/****************************************************************
 Purpose: Prints a list of active club members to the screen.

Algorithm: For each item in memberList [0 .. (noOfMembers - 1)],
         checks whether or not the current record represents an 
	 active member.  If active, then displays the member;
	 otherwise does nothing.

Preconditions: Describe appropriate preconditions for the 
         input parameters.

Postconditions: Describe appropriate postconditions for the 
         function.

Parameters: memberList: array of club members
            noOfMembers: number of members
***************************************************************
}

Declaration Comments

Constants and variables are always commented with short, precise comments giving their purpose. These comments normally follow the variable initialization on the same line and only rarely take more than a line or two. Similarly, function parameters are always commented.

Statement Comments

Statement comments generally fall into one of the following groups:

  1. Comments which explain a block of code: such a comment should precede the code itself and should be indented one indentation level. The entire block of code including the comment should be separated from other blocks of code by a blank line.
  2. Comments which explain a statement: such a comment should follow the statement on the same line. Such comments are common in assembly code.
  3. end comments: such a comment uniquely identifies the component which is being ended and is essential in finding the matching while, if, for, or function. In the case of a function, the comment contains the name of the handler or function.

The first two types of comments can obscure the code which is being commented and if not used properly can have a negative effect on the readability of the code. Thus, code block comments and statement comments should be created carefully. Before adding such comments you should first attempt to make the code itself more understandable, by improving the identifier names used, by replacing groups of statements with subprogram calls, by reducing the control complexity of the code, etc.

The Structure of Names

In a language like C++, names must be given to files, classes, functions, variables and constants. Usually the sequence in which the names of various entities are chosen is random. This should not be the case. There is a clear advantage in choosing the names in a certain order. The remainder of this section discusses the structure of names for the different objects. After that it will become clear that the proposed sequence in naming is preferable.

Function names

A function is (literally) called by its name which stands for a group of statements to be executed. Therefore the name should express the implied action (``Do This'') by including a verb.

Function names should always be capitalized. (Which will differentiate them from variable names.)

Examples: StoreWord, DisplayError, ShowPrinterStatus, PrintPage,
InvertMenuTitle, OpenWindow, DrawLine, PrintAddress, GetFirstElement,
CheckMachineState, FindName
.

Variable names

Variable As with all identifiers, identifiers that are the concatenation of two or more English words should have the first letter of all words after the first capitalized.

Examples: firstState, nextState, lastElement, bigWindow, homeAddress,
runningTitle, headPointer, titlePage, endOfList, maxLength, currentSymbol,
optimalLevel, screenWidth
.

Constants

Constants often describe a limit within a program. In these cases it is appropriate to use the prefix ``Max'' in conjunction with the type name. Otherwise treat the names for constants like variable names.

Constants should always appear in all capital letters.

Examples: MAXLINELENGTH, MAXLINESPERPAGE, MAXNOOFELEMENTS, MINWINDOWWIDTH,
FASTCLICK, SLOWCLICK, DEFAULTREPEATRATE
.

General Hints on Naming

The most important criterion when choosing a name is: how easily another programmer can understand the program (and not just yourself). If understanding a name was not important we could name the variables a, b, i, j, x, y, etc.

Miscellaneous C++ Style Conventions

Few numeric constants should appear in your code, other than 0, 1, '  ', and nil. (i.e. No magic numbers). All other constants should be declared and named as a CONTSTANT.

All selection and iteration constructs should use a begin brace ({) and an end brace (}) even if only one statement is placed inside the braces.