Walk Before You Run: Understanding CI in CD
With the buzz around Continuous Delivery (CD) these days it might seem like an antiquated notion to even speak of, let alone write about Continuous Integration (CI). However, in the many conversations we’ve had with organizations looking to implement CD or in the midst of an implementation (and stumbling), it has become rather clear to us that there exists a wide chasm that needs to be bridged on the foundational aspects that support an organization’s desire to adopt CD. CI is a key supporting construct whose principles are still not understood/implemented with sufficient clarity, and hence worth a revisit.
Integration is the process of eliciting fast, automated feedback on the correctness of your application every time there is a change to the code.
Delivery builds upon the earlier concept by providing fast, automated feedback on the correctness and production readiness of your application every time there is a change to code, infrastructure, or configuration.
The premise behind CD is that software is always deployable. Hmm. Sounds familiar. Anyone glance at the principles behind the Agile Manifesto lately? The very first principle states:
“Our highest priority is to satisfy the customer – through early and continuous delivery – of valuable software.”
It seems CD is less a newfangled notion and more about realizing a long-standing promise. And, the key prerequisites toward realizing this ideal are:
- Continuous Integration
- Comprehensive Configuration Management
- Multi-level Automated Testing
The rest of the post delves a little deeper into the CI aspect of CD.
CI is the process of executing the software Build-Deploy-Test (BDT) cycle frequently with minimal manual intervention with the underlying principle as one of constant communication and feedback among team members. Martin Fowler, a well-known author and speaker on software development topics, describes it as:
“…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.”
If It Hurts, Bring the Pain Forward
CI provides a framework for detecting software integration errors quickly, allowing teams to develop unified software more rapidly while ameliorating the dreaded “big bang” integrations and associated code merge misery that plague many software teams. CI aims to eliminate integration uncertainty by encouraging developers to make frequent integration of their work part of the daily development activity. It does not eliminate the challenging activity of code merge and conflict resolution – it sharply reduces the pain associated with infrequent merges by demanding small, incremental merges daily. It trades debilitating pain later for some pain today.
How does it change what the developer does daily?
CI is a mindset, and while the process can be executed in manual fashion, most teams use a tool to enforce the discipline. The figure below depicts the typical integration cycle within the context of using such a tool – a CI server – to help implement the practice.
- The day begins with the developer pulling the latest codebase from the source control repository
- Then there is the typical development activity (guided by automated unit tests preferably)
- Developer is ready to commit code into the repository and might need to communicate the intent to the team
- Updates local working copy with code from the repository (since others may have updated the code stream)
- Merges code and resolves any conflicts locally
- Builds and ensures tests pass locally
- Commits code into the repository
- The CI server “listens” for changes in the code repository. Any change triggers the build and test cycle automatically, and the results communicated to the team members in an automated fashion. A broken or “red” build (either due to compilation or test failures) is indicative of an integration failure and should be tended to immediately. Bringing the CI environment to “green” should become the top priority of the developer/team.
Where do we begin?
As is evident from the description of the integration cycle, the adoption of CI mandates certain practices that are necessary to make CI possible and effective.
Single Source Repository
All source code files, database scripts, dependent libraries, property files needed to build the deployable software artifacts need to be version controlled in some sort of a source control system since the CI server monitors changes to the code repository to trigger the BDT cycle. As rudimentary as this constraint might seem, there remain some organizations that haven’t yet reached that stage of maturity where centralized source control and version management is a given.
Even with centralized source control in place, many organizations still rely upon manual processes to creating deployable software artifacts that involve coordination across organizational silos and team members. Since the premise of CI is to kick off a build without human intervention, it necessitates the creation of a single-click build capability in order to automate the BDT cycle. The rule of thumb prescribed for build automation is to be able to stand-up a running system from scratch.
While not a precondition, test automation plays a key role in providing reliable feedback to the team that the software components are not only integrated but also working correctly. Don’t let test automation get in the way of moving towards CI, but its best not to wait too long to introduce automated tests into the mix to truly harness the benefits of the practice.
What are some of the “best practices”?
- Frequent commits to a common code stream
- Disallow commits into a “broken” build
- A “broken” build on CI should be attended to immediately and its resolution should be of utmost priority
- Address long-running builds. 10-15 minutes is ideal; more than 20-30 min is the outside limit for meaningful frequent integration. The shorter the cycle the better. The most likely culprit could be integration tests masquerading as unit tests. Stage the builds if necessary.
- Rebuild the database (build from zero)
- Build/deploy/test in production-like platform
- Provide capability to QA to deploy targeted builds to higher-level environments
What are some of the misconceptions?
CI is the Same as the Nightly Build
Not true. A nightly build produces software artifacts for external consumption i.e., QA functional testing, product review, etc. XP took the notion of a nightly build and pushed it to an extreme by suggesting frequent intra-day code synchronization check points as a means for a developer to converse with the system to ensure that he/she has done his/her part, at least for the time being. It is not to say that there isn’t value in the nightly build, and in fact CI could be used to generate it in a staged manner.
We Are Not Agile, So We Don’t Do CI
While the term “Continuous Integration” was introduced by Extreme Programming (XP) the underlying concept of more frequent integration predates XP. In fact, CI is one of the least controversial of the practices espoused in XP and its guiding principles are relevant whether an organization has embraced agile or not.
Frequent Deployment Disruptive
Adoption of CI doesn’t necessarily mean an automatic deployment of each every “green” build to higher-level environments whether requested or not. A good CI implementation should provide the capability such that QA or other team members can deploy targeted builds on the CI server into other environments as needed.
In the Automation for the people series, Paul Duvall lists some common CI anti-patterns and misconceptions and how to avoid them.
The greatest benefit of CI is that of reduced risk. Too often the issues with delayed and infrequent integration manifest during the latter part of the project, when the stakes are high and pressure to deliver is greatest. Further, it paves the way for automation at many levels, starting with build automation, test automation and more recently continuous delivery/continuous deployment, all of which aim to foster the creation of higher quality software, faster.
- Continuous Integration: Improving Software Quality and Reducing Risk – Duvall, P & Matyas, S & Glover, A
- Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation – Humble, J & Farlay, D