Skip to content

Dev Advice, Best Practices, and Style Guide

Benjamin Pittman-Polletta edited this page Dec 20, 2017 · 63 revisions

Overview

  • Strive for backwards compatibility anytime you change the API (application programming interface)!
  • Test Octave compatibility with new features. Or block the for octave if they don't work (check reportUI).
  • Add an empty folder to dynasim directory called '_dev' that is ignored by git, but that triggers developer outputs.
  • Changes to many files in the codebase might be accelerated by using Atom, or using Codacy and writing our own patterns.
  • Always put rethrow(err) in a try...catch block. This enables using dbstop if error for debugging.
  • Put your personal use files that won't be synced to github in '_ignore'
  • Reopen old closed issues instead of making new ones
  • If commit references an issue, make the first line of the message "#XXX Max 50 char summary" followed by more explanation as needed on subsequent lines.
  • Use fileparts2 instead of fileparts. Use .. instead of fileparts for parent directory.
  • Use getAbsolutePath(thePath) instead of fullfile(pwd, thePath) to avoid double pwd concatenation bugs
  • use mfileFnName instead of mfilename to allow for package support
  • Update git version on cluster for easier use of submodules
  • Use 'X.mech' for mechanism files instead of 'X.txt'

Naming Conventions

  • User functions are camelCase with no underscore.
  • Utility functions are currently inconsistent; should be camelCase; some are currently lowercase or lower_case
  • Options are lower_case with underscore.

Branches

  • Name your feature branches after both the Issue # they're related to and a tiny explanation of the content. Some good examples include iss59_md_plotting_framework and iss90_one_file_mode_for_parallel.

Unit Testing

  • Documentation on Class-Based Matlab Unit Testing

  • Unit Testing Function Template

  • Automatic Unit Test Data Creation

    • flag name: auto_gen_test_data_flag
    • mat file name: fnName_autogen_hash.mat
  • If function makes figures or saves data, function should permit last 2 arguments to be 'xUnit',1 to enable unit testing mode that changes behavior, eg suppresses data saving

    • Example code:
    if strcmp(varargin{end-1},'xUnit') && varargin{end}==1
      output = struct('eachOutput',eachOutput, 'pathsToSavedDataVar',pathsToSavedDataVar, 'localfunctions',localfunctions);
    end
    
  • If function has nested or local functions

    • Convert/make all nested functions into local functions (doesn't share any scope/variables with main function)
      • This also enables cutting and pasting of local function into separate function file at any time
    • In unit testing mode, if pass empty arguments to function, that function should return the local function handles without evaluating the function
      • If needed to differentiate from normal behavior, main function should permit last 2 arguments to be {'xUnit', 1} to enable unit testing mode
      • localfunctions is a function that returns handles to all local functions
      • Example Code:
      if isempty(eachArg)
        output = struct('eachOutput',[], 'localfunctions',localfunctions);
        return
      end