Most software development today is done in teams working on one or more code repositories managed in a version-control system. Individual developers work on the areas of code that require changes and must decide when to commit their changes back into version control.
Sometimes, the code changes are easy and introduce few risks, so the developer can make the edits and commit with a low risk of interfering teammates working on the same codebase.
But what if the team is working on a bigger feature that will require several days, weeks, or even months of development? When is it appropriate to check in these code changes back into version control? Furthermore, what happens when that code is checked in to ensure that the integrated code developed by the team of developers integrates without build errors or other functionality defects?
Why you need continuous integration (CI)
An intuitive approach is to separate out this work into separate version-control branches. Teams decide on whether to use a single feature branch or create multiple ones for each developer.
Although intuitive, it turns out that this way of working is not optimal. Each feature branch has changes that diverge from the main trunk of development. If these feature branches are used for extended periods of time, the integration can be difficult, time-consuming for resolving conflicts, and error-prone.
Larger teams looking to develop and deploy features quickly sought out a new approach where changes are integrated frequently and then use automation to validate the build and functionality. This is now known as continuous integration (CI).
Continuous integration (CI) defined
Continuous integration is a coding philosophy and related set of practices that drive development teams to implement small changes and check in code to version-control repositories frequently.
Because most modern applications require developing code in different platforms and tools, the team needs a mechanism to integrate and validate their changes. The technical goal of continuous integration is to establish a consistent and automated way to build, package, and test applications. With consistency in the integration process in place, teams are more likely to commit code changes more frequently, which leads to better collaboration and software quality.
How continuous integration (CI) works in practice
Continuous integration is a development philosophy backed by process mechanics and software build automation. When practicing CI, developers commit their code into the version-control repository frequently and most teams have a minimal standard of committing code at least daily.
The rationale behind this is that it’s easier to identify defects and other software quality issues on smaller code differentials rather than larger ones developed over extensive period of times. In addition, when developers work on shorter commit cycles, it is less likely for multiple developers to be editing the same code and requiring a merge when committing.
Teams implementing continuous integration often start with version-control configuration and practice definitions. Even though checking in code is done frequently, features and fixes are implemented on both short and longer time frames. Development teams practicing continuous integration use different techniques to control what features and code is ready for production.
Teams practicing CI prefer committing code into a single development branch or trunk. If feature branches are used, they prefer seeing them have short lives and merged into the development branch frequently.
There are techniques for managing features that require longer development times but are still integrated into the development branch. Some teams also use feature flags, a configuration mechanism to turn on or off features and code at runtime. Features that are still under development are wrapped with feature flags in the code, deployed with the master branch to production, and turned off until they are ready to be used.
The build process itself is then automated by packaging all the software, database and other components. For example, if you were developing a Java application, CI would package all the static web server files such as HTML, CSS, and JavaScript along with the Java application and any database scripts.
Most CI tools let developers kick off builds on demand, triggered by code commits in the version-control repository, or on a defined schedule. Teams need to discuss the build schedule that works best for the size of the team, the number of daily commits expected, and other application considerations. A best practice is to ensure that commits and builds are fast; otherwise, it may impede the progress of teams trying to code fast and commit frequently.
All of this workflow is called a CI pipeline.
Development and testing using continuous integration (CI)
Once a CI pipeline is introduced, it establishes a new workflow for developers. They edit code in their editor or IDE on their own “local” environment. Ideally, they also have a runtime environment running on their local environment and can perform some basic functionality tests. They then run through any automated unit tests that can easily be run on their environments.
With these basic tests validated, they can then commit the code. A CI platform such as Jenkins or Travis can trigger a build that packages all the code elements into one or more built components. The CI platform can then execute any static-code analysis tools and report back to the developers if there were any failure in the build.
If failures are detected, team members must move fast to research and resolve the issue because a failed build pipeline can halt the development activities of the entire team. Many teams track capture metrics on build success and failure rates and use this data to identify development process improvements.
Once the software is packaged, CI tools can then help deliver the built software to a targeted delivery environment, trigger any services required for the delivery such as restarting application servers, and kick off any automated tests. These delivery steps are commonly known as continuous delivery, and the testing functions that are integrated into the full continuous integration and delivery (CI/CD) pipeline are parts of continuous testing.
Teams practicing CI/CD can deliver features and enhancements to users faster. The automation and workflow reduce coding and functional defects. This type of workflow also increases the collaboration across the team and that often drives smarter, more innovative solutions. And it all starts with continuous integration (CI).