]> granicus.if.org Git - icinga2/commitdiff
Docs: Add styleguide with development details 7199/head
authorMichael Friedrich <michael.friedrich@icinga.com>
Fri, 24 May 2019 12:17:18 +0000 (14:17 +0200)
committerMichael Friedrich <michael.friedrich@icinga.com>
Fri, 24 May 2019 12:48:56 +0000 (14:48 +0200)
@htriem

CONTRIBUTING.md
doc/12-icinga2-api.md
doc/21-development.md

index 3bae78c4a1b5b3c901d75f692656a11a042152fe..fc9a4bfb0d7841bb10fd60942b8465bb39fedd7b 100644 (file)
@@ -246,11 +246,8 @@ git push -f origin bugfix/notifications
 
 ## <a id="contributing-testing"></a> Testing
 
-Basic unit test coverage is provided by running `make test` during package builds.
-Read the [INSTALL.md](INSTALL.md) file for more information about development builds.
-
-Snapshot packages from the latest development branch are available inside the
-[package repository](https://packages.icinga.com).
+Please follow the [documentation](https://icinga.com/docs/icinga2/snapshot/doc/21-development/#test-icinga-2)
+for build and test instructions.
 
 You can help test-drive the latest Icinga 2 snapshot packages inside the
 [Icinga 2 Vagrant boxes](https://github.com/icinga/icinga-vagrant).
@@ -258,17 +255,11 @@ You can help test-drive the latest Icinga 2 snapshot packages inside the
 
 ## <a id="contributing-patches-source-code"></a> Source Code Patches
 
-Icinga 2 is written in C++ and uses the Boost libraries. We are also using the C++11 standard where applicable (please
-note the minimum required compiler versions in the [INSTALL.md](INSTALL.md) file.
-
 Icinga 2 can be built on Linux/Unix nodes and Windows clients. In order to develop patches for Icinga 2,
 you should prepare your own local build environment and know how to work with C++.
 
-More tips:
-
-* Requirements and source code installation for Linux/Unix is explained inside the [INSTALL.md](INSTALL.md) file.
-* Debug requirements and GDB instructions can be found in the [documentation](https://github.com/Icinga/icinga2/blob/master/doc/20-development.md).
-* If you are planning to develop and debug the Windows client, setup a Windows environment with [Visual Studio](https://www.visualstudio.com/vs/community/). An example can be found in [this blogpost](https://blog.netways.de/2015/08/24/developing-icinga-2-on-windows-10-using-visual-studio-2015/).
+Please follow the [development documentation](https://icinga.com/docs/icinga2/latest/doc/21-development/)
+for development environments, the style guide and more advanced insights.
 
 ## <a id="contributing-patches-documentation"></a> Documentation Patches
 
index 1b526c6493bad60da43ea5a6a3595a8ba7ce37b8..959f8e6d93c9d4984cfc6d813517f5b14c4ead05 100644 (file)
@@ -308,7 +308,7 @@ consider passing them in the request body. For GET requests, this method is expl
 [here](12-icinga2-api.md#icinga2-api-requests-method-override).
 
 You can use [jo](https://github.com/jpmens/jo) to format JSON strings on the shell. An example
-for API actions shown [here](#icinga2-api-actions-unix-timestamps).
+for API actions shown [here](12-icinga2-api.md#icinga2-api-actions-unix-timestamps).
 
 
 ### Global Parameters <a id="icinga2-api-parameters-global"></a>
index fa855cfbffba7611ab777218b7c27d6261ae913f..8db0640ea492fcc30c87c14480c4a2cf44dc21f6 100644 (file)
@@ -4,20 +4,27 @@ This chapter provides hints on Icinga 2 debugging,
 development, package builds and tests.
 
 * [Debug Icinga 2](21-development.md#development-debug)
-  * [GDB Backtrace](21-development.md#development-debug-gdb-backtrace)
-  * [Core Dump](21-development.md#development-debug-core-dump)
+    * [GDB Backtrace](21-development.md#development-debug-gdb-backtrace)
+    * [Core Dump](21-development.md#development-debug-core-dump)
 * [Test Icinga 2](21-development.md#development-tests)
-  * [Snapshot Packages (Nightly Builds)](21-development.md#development-tests-snapshot-packages)
+    * [Snapshot Packages (Nightly Builds)](21-development.md#development-tests-snapshot-packages)
 * [Develop Icinga 2](21-development.md#development-develop)
-  * [Linux Dev Environment](21-development.md#development-linux-dev-env)
-  * [macOS Dev Environment](21-development.md#development-macos-dev-env)
-  * [Windows Dev Environment](21-development.md#development-windows-dev-env)
+    * [Preparations](21-development.md#development-develop-styleguide)
+    * [Design Patterns](21-development.md#development-develop-design-patterns)
+    * [Build Tools](21-development.md#development-develop-builds-tools)
+    * [Unit Tests](21-development.md#development-develop-tests)
+    * [Style Guide](21-development.md#development-develop-styleguide)
+* [Development Environment](21-development.md#development-environment)
+    * [Linux Dev Environment](21-development.md#development-linux-dev-env)
+    * [macOS Dev Environment](21-development.md#development-macos-dev-env)
+    * [Windows Dev Environment](21-development.md#development-windows-dev-env)
 * [Package Builds](21-development.md#development-package-builds)
-  * [RPM](21-development.md#development-package-builds-rpms)
-  * [DEB](21-development.md#development-package-builds-deb)
-  * [Windows](21-development.md#development-package-builds-windows)
+    * [RPM](21-development.md#development-package-builds-rpms)
+    * [DEB](21-development.md#development-package-builds-deb)
+    * [Windows](21-development.md#development-package-builds-windows)
 * [Advanced Tips](21-development.md#development-advanced)
 
+<!-- mkdocs requires 4 spaces indent for nested lists: https://github.com/Python-Markdown/markdown/issues/3 -->
 
 ## Debug Icinga 2 <a id="development-debug"></a>
 
@@ -559,7 +566,9 @@ not a full-featured master or satellite.
 
 Before you start with actual development, there is a couple of pre-requisites.
 
-### Choose your Editor <a id="development-develop-choose-editor"></a>
+### Preparations <a id="development-develop-prepare"></a>
+
+#### Choose your Editor <a id="development-develop-choose-editor"></a>
 
 Icinga 2 can be developed with your favorite editor. Icinga developers prefer
 these tools:
@@ -572,44 +581,14 @@ these tools:
 Editors differ on the functionality. The more helpers you get for C++ development,
 the faster your development workflow will be.
 
-
-#### Whitespace Cleanup <a id="development-develop-choose-editor-whitespaces"></a>
-
-Patches must be cleaned up and follow the indent style (tabs instead of spaces).
-You should also remove any training whitespaces.
-
-`git diff` allows to highlight such.
-
-```
-vim $HOME/.gitconfig
-
-[color "diff"]
-        whitespace = red reverse
-[core]
-        whitespace=fix,-indent-with-non-tab,trailing-space,cr-at-eol
-```
-
-`vim` also can match these and visually alert you to remove them.
-
-```
-vim $HOME/.vimrc
-
-highlight ExtraWhitespace ctermbg=red guibg=red
-match ExtraWhitespace /\s\+$/
-autocmd BufWinEnter * match ExtraWhitespace /\s\+$/
-autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\@<!$/
-autocmd InsertLeave * match ExtraWhitespace /\s\+$/
-autocmd BufWinLeave * call clearmatches()
-```
-
-### Get to know the architecture <a id="development-develop-get-to-know-the-architecture"></a>
+#### Get to know the architecture <a id="development-develop-get-to-know-the-architecture"></a>
 
 Icinga 2 can run standalone or in distributed environments. It contains a whole lot
 more than a simple check execution engine.
 
 Read more about it in the [Technical Concepts](19-technical-concepts.md#technical-concepts) chapter.
 
-### Get to know the code <a id="development-develop-get-to-know-the-code"></a>
+#### Get to know the code <a id="development-develop-get-to-know-the-code"></a>
 
 First off, you really need to know C++ and portions of C++11 and the boost libraries.
 Best is to start with a book or online tutorial to get into the basics.
@@ -630,7 +609,6 @@ In addition, it is a good bet to also know SQL when diving into backend developm
 
 Last but not least, if you are developing on Windows, get to know the internals about services and the Win32 API.
 
-
 ### Design Patterns <a id="development-develop-design-patterns"></a>
 
 Icinga 2 heavily relies on object-oriented programming and encapsulates common
@@ -689,8 +667,9 @@ vim lib/perfdata/gelfwriter.cpp
 The logic is hidden in `tools/mkclass/` in case you want to learn more about it.
 The first steps during CMake & make also tell you about code generation.
 
+### Build Tools <a id="development-develop-builds-tools"></a>
 
-### Builds: CMake <a id="development-develop-builds-cmake"></a>
+#### CMake <a id="development-develop-builds-cmake"></a>
 
 In its early development stages in 2012, Icinga 2 was built with autoconf/automake
 and separate Windows project files. We've found this very fragile, and have changed
@@ -704,7 +683,7 @@ The most common benefits:
 * Separate binary build directories, the actual source tree stays clean.
 * CMake automatically generates a Visual Studio project file `icinga2.sln` on Windows.
 
-### Builds: Unity Builds <a id="development-develop-builds-unity-builds"></a>
+#### Unity Builds <a id="development-develop-builds-unity-builds"></a>
 
 Another thing you should be aware of: Unity builds on and off.
 
@@ -723,6 +702,520 @@ There's a couple of header files which are included everywhere. If you touch/edi
 the cache is invalidated and you need to recompile a lot more files then. `base/utility.hpp`
 and `remote/zone.hpp` are good candidates for this.
 
+### Unit Tests <a id="development-develop-tests"></a>
+
+New functions and classes must implement new unit tests. Whenever
+you decide to add new functions, ensure that you don't need a complex
+mock or runtime attributes in order to test them. Better isolate
+code into function interfaces which can be invoked in the Boost tests
+framework.
+
+Look into the existing tests in the [test/](https://github.com/Icinga/icinga2/tree/master/test) directory
+and adopt new test cases.
+
+Specific tests require special time windows, they are only
+enabled in debug builds for developers. This is the case e.g.
+for testing the flapping algorithm with expected state change
+detection at a specific point from now.
+
+
+### Style Guide <a id="development-develop-styleguide"></a>
+
+Overview of project files:
+
+File Type      | File Name/Extension | Description
+---------------|---------------------|-----------------------------
+Header         | .hpp                | Classes, enums, typedefs inside the icinga Namespace.
+Source         | .cpp                | Method implementation for class functions, static/global variables.
+CMake          | CMakeLists.txt      | Build configuration, source and header file references.
+CMake Source   | .cmake              | Source/Header files generated from CMake placeholders.
+ITL/conf.d     | .conf               | Template library and example files as configuration
+Class Compiler | .ti                 | Object classes in our own language, generates source code as `<filename>-ti.{c,h}pp`.
+Lexer/Parser   | .ll, .yy            | Flex/Bison code generated into source code from CMake builds.
+Docs           | .md                 | Markdown docs and READMEs.
+
+Anything else are additional tools and scripts for developers and build systems.
+
+All files must include the copyright header. We don't use the
+current year as this implies yearly updates we don't want.
+
+Depending on the file type, this must be a comment.
+
+```
+/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
+
+# Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+
+```
+
+#### Code Formatting <a id="development-develop-code-formatting"></a>
+
+We follow the clang format, with some exceptions.
+
+- Curly braces for functions and classes always start at a new line.
+
+```
+String ConfigObjectUtility::EscapeName(const String& name)
+{
+//...
+}
+
+String ConfigObjectUtility::CreateObjectConfig(const Type::Ptr& type, const String& fullName,
+       bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs)
+{
+//...
+}
+```
+
+- Too long lines break at a parameter, the new line needs a tab indent.
+
+```
+       static String CreateObjectConfig(const Type::Ptr& type, const String& fullName,
+               bool ignoreOnError, const Array::Ptr& templates, const Dictionary::Ptr& attrs);
+```
+
+- Conditions require curly braces if it is not a single if with just one line.
+
+
+```
+       if (s == "OK") {
+               //...
+       } else {
+               //...
+       }
+
+       if (!n)
+               return;
+```
+
+- There's a space between `if` and the opening brace `(`. Also after the closing brace `)` and opening curly brace `{`.
+- Negation with `!` doesn't need an extra space.
+- Else branches always start in the same line after the closing curly brace.
+
+
+#### Code Comments <a id="development-develop-code-comments"></a>
+
+Add comments wherever you think that another developer will have a hard
+time to understand the complex algorithm. Or you might have forgotten
+it in a year and struggle again. Also use comments to highlight specific
+stages in a function. Generally speaking, make things easier for the
+team and external contributors.
+
+Comments can also be used to mark additional references and TODOs.
+If there is a specific GitHub issue or discussion going on,
+use that information as a summary and link over to it on purpose.
+
+- Single line comments may use `//` or `/* ... */`
+- Multi line comments must use this format:
+
+```
+/* Ensure to check for XY
+ * This relies on the fact that ABC has been set before.
+ */
+```
+
+#### Function Docs <a id="development-develop-function-docs"></a>
+
+Function header documentation must be added. The current code basis
+needs rework, future functions must provide this.
+
+Editors like CLion or Visual Studio allow you to type `/**` followed
+by Enter and generate the skeleton from the implemented function.
+
+Add a short summary in the first line about the function's purpose.
+Edit the param section with short description on their intention.
+The `return` value should describe the value type and additional details.
+
+Example:
+
+```
+/**
+ * Reads a message from the connected peer.
+ *
+ * @param stream ASIO TLS Stream
+ * @param yc Yield Context for ASIO
+ * @param maxMessageLength maximum size of bytes read.
+ *
+ * @return A JSON string
+ */
+String JsonRpc::ReadMessage(const std::shared_ptr<AsioTlsStream>& stream, boost::asio::yield_context yc, ssize_t maxMessageLength)
+```
+
+While we can generate code docs from it, the main idea behind it is
+to provide on-point docs to fully understand all parameters and the
+function's purpose in the same spot.
+
+
+#### Header <a id="development-develop-styleguide-header"></a>
+
+Only include other headers which are mandatory for the header definitions.
+If the source file requires additional headers, add them there to avoid
+include loops.
+
+The included header order is important.
+
+- First, include the library header `i2-<libraryname>.hpp`, e.g. `i2-base.hpp`.
+- Second, include all headers from Icinga itself, e.g. `remote/apilistener.hpp`. `base` before `icinga` before `remote`, etc.
+- Third, include third-party and external library headers, e.g. openssl and boost.
+- Fourth, include STL headers.
+
+#### Source <a id="development-develop-styleguide-source"></a>
+
+The included header order is important.
+
+- First, include the header whose methods are implemented.
+- Second, include all headers from Icinga itself, e.g. `remote/apilistener.hpp`. `base` before `icinga` before `remote`, etc.
+- Third, include third-party and external library headers, e.g. openssl and boost.
+- Fourth, include STL headers.
+
+Always use an empty line after the header include parts.
+
+#### Namespace <a id="development-develop-styleguide-namespace"></a>
+
+The icinga namespace is used globally, as otherwise we would need to write `icinga::Utility::FormatDateTime()`.
+
+```
+using namespace icinga;
+```
+
+Other namespaces must be declared in the scope they are used. Typically
+this is inside the function where `boost::asio` and variants would
+complicate the code.
+
+```
+       namespace ssl = boost::asio::ssl;
+
+       auto context (std::make_shared<ssl::context>(ssl::context::sslv23));
+```
+
+#### Functions <a id="development-develop-styleguide-functions"></a>
+
+Ensure to pass values and pointers as const reference. By default, all
+values will be copied into the function scope, and we want to avoid this
+wherever possible.
+
+```
+std::vector<EventQueue::Ptr> EventQueue::GetQueuesForType(const String& type)
+```
+
+C++ only allows to return a single value. This can be abstracted with
+returning a specific class object, or with using a map/set. Array and
+Dictionary objects increase the memory footprint, use them only where needed.
+
+A common use case for Icinga value types is where a function can return
+different values - an object, an array, a boolean, etc. This happens in the
+inner parts of the config compiler expressions, or config validation.
+
+The function caller is responsible to determine the correct value type
+and handle possible errors.
+
+Specific algorithms may require to populate a list, which can be passed
+by reference to the function. The inner function can then append values.
+Do not use a global shared resource here, unless this is locked by the caller.
+
+
+#### Conditions and Cases <a id="development-develop-styleguide-conditions"></a>
+
+Prefer if-else-if-else branches. When integers are involved,
+switch-case statements increase readability. Don't forget about `break` though!
+
+Avoid using ternary operators where possible. Putting a condition
+after an assignment complicates reading the source. The compiler
+optimizes this anyways.
+
+Wrong:
+
+```
+       int res = s == "OK" ? 0 : s == "WARNING" ? 1;
+
+       return res;
+```
+
+Better:
+
+```
+       int res = 3;
+
+       if (s == "OK") {
+               res = 0;
+       } else if (s == "WARNING") {
+               res = 1;
+       }
+```
+
+Even better: Create a lookup map instead of if branches. The complexity
+is reduced to O(log(n)).
+
+```
+       std::map<String, unsigned int> stateMap = {
+               { "OK", 1 },
+               { "WARNING", 2 }
+       }
+
+       auto it = stateMap.find(s);
+
+       if (it == stateMap.end()) {
+               return 3
+       }
+
+       return it.second;
+```
+
+The code is not as short as with a ternary operator, but one can re-use
+this design pattern for other generic definitions with e.g. moving the
+lookup into a utility class.
+
+Once a unit test is written, everything works as expected in the future.
+
+#### Locks and Guards <a id="development-develop-locks-guards"></a>
+
+Lock access to resources where multiple threads can read and write.
+Icinga objects can be locked with the `ObjectLock` class.
+
+Object locks and guards must be limited to the scope where they are needed. Otherwise we could create dead locks.
+
+```
+       {
+               ObjectLock olock(frame.Locals);
+               for (const Dictionary::Pair& kv : frame.Locals) {
+                       AddSuggestion(matches, word, kv.first);
+               }
+       }
+```
+
+#### Objects and Pointers <a id="development-develop-objects-pointers"></a>
+
+Use shared pointers for objects. Icinga objects implement the `Ptr`
+typedef returning an `intrusive_ptr` for the class object (object.hpp).
+This also ensures reference counting for the object's lifetime.
+
+Use raw pointers with care!
+
+Some methods and classes require specific shared pointers, especially
+when interacting with the Boost library.
+
+#### Value Types <a id="development-develop-styleguide-value-types"></a>
+
+Icinga has its own value types. These provide methods to allow
+generic serialization into JSON for example, and other type methods
+which are made available in the DSL too.
+
+- Always use `String` instead of `std::string`. If you need a C-string, use the `CStr()` method.
+- Avoid casts and rather use the `Convert` class methods.
+
+```
+       double s = static_cast<double>(v); //Wrong
+
+       double s = Convert::ToDouble(v);   //Correct, ToDouble also provides overloads with different value types
+```
+
+- Prefer STL containers for internal non-user interfaces. Icinga value types add a small overhead which may decrease performance if e.g. the function is called 100k times.
+- `Array::FromVector` and variants implement conversions, use them.
+
+#### Utilities <a id="development-develop-styleguide-utilities"></a>
+
+Don't re-invent the wheel. The `Utility` class provides
+many helper functions which allow you e.g. to format unix timestamps,
+search in filesystem paths.
+
+Also inspect the Icinga objects, they also provide helper functions
+for formatting, splitting strings, joining arrays into strings, etc.
+
+#### Libraries <a id="development-develop-styleguide-libraries"></a>
+
+2.11 depends on [Boost 1.66](https://www.boost.org/doc/libs/1_66_0/).
+Use the existing libraries and header-only includes
+for this specific version.
+
+Note: Prefer C++11 features where possible, e.g. std::atomic and lambda functions.
+
+General:
+
+- [exception](https://www.boost.org/doc/libs/1_66_0/libs/exception/doc/boost-exception.html) (header only)
+- [algorithm](https://www.boost.org/doc/libs/1_66_0/libs/algorithm/doc/html/index.html) (header only)
+- [lexical_cast](https://www.boost.org/doc/libs/1_66_0/doc/html/boost_lexical_cast.html) (header only)
+- [regex](https://www.boost.org/doc/libs/1_66_0/libs/regex/doc/html/index.html)
+- [uuid](https://www.boost.org/doc/libs/1_66_0/libs/uuid/doc/uuid.html) (header only)
+- [range](https://www.boost.org/doc/libs/1_66_0/libs/range/doc/html/index.html) (header only)
+- [variant](https://www.boost.org/doc/libs/1_66_0/doc/html/variant.html) (header only)
+- [multi_index](https://www.boost.org/doc/libs/1_66_0/libs/multi_index/doc/index.html) (header only)
+- [function_types](https://www.boost.org/doc/libs/1_66_0/libs/function_types/doc/html/index.html) (header only)
+- [circular_buffer](https://www.boost.org/doc/libs/1_66_0/doc/html/circular_buffer.html) (header only)
+- [math](https://www.boost.org/doc/libs/1_66_0/libs/math/doc/html/index.html) (header only)
+
+Events and Runtime:
+
+- [system](https://www.boost.org/doc/libs/1_66_0/libs/system/doc/index.html)
+- [thread](https://www.boost.org/doc/libs/1_66_0/doc/html/thread.html)
+- [signals2](https://www.boost.org/doc/libs/1_66_0/doc/html/signals2.html) (header only)
+- [program_options](https://www.boost.org/doc/libs/1_66_0/doc/html/program_options.html)
+- [date_time](https://www.boost.org/doc/libs/1_66_0/doc/html/date_time.html)
+- [filesystem](https://www.boost.org/doc/libs/1_66_0/libs/filesystem/doc/index.htm)
+
+Network I/O:
+
+- [asio](https://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio.html) (header only)
+- [beast](https://www.boost.org/doc/libs/1_66_0/libs/beast/doc/html/index.html) (header only)
+- [coroutine](https://www.boost.org/doc/libs/1_66_0/libs/coroutine/doc/html/index.html)
+- [context](https://www.boost.org/doc/libs/1_66_0/libs/context/doc/html/index.html)
+
+Consider abstracting their usage into `*utility.{c,h}pp` files with
+wrapping existing Icinga types. That also allows later changes without
+rewriting large code parts.
+
+> **Note**
+>
+> A new Boost library should be explained in a PR and discussed with the team.
+>
+> This requires package dependency changes.
+
+If you consider an external library or code to be included with Icinga, the following
+requirements must be fulfilled:
+
+- License is compatible with GPLv2+. Boost license, MIT works, Apache is not.
+- C++11 is supported, C++14 or later doesn't work
+- Header only implementations are preferred, external libraries require packages on every distribution.
+- No additional frameworks, Boost is the only allowed.
+- The code is proven to be robust and the GitHub repository is alive, or has 1k+ stars. Good libraries also provide a user list, if e.g. Ceph is using it, this is a good candidate.
+
+
+#### Log <a id="development-develop-styleguide-log"></a>
+
+Icinga allows the user to configure logging backends, e.g. syslog or file.
+
+Any log message inside the code must use the `Log()` function.
+
+- The first parameter is the severity level, use them with care.
+- The second parameter defines the location/scope where the log
+happened. Typically we use the class name here, to better analyse
+the logs the user provide in GitHub issues and on the community
+channels.
+- The third parameter takes a log message string
+
+If the message string needs to be computed from existing values,
+everything must be converted to the String type beforehand.
+This conversion for every value is very expensive which is why
+we try to avoid it.
+
+Instead, use Log() with the shift operator where everything is written
+on the stream and conversions are explicitly done with templates
+in the background.
+
+The trick here is that the Log object is destroyed immediately
+after being constructed once. The destructor actually
+evaluates the values and sends it to registers loggers.
+
+Since flushing the stream every time a log entry occurs is
+very expensive, a timer takes care of flushing the stream
+every second.
+
+> **Tip**
+>
+> If logging stopped, the flush timer thread may be dead.
+> Inspect that with gdb/lldb.
+
+Avoid log messages which could irritate the user. During
+implementation, developers can change log levels to better
+see what's going one, but remember to change this back to `debug`
+or remove it entirely.
+
+
+#### Goto <a id="development-develop-styleguide-goto"></a>
+
+Avoid using `goto` statements. There are rare occasions where
+they are allowed:
+
+- The code would become overly complicated within nested loops and conditions.
+- Event processing and C interfaces.
+- Question/Answer loops within interactive CLI commands.
+
+#### Typedef and Auto Keywords <a id="development-develop-styleguide-typedef-auto"></a>
+
+Typedefs allow developers to use shorter names for specific types,
+classes and structs.
+
+```
+       typedef std::map<String, std::shared_ptr<NamespaceValue> >::iterator Iterator;
+```
+
+These typedefs should be part of the Class definition in the header,
+or may be defined in the source scope where they are needed.
+
+Avoid declaring global typedefs, unless necessary.
+
+Using the `auto` keyword allows to ignore a specific value type.
+This comes in handy with maps/sets where no specific access
+is required.
+
+The following example iterates over a map returned from `GetTypes()`.
+
+```
+       for (const auto& kv : GetTypes()) {
+               result.insert(kv.second);
+       }
+```
+
+The long example would require us to define a map iterator, and a slightly
+different algorithm.
+
+```
+       typedef std::map<String, DbType::Ptr> TypeMap;
+       typedef std::map<String, DbType::Ptr>::const_iterator TypeMapIterator;
+
+       TypeMap types = GetTypes();
+
+       for (TypeMapIterator it = types.begin(); it != types.end(); it++) {
+               result.insert(it.second);
+       }
+```
+
+We could also use a pair here, but requiring to know
+the specific types of the map keys and values.
+
+```
+       typedef std::pair<String, DbType::Ptr> kv_pair;
+
+       for (const kv_pair& kv : GetTypes()) {
+               result.insert(kv.second);
+       }
+```
+
+After all, `auto` shortens the code and one does not always need to know
+about the specific types. Function documentation for `GetTypes()` is
+required though.
+
+
+
+#### Whitespace Cleanup <a id="development-develop-choose-editor-whitespaces"></a>
+
+Patches must be cleaned up and follow the indent style (tabs instead of spaces).
+You should also remove any training whitespaces.
+
+`git diff` allows to highlight such.
+
+```
+vim $HOME/.gitconfig
+
+[color "diff"]
+        whitespace = red reverse
+[core]
+        whitespace=fix,-indent-with-non-tab,trailing-space,cr-at-eol
+```
+
+`vim` also can match these and visually alert you to remove them.
+
+```
+vim $HOME/.vimrc
+
+highlight ExtraWhitespace ctermbg=red guibg=red
+match ExtraWhitespace /\s\+$/
+autocmd BufWinEnter * match ExtraWhitespace /\s\+$/
+autocmd InsertEnter * match ExtraWhitespace /\s\+\%#\@<!$/
+autocmd InsertLeave * match ExtraWhitespace /\s\+$/
+autocmd BufWinLeave * call clearmatches()
+```
+
+
+## Development Environment <a id="development-environment"></a>
 
 ### Linux Dev Environment <a id="development-linux-dev-env"></a>