Camino code organization and standards

This page describes in detail how Camino code is (or should be - work in progress) organized.

Workflow for developing code

  1. Check out a version of the code
  2. Run unit tests
  3. Run ScriptTest and save the output as ScriptTest.yourmachine.check
  4. Check that ScriptTest.out.yourmachine.check has no diffs with ScriptTest.out.yourmachine in camino/test
  5. Make your changes, including
    1. Comments and Javadoc in the code
    2. Tests for your new code
    3. Updated man page to reflect any changes to applications
  6. Run tests again; make further changes and test as necessary.
  7. Copy ScriptTest.out.yourmachine to camino/test/ScriptTest.out.yourmachine
  8. Commit with a detailed message describing what you did

The user interface

Camino users interact with the commands in the bin/ directory. These are executable files that may call one or more Camino program. Currently, most of the executables are bash scripts that do some simple system checks and then forward the application name and arguments to EntryPoint. New scripts should be written in bash, though we may allow other scripting languages later. Users never invoke Java or any other interpreter explicitly.

Applications (apps)

Apps have a special structure to accomodate Matlab wrapping and provide a consistent user interface. All applications should extend the Executable class. Executables provide the following methods, which are executed in the following order:

  1. void initDefaultVals() - Set all class variables to default values
  2. void initOptions(String[]) - Process command line options
  3. void initVariables(String[]) - Any additional setup that is required after processing command line args
  4. void execute(data.OutputManager) - Runs the executable and passes output to the OutputManager

Executables must also provide a String usage() method, which returns basic information on how to run the application. This method is called by EntryPoint only if the command is run with -help and no other options.

Once you've written an app, you need to add it to the getExecutable method of the EntryPoint class, which is what actually gets executed in the script called by the user:

    java [options] EntryPoint AppName [options]

EntryPoint simply constructs an AppName object, forwards the command line arguments, and then calls its execute method - unless the command is called with -help.

Other modules

Other modules are arranged by theme. These classes should not have main methods (a couple currently do, eg AnalyzeHeader / Nifti1Dataset), they should be objects with a well-defined and documented API. We don't have well-defined coding standards, but Effective Java by Bloch has some good guideines.

Compiling

Compilation is performed via a Makefile. Each class in apps is compiled individually, which should in turn compile the rest of the code. However, this relies heavily on Java to correctly work out all the dependencies with other classes, which it doesn't always do correctly. You can bypass this issue with make allclasses, which will compile everything under the Camino tree that isn't in the test directory. Alternatively, you can do make clean and then make, which should be equivalent, but this is slower. However, most users will download the code and just do make, so be sure that your apps all work by doing make clean, make, and then running the tests.

Documentation

Applications should be documented with command-line usage, man pages, and online tutorials as appropriate. All classes should be documented with Javadoc for all methods.

Javadoc

By default, public, package and protected methods will appear in the javadoc. Private methods should be documented in the code with a Javadoc comment, but this is more for the benefit of people coding the class itself.

You can build the Javadoc with make docs. See the Javadoc tutorial for more information on coding doc comments.

Usage

All applications should provide a basic usage when passed the -help option. This is handled by EntryPoint so applications don't have to do anything except implement the usage() method.

Man pages

Man pages are written in NROFF. Check how your man pages look when you type man <command>. The man pages should follow a consistent format:


NAME
      program - One or two sentence description of what the program does

SYNOPSIS

      program -mandatoryOption <arg> [-notMandatory <arg>] [...]

      Some programs have too many options to list; in which case just list the most common ones and indicate 
      that there are more

DESCRIPTION
    Detailed description of what the program does

OTHER SECTIONS  AS NECESSARY

EXAMPLES
   Some common examples with a brief explanation

OPTIONS
    Complete listing of options with explanation of their syntax and function

AUTHORS
    Who wrote the program or a substantial portion thereof

SEE ALSO
    Other programs of interest

CAVEATS 
    Formerly bugs, but more general. Includes known bugs, limitations, or common misconceptions

The HTML man pages are auto-generated nightly - but new man pages need to be added to the Wiki. If you commit a new command, update the Wiki command list to point to the HTML version of that man page.

Testing

Please see the test page for information about tests. Avoid embedding test code in the main methods of classes, or by writing test classes inside the packages themselves. For application tests, write a real-world use of the class and place it in ScriptTest. For unit tests, use the JUnit framework in the test directory. Java packages are virtual, you have the same access to package / protected methods in test/numerics as you do in numerics. A JUnit test is accessible to all users rather than just the person who wrote the test, and it can be run automatically by all users.

The automated testing system requires one of two things to be true each night. Either

  1. ScriptTest produces no diffs with the repository ScriptTest.out

or

  1. Another ScriptTest.out.somewhere exists that is newer than ScriptTest.out.

Please see the testing page for more information.