At Don’t Panic Labs, we build a lot of software. Much of it is for new greenfield projects, but we also do a good amount of brownfield improvement projects. But regardless of the type of project, we want certain things in place, and a big one of those items is automated builds.
Automated builds are just one of those things that are essential for successful projects. Builds are probably a little like the Design Stamina Hypothesis by Martin Fowler. With the Design Stamina Hypothesis, Martin argues that you can maybe move faster initially without design, but you will quickly topple over as the size of the system grows. Builds are much the same. You can move faster initially without them, but you won’t sustain the pace without a good build process in hand.
Most of our applications are built using Azure Dev Ops, but build systems are pretty much the same across platforms. The features will be the same, but many of the details vary.
With code management, builds, and releases, there are many things you want to get in place. Each aspect has many important details. Here I will cover a few of those details.
Code management is critical to good development practices. And many code branching strategies can be used. We typically use either feature branch strategy (one branch per feature) or more of a git flow strategy, which better supports multiple environments and longer QA cycles. Both options are viable, but the decision is often a reflection of the project and its needs.
Another important aspect of code management is enforcing that someone reviews all PRs (Pull Requests) going into the system. We typically run our projects where the Dev Lead is the person responsible for looking at the code before it is merged into the mainline code. This sort of rule in Dev Ops is configured using a “branch policy.”
These branch policies are one of the most important things you can configure. But part of that is ensuring that the builds are passing. In the case of the image below, we require two builds to potentially pass on the build. There is a “Path Filter,” which means the build must pass if code matching that path has changed.
But to force builds to pass, we must have some builds. For one of our projects, we have the following builds configured. Some of the builds focus on actually building the code to run the code. Some of the builds, labeled PR, are only used for verifying the code should be allowed to merge, should we allow the PR to be completed.
Builds in Azure Dev Ops are often configured as .yml files. These files contain many steps that the build will go through.
The build files often complete many steps. Some of these steps build the code. Some steps run automated tests against the code.
We have continued to expand these steps over time. We have added a step that runs a tool that evaluates our code for quality and security problems. This static analysis is just another way to ensure we are building quality solutions.
We have added another step recently to our process. This step runs Google Chrome’s Lighthouse tool against our site automatically. This tool analyzes our web solutions from a variety of aspects such as performance and accessibility. We can now actually fail builds if we don’t fall below a performance or accessibility threshold.
The last major piece to this is released. Most projects will have multiple release options. We often break up our releases by environment and piece of the solution. This means that we can often easily release just the QA backend or just the QA frontend. But these can be rolled into a single release; we have done that too.
Release in Dev Ops is a big topic, and Azure Dev Ops has UI screens that make the configuration of this pretty easy, especially if you are releasing it into the Azure Cloud.
Configuring code management builds and releases is important if we want to build systems that we can live with over time.
Also, a special thanks to Branden Barber for naming this post.