On coding standards

Published 06:00 on 01 February, 2011

In my time as a web developer, I have been involved in the definition, implementation, and maintenance of several different coding standards, across various web-based languages. In my experience, this process is not as straightforward as it first seems, and can lead to a great deal of headaches if not handled in a very specific manner.

As the front-end development team where I currently work are going through a definition process, I have been reminded of a few things I’ve learnt over the course of my career. With that in mind, I thought I’d type up some of that knowledge in the hope that it might benefit other developers out there.

Some things to remember

It’s important to remember that a developer takes great pride in his or her work, and as a result has a significant emotional attachment to the code they output. When that code is submitted for a code review—where the implementation of any coding standards is going to be assessed by the developer’s peers (obviously alongside other things)—it is important not to tear the code apart without respecting that emotional attachment.

Further to this, it is important that the reasoning behind the rules in the coding standard are rigorously explained and well documented, along with good and bad examples. If the developers understand why they should be doing something, you’re more likely to get them doing it as second nature.

Finally, always check to see if there is a more general coding standard you can utilise, such as Python’s PEP-8 standard or the PHP PEAR standard. It makes far more sense to start with one of these and then build your own standards upon it.

Why have a coding standard?

There is really only one reason to adopt a coding standard; to maintain a predictable base of easily maintainable, understandable, and legible code. Ultimately, you are aiming to develop code that can be picked up by any developer—either in an internal team, or some other, wider community—and easily read, understood, and either fixed or appended.

Further to that, it is not the opportunity to enforce your own particular coding style on others; in fact, you should probably expect to change your own style as there will invariably be some decisions made that will alter your usual syntax or method. This should be embraced as a good thing, as you may learn something.

Creating

When creating a new coding standard, it’s important not to dictate rules to the wider team or community. The best standards are defined in agreement, not by dictation. It’s important to make the definition of team standards a team task.

When a standard—and the reasoning behind that standard—are offered to the team, discussion will invariable ensue. That discussion needs to be controlled and constructive, without dragging on. Nobody wants to sit and listen to two or three developers arguing; sooner or later someone will need to step in and make a decision, despite potentially disagreeing (and therefore upsetting) multiple parties involved.

A good way to avoid massive discussion on mailing lists, or in team meetings, is to make sure your recommendation and acceptance processes are not too complex. As soon as you instigate a complicated system of recommendation, confirmation, voting etc. you will instantly regret it. Developers are adverse to change, and you are potentially changing the very fundamentals of their day to day work. You just can’t expect the process to be quick and painless unless you enforce quick and painless at every possible stage.

The absolute best way to implement and maintain a coding standard is based on the outcome of code reviews. These are the perfect forum for discussion of style and method, and a good follow-up on that discussion is to update the coding standard.

The last thing you should bear in mind when developing a coding standard is that it will usually work best if it’s fairly language agnostic. Similar rules should be applied universally across languages; if you break this rule, you’ll quickly find yourself in a heated discussion about some minutia of syntax that is entirely deconstructive. Having said that, there are always going to be particular features and conventions of a specific language that should be applied to aid legibility or maintenance.

Comments

I hate badly commented code. I also hate writing comments. Ergo, I hate my own code.

Comment as you go

Commenting code is usually way outside the modus operandi of most developers. If we feel a piece of code should be commented, we’ll go back and do it afterwards, which means we’ve automatically given ourselves a mind-numbingly dull job that will, without fail, fall by the wayside upon release. To comment effectively, it’s important to do it as you go, even if you find yourself changing the comments as you refactor your code.

Comment sensibly

Comments should be added in distinct blocks, rather than commenting every single line. It’s important to remember what is important in a block of code and explain that. You’re documenting it for maintenance, so at least afford the next developer a modicum of intelligence. Of course, if you come back to it 6 months down the line, that next developer could very well be you!

When I say “distinct blocks”, I mean functions, methods, objects, classes, event callbacks, blocks of CSS rules, and anything else that requires explanation e.g. particularly complicated or confusing sections of functionality that might not otherwise be entirely obvious. Also, be sure to include references to other sections / files that may be relevant.

Pick your audience

As I’ve said previously, comments are there for the code maintainer, so if you can hide them from the end user, you may as well do so. Comments should be added in the template language rather than the HTML; likewise, any other code generation should keep the comments in the generator not the generated file (unless it is specifically pertinent to do so). If you comment JavaScript and CSS, make sure the comments are removed as part of your build process/combo handler, alongside minification.

Commenting standards

Commenting standards, such as JSDoc, are a good thing. You’re already trying to implement a coding standard, you might as well leverage [manager++] someone else’s.

Naming conventions

Language constructs may allow you the freedom of your given language, but please adopt a little restraint. It’s important to make them readable and decipherable by the next developer along.

Style

Try and adopt a naming convention that suits the style of the language. Here are some examples:

  • HTML and CSS — Use hyphenated lowercase IDs and classes:

    <div id="live-scores" class="tab-module"></div>
  • JavaScript — Use camelCase variable naming, with constructors in UpperCamelCase:

    var myVar = true,
        myFunction = function() {
            // Wicked awesome codez here.
        },
        MyConstructor = function(id) {
            this.id = id;
        };
  • PHP, Python — Use lowercase with underscore separation, with UpperCamelCase for classes:

    $dev_name = "Timmah";
    
    
    function get_foo() {
        return "foo";
    }
    
    
    class SimpleClass {
        // property declaration
        public $var = 'a default value';
        // method declaration
        public function displayVar() {
            echo $this->var;
            }
    }

Grace

It is important to keep names concise yet explanatory. There’s no need to write a variable name that’s fifty characters long, if you could do it in ten. Likewise, it’s important you aren’t just writing a nonsensical string of characters that ends up looking like some kind of demented Countdown Conundrum.

Bad:

var boolean_flag_for_portrait_view = true;

Also bad:

var bl_flg_pview = true;

Good:

var is_portrait = true;

Prefixing / suffixing type

Type prefixes and suffixes are a bad idea; loosely typed languages allow the developer the ability to change things up, so you’d better expect it once in a while. Further to that, any intelligent developer can work out what type a variable is if they absolutely have to, so why waste the characters?

Final note: If type prefixes and suffixes are a bad idea, Hungarian notation is a very very bad idea. Don’t go there. SRSLY.

Style

As I’ve stated previously, a coding standard is not a way for you to enforce your own coding style on others. Try and keep any such rules to a minimum.

Tabs vs. spaces

One of the first conversations you’re going to have, when defining a coding standard, is whether you should be using tabs or soft-tabs (spaces) for indentation. In a modern development environment, this is irrelevant—even in languages where whitespace indentation is important, such as Python.

A developer should be able to set-up their IDE to use either tabs or spaces when indenting, thus they shouldn’t have to worry about it. The only thing that is important in this area is that it remains uniform in any given file. There is nothing worse than opening a file to find some things indented by 4 spaces, and others indented by 3 [deviants!].

Legibility

It’s important to write code that is legible; the more so, the better. To aid comprehension of blocks of code, it is useful to separate them with new lines.

It’s also important to try to keep lines of code to a reasonable length. Many developers and coding standards recommend a length of around 80 characters, with some even enforcing it. Python’s PEP-8 certainly falls under this heading. Personally, I’d prefer going over that length if the line remains legible; often breaking a line with carriage returns can have a negative effect on legibility.

Similarly, Lines that are too long are often difficult to read. If this is the case, then you must attempt to find the most legible form. Legibility is always the most important factor.

Whitespace

Liberal use of whitespace in your syntax can mean the difference between readable and unreadable code. Having said that, over use of whitespace can be entirely detrimental. Like my previous notes on style, it is important to find a balance when wrapping parentheses, expressions, assignments, and other such code with whitespace:

Readable:

var myVar = 'foo';

for ( var i = 0, j = myArray.length; i < j; i++ ) {
    
}

Less readable:

var myVar='foo';

for(var i=0,j=myArray.length;i<j;i++){
    
}

Accepted standards

There are many accepted standards used across multiple languages. It is important to make sure you don’t break these with your coding standard, even if you don’t specifically declare them anywhere. Good examples might be:

  • Use of i, j, k for simple iterators.

    for ( var i = 0, j = myArray.length; i < j; i++ ) {
        
    }
  • Use of _ to denote private members.

    var myConstructor = function() {
        this._private = 'something private';
    };
  • Use of UPPERCASE to denote constants.

    var VERSION = 'v1.1';

Expressions

Expressions are often where the complex logic within your code can be found. As such, to aid assimilation, you may like to break them down to their constituent parts.

A complex expression:

if ( myArray.length < 4 || ( myString.length > 2 && myString !== 'foobar' ) ) {
    
}

Might become:

var isArrayShort = ( myArray.length < 4 ),
    isStringCorrectLength = ( myString.length > 2 ),
    isStringMatched = ( myString !== 'foobar' ),
    hasCorrectString = ( isStringCorrectLength && isStringMatched ),
    isPassed = ( isArrayShort || hasCorrectString );

if ( isPassed ) {
    
}

If we clean it up further:

var isArrayShort = myArray.length < 4,
    isStringCorrectLength = myString.length > 2,
    isStringMatched = myString !== 'foobar',
    hasCorrectString = isStringCorrectLength
                       && isStringMatched,
    isPassed = isArrayShort
               || hasCorrectString;

if ( isPassed ) {
    
}

Note the fact that I have broken the logical operators onto their own lines. This is another technique that can sometimes aid the readability of an expression, should it adopt multiple ANDs and ORs.

This last example may look more complex to begin with, but should a second developer read your original code, they will be left confused. The second example breaks the expression down into constituent boolean values to aid legibility.

Now imagine we have a similar example, but adopted using ternary notation:

var output = ( myArray.length < 4 || ( myString.length > 2 &&; myString !== 'foobar' ) ) ? 'win' : 'fail';

This would become:

var isArrayShort = myArray.length < 4,
    isStringCorrectLength = myString.length > 2,
    isStringMatched = myString !== 'foobar',
    hasCorrectString = isStringCorrectLength
                       &&; isStringMatched,
    isPassed = isArrayShort
               || hasCorrectString,
    output = isPassed ? 'win' : 'fail';

Ternary becomes much easier to read by a second party when used in this way; particularly when dealing with nested ternary statements. Of course, a good rule of thumb is to just avoid nesting ternary statements altogether.

Concerns over file size

In some languages, the size of the source code files you are creating can be pertinent to the performance of the final software. The obvious example of this is JavaScript files being served to a client.

In this instance, it is important not to sacrifice maintainability for optimisation. Should your files need optimising for final consumption, factor that optimisation away into your build or delivery mechanism. With JavaScript, this means minifying your code using an algorithm that can understand how to refactor it. Google’s Closure Compiler is a good example of one such tool; however, it still has limitations, and you may find it beneficial to write your own based around your coding standards.

Enforcing

There is really only one way to enforce a coding standard, and that is exactly the same way you should be developing your coding standard; through code reviews.

Summary

As my final word, I’d just like to point out that your mileage with this may vary wildly. This article is really only based on my own experience. However, whether you agree with everything here or not, I would hope you agree that easily maintainable code is the most important outcome of any good coding standard.