Imagine its late Sunday afternoon… you’re at the office, and have been all weekend. You are diligently working to ensure that the Monday build deadline is met. You have been testing your code, and all is looking good in your dev environment, so you decide it’s time to check in your code and run the build process. But once you get the latest code from your repository the build no longer compiles!!! How frustrating!
Why did this happen… who is responsible… You could be here all night trying to track down the cause! If you are working in a remote environment or on a multi-site team tracking down the problem will be even more difficult.
Now imagine that your development team uses a Continuous Integration (CI) process. When anyone checks in code to the team’s source code repository the build is automatically run, and if there are any compile issues an email is sent out to the team. Now you know exactly what code broke the build, and which team member was responsible. Better yet, the issue can be addressed immediately. But why stop at just compile issues? Why not automate your suite of unit tests as well? Throw in a code coverage tool and just imagine how confident you would be that not only your build will consistently compile, but that the new code you have introduced has not broken any existing functionality.
If your team does not employ any of the tactics mentioned above, you know these integration pains firsthand. And while implementing a Continuous Integration process is not a change that will happen overnight, the time and effort spent in implementing such a plan will certainly be less than the amount of agonizing hours spent by team members tracking down such integration issues.
According to Martin Fowler:
The fundamental benefit of continuous integration is that it removes sessions where people spend time hunting bugs where one person's work has stepped on someone else's work without either person realizing what happened. These bugs are hard to find because the problem isn't in one person's area, it is in the interaction between two pieces of work. This problem is exacerbated by time. Often integration bugs can be inserted weeks or months before they first manifest themselves. As a result they take a lot of finding.
I recommend implementing your CI process in stages:
-
Implement a Source Code Repository that meets the needs of your team. For example, does it work well with remote teams (accessible from the internet)?, does it integrate well with other CI tools (auto-build tools, unit testing tools, etc.)?
- Document your build process and train all developers on this. This should clearly layout items such as when you should check in your code, what structure you will use and what each folder is used for, under what circumstances to tag or branch the repository, how to version the build, etc. The idea is to make sure everyone is familiar with and follows this consistent process.
- Once this is in place you should add the automated build component. There are a lot of good tools out there. Finding one that integrates with your code repository is a must (this should not be hard). Here is a feature matrix published by ThoughtWorks that is an excellent resource for evaluating which CI system is the best fit for your organization.
- Train your development team to effectively use test-driven development and strive to have the team write ‘self-testing code’. This is the hardest and most time consuming step because this is not just a tool that needs to be learned and configured… this is a fundamental change in your approach to writing code.
- Automate the running of your unit tests. Once the team is writing effective unit tests, you will want to have these run every time the build is compiled. This adds an even greater level of assurance that everything is still ‘a-ok’ after introducing new code.
- And finally, use a code coverage tool to ensure maximum effectiveness of your unit tests.