Skip to content

Programming Guidelines

mikael-s-persson edited this page Sep 3, 2011 · 16 revisions

#Programming Guidelines

This page lays out some guidelines to follow when programming library code within the ReaK platform. These are not guidelines on using the different elements of the library, but since this is an open-architecture library, to use the library often implies extending the library for custom purposes, and these guidelines can be followed to do so harmoniously. Some guidelines will be stressed more than others, depending on their importance. For a more detailed list of issues and practical coding guidelines, refer to "The N Commandments" document.

First, folders and files organization issues will be cleared. Second, some notes on notation and programming style will be mentioned as a way to show the look and feel of the code, hoping these notation guidelines can be followed to preserve a uniform look. Third, the namespace structure will be briefly laid out. Fourth, the fundamental building blocks of the library will be described along with guidelines on best practices when using them to program the different types of software elements that compose the ReaK library.

##Folders and Files

First thing's first, file names are as follows:

  • Header files should have the ".hpp" extension.
  • Source files (TUs) should have the ".cpp" extension.
  • All file names should be made of _ (underscore) separated, lower-case words, without spaces or special characters.

Second, all ReaK code are under the top folder with the same name, then separated between core elements, control elements (here "control" is meant as all elements related to building robot control software), and example elements which are user-side code elements which use the library and thus constitute examples for users. It is important to respect this structure. In other words, all user-side code (beyond unit-test programs) should be under the "examples" folder, or another folder completely separate from library code. For writing any library code which is neither core elements or control elements, a new intermediate folder should be created, after discussion with the project's manager.

Third, the final folder separations (e.g. sub-folders of ReaK/core or ReaK/ctrl) is determined based on the type of functionality they provide. Generally, the idea is to keep this in order and leave sources and headers in the folders where one would expect to find them. It is also preferred to leave folders general enough not to clutter, but specific enough to keep the amount of source files they contain to a reasonable amount (40-50 max).

Finally, each folder and sub-folder should have its own "CMakeLists.txt" file. The structure of which will be explained in a later section.

##Notation and Code Formatting

All experienced programmers know that notation is not a critical design decision, and, in that sense, is not so important. However, it is desirable, in general, that the notation be kept uniform to increase clarity and self-documenting nature of the code. The section will petition the library programmer to strictly up-hold the chosen notation and programming style. The level of strictness of these guidelines go as follows:

  1. The notation must be abide to for all interface code, which includes class and function names, or anything else which is expected to be used by user-side code.
  2. The notation should be used for all internal code, which includes private data members, helper functions, private member functions and helper classes. In other words, anything that is expected to be of interest to other developers, code reviewers or users interested in the implementation details.
  3. The notation is suggested for implementation code, which includes the body of the functions and elements put in a "detail" namespace, i.e., any code that is only really meant to concern the original developer and possibly an expert reviewer.

So, without further a due, let's get to it. Programmers experienced with C++, that is to say, familiar with the STL, will be familiar with these notation rules. And these rules only apply to writing C++ code, as it is the only programming language for this library (any non-C++ code would be considered as external dependencies). Here is an example header file (not a real class of ReaK), called "my_vect.hpp":

//header-guards that the name of the file, making all letters upper-case and dots become underscores.
#ifndef MY_VECT_HPP
#define MY_VECT_HPP

namespace ReaK {

template <typename T, unsigned int Size> //all template arguments in CamelCase notation
class fixed_vect { //all class names with lower-case, underscore-separated words
  public:
    typedef fixed_vect<T,Size> self; //provide a nested typedef for "self".
    typedef T value_type; //provide the usual STL-like nested typedefs for all types used in the class.
    //..
  private:
    T q[Size]; //use "normal" names for data members, no need for leading m's or p's.
  public:
    //use nested typedef "self" everywhere.
    fixed_vect(const self& aV) { //use a leading "a" and CamelCase for parameter names.
      for(size_type i = 0; i < Size; ++i) 
        q[i] = aV.q[i];
    };
    //prefer constructors with default values, rather than actual default constructors.
    fixed_vect(const_reference aFill = value_type()) { //again, use only the nested typedefs.
      for(size_type i = 0; i < Size; ++i) 
        q[i] = aFill;
    };
    //..
};

};

#endif

As it can be seen in the above, the preferred indentation is of two spaces (no tabs). No need to indent for namespace enclosures. In general, it is preferred to open the curly-brace on the same line as the block's starting statement (e.g. for, if, while, etc.). The reason for using leading "a" and CamelCase for the parameter names is to avoid any confusion with data members.

##Namespace Structure

All ReaK elements are in and should be put in the ReaK namespace. Then, there are sub-namespaces for each category of code, including rtti, recorders, serialization, and ctrl for examples. It is generally preferred that namespace names remain one-word and reasonably short, but it should be kept clear about its meaning and scope.

Any implementation-related helper functions and classes which are not useful to library users should be relegated to the detail namespace enclosed in whatever namespace the main code resides. This measure prevents pollution of the namespaces with functions or classes that should be hidden from the users of the library. This can be useful for example when writing a function which is most efficiently implemented with a certain set or input/output parameters (e.g. in-place algorithms), then one can put this implementation in the detail namespace without fear that these "low-level" parameters will be misused, and then provide interfacing functions which take different parameters which can more easily be specified, overloaded and concept-checked (and Sfinae-switched), or are just more convenient to a user.

...this page is a work in progress...

Clone this wiki locally