Continuous integration (CI) and continuous deployment (CD). That sounds so … fuzzy?
Let’s take a look at CI/CD from an industrialization of IT perspective. Many of our apps are built in a “custom-built” style where a group of developers sit down and build all of the various pieces by hand. Oh, occasionally a piece will be added that someone else built, either internally or externally, but by and large, it is a custom build. You usually don’t even see the end product until it is finished. In the CI/CD world, things are built incrementally, much like an assembly line. Parts one and two go together and then part three is bolted on. At any time you can take that product in the making and get it a spin. Yeah, the analogy is getting pretty thin, so I think I’ll stop here and look at the pieces separately.
Continuous Integration. In software development when you have a stable release, the release upon which all other changes are based, you call this the trunk. When you start to work on a release you call it a branch and when the branch is complete you merge it back into the trunk. Kind of like pruning a tree. Our normal method of developing is to build something so that it is complete and then merge that code back into the trunk when we release. Continuous integration is different, however, in that you quite often don’t have a branch upon which you are making changes, you are making changes to the trunk. You write code, a function or procedure, and you integrate code back into the trunk of the product when you are finished. You don’t wait for a release, you don’t wait for marketing to get all of the mouse pads printed up with the correct URL, you integrate right away. Daily in fact.
This rapid integration causes concerns for some people. Lots of concerns. What if the code is not ready to be released? Then why did you say that you were finished? You integrate code when you are finished writing and testing the code. Not before and not six days later.
But you’re not ready with all of the pieces yet! Then you implement feature flags which state that the feature is not available for public consumption. Each environment in which your application is deployed has a set of feature flags so that you can be testing something in System Test that doesn’t show up in UAT or Production. Continuous integration ensures that everyone has the latest version of the code at all times and that the code is functioning code.
Continuous deployment. Theoretically, every time someone checks code back into the repository, you would compile and send the latest version to a development server. While this is a laudable goal, with larger projects this is unrealistic. So a daily deployment to a development or system test servers works out just as well. Yes, daily. Every single day the code gets compiled and deployed. We know the code should be working (we tested it before committing it back into the repository) so there is no danger of the app not working.
I sense much fear in you. Continuous integration and continuous deployment are missing one piece: continuous testing. Yes, we test the application a lot. Indeed, in a perfect world, we would be testing immediately after we compile. When we deploy onto a system test server when we deploy to a UAT server and even some testing when we deploy to production. Continuous testing means automated testing. If you do enough testing, at enough stages, an application change can go from the developer’s machine all the way into production without a single person manually testing the change.
And how does all this get done? Through automation and standardization.
We know that we need to automate things and continuous integration and continuous deployment give us an idea as to what we need to automate. But is simple automation going to be enough? If you automate a bad process, it’s still a bad process; it just gets done faster. We need to be more flexible, more … agile.