This website is no longer maintained. Its content may be obsolete. Please visit http://home.cern/ for current CERN information.
Anaphe Programming Guidelines
Adapted by Max Sang from the Rational© guidelines and
others (Taligent©, Ellemtal©, Stroustrup, Eckel, etc.)
Please read Effective C++ and its successors if you haven't already. They are good
for your soul. Also read the design guidelines.
First Principles
- Minimal Surprise Over its lifetime, source code is read more often than it is
written, so programs should be written for human consumption rather than for the compiler.
Doing unusual things places a burden on future maintainers of your code.
- Abstraction. Abstraction is fundamental to
readable and maintainable code. Every function should do exactly one task, and be as short
as possible. Anything that takes several lines to express should be moved to a separate
function. Humans can only hold a small number of items in their 'memory cache', so long functions
are much more difficult to understand. Always look for places where new classes would help
to represent concepts in your code (this may be considered design rather than coding).
- Localisation. Say things exactly once. Code duplication is a maintainance
problem (abstraction naturally reduces duplication, but doesn't eliminate it).
General Style
- Indentation should be uniform and conventional - 'Stroustrup-like' is a good guide.
If the Emacs automatic formatting looks extremely different to your style,
think again!
- Make the effort to avoid cluttering the source
code with visual 'noise': bars, boxes, and other text with low
information content. Clean code is easier to read and maintain.
- Resist the temptation to put gratuitous whitespace inside methods, functions or class
declarations. It usually makes them harder for others to read.
- Don't let your lines get excessively long - pick a number (e.g. 90 characters), and stick to it,
especially in a single file. Wrap long lines consistently and conventionally.
Comments
Avoid comments except where necessary - over time and editing, comments can become misleading,
which is much worse than no comments at all.
- Write self-documenting code rather than comments by,
for example, choosing better names; using extra temporary variables;
or re-structuring the code.
- They should supplement source code by explaining what is not obvious - they
should not duplicate the language syntax or semantics.
- They should highlight: deviations from coding or design standards; the use
of restricted features; special 'tricks'; things which could be improved but
you just didn't get round to improving them yet.
- Use // ... rather than /* ... */, except when commenting large chunks
of code (during debugging or whatever). The C-style comment can cause horrible bugs.
Naming
The naming rules from the design guidelines are also recommended
for implementation. In addition,
- Augment names with grammatical elements to emphasise meaning - e.g.
to indicate uniqueness, or to show that this entity is the main focus of the
action, prefix the object or parameter name with the.
- In general, the scope of a name determines
how explicit it needs to be. In a three line method, using the variable nt is sometimes
fine, and using numberOfInputTracks is overkill. In namespace scope, the latter would be
essential (and perhaps even a bit brief!) and the former would be absolutely insane. If you are in
any doubt use a longer, more explicit name.
Classes
- Avoid method definitions in the class declaration. It makes the declaration much less
readable and splits implementation details over (at least) two files. It can also cause code
bloat, since they are usually inlined.
- Remember to do 'deep copying' of pointer members where appropriate (which is almost everywhere).
- Use constructor-initialisers rather than assignments in constructors whenever possible.
- Calling member functions from a constructor body can be risky, and calling them from an initialiser
is even more risky. Discuss it with somebody first to make sure you know what you're doing and there's no
other way to do it.
- Use static const for class-scope constants.
- operator= should check for self assignment, and return *this.
- Use class-scope typedefs to create more concise typenames - they can make methods
much easier to read, e.g.
typedef std::map<std::string, Widget>::const_iterator WidgetMapCIt;
Other Guidelines
- Treat compiler warnings as if they were errors
- Avoid 'magic numbers' in all their forms, e.g.
int A=7, B=A, ohDear = A+8; // two bad things
- Strive for functions with a single point of return. return statements sprinkled
freely over a function body make the code more difficult to read and to maintain.
- Pass arguments by (const) reference, unless you have a good reason to do otherwise.
- Never choose a 'more efficient' way of coding an algorithm if it affects the readability.
It can always be changed later. Premature optimisation is generally harmful.
- Preprocessor macros are evil! Don't use them (debugging is a possible exception...)
- Declare objects close to their point of first use - except when deeply-nested object creation
and destruction could cause a performance problem.
- Always initialise objects at declaration - don't rely on compiler defaults
- Use const wherever possible. Avoid casting away the const-ness of an object.
If essential make a non-const copy and use that instead. const is a "guarantee", checked by
the compiler, and should not be subverted.
- Use redundant parentheses to make compound expressions clearer. Even if you think you know the
precedence of every operator in C++, a reader might not.
- Avoid nesting expressions too deeply. If you have more than three nested expressions, there is
probably a need for more abstraction.
- Don't use C-style casts. They are a nightmare to spot, and can be very ambiguous.
- After deleting a heap object, always assign its pointer to zero.
- Provide a default branch for switch-statements for catching errors. The exception is
for enumerations, where the compiler can warn you if you forget any.
- Don't use goto. It is the most evil construct known to man.
- Avoid the hiding of identifiers in nested scopes
- Use assertions liberally during development, but remember the assertion statements
will disappear from the released libraries.
- Be aware of default type conversions.
- Perform safety checks locally - do not expect your clients to do so.
- Use standard library components whenever possible.
Physical Organisation
- Place class specifications and implementations in separate .h and .cpp files
- Avoid defining more than one class per module specification
Only upon rare occasions should multiple classes be placed together in a
module; and then only if they are closely associated (e.g., a container and
its iterator).
- Use forward-declarations (e.g. class X;) in header files
and only use #include "X.h" in the implementation file(s). This reduces
physical dependencies, and therefore compilation overhead.
- Use inclusion guards to protect against repeated file inclusions, e.g. file
fred.h uses:
#ifndef FRED_H
#define FRED_H
// Fred is an nice class which ...etc...
class Fred
{ ...
};
#endif // FRED_H
Max Sang
Last modified: Wed Mar 6 18:52:26 CET 2002