Programming Style Guidelines
Program elements
Every program should have the following:
- a header
- comments describing parts of the code
- appropriately named identifiers for variables, constants, and functions
- constants in place of "magic" numbers and values
- judicial use of whitespace
- an 80-character line width
Check out these examples to get an idea of why style matters.
Note that this page uses C++ example in many places. You can use these guidelines for just about any language, however.
Header
Every one of your program files should have this comment at the very top of the file. This is helpful to you and me. For instance, if you look back at a source code file several weeks (or months or years) after you've written it, this header will provide you with the context of the program.
(Back to top)Comments
You should use comments in your code to ensure it is understandable. It is important that larger blocks of code, even if they are easy to follow, are preceded by a comment summarizing the goal of the following code. For lines or small blocks of code that are confusing, it is helpful to have comments that make clear the confusing bits. Comments should not describe the code itself, but rather the goal of the code. Here's an example of good commenting and bad commenting:
Bad commenting
// Assign 'Alice' to a variable named 'name'. string name = "Alice";
Good
// Alice is the name of the heroine in our adventure game. string name = "Alice";
JavaDocs
One common style for function comments is JavaDoc format (which can also be used with the Doxygen documentation generator). This style has annotations that allow an external program to be run over the source code to build documentation pages in HTML. The basic format is:
Note that the opening of the comment starts with a /
followed by
**
). Every other line should lead with
a space and an asterisk, and the final line should close the comment.
The @...
things are called annotations.
JavaDocs should have one @param
annotation per parameter and
they should be listed in the order specified in the function signature (that
also means that there should be no @param
if the function has
no parameters). The format is:
@param
, space, the name of the parameter, space, and a short
description of the parameter.
The @return
annotation should occur last and should only be
included if the function returns a value; i.e., do not include it if the return
type is void
.
Here are some examples of JavaDocs in action:
Comment checklist
- Be sure include comments in the following places:
- at the top of each file describing the overall purpose of the code
- above each function, describing the purpose, inputs, and outputs of the funciton
- above each large, cohesive chunk of code, describing its purpose
- above small, confusing chunks of code where it may not be immediately obvious what is going on
- Ensure your comments are grammatically correct—use the correct punctuation and capitalization
Appropriate Identifier Naming
Identifiers are the names you give to elements like constants, variables, functions, and classes, and they should make clear what the element is and does. Identifiers should be concise, consistent, and readable. What does that mean?
Concise
Identifiers should be as short as possible while still clearly conveying the purpose of the underlying element.
Consistent
Consistency means that multiple identifiers referring to relative levels of
concepts should show that relativity in their names. For example, if a program
has variables for a customer's first and last name, well named identifiers for
these two variables are: firstName
and lastName
; poorly named identifiers are: name
and lastName
.
In the poorly named case, it's unclear looking at name
to know how
it differs from lastName
(is it the first name, whole name, middle
name, nick name, ...?).
Readable
You should avoid abbreviations, uncommon acronyms, and single characters (unless
appropriate, such as using x
in a math function or i
in a for loop). Studies have shown that expanded identifiers make it easier to
comprehend code blocks. In addition, use clear delimiters between words within
an identifier, e.g., under_scores
or camelCasing
. The
identifier maxoveralscore
is much harder to read than
maxOverallScore
or max_overall_score
.
Constants in place of "magic" numbers and values
It's tempting to add arbitrary hard-coded values to your code. For instance, consider a program to check if a user provided number is less than some threshold, and then divides that number by some value (it's a weird program...). You might write the program as follows:
In this version of the program, I happened to set both the threshold and the divisor to 10. These are called magic numbers because there doesn't appear to be a reason they were picked, and they are hard-coded directly into the center of the program. There are two major issues related to comprehension and maintainability with magic numbers that this program illustrates.
First, it is unclear how the 10's are related. Is the 10 in the if statement the same 10 at the bottom of the program? If I want to change the threshold, should I change the divisor, too? It's unclear!
Second, if I do want to change either the threshold or the divisor (assuming I know which is which), I have to change it everywhere in the code, including in the comments. For each, that means modifying two or three lines of code.
What's the alternative? Use a constant! You can think of constants as variables that don't vary (hence why we don't call them variables). Some languages (like JavaScript) don't offer a way to differentiate between variables and constants. That's okay, just use a variable, but make it all caps (or whatever the convention is in that language). Now use that constant in place of the magic number in the code, and don't specify any specific number in comments. Here's the example from above with constants, one for the threshold and one for the divisor.
Now we know 1. what code uses the threshold value vs. the divisor value and 2. if we want to change either value, we need only update one line of code at the top of our function. Easy to read, easy to comprehend, and easy to modify!
(Back to top)Judicial use of white space
White space includes brace placement, spacing between lines, and indentation. The convention we use in this class is to always place curly braces on their own line, indented to the level of the code outside of the curly braces. Inside of the curly braces, everything should be indented one tab more. I usually use four spaces per tab. Code that is aligned is significantly easier to read.
Also, add in blank lines between chunks of strongly related code. In the good examples below, I put a blank line between logical segments of code. The rule of thumb I use is, one blank line above every comment.
Good
Or, with the curly braces removed because the block only has one line:
Bad (Back to top)80-character line width
A standard CLI is 80 characters wide. Even though I do most of my editing in a
text editor rather than via a CLI, I still use 80 characters as my limit. Text
that is longer than that auto wraps, but often not in a way that is easy to
read. In Sublime Text, it's easy to set up a ruler at 80 characters. This lets
you see how close you are to hitting the limit. Go to
View
→Ruler
→80
. Remember that
you can spread long C++ statements across multiple lines!
Examples
Take a minute to think about what this next program does:
Now take a look at this functionally-equivalent program that is styled using the guidelines above:
So what did I do here? First, I added a header, which lets everyone know what the program does. Now I need only read to the second line and see the file name is average.cpp
to have an idea of what it does. The description field makes it obvious. I've also added a function comment above main
. I've created concise but descriptive identifiers for each variable—total
keeps track of the running sum, while userNumber
is a number entered by the user. Through judicial use of whitespace, blocks of code are now indented consistently, making it easy to tell when I'm in a function or for loop. I've used blank lines to segment chunks of related code, making the flow of operations easier to comprehend. I added some extra output to the user to make it clear what's expected. Finally, I've used a constant to keep track of the number of values to read in from the user. This relates all instances of NUMBERS_TO_READ
to the same conceptual meaning, and also makes it easy to change the value to something else (otherwise, we'd have to manually replace every instance of 10 in the code).