Continuous integration

Continuous Integration (CI), in its simplest description, is a repeatable, automated process for merging new or altered code into a common, shared environment, either on some sort of timed basis, or as a result of some event such as committing changes to a source control system. Its primary goal is to try and detect potential integration problems as early in the code promotion or deployment process as possible, so that any issues that arise can be resolved before they are deployed to a live, production branch. In order to implement a CI process, regardless of any tools that might be used to control or manage it, there are a few prerequisites:

  • Code needs to be maintained in a version control system of some sort, and there should be, ideally, one and only one branch that a CI process will execute against.
  • The build process should be automated, whether it fires off on a predetermined schedule, or as a result of a commit to the version control system.
  • As part of that build process, all automated tests (unit tests in particular, but any integration or system tests that can be usefully executed should at least be considered for inclusion) should execute. When those test fire off may be worth discussing, since there may be two or more windows of opportunity, and they both have their advantages:
    • Tests executed before the commit and build is complete, if the tools and processes can either prevent the commit or build, or roll a commit back to its last good state on a test failure, will prevent code that fails its tests from being committed. The trade-off in this scenario is that it's possible that conflicting changes from two or more code change sources might be significantly tangled and need correspondingly significant attention to remedy. Additionally, if the offending code cannot be committed, that may make it difficult to hand off the offending code to a different developer who might well be able to solve the issue quickly.
    • Tests that execute after a build will allow code that's failed one or more tests to be committed to the collective code base, but with known issues at a minimum. Depending on the shape and scope of those issues, it might well break the build—and that can be disruptive to the whole team's productivity.
    • Some sort of notification process needs to be in place to alert developers that there is an issue—particularly if the issue resulted in a broken build.
    • The process needs to assure that every commit is tested and successfully buildable.
    • The results of a successful build need to be made available in some fashion—whether through some sort of scripted or automated deployment to a specific testing environment, making an installer for the new build available for download, or whatever other mechanism best suits the product's, team's, or stakeholders' needs.

With these in place, the rest of the process is just a case of working out some of the process rules and expectations, and implementing, monitoring, and adjusting them when/if needed:

  • When should commits happen? Daily? At the end of development of a story, feature, or whatever unit of work might apply?
  • How quickly does the commit-test-build process need to run? What steps can be taken, if any, to keep it quick enough to be useful?