This website is no longer maintained. Its content may be obsolete. Please visit http://home.cern/ for current CERN information.
Anaphe Design 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 coding guidelines.
First Principles
- If you don't understand a guideline, don't just ignore it, ask somebody for clarification! :-)
- If you feel a guideline doesn't apply to your problem, discuss it. These are not 'rules'.
- Keep It Simple, Stupid! Elegance is important, and hacks are a
false economy.
- Use abstraction to manage complexity.
- Use localisation ("say things exactly once") to reduce maintainance effort
- Use encapsulation to insulate interface from implementation
- We don't throw exceptions in Anaphe (so far).
Class Design
- Try to map the distinct concepts in the problem domain to classes.
- Model using UML, and keep the model up to date.
- Never write a line of implementation until your classes and their public interfaces are defined
and reasonably stable.
- A class interface should be minimal and orthogonal
- Use public inheritance to model 'is a' (specialisation). Don't use protected or private
inheritance.
- Avoid multiple inheritance
- Never re-define non-virtual methods. If you have a class with some virtual and some non-virtual
methods, think again!
- Destructors should be virtual unless derivation from the class makes no sense.
- Use private aggregation (and controlled exposure) to model 'has a'. Always prefer it to public
aggregation, which can be inflexible.
- Downcasting or run-time type identification often means there are flaws in the design. Discuss it!
- Don't use the f(...) syntax to subvert the type system
- Think very carefully about the semantics of each class (abstract/concrete? is it a singleton?
is assignment allowed? should it have a default constructor? etc.)
- Declare the four magic methods (default and copy ctors, op= and dtor) in every class. Decide which
should be public, private or protected; and then decide which should be defined.
- Never use public member data
- Protected data is risky, and only ever allowed in abstract classes. Even here, there are usually better
solutions. Discuss it.
- Friendship is usually a bad thing, but with two closely related classes, friendship is
certainly preferable to violating encapsulation. However, it is a maintainance nightmare. To limit the
damage, abstract the functionality which requires friendship into a new class, and make this class friends
with one or both classes as necessary. Document it carefully!
- Build in const-safety at the beginning, and understand whether you mean bit-wise or logical
constness
Modularity and re-use
- Stick to bool, char, int and double (avoid the other basic types).
- Minimise logical dependencies. Normally, the only dependencies permitted are on the Interfaces,
these basic types and the foundation libraries (STL and HepUtilities).
- Use the STL as much as possible - e.g. use vectors instead of arrays, strings instead
of char*s, etc.
- Learn about Design Patterns and employ them wherever appropriate. Name your classes similarly
to their analogues in the pattern.
Object Management
- Where a function returns a reference or pointer, the ownership of the object referred to
should be unambiguous
- Consider using auto_ptr instead of manually deleting heap objects
Functions, Methods and Operators
- Getters and setters should refer only to conceptual, independent "attributes", not implementation
details (see encapsulation). When you write a getter, use theProperty() rather than
getTheProperty()
- Don't use pointers where you can use references
- Every function argument, except the built-in types, should be passed by reference or (sometimes)
pointer. Avoid passing by value!
- Don't try to return a reference when you should return an object
- Declare function arguments in order of decreasing importance (from the client's point of
view), and use default arguments where appropriate.
- Prefer default parameters to function overloading
- Don't be afraid to use function overloading if the meaning is clear
- If you really have to overload operators, be very conservative - stick to the semantics of
the built-in types ('do as the ints do')
Naming
Max Sang
Last modified: Wed Mar 6 18:50:40 CET 2002