How we tackle Continuous Delivery at Ibuildings
At Ibuildings we strive to implement Continuous Delivery for all our projects. It helps us build quality software that can be controlled and well managed. My colleague Tom talked about Continuous Delivery before. In this article I want to take you through the technical stuff that enables us at Ibuildings to do continuous delivery.
But, what is continuous delivery? In my opinion Martin Fowler does a good job in describing the term.
Continuous Delivery is a software development discipline where you build software in such a way that the software can be released to production at any time.
— Martin Fowler
When software is releasable at any time, testing and deploying is probably automated. Ideally, deploying should be as simple as pushing a button. In that way it’s fully up to the business whether to release or not. But, be aware. There is a catch. When business keeps postponing deployments is it still “continuous”?
To me, Continuous Delivery is all about the process on how you manage and prepare the work. By properly refining the work that needs to be done. Is the work, in our case usually a “user story”, ready for development? Is the work clear, testable and shippable as a whole? If not, refine the story and make sure that it is ready in way that you can ship it to production. But, for this article we only focus on the technical tools.
Once we start developing we’ve basically incorporated three disciplines:
Coding following the GitHub Flow
Continuous Integration for Quality Assurance
Continuous Integration and Automated Deployments, are usually implemented with the help of CI/CD pipelines.
At Ibuildings we use GitHub or GitLab depending on the project. In both cases we follow the GitHub Flow workflow. We are very keen on code reviews. Pushing changes to a feature branch helps us to review and improve the code before it gets merged. We require at least one reviewers’ approval. In order to prevent wasting someone else’s time you have the responsibility to first test your work before you request a review.
A reviewer obviously reviews the code. We look at things like the SOLID principles and DRY to improve the code where we can. Another responsibility for the reviewer is to do manual functional test. This means that the reviewer has to have a working instance of the software. For people on the team this is usually not an issue. In the other case it is the responsibility of the requester to provide a working instance. Ideally, we’ve set this up with so-called Review Apps but that is, unfortunately, not always the case. The use of Review Apps enables you to show your progress to team members. Think of product owners that can have a quick look to verify this is what they want.
When software should be deployable at any time you have to make sure that with every change you can guarantee the quality of the software. While code reviews help guarantee quality, Continuous Integration helps it even further. In our case we’ve automated CI with the help of Travis-CI or GitLab Pipelines. For every change or feature we integrate the code and run the tests. We have a number of static code analysis tools like code style rules, lint checking, mess detection, dependency tracking and checking security vulnerabilities. After running code analysis, we run the tests. Starting with the Unit tests.
Secondly, we run functional tests. This requires a running instance of the software but still mocked with external services. I prefer writing functional tests with Behat but we also use Symfony’s browser kit for Symfony projects and occasionally Browserstack.
If one the tools or tests fails, the build is reported broken and cannot be merged into the main codebase. If all is OK, we finally remove all development dependencies which leaves us with a releasable build artifact.
The final step is to deploy the releasable artifact. We use Ansible for automating the deployments. It integrates nicely with our CI/CD pipelines and often we re-use some of the tasks and roles to provision local development VM’s.
Deployments usually consists of a number of tasks like copying the code, creating release directories running database migrations and clearing caches. There is a nice ansible deployment helper that helps managing the release directories. Most projects have a testing, staging and production environment. Since the environment and deployment steps are practically the same we only have to set it up once. Due to its flexibility I prefer to use the GitLab CI/CD pipelines and with the help of GitLab CI/CD environments we can easily track and manage deployments.
We create a deploy job for every environment in the deploy stage. The job is triggered manually. We use job policies to only allow deploys from builds on the master branch to production. Setting up the jobs and configuring the environments in the GitLab pipelines provides a nice UI on GitLab that enables us releasing to any environment at any time with a simple mouse click.
I hope you found this an interesting read. It describes the way how we at Ibuildings implement continuous delivery. We found that it works best for our teams. Still, we are always looking for ways to improve. We run retrospective meetings order see if we need to improve and change our process. If you have any questions or feedback please leave a comment below.