Learning to Think

Release Management Strategy

One of the problems to solve for any development shop is how to keep track of what you ship. Each version of software that you release has a set of changes associated with it. How do you manage all the changes so you know which versions of which files are in any given release?

A solution that we use at my current employer is to combine a Release Management Database with a Version Control System. We use tags in our version control system to track what is in development, what will be shipped, and what has shipped. We have pushed this system as far as doing monthly releases with our enterprise application. I’ll do my best to describe our process for you.

We are an Agile development team, so each feature we choose to implement or each defect we find in the software is managed by a User Story. We document these stories in the release database. Each documented story has a description of the change, testing criteria, implementation notes, etc.. When a story is created, it is assigned to the current Iteration (release). We do not permit stories to be associated with previous releases of the software.

The release database scans the version control system for changes. When it detects a code change, a developer is allowed to associate that change with a particular User Story. When a code change is associated, it is tagged with an ID for the User Story as well as an ID for the Iteration. What you end up with is the following:

  • HEAD: 1.85
  • ITER_127: 1.83
  • DEFECT_828: 1.83
  • DEFECT_820: 1.82
  • ITER_126: 181
  • ITER_125: 1.81
  • ITER_124: 1.81
  • FEATURE_9392: 1.81

Looking at these tags, we can see the history of the changes for this particular file. Release 124 shipped with version 1.81 of the file. I can see that version 1.81 also has the tag FEATURE_9392, which I can look up in my release database for further information or I can search my version control system for other files with that tag. I also see that releases 125 and 126 also are associated with version 1.81 of the file. This means that no changes were associated with it for those two releases. For release 127, version 1.83 is shipped. I see that versions 1.82 and 1.83 were both associated with defects 820 and 828 in our release database. Also of note is that versions 1.84 and 1.85 of the file have been checked in, but are not yet associated with a change. That indicates that a developer has not yet finished work on a feature or defect for the current iteration.

We use a Continuous Integration system to build and test our software. Whenever a change is checked in to version control, a build is started. The build compiles, packages and executes unit tests on the software. The build that is executed for each change retrieves all files tagged as HEAD from the system. We also have a nightly “integration” build to package our software and run additional tests. This build retrieves all files tagged for the current release (i.e. ITER_127), compiles and packages the software for us. In theory, this release should always be shippable as long as the integration tests pass.

This system has served us well for a few years, but it does have its weaknesses. Patches are tracked outside this system. We do not believe that patches are a good way to manage software, but in reality, we do have to do them. We make sure that any time one of our customers does require a patch for an older release that we first integrate the fix or the feature into the current release, then work backward to determine what needs to change to make it work with the older release. It isn’t always easy, but as long as you have a well documented set of changes, it usually is not too difficult. We could likely create a new tagging mechanism that would allow us to track patches as well, but given that we do maybe ten of them a year, it hasn’t been necessary.

Using this method, it is easy for us to have access to any particular build of our system. If a customer upgrades from release 247 to release 249, we can use our version control system easily see differences between our ITER_247 and ITER_249 tags. Once we see the differences, we can refer to the release database for the details in the stories associated with those changes.

We use this system to track code changes, documentation changes, and configuration changes. Everyone from our developers to our QA staff to our managers are familiar with how the release database works, even if they don’t understand the ins and outs of our version control system. This method could be extended to allow for branching with the addition of more tags and a solid branching strategy, but that is a topic we’ve managed to avoid quite happily.