Code Standards
Programming Guidelines at Transylvania University Dr. Kenneth Moorman Dr. Tylene Garrett Dr. James Miller
Introduction
There are many different styles when it comes to the art of writing computer programs. Some people, for example, tend to be very wordy in their program--long variable names, page-long comments, and so on. Unfortunately, most people go to the other extreme--small variable names and no comments. This document is an attempt to describe a set of guidelines which you will be expected to follow on any program you write for the CS faculty here at Transy. The goal is to produce programs which are readable not only by the computer that is interpreting your programs but by other humans as well.
Programming is rarely done in a vacuum. Other people will need to read and understand your code. Of course, if you are ``still around to answer questions, this is not always a big problem. But, if the author is not around, then only the code itself can speak. It can also be a problem even if it is yourself trying to decipher code six months after you have written it. Good programming style will help to alleviate some of the pain.
The style which we are suggesting is a blend of several different techniques. It focuses on these points:
1.
Function names should be well-chosen so that they describe the purpose of the function.
2.
The same rule applies to variable names.
3.
Comments should fill in the gaps which the first two points do not address.
4.
Use white space to guide the reader.
5.
Finally, don't try to teach your reader the language.
Let's jump in and examine these points more closely.
Naming of functions
Function names should be descriptive of what they do. This means that many times you will need a function name made up of multiple words. Since our languages do not allow spaces in a name, we have to develop an alternative to indicating word boundaries. For this, we use one of the following convention. One possibility is to separate the multiple words with underscore characters. For example:
...
int Calculate_Student_Average () {
...
}
Many folks feel that this is a little unwieldy, both in writing it and in reading. A different approach is to start the name with a lowercase letter; then, each new word in the name should begin with a capital letter.
...
int calculuateStudentAverage () {
...
}
Pick a style which appeals to you and follow it consistently.
Naming of variables
Variables follow the same naming convention as function names, with one exception. Indices used in iteration (loops) will many times be a single character. The convention is to use i for a loop, j for a nested loop inside of that, k for another level, and so on.
Commenting
The rules for commenting can be summed up in two sentences:
* Give the reader of the code enough information to figure out what is going on. * Do not give the reader too much information.
First, assume that the reader of the code knows the language. You are not supposed to teach the reader the basic syntax of the language in question. Practically, this means that you do not comment things which are obvious. For example, the following comment is unnecessary:
... int i; // sets up an integer variable called i ...
On the other hand, the next comment tells the user something which they do not immediately know and so is a ``good comment:
... int count; // keeps track of incoming data records ...
On the third hand, there is often no need to comment, if the choice of function names and variable names has been reasonable:
... int numberOfStudents; // keeps track of the number of students ...
Global commenting
Since we encourage modular programming, there is rarely the need to comment at a global level, except for a couple of instances. First, each file which is part of the project should have a comment at the beginning which identifies the name of the file, the project which is it part of, the people who worked on the code, the date it is due, the purpose of the code in general, and any bugs which the programmers have identified. Second, in the event that you find a good use for a global variable, any such variable which you use needs to be commented as to its purpose and in what files it is used.
Separation of code, header files, and makefiles
For simple programs, you will find that one file is sufficient for all the work you are doing. However, when the programs begin to grow in complexity, a more modular approach is preferred.
There are two broad categories of files in C and C++: source files and header files. Program files contain the code which makes the magic happen. Header files are used to ``help the system work its magic. For example, header files will often contain the function prototypes which are necessary for the program to work. They may also contain various constants which you have defined for the program.
One of the most important things which you should find in the header file are the comments which describe what each function is supposed to do. The information should include the date that the function was written (or last modified), who has worked on it, what the inputs are, and what kind of output to expect. This provides a kind of summary of everything going on in your code. So, someone else can use this as a roadmap to figure out what functions need to be called to accomplish X, Y, or Z, and what parameters need to be passed into those functions.
Each header file which you write will be associated with one or more source files. These are the ones which end in .c, .cpp, or .cxx. In the early days of your CS education, it will not be uncommon for your entire program to fit into one such file. However, as the programs grow in complexity and you spend a great deal of time maneuvering around a huge text file, you will discover the benefits of splitting the source code up into more manageable chunks.
Let's say that you are writing a compiler. There's a well-defined translation stage and a well-define execution stage. Rather than lumping all of the functions needed for these two stages together into one large and unwieldy file, why not break the program into three pieces. One file will be all of the translator stuff. We'll call that one translator.cpp. There will be things that it needs to have from header files that just apply to this one file. So, we will have a header file called translator.h. Similarly, we will write execution.cpp and execution.h. There will also need to be some header material which both files share. Rather than duplicating it, we'll create compiler.h which both files will include. Finally, we need a third source file which will contain the ``glue that holds it all together. Since we try to be descriptive, let's call this last file compiler.cpp. This will be the file that contains the main function which runs everything.
Of course, there are countless ways to do this project. We could have stayed with two files, for example, and made a standalone translator and a standalone executor. Then, the need for the compiler.cpp file would be eliminated. Remember, there is no one ``right way to do things--find a system that is consistent and helps the reader understand what is going on and you will be fine.
Function commenting
As pointed out, the header will contain a comment for each function prototype explaining who wrote it and what the input and (expected) output are. This will allow the reader to quickly understand the purpose of each function in your program.
Any block of code which may not be clear should also be commented. What you want to indicate to the reader is why something is being done, not how it is being done.
White space
There is one final aspect to the readability of a piece of code--the correct use of white space. By this, we mean two things. First, you should indent various blocks of your code. Second, you should separate various blocks with blank lines. These two elements will help to make your code more readable.
Indentation does not seem like it would be very important. But, it can make a vast difference in the way a program looks. The same goes for blank lines--after all, they're blank, what information can they convey! But, consider the following:
- include <stdlib.h>
- include <iostream.h>
void main () { int i; char name[50]; cout << "Please enter your name" << endl; cin >> name; for (i=0;i<10;i++) { cout << "Pleased to meet you, " << name << endl; } }
Contrast that to:
- include <stdlib.h>
- include <iostream.h>
void main () {
int i; char name[50];
cout << "Please enter your name" << endl; cin >> name;
for (i=0;i<10;i++) { cout << "Pleased to meet you, " << name << endl; }
}
It is obvious to the reader in the second example that the program is made up of one function which consists of three sections. The variable declarations are laid out at the top. Then comes a section which does input. Finally, a block of code prints the message 10 times.
Blocks of code which do distinct things should be separated by blank lines. Any control structure should have its elements indented--this includes functions, for loops, while loops, if statements, and so on. Those are the two rules to remember when writing programs.
One of the nice things about using a ``modern editor like XEmacs is that it will do a lot of this work for you. XEmacs is aware of dozens of different languages. When you start working on a program called foo.cpp, for example, XEmacs knows that it is a C++ program. If you press the tab key, the editor will automatically indent what is considered a reasonable amount in that language. By the way, XEmacs will also help you do things like match parentheses and braces. It will also highlight with color different pieces of a language (all comments in one color, all keywords in another, an so on). Of course, one of the authors of this paper is an avid fan of XEmacs, so consider this a biased push for it.
Minimal requirements of any program
Finally, beyond the style, there is a certain level of competence which we expect from you.
1.
Programs should compile without errors. If this cannot be accomplished, a comment must exist at the top of the main file indicating to the professor the problem.
2.
Programs should not crash on ``good data. Again, a comment indicating problems is required.
3.
All global headers must indicate with whom the code has been discussed and the level of that discussion. This includes printed and electronic sources as well.
Conclusion
The code you produce has to be syntactically correct in order to be run by the computer. But, it is equally important that it be readable by humans. Use good function and variable names. Don't be afraid of white space and comments. And don't try to teach the language. Your professors, other programmers, and yourself are all people who will one day need to look at your code and figure out what it is supposed to be doing. Give them some help, OK?