Continuous Integration or CI is the practice of automatically building your software and running it through a battery of tests, every time a change is committed to source control (or based on a timer). In last week's Continuous Integration article I introduced the concept of CI and detailed the four phases of the CI loop. What I did not cover in detail is the question why you would want to implement CI in the first place. That is the topic of this article.
One of the main benefits of unit testing is a shorter feedback loop. The less time passes between a developer making a mistake and the discovery of that mistake, the easier and cheaper it is to fix the problem. Frequent execution of all unit tests keeps that interval short. The more automated you tests, the easier it is to run them and with that, the more likely it is that the developers will actually execute them. Always remember:
The most common reason that developers do not execute the tests is the (perceived) hassle involved in doing so. I always recommend that you should write your unit tests in a way that you can execute them with a press of a button. CI goes one step further: It automates the execution for you. But CI automates even more. The entire software package is built and deployed (to a CI environment) and then tested. With that, you can be sure that your product can be built and deployed and it conforms to all requirements (at least the ones currently covered by a test).
To make CI work, both the built and the deployment process have to be automated. Because the entire process potentially has to run several times a day, it also has to execute fast. That requires you to think about deploy-ability early on, which leads to a robust and performant build and deployment framework. By the time you are done with development, you do not have to struggle with creating packages that include actually all the pieces required to install the product, because the system has gone through that cycle several times already.
Writing automated unit tests tends to lead you towards testable code. The same holds true for the CI process. Because you are thinking about testability, build-ability and deploy-ability early on, your software is pushed towards a design that makes these interactions simple.
All the effort put into unit testing by a development team can be undone by a single person that is not diligent about writing new or fixing broken unit tests. Often this type of behavior is caused by perceived pressure to get things done in too little time.
With a working CI setup, every member of the team is notified instantly when "the build breaks". That notification includes the information about what the last change was and by whom that change was checked into source control.
This provides accountability. Non-supportive team members cannot hide their actions (or inactions) until it is too late. The feedback is immediate. But even if no one is to blame for the problem, CI will identify any form of integration issues early and provide documentation about the last few changes. With that it is usually very simple to understand and remedy the problem.
CI automatically executes your build, your deployment process and your tests. The tests executed during the CI loop should include all unit and acceptance tests. Automated UI and performance tests can be part of the process as well.
In addition, you can run checks against your code base to enforce code quality standards. Prime examples for this are static analysis tools and unit test coverage metrics, if your language provides them. Unit test coverage measures the ratio of code validated by unit tests to code not validated by tests. Static analysis tools can be used to check for naming conventions and misuse of language features.
Enforcing code quality standards with CI leads to a more even code quality and can help to avoid issues do to incongruent coding standards.
In addition to all the benefits mentioned above, CI can provide rich reports about the health and progress of your project. Information you can collect includes metrics like number of test cases over time, number of test case failures over time, number of completed check-ins (even by employee), the overall adherence to coding standards and test coverage.
CI provides several strong advantages that make its use almost a must. However - as every good thing - it comes at a price. CI requires a significant upfront time investment as well as regular maintenance activities. While it can increase team participation through accountability, you still need the entire team's buy-in for it to work.
But if you do implement CI, in the long run the benefits will by far outweigh these investment costs and lead you to a cleaner more stable (or in short: better) product.