Tags: , | Posted by RTomlinson on 5/22/2012 5:19 AM | Comments (0)

The software release process usually involves the deployment of a mixture of bug fixes and feature releases. Bug fixes usually come more frequently than features (or large abstractions) and software teams often hit the decision point to consider how they release small fixes when larger/longer fixes or features are in development. In an environment where the team are doing branch by feature then the pain is eased somewhat. Features are done in completely seperate branches are more often than not, using this branching strategy, fixes are done on the mainline (trunk). In a team where continuous delivery or continuous deployments are employed then the problem becomes more complex.

Release branching

Release branching involved creating a completely seperate branch where production ready code (or potential production ready code) is merged to and deployed from.

With this strategy the benefit is that the release manager can merge over only the chosen revisions that contain bug fixes and satisfaction comes from knowing only known revisions are applied and more importantly feature revisions are excluded.

Adopting continuous delivery/deployment means that this adds a manual step to the process. It's also not error proof as it's often difficult to exclude feature revisions that are checked in and the management and maintenence, over time, can become painful.

Builds, tests and deployments can then be done from the "stable" release branch to promote to staging or live (production) environments and development environments can continue to use trunk.

Branch by abstraction with feature toggles

Another method that can be employed is to use a mixture of branch by abstraction with feature toggling. This allows you to maintain a single trunk (WIN!!) and apply bug fixes on the trunk but larger or longer fixes of features can be effectively toggled off until they are ready to be deployed. The team can continue to fix and check in without having to worry that a half implemented feature will make it to live.

Branch by abstraction involves abstracting classes away from their implementation whilst in a development environment yet still maintaining the current class in the live environment. In practical terms that could mean creating a new class that implements an interface and (if using IoC) inject your feature class rather than the existing implementation.

Given the scenario whereby we're implementing a new feature for card payments:

  1. We would create a completely new concrete implementation of ICardWithdrawalService as FeatureXCardWithdrawalService.
  2. Create a configuration toggle. This could simply be an app setting of true/false in a Web.Config or App.Config with a transform for each environment targetted.
  3. At the point of IoC bootstrapping register the FeatureXCardWithdrawalService instead of the existing implementation to be injected.
  4. Where view (front end view) specific feature changes are applied the same toggle can be checked (ideally using a central helper to manage these).

Developers and release managers need not be concerned with branching and merging with this strategy and thus time is saved in doing so. However, concerns come from knowing when a toggle should be employed and the management of toggles throughout the codebase. Developers should be encourages to checkin early and often and it could be tempting to reduce the amount of toggles by not checking work in for longer fixes until it is complete.

The quality gate

Both strategies are not without dangers. The decision as to which is best is very much dependant on the product, the team, the release strategy (and amount of releases), the environment etc. The key in both is the quality gates at each step in the continuous delivery/deployment process. Ensuring that each stage of the test pyramid provides adequate coverage or your product and your existing features will define the quality and readiness of a release.

Further Reading