Mature Branching Plan – Branching for Feature Development

Within a Team Project, everything starts with the MAIN branch. This is a consistent theme with all our guidance (https://tfsbranchingguideii.codeplex.com/). The question becomes, when do you need to create one or more branches for development? My answer would be that one goal of a good branch plan is to have the code in MAIN be as stable as possible. You probably want your QA team to be using code from MAIN so they are isolated from ongoing development that is not ready for QA. So anytime you have multiple teams with a separation of responsibilities (such as QA and Development), you probably want to use branching to provide important and necessary isolation between these teams. By creating one or more DEVELOPMENT branches, you allow ongoing feature development to take place while the QA team is testing a more stable version of the software.

Integration (merging) between the MAIN branch and the DEVELOPMENT branches is bidirectional. Generally you want to do frequent merges (forward integrations or FIs) from the MAIN branch to the DEVELOPMENT branches. You want to do merges from MAIN to DEVLOPEMENT when you have a known good state in the MAIN branch.  The principle here is that the longer you go between these FIs, the farther apart the code state in these branches becomes. When you eventually do an FI from MAIN to DEVELOPMENT, you will probably have a lot of change conflicts to deal with at the time of the merge. This is why people tend to dislike branching – the time and effort required to resolve change conflicts. But doing frequent FI merges from MAIN to DEVELOPMENT tends to keep these branches more in sync and avoids the “big bang” change conflict problem.

Changes in a DEVELOPMENT or FEATURE branch are only merged (Reverse Integration) when you reach a predetermined level of quality (quality gates). It would be silly, for example to merge untested code from a DEVELOPMENT branch back to the MAIN branch. Doing so simply defeats the purposes of isolating these branches in the first place. The MAIN branch is no longer as stable as possible, since it is constantly taking untested changes from DEVELOPMENT. Once you reach your quality gates for a feature, then you can merge (RI) the DEVELOPMENT branch back to the MAIN branch. A key point here is that just before doing this merge (RI) from DEVELOPMENT to MAIN, you want to do one last merge (FI) from MAIN to DEVELOPMENT. This allows you to test the integration in the DEVELOPMENT branch and not the MAIN branch.

The question becomes, when do I need more than one DEVELOPMENT branch (e.g. FEATURE TEAM 1, and FEATURE TEAM 2)? Branches are used to isolate separation of responsibilities or other needs for isolation. For example if two teams are working on the same components, but one team is releasing their feature on a different schedule from the second team, it is useful to separate the teams using Feature Branches. There are probably other reasons why you want or need isolation. I would simply ask the question – “what is the benefit of providing this isolation, given that isolation has a cost?” One needs to weigh the relative costs and benefits before unnecessarily complicating the branching plan.

Once again, the costs of isolation generally revolve around the time and effort to integrate changes from different branches. If two developers are working on the same feature, and need to integrate their changes on a regular basis, why aren’t they working in the same branch, and using Workspace isolation? However, if two developers are working on conflicting changes on the same code and are on a different release schedule, they probably  want to integrate their changes when reach a certain point in time. Working in separate branches allows for a more controlled integration process.

There is no right or wrong answer with respect to the number of DEVELOPMENT branches, but there should be consistent criteria applied to the decision as to when and if a new DEVELOPMENT branch is needed.

In addition to trying to keep the code in the MAIN branch as stable as possible, there are other branching / development goals. Key development goals include maximizing, where possible, code velocity and minimizing code latency. There are several techniques and tools one can use to achieve these goals. Test-driven development (TDD) and automated testing help uncover bugs in a DEVELOPMENT branch sooner rather than later. Continuous Integration (CI), for example: build on check-in, gated check-in, and nightly builds, help to ensure that one developer does not slow down other developers in the same branch. Build verification tests (BVTs) combine the benefits of CI with TDD.

When is it appropriate to add another level to the DEVELOPMENT branch tree? Many organizations add an “integration” level between the MAIN branch and multiple FEATURE branches. The problem with this approach is that it tends to increase the cost of branching - the time and effort to do merges and resolve conflicts. By definition, as soon as you add a new level of branching to the branch plan, your code is now in another state (stable in the MAIN branch, under development and not fully tested in the FEATURE branches, and somewhere in between in the INTEGRATION branch. This affects code latency, for example how long it takes to bring a feature change from the FEATURE branch down to the MAIN branch. The more levels a set of changes needs to traverse, the more merges are required, and the result is more merge conflicts that need to be resolved. It may seem like you are achieving a benefit (increasing code velocity in the FEATURE branch and increasing stability in the MAIN branch), but it comes at a cost. Who is doing the merging and conflict resolution? If it is the development team (because they understand the code), maybe you are affecting the teams code velocity while they deal with periodic merges and conflict resolution between the FEATURE branch and the INTEGRATION layer. Each new layer that is introduced adds more merge time and effort (both RI and FI).

To summarize, stick to a two-level branching structure on the DEVELOPMENT side, and add new branches to DEVELOPMENT (as full branches of MAIN) when you understand the cost/benefits of doing this.