Skip to content

CAM Coding Standards

goldy edited this page Sep 22, 2021 · 18 revisions

The standards in this document are largely prescriptive, i.e., they should be followed.

  • MUST: Exceptions must be discussed and agreed to by the CAM SEs and noted in this document.
  • SHOULD: Exceptions must be approved by the CAM SEs and documented in the ChangeLog.

While some legacy code will not follow these rules, efforts SHOULD be made to improve the code whenever you are working on it (e.g., bug fixes, enhancements).

Python Coding Standards

For the most part, python code should pass pylint where pass is defined as a 10.0 score. Most of the rules for python coding are listed in the main .pylintrc (in <root>/test) file with significant deviations from standard pylint noted below, followed by allowable source code exceptions.

.pylintrc changes

  • disable=import-error: This may be temporary until a test framework can be set up to correctly set up PYTHONPATH to avoid import errors
  • max-nested-blocks=15: Allow more complex logic (was 5)
  • bad-names: Added qux
  • ignore-long-lines: Modified regex to ignore doctest statements
  • max-module-lines=2000: Allow longer files (was 1000)
  • max-args=10: Allow more arguments to functions (was 5)
  • max-branches=30: Allow more branches, part of the more complex logic bit (was 12)
  • max-locals=25: Allow more local variables (was 15)
  • max-statements=100: Allow longer methods / functions (was 50)

Allowable local pylint pragmas

These pylint statements are allowed in your code as long as you follow the guidelines described below

  • disable=wrong-import-position: Sometimes you have to modify the sys.path before you can do an import. Disable this warning just before the import but be sure to re-enable it (enable=wrong-import-position) right afterwards.
  • disable=import-outside-toplevel: Use this when an import is required by the code logic. Try to minimize use of this pragma. Disable this warning just before the import but be sure to re-enable it (enable=import-outside-toplevel) right afterwards.

Indentation and Style

  • Do not use the tab (\t) character for indentation or for whitespace.
  • Indentation is 4 spaces
  • Close blocks with a comment line, out-indented to the block beginning (e.g., # end for, # end if).
  • No trailing spaces (i.e., no spaces at the end of a line)

Fortran Coding Standards

MUST

  • No naked use statements
  • No continued single-line if statements (i.e., all if statements should have a then if the statement is on more than one line)
  • Every namelist variable in each active namelist group is present in the namelist file. An active namelist group is one which may be read during the current run.
  • All namelist variables except for logical quantities are initialized to invalid values (integer: -HUGE(1), real: NaN, character: 'UNSET').
  • Do not combine statements on a single line (i.e., avoid use of the semi-colon to combine statements).
  • Use intent for dummy arguments except for pointers.
  • Functions may not have side effects.
  • Always use spaces instead of tabs
  • All variables of type real must have a specified kind, including literals. For example, use 1.5_r8, not 1.5 or 1.5D0.
  • All character declarations must use Fortran 90+ syntax (e.g., character(len=*) or character(len=CL)).
  • All variable declarations must use Fortran 90+ syntax (i.e., must include the double colon between the attributes and the variable name).
  • All type and procedure declarations must use Fortran 90+ syntax (i.e., must include the double colon before the type or procedure name).
  • All modules should include an implicit none statement in the preamble (after the use statements). Module routines then do not need this statement.
  • All optional arguments must be passed via keyword (e.g. use call subroutine(x, optional_y=y) instead of call subroutine(x, y) for the optional variable optional_y).

SHOULD

  • Avoid use of preprocessor directives (e.g., #if, #ifdef). Always try for runtime variable logic instead.
  • Keep formula statements relatively short. Use temporary variables to break long formulas into easier-to-read sections.
  • Use subroutines to avoid repeated (cut and paste) code logic.
  • Avoid side effects in subroutines. Pass variables to routines instead of 'using' them from elsewhere.
  • Use comments to explain what you are doing (logic). When working with code, always check the comments to make sure they are still correct and useful.
  • Do not use comments to 'save code for later in case it might be useful'.
  • List dummy arguments one per line, however, related items may be grouped.
  • Dummy argument order should match the order in the argument list.
  • Use symbolic numerical comparison operators (e.g., ==, /=, <, >=) not old character versions (e.g., .eq.).
  • Avoid the use of pointers as dummy arguments (exceptions must be discussed in design or code review)
  • Modules should be default private. Public interfaces are declared after the private declaration.
  • Module names should conform to their filename (i.e., the module name should be the filename without the .F90).

Indentation and Style

  • Scoping: Indentation should follow scope. That is, whenever entering a new scope (e.g., module, subroutine, if, do), indent that scope relative to the scoping statement (recommended 3 spaces but each module should at least be self consistent).
  • Continue lines: Indent continue lines 5 spaces or align with similar lines in statement.
  • No trailing spaces (i.e., no spaces at the end of a line)
  • Use spaces to ease reading statements (e.g., before and after operators, after commas except in a dimensions list)
  • Include a space after if, else, end, do, and while.
  • Include a space before and after ::
  • No space after only, i.e., only:, not only :.
  • When aligning code for readability, commas go immediately after a symbol (no space).
Clone this wiki locally