Continuous integration happens when software engineering teams frequently integrate their code into a shared branch, usually referred to as main or mainline, with a goal of discovering merge conflicts as quickly as possible, rather than deferring discovery of issues until some later milestone. After pushing up new code, generally, automated tests will run and block the merge if any test fails.
Continuous Integration: Push More Often in Smaller Increments
As part of continuous integration best practices, the goal is to commit code frequently (daily, if not more often) and to build in smaller increments that each focus on a limited scope. Working this way makes it much easier to quickly identify where a code problem exists when a test fails.
For teams new to continuous integration, the first task is to learn how to break large problems down into multiple small increments that can be coded, built and tested independently. This is known as incremental feature development.
The Difference Between Continuous Integration and Continuous Delivery
Often we hear the terms of continuous integration and continuous delivery used together. Continuous integration happens when you automate the process of integrating your code to master to ensure there are no conflicts. Continuous delivery is when you automate the process of taking that shared branch (master/main) and turning it into a deployable release that you can push to production whenever you want. You need continuous integration to do continuous delivery, which is why you frequently see them mentioned together as “CI/CD.”
Continuous Integration is not a Technology; it’s a Practice
If you run the automated tests against your code, it doesn’t necessarily mean you are practicing CI. If you are not doing the integration part, then you are not doing CI. Automated testing happens when you integrate your branch with the main, or a shared branch, not your local branch. This is the fundamental principle of integrating changes. Just because you use Jenkins or CircleCI doesn’t mean you’re doing CI. Some people feel like if they pull from the main, they solve the problem, but here’s why it doesn’t work that way.
The most common pushback on continuous integration is when engineers are afraid of merge conflicts. Sally and Joe are two engineers on the same team who both have their own feature branches they are working on. They are afraid they will have merge conflicts. The way they resolve this is by continually pulling in whatever changes are in main. However, all the code on Sally’s branch is not integrated with all of the code on Joe’s branch because Joe hasn’t shared it yet, and vice versa. Until they both merge to main, they will share the risk of having merge conflicts. By keeping pull requests small and pushing to main frequently, you avoid these conflicts.
Trunk-based development is a modern restatement of CI principles. It takes the original ideas based on continuous integration, development on the shared frequently integrated branch, and enables continuous delivery. There are two types of development in trunk-based development – feature branches and traditional trunk-based development. When developing with a feature branch, a developer or a group of developers will work from a feature branch and merge it to master once the feature is done. In traditional trunk-based development, a developer will divide their work into small chunks and merge that into master many times a day. The difference here is scope.