Perhaps the most valuable of all the software development practices today is continuous integration (CI). It’s usually easy to set up a CI environment for either an agile project or a traditional waterfall one, and the benefits are huge.
Continuous integration essentially means merging all developer work to a shared mainline several times a day. It’s more than just setting up a build server, and it's also more than version control. Continuous integration is an automated system, and when new source files are created or existing files are modified, it automatically kicks off the build to compile the system and run the entire suite of automated regression tests.
I won't be going into how to set up a continuous integration system, or even some of the best practices around it. There are several articles and other sources on how to do this. In fact, many CI systems are open source or otherwise free, so they can be downloaded and installed at essentially no cost. Even the ones that are commercial products are typically pretty inexpensive, especially considering the value they provide. Instead, I’ll detail some of the many benefits of continuous integration that you may not have considered.
Some Surprising Benefits of Continuous Integration
Perhaps the most obvious benefit of continuous integration is the elimination of the integration phase that existed in traditional waterfall projects. This phase is where we typically slip the worst on deadlines.
During many projects I’ve worked on, we'd be in good shape during design, development, and even unit testing, but when it came time to integrate all the code together, we found integration bugs that we never realized existed. What should have been a simple process of stitching all our modules together turned out to be integration hell, taking far longer than we ever anticipated. It was not uncommon to recognize in the eleventh hour, during integration, that we made some serious mistakes in the design and implementation of modules that made our code incompatible with other pieces. We would then have no choice but to go back to the drawing board and redesign and recode big parts of a system weeks before we were supposed to deliver it. As a result, I’ve seen project delivery delayed by weeks or even months.
This does not happen when continuous integration is used on a project because we get continuous feedback about whether the code we recently wrote integrates into the system. Rather than a single integration point at the end of a project, with continuous integration there are hundreds or even thousands of tiny little integration points along the way, which makes for a far more stable product that has far more predictable results.
Developers on a team using CI should integrate their code at least once per day. But if the team is told that they must integrate any code they've written before they leave at the end of the day, something interesting happens. The last person to integrate usually finds some of the worst problems, so in order to avoid that, many developers integrate more frequently. It's not uncommon for a developer to start integrating their code as they build it, perhaps several times a day or even multiple times each hour.
Doing this gives instant feedback so we can tell where a problem exists in our code that affects other code in the system. As we integrate and get feedback throughout the day, we begin to think about how we build our software a little bit differently and start to focus on practices that will make our code more robust and less brittle.
Working on a large system can often feel like fumbling around in the dark. Feedback is like shining a light into that dark room. Suddenly we see what's there—and not there.
People naturally adjust to feedback when it's given to them on a timely basis, especially impartial feedback like the kind we get during CI. When we see that our code is constantly breaking other code, we naturally think of ways to make that not happen. Even “cowboy coders” have to take a step back and see how their work integrates with the rest of the team or they end up spending late nights in front of the computer rather than at home. I’ve found that once a team adopts continuous integration, it automatically leads to building higher quality software because higher quality software is what passes the integration server faster.
How to Get Started with Continuous Integration
Continuous integration is easy to set up. All you need is a build server and some free software. It’s really a matter of just sitting down and setting it up, but there is one subtle aspect to continuous integration: the quality of the automated tests you have.
Automating unit testing means you don't have to do manual regression testing, which can take an enormous amount of time and resources on traditional projects. Unit tests are only effective if we're testing the right things, so there it is a bit of an art to building the right tests.
I believe the best way to build unit tests is with test-first development because it also informs our design and assures us that we have a full suite of tests for all of our implementation. Doing test-first development, however, doesn’t replace a quality assurance effort, so you may also want to add additional acceptance, integration, and system tests to assure your code is behaving as you expect.
Test-driven development is a discipline in and of itself, but unfortunately, there aren’t a lot of good resources available to learn how to do TDD properly. Tests have to be complete but not redundant, and they have to test the right things so they run fast. There are many schemes for staging builds when projects become very large. We want our builds to run quickly, or else we’ll tend not to use continuous integration. A minute or two to run is fine, but when we start to take ten, twenty, forty minutes or more to build the system, then developers tend to shy away from doing it—and that's not at all what we want.
The correct way to do continuous integration is to do a complete build on our local machine before we build on the integration server to assure that everything works correctly and that the first layer of unit tests all pass. Then we promote our code to the mainline and run the build again on the integration server. This can be a more extensive build and test environment. Depending on the size and complexity of our system, we may do nightly builds so as to run a full suite of tests that we can’t run during the day. Staging builds in this way lets us work with very large systems that require a great deal of processing power to determine if they’re running correctly. Even very large projects can be handled using staged builds.
Continuous Integration: Better Collaboration, Better Software
By doing continuous integration, our code is always ready to ship. This means that at any point in time we can push a button and produce shippable code. Now, we may not want to do this very often, but it's good to know we can at any point in time. Suddenly development is decoupled from marketing or other services that are involved in the delivery of software.
Continuous integration means that there is no integration phase like there is in a traditional waterfall project, so we're not deluding ourselves in situations where we might end up having more work than we thought due to integration bugs. Using continuous integration, we get a true measure of our progress, and the worst bugs are found sooner.
Another huge advantage of CI is that it promotes “fearless refactoring” because the risk of breaking something else while changing code and not detecting it quickly is dramatically reduced. This gives developers confidence that they can continually improve code maintainability and quality without breaking other things in the process.
But I think one of the most important benefits of doing continuous integration is how it impacts the culture of the development organization. Team members work together better because they realize what they do impacts each other's code. It's very easy to get siloed on traditional waterfall projects and end up building software in a virtual vacuum, but continuous integration gives us a touchstone for the rest of the team and helps us build software that’s more compatible with other team members’ code.
So, continuous integration has many benefits and very low cost. Why not try it?