How to contribute

Thanks for taking the time to contribute to the open source Tracx toolbox!

_images/TrackerLogo.png

Please follow the Documentation, Style and Changelog Guide to make sure that all your great work will work flawlessly and also be properly documented.

Documentation guide

This guideline is modified for Tracx taken from here.

In order to enable the automatic documentation generation, the header of a MATLAB function has to be formatted properly. The automatic documentation extracts the commented header of the function (commented lines between the function’s signature and the first line of code) based on keywords and blocks.

Rule 1: There should be 1 free space between the percentage sign % and the text. For instance, a correctly formatted line in the header reads:

% this is correct

A line in the header that is formatted as follows is ignored:

%this is not correct (note the space)

Rule 2: After the last line of the header, leave one empty line before the body of the function.

% This is the end of the header of the function

x = 5;  % the body of the function begins after one empty line

Importantly, do not put a comment above the first line of code, but include the comment inline:

% This is the end of the header of the function

% the body of the function begins after one empty line
x = 5;

Rule 3: A line in the header that includes .. after the percentage sign will be ignored in the documentation:

% .. this line will be ignored

Function signature

The function signature must be correctly formatted. Leave a space after every comma and before and after the equal sign =. A correctly formatted function signature reads:

function [output1, output2, output3] = someFunction(input1, input2, input3) % good practice

A function signature that is not formatted properly throws an error during the automatic documentation generation:

function [ output1,output2,output3 ]=someFunction( input1,input2,input3 ) % bad practice

Function description

The description of the function is a brief explanation of the purpose of the function. Start with a capital letter function name. The description of the function may extend over several lines. However, try to keep the explanations as brief as possible.

function [output1, output2, output3] = someFunction(input1, input2, input3)
% SOMEFUNCTION. This is a description of the function that helps to understand how the function works
% Here the description continues, then we leave an empty comment line
%

Keywords

The automatic documentation software relies on keywords to properly format the documented function. A keyword also defines the start of a block with the header of a function. Main keywords include:

  • Args:: block with input argument(s)

  • Returns: block with output argument(s).

  • Example:: block with example code (formatted MATLAB syntax)

  • .. note::: highlighted box with text

  • :Authors:: list with author(s)

Each of them must be followed by non-empty lines and should be separated from the next block by an empty line.

All keywords are optional. For instance, if a function does not have any input arguments, the keyword Args: can be omitted.

Any line of the block must be indented by 4 spaces after the comment sign %:

% Args:
%    input1 (:obj:`object`):     Description of input1
%    input2 (:obj:`int`):        Description of input2
% input3:    Description <-- this is bad practice
%
% Returns
% -------
%    output1: :obj:`bool` <-- no brackets needed
%                                                           Description of output1 <-- start on next line

If the indentation differs, there will be an error.

Keyword Example:

In the block starting with the keyword Example:, the function’s signature must be given in order to show how the function should be used. It is important to leave one empty line before the keyword Example:, after the keyword, and after the function’s signature.

% the end of the description
%
% Example:
%
%    [output1, output2, output3] = someFunction(input1, input2, input3)
%
% here the other section can begin

Keyword Args: and Returns

The arguments declared in the blocks: Args:, Example: Authors: must be followed by a colon : before the argument description is provided. Except Returns this needs to be followed by a line with dashes.

The indentation between the argument (with colon) and the description should be at least 4 spaces, so that all argument descriptions are aligned.

% Args:
%    input1 (:obj:`int`):     Description of input1 <-- good practice
%    input2 (:obj:`int`)     No colon <-- bad practice
%    input3 (:obj:`int`): Not enough distance (4+ spaces) <-- bad practice
 %   input4: No info on datatype <-- bad practice
%
% Returns
% -------
%    longerNameOutput:
%                                             Description of longerNameOutput after 4 spaces
%    output1:
%                         Description begins at the same place as the longest argument <-- good practice
%    output2:
%                  Description begins too soon <-- bad practice

For a structure argument, it is possible to list its fields. An empty line is added after the structure argument. Then, in the next line, the field is written aligned with the description of the structure plus 2 extra spaces.

The field is listed beginning as * .field - description (note the space between * and .). It is not necessary to leave an empty line after listing fields and writing the next argument. The following illustrates how to list a structure with its fields:

% Returns
% -------
%    output:    output argument with fields:
%
%                 * .field1 - first field of the structure.
%               * .field2 - no indent <-- bad practice
%                 * .field3 - multi-line comment must begin always
%                   where the text of the first line begins <-- good practice
%                 * .field4 - multi-line comment where
%                 the text in line 2 begins too soon <-- bad practice
%    next:      next argument can be added without empty line

It is also possible to replace * with a numbered list. You can use numbers followed by a dot (e.g., 1.) instead of * ..

% Args:
%     varargin (:obj:`str varchar`):
%
%        * **opt input 1** (:obj:`float`): Description of optional argument1.
%        * **opt input 2** (:obj:`float`): Description of optional argument 2. Note do not linebreak!

Keyword Example:

A common usage example can be included in the Example: block. Code included in this block will be formatted as MATLAB formatted code. Leave one empty line before the keyword Example:, after the keyword, and after the properly indented (4 spaces) code snippet.

% the previous block ends here
%
% Example:
%
%    result = someFunction(input1, input2)
%    %additional comment if necessary
%
% another block begins here

Keyword ..note::

Important information, such as common errors, can be included in the block that starts with the keyword ..note::. A ..note:: block is formatted in a dedicated and highlighted box in the documentation.

Leave one empty line before the keyword ..note::, after the keyword, and after the properly indented text (indent of 4 spaces). The keyword needs to start with two dots followed by two colons after the name.

Normally formatted text can be left at the with one space after the comment sign. An example of a ..note:: block reads:

%
% ..note::
%
%    This is a note that contains a important information.
%    It will be clearly visible in the documentation online.
%
% This is an additional final comment that can be added and that is
% only relevant to the code itself

Keyword :Authors:.

In the :Authors: block, the author(s) that have written or contributed to the function are listed. Authors are shown in the documentation. For multiple authers use a list with a dash.

%
% :Authors: - Name, date, additional information if needed
%     Author Name - Short description


x = 5;  % here the body of the function begins

If there are 2 or more authors, format as follows:

%
% :Authors:
%
%     - Author Name - Short description
%     - Author2 Name - Short description

x = 5;  % here the body of the function begins

Example

A complete example of a function is provided here. Please remember that colons, indentations, and keywords are important to guarantee pretty formatting.

function [output1, output2] = someFunction(input1, input2, input3, varargin)
% SOMEFUNCTION. This is a description of the function that helps understand how the function works
% Here the description continues, then we leave an empty comment line
%
% Example:
%
%    [output1, output2] = someFunction(input1, input2, input3, input4)
%
% Args:
%    input1 (:obj:`int`):     Description of input1
%    input2 (:obj:`str`):     Description of input2
%    varargin (:obj:`str varchar`):
%
%        * **opt input 1** (:obj:`float`): Description of optional argument1.
%        * **opt input 1** (:obj:`float`): Description of optional argument1.
%
% Returns
% -------
%    output1 :obj:`unit8` NxM
%                                          Description of output
%    output2 :obj:`unit8` NxM
%                                          Description of output
%
% Example:
%
%    % this could be an example that can be copied from the documentation to MATLAB
%    [output1, output2] = someFunction(11, '22', structure, [1;2])
%    % without optional values
%    output1 = someFunction(11, '22')
%
% ..note::
%
%    This is a very important information to be highlighted
%
% This is a final comment that cannot be in the description but can be useful
%
% :Authors:
%    Name - some information

x = 5;  % here the body of the function begins

Style guide

A comprehensive MATLAB style guide written by Richard Jonson can be found here. This guide is adopted from here.

Code

  1. Spacing

  • Write if singleCondition, and not if (singleCondition). Use brackets only for multiple conditions.

  • Use spaces around operators, e.g., i + 1 instead of i+1

  • Use spaces after commas (unless separated by newlines)

  • Avoid spaces inside the curly-braces of cells: {a, b} instead of { a, b }

  • Use spaces after commas in lists, after operands, after names, etc. This also improves readability. e.g. a = [1, 2, 3; 4, 5, 6]; instead of a=[1,2,3;4,5,6];

  • Include a single line of whitespace between blocks of code

  • Include a whitespace after a comment sign %

  1. Variable names

  • When using mixed words, separate with capital letters (with no intervening spaces or punctuation), e.g. calculateKineticFlux

  • Avoid ambiguity when naming variables: be as specific as possible

  • All variable names must be written in English

  • Use verb-noun structure for functions: allows to explain the operations performed

  • Append meaningful prefixes when possible, e.g. Av, Sum, Min, Max, etc

  • Boolean type variables, i.e. with only true/false values, with Is or is to stress this fact, e.g. if dataIsLoaded

  • Reuse names for short-life and variables with local scope, such as indexes of loops

  • Only use i, j, etc., as indexes for very short loops

  1. Miscellaneous

  • Add sanity checks to the code, e.g., if something does not work as expected, there should be code to check for this and either issue a warning or an error if there is a problem.

  • Do not encode the absolute position of any files within any function: use relative paths, where possible

  • Indent the code: really improves readability.

  • Fix a maximum line length: break large ones if needed. Ensure that it is clear that the sentence is separated through different lines, e.g.:

function [parameter1, parameter2, parameter3, parameter4] = functionManyParameters...
          (InputParameter1, InputParameter2, InputParameter3, InputParameter3, ...
           InputParameter4, InputParameter5)
  • Divide the code in separate functional files whenever it is possible (and logical). Latest at ~1.5k lines of code seperate files should be used. Only exception are documentation strings for varargins and class properties which would not be rendered correctly otherwise.

  1. Platform independent code

  • Use pwd to get the current directory

  • Use filesep for paths (e.g., ['myPath' filesep 'myFile.m'])

Documentation and comments

  • Make sure the code is fully documented and commented, especially parts of the code that might be difficult to understand for beginner users.

  • Header for each file with the following elements:

    • Brief description (easy and short functions) or more detailed explanations (more complicated functions).

    • Description of INPUT and OUTPUT variables

    • Authors, co-authors, contributors (and the contribution of each of them)

    • Date of first fully operative version, and dates of consequent modifications with the corresponding number of version, e.g. v1 - 11/06/2014 / v2 - 12/08/2014

    • Description of modifications in later versions, e.g. v2: the efficiency has been improved by substituting the loops with matrices operations

  • Throughout the file:

    • Comment smartly. Not every line, but enough to allow tracking the execution

    • Try to use brief comments.

    • In case you believe a more complicated part requires a more comprehensive explanation, describe What are you doing and How it is done through a more detailed paragraph.

    • If the code is divided in blocks, you can also introduce briefly what is the function of each block beforehand.

    • Format the comments with a whitespace after the % sign. Try to use lowercase letters for comments.

Tests

  • Annotate the individual tests extensively for review

  • Use assert(computedResult == expectedResult) to logically test the computedResult and the expectedResult (you may also use < or >)

  • For testing all entries of a vector, use assert(all(vector1 == vector2))

  • Only use equality assert tests for integer values

  • Make sure that equality assert tests within a given tolerance, e.g., tol = 1e-9; assert(condition < tol);

  • Test, if possible, your contribution on cross platform such as OSX, Linux and WIN.

  • Make sure to limit the output of the function to a minimum - only print the necessary information

  • Use verbose or printLevel to switch the verbose mode

  • Ensure that the solution of optimization problems is actually a solution (test that the solution vector satisfies the imposed constraints)

Git commit messages

  • Use the present tense (“Add feature” not “Added feature”)

  • Be as specific and concise as possible

  • Reference issues and pull requests liberally

  • When only changing documentation, include [documentation] in the commit description

Changelog guide

The Changelog of Tracx contains a curated, chronologically ordered list of notable changes for each version of Tracx to make it easier for users and contributors to see what changes have been made. This is especially important in terms of reproducibility of Biomedical analysis.

We follow the guidelines described here in detail:

Keep in mind that:

  • Changelogs are for humans, not machines.

  • There should be an entry for every single version.

  • The same types of changes should be grouped.

  • Versions and sections should be linkable (i.e. used in git tags).

  • The latest version comes first.

  • The release date of each version is displayed. We use the isodata format ISO 8601. YYYY-MM-DD

Label changes as follows:

  • Added for new features.

  • Changed for changes in existing functionality.

  • Deprecated for soon-to-be removed features.

  • Removed for now removed features.

  • Fixed for any bug fixes.

  • Security in case of vulnerabilities.

We stick to Semantic versioning

The version number is therefore structured as MAJOR.MINOR.PATCH, with:

- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards compatible manner, and
- PATCH version when you make backwards compatible bug fixes.

Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

More details here