6 Tips for Managing Software Releases
Building code and releasing code are not the same, despite what some may think. Most organizations become proficient at the act of creating software including writing code, adding new features, fixing bugs, etc. However, many struggle mightily when it comes to releasing what they’ve made into the world. I would argue releasing code is somewhat of an afterthought for most development teams; it continues despite the recent rise of the DevOps culture. In an effort to kick-start improvements in your own organization, here’s a summary of best practices and lessons-learned regarding software releases.
#1 – Use a dedicated and isolated build environment
A release destined for the hands of end users should never originate from a developer’s machine. While this should go without saying, we still see it. Most developers are curious by nature. As a consequence, the development environment on their machine is rarely stable over time. This instability directly translates into unpredictability and inconsistency in the build artifacts that are produced.
Internal “Build Servers” have fallen out of favor, being replaced by SaaS solutions or containerization. By their nature, these modern implementations further support the principle of an isolated build environment as a best practice. Ideally, your team would create these build environments on-demand from a known starting point. This provides a clean-slate for construction of each and every build of your software.
#2 – Make releases as small as possible
Any change to your application will incur risk, so it makes sense that a large release with many changes is inherently more risky than a small release. However, most organizations tend to have long release cycles because of the difficulty involved, so the idea of releasing more frequently might at first appear to be counter intuitive. Reasons for painful software releases can link back to manual steps, human error, or lack of documented, repeatable processes. Releasing more often will force teams to develop the muscles (automation) to reduce this pain over time.
For most complex systems, it’s much safer and reliable to take a slow and steady stair-step approach, rather than big-bang shocks to the system. What constitutes large or small is relative to the scale of the system. Adapt releases to a size that is appropriate for your needs.
#3 – Create an automated build pipeline
The only way to increase the frequency and reliability of software releases is through automation. Fully automate all steps, dependencies, and resources needed to test and package your product. This means that all points after a developer checks-in a new change, to the final, deliverable artifacts should be able to run unattended at the click of a button, if not triggered by a commit to source control. Configuration files and necessary prerequisites to build and test should also be checked into source control – not just the source code.
The goal is for version control to manage your application and the files needed for the build pipeline. This allows you to track changes over time and revert bad commits.
#4 – Use named releases for planning purposes (aka: hurricane names)
Instead of cryptic version strings, like v2.5.3, pick an alphabetic naming strategy and use it for all planned releases – Albert, Bob, Charles. Your organization will be working on these releases for weeks (hopefully not months) and team members need to communicate efficiently throughout. Backlog items move freely between planned releases with this strategy. They avoid being bogged down in “should the next release be a full version bump, or a patch?” Let the content of the release determine the final version number, rather than what you planned in the past.
#5 – Always use a unique build number
It would be difficult to improve upon Jeff Atwood’s analogy, “think of version numbers as dog tags for your code.” They are mostly decorative, occasionally annoying, but absolutely vital when something goes wrong.
The following scenario can attribute to a considerable amount of churn:
• A developer fixes a bug and makes a new build to deliver to a tester.
• The tester rejects the build because the problem is still occurring.
•The tester states, “it’s still broken.”
• Next, the two go around in circles because they were unknowingly testing the old version. Both parties assumed they were testing the new version without checking.
Usually after many exasperated hours, someone stumbles upon the fact that the old version was still installed and testing the actual new build is successful.
#6 – Embed a human-readable date in the version number
At a certain point, traditional version numbers (MAJOR.MINOR.PATCH) lose their meaning to non-technical users. “I’m on version 2.1.5,” on its own, provides very little information to most end-users. If the version number is something like 2015.12.1, we have some intuition when compared to a more recent build, 2020.3.1 – “Wow, I’m using a really old build.”
Where to start?
These ideas can help your organization bring the practice release management to the forefront. That said, don’t try to implement all of these changes at once. Just as focusing on smaller releases reduces risk, the same principle should apply to organizational changes. For example, if your organization currently releases software every six months, first aim to cut the release time in half. Once a three month cycle has become the new normal, reduce the size and time again and so on. Implementing these techniques iteratively will help smooth out the process and avoid shocks to the system.