Program Style Guidelines
In general, the goal in programming is to write clear, readable programs
that are as efficient as possible and solve a given problem. A program
is not only a means of communicating with the computer, but is also a
means of communicating with other people, including yourself. A program
should be written so that a person who has not seen the program before,
but knows the language, can read and understand the code. The following
guidelines will be used in grading programs for this course and help you
in achieving the goal of writing readable programs.
Visual Clarity
Program Outline
The file containing the main function should have the following basic
outline:
- Program heading comments
- #include statements
- Constant global variables
- Heading comment and implementation for each function or method
Indentation
Use a uniform indentation scheme (always indent the same way) to
indicate statements within control structures, nesting of control
structures, and statement continuation (if a statement will not fit on one
line). Indentation of 4 spaces is usual; much less is not enough and
any more does not leave room for deep nesting. Avoid putting more than
one statement on a line.
Braces
All braces should line up with the current level of indention. Braces
may follow a control structure or appear on the next line.
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 10; ++j)
{
foo[i][j] = i + j;
}
}
Or
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
foo[i][j] = i + j;
}
}
NOT
for (int i = 0; i < 10; ++i)
{
for (int j = 0; j < 10; ++j)
{
foo[i][j] = i + j;
}
}
Spacing
Use spacing within a line to make it more readable. Use blanks around
operators and other delimiters, after each comma in a list of items, and
anywhere else that makes a program more readable.
int currentIndex = 2;
char currentCharacter = 'A';
Widget myWidget = new Widget();
Blank lines
Use blank lines for vertical grouping of statements that logically
belong together. Blank lines are useful in the following situations:
- Around the body of compound statements,
- To separate sequential statements into logical groups,
- To separate a control structure (if, while, for) from complex
surroundings.
An excess of blank lines is not helpful. For example, do not
double space your entire program.
Line Length
Lines should be no longer than 80 characters. If a line gets too long,
either simplify the expression on that line or break the line up at
some white space character.
if (thisVariable == thatVariable ||
someOtherVariable == anotherVariable) {
...
}
someObject.someMethod(thisParameter, thatParameter,
someOtherParameter, anotherParameter);
Program, class, method, and function heading comments
Every program file, include file, and function within the program
should be prefaced by a heading comment.
- Main program heading
// Program: <Program Name>
// Author: <Your Name>
// Date: <Date program was started>
// Assignment: <Which Program>
// Purpose: <A brief description of what the program does and,
// at a very basic level, how it does it>
// Input: <Describe the input expected by the program>
// Output: <Describe the output produced by the program>
// Related
// Files: <Other files needed - header files, source files>
// Functions: <A list of the functions used in the program
// with a brief description of each function>
// History: <Optional - list of modifications following
// the initial implementation>
- Heading for files containing other functions and for include files
// Filename: <Filename>
// Author: <Your Name>
// Date: <Date code was started>
// Assignment: <Which Program>
// Purpose: <A brief description of what type of functions are in
// the file and how they relate to other program files>
// Related
// Files: <Other files needed - header files, source files>
// Functions: <A list of the functions defined in this file
// with a brief description each function>
// History: <Optional - list of modifications following
// the initial implementation>
- Class Heading
// Class: <Class Name>
// Purpose: <Description of the object this class models>
// Author: <Your Name>
// Date: <Date code was started>
// Superclasses: <List of superclasses>
// Subclasses: <List of known subclasses>
// Associated
// Classes: <List of classes that are associated with this class>
- Method Heading
// Method: <ClassName::MethodName>
// Purpose: <A brief description of the method's behavior>
// Author: <Your name or whoever wrote the method>
// Date: <Date the method was written>
// Parameters: <List of the parameters expected by the method and
// a description of what each one means logically>
// Returns: <Value, if any, the method returns>
// Pre-
// Conditions: <A list of conditions that must be true before
// the method is invoked>
// Post-
// Conditions: <A list of conditions that will be true after the
// the method returns>
- Function Heading
// Function: <Function Name>
// Purpose: <A brief description of the function's behavior>
// Author: <Your name or whoever wrote the function>
// Date: <Date the function was written>
// Parameters: <List of the parameters expected by the function and
// a description of what each one means logically>
// Returns: <Value, if any, the function returns>
// Pre-
// Conditions: <A list of conditions that must be true before
// the function is invoked>
// Post-
// Conditions: <A list of conditions that will be true after the
// the function returns>
Inline comments
You should spend some time thinking about what should be commented.
Do not add comments that do not add any new information. Too many comments
can be just as distracting as too few comments. Inline comments are useful
in the following situations:
- Each constant and variable should be placed on a separate line and
should be followed by a comment which describes how it is used in the
program. Recall that formal parameters are documented in the function
header, although it is okay to include inline documentation of them as
well.
- The ending of a control structure in a complex section of
code should be marked by a comment indented at the same level as the
beginning of the control structure. e.g., the end of the body of a
nested if statement or the else part of nested if's.
- Unclear program statements should be documented. These comments
should describe the logical effect of the statements or help the
programmer remember obscure facts. In the following example, the
specified comment is useless.
// a gets the value of b
a = b;
- Do not apply creativity to your commenting. Use your creativity to
solve the problem at hand, not to document your code. Make comments
meaningful.
Upper/lower Case
- Use all uppercase characters for constants:
static const int MAX_BUFFER_SIZE = 10;
- All class and struct names begin with an uppercase letter:
class Widget
struct Node
- Multi-word class and struct names begin with an uppercase letter
and the first letter of each word is uppercase
class BigInteger
struct ListNode
- All function, method, and variable names begin with with a lowercase letter
int paint();
int count;
- Multi-word function, method, and variable names begin with a lowercase
letter and the first letter of each word is uppercase
int getCurrentIndex();
int currentIndex;
Understandability
Names
The names of variables, functions, types, etc. should be descriptive of their
purpose. Do not be afraid to use longer names to avoid names that are short
and cryptic. Some general rules:
- Function names can be long and descriptive since they usually appear
infrequently and describe an action rather than an object.
- Type names can be long and descriptive since they usually appear only
in variable or parameter declarations.
- Variable names up to 10 characters usually provide a sufficient
description without cluttering up expressions.
- Variables used as array subscripts should be shorter if possible.
- Variables used only as counters, loop controls, etc., can be as short
as 1 to 3 characters in length.
"Magic Constants"
Avoid using literals throughout your code. If you need to use a constant
variable, assign that value to a const variable and use that variable
throughtout your program. Should that value need to be changed, this
allows you to change the value in once place, and not have to search
for every place you happened to use that literal. This is especially
important when two things might have the same value, but different
meaning. Remember to give your variables meaningful names. A variable
like the following is not helpful.
const int MAX = 20;
Max what? What does MAX mean in the context of the application?
Complexity
Make algorithms as simple and straightforward as possible. This usually
does not happen with the first implementation of an algorithm. It requires
a clear understanding of the algorithm through multiple attempts/refinements.
In cases where efficiency and clarity are at odds, clarity should usually
win out.
Modularity
A program is easier to design/write/debug/maintain when it is broken into a
group of smaller units that solve particular parts of the whole problem.
All functions should be designed to do one task only. Thus,
functions should be relatively small (say 50 lines or less). Any task
that is repeated at several points in the program should be put in a
separate function. Even tasks that are done only once, like initialization,
can be put in a separate function to simplify the code. Your main function
will normally be a few function calls and perhaps some simple
control structures.
Global variables
No global variables will be used. Any communication between a function and
its caller will be done through parameters and/or the function's return
value. The use of global variables often introduces hard-to-find logic
errors and indicates a poorly organized program. There are circumstances
where global variables may be used, but we will not see those circumstances
in this course.
Runtime behavior
Robustness
A program that does not terminate abnormally when given erroneous input data
is robust. Input validation can require extensive programming and some
errors may still not be detected. The amount of input validation necessary
depends on the reliability of the input source.
Error handling
When an error is detected at runtime, usually an input error, the program
should report the error in an informative manner and continue useful
processing. If the program cannot continue useful processing, it should
terminate as gracefully as possible.
Output formatting
A program's usefulness is generally measured by its output. Output should
be readable by the program user. Any output data should be accompanied by a
description or put into tabular form with appropriate headings.
Generality
Programs are not static creatures. They should be designed to accommodate
change. Avoid using hard-coded constants, use constant variables or read
the values from the user. A general function is easier to use in another
program. Related functions should be grouped together in separate
source files and related declarations should be grouped in include files.
If you are smart about the way you write programs, you will rarely have to
start from scratch when starting a new program. Reuse code when possible.