Design Rules
From iWear
The iWear Framework follows a few style and design rules. We believe that the developers of the framework apply common sense, and to not try to circumvent willingly any general design guidelines. Therefore this set of rules is extended by global valid knowledge, as well as a set of per-library rules. Most of them are in fact style rules, but since they sometimes go hand in hand, we called this article Design Rules.
Contents |
Naming conventions
Filenames
All filenames shall be completely lowercase. All headers shall have .h as their ending. All C files shall have .c as their ending. All C++ files shall have .cpp as their ending. All generated C++ files shall have .cc as their ending.
Include Guards
All include guards shall contain their path and header names, while / and . are replaced by underscores. All headerguards are uppercase and start with two underscores. While we are well aware that the ISO standards reserve all identifiers that contain double underscores, we believe that our names will nevertheless never collide with names possibly chosen by a standards implementation.
Note: These rules are not yet in effect, due to delay because the context modules have to be extended. When jrei is done with his thesis, those new rules will take effect.
Example:
#ifndef __IWEAR_IWEAR_CONFIGURATION_H #define __IWEAR_IWEAR_CONFIGURATION_H #endif // or #ifndef __IWEAR_IWSENS_SENSOR_H #define __IWEAR_IWSENS_SENSOR_H #endif
To save a little bit of compilation times, all iWear headers shall only conditionally include other iWear headers, taking advantage of the header guards.
Example:
#ifndef __IWEAR_IWEAR_CONFIGURATION_H #include <iwear/iwear/configuration.h> #endif // or #ifndef __IWEAR_IWSENS_SENSOR_H #include <iwear/iwsens/sensor.h> #endif
Here you can see, why we choosed that representation: it lines up nicely with the include statements.
classes
Classes shall be named uniformly within their respective modules. But it is recommended to 'not' use CamelCase but instead use all lowercase functions, with underscores as delimters.
Example:
get_latest_context_subset(); // Use this GetLatestContextSubset(); // do NOT use this
Code Conventions
These conventions mainly are for the core and sensor libraries, but as long as other libraries do not have their own, they should try using these ones
macros
Macros are all caps and use underscores as seperators.
Example:
#define STRINGIFY_PURE(x) STRINGIFY(x) //NOT: #define StringifyPure(x) STRINGIFY(x)
This is to make clear that its a macro and not a function call.
blocks
Blocks start and end on a single line, with the same indentation as the statement introducing the block (if any).
Example:
if( foobar )
{
for(;;)
{
}
}
// NOT:
if( foobar ) {
for(;;;) {
}
}
While the later one clearly uses less lines -- which is probably the main argument of their users -- the earlier has the clear advantage, that -- especially when using an editor that highlights matching braces -- its much easier to spot on much nested constructs. Also, when you have an editor, that allows you to jump between the braces, especially on long complex code, you can more easily navigate, by just going a few lines down, then jump to the next brace, again a few down etc.
Also, there shall be statements that can introduce blocks, but don't.
Example:
if( foobar )
{
do_something();
}
else
{
do_something_else();
}
// NOT:
if( foobar )
do_something();
else
do_something_else();
While also here the latter is shorter (fitting to those who think its important that "as much code as possible is visible in one window") the earlier has the advantage that its clearer, less error prone, and easier to quickly extend. Like, when I want to just quickly add some debug statement and them remove it again, in the first version, I just add and remove the statement, while in the second I have to add and remove braces. Or I can forget to add them, which leads to errors.
Directory structure
Beginning with the works for the new release, the iWear framework has a new directory structure of the include files. The full conversion to this scheme will also be delayed until jrei finishes his thesis.
.
`-- iwear
|-- sensor
|-- rpc
|-- output
|-- iwear
`-- input
Interfaces
We distinguish between public, protected and private interfaces.
public interfaces
Public interfaces are all those functions that begin with a letter, that are declared public access within a class. Also types that are declared public within another class belong to the public interface, as well as types declared within namespace scope. Exceptions are either marked directly in the code, or in the specification of the other interface types.
These are the functions that the users of the classes shall use.
protected interfaces
Protected interfaces are those functions beginning with a letter that are within the protected access block of the classes. The same applies to types within such blocks, or within a namespace called detail that is under the current namespace. Exceptions will be explicitly marked in code.
These are the functions, that developers who wish to extend functionality of the classes shall use.
private interfaces
Private interfaces are all functions and types that are declared within the private protection block of a class. Aditionally all functions and types in all other blocks of a class, or within any other namespace that begin with an underscore belong to the private interface.
These are the parts neither the users of the framework, nor third party developers who wish to extend the framework shall use. Functionality, signature and naming of those functions may change within even subreleases. Even within the framework, it is recommended to not use those functions from other modules at all.
Releases
We have the common naming scheme of releases. They can be of the form: x.y.z.p
Major Releases (x)
Major releases will be made, when something fundamental changes. This can be a complete rewrite of a big part of the library, or a huge reorganizazion within the project, or a vast addition of functionality.
These releases are not in any way source or binary compatible to previous releases. SVN branches will be created only when necessary, deviating from HEAD.
Minor Releases (y)
These releases denote some bigger changes, such as some reorganizations, features beeing added, big bugfixes, new libraries etc.
These releases are not in any way source or binary compatible to previous releases. Developement will take part in the SVN HEAD until a stable enough state is reached, at which a branch for that release will be generated. Those releases will go through major beta phases, as well as release candidate phases.
Subreleases (z)
Whenever some bigger bugs have to be fixed, or when some functionality can be added that doesn't disturb the other code much, it will be done in a subrelease.
Subreleasese shall be source compatible if possible, as well as binary compatible if possible. They will be made ongoing from the branch that was made to create the corresponding minor release. Important bug fixes that are easy to merge from HEAD shall also go here.
Quick releases (p)
Quick releases are -- as the name implies -- releases that are there for fast reaction on bugs, most likely security fixes.
Quick releases shall only fix important issues, and shall also be source and binary compatible, if possible. For that it is also acceptible to introduce "hacks" into the source code, that will never occur in the mainline code. This will also create a branch, where the changes shall either be merged into the minor and HEAD, or if its a hack, minor and HEAD shall implement a better fix.
