cprogrammer.org
Welcome to cprogrammer.org.
Projects
IDOL
Programming AUP
Solomon MySQL-Web
Help in the Seti War!


Misc
Use Galeon!
I love Emacs. Do you?
What the hell is happening to Perl?
My keyboard.
webmail
Post to this page!
ANGRYDOT
Account Request
 

The Programming Acceptable Use Policy
By Jonathan Daugherty
Disclaimer: The ideas contained in this document are completely opinionated in nature, though they may coincide with the general views of professional programmers and system administrators, and the field of Computer Science in particular. These ideas have arisen from neary nine years' experience as a computer programmer in Pascal, C, C++, Java, Perl, Pascal, and PHP.

This document is intended as a boilerplate take at how one might (or should) approach syntactical aspects of computer programming. Generally, the ideas stated herein are language-independent, but for the most part they apply to C-like languages (C/C++/Java). This document is also intended as a guide to help beginning programmers develop a standard coding style. Such a style is important in situations where others may read your code, and important still when you read or debug your own code.

Step 1: Get used to a powerful code editor.

Here, I don't mean an IDE. Integrated Development Environments are for people who need to drag and drop functionality into their code. Some examples of powerful code editors are standard UNIX text editors: Emacs, Vi, Vim, Joe. Generally, it doesn't matter which editor you use. I endorse Emacs because it gives me many code-friendly features:

Automatic language-specific indentation. This is great because hitting the Tab key under most editors will either insert a tab character or eight spaces. Under Emacs, hitting the Tab key automatically inserts a number of spaces, whose length depends on the editing mode (such as c-mode, perl-mode, html-mode). I have gotten this feature to work with Vim, but I do not prefer modal editors.

Language-specific syntax highlighting. Although this feature doesn't touch the final product, it's great for structural visualization.

Parenthesis and brace matching. This feature allows me to easily see the alignment and pairing of the two most important code tokens -- parentheses and curly braces. Especially with languages like C, leaving out one of these can generate hordes of errors.

Step 2: Use a consistent indentation style, regardless of the editor.

# The following set of guidelines should be considered when indenting code: Function prototypes should be on the left margin.
# The top-level code inside a function should be indented one tab's width from the left margin. That is, if a function contains only one line of code, there should be one tab before the first character on that line of code.
# All code inside a block should be indented one tab's width from the block's opening line. That is,

for (int i = 0; i < 5; i++) {
// code inside the block should be
// indented. Here the tab width is
// two spaces.
}

A full example follows:

void testFunc(void *param) {
// this is a sample remark
for (int i = 0; i < 5; i++) {
// this is a super-indented remark
i++;
}
}

Step 3: Space tokens apart.

The following is an example of insufficient token spacing:

if(a==5&&b==6){i++;}

# Instead, these guidelines form a good spacing policy: Place one (1) space around each and every assignment and comparison operator. This set includes ||, &&, ==, <=, >=, !=, +=, -=, /=, *=, =.
# Place one (1) space between control statements and their counterpart expressions. That is, between for and its corresponding ternary condition, if, else, while, etc.
# Place one (1) space between type specifiers and parameter names in function prototypes, and after the commas in between parameter names. For example,

void testFunc(void param1, char *param2);
^ ^ ^

# Place zero (0) spaces after opening parentheses and before closing parentheses.
# Place at least one empty line of code before all blocks, including if statements and functions. This applies especially to very small blocks of code whose existence may be hard to determine when scanning for errors. However, this does not apply to atomic operations, such as i++;. If a remark accompanies the block, the blank line[s] should come before the remark:

.
.
.
i++;

// loop comment here
for (...) {

Though tedious, these guidelines produce code like the following:

void testFunc(void param1, char *param2) {

if (param2) {
param2++;

// do something useless inside this loop
for (int i = 0; i < 5; i++) {

// do something with i here. This is another
// block-level comment.
if (i == 2) {
// blah.
}
}
}
}

Step 4: Use consistent placement of curly braces, pointers (*/&), and use a consistent capitalization scheme.

# Always place the opening brace for a block on the same line of code that contains the block's opening statement. That is, never do this:

void testFunc(void *param)
{
.
.

# The closing brace for a block should be at the same indentation level as the line of code that contains the block's opening statement.
# When possible, do not enclose single-line blocks' contents with braces. That is, when using a for or if construct for which there is only one line of enclosed code, omit the braces. Indentation rules for these situtations still apply, however. For example,

if (condition)
i++;

.
.

# When using a pointer token with a parameter name in a function prototype, put the pointer token next to the variable name, not the type specifier (void *param). This also applies to standard variable declarations.
# When naming variable, use a name that describes its function using as small an expression as possible. In fact, one- or two-word descriptions are best. This naming scheme applies to all named entities such as function names, etc. Furthermore, use the following rules when naming entities: use only alphabetic characters, numbers when necessary. Capitalize all words in the name except the first. For example, configGenerator or loopVariable. Shortening and abbreviation is always preferred, especially if the result is succinct. The above examples would then be confGen and loopVar, respectively. In addition, make sparing use of underscores at all times*. The main idea is that reduction of special keys that must be typed leads to a reduction in the overall complexity of typing a segment of code; this idea's importance grows with the code size.
# Use all caps for #defines only.

Step 5: Make minimal use of global variables, observe modularity, and respect flow control.

# Stay away from global variables when possible. The only globally accessible elements of a program should be in the form of #defines and other constants. Use of global variables promotes laziness. That is, if an entire system is designed in such a way that a web of dependencies and conditions is required to keep it running, the system will be inherently unstable, unmanageable, and ultimately non-portable. Furthermore, by using global variables throughout a program it is exposed to the risk introduced by faulty modifications of those globals; if functionality is compartmentalized in functions or classes, debugging becomes easier, problems are easier to target, and their effects are less widespread. In some cases use of these variables is unavoidable, at which point their use should be closely monitored and concisely documented. Documentation is important, most of all, and is detailed in the next section.
# Modularity is a programmer's best friend. The idea is to build a program in such a way that its components' functionalities can be re-used elsewhere, and/or in new ways. To do this, the components must be designed to work by themselves. In other words, a list struct and functions that operate on list structs would be better than a specialized list with specific features and preconditions dependent on the structure of the program.
# Here I address the issue of flow control with specific attention to the exit system call and other similar program-altering functions. Whether you're using System.exit in Java or exit(0) in C / C++ programs, the point is this: the exit point of a program should always lie in its main body rather than an outlying subroutine or function. This idea applies recursively. That is, functions should always return, rather than exit. If a routine is called whose preconditions are false, the program should not terminate. The calling block should be given the opportunity to handle the error gracefully and properly. The following is an example of improper flow control:

int testFunc(void *param) {
// something goes wrong here
if (!param)
exit(1);
}

int main(int argc, char **argv) {

int result;
result = testFunc(NULL);

return result;

}

Some compilers would warn you that the testFunc function is not returning a value, as it should. Such a warning may be ignored if that's the intention, but the main idea is that main has no jurisdiction over the fact that testFunc will terminate the program upon discovering that its parameter is null. This can be dangerous because a program may terminate inside a library call, if that call violates this principle, for example. In such a situation the programmer has no control over that call and no way to determine the exact exit point of the program (without the use of a debugger, that is). The main function above should be granted the right to decide how to deal with testFunc's return value. Instead, the previous example would be rewritten as

int testFunc(void *param) {

if (param) {
// do something with param's valid value
// return a success value
return 0;
} else return -1;
}

int main(int argc, char **argv) {

int result;
result = testFunc(NULL);

return result;

}

The best way to illustrate this is with a real example. If your program connects to a database server and the client-side database connection method decides to exit the program with an arbirary status number upon a connection error, you have no control over the error. You may want to keep your program open -- deal with the error -- display a message to the user, perhaps, and continue to attempt your connections to the database. If the database API violates this principle, you may be at an impass. If you are the API's author, you would be responsible.