Continuous integration is a software development practice that has been used for more than 15 years in agile development. So, what is Continuous Integration and why should we care?
To help us sort this question out, we took an interview with Mihai, our colleague and Continuous Integration “evangelist”, in which we asked him to explain some of the concepts related to this practice.
Alina: OK, we hear a lot about Continuous Integration, but what does it actually mean?
Mihai: The best definition I find to be the one from Martin Fowler:
“Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily - leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly.”
One of the requirements of Continuous Integration is the use of source control, I won’t discuss in this article why you should use source control, but here is a good article about what it is and why you should use it: What is source control and why should I use it?
Assuming that you are using source control, the next step is to integrate the source code frequently with the source control system, so that the integration of your changes to the source control can be verified. A good article about frequent integration: check in early check in often.
Roy Osherove and others say that from the Continuous Integration point of view you only need to integrate frequently, and decide when to make the builds, and that build automation is a separate topic (Build Automation - Continuous Builds), but in this article we will refer to Continuous Integration as it was described by Martin Fowler.
In order to be able to integrate frequently, the build needs to validate that the application is running correctly. If no tests are written or executed, developers tend not to push the code so often because of the fear of breaking something. Another concern resulting from the lack of automated tests appears when developers get the latest sources - what if someone else introduced a bug in the code and I can’t continue my work?
Therefore, the automated builds that are executed with each integration run some “sanity” checks that verify whether the software is working correctly or not.
A: What are the best practices of continuous integration?
M: In order to do Continuous Integration successfully there are 2 aspects that need to be followed: 1) the team’s way of working and 2) the continuous integration configuration.
1. The way of working
Push code frequently
This often comes with the need to change the way you organise yourself when working on a task. In order to achieve this, you need to write your code in such a manner that you never have unsubmitted local changes older than 24 hours.
Don’t push broken code/untested code
Every member of the team should run the unit tests locally before they push the code, so that you don’t risk to block the team. The team gets blocked when your build fails, a situation in which nobody in the team is allowed to push their code until you fix the bug.
Don’t push when the build is broken (build or unit tests failed)
When a colleague breaks the build, nobody should get the source code or push other changes to the source control until the build is fixed. This is because if you push and your push fails, there is no way for you to know whether you introduced any new build errors. Conversely, if your colleague’s fix fails, you cannot know if he fixed his errors or not. In any case, you don’t want to write code starting from a broken copy.
Don’t call it a day until your changes are validated by the build
As I said in the previous points, if a build fails, nobody should get the latest source code or push new changes. If you go home before you fix your bugs, you might block other team members from working.
2. How to configure Continuous Integration
A single repository with everything that is needed
Everything should be in the source control, code/documentation/build script. It’s a lot easier to build and integrate the big project if all the sources are under one repository.
Have an automated build that is running the tests
The purpose of the build/test is to give developers confidence to integrate frequently knowing that the application will still work after getting the source code.
Keep the build fast
Taking into consideration that everyone pushes the code at least daily, your code should be validated as fast as possible, so that you know that everything is ok. If this takes too much, your team will stop validating the build locally, and as a result, you will have a lot of failed builds.
There should be different types of builds. On the automated build that runs on each push, only unit tests should be executed (they are fast). The integration and system tests should be executed only once an hour, or at night, as they take longer to execute.
Make the app’s install as automated/fast as possible
Everyone should be able to get the latest version of the application. If it’s an executable, there should be a place where you can find the install on the source control. If it’s a website, there should be a script or an easy way to install the website.
Everyone can see what’s happening
Continuous Integration is all about communication, so you want to ensure that everyone can easily see the state of the system and the changes that have been made to it. A best practice is to mention on each commit the ID of the task. Also, the CI server should show you the builds when they failed, and what’s on the mainline.
After the build finishes, you should be able to run a script that deploys the software to test/production environment. You can learn more about this way of thinking here: Continuous delivery.
A: What are the advantages of using continuous integration?
Integration bugs are detected early and are easy to track down due to small change sets. This saves both time and money over the lifespan of a project.
Avoids the last-minute chaos that happens at release dates, when all team members try to check in their slightly incompatible versions.
When unit tests fail or a bug emerges and a developer needs to revert the codebase to a bug-free state without debugging, only a small number of changes are lost (because integration happens frequently).
Constant availability of a “current” build for testing, demo, or release purposes.
Frequent code check-in compels developers to create modular, less complex code.
As a summary, once you have CI in place, you start to fail early, because the integration happens early, and if it doesn’t fail, you know that it didn’t.
A: Cool! But are there any disadvantages of CI?
1. Initial setup time
For small projects, sometimes it is a waste of time. By small projects I’m referring to projects that last for 2 to 3 weeks and involve 1 or 2 people.
2. Need to buy/learn tools needed for Continuous Integration (and sometimes even build servers)
There are a lot of good free tools for Continuous Integration (Jenkins, Team City, Cruise Control), you just need someone to learn how to use them.
You will need a server to run the automated test. Depending on how many tests you need to run, you might need multiple build servers.
3. Need to change the team’s way of working in case they are not used to write unit tests/TDD, or if they are not used to push code often to source control.
4. Need to convince the product owner to allocate more time for the initial development phase.