Tabel of Contens
First at all I would like to thank Gunnstein Lye. He his the author of the originale style-guide. It is a good one to use it in opensource projects. For our project I was so free to add some extras and remove some . The rest of document is the same like at zez.org. Coding standards define a standard for the look and feel of your code. This is helpful to most projects, and to some it is a necessity. Especially in open source projects. The goal of this articles is to show how coding standards will improve a development project.
A coding standard is a set of rules describing how your code should look, which features of the programming language you will use and how, and possibly which tools should be used to write the code. It can of course be as specific as you want it to be. Why is it good?
People are different. We like different things, wear different clothes, and use different styles when coding. This is fine as long as we just write small programs and scripts for ourselves. When many people
collaborate on a project, the differences in coding style will lead to disagreements and poor readability which will hamper the cooperation and thereby the effectiveness of the project. An example of such disagreements is the simple, but widespread problem of indentation. How much indentation should be used? Where? Should we use spaces or tabs? There are probably as many opinions on this as there are programmers, and most of them are dead sure that their way is the right one. (The correct way of indenting C++ code is 3 or 4 spaces per level and no tabs, if you were curious. And, by the way, keep those curly brackets on a separate line, or you'll face at least seven years of bad luck and core dumps.) These problems are obvious in many open source projects where perhaps hundreds of people from all around the world develop software together, but it will soon become a problem in small projects and corporate environments as well. Even when you just write your own programs you will run into difficulties sooner or later, unless you use some kind of coding standard.
Your personal
taste in programming is in itself a coding standard. You don't randomly
use constants with upper and lower
case, you probably don't mix different styles of while-loops
and you definitely don't use a
different indentation for each line of code. (At least I hope you don't,
for your own sanity's sake.) Standards
are natural. Unfortunately, arguing about them is, too. Always remember,
when you join an open source project
it is common sense to follow that project's standards.
If you try to force your
standards on others you'll lose your write privileges faster than fast.
That's one of the great advantages of starting a
project, you get to do it the right way - your way.
I'll try not to talk too much about how great this standard is (it is of course the best possible standard, but, as I said, I'll try not to talk too much about that) but rather to stress the importance of having standards at all. Almost any standard is better than no standard. And again, this is a C++ example, but the principles and concepts here are valid for many, if not most programming languages.
All filenames are lowercase. Header files are suffixed with .hpp, implementation files with .cpp. The advantages of using all lowercase filenames on a case-sensitive system like Linux is obvious. The use of the .hpp suffix enables us to differ between C and C++ header files. Each cpp/hpp pair contains only one class, unless we are using private classes. If a header file contains constants and declarations that don't need external includes, as well as other declarations that do need external includes, then dividing this file to avoid too many dependencies could be a good idea. An implementation file that has to be written differently for different platforms, is to be split into one file containing platform-independent code, and one file per platform containing platform-dependent code. All #include<> should be sorted from A to Z. Below of that kind of includes you can list the #include"" in the same order like the others.
The header of each file should contain a couple of importend information like:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Programm: This class handels
the tabbar (e.g. paint, repaint, add/del tab)
//File: tabbar.h
//Author: Juergen P. Messerer
//Date(dd.mm.yy): 3.2.1999
//License:
//Revision:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
Macros and other # commands are
to be avoided. Exceptions are #include and the necessary #ifndef, #define,
#endif in header files. Macros can be used when there are good reasons
to do so, though.
Use 3 or 4 character indentation, this is commonly used and allows for easy recognition of the indentation level. Use spaces in stead of TABs, to assure the code looks the same every-where.
int meaning( int x, int y )
{
if( x == y )
{
..
}
else
{
if( x > y )
{
...
}
else
{
...
}
}
return42;
}
|
2.4 Parentheses, brackets and comma
Nested if statements must use brackets {}. If you have many consecutive if and else if statements, consider using case statements instead, or redesign using a more object oriented approach. If statements and while loops can only execute boolean expressions, never assign or change any data.
The next part of this article will be a bit longer and more advanced, as I'll advance to topics such as naming conventions, functions, classes and namespaces.
All names must be written in English, and be grammatically correct. Avoid names that don't mean anything, like foo and tmp. Any numbers in a name must be written using letters, not numbers, unless there is a good reason not to.
ValueOne |
Functions can be made up from several words, the first letter of each word in uppercase and the rest in lowercase. The first word must be all lowercase. Acronyms should not be used.
void setText( const QString &r_text ); |
|
Pointers should start
with a p_ and references with r_.
int*p_myPointer;
char&r_yourReferenc;
|
Constants are written
in uppercase, multiple words divided by underscore.
const float PI =3.1415;
const int MAGIC_NUMBER
=42;
|
Enumerators and member variables can be made up from several words, the first letter of each word in uppercase and the rest in lowercase. They should normally not consist of more than three words. Acronyms can be used as long as the meaning is obvious.
enum DayType
{
Monday,
Tuesday,
...
};
|
private:
int Len;
int X,Y;
|
Local variables can consist of several words, using only lowercase. Use underscore to divide words. Use as few words as possible, and use acronyms when needed. Special acronyms like i (index) and x,y (position) are allowed. Parameters should be named in the same way as local variables.
int i, index, x, y;
int x_add;
|
Class
names can be made up from several words, the first letter of each word
in uppercase and the rest in lowercase.
class Dialog;
lass ModuleManager;
|
Static variables should
be named like member variables, but they must end with an underscore.
static int refCount;
double myMember_; //Membervariable of a class
char *m_alsoMember; //Membervariable of a class |
Never use global
variables, put them in a class and make them static.
All functions must be placed inside classes. Exceptions are main() and functions used as an interface between classes and a C-API. Functions should be short and do one task. The length of the function depends on how complex it is. The more complex the function is, the shorter it should be. Too long functions should be split into several functions each doing a minor task. A function should not be longer than 30-40 lines. Use variables sparingly, split the function when you have too many. If the function is clearly divided into different parts you may use more variables, but no more than 7 per block of code. Exceptions to this rule are certain mathematical calculations where speed is essential. If a function has many parameters it might be wise to split the parameter line into several lines, place the parameters with a close relation to each other on the same line. Many parameters is often a sign that your function is too big, try splitting it. Try to make functions const as often as possible. Avoid inline code, but when you do use it, try to post phone it until the class is considered done. This is to avoid massive recompiling due to dependencies. Be careful with default values for function parameters, try to specify everything as explicitly as possible. For optical reason it is better to put a comment line between each implementation of the functions.
}
//---------------------------------------------------------------
void MyClass::function()
{
|
In order to avoid bad or too long class
names, use name spaces to split and ground classes and functions. This
means that two classes can have the same name as long as they exist in
different name spaces, enabling you the use more intuitive names. However,
before you start using name spaces make sure it will work on all platforms
used in the project.
Classes should do only one thing and do it well. Split it into subclasses if it's too big. Use multiple inheritance sparingly, consider using a pointer to an object (this is often called composition) instead of inheriting it. All member variables must be private. When access to member variables is required use functions, never use public or protected variables.
Helper functions
should be private. Functions that don't access member variables or functions
can be made static.
For every
function, write a comment that explain what it does, and any hard-to-understand
parameters. These comments
should be written in Doxygen syntax. Also write a comment on a class'
area of responsibility. Use a newline
between comments and functions. Don't
over comment your code, use comments when needed. If you have to put lots
of comments in your code to
make it readable, it's a sign that it is badly written and should be redone.
Use exceptions to control things that don't work as they were expected to, like parameters having values they should never have. Use them often. Don't use exceptions as a way of leaving loops or nested function calls, or signalling an expected outcome. Be aware of memory leaks that may happen when using exceptions. (The book "The C++ Programming Language" by Bjarne Stroustrup has comments on this.) Functions that use exceptions should explicitly state so in the documentation. When using a function with exceptions, always use a try/catch statement to handle it. Use a try/catch statement in main() to tell the user/developer of any fatal errors that happens.