The 5 principles help guide decision making, but there’s also technology and processes you must have in place to adopt Continuous Delivery.
Specifically, there are 7 capabilities needed for a successful adoption:
- Continuous Integration (CI)
- Trunk-based development
- Continuous testing
- Monitoring and observability
- Loosely coupled architecture
- Database change management
- Deployment automation
These technical foundations allow you to build, perform, and refine your processes.
Let’s explore each.
1: Continuous Integration (CI)
Traditionally, developers worked to deadlines or only committed code once they’d finished a feature. Working this way gave build managers time to compile and test their work. This was a manual and methodical process that left developers waiting for feedback and slowed down software delivery.
Instead, Continuous Integration improves commit rates and automates time-intensive and repetitive build tasks.
Rather than waiting for deadlines, developers commit changes to the code repository many times throughout the day. As soon as they do, a build platform (also known as a ‘CI service’) automatically compiles and tests their changes.
If successful, the build platform can package the code for deployment (or trigger packaging). If the build fails its tests, developers know there’s a problem straight away.
The benefits are:
- It’s easier to find and fix problems in small commits
- Developers get almost instant feedback
- No one’s bound by deadlines or change freezes
- Automation’s repetition makes results more predictable
- Everyone gets more time - developers can code without barriers, operations teams can work on more important tasks
- New features move through your deployment pipeline much quicker and more reliably
2: Trunk-based development
Almost all software developers are familiar with ‘distributed development’ thanks to Git. And we wager most development teams already use Git repositories like GitHub or similar services.
Distributed development is hugely important in modern software delivery. It allows developers in large teams to work independently in their own branches before merging into the main source code.
This is great! It means everyone works safely and no one’s work affects anyone else. However, Continuous Delivery still recommends setting some limits with branching with trunk-based development.
Trunk-based development is when developers either:
- Commit code directly into the main branch
- Use 3 or fewer branches and merge into the main branch within 24 hours
The reason for these limits is the longer developers work on separate branches, the higher the risk of merging problems. By committing to the main branch as often as possible, you are:
- More likely to build on the newest code
- Less likely to see developers’ work clashing against each other when merging
3: Continuous testing
We talked about testing as part of Continuous Integration, but testing doesn’t end at a successful build. Testing happens throughout your deployment pipeline and in all environments, including:
- Usability
- User-access testing (UAT)
- Security
- Post-release vulnerabilities
One truth remains with all testing: It should happen often, quickly, and—if possible—automatically. Invest in testing tools to take the load off your teams.
The structure of testing is also important. Strategically run your fastest and automated tests first. That way, if you find a problem, you haven’t wasted effort on slower or manual tests and can use that time elsewhere.
4: Monitoring and observability
Much of operations revolves around tracking infrastructure stability and security. The goal is simple: Ensure services and systems work as expected so you can prevent outages.
Continuous Delivery expands that goal. You should collect data from every possible source and use it to spot all patterns and relationships, not just those affecting performance.
Continuous Delivery also recommends pulling all those metrics into a single tool. Doing so helps you spot relationships easier and react much faster. Plus, it can help direct your improvement efforts.
For example, you could see when a new version causes complaints by tracking software versions and support tickets in one place. Or, by tracking deployments and cloud infrastructure activity, you see the changes making your costs rise.
The data to track depends on your business needs. We recommend experimenting, though, as you might find unexpected but valuable insights.
At the very least, you want to track:
- Infrastructure performance
- Internal process times
- Application feature usage
- Business metrics
5: Loosely coupled architecture
‘Loosely coupled architecture’ is a development structure where teams build apps in separate components.
Each component has:
- Its own infrastructure
- Few dependencies
- Its own deployment pipeline
- Its own team who can do the following without input from others:
- Develop
- Test
- Deploy
- Make decisions
Structuring an application like this means:
- You can deliver updates much quicker as a component’s pipeline is shorter
- Updates shouldn’t delay or impact delivery to other components
Continuous Delivery recommends your development team structure mirrors your application’s architecture.
6: Database change management
Updating a database can be more disruptive or damaging than updating an application. Data changes quickly in modern software delivery and that can affect both deployments and your recovery options.
Say you remove a database column, row, or field between application versions. You could roll back to the previous version if the application update has major problems. A rollback becomes more difficult if the old version relies on the deleted information and users have already made changes.
That’s why it’s important to have strategies to help manage database changes during deployments. Your exact strategy depends on the type of application you develop.
There are a couple of common strategies to help manage database changes.
Have a database for each version
This strategy involves making your app’s database read-only during deployment and making a copy. You then upgrade and change the copy for the new version. Once happy, you redirect all traffic to the new app version.
It’s important to perform each step as quickly as possible. The longer you dwell, the higher the risk of recovery.
Decouple your database changes
When there’s one database for all versions, you can use an ‘expand and contract’ pattern to limit upgrade problems.
With this method, you can add to the database without impacting your application. The downside, however, is you can’t remove anything unless no running version depends on that information.
The pattern itself is to repeat 2 simple steps:
- Make a small change to the database
- Deploy
Let’s look at an example. If you wanted to change the ‘surname’ column’s label to ‘lastname’, you would:
- Add a new ‘lastname’ column to the database, and use a synchronization trigger so ‘lastname’ updates whenever ‘surname’ changes
- Deploy!
- Copy data from ‘surname’ to ‘lastname’
- Deploy!
- Update the application to use ‘lastname’ and remove all references to ‘surname’
- Deploy!
- Delete the synchronization trigger and ‘surname’ column, to prevent mistakes
- Deploy!
7: Deployment automation
Deployment automation helps you deploy more often and reliably, with the same packages and processes throughout a version’s lifecycle.
By automating your deployments, you achieve reliability through repetition. There should be no surprises deploying to Production if you already successfully deployed to Dev and Test.
Automating your deployment processes also helps you avoid human error. You’ll never miss steps or do them out of order. Plus, different teams can trigger deployments and not worry about making mistakes.
Deployment automation, of course, is our business. Take a look at Octopus’s features or sign up for a free trial to see what we can offer.
Help us continuously improve
Please let us know if you have any feedback about this page.