If you’ve been around software development for a while, you’ve probably come across the term CI/CD. Continuous integration, delivery and deployment are practices that seek to speed up the process of releasing software by shortening feedback loops and automating repetitive tasks. These practices play a key role in making the agile principle of frequently delivering valuable, working software to users a reality.
For teams that have found their rhythm and put in place the tools and processes to support a regular release cycle, a well-functioning CI/CD pipeline is a source of pride; a sign of developers using their tools to improve both their own environment and the end product that they’re creating.
However, for someone new to the practice, transforming your build, test and deployment process into an automated system may seem daunting and unachievable. That doesn’t have to be the case. The beauty of building a CI/CD pipeline is that it lends itself perfectly to being broken down into separate stages, each building on the former. Let’s look at each in turn.
Continuous integration is the practice of running the steps that were traditionally performed during “integration” little and often throughout the development process, rather than waiting until code is complete before bringing it all together and testing it.
Assuming you have more than one person working on a software product – which is the norm for most commercial and open-source software – at some point, you need to combine the pieces each developer has worked on and check that the end result works as intended. With continuous integration that point happens at least once a day, if not more.
The rationale is simple. If you leave integration until all the code has been written, there’s a good chance that you’ll have to spend a considerable amount of time unpicking and rewriting sections of your code to get the solution to build, let alone get it working as intended. Code is complex. Even with detailed upfront design, it’s incredibly difficult to predict exactly how the logic will interact and avoid any issues. The more code there is, the greater the complexity and the more there is to unpick when something doesn’t work.
With continuous integration, your developers share their changes by committing them to source control regularly – at least once a day – and check that the solution builds and passes tests. This means that if something breaks, there are far fewer changes to go through in order to find the source of the problem. Getting feedback quickly also makes it easier to fix any issues, because you haven’t lost the context of what you were doing.
A good CI process requires a few essential ingredients:
Putting all these ingredients together gives you fast and regular feedback on your code. By checking that any change to the codebase – be it a bug fix, refactor or part of a new feature – at least results in a clean build that passes tests – teams can avoid building new work on top of bad foundations, and the inevitable re-work that follows. Implementing continuous integration on its own is one big step towards speeding up the process of delivering working software to your users.
Continuous delivery builds on the foundations of build and test automation established with continuous integration. With continuous delivery, you turn the manual steps used to release a build of your software to production into an automated process.
Whereas in the past there may have been a handoff from your developers to testers, and then from testers to release managers, with continuous delivery, your team (which may include people from a range of disciplines) owns the entire process of building, testing and releasing their product. This comes with several advantages:
The exact steps involved in delivering software to your users – and therefore the required stages in the delivery pipeline – vary according to business and user needs, but it’s common practice to deploy to at least one pre-production environment before they are released into the wild.
These can be testing environments for additional layers of testing, such as security, load and performance tests; sandbox environments for support and sales teams to familiarize themselves with new features; and acceptance testing environments for QA and product professionals to verify that changes work as intended.
With continuous delivery, each successful build is automatically deployed to each of the pre-production environments, with confidence in the quality increasing with every stage. This is a worthwhile goal that takes some investment to put into practice:
With continuous delivery, your team takes responsibility for the delivery of software, and benefits from the timely feedback provided throughout the process. As with continuous integration, the practice can be built up and improved over time.
Continuous deployment takes the practices of continuous integration and delivery to their logical conclusion: if a build passes all previous stages in the pipeline successfully it is automatically released to production. This means that as soon as any change to your software has passed all tests it is delivered to your users. Continuous deployment shortens the feedback loop from code change to use in production, giving your team timely insight into how their changes perform in the real world without having to compromise on quality.
Although automating deployment of software to production is not suitable for every product and organization, it’s worth considering the steps required to get there as each individual element is valuable on its own:
Continuous integration, delivery and deployment all serve the goal of delivering valuable, working software to your users frequently. Taking a little and often approach to integration and releasing makes the process more manageable and means that teams practice the steps regularly and get better at them.
Bringing automation into the mix not only speeds the process up but also makes it more reliable. Each step in the pipeline builds on the previous, and you can choose how much is right for you at any given time and return to build on it later.