Coding Conventions for the KOM(S) Streaming System
This document describes the preferred coding style when changing and/or
extending komssys. Many developers contributed code to komssys over the time,
due to this fact the code has become quite inconsistent which makes it
difficult to read and to change. A lot of komssys code was written before
namespaces and the standard template library (STL) were part of C++. In order
to achieve better maintainability any newly written code should follow these
guidelines.
Section 1: Naming
Some classes start with the prefix "MN", don't use it in newly written classes,
in fact you shouldn't use class prefixes at all, use namespaces instead.
The Naming conventions you should stick to are pretty much the same as Sun's
Java Naming Conventions. That means in detail:
- Class names should be nouns, in mixed case with the first letter of each
internal word capitalized, e. g. "class ProxyServer".
- Function names should be verbs with the same syntax as class names except the
first letter always being lowercase, e. g. "int getClientCount()".
- Member variables should start with an underscore and the next letter in
lowercase, e. g. "int _clientCount".
- Local variables should look like member variables but without the underscore,
e. g. "int tmp".
- Constants are written all uppercase letters with underscores delimiting the
distinct words, e. g. "const int MAX_VALUE = 64".
Section 2: Indentation and placing of braces
Indentation width should be 4 spaces. Following is a short example of how code
should look like. It also shows how curly braces should be placed, that is
to say every brace on its own line.
class Foo
{
public:
int getCount();
Foo* doSomething(Foo* aFoo);
private:
int _count;
};
int Foo::getCount()
{
return _count;
}
Foo* Foo::doSomething(Foo* aFoo)
{
if (aFoo == this)
{
_count++;
return this;
}
for (int i = 0; i < _count; ++i)
{
doWhatever(aFoo);
doMore();
}
return aFoo;
}
Section 3: Comments
You should at least comment class and function declarations unless the purpose
is really obvious. That means in front of every class and function should be an
comment block describing the purpose of it. The emphasis should be placed on
what a class or function does, not how. These comments should be in
the corresponding header files, preferably using doxygen style.
Inside functions you can comment blocks of code using normal C++ style
comments, but don't overdo it. Too many comments inside functions make the code
harder to read and sometimes even hint at bad code. Most of the time it's
better to extract complicated code into its own function with a meaningful name
instead of writing a comment.
Following is a commented class declaration as an example:
/*!
* The Foo class maintains connections from and to the
* proxy server. For the establishment of these connections
* see Bar class.
*/
class Foo
{
public:
/*! This function must be called directly after the constructor
* and before any other member function
*/
void initializeSockets();
/*! Responsible to start something */
int startSending();
private:
/*! container to keep the sockets */
std::vector<int> _connections;
};
Section 4: Macros
Simple rule: Avoid them. If you want to define constants use the const
qualifier or enum instead of #define. Especially the NULL macro for pointers
is frowned upon in C++, use 0 or 0x0 if you want to emphasize that it's a
pointer. One exception to this rule are include guards, which you should use in
every header file to avoid conflicts when included multiple times,
e. g. ServerGM.h looks like this:
#ifndef SERVER_GM_H
#define SERVER_GM_H
/* ...contents... */
#endif
Section 5: General Programming Practices
Komssys is a large software project. Without the aid of an IDE you will
probably get lost in the complexity. So do yourself a favor and get used to
one. If you don't know any IDEs try kdevelop or eclipse with CDT plugin.
Avoid public methods that return pointers or references to private member
variables; if you think you really have to do that, at least make the return
value const. Unfortunately this violation of the encapsulation principle is
quite common in current komssys code. The severe disadvantage of this is that it
leads to almost unmaintainable code, because changes to the private member
variable almost always force you to change every caller (which can be a lot) of
the method which returns the pointer or reference.
There are a number of container classes in komssys which are very similar to
classes in the Standard Template Library (STL) which is part of the C++
language standard. They stem from libg++, which was included with gcc before
STL. Most notably are the classes MNString and MNList. Use std::list in newly
written code instead of MNList, because the handling of std::list is more
intuitive and it's easier to read for people not used to the komssys code.
MNString on the other hand is so prevalent in komssys code that it makes no
sense to use std::string instead. As a general rule, prefer STL classes and
algorithms over self written code.
Functions should be preferably short to increase chances of code reuse.
Withstand the urge to copy and paste and extract code into its own function
instead of duplicating it, it leads to much better code.
Think twice before you define a function inline. Most of the time you
will be writing code that is not performance critical, so inlining will most
likely do more harm than good, because it makes debugging much harder.
If you notice that a switch statement you are writing becomes longer and longer
you should check if class inheritance and virtual functions are an appropriate
alternative. Maybe the state or strategy design patterns are helpful as well.
Section 6: Helpful literature
Stroustrup: The C++ Programming Language
{The definite reference regarding C++ details but not an easy
read for beginners}
Meyers: Effective C++; More Effective C++
{Recommendable to every C++ programmer. Very helpful guidelines
and easy to understand even for beginners}
Gamma et al: Design Patterns
{Very helpful with regard to object oriented software design}