iMSTK
Interactive Medical Simulation Toolkit
Docs/Maintainance/Coding_Guide.md
1 # Coding Guide
2 
3 ## Introduction
4 
5 This guide collates best practices from a variety of sources, while some of these express a certain _taste_ we want the items that are covered here to be consistent across iMSTK.
6 
7 Coding style is not only limited to the actual formatting but also to things like the naming of functions or variables, or the use of certain c++ features or patterns. By being consistent in these we make development for iMSTK easier for ourselves and others as names and patterns are reused across the code base.
8 
9 While the text of this guide is mostly culled from the [OpenSurgSim coding guide](https://app.assembla.com/spaces/OpenSurgSim/wiki/Coding_Standards) the following resources were used to create and refine the style
10 
11 - [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)
12 - [Google C++ Style guide](https://google.github.io/styleguide/cppguide.html)
13 - [High Integrity C++ Coding Standard](https://www.perforce.com/resources/qac/high-integrity-cpp-coding-standard)
14 
15 ### How to apply these standards
16 
17 * When working with existing code, fix its shortcomings as necessary.
18 * When extending code created externally to the project (e.g. VTK, Eigen), try to remain consistent with the naming conventions of the external code.
19 * Be flexible and reasonable. If the best thing for code readability is to violate these guidelines, please do so but that is rarely the case.
20 * When in doubt, ask someone else for a second opinion.
21 
22 ## Layout, white space and comments
23 
24 First and foremost, be reasonable and pay attention to clarity. White space and comments are to aid in code readability, not detract from it.
25 
26 ### Layout
27 
28 - Use uncrustify to fix the formatting before you submit a merge request, the `CodeFormatEnforcer` target will correct all formatting issues.
29 
30 ### Comments
31 
32 * In general, the code should be made as self-documenting as possible by appropriate name choices and an explicit logical structure.
33 * All comments should be written in US English, be spelled correctly, and make grammatical sense.
34 * Use doxygen style comments.
35 
36  Example:
37 ```
38 /// \brief Does foo and bar.
39 ///
40 /// Does not do foo the usual way if \p baz is true.
41 /// Add reference to implemented papers
42 ///
43 /// Typical usage:
44 /// \code
45 /// fooBar(false, "quux", Res);
46 /// \endcode
47 ///
48 /// \note Take care not to create a division by zero
49 ///
50 /// \param quux kind of foo to do.
51 /// \param [out] result filled with bar sequence on foo success.
52 ///
53 /// \throws if a division by zero occurs
54 ///
55 /// \returns true on success.
56 ///
57 /// \warning missing feature
58 bool
59 fooBar(bool baz, StringRef quux, std::vector<int>& result);
60 ```
61 
62 * Prefer using `//` for all embedded comments, including multi-line comments, using `/*`, `*/` prevents the use of that style comment around it.
63 
64  Example:
65 ```
66 // Comment spanning
67 // more than one line.
68 ```
69 
70 * Document responsibilities and background rather than what the code does, especially inline. The code should be readable and its details shouldn't need documentation.
71 
72  Example :
73 ```
74 ///
75 /// \class Viewer
76 ///
77 /// \brief Base class for viewer that manages render window and the renderers
78 /// Creates backend-specific renderers on a per-scene basis.
79 /// Contains user API to configure the rendering with various back-ends
80 ///
81 ```
82 
83 * Extensive comment blocks should generally only be used to explain the "rationale" behind an algorithmic choice or to explain an algorithm.
84 
85 * When using formulas from published work, add a reference to the work to the documentation
86 
87 * Doxygen supports inline [MathJax](https://www.doxygen.nl/manual/formulas.html) use it to write out formulas in critical algorithm implementations.
88 
89 * `///<` Can be used to create a comment within a line
90 
91 ```
92 int m_complexVar; ///< The sum of all things
93 ```
94 * `///@{` and `///@}` can be used to group entries, for example when functions are overridden
95 
96 ```
97 /// Sets the point of interest
98 ///@{
99 void setPoint(const Eigen::Vector3d& p);
100 void setPoint(double x, double y, double z);
101 ///@}
102 ```
103 
104 * See the [Doxygen Commands](https://www.doxygen.nl/manual/commands.html) or a [Quickreference](https://www.mitk.org/images/1/1c/BugSquashingSeminars%242013-07-17-DoxyReference.pdf)
105 
106 ## Naming conventions
107 
108 ### General naming conventions
109 
110 Consistent naming enables users to guess names and once they are familiar, correctly named functions and variables also should enhance readability of the code
111 
112 #### Terms
113 
114 For the purpose of this document we use the following convention
115 
116 * PascalCase: used for classes, enum constants
117 * camelCase: used for function and variable names,
118 * MACRO_CASE: used for macros and defines
119 
120 #### Rules
121 
122 * Names representing types should be in PascalCase.
123 
124  Example: `Line`, `SurfaceMesh`
125 
126 * Variable names should be in camelCase, class member variable should be prefixed with `m_`.
127 
128  Example: `line`, `surfaceMesh`, `m_surfaceMesh`
129 
130 * Named constants (including enumeration values) must be all MACRO_CASE.
131 
132  Example: `MAX_ITERATIONS`, `COLOR_RED`, `PI`
133 
134  * Avoid named constants in public interfaces.
135 
136 * Macro names follow the same rules as constants.
137 * All macro names should be prefixed with `IMSTK_` this prevents clashes with macros imported from other projects
138 * Names representing methods or functions should be verbs and written in camelCase.
139 
140  Example: `getName()`, `computeTotalWidth()`
141 
142 * Names representing template types should usually be a single uppercase letter, use descriptive nouns when it adds to clarity
143 
144  `template <class T>`
145 
146  `template <int N, class C, typename D>`
147 
148 * Abbreviations and acronyms should use mixed case when used as a part of a name.
149 
150  `exportHtmlSource();` (NOT: `exportHTMLSource();`)
151 
152  `openDvdPlayer();` (NOT: `openDVDPlayer();`)
153 
154 * Data members in a class should have names starting with "m_".
155 
156  `class SomeClass { private: int m_length; }`
157 
158 * Data members in a data-only struct should not start with "m_". As the purpose is to access member variables of structs prefixing those with `m_` makes the code less readable
159 
160  `struct SomeStruct { int a, int b}`
161 
162 
163 * All names should be written in US English and spelled correctly.
164 
165  `fileName` (NOT: `imeDatoteke`)
166 
167 * Variables with a large scope should have long (and descriptive) names; iteration variables with a short scope can have short names (i, j, ...).
168 * The name of the object is implicit, and should be avoided in a method name.
169 
170  `segment.getLength();` (NOT: `segment.getSegmentLength();`)
171 
172  `curve.getSegmentLength();` (this is OK, method name doesn't refer to the object)
173 
174 * Rule for namespace names is same as type names.
175 
176 * Top level namespace for iMSTK code is `imstk`.
177 
178 * Highly math based code is an exception to the naming rules, to maintain correspondence with published formulas, appropriate variable names may be used, be that single letter variables or capitalized, e.g. the implemented formula may use `F` and `f` and so should the code. The documentation in these cases should include references to the published work
179 
180 ### Specific naming conventions
181 
182 * Plural form should be used on names representing a collection of objects.
183 
184  `vector<Point> points;`
185 
186  `int values[];`
187 
188 * The prefix "num" should be used for variables representing a number of objects.
189 
190  `numPoints` (NOT: `nLines` and NOT: `nbLines`)
191 
192 * Iteration variables of any integer type should be called i, j, k etc.
193  * Variables named j, k etc. should be used for nested loops only.
194 * Variables that represent iterators for short loops may be abbreviated to "it"
195 
196  `for (vector<Foo>::iterator it = list.begin(); it != list.end(); ++it) ...`
197 
198  * Use more expressive names when using multiple iterators in the same construct
199 
200  * Generally prefer ranged based for loops over iterators
201 
202 * Accessors and modifiers must start with "get" and "set".
203 
204 * Accessors that return boolean must start with an interrogative such as "is" or "are".
205 
206 * Try to use complementary names for complementary operations.
207  * get/set, add/remove, create/destroy, start/stop, insert/delete, increment/decrement, old/new, begin/end, first/last, up/down, min/max, next/previous, old/new, open/close, show/hide, suspend/resume, etc.
208 
209 * Try to avoid abbreviations in names.
210  * Do not abbreviate common words:
211 
212  Write `command`, not `cmd`, `copy`, not `cp`, `point`, not `pt`, `compute`, not `comp`
213 
214  * Do use acronyms that have become more common than their expansions, at least in the jargon of the problem domain:
215 
216  Write `HTML`, not `HypertextMarkupLanguage`, or `CPU`, not `CentralProcessingUnit`
217 
218 * Do not encode the type of the variable in the name
219 
220  `Line* line;` (NOT: `Line* pLine;` and NOT: `Line* linePtr;`)
221 
222 * Avoid negated boolean names.
223 
224  `bool isSuccess` or `bool isError` (NOT: `isNoError`)
225 
226  `bool isMissing` or `bool wasFound` (NOT: `wasNotFound`)
227 
228  It is not immediately apparent what `!isNotFound` means.
229 
230 * Enumeration should use `class` identifiers, and enum Constants should use PascalCase
231 
232  `enum class Color { None = 0, Red, Green, Blue, MaxColors };`
233 
234  If the final enumeration value is used only to track the number of other values, it should be named `Max<type>s`; this is clearer than `<type>Max`.
235 
236 ## Declarations
237 
238 ### Free functions and member functions
239 * Use "()", not "(void)", for an empty argument list.
240 
241  `void foo();` (NOT: `void foo(void);`)
242 
243 * Methods overriding virtual methods from a base class should be declared as `override` only (`virtual` keyword omitted).
244 
245  Example:
246 ```
247 class Y : public X
248 {
249  void complain() const override;
250  ...
251 }
252 ```
253 
254 * Declare arguments as `const` when appropriate.
255 
256 * Declare member functions as `const` when appropriate.
257 
258 ## Statements
259 
260 ### Types
261 
262 * Type conversions should be done explicitly.
263 
264  `floatValue = static_cast<float>(intValue);` (NOT: `floatValue = intValue;`)
265 
266 * Do not use old style casts. NOT: `(float)intValue`.
267 
268 * Be aware that numeric values can overflow/underflow when using `static_cast`. You may need to verify the new type can hold the result.
269 
270 * Be aware that arithmetic can result in invalid or wrapped values. You may need to verify the result will be within a valid range before performing arithmetic.
271 
272 * We prefer using integer values that match the processor's word size: `size_t` for unsigned values and `ptrdiff_t` for signed values.
273 
274 * In Standard Library, `size_type` corresponds to `size_t`, and `difference_type` corresponds to `ptrdiff_t`.
275 
276 * In `Eigen::Index` and `Eigen::DenseIndex` corresponds to `ptrdiff_t`.
277 
278 * `auto` use when the type is clear, or can't be written out
279 
280 ### Variables
281 
282 * Variables should not have dual meaning.
283 
284  * Do not reuse the same variable for a different role.
285 
286 * Use of global variables should be minimized. The use of a global across modules is an indication of a design flaw.
287 
288 * Avoid declaring class data members (class variables) public.
289 
290 * Variables should be declared in the smallest scope possible.
291 
292 ### Loops
293 
294 * In a for loop, the initialization, condition and update should contain only loop control statements.
295 
296  Example:
297 ```
298 int sum = 0;
299 for (int i = 0; i < 100; i++)
300 {
301  ...
302 // NOT: for (int i = 0, sum = 0; i < 100; i++)
303 ```
304 
305 * Avoid "do-while" loops.
306 
307 * In order prefer
308  * algorithms
309  * range based for loops
310  * index acces
311 
312 ### Conditionals
313 
314 * Avoid including side effects in conditionals.
315 
316  Example:
317 ```
318 File* fileHandle = open(fileName, "w");
319 if (!fileHandle)
320 {
321  ...
322 // NOT: if (!(fileHandle = open(fileName, "w"))) ...
323 ```
324 
325 * when dealing with pointers the following is an acceptable use within if
326 
327 ```
328 if (auto ptr = getPtr())
329 {
330  ptr->useTheFunction();
331 }
332 ```
333  in this case the body of the `if` statement will only be executed if the `ptr` variable converts to `true` (i.e. is `!= nullptr`) this replaces
334 ```
335 PtrType* ptr = getPtr();
336 if (ptr != nullptr)
337 {
338  ptr->useTheFunction();
339 }
340 ```
341 
342 ## Constructors
343 
344 * Ideally all or most member variables should be initialized after the constructor has run
345 
346 * Note that `Eigen` matrices do not initialize to `0` the default constructor intentionally leaves the content at a random value
347 
348 * Prefer the default member initializer over constructor initialization, this is safer when multiple constructors need to be implemented and reduces the footprint of the member initializer list.
349 
350 Example:
351 ```
352 class A
353 {
354  int m_a = 5;
355 }
356 ```
357 NOT
358 ```
359 class A
360 {
361  A() : m_a(5) {}
362  int m_a;
363 }
364 ```
365 
366 
367 ### Miscellaneous
368 
369 * Avoid the use of magic numbers in the code. Consider declaring numbers other than 0 and 1 as named constants instead.
370 
371 * Avoid any obviously bad programming practices (goto, default-int, etc).
372 
373 * In C++ code, use `nullptr` instead of `NULL` or `0`.
374 
375 * Use portable code constructs, that is code which will compile correctly under gcc and VisualStudio.
376 
377 * Use shared_ptr, unique_ptr, and weak_ptr for dynamically allocated classes.
378 
379 ### Warnings
380 
381 * We expect to have no compiler warnings.
382 
383 ## Std Library use
384 
385 * Prefer `std::vector` over all other containers, "When choosing a container, remember vector is best;
386 Leave a comment to explain if you choose from the rest!" [C++20 standard](https://timsong-cpp.github.io/cppwp/n4861/sequence.reqmts#2).
387 
388 ### Smart Pointers
389 
390 Smart Pointers are a very useful feature of C++11, but sometimes we use them too much to manage memory, while this is correct this may cause of an overuse, especially when needing to pass objects into other functions. When smart pointers are used to indicate *ownership* things become somewhat clearer and it is easier to decide on how to pass the given object. See the [CPP Core Guidelines Resource Management](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#S-resource) especially R.20 - R.37 for more information
391 
392 - Use smart pointer types to indicate owner ship
393 
394  - `unique_ptr` expresses single ownership, the holder lifetime determines the owned objects lifetime
395  - `shared_ptr` expresses shared ownership, the lifetime of the held object is the lifetime of all holding objects
396  - `weak_ptr` expresses no ownership it is only an observer of an object with shared ownership, use it to break cycles of `shared_ptr`
397 
398 Under this aspect, use:
399 
400 - `unique_ptr` and `shared_ptr` to indicate ownership
401 - Take smart pointers as parameters only to indicate lifetime semantics
402  - A `Widget&` or `Widget*` is non owning, use when no transfer of ownership is occurring
403  - Take a `unique_ptr<Widget>` to express that a function assumes ownership of the `widget`
404  - Take a `unique_ptr<Widget>&` to express that the function reseats the `widget`
405  - Take a `shared_ptr<Widget>` to express that the function is part owner
406  - Take a `shared_ptr<Widget>&` to express that the function might reseat the shared pointer
407 
408 ## Files
409 
410 ### Source files
411 
412 * C++ header files should have the extension .h. Source files should have the extension .cpp, files defining inlined functions and templates should end in -inl.h
413 
414 * Don't leave code in the header unless it is intended for inlining. In general there is no need to inline functions. Inline only when they are small, say, 10 lines or fewer. See [Google Style/Inline Functions](https://google.github.io/styleguide/cppguide.html#Inline_Functions).
415 
416 * A class should be declared in a header file and defined in a source file where the name of the files match the name of the class.
417  * Filenames can freely use camelCase. Don't create file names (or class names) that differ only in capitalization.
418 
419 * Unless absolutely necessary, have one .h file and one .cpp *or* -inl.h file per class, and only one class in each file.
420 
421 * Don't put any implementations after the class body.
422 
423 ### Include files and `#include` statements
424 
425 * Header files must `#pragma once` as include guard.
426 
427 * Include statements must be located at the top of a file only.
428  * Except -inl.h files should be included at the end of the .h file.
429 * Include statements should be sorted and grouped so items are easy to find.
430  * A typical approach:
431  * First the .h file with the same name as the .cpp, followed by a blank line.
432  * Then the includes from iMSTK, in alphabetical order, followed by a blank line.
433  * Any headers included from iMSTK should use "".
434  * Then the includes from outside of iMSTK, grouped by library, in alphabetical order, followed by a blank line.
435  * Standard library includes e.g, `<vector>` should come last and use `<>` delimiters
436 
437 Example:
438  ```
439 #include "MyClass.h"
440 
441 #include "MainWindow.h"
442 #include "PropertiesDialog.h"
443 
444 #include <vtkActor.h>
445 #include <vtkRenderer.h>
446 
447 #include <iomanip>
448 ```
449 
450 * When possible use forward class references but don't use forward references to other projects this may cause unintended side-effects see https://google.github.io/styleguide/cppguide.html#Forward_Declarations
451 
452 ## Git Repository
453 
454 * Git commit messages should follow the convention described [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html). Basically:
455 
456 ```
457 Short one line description, 50 characters or less
458 
459 A blank line, followed by a detailed description. The longer description
460 should be wrapped at 72 characters.
461 ```
462 
463 * Prefix messages with one of the following
464  * `BUG`: Fix for runtime crash or incorrect result
465  * `COMP`: Compiler error or warning fix
466  * `DOC`: Documentation change
467  * `ENH`: New functionality
468  * `REFAC`: Rework of existing functionality
469  * `PERF`: Performance improvement
470  * `TEST`: Test change
471  * `STYLE`: No logic impact (indentation, comments)
472  * `WIP`: Work In Progress not ready for merge
473 
474 ## Message Level Semantics
475 
476 - `DEBUG`, Use at your discretion.
477 - `INFO`, Informational, notify of state changes. Example a file was successfully loaded
478 - `WARNING`, Something failed, but the impact of the failure is not know or minimal (e.g. purely visual). Example: The iteration limit was exceeded
479 - `SEVERE`, Something failed and will impact functionality, some parts of the program will not function correctly. Example: NaN was found in a calculation result, where none was ever expected
480 - `FATAL`, Used by assertion, after using this level the program will not be functional at all. Example a nullptr was passed where not null was expected
481 
482 ## Error Handling
483 
484 A function that fails to do its job due to invalid input parameters or a violation of constraints should not do so silently, just printing a warning is not sufficient
485 
486 Prefer to use `CHECK()` or `LOG(FATAL)` and abort in most cases, a CHECK as per glog definition is a contract, if the contract is violated the program will not be able to execute correctly. There is no point in proceeding, examples here are, nullptr passed where that is not acceptable if you think that the error should not force the system to shut down, use `LOG(WARNING)` but in this case the function that failed needs to provide a method that indicates to the user that a failure occurred (e.g. returning `false`). Note that the latter will more likely cause more code to be written as now return values will have to be checked.