Code Craft

Software is equal parts Art, Craft, and Engineering

Coding Conventions

Outline

Introduction

This article details my personal coding conventions for C-like syntax languages. Strict application of these conventions is expected of a junior level programmer, however, more senior team members should feel free to exercise judgement in applying the details to specific situations.

Objectives of This Document

The goal of these conventions is to produce code which is consistent in layout, style and naming. Because the conventions are intended to cover the broad range of free-format C-syntax languages, some particulars may not apply to certain languages; in general Java terminology is used, rather than attempt to refer to each languages individual term for an entity. But the general principles apply to all.

Why Have Coding Conventions?

Coding conventions are important for a number of reasons:

  • Good coding conventions promote good code with less defects.
  • About 80% of the lifetime cost of software goes to maintenance.
  • Most software is maintained by someone other than the original author.
  • Consistent code conventions improve the readability of the software, allowing engineers to understand new code more quickly and thoroughly.

Terms and Meanings

This document employs the following terms:

Term Meaning
Must The practice must be adhered to in all cases.
Should The practice should usually be adhered to, though cases exist where an alternative may be preferable.
May The practice described is an alternative to a practice that *should* normally be followed.

Previously Existing Code

When maintaining an existing program, the engineer should stylistically conform to what is already there for any given class, unless willing to reformat the class in its entirety. Note that for all methods, naming must conform to the standard employed for the rest of the program.

Source Code Organization back to top

File Organization

Source files must adhere to the following general layout:

  1. Header block
  2. Package declaration
  3. Imports/Includes
  4. Code (language specific requirements below)

Java source code section must adhere to the following layout:

  1. Instance Properties (public, then protected, then package, then private, with final then non-final within these).
  2. Constructors, Initializers, Open, Close, Finalizers
  3. Instance Methods
  4. Instance Classes
  5. Static Classes
  6. Static Properties (public, then protected, then package, then private, with final then non-final within these).
  7. Static Methods
  8. Entry Point and Versioning

C and C++ code section must adhere to the following layout:

  1. Constants (Including simple #define literals)
  2. Type Definitions
  3. Module Variables
  4. Macros
  5. Prototypes
  6. Functions

Engineers should try to group methods by their visibility: public, package, protected and private.

Note that the choice was made to place static methods at the end of the class because the majority of static methods are of utility nature, unrelated to a particular instance of the class. primarily the class defines an instance, that is, a collection of properties and the code that manipulates them - so these are placed first, being the focus of the class.

Header Block

The header block should follow the following format - shown is for Java/C. Other languages may require different
commenting semantics.

// -------------------------------------------------------------------------------------------------
// Copyright (c) 2008 xxx.
// Source and all derived objects/programs are provided under license.
// -------------------------------------------------------------------------------------------------
// Modified   : xx CCYYMMDD
// -------------------------------------------------------------------------------------------------

Code Section Separators

For top-level classes, a section separator must be used between the major sections listed above.

// *************************************************************************************************
// INSTANCE METHODS
// *************************************************************************************************

Code Block Separators

A code block separator should be used to separate logical blocks of code. A code block separator is a blank line, followed by a one line comment in mixed case.

some code;
some more code;

// Read object data
for(int xa=0; ch=readChar(inp), xa<OBJ_MAXLEN && ch!=OBJ_ENDCHR; xa++) { objData.addChar(ch); }

File Requirements

All engineers must ensure that tabs are converted to spaces for saved documents.

A Java source file must contain only one top-level class.

Nested Classes

A nested class can exist in two forms, a static nested class and an instance nested class (inner class). For general reference and in conversation, “Nested Class” refers to a static nested class, and “Inner Class” refers to an instance nested class.

In general, nested classes should be used instead of inner classes to prevent accidental access to the enclosing class’s variables and methods. That is, nested classes should be used to create a tightly related but independent object.

Inner classes should be used only when an API requires an object of a particular type for which you would normally pass the enclosing object, but for reasons of implemented interface or required sub-classing, cannot. Examples that may warrant an inner class would be GUI adapters or listeners.

General Visual Form

Generally speaking, every effort should be made to ensure the code presents in a clean visually pleasing manner. Make successive lines of like things align vertically. Make judicious use of blank lines so as to group code segments. Use consistent and regular indenting. Separate comments from code when on the same line. Make constants and their values align vertically. The code should visually mirror the logic flow.

Source Code Formatting back to top

Compound Statements

Compound statements (blocks) must be indented 4 spaces. The only exception to this is for Java classes - see the Declarations section.

Wrapping Lines

When the maximum line length is reached, statements are wrapped according to the following guidelines:

  • Wrapped lines are indented one (1) space.
  • Prefer higher level breaks to lower level breaks.
  • Break after a comma
  • Break before an operator

Higher level breaks are those that are closest to the top in terms of logical nesting. For example:

// given
if(a && b && (c || d || e)) {

// prefer wrapping at
if(a && b
 && (c || d || e)) {

// rather than
if(a && b && (c || d
 || e)) {

Indentation & Alignment

Consecutive strongly related lines should conform to the same vertical alignment.

The engineer must vertically align consecutive variable declarations such that their logical sections line up. The only exception to this is for variables declared at the beginning of a block; these may or may not be aligned at the engineer’s discretion.

When consecutive lines contain related conditionals, the engineer must align the conditions and opening/closing braces vertically. For example:

if     (inktyp==RED)   { ink=new Ink(RED);   }
else if(inktyp==GREEN) { ink=new Ink(GREEN); }
else if(inktyp==BLUE)  { ink=new Ink(BLUE);  }
else                   { ink=null;           }

switch(inktyp) {
    case RED   : { ink=new Ink(RED);   } break;
    case GREEN : { ink=new Ink(GREEN); } break;
    case BLUE  : { ink=new Ink(BLUE);  } break;
    default    : { ink=null;           } break;
    }

Consecutive variable declarations must have vertically aligned types, name and comments. Recommended indentations are:

  • Class/Instance Level: type=left margin, name=column 41, comment=101
  • Method: type=column 4, name=column 41, comment=column 101
  • Code Block: type=+4, name=as appropriate, comment=column 101

Blank Lines

Blank lines should be used to improve readability of code by separating logical sections. Multiple blank lines should not be used. White-space should be considered a precious commodity which is not overused; For example, do not insert a blank line every 3 or 4 lines of code.

A blank line must be used between variables and the following code for method level variables. A blank line should not be used between variables and following code for variables declared within blocks, however, a blank line may be used in this case when it is desirable to separate the following code as a logical unit.

A blank line must be used before beginning a new method (before its documentation). A blank line should not be used after a method declaration, nor before a method closing brace.

Blank lines must be used before and after code section separator comment blocks.

Spaces

Spaces should be used to improve clarity and readability, but not excessively.

Spaces must be used in the following circumstances:

  • Around logical operators in an expression.
  • Following a semicolon when multiple statements occur on one line (including in a “for” loop)
  • To separate the parameters in a method declaration

Spaces may be used in the following circumstances:

  • Around mathematical operators
  • Around the plus symbol (‘+’) when concatenating strings in Java
  • To separate parameters in a method call
  • To vertically align multiple assignments

Spaces must not be used in the following circumstances:

  • Between a cast and the variable (e.g. (int)varName)
  • Between an identifier or keyword and its opening parenthesis
  • Between a unary operator and its operand (!, ++, –, etc)

Comments

Comments should be used to provide additional information that is not readily apparent from reading the code itself. It is generally considered that over-documentation impairs an engineer’s ability to maintain code. Therefore, comments should be concise and to the point, and used somewhat conservatively. As much as possible care should be taken to write self-documenting code and one should not comment the obvious.

In general avoid writing comments that are likely to get out of date or irrelevant as the code evolves. Try to document why rather than what.

Java-doc style comments are required for all public and protected methods, except accessor methods, and for all variables. JavaDoc is encouraged for package and private methods.

Comments used as code block separators must be mixed case, preceded by a blank line (to help them stand out clearly from the code) and must use the // commenting style.

Comments on consecutive lines, placed to the right of code, should be vertically aligned and must use //.

Refer to declarations for rules on commenting variable declarations.

Discussion of non-trivial design decisions is sometimes appropriate and such comments should always form a multi-line block preceding the relevant code, in mixed case using the /* .. */ commenting style. Where possible, such discussions should immediately follow the method declaration. For example

static public short generateHash(char[] data) {
    /*
     * Generate a hash using multiple reciprocal inversion technique.  This
     * technique is employed because it operates considerably faster than
     * more conventional algorithms; but it does not result in a good distribution
     * for binary data.  It is appropriate in this context because the data
     * is always character based.
     */
    int                                 len=data.length;
    ...
    }

Commenting out sections of code must be done with // at the same indentation level as the code, with no following space. It is strongly recommended that commented code is left in the source only until the changes are verified - leaving commented code permanently in sources files will, over time, clutter them and greatly reduce the readability of the source. For example:

static short hsmvar_idxmax(HMHSSNINF *hss, byte *lkpnam) {
    long                                loop;                               // variable loop counter
    HSMVAR1                             *var;                               // HSM variable structure
    short                               ndxmax;                             // maximum index of variable

    if(!lkpnam) { return 0; }                                               // so we can call easily skip the
    if(lkpnam[0]==ASCBYT_varpfx) { lkpnam++; }                              // variable prefix, if it exists

    ndxmax=0;
    loop=LOOP_HSMVAR;
    for(var=hsmvar_first(&hss->hsmvarcon); var!=NULL; var=hsmvar_next(var)) {
        loop--;
        //if(loop<0) { die_hsmsys(hss,"hsmvar ndxmax looped"); }  (NB changed for port from QNX)
        if(loop<0) { return 0; }
        if(mStrEqu(var->nam,lkpnam) && var->ndx>ndxmax!=0) { ndxmax=var->ndx; }
        }
    return ndxmax;
    }

Comments - Marking Statements

Debugging: When adding statements to debug a problem said statements must be marked with an empty comment (/**/), usually in the left margin. This allows for fast and accurate location of added code for removal when the problem is resolved. Such lines should not be left in the source code when work is complete.

Bad code: Code that works but is of questionable quality or needs improvement must be marked with a trailing comment of:

//CHGME: <descriptive text>

Broken code: Code that is known to be broken must be marked with:

//FIXME: <descriptive text>

Naming

General

No variable name may be less that 2 characters (for simple loop iterator variables follow the convention xa…xz, for others, use 2 or more characters as appropriate, e.g. ca for a char array, s1 for a string, tos for temporary output stream, scbobj for SCB object, etc).

For full words and mnemonic variables, the word may be pluralized to indicate an array, list, or other multiplicity as appropriate, e.g., nams might refer to an array of names. This device should not be used with acronyms, e.g. nams should not be used to refer to an array of “names and mixtures”.

Entity Convention
Package name The prefix is always all lower case, leading with a domain-name controlled by the owner of the code, per normal Java convention. Subsequent components are determined according to internal allocations.
Class/interface name Full words, mixed case with the first letter of each word leading uppercase, no underscores. Class names should be simple and descriptive and describe what the class is — think "noun". Avoid abbreviations unless the abbreviation is more widely used than the long form, or the long form is simply too verbose.
Constant Uppercase, abbreviations or words, underscore divider between words, group by using 2 or 3 character lead + underscore.
Method/function name Full words, mixed case with the first letter lowercase and each subsequent word leading uppercase, no underscores. Must accurately and succinctly describe what the function does -- think "verb".
Class/module variable Full words, mixed case with the first letter lowercase and each subsequent word leading uppercase, no underscores allowed.
Method/function variable Lowercase abbreviations, underscore divider between short words (1 or 2 characters). This includes parameters to methods/functions.
C Preprocessor Macro Full words, mixed case with leading lowercase 'm'.
C Type Uppercase, abbreviations or words, underscore divider between words, group by using 2 or 3 character lead + underscore.

Abbreviations

Abbreviations must be mnemonic or acronymic. For mnemonic name, each word represented should be exactly 3 characters, except at the end of an abbreviation where the last word may be represented by 1 or more characters. If an abbreviation follows a full word (because the word is 1 or 2 characters, e.g. “no”) then an underscore must be used. If a word follows an abbreviation and is at the end of the name, no underscore is required. The general form for mnemonic abbreviating is to drop vowels and to use consonant to represent syllables. Where this is not appropriate or looks obscure, simply use the first 3 letters of the word.

Keeping abbreviations uniform in this manner makes it easier for the next engineer to quickly understand the variable name. Does “notack” represent “no tack” or “not ack (acknowledged)”?

Declarations back to top

Variables

One declaration per line should be used, to aid in commenting. An engineer may group strongly related declarations on a single line (such as index variables, counters, etc.) - these should be such that one concise comment adequately describes them all.

For classes and methods, the name of the variable must be vertically aligned with other variables declared at the same scope and this must be at least 4 tab-stops (16 characters) from the beginning of the type. Comments should be present for all variables, and vertically aligned. Comments must be present for all variables containing an abbreviation, no matter how obvious the abbreviation may seem. These comments should include the full words in the same order, if possible. Refer to Source Code Formatting for recommended indentations.

For code blocks within methods, the engineer has complete discretion, and may align and add comments, or not, as appropriate. It is generally expected that such variables will be very self explanatory, and due to their limited scope, alignment and comment should normally be unnecessary.

Declarations must only be placed at the beginning of a method or block or in the initializer of a ‘for’ statement. In rare instances it is valuable to strictly limit the scope of variables within a method. In such a case an engineer may use an artificial construct to create a sub-block within the method. Examples:

someMethod() {
    int                                 xa,xb,xc;                           // loop counters

    ...
    if(true) {
        int wt,wl,wr,wb;
        ...
        }
    ...
    }

Declarations must not hide a variable already declared at an outer scope.

For method level variables a blank line must follow the variable declarations.

Variables must be at least 2 characters long. Single character variables are never permitted.

Variables at the class level (instance or static) should not be indented relative to their containing class. In all other cases they should be indented relative to their containing block. Note that for inner classes the entire class is indented and so the variables for that class are indented to the same level as their class declaration. If present, a static modifier must be placed first in a declaration, before its scope modifier (public, protected, private). If present, a final modifier must be placed *after * the scope modifier and before the type. For example: static private final String, not final static private String.

Array brackets must follow the type, not the variable name.

Examples:

// good Variable Declarations
SomeClass                               aClass;                             // the widget manager
long                                    width,height;                       // the width & height of the window
int                                     xa,xb,xc;                           // simple index variables
char[]                                  chrarr;                             // field value array

// Bad Variable Declarations
SomeClass aClass; // the widget manager
long width; // the width of the window
long height; // the height of the window
int xa,xb,xc; // simple index variables

// More Bad Variable Declarations
char                                    chrarr[];                           // [] is with name not type
int                                     lvl,siz,val;                        // multiple unrelated fields

Constants

Non-private constant values in Java should use the final modifier; NOTE: Using final causes the Java compiler to inline the value as a literal and remove the reference to the class (and is required to do so by the Java specification). This effectively locks in the value of a constant after publication, sometimes defeating the value of providing an abstract label for the value. However, using non-final variables allows the value to be changed at any time, by any class. In the balance, it is rare that a non-final non-private variable is required, and such cases should use a “getter” to enforce read-only protection.

With respect to these conventions, simple #define statements in C are considered to be constants, not macros.

Layout of constant declarations must follow that of variables.

Constants should be declared unindented relative to their containing class. If present, a static modifier should always be placed first in a declaration, before its visibility (public, protected, private).

Variable Initialization

Determining whether to initialize a variable at its declaration or explicitly in code is more art than science. In general this decision is left to the individual engineer’s judgment. The following guidelines apply:

  • Initializers for class should be simple assignments
  • Initializers for method scope variables should not be object construction or array allocation
  • Initializers for block scope variables have no restrictions
  • A notable exception to the no object construction rule is the use of a simple "new Object()" to assign a synchronization object.

Variable Scope

With one exception, no properties of a class may be public - instead “accessor methods” should be used to get and set values of properties.

The exception to the non-public declaration of class properties is the specialized use of a Java class to represent a data structure. Such classes should be named such that they end with “Vars”, and may contain public properties with the class itself as limited in scope as possible. A data-structure class should have no methods except a constructor. Normally this class would be a nested or inner class of the class that uses it. For example:

private class SessionVars
    extends Object
    {
    int                                 number;                             // session number
    String                              deviceName;                         // device name for this session
    String                              owner;                              // user number of session owner as zero padded string

    SessionVars() { super(); }                                              // prevents the compiler creating a dummy "accessor" class
    }

Class, Interface and Method Declaration

A class is declared with all elements on a separate line, including the opening and closing braces (‘{’ and ‘}’); code within the class itself is not indented. For example:

public class MyClass
extends Object
implements Runnable, MyInterface
{
...
public MyClass(String name) {
    super();
    }
...
}

Inner classes and all declarations within them are indented one level, relative to the containing class

Methods should not be indented relative to their containing class.

If present, a static modifier must always be placed first in a declaration, before its visibility (public, protected, private).

Methods which are not accessor methods should have the code within them on separate lines. Accessor Methods are methods that exist solely to get and set class properties. Unlike normal methods, accessor methods may be declared on a single line in the prescribed section. For example:

int getWidth()              { return width;   }
void setWidth(int newWidth) { width=newWidth; }

With the exception of groups of accessor methods, methods must be preceded by a blank line.

Inline Class Definitions

Class definitions which are inline to a method invocation (which are common in Java2 sample code) should be avoided - these are typically used for UI listeners, security actions, etc.

The following example of what to avoid was taken from standard Java example code:

someMethod() {
    ...
    someObject.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            // event handling goes here, eg
            someHandlerLogic(evt);
            }
        });
    ...
    }

The preceding code is difficult to follow, especially if the method call has more parameters than the one on-the-fly class. A separate local variable (defined inline, if appropriate, at method start) is much clearer and only one line longer:

someMethod() {
    ...
    ActionListener al=new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            // event handling goes here, eg
            someHandlerLogic(evt);
            }
        };

    someObject.addActionListener(al);
    ...
    }

Statements back to top

Simple Statements

Each line should contain only a single statement. An engineer may decide to group a few closely related statements on a single line.

// this is fine; the assignment and the increment are integrally related
parm=argv[xx]; xx++;

// this is pushing it - too much on one line
parm=argv[xx]; xx++; translate(parm,strlen(parm),ascebctbl); parm=parm.toLowerCase();

Compound Statements

Indentation occurs whenever a compound statement (block) is present. The opening brace (‘{’) for a block must occur immediately following the statement or expression to which it belongs. Statements within a block should occur indented on following lines, and when they do the closing brace (‘}’) must occur on a line by itself indented to the same level as the compound statements (an engineer may elect to put the entire block on a single line with the statement to which it belongs, provided the block is simple and fits entirely on one line). The reason for this is so that the visual outline of the code mirrors the actual logic – that is, one can “see” the program logic instinctively.

More than one opening or closing brace should not occur on a single line; a notable exception is that when writing Java code an engineer may put very simply try/catch code on a single line.

// allowed
try { obj.wait(); } catch(InterruptedException thr) { throw new RuntimeException("Interrupted"); }

// only rarely do this
if(condition) { ... } else { ... }

// almost never do this
void someMethod() { if(condition) { ... } }

In all cases where a compound statement is allowed, braces must be used. In the event of valid loop condition with an empty body, the trigraph “{;}” must be used to denote the empty body. Examples:

if(condition) { ... }
else          { ... }

if(condition) {
    ....
    }
else {
    ...
    }

for(int len=myString.length(); len>0 && myString.charAt(len-1)==' '; len--) {;}

switch(val) {
    case 0  : { valStr="Zero";    } break;
    ...
    case 9  : { valStr="Nine";    } break;
    default : { valStr="Invalid"; } break;
    }

Never code any of the following:

if(condition) statement;

for(int len=myString.length(); len>0 && myString.charAt(len-1)==' '; len--);

switch(val) {
    case 0  : valStr="Zero";    break;
    ...
    case 9  : valStr="Nine";    break;
    default : valStr="Invalid"; break;
    }

Conditional Statements - ‘if’

The if, if - else and if else if statements must conform to one of the following forms.

if(condition) { ... }
else          { ... }

if     (condition) { ... }
else if(condition) { ... }
else               { ... }

if(condition) {
    ...
    }
else if(condition) {
    ...
    }
else {
    ...
    }

Conditional Statements - ‘switch’

A switch statement must conform to one of the following forms (use a line between cases for complex switches so that variable declarations do not cause an incorrect visual break). Note that the default must be placed at the end of the switch.

switch(condition) {
    case VAL1: { statements; } break;
    case VAL2: { statements; } break;
    case VAL3: { statements; } return;
    default:   { statements; } break;
    }

switch(condition) {
    case VAL1: {
        *statements; *
        } break;
    case VAL2:
    case VAL3: {
        statements;
        } break;
    case VAL4: {
        *statements; *
        } // FALLS THROUGH
    case VAL5: {
        *statements; *
        } break;
    case VAL6: {
        boolean aVar;
        *statements; *
        return aVar;
        } // RETURNED
    default: {
        *statements;*
        } break;
    }

switch(condition) {
    case VAL1: {
        *statements; *
        } break;

    case VAL2: {
        *statements; *
        } // FALLS THROUGH

    case VAL3: {
        boolean         aVar;
        boolean         anotherVar;

        *statements; *
        return aVar;
        } // RETURNED

    default: {
        *statements;*
        } break;
    }

The default clause must always be present and must always end with a break. This latter requirement helps to eliminate problems where a default is changed to a specific value and a new default added.

Note the use of braces in the switch cases; this is for visual consistency and to allow the declaration of variables that are scoped to the case. The latter is a valuable ability, and the use of the brace also provides visual consistency with indenting.

Every case that does not have a break or return after the closing brace must end with the a FALLS THROUGH, RETURNED or THROWS comment. The “returned” comment is used in the event that what is returned is a variable scoped within the switch’s case and not available outside the closing brace.

Each case after the first may be preceded by a blank line if this increases the readability. Generally, switches with extensive coding in some or all cases will employ a blank line, and simple switches will not. But if any case has a blank line for a given switch, they all must have one, except any cases which fall through.

Conditional Statements - ‘Ternary’

A ternary expression should be a simple conditional, and ternary expressions should not be nested. Ternary expressions can be chained, as opposed to nested, to form a switch-like series of tests. The condition must be bracketed, and the individual parts may be bracketed as appropriate.

val=(condition) ? trueValue : falseValue;                                   // good
val=(condition) ? (complexTrueValue) : (complexFalseValue);                 // good
val=(condition1) ? val1 : (condition2) ? val2 : (condition3) ? val3 : val4; // okay (chained)
val=(condition1) ? (condition2) ? val1 : val2 : (condition3) ? val3 : val4; // bad (nested)

The following layout styles for more complex chaining are also permitted. The first is a pure expression, often useful in functional and semi-functional languages like Javascript. Note the encapsulation of the entire expression with parentheses.

( (foo==bar)
?   result1
: (foo==baz)
?   result2
: (foo==upQuark || foo==downQuark)
?   result3
: (foo==muon || foo==gluon)
?   result4
:   final_result)

result=(
    foo.equals(bar ) ? result1     :
    foo.equals(baz ) ? result2     :
    foo.equals(quak) ? result3     :
    foo.equals(quik) ? result4     :
                       final_result);

log.println("[DB] Error while doing something, code "+result+", description "+(
    result==1 ? "File not found"               :
    result==2 ? "File is read-only"            :
    result==3 ? "File write permission denied" :
                "File access denied"));

Loop Statements - For

A for statement must conform to one of the following forms:

for(init; condition; update) {;}

for(init; condition; update) { ... }

for(init; condition; update) {
    ...
    }

An engineer should avoid more than 3 initializers and updates in a for statement. Also, overly complex initializers, conditions and updates should be avoided.

Loop Statements - While

A while statement must conform to one of the following forms:

while(condition) {;}

while(condition) { ... }

while(condition) {
    ...
    }

while(pre-update, condition) {;}

while(pre-update, condition) { ... }

while(pre-update, condition) {
    ...
    }

// specifically avoid this:
while(((val=someExpression))==compValue || val==anotherValue) { ... }

// use this instead:
while((val=someExpression), val==compValue || val==anotherValue) { ... }

Loop Statements - Do/While

A do/while statement must conform to one of the following forms:

do { ... } while(condition);

do {
    ...
    } while(condition);

Try/Catch/Finally Statements

A try/catch/finally statement must conform to one of the following forms:

try { ... } catch(Exception thr) { ... }

try                  { ... }
catch(Exception thr) { ... }
finally              { ... }

try {
    ...
    }
catch(Exception thr) {
    ...
    }
finally {
    ...
    }

Return Statements

A return statement with a value should not use parentheses, unless the return is an expression. When parentheses are used they should be separated from the return keyword by a single space

return true;                                                                // good
return myMethod();                                                          // good
return (someVar*2);                                                         // good
return (condition ? 10 : 0);                                                // good

return (true);                                                              // bad
return(someVar*2);                                                          // bad
return (myMethod());                                                        // bad
return someVar*2;                                                           // bad
return condition ? 10 : 0;                                                  // bad

General Programming Practices back to top

Java Classes And Constructors

Java classes must explicitly declare the class they extend, even if they simply extend Object. All Java classes must include at least one constructor even if all it does is invoke the super constructor. All constructors must explicitly invoke their super constructor.

C Prototypes

C and C++ prototypes must always be used.

Self Documenting Code

Great pains should be taken to construct self-documenting code as much as possible with clear and accurate variable, method and class names. Special care should be exercised in selecting meaningful class and method names, leaning towards verbose, but generally without exceeding about 20 characters.

Variable Assignments

Engineers should not assign several variables to the same value in a single statement - it is hard to read. For example:

someValue=someOtherValue=aThirdValue=10;                                    // avoid

someValue=10;  someOtherValue=10;  aThirdValue=10;                          // multiple assignments preferred

Engineers must not use an assignment operator in a conditional such that it may be confused with the equality operator. For example:

if(someValue=someOtherValue) { ... }                                        // never do

if((someValue=someOtherValue)!=true) { ... }                                // ok

Engineers must not use multiple embedded assignments. Let the compiler handler the complex optimizations. For example:

val1=(val2=val3+val4)+val5;                                                 // Never acceptable

// the above should be written as
val2=val3+val4;
val1=val2+val5;

Parentheses

Parentheses should be used liberally whenever there are mixed operators to clearly indicate expected precedence. Though the operator precedence may be clear to you it may not be to others. But having said that, using parentheses around equality operator expressions is unnecessary clutter, and redundant due to use of white-space (see below for an example). For example:

if(a==b && c==d || e==f) { ... }                                            // no

if((a==b && c==d) || e==f) { ... }                                          // good

val=(aSimpleExpression ? 1 : 2);                                            // good

val=((aComplexExpression) ? 1 : 2);                                         // also good
if(((a==b) && (c==d)) || (e==f)) { ... }                                    // unnecessary

Parentheses should also be used around Java string concatenations. For example:

someMethod(10,"The message is "+msg+" and the code is "+code,true);         // bad

someMethod(10,("The message is "+msg+" and the code is "+code),true);       // good

Casting

Casts must never be followed by a blank space. And when an expression is cast, the entire expression must be surrounded by brackets. For example:

val=(int)longValue;                                                         // good
val=(int)(longValue/2);                                                     // good

val=(int) longValue;                                                        // bad
val=(int)longValue/2;                                                       // bad

The Big-Picture Summary back to top

The 10 over-arching principles to bear in mind while coding are:

  1. Organize source files into high-level blocks of related code with comment-block separators; this is especially important in Java for separating static and non-static code.
  2. Use whitespace to form a visual outline of the code structure. Among other things this means that the position of compound-statement delimiters, such as braces, should enhance the visual structure, not diminish it.
  3. Use indentation and alignment to form columnar blocks where-ever this effectively and usefully highlights the similarity/differences between related consecutive lines of code.
  4. Use a single blank line to break consecutive lines of code into conceptual “chunks”. But don’t overdo it. Use a comment title to describe the chunk when that seems useful.
  5. Use naming conventions to differentiate things of fundamentally different scope. Shorter names for localized scope, longer names for broader scope. When abbreviating use a rigorous grouping of 3’s convention.
  6. Use meaningful names; work hard on names to make them as accurate and informative as possible.
  7. Limit identifier scope as much as possible within the capabilities of the language.
  8. Use the language’s start/end delimiters whenever statements are associated with a loop or conditional construct.
  9. One statement per line, unless several statements are very tightly related.
  10. Wrap lines appropriately for the general viewport size for developers in your team or organization, not at some theoretical industry-wide lowest-common-denominator.