Continuous Integration (CI) Practices


Reading time: 20 minutes

Continuous integration is a practice that focuses on preparing for an early release and constantly, testing the software by building it after every change. We will go through the practices to execute this process successfully.

Continuous Integration Practices

The CI practices are:

  • Commit Code Frequently
  • Maintain a Single Source Repository
  • Don’t Commit Broken Code
  • Automate the Build
  • Keep the Build Fast
  • Every Commit Should Build the Mainline
  • Fix Broken Builds Immediately
  • Write Automated Developer Tests
  • All tests and Inspections must Pass
  • Run Private Builds
  • Avoid getting Broken Code
  • Automate Deployment

We will go through each practice in detail.

1) Commit Code Frequently

  • Integrate early and often is one of the central tenets of CI.
  • Commit code to version control repository regularly.
  • Waiting for more than a day to commit the source code consumes a lot of time and prevents other developers from using the most updated version of the source code.

Everyone committing at the same time may lead to confusions and conflicts. Build errors may occur because of the collision between the changes.

2) Maintain a Single Source Repository

  • Use a source code management system that serves as a centralized source code repository.
  • Source code management tools are available to maintain the code in a single centralized location, from where developers can check out the latest version of the mainline build.
  • Everything that a developer creates should be pushed to this source code repository, including: test scripts, properties files, database schema, install scripts, and third party libraries.
  • Most importantly, there should be a mainline, a single branch of the project that is currently under development.

3) Don’t Commit Broken Code

  • Don’t commit code that do not compile or tho code that fails a test.
  • Everyone in the development team should be aware that they should not commit code that doesn’t work.
  • Committing broken or non-functional code will affect the code in integration machine, and fellow developers will not get the correct version of the code.
  • Every developer should follow the practice of carrying out a private build before checking the code into the centralized repository.

4) Automate the Build

  • The build process has to be automated in a CI environment, which help build and launch the system using a single command.
  • The command will run the build scripts necessary for automating the build process.
  • A build process should include everything including getting the database schema from the repository and launching it in the production environment.
  • Most of the development environments (IDEs) that we use these days have built management systems, but these are proprietary to the IDE and are fragile.
  • Examples for build tools are Ant, Ruby Rake, MSBuild, etc.

5) Keep the Build Fast

  • Any build that takes an hour is considered unreasonable. Extreme programming (XP) has set a guideline that every build should take not more than 10 minutes.
  • The important step in getting a faster build is setting up a deployment pipeline, which enables multiple builds in a sequence.
  • The first build, also called commit build is the one that is triggered when a developer commits to the mainline. The commit build is done so quickly that it may bypass bugs and a balanced approach is necessary to identify bugs and gain speed.
  • A two-stage deployment pipeline can do compilation and run multiple localized tests, and at the same time it adheres to the 10-minute guideline.

6) Every Commit Should Build the Mainline

  • Regular builds should happen on the integration machine and the build should succeed in order for the commit to be considered done.
  • The developer who commits the latest code should be responsible for monitoring the mainline build, so that they can fix if anything breaks.
  • A CI server acts as a monitor the repository. Every time the commit gets done, the server checks the source code onto the integration machine and initiates a build.
  • The result of the build process is also notified to the committer through email.
  • Regular builds should also ensure that the problems are identified well in the early.

7) Fix Broken Builds Immediately

  • A broken build is one which prevents the build from reporting success.
  • Though it is common for a mainline build to break, the key part is that any error in the mainline build has to be fixed right away.
  • The best way to fix a broken mainline build is to revert the most recent commit from the mainline.
  • It is not advisable to debug on a broken mainline, unless the cause of breakage is very obvious. Debugging should always be done in the local development environment after reverting to the latest known good build.

8) Write Automated Developer Tests

  • A build should be fully automated. In order to run tests for a CI system, the tests must be automated.
  • Verify that the software works, using automated developer tests.
  • Testing can catch a lot of bugs, even from a program that runs.
  • Methods like extreme programming and test-driven development (TDD) have put a lot of emphasis on self-testing code and for this, automated test can check a large part of code for bugs.
  • Writing tests in an xUnit framework such as NUnit or JUnit will provide the capability of running these tests in an automated fashion.

9) All tests and Inspections must Pass

  • In a CI environment, it is very important that 100% of tests must pass prior to committing code to the version control repository.
  • Automated tests are as important as the compilation process.
  • Keeping the mainline with code that doesn’t pass the automated tests can result in low-quality software.
  • Coverage tools help in identifying the source code that doesn’t have a corresponding tool. This ensures that the entire code undergoes the testing phase.

10) Run Private Builds

  • To prevent integration failures, changes from other developers have to be received by getting the latest changes from the repository and running a full integration build, locally known as a private system build.
  • Developers should run an integration build in their local development environment after the code undergoes unit tests.
  • Code that the developer commits to the integration build server is less likely to fail, if it undergoes a private system build.

11) Avoid getting Broken Code

  • Getting a failed build from the repository means the latest code is not checked out from the repository.
  • This consumes a lot of time and effort, as the developer has to do some workaround to fix the error that has caused the build failure for compiling and testing the code.
  • Developers can wait for the change or help the other developer(s) fix the build failure and then get the latest code.
  • Though it is the responsibility of the team, the developer(s) who caused the breakage should fix the bug, for the build to work fine.

12) Automate Deployment

  • Automating the deployment is similar to automated build, we have a script that does the deployment automatically into any environment.
  • Automated deployment helps speed up the process and reduce errors.
  • Automated deployment is an economically viable option because it requires the same capabilities that are required to deploy in a test environment.
  • There should be a provision for automated rollback, since failures can happen at any point in time.
  • For testing new features or user interfaces, it is always suggested to deploy trial build deployed to a subset of users, who will then decide if it can be deployed to all users.

With this, you have the complete knowledge of maintaining CI systems for any software system. Enjoy.

Connect with the Author on LinkedIn and Twitter