WARNING: This is the _old_ Lustre wiki, and it is in the process of being retired. The information found here is all likely to be out of date. Please search the new wiki for more up to date information.

Difference between revisions of "Documenting Code"

From Obsolete Lustre Wiki
Jump to navigationJump to search
(Add a note about descriptions grammar, and a note about automatic cross-referencing)
Line 35: Line 35:
 
* it opens with a brief description of what this function is doing. Brief description runs up to the first full-stop mark (.)
 
* it opens with a brief description of what this function is doing. Brief description runs up to the first full-stop mark (.)
 
* brief description is followed by the detailed description.
 
* brief description is followed by the detailed description.
 +
* descriptions are written in active voice with indicative mood verbs in third person singular: "[This function] does this and that", "[This data-type represents] such and such concepts".
 
* to refer to a function argument use \a argname syntax.
 
* to refer to a function argument use \a argname syntax.
 
* to refer to another function use funcname() syntax---it will produce a cross-reference.
 
* to refer to another function use funcname() syntax---it will produce a cross-reference.
 
* to refer to a field or an enum value use SCOPE::NAME syntax.
 
* to refer to a field or an enum value use SCOPE::NAME syntax.
 
* if possible, specify a (weakest) precondition and (strongest) postcondition for the function. If conditions cannot be expressed as a C language expression, provide informal description. Use ''result'' to refer to the function return value. Mention all concurrency control restrictions (such as locks that function expects to he held, or holds on exit) here.
 
* if possible, specify a (weakest) precondition and (strongest) postcondition for the function. If conditions cannot be expressed as a C language expression, provide informal description. Use ''result'' to refer to the function return value. Mention all concurrency control restrictions (such as locks that function expects to he held, or holds on exit) here.
* describe possible return values with \retval
+
* describe possible return values with \retval.
* enumerate related functions and data-types in \see section
+
* enumerate related functions and data-types in \see section. Note, that doxygen will automatically cross-reference all places where given function is called, and all functions that it calls, there is no need to enumerate all this.
 
* optionally use \author tag, so that the world knows whom to praise.
 
* optionally use \author tag, so that the world knows whom to praise.
  

Revision as of 04:35, 13 May 2008

In addition to the architecture and design documentation, certain amount of documentation has to be maintained in the Lustre source code. Main reason for this is that it is very difficult to constantly keep separate documentation up to date with the changing code.

The best way to document the code is to make its so simple and clear that no additional documentation is necessary. As R. Pike, Esq. put it: Basically, avoid comments. Failing to reach this ideal, code has to be commented. There are two broad categories of the comments:

  • how: describes how this particular piece of code achieves its function;
  • what: describes what is the purpose of this function or data-type or module, and how it fits into larger picture. These are interface comments.

This page deals only with the latter type. Lustre is using (will use) doxygen to automatically generate cross-linked interface descriptions from source code. As a result, interface comments have to follow certain template, which has advantages on its own.

Below are few examples:

commenting a function

/**
 * Owns a page by IO.
 *
 * Waits until \a pg is in cl_page_state::CPS_CACHED state, and then switch it
 * into cl_page_state::CPS_OWNED state.
 *
 * \pre  !cl_page_is_owned(pg, io)
 * \post result == 0 iff cl_page_is_owned(pg, io)
 *
 * \retval 0   success
 *
 * \retval -ve failure, e.g., page was destroyed (and landed in
 *             cl_page_state::CPS_FREEING instead of cl_page_state::CPS_CACHED).
 *
 * \see cl_page_disown()
 * \see cl_page_operations::cpo_own()
 */
int cl_page_own(const struct lu_env *env, struct cl_io *io, struct cl_page *pg)

Note that:

  • doxygen comment starts with /** (like in javadoc)
  • it opens with a brief description of what this function is doing. Brief description runs up to the first full-stop mark (.)
  • brief description is followed by the detailed description.
  • descriptions are written in active voice with indicative mood verbs in third person singular: "[This function] does this and that", "[This data-type represents] such and such concepts".
  • to refer to a function argument use \a argname syntax.
  • to refer to another function use funcname() syntax---it will produce a cross-reference.
  • to refer to a field or an enum value use SCOPE::NAME syntax.
  • if possible, specify a (weakest) precondition and (strongest) postcondition for the function. If conditions cannot be expressed as a C language expression, provide informal description. Use result to refer to the function return value. Mention all concurrency control restrictions (such as locks that function expects to he held, or holds on exit) here.
  • describe possible return values with \retval.
  • enumerate related functions and data-types in \see section. Note, that doxygen will automatically cross-reference all places where given function is called, and all functions that it calls, there is no need to enumerate all this.
  • optionally use \author tag, so that the world knows whom to praise.

data-type

/**
 * "Compound" object, consisting of multiple layers.
 *
 * Compound object with given fid is unique with given lu_site.
 *
 * Note, that object does *not* necessary correspond to the real object in the
 * persistent storage: object is an anchor for locking and method calling, so
 * it is created for things like not-yet-existing child created by mkdir or
 * create calls. lu_object_operations::loo_exists() can be used to check
 * whether object is backed by persistent storage entity.
 */
struct lu_object_header {
        /**
         * Object flags from enum lu_object_header_flags. Set and checked
         * atomically.
         */
        unsigned long     loh_flags;
        /**
         * Object reference count. Protected by lu_site::ls_guard.
         */
        atomic_t          loh_ref;
        /**
         * Fid, uniquely identifying this object.
         */
        struct lu_fid     loh_fid;
        /**
         * Common object attributes, cached for efficiency. From enum
         * lu_object_header_attr.
         */
        __u32             loh_attr;
        /**
         * Linkage into per-site hash table. Protected by lu_site::ls_guard.
         */
        struct hlist_node loh_hash;
        /**
         * Linkage into per-site LRU list. Protected by lu_site::ls_guard.
         */
        struct list_head  loh_lru;
        /**
         * Linkage into list of layers. Never modified once set (except lately
         * during object destruction). No locking is necessary.
         */
        struct list_head  loh_layers;
};

files and modules

  • document functions in the .c files, rather than headers.
  • to document a software component add the following to the header file with definitions of the key data-types for this module:
/** \defgroup component_name component_name
 *
 * overall module documentation
 * ...
 *
 * @{ 
 */
type definitions...
exported functions...
/** @} component_name */
  • to separate a logical part of larger component add the following somewhere withing components's \defgroup:
/**
 * \name subcomponent_name subcomponent_name
 *
 * Description of a sub-component
 */
/** @{ */
type definitions...
exported functions...
/** @} subcomponent_name */