[Topic] Coding Standards and Style

I've recently witnessed a bit of strife in a development team I work with. The conflict orginated when source code was being arbitrarily reformatted to suit a particular developer's preferred formatting style—which was quite extreme and involved automatically reordering methods and variables within calsses, as well as a host of other formatting details. The changes were resulting in merge conflicts that were extremely tedious and time-consuming to deal with. Tension was building in the team due to the uninvited and unwarranted changes to stable code. Eventually, the situation came to the point that team members were angry the issue needed to be resolved. The team's coding style and practices needed to be collectively decided and agreed upon.

In the course of resolving these problems, I took the opportunity to outline a number of code style points, and my approach to them. I provide them here for those who are interested. It is written as though it were a published style guide for a team.

Preface

Programming style is a matter of personal preference and what constitutes good style is a subjective judgement. Progamming style rules can range from the appearance of code (formatting), to naming conventions, to higher-level constructs. When followed, style guidelines can impact readability, maintainability, and general quality of the code—for better or worse depending one's subjective point of view.

What I consider most important is that everyone on a programming team accepts whatever style rules are defined. If there are significant disagreements about particular style rules and the members of the team cannot come to an agreement, then those rules probably should not be rules. In the absense of strict rules, the individual programmer's preference should be respected. It is presumed that team members sharing a common goal will be able to come to a general consensus about which style guidelines are most important. If the details of code formatting are enough to cause a significant rift among team members, I would be concerned about how well that team will be able to work together.

I believe development processes play a big roll in the quality of what is produced, but processes will not be discussed here.

So, with that, I will present my coding standards. My purpose is not to justify any particular standard, but simply layout the rules I think are most important. I'll also discuss other guidelines that may be useful (but are not rules).

Summary

This article is pretty long, so I will summarize everything really quickly right here:

Rules

These style rules deal specifically with Java code, and a few conventions are Java specific, but most can be applied to many languages.

  1. Use CamelCase naming for classes, methods, and variables.
  2. Declare constants in ALL_CAPS.
  3. Establish and follow a brace positioning rule that the team agrees on—vote if necessary.
  4. Establish and follow a tab/spaces indentation rule that the team agrees on—again, vote if necessary.
  5. Use consistent indentation.

Strive for Quality

Work as a team to share knowledge and establish best practices. Work within an established system architecture. Respect each other's differences of style. Attempt adhere to the style of code found in different source files when making small changes. Learn from the experience of others. Work together.

Beyond that, try write code that is readable, testable, and maintainable.

Guidelines

Code standards are intended to guide programmers to produce good quality results. Striving for quality is the real objective. The quality of the results is more indicative of the quality of the programmers than the quality of the published style guide. A few high level objectives relating to writing source code can help direct programmers to achieve quality.

Readability

Programmers strive to produce readable code. This is accomplished to some a small degree by adhering to any formatting rules that are defined. Other style recommendations contribute to readability and quality. Beyond that, since there will be many differences of opinion regarding readability, programmers are respected to use their own judgement in producing readable code.

Testability

Code should be written so that it can be tested in an automated fashion. This is easiest to accomplish when automated tests are written in conjunction with the implementation. Putting a focus on testability also generally leads to better design of code as well.

Maintainability

Code should be maintainable and not intentionally obscure. Readability and testability contribute substantially to the maintainability of code. Additionally, programmers should try to provide useful comments that explain why something was implented a particular way (working around other bugs, business reason for doing something, etc). Conforming to existing architecture and code styles when writing new code and modifying existing code also help maintainability.

Formatting Rules

The following rules for code appearance are always followed. They are a minimal set of rules intended to provide a consistent general appearance for source code within a project.

Constants and Enums

Constants (static finals) are named in all capital letters, with underscores separating words for readability. Enum values are also named as such.

static final int MAGIC_NUMBER = 42;

enum SomeColors {
    RED, GREEN, BLUE
}

CamelCase

Class names, variable names, and method names are written in CamelCase. Class names begin with a capital, other names begin with a lowercase.

Capitalization requirements for abbreviations in names are not specified—e.g. toHtmlString and toHTMLString are both valid.

class CamelClass {
    int myCamelValue = 12;
    
    String camelizeHTML(String htmlString) {
        return htmlString + myCamelValue;
    }
}

Brace Positioning

Brace positioning is consistent throughout a project code base. The project team is responsible for deciding on the brace positioning convention to use.

Some variations of brace positioning include:

if (true)
{
    doSomething();
}
else
{
    doNothing();
}
if (true) {
    doSomething()
} else {
    doNothing();
}
if (true) { doSomething(); }
else { doNothing(); }

Braces can be excluded when the language does not require them. For example:

 if (true) doSomething(); else doNothing();
if (true) doSomething();
else doNothing();
if (true) 
    doSomething();
else
    doNothing();

Braces can always be placed on a single line when declaring arrays, but otherwise follow the project's brace positioning convention.

int[] a = { 1, 2, 3, 4 };
int[] a = {
    1, 2, 3, 4
};
int[] a =
{
    1, 2, 3, 4
};

Tabs/Spaces

Use of tabs or spaces for indentation must be consistent throughout a project code base. The project team is responsible for deciding on the indentation method to use.

If tab characters are used for indentation, they should never occur after an ordinary space in a line of text.

The main arguments concerning tabs and spaces are:

  • Tabs allow programmers so set their preferred indentation width, but when mixed with spaces can cause layout problems
  • Spaces allow consistent appearance across editors, but force everyone to use the same indentation width

Different team members will have different preferences. The project team collectively chooses the standard to follow. Once chosen, it is followed consistently throughout the project.

Indentation

Code blocks are always indented consistently, using the tab or space indentation preference chosen for the project. When using spaces for indentation, the indentation width is also specified by the team—e.g. 4-characters.

Indentation is consistently aligned.

String myFunction1() {
    indentSome();
    if (true) {
        indentMore();
    } else {
        indentAgain();
    }
}

Varying indentation is not allowed.

String myFunction1() {
    indentSome();
    if (true) {
      indentALittleMore();
    } else {
       indentAgain();
    }
}

When wrapping a statement due to line length, the wrapped portion of the statement is indented. The exact manner of indention is left to the discretion of the programmer.

Formatting Recommendations

These recommendations are not rules. The individual developers are given discretion in all these area, but these recommendations are here to promote consistency and offer perspective on some of the code formatting options available.

Line Length

Lines may be as long or short as they need be. It is expected that the coder will consider readability.

Consider the following long line example:

if (((myImportantValue == 233) && (yourImportantValue == 54) && !otherFailureConditions) || overrideAllFailures || ((incomingValueA * incomingValueB) == 15)) {
    return "Success";
}

The length of the line is left to the discretion of the programmer. It might just as well be broken up:

if (((myImportantValue == 233) && (yourImportantValue == 54) && !otherFailureConditions) 
    || overrideAllFailures 
    || ((incomingValueA * incomingValueB) == 15)) {
    return "Success";
}

Wrapping

When breaking function calls and declarations into multiple lines, it is useful to follow the brace positioning standard chosen for the project.

For example, if the brace positioning convention does not call for opening braces to be their own line:

String[] myStrings = {
    "Here is string 1.",
    "Here is string 2.",
    "Here is string 3."
};

Or, if braces should be on their own line:

bigMethodCall
(
    myFirstParameter,
    "A static string parameter",
    43
);

Flexibility is allowed. For consistency, it is suggested that the brace positioning convention be used.

White Space

Use of white space is left to the discretion of the coder. White space should be used to aid readability. It includes the use of blank lines in blocks of code, between methods, etc. It also includes the use of ordinary space in statements and expressions. There is no "ideal" set of whitespace rules.

Some possible whitespace conventions include:

  • Using one space before and after all binary operators, assignments, and conditionals.
int iAnswer = bCondition ? -4 + -9 : 0;
  • Using one space after all comma operators.
  • Using one space before the opening parenthesis in all control statements, but not before the opening parenthesis in method/function calls.
  • Using one space after the closing parenthesis in type casts.
String s = (String) object;
  • Using one space after the opening brace and before the closing brace in array initalizers.
int[] iNumArray = new int[] { 1, 2, 3 };
  • Not using a space before the opening angle bracket in parameterized types.
Map<DocumentID, Document> map = new HashMap();

Style Recommendations

Code appearance is an important aspect of a coding standard, but code style and conventions may have a larger impact on the overall quality and maintainability of code. As all programmers have differing experience and preference, they are expected to use good judgement. How a programmer implements a particular solution will vary, but sharing experience is important, and developing best practices is a team effort. To aid in the pursuit of best practices, some style recommendations are provided here.

Enums/Constants

Enums should be remembered as a good alternative to static final variables. ALL_CAPS naming convention applies to enum values as well.

In general, any time a magic number or string is used in an expression, it should be declared as a constant. Enums should be used when a collection of related constants are needed.

String evaluateLargeness(int number) {
    if (number < 0) return "negative";
    else if (number == 0) return "zero";
    else if (number < 100) return "not big";
    else if (number < 10000) return "somewhat big";
    else return "really big";
}

Another implementation might look like this:

static final int NOT_BIG_UPPER_BOUND = 100;
static final int SOMEWHAT_BIG_UPPER_BOUND = 10000;
 
enum Largeness {
    NEGATIVE, ZERO, NOT_BIG, SOMEWHAT_BIG, REALLY_BIG
}
 
Largeness evaluateLargeness(int number) {
    if (number < 0) return Largeness.NEGATIVE;
    else if (number == 0) return Largeness.ZERO;
    else if (number < NOT_BIG_UPPER_BOUND) Largeness.NOT_BIG;
    else if (number < SOMEWHAT_BIG_UPPER_BOUND) return Largeness.SOMEWHAT_BIG;
    else return Largeness.REALLY_BIG;
}

Naming

Classes, variables, and methods should all have meaningful descriptive names. This in large part will minimize the need for comments in code.

Consider the following method:

public int doMagic(int n) {
   int i = 1;
   int j = 0;
 
   while (i < n) {
       i += i;
       j++;
   }
 
   return j;
}

The code above does not hint at what the method is actually trying to do. It's not self-documenting. The following method reveals more about the intended functionality of the method through the use of naming and different logic.

public int lowestPowerOfTwo(int iBoundedNumber) {
   int iMultipleOfTwo = 1;
   int iPower = 0;

   while (iMultipleOfTwo < iBoundedNumber) {
      iMultipleOfTwo *= 2;
      iPower++;
   }
 
   return iPower;
} 

The second method is implemented with descriptive names that help the code be more readily understood.

Hungarian Notation

Hungarian notation is a naming convention that is used in few Java projects, but is considered useful to some. It may be used at the discretion of the coder though it is not recommended. Here are some examples prefixes:

  • Booleans begin with 'b'
  • Strings with 's'
  • Doubles with 'd'
  • Floats with 'f'
  • Ints with 'i'
  • Longs with 'l'.

Short Variable Names

It is important that variable names convey meaning in the context they're used, but this does not require that the names necessarily be verbose. Shorter names are easier to type and use less space on screen, which is advantageous if the shorter names retain meaning and readability.

Single character variables that are common:

  • i, j, k for loop index variables
  • x, y, z for coordinates
  • h, w for height and width
  • r, g, b for red, green, blue
  • h, l, s for hue, lightness, saturation

Other common shortened names:

  • sb instead of stringBuffer
  • out instead of outputStream
  • doc insteam of document

Short variable names can harm readability, so they should be used with care, but not feared.

Returns

It is often recommended that functions using complex logic declare the return variable at the begin of the function. Then, set the return value in the body of the function. And, finally return the value as the last statement in the function.

public int exampleFunction(boolean bCondition)
{
    int returnValue = 0;
    if (bCondition)
    {
        returnValue = 1;
    }
    else
    {
        returnValue = 2;
    }
    return returnValue;
} 

Comments

Comments should be kept to a minimum, and when used they should explain the purpose rather than function of code. If comments are needed to describe what code is doing, it may be worth trying to simplify the code. Good method and variable names help minimize the need for comments.

Another reason to keep comments minimal is that code never lies. Comments can lie. Comments have a tendency to be forgotten when making changes and can become out of date, or become entirely unrelated to the code.

It is common and sometimes beneficial to use comments as brief separators in methods. Such comments can succinctly describe the objective of a block of code and separate it from other blocks.

JavaDoc comments are useful, but not nearly as thorough as the source code when available. JavaDoc comments make JavaDoc generated API documentation look pretty, but if we're not publishing APIs, perhaps that should not be the reason for creating JavaDoc comments. Often when working with internal APIs, we have the source code. A JavaDoc comment is useful for explaining the function of certain member variables, explaining the functionality or purpose of unclear action methods, and the requirements of parameters for certain methods. However, the code is the authority and JavaDoc comments risk becoming just as outdated as any other comment.

Organization

How a class is organized is entirely in the hands of the programmer. Each programmer may have different organizing techniques, and the freedom to use those techniques aids in productivity and quality. There is no single correct way to organize code. There are advantages to adopting some consistent organization techniques, but reorganizing existing code should be limited to when it needs to be refactored as a part of planned updates.

When modifying existing code, it is recommended that the individual class file's organizational structure is followed. Reorganization of existing code leads to conflicts and confusion with other maintainers.

Architecture

A part of the organization of code is defined by the architecture of the system. Understanding and working within a well-defined and well-explained architecture leads to consistency and maintainability.

Team Play

The coding guidlines defined above assume that programmers are working in a team environment and are working together. They are respectful of each other's skills and decision making. It is presumed each programmer is competant, though individual experience will vary. That is expected and can be harnessed for the overall good of a project.

Automated Formatting

Code formatting tools can be used to format code according to the defined rules. It is likely that certain tools can accommodate a the team's formatting rules.

Formatting features should only be invoked manually. Automatic reformatting should never be enabled. Blanket reformatting of entire source files should be avoided.

Ownership

Some projects have a notion of collective code ownership within a project team. This is desirable in many ways. No single individual "owns" any of the code, and no one is prohibited from fixing bugs found in the code base, or making improvements.

However, detaching ownership from the source code can have the serious negative effect of also detaching personal interest in it. Many programmers take pride and responsibility for their work, and personal ownership drives that feeling. When their work is disrespected or altered without their input, they will likely lose feeling of ownership. Lack of ownership can affect the quality of code as programmers simply may not care as much about it.

Collective code ownership should not be achieved at the expense of individual accomplishment. To preserve the notion of collective code ownership, the members of the team must respect each other's work, and work together when making changes. Team communication is vital in promoting collective ownership.

Training

As has been stated, individual programmers have different experience and preferences. Difference in experience by itself can result in difference of preferences. It is useful to share experience and preferences with other programmers in the team so that everyone's knowledge is increased collectively. This can lead to the establishment of best practices and common conventions. In that way everyone can participate, share, and learn from others experience.

Again, working is a team is the key and trying to gain from everyone's unique perspectives.

—Posted by Adam Lane on May 5, 2008

You may post a reply to this topic, but you must be logged in. If you already have an account, you may login now. If you need to create an account, you may also register now.


Blogs

May 5, 2008
"Coding Standards and Style"

Oct 6, 2007
"Telecommuting and Software Development"

Aug 6, 2007
"Software Developer Office Space"

Jul 30, 2007
"Using Inno Setup to Create a Versioned Installer"

Jul 30, 2007
"Detect Java Installation with Shell Script"