TubeTK/Developers Guide: Difference between revisions

From KitwarePublic
Jump to navigationJump to search
No edit summary
 
(31 intermediate revisions by 3 users not shown)
Line 1: Line 1:
= TubeTK Developer's Guide=
= TubeTK Developer's Guide =
Created February 1, 2010.


Created Feb. 1, 2010
= Purpose =
 
= Purpose=
The following document is a description of the accepted coding style for TubeTK. Developers who wish to contribute code to TubeTK should read and adhere to the standards described here.
The following document is a description of the accepted coding style for TubeTK. Developers who wish to contribute code to TubeTK should read and adhere to the standards described here.


= Document Overview =  
= Document Overview =  
This document is organized into the following sections.
This document is organized into the following sections:
* System Overview & Philosophy --- coding methodologies and motivation for the resulting style.
 
* Copyright --- the copyright header to be included in all files and other copyright issues.
* '''System Overview and Philosophy:''' Coding methodologies and motivation for the resulting style;
* File organization --- how to organize source code.
* '''Copyright:''' The copyright header to be included in all files and other copyright issues;
* Naming conventions --- patterns used to name classes, variables, template parameters, and instance variables.
* '''File Organization:''' How to organize source code;
* Namespaces --- the use of namespaces.
* '''Naming Conventions:''' Patterns used to name classes, variables, template parameters, and instance variables;
* Code Layout and Indentation --- accepted standards for arranging code including indentation style.
* '''Namespaces:''' The use of namespaces;
* Exception Handling --- how to add exception handling to the system.
* '''Code Layout and Indentation:''' Accepted standards for arranging code including indentation style;
* Documentation Style --- a brief section describing the documentation philosophy used within TubeTK.
* '''Exception Handling:''' How to add exception handling to the system;
* '''Documentation Style:''' A brief section describing the documentation philosophy used within TubeTK.


This style guide is an evolving document. Please confer with the TubeTK  
This style guide is an evolving document. Please confer with the TubeTK development team if you wish to add, modify, or delete the rules described in these guidelines.
development team if you wish to add, modify, or delete the rules described in  
these guidelines.


= Style Guidelines =
= Style Guidelines =
The following coding-style guidelines are to be used in development of the
The following coding-style guidelines are to be used in development of the TubeTK. To a large extent these guidelines are a result of the fundamental architectural and implementation decisions made early in the TubeTK project. For example, the decision was made to implement TubeTK with a C++ core using principles of generic programming, so the rules are oriented towards this style of implementation. Some guidelines are relatively arbitrary, such as indentation levels and style. However, an attempt was made to find coding styles consistent with accepted practices. The point is to adhere to a common style to assist developers and users of the future learn, use, maintain, and extend TubeTK.
TubeTK. To a large extent these guidelines are a result of the
fundamental architectural and implementation decisions made early in the  
TubeTK project. For example, the decision was made to implement TubeTK with  
a C++ core using principles of generic programming, so the rules are oriented  
towards this style of implementation. Some guidelines are relatively
arbitrary, such as indentation levels and style. However, an attempt was made
to find coding styles consistent with accepted practices. The point is to
adhere to a common style to assist developers and users of the future learn,
use, maintain, and extend TubeTK.
 
Please do your best to be a upstanding member of the TubeTK team. The rules
described here have been developed with the team as a whole in mind.
If you consistently violate these rules you will likely be harassed
mercilessly, first privately and then publicly. If this does not result in
correct code layout, your right to GIT write access (if you are developer and
wish to contribute code) may be removed. Similarly, if you wish to contribute
code and are not a developer, your code will not be accepted until the
style is consistent with these guidelines.


Please do your best to be a upstanding member of the TubeTK team. The rules described here have been developed with the team as a whole in mind. If you consistently violate these rules you will likely be harassed mercilessly, first privately and then publicly. If this does not result in correct code layout, your right to Git write access (if you are developer and wish to contribute code) may be removed. Similarly, if you wish to contribute code and are not a developer, your code will not be accepted until the style is consistent with these guidelines.


== System Overview & Philosophy ==
== System Overview and Philosophy ==
The following implementation strategies have been adopted by the TubeTK team.
The following implementation strategies have been adopted by the TubeTK team. These directly and indirectly affect the resulting code style. Understanding these strategies motivate the reasons for many of the style guidelines described in this document.
These directly and indirectly affect the resulting code style. Understanding  
these strategies motivate the reasons for many of the style guidelines described  
in this document.


=== Implementation Language ===  
=== Implementation Language ===  
The core implementation language is C++. C++ was chosen for its flexibility,
The core implementation language is C++. C++ was chosen for its flexibility, performance, and familiarity to team members. The toolkit uses the full spectrum of C++ features including const and volatile correctness, namespaces, partial template specialization, operator overloading, traits, and iterators.
performance, and familiarity to team members. The toolkit
uses the full spectrum of C++ features including const and volatile
correctness, namespaces, partial template specialization, operator
overloading, traits, and iterators.


=== Generic Programming and the STL ===
=== Generic Programming and the STL ===
Compile-time binding using methods of generic programming and template
Compile-time binding using methods of generic programming and template instantiation is the preferred implementation style. This approach has demonstrated its ability to create efficient, flexible code. Use of the Standard Template Library (STL) is encouraged. In contrast with many libraries, STL containers are the acceptable for passing collections of data between public and private member functions. The STL is typically used by a class, rather than as serving as a base class for derivation of classes.  
instantiation is the preferred implementation style. This approach has
demonstrated its ability to create efficient, flexible code. Use of the STL
(Standard Template Library) is encouraged. In contrast with many libraries, STL containers are the acceptable for passing collections of data between public  
and private member functions. The STL is typically {\em used} by a class,  
rather than as serving as a base class for derivation of classes.  
          
          
=== Portability ===
=== Portability ===
Most applications as well as the core of the toolkit are designed to  
Most applications as well as the core of the toolkit are designed to compile on a set of target operating system/compiler combinations. These combinations are:
compile on a set of target operating system/compiler combinations. These  
combinations are:
* Windows XP with Microsoft Visual C++ (Released within the past 5 years.)
* Linux with GCC
* Mac OSX 10.4 (Tiger) and 10.5 (Leopard) with GCC
* Other *nix systems with GCC


Some applications and modules make use of specific GPU configurations
* Linux with GCC;
to optimize certain calculations. These vary according to system, but there
* Microsoft Windows XP with Microsoft Visual C++ (released within the past five years);
shall always be an unoptimized implementation that will comply to the above
* OS X with Clang or GCC;
portablity standards.
* Other Unix systems with GCC.


=== VTK and ITK Based ===
Some applications and modules make use of specific GPU configurations to optimize certain calculations. These vary according to system, but there shall always be an unoptimized implementation that will comply to the above portablity standards.
TubeTK makes extensive use of both the Visualization Toolkit (VTK) and the
Insight Toolkit (ITK). Image processing features added to TubeTK should
prefer ITK constructs over those of VTK. When visualization-geared code is
written for TubeTK, VTK should be favored.  


=== Slicer3 ===
=== VTK and ITK ===
TubeTK is intended to be use in conjunction with Slicer3 (http://www.slicer.org).
TubeTK makes extensive use of both the Visualization Toolkit (VTK) and the Insight Toolkit (ITK). Image processing features added to TubeTK should prefer ITK constructs over those of VTK. When visualization-geared code is written for TubeTK, VTK should be favored.  


* TubeTK Modules conform to the execution model used by the Slicer3 project. For more  
=== 3D Slicer ===
information regarding constructing Slicer3 modules seehttp://www.na-mic.org/Wiki/index.php/Slicer3:Execution_Model_Documentation
TubeTK is intended to be use in conjunction with [http://www.slicer.org 3D Slicer], version 4. TubeTK Modules conform to the execution model used by the 3D Slicer project. For more information regarding bundling 3D Slicer extensions see the [http://www.slicer.org/slicerWiki/index.php/Documentation/4.2/Developers/Tutorials/BuildTestPackageDistributeExtensions 3D Slicer documentation pages].


=== CMake Build Environment ===
=== CMake Build Environment ===
The TubeTK build environment is CMake. CMake is an open-source, advanced
The TubeTK build environment is CMake. CMake is an open-source, advanced cross-platform build system that enables developers to write simple ''makefiles'' (named ''CMakeLists.txt'') that are processed to generated native build tools for a particular operating system/compiler combinations. See the [http://www.cmake.org CMake web pages] at for more information.
cross-platform build system that enables developers to write simple
``makefiles'' (named CMakeLists.txt) that are processed to generated native
build tools for a particular operating system/compiler combinations. See the
CMake web pages at http://www.cmake.org for more information.


=== Tool and Library Versions ===
=== Tool and Library Versions ===
Because of the agile nature of TubeTK developement, the TubeTK team
Because of the agile nature of TubeTK developement, the TubeTK team uses developement versions of CMake, ITK, VTK, 3D Slicer, along with a recent stable version of Qt.
uses the latest developement versions of VTK, ITK, Slicer3, and CMake along
with the latest stable version of Qt.


These are the most important factors influencing the coding style found in
These are the most important factors influencing the coding style found in TubeTK. Now we will look at the details.
TubeTK. Now we will look at the details.


=== Copyright ===
=== Copyright ===


== File Organization ==
Classes are created and organized into a single class per file set. A file set consists of ''.h'' header file, ''.cxx'' implementation file, and/or a ''.hxx'' templated implementation file. Helper classes may also be defined in  the file set, typically these are not visible to the system at large, or  placed into a special namespace.


== File organization ==
Source files must be placed in the correct directory for logical consistency with the rest of the system, and to avoid cyclic dependencies. The TubeTK source directory structure is divided into several directories below ''TubeTK''. Please consult the TubeTK team before creating any new directories with TubeTK. Directories containing source are arranged as follows:
Classes are created and organized into a single class per file set. A file set
consists of .h header file, .cxx implementation file, and/or a .txx templated
implementation file. Helper classes may also be defined in  
the file set, typically these are not visible to the system at large, or
placed into a special namespace.


Source files must be placed in the correct directory for logical consistency
* '''TubeTK/Applications:''' TubeTK/Applications consists of subdirectories for each TubeTK application. No application should depend upon another in any way;
with the rest of the system, and to avoid cyclic dependencies. The
* '''TubeTK/Base''';
TubeTK source directory structure is divided into several directories below
* '''TubeTK/SlicerModules'''.
\texttt{TubeTK}. Please consult the TubeTK team before creating any new
directories with TubeTK. Directories containing source are arranged as
follows:


=== TubeTK/Application ===
== Naming conventions ==
TubeTK/Applications consists of subdirectories for each TubeTK
In general:
application. No application should depend upon another in any way.


=== TubeTK/Base ===
* Names are constructed by using case change to indicate separate words, as in ''TimeStamp'' (versus ''Time_Stamp''). Underscores are not used.
* Variable names are chosen carefully with the intention to convey the meaning behind the code.
* Names are generally spelled out; use of abbreviations is discouraged. (Abbreviation are allowable when in common use, and should be in uppercase as in RGB.) While this does result in long names, it self-documents the code. If you learn how to use name completion in your editor (e.g., ''vim'' or ''emacs''), this inconvenience can be minimized.


== Naming conventions ==
In general,
* names are constructed by using case change to indicate separate
words, as in TimeStamp (versus Time_Stamp). Underscores are not
used.
* Variable names are chosen carefully with the intention to convey the
meaning behind the code.
* Names are generally spelled out; use of abbreviations is discouraged. (Abbreviation are allowable when in common use, and should be in uppercase as in RGB.) While this does result in long names,
it self-documents the code.  If you learn how to use name completion in your
editor (e.g., vim), this inconvenience can be minimized.
Depending on whether the name is a class, file, variable, or other name, variations on this theme result as explained in the following subsections.
Depending on whether the name is a class, file, variable, or other name, variations on this theme result as explained in the following subsections.


=== Naming Classes ===
=== Naming Classes ===
Classes are named beginning with a capital letter. Classes are placed in the
Classes are named beginning with a capital letter. Classes are placed in the appropriate namespace, typically tube:: or itk::tube (see namespaces below). Classes are named according to the following general rule:
appropriate namespace, typically mav:: (see namespaces below). Classes are
named according to the following general rule:
 
  class name = <algorithm><input><concept>


In this formula, the name of the algorithm or process (possibly with an
''class name = <algorithm><input><concept>''
associated adjective or adverb) comes first, followed by an input type,
and completed by a {\em concept} name. A concept is an informal classification
describing what a class does. There are many concepts in TubeTK, here are a
few of them:


* Filter
In this formula, the name of the algorithm or process (possibly with an associated adjective or adverb) comes first, followed by an input type, and completed by a concept name. A concept is an informal classification describing what a class does. There are many concepts in TubeTK, here are a few of them:
** A class that participates in the data processing pipeline. Filters typically take one or more inputs and produce one or more outputs.
* Iterator
** Traverse data in various ways (e.g., forward, backward, within a region, etc.)
* Reader
** A class that reads a single data object (e.g., image or mesh).
* Region
** A subset of a data object, such as an image region.
* Source
** A filter that initiates the data processing pipeline such as a reader or a procedural data generator.
* Transform
** Various types of transformations including affine, procedural, and so on.
* Writer
** A filter that terminates the data processing pipeline by writing data to disk or to a communications port.


The naming of classes is an art form; please  review existing names to
* '''Filter:''' A class that participates in the data processing pipeline. Filters typically take one or more inputs and produce one or more outputs;
catch the spirit of the naming convention. Example names include:
* '''Iterator:''' Traverse data in various ways (e.g., forward, backward, within a region, etc.);
* '''Reader:''' A class that reads a single data object (e.g., image or mesh).
* '''Region:''' A subset of a data object, such as an image region;
* '''Source:''' A filter that initiates the data processing pipeline such as a reader or a procedural data generator;
* '''Transform:''' Various types of transformations including affine and procedural;
* '''Writer:''' A filter that terminates the data processing pipeline by writing data to disk or to a communications port.


* ShrinkImageFilter
The naming of classes is an art form; please review existing names to catch the spirit of the naming convention. Example names include:
* TriangleCell
* ScalarImageRegionIterator
* NeighborhoodIterator
* MapContainer
* DefaultImageTraits
* BackwardDifferenceOperator


* ShrinkImageFilter;
* TriangleCell;
* ScalarImageRegionIterator;
* NeighborhoodIterator;
* MapContainer;
* DefaultImageTraits;
* BackwardDifferenceOperator.


=== Naming Modules ===
=== Naming Modules ===
Modules created within TubeTK should be named in the same manner
Modules created within TubeTK should be named in the same manner ascribed to other TubeTK classes. The directories that the modules are constructed in should end in ''Module'' as well as the shared library build of the module. However, the standalone version of the module should omit ''Module'' from its name.
ascribed to other TubeTK classes. The directories that the modules are  
constructed in should end in \texttt{Module} as well as the shared library
build of the module. However, the standalone version of the module should omit
<em>Module</em> from its name.
 
 


=== Naming Files ===
=== Naming Files ===
Files should have the same name as the class, with the namespace of the library prepended (e.g., ``tubetk''). Header files are named .h, while implementation files are named either .cxx
Files should have the same name as the class, with the namespace of the library prepended (e.g., ''tube''). Header files are named ''.h'', while implementation files are named either ''.cxx'' or ''.hxx'', depending on whether they are implementations of templated classes. It is important to note that VTK, ITK, and Qt classes fall under their respective namespaces and do not use the ''tube'' namespace.
or .txx, depending on whether they are implementations of templated
classes. It is important to note that VTK, ITK, and Qt classes fall under their
respective namespaces and do not use the mav namespace.


=== Naming Methods and Functions ===
=== Naming Methods and Functions ===
Global functions and class methods, either static or class members, are named
Global functions and class methods, either static or class members, are named beginning with a capital letter. The biggest challenge when naming methods and functions is to be consistent with existing names. For example, given the choice between ''ComputeBoundingBox( void )'' and ''CalculateBoundingBox( void )'' (''CalcBoundingBox( void )'' is not allowed because it is not spelled out), the choice is ''ComputeBoundingBox( void )'' because ''Compute'' is used elsewhere in the system for a similar circumstance. The concepts described previously should be used whenever possible.
beginning with a capital letter. The biggest challenge when naming methods
 
and functions is to be consistent with existing names. For example, given the
When referring to class methods and variables in code, an explicit ''this->'' pointer should be used, as in ''this->ComputeBoundingBox()''. The use of the explicit ''this->'' pointer helps clarify exactly which method, and where it originates, is being invoked. Similarly the ''::'' global namespace should be used when referring to a global function.
choice between ComputeBoundingBox() and CalculateBoundingBox (CalcBoundingBox()
is not allowed because it is not spelled out), the choice is  
ComputeBoundingBox() because ``Compute'' is used elsewhere in the system for
a similar circumstance. (The concepts described previously should be used
whenever possible.)


When referring to class methods and variables in code, an explicit ``this->'' pointer
should be used, as in this->ComputeBoundingBox(). The use of the explicit
this-\(>\) pointer helps clarify exactly which method, and where it originates,
is being invoked. Similarly the ``::'' global namespace should be used when
referring to a global function.
=== Naming Class Data Members ===
=== Naming Class Data Members ===
Class data members are prepended with '''m_''' as in m_Size. This clearly
Class data members are prepended with ''m_'' as in ''m_Size''. This clearly indicates the origin of data members, and differentiates them from all other variables.
indicates the origin of data members, and differentiates them from all
other variables.


=== Naming Local Variables ===
=== Naming Local Variables ===
Local variables begin in lowercase. There is more flexibility in the naming
Local variables begin in lowercase. There is more flexibility in the naming of local variables; please remember that others will study, maintain, fix, and extend your code. Any bread crumbs that you can drop in the way of explanatory variable names and comments will go a long way towards helping other developers.
of local variables; please remember that others will study, maintain, fix,
and extend your code. Any bread crumbs that you can drop in the way of
explanatory variable names and comments will go a long way towards helping
other developers.


=== Naming Template Parameters ===
=== Naming Template Parameters ===
Template parameters follow the usual rules with naming except that they
Template parameters follow the usual rules with naming except that they should start with either the capital letter ''T'' or ''V''. Type parameters begin with the letter ''T'' while value template parameters begin with the letter ''V''.
should start with either the capital letter <em>T</em> or <em>V</em>. Type
parameters begin with the letter <em>T</em> while value template parameters
begin with the letter <em>V</em>.


=== Naming Typedefs ===
=== Naming Typedefs ===
Typedefs are absolutely essential in generic programming. They significantly
Typedefs are absolutely essential in generic programming. They significantly improve the readability of code, and facilitate the declaration of complex syntactic combinations. Unfortunately, creation of typedefs is tantamount to creating another programming language. Hence typedefs must be used in a consistent fashion.
improve the readability of code, and facilitate the declaration of complex
syntactic combinations. Unfortunately, creation of typedefs is tantamount to
creating another programming language. Hence typedefs must be used in a
consistent fashion.


The general rule for typedef names is that they end in the word  
The general rule for typedef names is that they end in the word ''Type''. For example:
<em>Type</em>. For example


   typedef TPixel PixelType;
   typedef TPixel PixelType;


However, there are many exceptions to this rule that recognize that TubeTK
However, there are many exceptions to this rule that recognize that TubeTK has several important concepts that are expressed partially in the names used to implement the concept. An iterator is a concept, as is a container or pointer. These concepts are used in preference to ''Type'' at the end of a typedef as appropriate. For example:
has several important {\em concepts} that are expressed partially in the
names used to implement the concept. An iterator is a concept, as is a  
container or pointer. These concepts are used in preference to  
<em>Type</em> at the end of a typedef as appropriate. For example


   typedef typename ImageTraits::PixelContainer PixelContainer;
   typedef typename ImageTraits::PixelContainer PixelContainer;


Here <em>Container</em> is a concept used in place of <em>Type</em>.
Here ''Container'' is a concept used in place of ''Type''.


=== Using Underscores ===
=== Using Underscores ===
Don't use them. The only exception is when defining preprocessor variables
Do not use them. The only exception is when defining preprocessor variables and macros (which are discouraged). In this case, underscores are allowed to separate words.
and macros (which are discouraged). In this case, underscores are allowed
to separate words.


=== Preprocessor Directives ===
=== Preprocessor Directives ===
Some of the worst code contains many preprocessor directives and macros. Do
Some of the worst code contains many preprocessor directives and macros. Do not use them except in a very limited sense (to support minor differences in compilers or operating systems). If a method makes extensive use of preprocessor directives, it is a candidate for separation into its own class.
not use them except in a very limited sense (to support minor differences in
compilers or operating systems). If a method makes extensive use of preprocessor
directives, it is a candidate for separation into its own class.


=== Unused Parameters and Shadowed Parameters ===
=== Unused Parameters and Shadowed Parameters ===
Use the macros vtkNotUsed() and itkNotUsed() when implementing class member functions that have unused parameters.   Warnings are errors, and unused parameters will generate warnings
Use the macros ''vtkNotUsed()'' and ''itkNotUsed()'' when implementing class member functions that have unused parameters. Warnings are treated as errors, and unused parameters will generate warnings


  void SetSigma( double sigma, double itkNotUsed(extent) )
  void SetSigma( double sigma, double itkNotUsed( extent ) )
  {
{
   ...some code that doesn't use the parameter extent...
   ...some code that does not use the parameter extent...
  }
}


Shadowed parameters are particularly troublesome in that they often indicate code errors and ambiguities. Again, warnings are errors, and shadowed variables will generate warnings!
Shadowed parameters are particularly troublesome in that they often indicate code errors and ambiguities. Again, warnings are treated as errors, and shadowed variables will generate warnings.


A common mistake is to give a variable larger scope than what it needs.   To avoid this, define loop variables in the loop declaration:
A common mistake is to give a variable larger scope than what it needs. To avoid this, define loop variables in the loop declaration:


  for( int i=0; i<100; i++ )
  for( unsigned int i = 0; i < 100; ++i )
   {
   {
   ...loop stuff...
   ...loop stuff...
   }
   }


Following our naming conventions also helps avoid shadowed vars. In particular, make sure all member variables begin with '''m_''', functions begin with upper-case variables, and variables names are descriptive!
Following our naming conventions also helps avoid shadowed variables. In particular, make sure all member variables begin with '''m_''', functions begin with uppercase variables, and variables names are descriptive.


=== Hidden virtual functions ===
=== Hidden Virtual Functions ===
If a base class declares a function, then an instance of that function overloaded in subclasses must include a definition that has the same parameter arguments (signature).   For example, if the base class function takes two doubles as args, and the derived class has an instance that takes only one double as an arg, then a warning (i.e., an error) is generated.   You must also define an instance in the derived class that takes two args.
If a base class declares a function, then an instance of that function overloaded in subclasses must include a definition that has the same parameter arguments (signature). For example, if the base class function takes two doubles as arguments, and the derived class has an instance that takes only one double as an argument, then a warning (i.e., an error) is generated. You must also define an instance in the derived class that takes two arguments.


=== Newline at EOF ===
=== New Line at End of File ===
Some compilers will complain (generate a warning/error) if a file does not end with a newline. To be safe, make sure each file ends with a blank line.
Some compilers will complain (generate a warning/error) if a file does not end with a new line. To be safe, make sure each file ends with a blank line.


== Namespaces ==
== Namespaces ==
All classes that do not inherit from VTK, ITK, or Qt classes should be placed in
All classes that do not inherit from VTK, ITK, or Qt classes should be placed in the tube namespace.  
the tubetk:: namespace.  


== Const Correctness ==
== Const Correctness ==
Const correctness is important. Please use it as appropriate to your class
Const correctness is important. Please use it as appropriate to your class or method.
or method.


== Exception Handling ==
== Exception Handling ==
Indicate that methods throw exceptions in the method declaration as in:
Indicate that methods throw exceptions in the method declaration as in:


   const float* foo() const throws std::exception
   const float * foo( void ) const throws std::exception


== Code Layout and Indentation ==
== Code Layout and Indentation ==
The following are the accepted TubeTK code layout rules and indentation style.
The following are the accepted TubeTK code layout rules and indentation style. After reading this section, you may wish to visit many of the source files found in ITK. This will help crystallize the rules described here.
After reading this section, you may wish to visit many of the source files
found in ITK. This will help crystallize the rules described here.


=== General Layout ===
=== General Layout ===
Each line of code should take no more than 80 characters. Break the code
Each line of code should take no more than 80 characters. Break the code across multiple lines as necessary. Use lots of whitespace to separate logical blocks of code, intermixed with comments. To a large extent the structure of code directly expresses its implementation.
across multiple lines as necessary. Use lots of whitespace to separate
logical blocks of code, intermixed with comments. To a large extent the
structure of code directly expresses its implementation.


The appropriate indentation level is two spaces for each level of
==== Indentation and Tabs ====
indentation. DO NOT USE TABS. Set up your editor to insert spaces. Using tabs
The appropriate indentation level is two spaces for each level of indentation. Do not use tabs. Set up your editor to insert spaces. Using tabs may look good in your editor but will wreak havoc in someone else's.
may look good in your editor but will wreak havoc in someone else's.


The declaration of variables within classes, methods, and functions should
[[File:VisualStudioTabsSpaces.png]]
be one declaration per line.
 
==== Declarations ====
 
The declaration of variables within classes, methods, and functions should be one declaration per line.


   int    i;
   int    i;
Line 322: Line 196:
   char * stringname;
   char * stringname;


=== Spaces (USE THEM!) ===
=== Spaces ===
TubeTK, like ITK, makes liberal use of spaces to improve the readability of code. When in doubt, use a space. Common examples:


TubeTK, like ITK, makes liberal use of spaces to improve the readability of code.  When in doubt, use a space.  Common examples:
* Separate expressions from their enclosing paren:
* Separate expressions from their enclosing paren:
if( a < b )
  if( a < b )
  {
    {
  a = ( 1 + 1 ) / 2;
    a = ( 1 + 1 ) / 2;
  }
    }
* Separate arguments from their enclosing paran and from other args (there should be a space after every comma:
* Separate arguments from their enclosing paren and from other args (there should be a space after every comma):
foo( int a )
  foo( int a )
  {
  {
  foofoo( a );
    foofoo( a );
  foofoofoo( a, b );
    foofoofoo( a, b );
  }
  }
* Favor right-flush for lines that are continuations of previous lines:
* Favor right-flush for lines that are continuations of previous lines:
   this->IsMyReallyLong()->ITK()
   this->IsMyReallyLong()->ITK()
Line 341: Line 215:
* Use ( void ) when declaring a function that takes no arguments:
* Use ( void ) when declaring a function that takes no arguments:
   int DoesNothing( void )
   int DoesNothing( void )
    {
  {
    }
  }
* Use spaces before and after raw pointer declarations:
* Use spaces before and after raw pointer declarations:
   int * a;
   int * a;
** You do not need to use spaces when accessing raw pointers:
* You do not need to use spaces when accessing raw pointers:
   a->b;
   a->b;
   *a = b;
   *a = b;


=== KISS ===
=== Keep It Simple ===
Keep it simple, stupid!
Break complex methods into multiple lines. Program in a way that makes it easy for your code to be debugged by others. Examples:


Break complex methods into multiple lines - program in a way that makes it easy for your code to be debugged by others. 
* ''?:'' statements should not be used instead of ''if...then'' statements;
Examples:
* Limit the variety of operators that appear in any one line of code.
* ?: statements should not be used instead of if...then statements
* Limit the variety of operators that appear in any one line of code


=== Includes ===
* Only include the necessary files, no more;
* Group includes per library;
* Alphabetically sort files within groups;
* Order groups from local to global;
* Implementation files should include the header files first.


=== Class Layout ===
=== Class Layout ===
Classes are defined using the following guidelines.
Classes are defined using the following guidelines:


* Begin with <em>#include</em> guards.
* Begin with ''#include'' guards;
* Follow with the necessary includes. Include only what is necessary to avoid dependency problems.
* Follow with the necessary includes. Include only what is necessary to avoid dependency problems;
* Place the class in the correct namespace.
* Place the class in the correct namespace;
* Public methods come first.
* Public methods come first;
* Protected methods follow.
* Protected methods follow;
* Private members come last.
* Private members come last;
* Public data members are forbidden.
* Public data members are forbidden.


The class layout looks something like this:
The class layout looks something like this:


   #ifndef __tubetkImage_h
  /*=========================================================================
   #define __tubetkImage_h
 
  Library:  TubeTK
   #include "itkImageBase.h"
 
   #include "itkPixelTraits.h"
  Copyright 2010 Kitware Inc. 28 Corporate Drive,
   #include "itkDefaultImageTraits.h"
  Clifton Park, NY, 12065, USA.
   #include "itkDefaultDataAccessor.h"
 
  All rights reserved.
   namespace tubetk
 
  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
 
      http://www.apache.org/licenses/LICENSE-2.0
 
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 
  =========================================================================*/
 
   #ifndef __itktubeExampleImage_h
   #define __itktubeExampleImage_h
 
   #include <itkDefaultDataAccessor.h>
   #include <itkDefaultImageTraits.h>
   #include <itkImageBase.h>
   #include <itkPixelTraits.h>
 
  namespace itk
  {
 
   namespace tube
  {
 
  template< class TPixel, unsigned int VImageDimension = 2,
            class TImageTraits = DefaultImageTraits< TPixel, VImageDimension > >
  class ITK_EXPORT ExampleImage : public ImageBase< VImageDimension >
   {
   {
   template < class TPixel, unsigned int VImageDimension=2,
   public:
            class TImageTraits=DefaultImageTraits< TPixel, VImageDimension > >
    typedef ExampleImage                Self;
  class TubeTK_EXPORT Image : public itk::ImageBase< VImageDimension >
    typedef ImageBase< VImageDimension > Superclass;
    {
    typedef SmartPointer< Self >         Pointer;
     public:
    typedef SmartPointer< const Self >   ConstPointer;
      ....stuff...
 
     protected:
     itkNewMacro( Self );
      ....stuff...
     itkTypeMacro( ExampleImage, ImageBase );
     private:
 
      ....stuff...
     ....
    };
   
   
   }//end of namespace
   protected:   
    ExampleImage( void );
 
    virtual ~ExampleImage( void )
      {
      }
 
    ....
   
   
   #endif //end include guard
   private:
 
    ExampleImage( const Self & other );
=== Method Definition ===
 
Methods are defined across multiple lines. This is to accommodate the
    void operator=( const Self & other );
extremely long definitions possible when using templates. The starting and
 
ending brace should be indented. For example:
    ....
 
    PixelContainerPointer m_Buffer
 
    ....
 
  }; // End class ExampleImage
 
  } // End namespace tube
 
  } // End namespace itk
 
  #endif // End !defined(__itktubeExampleImage_h)


=== Method Definitions ===
Methods are defined across multiple lines. This is to accommodate the extremely long definitions possible when using templates. The starting and ending brace should be indented. For example:


   template< class TPixel, unsigned int VImageDimension,  
   template< class TPixel, unsigned int VImageDimension,  
             class TImageTraits >
             class TImageTraits >
   const double *  
   const double *  
   Image< TPixel, VImageDimension, TImageTraits >
   ExampleImage< TPixel, VImageDimension, TImageTraits >
   ::GetSpacing( ) const
   ::GetSpacing( void ) const
  {
    ...
  }
 
The first line is the template declaration. The second line is the method return type. The third line is the class qualifier. And the fourth line in the example above is the name of the method.
 
=== Use of Braces { } ===
Braces must be used to delimit the scope of an ''if'', ''for'', ''while'', ''switch'', or other control structure. Braces are placed on a line by themselves:
 
  for( unsigned int i = 0; i < 3; ++i )
     {
     {
     ...
     ...
     }
     }


The first line is the template declaration. The second line is the method
or when using an ''if'':
return type. The third line is the class qualifier. And the fourth line in the
example above is the name of the method.


=== Use of Braces { } ===
  if( condition )
Braces must be used to delimit the scope of an <em>if</em>, <em>for</em>,
    {
<em>while</em>, <em>switch</em>, or other control structure. Braces are
    ...
placed on a line by themselves:
    }
 
  else if( other condition )
  int i;
    {
  for( i=0; i<3; i++ )
    ...
    {
    }
    ...
  else
    }
    {
    ....
    }


=== Use of vnl and accessing vnl matrix and vector elements ===


or when using an <em>if</em>:
We favor the direct use of vnl for mathematics in TubeTK.  ITK methods can also be used when the elements are ITK constructs, but the direct use of vnl is encouraged when the context is neutral.


When accessing vnl_matrix elements, we recommend the use of parenthesis when accessing a matrix element, and the use of get_column and set_column member functions when accessing rows and columns.  In general, the least ambiguous form should be chosen in any context.


  if( condition )
When accessing vnl_vector elements, parenthesis or brackets may be used - typically dictated by code flow / context.
    {
    ...
    }
  else if( other condition )
    {
    ...
    }
  else
    {
    ....
    }


== Doxygen Documentation System ==
== Doxygen Documentation System ==
Doxygen is an open-source, powerful system for automatically generating  
[http://www.doxygen.org Doxygen] is an open-source system for automatically generating documentation from source code. To use Doxygen effectively, the developer must insert comments, delimited in a special way, that Doxygen extracts to produce the documentation. While there are a large number of options to Doxygen, developers at a minimum should insert the following Doxygen commands.
documentation from source code. To use Doxygen effectively, the developer
must insert comments, delimited in a special way, that Doxygen extracts
to produce the documentation. While there are a large number of options  
to Doxygen, developers at a minimum should insert the following Doxygen
commands. (See more at http://www.stack.nl/~dimitri/doxygen/index.html.)


=== Documenting a Class ===
=== Documenting a Class ===
Classes should be documented using the \texttt{\\class} and \texttt{\\brief}
Classes should be documented using the ''\class'' and ''\brief'' Doxygen commands, followed by the detailed class description:
Doxygen commands, followed by the detailed class description:


   /** \class Object
   /**
  * \class Object
   * \brief Base class for most itk classes.
   * \brief Base class for most itk classes.
   *
   *
Line 463: Line 388:
   * implementing debug flags/methods and modification time tracking.
   * implementing debug flags/methods and modification time tracking.
   */
   */


=== Documenting a Method ===
=== Documenting a Method ===
Methods should be documented using the following comment block style as shown
Methods should be documented using the following comment block style as shown in the following example:
in the following example.


   /**
   /**
Line 473: Line 396:
   */
   */
   TPixel & operator[]( const IndexType & index )
   TPixel & operator[]( const IndexType & index )
    {  
  {  
    return this->GetPixel( index );  
    return this->GetPixel( index );  
    }
  }
 
The key here is that the comment starts with <em>/**</em>, each subsequent
line has an aligned <em>*</em>, and the comment block terminates with a
<em>*/</em>.
 
= Documentation =
 
The TubeTK has adopted the following guidelines for producing
supplemental documentation.


* Most documentation should begin as a wiki page
The key here is that the comment starts with ''/**'', each subsequent line has an aligned ''*'', and the comment block terminates with a  ''*/''.
* Documentation for releases should be available as PDF
* Administrative documentation for releases should be available as Word
* Presentations are acceptable in Microsoft PowerPoint format.


= Testing =
= Testing =
Each developer should do his or her part to aid in testing process. It is
Each developer should do his or her part to aid in testing process. It is generally accepted that each developer should write proper unit tests using CTest and those tests will be run on nightly and continuous dashboards.
generally accepted that each developer should write proper unit tests using
CTest and those tests will be run on nightly and continuous dashboards.


== Dashboards ==
== Dashboards ==
* [http://open.cdash.org/index.php?project=TubeTK Dashboards] shall be maintained for all platforms
* [http://open.cdash.org/index.php?project=TubeTK CDash Dashboards] are maintained for all platforms;
* Warnings will not be tolerated
* Warnings are not tolerated;
* Failing tests are preferred over disabling tests or using case/system-specific hacks for solutions
* Failing tests are preferred over disabling tests or using case/system-specific hacks for solutions. The best answer is to fix the code.
** Best answer is to fix the code
   
   
== Releases ==
== Releases ==
Before each product release, a battery of testing (specified on the project
Before each product release, a battery of testing (specified on the project wiki) will be carried out to check for regressions not caught by traditional unit testing. Release version naming convention:
wiki) will be carried out to check for regressions not caught by traditional
* ''MajorReleaseNumber.MinorReleaseNumber.PatchReleaseNumber'';
unit testing.
* These variables are controlled in the top-level ''CMakeLists.txt'' file. They apply to all applications within TubeTK.
* Release version naming convention
** <em>MajorReleaseNumber.MinorReleaseNumber.PatchReleaseNumber</em>
** These variables are controlled in the top-level CMakeLists.txt file.   They apply to all applications within TubeTK


= Code Coverage =
= Code Coverage =
Code coverage is everyone's responsibility...
Code coverage is responsibility of all developers.


= Memory Leaks =
= Memory Leaks =
Memory leaks must be plugged. A list of leaks and memory defects can be found on the [http://open.cdash.org/index.php?project=TubeTK Dashboard] under the ''Dynamic Analysis'' section. Clicking on the ''Defect Count'' will show further information.
Memory leaks must be plugged. A list of leaks and memory defects can be found on the [http://open.cdash.org/index.php?project=TubeTK Dashboard] under the ''Dynamic Analysis'' section. Clicking on the ''Defect Count'' will show further information.
 
A script is available for Linux and OS X to help debug the memory leaks. It can generate the same output present on the dashboard on demand for a subset of tests. The command
 
''./TubeTK/Utilities/Valgrind/runValgrind.sh -h''
 
shows full usage instructions. Essentially install ''valgrind'' and ''xsltproc'', then execute the ''runValgrind.sh'' script from ''TubeTK-Build'' with arguments such as
 
''-R leakyTubeTestName''.
 
= Git repo management =
 
Create a fork in your github account, and perform pull requests.
 
* [https://help.github.com/articles/fork-a-repo Fork the Github repo for TubeTK]


A script is available for Mac/Linux to help debug the memory leaks.  It can generate the same output present on the dashboard on demand for a subset of tests.
= Optimizing code in Linux =


  ./TubeTK/Utilities/Valgrind/runValgrind.sh -h
* [[TubeTK/Code Optimization in Linux|Code Optimization in Linux]]


shows full usage instructions.  Essentially install valgrind and xsltproc, then execute the ''runValgrind.sh'' script from ''TubeTK-Build'' with arguments such as "-R leakyTubeTestName".
[[Category:TubeTK|Developers Guide]]

Latest revision as of 23:01, 10 May 2016

TubeTK Developer's Guide

Created February 1, 2010.

Purpose

The following document is a description of the accepted coding style for TubeTK. Developers who wish to contribute code to TubeTK should read and adhere to the standards described here.

Document Overview

This document is organized into the following sections:

  • System Overview and Philosophy: Coding methodologies and motivation for the resulting style;
  • Copyright: The copyright header to be included in all files and other copyright issues;
  • File Organization: How to organize source code;
  • Naming Conventions: Patterns used to name classes, variables, template parameters, and instance variables;
  • Namespaces: The use of namespaces;
  • Code Layout and Indentation: Accepted standards for arranging code including indentation style;
  • Exception Handling: How to add exception handling to the system;
  • Documentation Style: A brief section describing the documentation philosophy used within TubeTK.

This style guide is an evolving document. Please confer with the TubeTK development team if you wish to add, modify, or delete the rules described in these guidelines.

Style Guidelines

The following coding-style guidelines are to be used in development of the TubeTK. To a large extent these guidelines are a result of the fundamental architectural and implementation decisions made early in the TubeTK project. For example, the decision was made to implement TubeTK with a C++ core using principles of generic programming, so the rules are oriented towards this style of implementation. Some guidelines are relatively arbitrary, such as indentation levels and style. However, an attempt was made to find coding styles consistent with accepted practices. The point is to adhere to a common style to assist developers and users of the future learn, use, maintain, and extend TubeTK.

Please do your best to be a upstanding member of the TubeTK team. The rules described here have been developed with the team as a whole in mind. If you consistently violate these rules you will likely be harassed mercilessly, first privately and then publicly. If this does not result in correct code layout, your right to Git write access (if you are developer and wish to contribute code) may be removed. Similarly, if you wish to contribute code and are not a developer, your code will not be accepted until the style is consistent with these guidelines.

System Overview and Philosophy

The following implementation strategies have been adopted by the TubeTK team. These directly and indirectly affect the resulting code style. Understanding these strategies motivate the reasons for many of the style guidelines described in this document.

Implementation Language

The core implementation language is C++. C++ was chosen for its flexibility, performance, and familiarity to team members. The toolkit uses the full spectrum of C++ features including const and volatile correctness, namespaces, partial template specialization, operator overloading, traits, and iterators.

Generic Programming and the STL

Compile-time binding using methods of generic programming and template instantiation is the preferred implementation style. This approach has demonstrated its ability to create efficient, flexible code. Use of the Standard Template Library (STL) is encouraged. In contrast with many libraries, STL containers are the acceptable for passing collections of data between public and private member functions. The STL is typically used by a class, rather than as serving as a base class for derivation of classes.

Portability

Most applications as well as the core of the toolkit are designed to compile on a set of target operating system/compiler combinations. These combinations are:

  • Linux with GCC;
  • Microsoft Windows XP with Microsoft Visual C++ (released within the past five years);
  • OS X with Clang or GCC;
  • Other Unix systems with GCC.

Some applications and modules make use of specific GPU configurations to optimize certain calculations. These vary according to system, but there shall always be an unoptimized implementation that will comply to the above portablity standards.

VTK and ITK

TubeTK makes extensive use of both the Visualization Toolkit (VTK) and the Insight Toolkit (ITK). Image processing features added to TubeTK should prefer ITK constructs over those of VTK. When visualization-geared code is written for TubeTK, VTK should be favored.

3D Slicer

TubeTK is intended to be use in conjunction with 3D Slicer, version 4. TubeTK Modules conform to the execution model used by the 3D Slicer project. For more information regarding bundling 3D Slicer extensions see the 3D Slicer documentation pages.

CMake Build Environment

The TubeTK build environment is CMake. CMake is an open-source, advanced cross-platform build system that enables developers to write simple makefiles (named CMakeLists.txt) that are processed to generated native build tools for a particular operating system/compiler combinations. See the CMake web pages at for more information.

Tool and Library Versions

Because of the agile nature of TubeTK developement, the TubeTK team uses developement versions of CMake, ITK, VTK, 3D Slicer, along with a recent stable version of Qt.

These are the most important factors influencing the coding style found in TubeTK. Now we will look at the details.

Copyright

File Organization

Classes are created and organized into a single class per file set. A file set consists of .h header file, .cxx implementation file, and/or a .hxx templated implementation file. Helper classes may also be defined in the file set, typically these are not visible to the system at large, or placed into a special namespace.

Source files must be placed in the correct directory for logical consistency with the rest of the system, and to avoid cyclic dependencies. The TubeTK source directory structure is divided into several directories below TubeTK. Please consult the TubeTK team before creating any new directories with TubeTK. Directories containing source are arranged as follows:

  • TubeTK/Applications: TubeTK/Applications consists of subdirectories for each TubeTK application. No application should depend upon another in any way;
  • TubeTK/Base;
  • TubeTK/SlicerModules.

Naming conventions

In general:

  • Names are constructed by using case change to indicate separate words, as in TimeStamp (versus Time_Stamp). Underscores are not used.
  • Variable names are chosen carefully with the intention to convey the meaning behind the code.
  • Names are generally spelled out; use of abbreviations is discouraged. (Abbreviation are allowable when in common use, and should be in uppercase as in RGB.) While this does result in long names, it self-documents the code. If you learn how to use name completion in your editor (e.g., vim or emacs), this inconvenience can be minimized.

Depending on whether the name is a class, file, variable, or other name, variations on this theme result as explained in the following subsections.

Naming Classes

Classes are named beginning with a capital letter. Classes are placed in the appropriate namespace, typically tube:: or itk::tube (see namespaces below). Classes are named according to the following general rule:

class name = <algorithm><input><concept>

In this formula, the name of the algorithm or process (possibly with an associated adjective or adverb) comes first, followed by an input type, and completed by a concept name. A concept is an informal classification describing what a class does. There are many concepts in TubeTK, here are a few of them:

  • Filter: A class that participates in the data processing pipeline. Filters typically take one or more inputs and produce one or more outputs;
  • Iterator: Traverse data in various ways (e.g., forward, backward, within a region, etc.);
  • Reader: A class that reads a single data object (e.g., image or mesh).
  • Region: A subset of a data object, such as an image region;
  • Source: A filter that initiates the data processing pipeline such as a reader or a procedural data generator;
  • Transform: Various types of transformations including affine and procedural;
  • Writer: A filter that terminates the data processing pipeline by writing data to disk or to a communications port.

The naming of classes is an art form; please review existing names to catch the spirit of the naming convention. Example names include:

  • ShrinkImageFilter;
  • TriangleCell;
  • ScalarImageRegionIterator;
  • NeighborhoodIterator;
  • MapContainer;
  • DefaultImageTraits;
  • BackwardDifferenceOperator.

Naming Modules

Modules created within TubeTK should be named in the same manner ascribed to other TubeTK classes. The directories that the modules are constructed in should end in Module as well as the shared library build of the module. However, the standalone version of the module should omit Module from its name.

Naming Files

Files should have the same name as the class, with the namespace of the library prepended (e.g., tube). Header files are named .h, while implementation files are named either .cxx or .hxx, depending on whether they are implementations of templated classes. It is important to note that VTK, ITK, and Qt classes fall under their respective namespaces and do not use the tube namespace.

Naming Methods and Functions

Global functions and class methods, either static or class members, are named beginning with a capital letter. The biggest challenge when naming methods and functions is to be consistent with existing names. For example, given the choice between ComputeBoundingBox( void ) and CalculateBoundingBox( void ) (CalcBoundingBox( void ) is not allowed because it is not spelled out), the choice is ComputeBoundingBox( void ) because Compute is used elsewhere in the system for a similar circumstance. The concepts described previously should be used whenever possible.

When referring to class methods and variables in code, an explicit this-> pointer should be used, as in this->ComputeBoundingBox(). The use of the explicit this-> pointer helps clarify exactly which method, and where it originates, is being invoked. Similarly the :: global namespace should be used when referring to a global function.

Naming Class Data Members

Class data members are prepended with m_ as in m_Size. This clearly indicates the origin of data members, and differentiates them from all other variables.

Naming Local Variables

Local variables begin in lowercase. There is more flexibility in the naming of local variables; please remember that others will study, maintain, fix, and extend your code. Any bread crumbs that you can drop in the way of explanatory variable names and comments will go a long way towards helping other developers.

Naming Template Parameters

Template parameters follow the usual rules with naming except that they should start with either the capital letter T or V. Type parameters begin with the letter T while value template parameters begin with the letter V.

Naming Typedefs

Typedefs are absolutely essential in generic programming. They significantly improve the readability of code, and facilitate the declaration of complex syntactic combinations. Unfortunately, creation of typedefs is tantamount to creating another programming language. Hence typedefs must be used in a consistent fashion.

The general rule for typedef names is that they end in the word Type. For example:

 typedef TPixel PixelType;

However, there are many exceptions to this rule that recognize that TubeTK has several important concepts that are expressed partially in the names used to implement the concept. An iterator is a concept, as is a container or pointer. These concepts are used in preference to Type at the end of a typedef as appropriate. For example:

 typedef typename ImageTraits::PixelContainer PixelContainer;

Here Container is a concept used in place of Type.

Using Underscores

Do not use them. The only exception is when defining preprocessor variables and macros (which are discouraged). In this case, underscores are allowed to separate words.

Preprocessor Directives

Some of the worst code contains many preprocessor directives and macros. Do not use them except in a very limited sense (to support minor differences in compilers or operating systems). If a method makes extensive use of preprocessor directives, it is a candidate for separation into its own class.

Unused Parameters and Shadowed Parameters

Use the macros vtkNotUsed() and itkNotUsed() when implementing class member functions that have unused parameters. Warnings are treated as errors, and unused parameters will generate warnings.

void SetSigma( double sigma, double itkNotUsed( extent ) )
{
  ...some code that does not use the parameter extent...
}

Shadowed parameters are particularly troublesome in that they often indicate code errors and ambiguities. Again, warnings are treated as errors, and shadowed variables will generate warnings.

A common mistake is to give a variable larger scope than what it needs. To avoid this, define loop variables in the loop declaration:

for( unsigned int i = 0; i < 100; ++i )
  {
  ...loop stuff...
  }

Following our naming conventions also helps avoid shadowed variables. In particular, make sure all member variables begin with m_, functions begin with uppercase variables, and variables names are descriptive.

Hidden Virtual Functions

If a base class declares a function, then an instance of that function overloaded in subclasses must include a definition that has the same parameter arguments (signature). For example, if the base class function takes two doubles as arguments, and the derived class has an instance that takes only one double as an argument, then a warning (i.e., an error) is generated. You must also define an instance in the derived class that takes two arguments.

New Line at End of File

Some compilers will complain (generate a warning/error) if a file does not end with a new line. To be safe, make sure each file ends with a blank line.

Namespaces

All classes that do not inherit from VTK, ITK, or Qt classes should be placed in the tube namespace.

Const Correctness

Const correctness is important. Please use it as appropriate to your class or method.

Exception Handling

Indicate that methods throw exceptions in the method declaration as in:

 const float * foo( void ) const throws std::exception

Code Layout and Indentation

The following are the accepted TubeTK code layout rules and indentation style. After reading this section, you may wish to visit many of the source files found in ITK. This will help crystallize the rules described here.

General Layout

Each line of code should take no more than 80 characters. Break the code across multiple lines as necessary. Use lots of whitespace to separate logical blocks of code, intermixed with comments. To a large extent the structure of code directly expresses its implementation.

Indentation and Tabs

The appropriate indentation level is two spaces for each level of indentation. Do not use tabs. Set up your editor to insert spaces. Using tabs may look good in your editor but will wreak havoc in someone else's.

VisualStudioTabsSpaces.png

Declarations

The declaration of variables within classes, methods, and functions should be one declaration per line.

 int    i;
 int    j;
 char * stringname;

Spaces

TubeTK, like ITK, makes liberal use of spaces to improve the readability of code. When in doubt, use a space. Common examples:

  • Separate expressions from their enclosing paren:
 if( a < b )
   {
   a = ( 1 + 1 ) / 2;
   }
  • Separate arguments from their enclosing paren and from other args (there should be a space after every comma):
 foo( int a )
 {
   foofoo( a );
   foofoofoo( a, b );
 }
  • Favor right-flush for lines that are continuations of previous lines:
 this->IsMyReallyLong()->ITK()
                       ->FunctionCall()
  • Use ( void ) when declaring a function that takes no arguments:
 int DoesNothing( void )
 {
 }
  • Use spaces before and after raw pointer declarations:
 int * a;
  • You do not need to use spaces when accessing raw pointers:
 a->b;
 *a = b;

Keep It Simple

Break complex methods into multiple lines. Program in a way that makes it easy for your code to be debugged by others. Examples:

  • ?: statements should not be used instead of if...then statements;
  • Limit the variety of operators that appear in any one line of code.

Includes

  • Only include the necessary files, no more;
  • Group includes per library;
  • Alphabetically sort files within groups;
  • Order groups from local to global;
  • Implementation files should include the header files first.

Class Layout

Classes are defined using the following guidelines:

  • Begin with #include guards;
  • Follow with the necessary includes. Include only what is necessary to avoid dependency problems;
  • Place the class in the correct namespace;
  • Public methods come first;
  • Protected methods follow;
  • Private members come last;
  • Public data members are forbidden.

The class layout looks something like this:

 /*=========================================================================
 
 Library:   TubeTK
 
 Copyright 2010 Kitware Inc. 28 Corporate Drive,
 Clifton Park, NY, 12065, USA.
 
 All rights reserved.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
     http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 
 =========================================================================*/
 
 #ifndef __itktubeExampleImage_h
 #define __itktubeExampleImage_h
  
 #include <itkDefaultDataAccessor.h>
 #include <itkDefaultImageTraits.h>
 #include <itkImageBase.h>
 #include <itkPixelTraits.h>
 
 namespace itk
 {
  
 namespace tube
 {
  
 template< class TPixel, unsigned int VImageDimension = 2,
           class TImageTraits = DefaultImageTraits< TPixel, VImageDimension > >
 class ITK_EXPORT ExampleImage : public ImageBase< VImageDimension >
 {
 public:
   typedef ExampleImage                 Self;
   typedef ImageBase< VImageDimension > Superclass;
   typedef SmartPointer< Self >         Pointer;
   typedef SmartPointer< const Self >   ConstPointer;
 
   itkNewMacro( Self );
   itkTypeMacro( ExampleImage, ImageBase );
 
   ....

 protected:    
   ExampleImage( void );
 
   virtual ~ExampleImage( void )
     {
     }
 
   ....

 private:
   ExampleImage( const Self & other );
 
   void operator=( const Self & other );
 
   ....
 
   PixelContainerPointer m_Buffer
 
   ....
 
 }; // End class ExampleImage
 
 } // End namespace tube
 
 } // End namespace itk
 
 #endif // End !defined(__itktubeExampleImage_h)

Method Definitions

Methods are defined across multiple lines. This is to accommodate the extremely long definitions possible when using templates. The starting and ending brace should be indented. For example:

 template< class TPixel, unsigned int VImageDimension, 
           class TImageTraits >
 const double * 
 ExampleImage< TPixel, VImageDimension, TImageTraits >
 ::GetSpacing( void ) const
 {
   ...
 }

The first line is the template declaration. The second line is the method return type. The third line is the class qualifier. And the fourth line in the example above is the name of the method.

Use of Braces { }

Braces must be used to delimit the scope of an if, for, while, switch, or other control structure. Braces are placed on a line by themselves:

 for( unsigned int i = 0; i < 3; ++i )
   {
   ...
   }

or when using an if:

 if( condition )
   {
   ...
   }
 else if( other condition )
   {
   ...
   }
 else
   {
   ....
   }

Use of vnl and accessing vnl matrix and vector elements

We favor the direct use of vnl for mathematics in TubeTK. ITK methods can also be used when the elements are ITK constructs, but the direct use of vnl is encouraged when the context is neutral.

When accessing vnl_matrix elements, we recommend the use of parenthesis when accessing a matrix element, and the use of get_column and set_column member functions when accessing rows and columns. In general, the least ambiguous form should be chosen in any context.

When accessing vnl_vector elements, parenthesis or brackets may be used - typically dictated by code flow / context.

Doxygen Documentation System

Doxygen is an open-source system for automatically generating documentation from source code. To use Doxygen effectively, the developer must insert comments, delimited in a special way, that Doxygen extracts to produce the documentation. While there are a large number of options to Doxygen, developers at a minimum should insert the following Doxygen commands.

Documenting a Class

Classes should be documented using the \class and \brief Doxygen commands, followed by the detailed class description:

 /**
  * \class Object
  * \brief Base class for most itk classes.
  *
  * Object is the second-highest level base class for most itk objects.
  * It extends the base object functionality of LightObject by
  * implementing debug flags/methods and modification time tracking.
  */

Documenting a Method

Methods should be documented using the following comment block style as shown in the following example:

 /**
  * Access a pixel. This version can be an lvalue.
  */
 TPixel & operator[]( const IndexType & index )
 { 
   return this->GetPixel( index ); 
 }

The key here is that the comment starts with /**, each subsequent line has an aligned *, and the comment block terminates with a */.

Testing

Each developer should do his or her part to aid in testing process. It is generally accepted that each developer should write proper unit tests using CTest and those tests will be run on nightly and continuous dashboards.

Dashboards

  • CDash Dashboards are maintained for all platforms;
  • Warnings are not tolerated;
  • Failing tests are preferred over disabling tests or using case/system-specific hacks for solutions. The best answer is to fix the code.

Releases

Before each product release, a battery of testing (specified on the project wiki) will be carried out to check for regressions not caught by traditional unit testing. Release version naming convention:

  • MajorReleaseNumber.MinorReleaseNumber.PatchReleaseNumber;
  • These variables are controlled in the top-level CMakeLists.txt file. They apply to all applications within TubeTK.

Code Coverage

Code coverage is responsibility of all developers.

Memory Leaks

Memory leaks must be plugged. A list of leaks and memory defects can be found on the Dashboard under the Dynamic Analysis section. Clicking on the Defect Count will show further information.

A script is available for Linux and OS X to help debug the memory leaks. It can generate the same output present on the dashboard on demand for a subset of tests. The command

./TubeTK/Utilities/Valgrind/runValgrind.sh -h

shows full usage instructions. Essentially install valgrind and xsltproc, then execute the runValgrind.sh script from TubeTK-Build with arguments such as

-R leakyTubeTestName.

Git repo management

Create a fork in your github account, and perform pull requests.

Optimizing code in Linux