General points::
- No line of code exceeds 80 characters in length.
- There are no tab characters.
- 2-space indentation is used.
- Comments contain no spelling or grammatical errors. (Abbreviations and sentence fragments are acceptable when trying to fit a comment on a single line as long as the meaning is clear.)
- The tone of comments is professional and courteous. Comments contain no profanity, obscenity, or inuendo.
- All C-code conforms to ANSI C-89.
C preprocessor macros:
- The purpose of every preprocessor macros is clearly explained in a comment associated with its definition.
- Every preprocessor macro is used at least once.
- The names of preprocessor macros clearly reflect their use.
- Assumptions about the relative values of related macros are verified by asserts. Example: assert(READ_LOCK+1==WRITE_LOCK);
Function header comments:
- Every function has a header comment describing the purpose and use of the function.
- Function header comment defines the behavior of the function in sufficient detail to allow the function to be reimplemented from scratch without reference to the original code.
- Functions that perform dynamic memory allocation (either directly or indirectly via subfunctions) say so in their header comments. The memory pool used for dynamic memory allocation is clearly stated.
- The behavior of functions in an OOM situation is clearly stated in the header comment.
- The behavior of functions during an I/O error is clearly stated in the header comment.
- The behavior of functions when faced with a corrupt database file is clearly stated in the header comment.
- The behavior of the function during all other exception conditions (conditions other than OOM, I/O error, or corruption) is clearly stated.
Function bodies:
- The name of a function clearly reflects its purpose.
- Exception conditions do not cause memory or other resource leaks.
- Exception conditions leave the system in a consistent and well-defined state.
- The maximum size of a memory allocation is proportional to the the uncompressed database page size.
- Automatic variables are small, not large objects or arrays. Avoid excessive stack usage.
- The check-list items for functions also apply to major subsections within a function.
- Bounded recursion
- All code subblocks are enclosed in {...}.
- assert() macros are used as follows :
- Function preconditions are clearly stated and verified by asserts.
- Assumptions about which thread locks are held are explicitly stated and tested by asserts.
- Invariants are identified by asserts.
- testcase() macros are used as follows:
- Sufficient testcase() macros and/or code paths exist to verify that all OOM scenarios have been tested.
- Sufficient testcase() macros and/or code paths exist to verify that all I/O error scenarios have been tested.
- Sufficient testcase() macros and/or code paths exist to verify that all corrupt database file scenarios have been tested.
- Sufficient testcase() macros and/or code paths exist to verify that all exception conditions have been tested.
- Sufficient testcase() macros and/or code paths exist to verify that all boundary conditions have been tested.
- Testcase() macros exist to prove that all cases of a switch statement are tested.
- Testcase() macros exist to prove that all cases of bit-wise conditional are tested.
Class (struct) declarations:
- The purpose and use of every class (a.k.a. structure) is clearly defined in the header comment of its declaration.
- The purpose and use of every class member is clearly defined either in the header comment of the class declaration or when the member is declared or both.
- The names of class members clearly reflect their use.
- Members use the smallest practical datatype.
- Members are arranged within a class to make the class as small as practical.
- Every member of internal classes is constructively used. (In other words, we have removed class members that have fallen out of use.)
- Invariants for classes are clearly defined.
- Functions exist within #ifndef NDEBUG which test class invariants and these functions are called from within asserts at appropriate places.
Variables and class instances:
- The purpose and use of every variable is defined by a comment at the variable definition.
- The names of variables clearly reflect their use.
- Related variables have related names. (ex: aSavepoint and nSavepoint.)
- Variables have minimum practical scope.
- Automatic variables are small, not large objects or arrays.
- Constants are "const".
- Invariants on variables or groups of variables are defined and tested by asserts.
- Sufficient testcase() macros and/or code paths exist to verify that every variable is exercised through the full range of its possible values.
- When a variable that refers to the same value is used within multiple scopes, the same name is used in all cases.
- When variables refer to different values, different names are used even when the names are in different scopes.
- Variable names with wide scope are sufficiently distinctive to allow searching for them using grep.