Imagine that you are visiting the production line of a major car manufacturer. You enter the production hall and see no assembly line, no manufacturing robots, no quality assurance: instead, everyone just appears to be tinkering.
After a few years of production, the various parts are combined into a car and handed over to the plant manager for acceptance. They test-drive it for a few meters, after which the car gives up the ghost.
Fortunately the automotive industry doesn’t work this way – and it shouldn’t look like this in software development either.
This is because “assembly line”, “manufacturing robots” and “quality assurance” have already arrived in the world of software development, in the form of deployment pipelines, build automation and automated tests.
The deployment pipeline ensures that any changes we make to our software as developers reach the user, and as quickly as possible.
Code quality and functionality are tested along the way: in the best case this is fully automated.
It is important that every change is fed directly into the entire system. We achieve this as follows.
Everything from build script to test files is managed using a versioning system such as Git.
Why do we do this?
Because it ensures that all changes are traceable, including those to the infrastructure or the build process, and everything can be edited from anywhere at the push of a button.
A simplified branching strategy can look like this:
Development is shown by the Develop branch. As soon as a release is pending, a version number is assigned and merged to Testing. This branch is for test purposes only: after the software has passed its automated tests, it is delivered to test users.
Problems and bugs with the version are then resolved exclusively on this branch and then merged back to Develop. On the Develop branch work can continue in parallel on new features for the next release.
If the test phase is successful, the Testing branch passes the software on to the Release branch and the software is delivered to end users.
Tools such as Gradle and Maven allow the software to be built on a build server both locally and automatically. After each code change, a build process is triggered to ensure that the change compiles successfully.
This is the first test of a change before it goes forward to testing.
Component and integration tests ensure that the code does what it should and doesn’t change existing functionality.
Any new functionality must be covered by tests, to guard against future changes unintentionally impairing them. Automated tests should run in an environment that is closest to the production environment, and manual testing should be kept to a minimum.
After all, who wants to do manual testing?
Frameworks such as Espresso (Android) and SWTBot (Java) can remove most of the manual workload.
After the code has successfully passed its tests it will be delivered to users, again automated as far as possible.
For example, if the software is an Android app, it will be published on the Play Store and users will receive an update notification.
In the Eclipse environment, users will get the update via the corresponding update site.
There are now enough tools to help automate delivery: for example, Jenkins and Co offer various plug-ins to support this.
Building on the branching strategy, a simplified deployment pipeline can look like this:
Delivery to test users is shown as optional. The ideal is that all functionalities are covered by automated testing, completely eliminating manual testing.
The most important thing in the diagram, however, is the feedback loop. Feedback ensures that we always know whether we are moving in the right direction: the faster the feedback, the better.
In the fictitious automotive example at the start of this article, feedback came much too late and the individual parts were assembled only at the end. This more or less ensured the delivery of a non-functional product.
A deployment pipeline of the sort described here allows us to achieve the goal of releasing software at the push of a button at any time.
The basic idea behind this is described well in the Agile Manifesto:
Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.
This is made possible by:
- Continuous integration
- Fast feedback
- Sound testing
A “green” build status guarantees us that everything works in the best way. This warranty depends solely on the structure of the deployment pipeline and the quality of the testing. Methods such as test-driven development can be helpful here.