Coding standard

From tm5
Jump to: navigation, search

Coding Standards help reduce sources of common bugs, causes of inscrutable software, differences in coding style, ... In other words, they facilitate maintenance, and improve code portability and readability. And at the end, they improve science productivity.

"Mostly, a program is communication from one programmer to another (forget about the machine), where the "other" programmer is likely to be myself next week, and using the clearest coding style is usually the best. D. Hendrickson, on comp.lang.fortran

For TM5 a couple of rules are mandatory: internal documentation and line length. Others are recommendations. Feel free to add your own suggestions (so we can discuss it). Three broad categories are considered here: style, language, and design. Have a look at some of TM5 most recent modules to see how these standards are applied.

Contents

Coding style

Internal documentation

These rules force you to clean up your code. You should describe module/procedure/function, and their variables. It also brings a consistent look-and-feel across the code, which increases readability. We recommend using ProTex keywords to introduce these mandatory comments in your code. You should at least include:

We do not recommend including history. This is better retrieved through the version control software (subversion).

Formatting conventions

This concerns names, indentation, usage of spaces, case, ... We have not agree on any conventions, but have these suggestions:

F90 language constructs

These rules seem to be tacitly followed, and are viewed as good practice.

Code design and control

These rules are particularly helpful for new developments.

Error handling

Add these lines at the top of your module:

#define TRACEBACK write (gol,'("in ",a," (",a,", line",i5,")")') rname, __FILE__, __LINE__; call goErr
#define IF_NOTOK_RETURN(action) if (status/=0) then; TRACEBACK; action; return; end if
#define IF_ERROR_RETURN(action) if (status> 0) then; TRACEBACK; action; return; end if

Add a return code to your subroutines:

integer, intent(out) :: status

and define the rname parameter for each subroutine:

 character(len=*), parameter ::  rname = 'routine_name'

Then, if your code catches an error, it must return a status with a value different from 0. After a call to that subroutine, you can catch any error and return to the caller with either one of these lines:

IF_NOTOK_ERROR(action)
IF_ERROR_RETURN(action)

where action is typically status=1 for a typical error.

Specific treatment for MDF routines (the user interface to data files) are used, see io_save.F90 for example.

Print statements

For for logs and print statements, just use the General Object (GO) suite of tools.

use GO, only :: gol, goPr, goErr, goBug
...
write(gol,*) 'something to write'
call goPr

If you call goErr or goBug instead of goPr, the [ERROR] or [BUG] is prepended to the output.

You can find more details about formatting the logs in Output options.

Universal constants

Put them in the binas.F90 module.

New developments

They should be below the TM5/proj/ dir. In the following tree, alanis, budget, c13, and chem/base are different projects. See Creating a new project for more details on creating your own.
TM5  
 |-- base
 |   |-- branches
 |   |-- release
 |   `-- trunk
 |-- proj
 |   |-- alanis
 |   |-- budget
 |   |-- c13
 |   |-- chem/base
 |   |   |-- branches
 |   |   |-- release
 |   |   `-- trunk
A project has typically a trunk and a branches sub-directories. Before inclusion in the trunk, major modifications to the project should be carried on a copy of the trunk into a branch under the branches directory. See Creating a new branch for more details on creating your own branch.
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox