Strus programming guidelines
Programming language
Strus is implemented in C++.
Paradigms
Exception free interfaces
Interface classes must be exception free (they must not throw any exception) because
their calls might cross library or module boundaries and the very rigid linking rules
implied do not allow exceptions to be caught when
crossing library or module borders on many systems (e.g. with GCC).
Classes implementing such an interface class catch exceptions in their
methods before returning and report the caught exceptions through an error reporting
interface. The caller can later fetch the error from this error buffering interface.
The error reporting interface is passed down to the objects behind the scenes when
constructing the objects. This way it does not appear in the interfaces, only as interface class
on its own.
Polymorphism
Inheritance is only used for implementing pure interfaces. The names of the abstract classes all end with "Interface". Objects in strus are all either pure data types with no polymorphism or implementations of pure interfaces referenced by pointers. This restriction makes all elements of the interface either serializable or proxyable.
Public/private/protected
Avoid protected members and don't use public or friends to open backdoors whenever possible.
Components built as libraries
All components even extensions should be implemented as libraries. If they are built a modules the module whould wrap to the library.
Use of templates
No templates in public interfaces.
Naming conventions
Type naming
In interfaces, strict camel case is used. Type, struct and class names and enum members start with a capital letter. Exceptions to this rule are data types implementing an STL concept like for example an iterator. Method names start with a lower case letter. Enum names may or may not contain only capital letters.
Source file names
Source and header file names start with a lower case letter
and have - despite that - exactly the same name as the main class they implement.
The wished rule is one class per source file, but this is not always the case, though
it is the case for interface header files.
The main source file of a library has the same name trunk as the library. This name trunk has always
the prefix 'libstrus_'. Main header files of libraries are in a 'lib'
subdirectory of the main include and have the same name as the library
without the prefix 'libstrus_'.
Macro names
Macros have only capital letters with underscores '_'
separating semantical parts of the macro identifier.
The use of macros should be avoided. Their use is obviously inevitable when they stear
alternative compiling or when they inject externally defined values like for example
version numbers.
In other cases, the use of macros has to be discussed and it is not a single contributors
decision when to use macros. If used they should conceptually add value to the
software in terms of readability and uniformity.
In the exported application interfaces the use of macros is forbidden.
Module global variable names
Static global variable names in a modules (never exported) have the prefix 'g_'.
Parameter names
Class method parameter names of classes have the suffix '_', if their name clashes with a member name. Such name clashes should only happen if the parameter initializes a member name. Otherwise the naming would be misleading.
Local variable names
Avoid variable names containing only one letter like 'i', 'x'.
They are hard to find without an editor supporting the programming language.
(I personally do not like programming environments that go beyond a text editor with some
highlighting. I am convinced that the quality of code raises in the absence of
semantically supported navigation help because it educates you to work towards
a clear and consistent naming scheme.)
Visibility
Use explicit visibility to declare exported symbols of shared libraries. Shared libraries export only functions constructing objects implementing an interface, having only interface references or POD data types or serializable C++ and STL data types as arguments.
Friend declarations
Do not use friend declarations if possible. In most cases they are just backdoors that camouflage bad design.
Member variables
Member variable names have the prefix 'm_' if they are part of the interface. For pure POD structure types, that are only used internally this prefix may be omitted.
Build system
Build tool
The build system is currently CMake. But packaging with CPack is forbidden. Packages are implemented manually.
Mixing compilers/linkers
Compilers and linkers for building libraries and modules of strus may not be mixable due to an interface design using STL data types passing the interface. You have to check, if the STL data type implementations are compatible before mixing compilers. Due to the fact that the interfaces are exception free, there are no further restrictions.
Code appearance
Indentation
Indentation with TABs only. Pascal style opening of block brackets '{' '}'. This means that you start a new line for the '{' opening a new block. The then clause of if statements with one assignment may be written without opening and close brackets, e.g. "if (size > 0) sizeType = NON_ZERO;"
Source code documentation
Avoid documenting the obvious. Documentation should be minimal
in the source and only contain real information. Use numbering for execution steps and
alphabetic labeling for alternative choices. If you have the alternative to
choose an implementation of a function with 300 lines of expanded code or an
implementation of it as small function calling 10 subroutines, that have 7
arguments and names that are not self-explaining and each of them is called only
once, then please choose the 300 line expanded implementation and document
the execution steps well.
Use prefixes like
XY:NOTE or XY:HACK where XY stands for your acronym for marking undesirable
situations (NOTE) or incomplete fixes or fixes with bad implications (HACK)
that should be fixed but can not be fixed instantly.
Doxygen documentation
Interface documentation should be in doxygen style (backslash variant).
Errors/Warnings
There must not appear any compiler warning or error in the build.
Use the most restrictive compiler and linker settings available on your platform and declare warnings as
errors. There might exist exceptional cases (not till now !), but they have to be discussed.
One exception are some language bindings, because their sources are generated by 3rdParty software.