The developer’s manifesto

The developers manifesto I’ve created here are a set of coding guidelines that me and the development team I work with believe will lead to high quality, easily readable code. Code written not for you to read, but for someone else to read. It is the result of several weeks of meetings, reading a number of books, and years of making these mistakes. I am publishing it here first so the team have an online resource to refer to, and to inspire others to create great code also.

Indentation, brackets and spaces

We have selected the following standards, but what matters most is not which standard, but that you have a standard. We will use this convention on all new projects. On existing projects, stick with the previously established convention.

Use 4 spaces, soft tabs (so really uses spaces, not tabs when you press the tab key) unless the language requires otherwise. More over on coding horror…

Use brackets on the same line

function functionName() {
	if (shouldDoSomething) {
		doSomething();
	} else {
		doNotDoAnything();
	}
}

Add 1 space between brackets and braces

function functionName() {
	if (shouldDoSomething) {

Add 1 space between operators

var concatenatedString = string1 + string2 + ".";

Use meaningful names

Use meaningful names for variables, functions and classes, select names which describe exactly what the variable, function or class does

So this :

function name(b, c) {
    strName = b + " " + c;
}

becomes:

function setName(firstName, lastName) {
    name = firstName + " " + lastName;
}

Use consistent names

Define these patterns at the start of the project

Functions and classes

Structure of classes

Classes should be laid out thus:

  1. public static constants
  2. private static constants
  3. private instance variables
  4. overridden functions
  5. public/private functions, ordered in layers as they are used so used functions are as close as possible to the function calling it (see levels in code example below)

These are controversial, but after trying them, we find code is more readable.

Before:

var splash = (function() {

    var
    _shouldAutomaticallyChange = true,
    _numberOfSlides = 0,

    _getPositionOfCurrentSlide = function() {
        var slidesArray = _getSlidesAsArray();
        var i = slidesArray.length - 1;
        for (i; i >= 0; i--) {
            if (jQuery(slidesArray[i]).hasClass("current")) {
                return i + 1;
            }
        }
        return false;
    },

    _getPositionOfNextSlide = function(currentSlide, numberOfSlides) {
        if (currentSlide === numberOfSlides) {
            return 1;
        } else {
            return currentSlide + 1;
        }
    },

    _getPositionOfPreviousSlide = function(currentSlide, numberOfSlides) {
        if (currentSlide === 1) {
            return numberOfSlides;
        } else {
            return currentSlide - 1;
        }
    },

    _changeSlide = function(from, to) {
        if (from !== to) {
            jQuery('#splash-tabs > li:nth-child('+from+')').removeClass('current');
            jQuery('#splash-tabs > li:nth-child('+to+')').addClass('current');
            jQuery('.splash'+from).fadeOut('slow').removeClass('current');
            jQuery('.splash'+to).fadeIn('slow').addClass('current');

        }
    },

    _getSlidesAsArray = function() {
        return jQuery("#splash-tabs > li");
    },

    _onClickNext = function() {
        var currentSlide = _getPositionOfCurrentSlide();
        _changeSlide(currentSlide, _getPositionOfNextSlide(currentSlide, _numberOfSlides));
    },

    _onClickPrevious = function() {
        var currentSlide = _getPositionOfCurrentSlide();
        _changeSlide(currentSlide, _getPositionOfPreviousSlide(currentSlide, _numberOfSlides));
    },

    _changeIfShouldChange = function() {
        if (_shouldAutomaticallyChange) {
            setTimeout(_change, 6000);
        }
    },

    _change = function() {
       if (_shouldAutomaticallyChange) {
          _onClickNext();
          _changeIfShouldChange();
       }
    };

    init = function() {

        _numberOfSlides = _getSlidesAsArray().length;

        jQuery("#splash .next").bind('click', function() {
            _shouldAutomaticallyChange = false;
            _onClickNext();
        });

        jQuery("#splash .previous").bind('click', function() {
            _shouldAutomaticallyChange = false;
            _onClickPrevious();
        });

        jQuery("#splash .next").bind('touchstart', function() {
            jQuery(this).addClass('active');
        });
        jQuery("#splash .next").bind('touchend', function() {
            jQuery(this).removeClass('active');
        });

        jQuery("#splash .previous").bind('touchstart', function() {
            jQuery(this).addClass('active');
        });
        jQuery("#splash .previous").bind('touchend', function() {
            jQuery(this).removeClass('active');
        });

        jQuery('#splash-tabs > li').bind('click', function() {
            _shouldAutomaticallyChange = false;
            var currentSlide = _getPositionOfCurrentSlide();
            var position = _numberOfSlides - jQuery(this).nextAll().length;
            _changeSlide(currentSlide, position);
        });

    };

   return {
      init: init
   }

}());

After:

var splash = (function() {

    var
    _NUMBER_OF_SLIDES,

    _shouldAutomaticallyChange = true,
    _postionOfCurrentSlide = 1,

    init = function(automate) {
        _NUMBER_OF_SLIDES = _countNumberOfTabs();

        jQuery("#splash .next").bind('click', _onClickNext);
        jQuery("#splash .previous").bind('click', _onClickPrevious);
        jQuery('#splash-tabs > li').bind('click', _onClickTab);

        jQuery("#splash .next").bind('touchstart', _onTouchStartButton);
        jQuery("#splash .next").bind('touchend', _onTouchEndButton);

        jQuery("#splash .previous").bind('touchstart', _onTouchStartButton);
        jQuery("#splash .previous").bind('touchend', _onTouchEndButton);

        if (automate) {
           _triggerDelayedCallToGoToNextSlideAutomatically();
        }
    },

    //Level 1

    _onClickNext = function() {
        _preventSlidesFromAutomaticallyChanging();
        _goToNextSlide();
    },
    _onClickPrevious = function() {
        _preventSlidesFromAutomaticallyChanging();
        _goToPreviousSlide();
    },
    _onClickTab = function() {
        var positionOfClickedTab = _numberOfSlides - jQuery(this).nextAll().length;
        _preventSlidesFromAutomaticallyChanging();
        _changeSlide(positionOfClickedTab);
    },

    _onTouchStartButton = function() {
        jQuery(this).addClass('active');
    },
    _onTouchEndButton = function() {
        jQuery(this).removeClass('active');
    },

    /**
       @return {number}
    */
    _countNumberOfTabs = function() {
        return jQuery("#splash-tabs > li").length;
    },
    _triggerDelayedCallToGoToNextSlideAutomatically = function() {
        if (_shouldAutomaticallyChange) {
            setTimeout(_goToNextSlideAutomatically, 6000);
        }
    },

    //Level 2
    _preventSlidesFromAutomaticallyChanging = function() {
        _shouldAutomaticallyChange = false;
    },
    _goToNextSlide = function() {
        _changeSlide(_getPositionOfNextSlide());
    },
    _goToPreviousSlide = function() {
        _changeSlide(_getPositionOfPreviousSlide());
    },
    _goToNextSlideAutomatically = function() {
        if (_shouldAutomaticallyChange) {
            _goToNextSlide();
            _triggerDelayedCallToGoToNextSlideAutomatically();
        }
    },

    //Level 3
    _getPositionOfNextSlide = function() {
        if (_postionOfCurrentSlide === _numberOfSlides) {
            return 1;
        } else {
            return _postionOfCurrentSlide + 1;
        }
    },
    _getPositionOfPreviousSlide = function() {
        if (_postionOfCurrentSlide === 1) {
            return _numberOfSlides;
        } else {
            return _postionOfCurrentSlide - 1;
        }
    },
    _changeSlide = function(postionToChangeTo) {
        if (_postionOfCurrentSlide !== postionToChangeTo) {
            jQuery('#splash-tabs > li:nth-child(' + _postionOfCurrentSlide + ')').removeClass('current');
            jQuery('#splash-tabs > li:nth-child(' + postionToChangeTo + ')').addClass('current');
            jQuery('.splash' + _postionOfCurrentSlide).fadeOut('slow').removeClass('current');
            jQuery('.splash' + postionToChangeTo).fadeIn('slow').addClass('current');
            _postionOfCurrentSlide = postionToChangeTo;
        }
    };

    return {
        init: init
    };

}());

Comments

Testing

We write code with full unit testing and integration/automated user testing (using tools such as Selenium to mock user input)

Repository management

We use git

Code reviews

All code pushed to the main development branch is reviewed by another team member, checking all of the points listed here and making sure code is readable and makes sense

  • The Incredible LOAP

    This should be the preface to all programming books!
    Thank you!