Coding Standards

From NexusCrossing

Jump to: navigation, search

Every project, and for that matter every organization, needs a set of standards and guidelines to follow while writing programs in order to insure that their code is clean and readable. If one programmer passes their code off to another it is important that the new programmer be able to know what is going on in the code.

At this time, I am reading various books and articles, and working on building a standard for use with my projects. Feel free to use the Discussion link to discuss changes that you think should be made.

One text that I am looking at heavily is Industrial Strength C++ [1][2].

As in Industrial Strength C++, I will list things here in terms of Rules and Recomendations. As this is a wiki environment, even rules are subject to change from time to time. Much discussion is possible on the subject via the discussion link at the top of this page. I will come up with a numbering system eventually, but that will come when I have more of the rules and guidelines in place.

This page will likely be a work in progress for a while. For the moment, I highly suggest taking a look at Industrial Strength C++. Even though it is ten years old, it is still heald as a standard by much of the community, and the rules it gives are all very helpful.

Contents

[edit] Naming Conventions

How you name variables can be very important. It can have an impact on the future readability of your code. If code cannot be read and understood, then it cannot be properly maintained.

[edit] Recommendation: Use Meaningful names

The name of a variable should describe it's function. This does not mean that every itterator will be given a unique name, but the variables that need to be used and changed often probably should.

[edit] Recommendation: Use English names for identifiers

This is not a matter of predudice. It is commonly accepted that English is the default language in programming. This is not because English is better than any other language. This is not because there are more English speaking programmers than any other language. It is simply because over the course of the last four hundred years or so English speaking countries have been stubborn and obstinate enough that everyone else had to learn at least a little English in order to do business. Because we are stuborn bastards, everyone knows our language to at least a small degree. That just makes it a convenient language for programmers to use now.


[edit] Recommendation: Avoid using Abreviations.

Abreviations may seem like a good idea, but if they are not commonly known to pretty much everyone, then they can eventually get in the way. Abreviations are not all bad, but use them with care.

[edit] Recommendation: Be consistant when naming things.

When you name types, variables, constants, member functions and such maintain some degree of consitancy so that it will be easier for people to figure out what different objects do. The easier it is for a person to look at information and understand what they are seeing, the more likely they are to reuse the code.

[edit] Recommendation: Only namespace names should be global.

Everthing else should reside in a namespace. This helps you avoid namespace collisions. It helps to keep all of your code in an organized package so that you do not risk outside interfearance.

[edit] Recommendation: Do not use global using delcarations or using directives in headers

If you think about this one you will realize that putting a global using directive or declaration in a header file is a quick way to cancel out the beneffits of using a namespace. using directives import names into the current namespace, where they are then free to clash with everyone else. Be careful when you do this.

This does not stop us from using the using directive (no pun intended) inside of implementation files though.

[edit] Recommendation: Use Prefixes to group Macros.

Two or three characters added to the beginning of macro names can help to identify which library the macro belongs to. This can be helpfull, because macros do not follow any particular namespace rules.

[edit] Recommendation: Use subdirectories in the grouping of source files.

[edit] Recommendation: Use prefixes in the naming of Classes and Enumerated Types.

 At this time, I am using namespaces to group classes, and directories to group source files.
 I will do a better writeup on this soon.

While the use of namespaces makes this more a matter of prefference and style, prefixes still allow you to quickly identify which version of a class you are dealing with. It also leaves less chance of namespace collision if the end user decides to import entire namespaces with the using statement. A three or four character prefix takes only a slight adjustment to get used to using, and can help to make the code more readable in the longrun.

[edit] Rule: Do not use identifiers that contain two or more underscores in a row.

[edit] Rule: Do not use identifiers that start with an underscore.

Identifiers cannot contain two underscores in a row. All such identifiers are reserved for use by the compiler.

Identifiers that start with an underscore and a capital letter (i.e. _X or _Y) are also reserved by the compiler. For this reason, it is best to avoid using underscores as the first character of an identifier so that we can avoid confusion.


[edit] Recommendation: Variable Names should start with lowercase letters, then capitalize the first letter of each additional word.

[edit] Recommendation: Class, typedef, and enum names should start with a capital letter

[edit] Recommendation: The names of Macros should be in all capital letters

[edit] Recommendation: Identify data members with the suffix _m

Examples:

 #define MAXVALUE 100
 typedef vector<int> IntVector;
 enum Toys {JACKINTHEBOX=0, SPINNINGTOP, BARBIEDOLL};
 int testCases;
 
 class MyObjectClass
 {
   public:
     int size(void){return count_m;}
     void set_object_id(int id);
     int get_object_id(void);
   private:
     int count_m;
     int objectId_m;
 };

[edit] Comments & Documentation

[edit] Rule: Header Files should be documented in a Doxygen friendly manner

Doxygen[3] is a program designed to automatically generate documentation for software projects. This is done by parsing the code and comments in source files. It is ideal for creating API and interface documentation but can also be used for the generation of more general documents.

The Doxygen documenation[3] has information on how to propperly comment your code to be readable by Doxygen. It is no more difficult to use these commenting guidelines than any other, it just takes a bit of a learning curve at first. The result however is that the comments are written in a standardized and readable manner, and can be used to quickly generate documentation for the project distributions.

The easiest way to summarize Doxygen is that it starts with the concept that the best documentation for a source file is the source file itself. It then abstracts that concept out to generate HTML, Latex, PDF, and other document formats.

The reason I specifically state header files, is so that we have a uniform way of documenting class interfaces, constants, enum data types etc...

[edit] Rule: Each file should contain a copyright comment

[edit] Rule: Each file should contain a description of it's contents

[edit] Rule: Each file should contain Licensing information

Below is an example of the kind of header I personally will include in most files. First of all, the comments are formatted in such a way as to be readable by Doxygen[3]. Because of the nature of Doxygen however, they are also very much human readable.

The \file tag tells the reader and Doxygen that we are looking at the file lgp_random.h. \brief is the most brief description of the file's comments. \author and \version provide more details about the file. The rest of the comment block is seen as the long description of the files comments. Doxygen will treat it all as one section until it reaches another tag that defines a block of information.

Also here I have included the copyright notice for the file as well as licensing information. Since I am using the BSD license, and it does not take much space, I am including the license in file.

The reason for the <br /> at the ends of each line of the copyright notice is to make up for the fact that Doxygen produces documentation in HTML and other formats. When creating HTML Documentation the <br /> will be added directly into the file causing the text to display properly in HTML. In non-HTML formats the <br /> will be converted to an appropriate line break for that format.


 /// \file lgp_random.hpp
 /// \brief A set of functions to deal with random numbers.
 /// \author Kenneth. M. Burling Jr. (a.k.a Emry)
 /// \version Alpha-0.001
 ///
 /// copyright: Copyright © 2008, 2009, 2010 K. M. Burling Jr.
/// All Rights Reserved /// /// Redistribution and use in source and binary forms, with or without modification, are permitted provided that /// the following conditions are met: /// /// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. /// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following /// disclaimer in the documentation and/or other materials provided with the distribution. /// * Neither the name of the libgamepieces project team, nor the names of its contributors may be used to endorse or /// promote products derived from this software without specific prior written permission. /// /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, /// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE /// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, /// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR /// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, /// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE /// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// /// randomnumbers.hpp and randomnumbers.cpp are part of libemtools. They /// contain a handfull of basic functions for dealign with random numbers. /// /// libemtools is a library of basic tools that I am putting together as I go. /// /// File last updated 14:34 JST on 9 Sept 2009

[edit] Recommendation: All comments should be in English

This will make things easier on others who are contributing to the project.

[edit] Recommendation: Document all Classes and all public member functions

[edit] Code Organization

[edit] Rule: Each header file should be self contained

You should only need to include one header file in order to fully access a given class. When possible, header files should be tested to see that they can achieve this. If the header file describes the interface to a class, it should be the first file included in the cooresponding implementation file. This way, if the header file is not self contained it will likely give errors indicating what needs to be fixed.

[edit] Rule: Avoid unneccessary inclussion

Include only what is needed to allow a file to compile and perform its expected functions.

There are cases where a file does not need to know the entire description of a class, and a forward declaration will suffice.

[edit] Rule: Always use include guards

The contents of a header file should only be included once. Sometimes in large projects it is possible for a file to be included many times. To prevent this from being a problem, use include guards to guarantee that the information is only actually included once.


  #ifndef LGP_OBJECT_CLASS_HEADER
  #define LGP_OBJECT_CLASS_HEADER
  ...
  ...Rest of File...
  ...
  #endif   //LGP_OBJECT_CLASS_HEADER

[edit] Flow Control

[edit] Rule: Do not change the loop variable inside a for loop block.

For loops are inteded to create a situation in which a set of instructions are repeated a finite number of times. While this number may be variable, it should be determined before entering the loop. Directly manipulating the variable within the loop can potentially cause an infinite loop, or strange logic errors that are hard to track down.

[edit] Recommendation: Update the looping variable neer where the condition is checked.

When a for loop is used, the only place the variable should be updated is in the header for the loop. The loop variable is updated after the block has exited, and after the loop condition has been checked.

When a while loop is used, the loop condition is checked before entering the block. The loop variable should be updated at the beginning of the block.

when a do-while loop is used, the loop executes at least once before the loop condition is tested. The loop variable should be updated at the end of the block.

These guidelines allow you to quickly look at a loop and see the conditional statement, and the statement that updates the loop without having to hunt around for the two lines. Often times errors in loops will be in one of these places, and the two are very closely connected.

[edit] Rule: All flow control primitives should be followed by a block.

Even if the code doesn't really do anyting other than loop or update the variable repeatedly, it should still be followed by a block. Even if the code is only one line, it should be followed by a block. This makes it very obvious when you do intend for the loop to be empty. It also makes it easier to avoid including an unintended statement as a part of the conditional statement.

 Examples:
 
 int x = 0;
 while(x <= 100){x++;}
 
 for(int x=0; x <= 100; x++){;}

This applies to if, else, for, while, do, switch, and case.

[edit] Recommendation: Blocks following a case statement should temrinate with a statement that exits the switch statement.

for instance, break or return. Fall through is allowable for cases that are intended to do the same thing. Fallthrough can also be used for cumulative effects, but be careful to document the code so that other programmers know what you are doing.

[edit] Recommendation: All switch statements should have a default clause.

I am tempted to list this one as a rule. A default clause lets you test for those situations where the program just throws you random data. Without a default clause, invalid data could simply be ignored.

[edit] Rule: Do not use goto.

[edit] Recommendation: Avoid overly complex functions

If a function is getting too long, then you can probably refactor it as two or three functions.

[edit] References

  1. http://sannabremo.se/nyquist/industrial/
  2. Industrian Strength C++, Copyright ©1997 Mats Henricson, Erik Nyquist and Ellemtel Utvecklings AB, Published by Prentice Hall PTR. ISBN 0-13-120965-5
  3. 3.0 3.1 3.2 http://www.stack.nl/~dimitri/doxygen/
Personal tools