Physics Logo

CET 375: Data Structures & Algorithms
Professor: Ricky J. Sethi Instructor Info

Sethi Family HomePage » Classes » Cet375 » Daily Lecture Notes » Programming Style Sheet


Programming Style Sheet


Source Code Documentation & Naming
  1. Opening Documentation: the header block should include the following:
    • Program name/syntax
    • Description of what the program does
    • Summary of the problem's specifications and assumptions
    • License info (optional)
    • References to sources of additional information used
    • Parameters
    • Class/Program Invariant (ensure these conditions are true)
    • Algorithm(s) used (including any special notes)
    • Output (any print statements, files created, etc.)
    • Return values (does it return any parameters?)
    • Name of the authors (plus contact info)
    • Creation & modification dates
    • To Do Items (optional)
    Sample:
    /*********************************************************************
    * 
    * PROGRAM:      foobar
    * SYNTAX:       foobar <param_1>
    * DESCRIPTION:  This program does foobar on param_1
    * 
    * LICENSE:      ---OPTIONAL---
    *               ****************************************************
    *               GPL & Postcard-Ware!  This program is distributed
    *               under the standard GPL and is freely useable or
    *               distributable as long as this license is attached.
    *               ****************************************************
    * 
    * SPECS:        Program's specifications and assumptions here
    * REFERENCES:   Original idea based on emacs
    * PARAMETERS:   Uses following parameters:
    *                - <param_1>: integer, used to determine iterations
    * ALGORITHM:    Pseudocode describing the algorithm here
    * INVARIANT:    Class or program invariants (verify state of class) here
    * OUTPUT:       foobar automagickally creates:
    *                - data.txt (contains guest data)
    *                - log.html (entries' log file)
    *                - Prints diagnostic messages to STDOUT
    * RETURN:       Returns return_int code to indicate successful conclusion
    * 
    * AUTHOR(S):
    *               Ricky J. Sethi (rickys@sethi.org)
    *               http://www.sethi.org/
    * MODIFICATIONS:
    *               Created by Ricky J. Sethi on 2003-03-07
    *               Modified by Ricky J. Sethi on 2003-03-08
    *               Modified by John Q. Public on 2003-03-11
    * TODO:         ---OPTIONAL---
    *               * Add new icons
    * 
    *********************************************************************/
    	
  2. Each subprogram should contain all of the following:
    • Function name/syntax
    • Description of what the function does
    • References to sources of additional information used
    • Precondition: the state of the object before this fxn is called
    • Receive: implicit and explicit parameters
    • Return: implicit and explicit returns
    • Output: anything it might print out or display
    • Postcondition: the state of the object after this fxn is called
    Sample:
    /*********************************************************************
    * 
    * FUNCTION:      foobar(<param_1>)
    * DESCRIPTION:   foobar() does foobar on param_1
    * REFERENCES:    Original idea based on emacs
    * PRECONDITION:  A stack has been defined
    * RECEIVE:       Uses the following EXPLICIT parameters:
    *                  - <param_1>: integer, used to determine iterations
    *                Uses the following IMPLICIT parameters:
    *                  - the stack itself
    * RETURN:        foobar() EXPLICITLY returns:
    *                  - return_int, a reference to an int 
    *                foobar() IMPLICITLY returns:
    *                  - the modified stack
    * OUTPUT:        Prints a "FULL STACK" message if no space available
    * POSTCONDITION: The new element has been added to the stack
    * 
    *********************************************************************/
    	
  3. Comments should be used to explain key code segments and/or segments whose purpose or design is not obvious. Use comments liberally to explain non-trivial code. When possible, align comments to the right of the code segment as in the following sample (such code can be read without comments by looking only at the left side of the page):
    
    static int j = 0;
    if (j++ == 0)                     // Guard against cerr allocating memory
        cerr << "Out of memory\n";    // Tell the user
    abort();                          // Give up now...
        
  4. All methods and data members in a class declaration are required to be prefaced with single line comments describing the purpose of the member. For example:
    
    class CVXFoo {
    ...
    // registers the foo factory interface
    void RegisterFactory(CFooFactoryInf* pFact);
    ...
    // factory interface used to allocate new foos
    CFooFactoryInf * m_pcffiFooFactoryPointerMember;
    };
        
  5. Use formatting comments to separate functions and related sections of the code (see Class Member Organization).
  6. All functional code must be clearly commented to indicate exactly what the code is doing. Any numerical calculations should have descriptive comments stating the purpose of the calculations
  7. In general, there should be sufficient documentation to understand the method logic without having to read the executable code.
  8. Separating Source Members: Class declarations and definitions/implementations should be contained in separate files. All source members should assume the follow the naming convention:
    • <descriptor>.h
    • <descriptor>.cpp
    • <descriptor>.c
    where the <descriptor> does not contain spaces or strange characters (use the underscore character ("_") to separate words) and the first word should always start with a lowercase letter.
Appearance of code
  1. Put each statement on a separate line.
  2. Class Member Organization: The "interface" of the class should be given last. That means the data member declarations should be made first followed by class method declarations. Generally, methods and data members should be organized by security in the order of private, protected, and public.
    
    class CFoo : public CFooBase {
       // attributes
       //-------------------------------
       private :
       protected :
       public :
    
       // methods
       //-------------------------------
       private :
       protected :
       public :
    };
    
  3. Put each { and } on separate lines and align the corresponding braces.
  4. Indent the statements enclosed by { and }.
  5. When a statement is continued from one lie to another, indent the continued line(s). Align the identifiers in each constant and variable definition, placing each on a separate line. For example:
    
    const double TAX_RATE      = 0.33,
                 INTEREST_RATE = 0.195;
    int employeeNumber;
    double hours,
           rate,
           wages;
    
  6. Use blank lines and spaces liberally between declarations and statements and also between blocks of statements to make the program structure clear.
  7. Label all output produced by a program. For example:
    
    cout << "Employee # " << employeeNumber
         << " Wages = $ " << employeeWages;
    
    Instead of this:
    
    cout << employeeNumber << " " << employeeWages;
    
Naming & syntactical guidelines
  1. Put identifiers for constants in uppercase, separating words by underscores ("_"), as in
    const int TAX_RATE = 33;
  2. Put identifiers for variables in lowercase, capitalizing the first letter of each subsequent word or separate the words with underscores ("_"). For example, either
    int totalHoursWorked;
    or
    int total_hours_worked;
  3. Method/Member Function Naming: Put identifiers for types and functions in lowercase, but capitalizing the first letter of each word after the first one. Special characters such as dashes and underscores are prohibited. The method name chosen should be descriptive of the method functionality. For example:
    displayInfo()
  4. Class Naming: All class names should begin with "C" and all words should begin with a capital letter. The class name should be descriptive of the class intention(s). For example:
    class CFooBar : public CFooBarBase
  5. Data Member Naming: Use meaningful identifies (e.g., "wages = hoursWorked * hourlyRate;" instead of "w=h*r;"). Don't use "skimpy" abbreviations just to save a few keystrokes when entering the source code. All data members should assume the following format:
    [m_]<type><identifier>
    where [m_] indicates class member data, <type> is a data type prefix and <identifier> describes what the data represents. The identifier should always begin with a capital letter. The conventions for data type descriptors include:

    short int       i
    long int l
    float f
    double d
    bool b
    CString str
    char c
    char* sz
    pointer p
    enum e
    CSomeClass c<first_letters_of_each_word>

    Examples:

    unsigned short      m_iMaxRetries;
    long m_lNumberOfRows;
    float m_fPercentComplete;
    double m_dCountResult;
    bool m_bCacheItemsYN;
    CString m_strName;
    char m_cSwitchType
    char * m_szLogBuffer;
    int * m_piState;
    eObjectType m_eFirstObjectType
    CSomeClass m_cscObjectOfSomeClass

Declaration file guidelines
  1. Include Guards: All class definition and interface source members must have a preprocessor include guard to prevent compilation errors due to accidental multiple includes. The include guard should come just before the Comment Header. The scope should include all the entire contents of the. The #endif directive should be the last line in the module. Example:
    
    #ifndef _FOOBAR_H
    #define _FOOBAR_H
       . . .
       some source code
       . . .
    #endif  // _FOOBAR_H
        
  2. Header Includes: Class header files should include only headers that are required for the class definition. Headers should not be included as a convenience or "shortcut" to automatically include resources for other source members. Headers should only be included for the following reasons: to provide class definition of super class(es) or to provide class definitions for other classes referred to in data members and methods.
  3. Inline Methods: Inline methods should only be used under unique circumstances. These are typically used for operations that are called frequently and would otherwise present performance issues. Inline methods in general should be avoided because they will introduce build dependencies when the behavior of the inline method is changed.
Good programming habits/guidelines
  1. All method parameters should include an argument name following the type. This helps to identify the purpose of the parameters. It is helpful to identify the directional usage of parameters with "in" and "out" name qualifiers. If possible, "in" parameters should be passed as a const reference (or pass-by-value) to prevent accidental data changes. All class instances should be passed as references (&) where possible. Examples:
    
    BOOL CopyTables( const CPList& inTables, CPList& outTables);
    
    BOOL CopyMoreTables( /*in*/  const CPList& curTables,
                         /*out*/ CPList& newTables);
    
  2. Variables and Parameters: All local and global variables should always be initialized when declared. All variables and parameters should have a meaningful name and must begin with a type prefix (see Data Member Naming). Examples:
    
    BOOL      bForceYN   = FALSE;
    CString   strName    = "John";
    ObjectId  lObjectID  = NEW_ID;
    
  3. Arithmetic: All arithmetic code should include validations for numerical exceptions. This includes trapping the following conditions:
    • Divide by zero
    • Data type overflow
    • Boundary conditions
  4. Memory Management: If at all possible, try to avoid heap memory allocation for data members. Whenever temporary memory is required for the scope of some function, use stack allocated memory rather than heap allocated. This will ensure reliable cleanup upon exiting the scope of the function (even when exceptions are thrown). And, it's less code to manage. Example:
    
    //heap allocated aproach is risky
    CFoo * pcfObj = new CFoo();
    pObj->SomeMethod( pcfObj );
    delete pcfObj;
    
    //stack allocation approach is safer
    CFoo cfObj;
    pObj->SomeMethod( &cfObj );
    
  5. Use a modular approach for a complex problem. Don't write one giant subroutine.
  6. Use the basic control structures when developing each code segment. Any program unit can be written using only the sequential, selection, and repetition structures.
  7. Use local variables within subprograms. Declare variables near their first use (not in C programs, though). Declare the constants, on the other hand, at the beginning of a function.
  8. Avoid using global variables to share information between subprograms. Instead, use parameters to pass information.
  9. Use constants instead of "magic numbers". I.e., use BIRTH_RATE instead of the actual number 38573.
  10. Identify any pre-conditions and post-conditions a program or sub-program has and check them. The assert() mechanism should be used to check pre- and post-conditions.
  11. Strive for simplicity and clarity! Clever programming tricks intended only to demonstrate the programmer's ingenuity or to produce code that executes only marginally more efficiently should be avoided.
Helpful Programming Techniques
  1. Manual Debugging Techniques: when using the following debugging techniques, take care to put such temporary output statements in places that are helpful in locating the source of the error and not use so many of these statements that the volume of output hinders the search for the error.
    • Use a dbg() function to display error codes:
      	void dbg(String msg) {
      	   cout << msg << endl; 
      	}
      	
      The advantage to using a debug() function to announce errors is that once you're done debugging, you can simply comment out the cout statement without having to hunt down each instance of error statements.
    • For more localized debugging, use a global variable $DEBUG which you can then implement with a simple if statement:
      	if ($DEBUG) {
      	   cout << msg << endl; 
      	}
      	
    • Commenting out regions of code: often, you run into the problem of commenting out huge blocks of code that already contain comments. How can you comment out regions of code with nested comments (especially if you use C-style comments)? Just enclose it in an if statement; for example:
      	if (false) {
      	   /* Other code comments */
      	   . . . 
      	}
      	
  2. Use a stub function statement in each method or subroutine to announce itself and also to include pseudocode in comments describing what that method will do. For the announcing, use the dbg() function you used above. A sample stub would be:
        int ComputeInterestPaid(int iRate) {
           dbg("ComputeInterestPaid("+ iRate +")");
           /* ComputeInterestPaid does this:
              1. Get the (global variable) principal
              2. Get the interest_rate
              3. Compute Interest Paid
           */
        }
        
  3. Use templates (with sections for constructors, accessors, mutators, etc.) (examples to come)
Course Notes & Guidelines: All lower case!
  1. Program submission naming guidelines/protocol:
    project<project_no>_group<group_no>_<type_of_file>.<file_extension>

    So, for example, if Group 1 was submitting their first project, they'd submit it as follows:

    project01_group01_specs.txt
    project01_group01_flowchart.gif
    project01_group01_header1.h
    project01_group01_program1.cpp

    Please Note: Text files should be plain text files; i.e., if you use MS Word to create your specifications file, choose "Save As" and then choose "Plain Text". An alternative is to use Notepad (shudder!) or download a copy of Emacs for Windows or Linux from http://www.gnu.org/software/emacs/windows/faq2.html#where-precompiled and use that (recommended). Also, the Flowchart files should be submitted in GIF or JPG formats.

  2. Program submission emailing guidelines/protocol; email address:
    cet375_submissions@sethi.org

  3. Program submission emailing guidelines/protocol; email subject:
    <assignment-name>_<last-name>_<first-name>
    So, for example, if I was submitting my first project, I'd submit it as follows:
    project01_sethi_ricky
Misc Links/Notes
  1. Course Tutorials & Links:
  2. Unix Tutorials & Links:
  3. Links to coding standards & styles:
  4. Guide to writing/compiling Visual C++ programs:
  5. Misc Programming Links: