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.