Improving Release Management
Based on experience on multiple projects in the past, I've settled upon a CVS method of working that seems to work best. The process is based on code branching. It's important to note that I've seen projects go very wrong through the improper use if branching, so I've come up with a recipe that works well.
Even if you don't maintain parallel programming teams, there may be times when you'll need to work on two versions of the same application at one time. For instance, when a software release is deployed to production, it's important that you be able to get to the exact source code and all supporting files that were used for that release, even if coding has progressed since then, in case bugs are found in production.
To achieve this, development is done in the HEAD (sometime called the "tip") of the source code repository, and each release cycle must be performed in its own branch. This branch, uniquely labeled to represent the particular release being tested/deployed, is created when development is complete, and a comprehensive quality-assurance (QA) cycle is about to begin prior to its release to production.
Also note that there is only one active source code branch at any one time. This rule should be strictly followed. The branch is created when development is "feature complete," and a QA cycle is about to begin. The following steps discuss this procedure in more detail:
- Create a new branch with the release cycle/version/name as part of the branch name (i.e., BRANCH_MYAPP_v_2_34)
- Important note: At this time, development for the next release can begin in the HEAD again. The branch ensures you can get back to this release's specific code base.
- Pull the latest code from the branch created in step 1, and do a complete build on a trusted machine. This can be a dedicated build machine, or a developer's machine that is considered the build master.
- Place the resulting binaries back into the CVS branch.
- Label the branch with a unique label for that release and build (i.e., MYAPP_v_2_34_build_001)
- Pull the binaries and all supporting files (i.e. configuration files) from the CVS branch using the label created in step 4, and deploy to your QA servers.
- If bugs are found, perform code fixes in the branch (not the HEAD), and repeat the QA cycle starting from step 2. Note that this will result in an incremented label in step four due to the new build number.
- When the release passes QA, pull the binaries and supporting files from the branch using the most recent label created in step 4, and deploy to production.
- Merge the branch back into the CVS HEAD, paying careful attention to any potential conflicts (remember that development may have started for the next release there). In my experience conflicts are rare, and are easily resolved when they do occur. However, they should never be done automatically; it's crucial to review the conflicts and make careful decisions to resolve them.
- Development for the next release can continue in the CVS HEAD, and this process is repeated when that cycle is "code complete."
Because the code in a branch is merged into the HEAD when it passes QA and is released, the HEAD is sure to have all of the code changes (bug fixes) made during the QA cycle, even if development has progressed in the HEAD for the next release. Also, if a problem arises in an earlier release, because the branches are not deleted or removed in any way, the precise code base is always available for every release ever made. This guarantees that you can recreate any revision of your application at any point in the future.
This process works well for a one development group working on one release at a time, as well as multiple development groups working on multiple releases at a time. The most efficient approach to follow involves two parallel development groups, where you align the releases so that when one development group is in a QA/bug fix/release cycle, the second development group is coding the next release. As a result, if you plan each release to be roughly equal in terms size and development time, the second development group should be entering QA as the first development group deploys its release and begins coding the next version.
This swapping of roles between the development groups (when one is coding, the other is testing/bug fixing) ensures the most efficient use of resources, and that the release frequency is increased. This process has the following advantages:
- Both of your development groups work at a reasonable pace
- You achieve twice as many software releases in a normal time frame
- New features made available to users sooner, without sacrificing quality
Next, let's dive deeper into improvements to the software deployment process. These improvements build from the process we just examined. The example we'll follow is for enterprise (hosted) applications, but the process should apply to any type of software.
Improving Release Deployment
The CVS development and branching procedures outlined in the previous section are important to ensure that the exact code and configuration for every release can be retrieved when needed. It also provides an efficient process for parallel development groups to follow. However, it's also important that software deployment be done efficiently, and without error. To make this process painless and error-free, the solution I use is to combine Ant scripts with CVS, using the proper software release label.
Ant scripts that take as parameters the task/software name, the software's CVS label, and the server name to deploy to, make for a quick, easy, and precise deployment process. For example, look at the following command:
> ant deploy.xml -Dcvsuser=ebruno -Dlabel=MYAPP_2_234_build_012 - Denvironment_name=prodserver_01 deploy_app
In this command, the first parameter is the Ant script; next is the CVS username to use; next is the CVS label to use to pull the release; next is the server to deploy to; and the final parameter is the ant task itself. In this case, the Ant task, deploy_app, clearly indicates that we are deploying software.