Branching–Sprint is Done, Some Features Are Not
Download the latest VS ALM Rangers Branching Guidance Here: http://tfsbranchingguideiii.codeplex.com/
Background – I keep getting this question:
I have a quick question for you on branching in Scrum and feature management.
My client is using Scrum and if we look at the branching structure all sprints branch off of main.
I noticed in your blog that you take one branch to development in sprint 1 and then do merges going forward as you move from sprint to sprint. I must be confused because I was thinking that each sprint was a branch off of Main, with Main being the stable code base that moves forward.
At any rate the question is how do they manage feature releases in sprints?
The example is that you select 10 features for a sprint.
When you get to the end of a sprint, say it is time bound by the business, two features are not ready so you need to move them to the next sprint.
How do we merge and release the 8 ready to release features and hold the other 2 to later sprints.
The code for the 2 not ready to go features is interwoven with the rest of the code in the sprint.
Ideally (in the perfect world) you would solve this at the beginning of the Sprint, not at the end. As your question suggests Sprints are time boxed. During the Sprint Planning meeting, the Sprint Team accepts a certain amount of work (features) from the Product Backlog that the Team agrees they can deliver as a working increment of code by the end of the Sprint.
One solution might be to begin the Sprint with more than one branch for development. You could split off the *at risk of not finishing* feature(s) into this second Sprint branch at the beginning of the Sprint. In this way, you don’t integrate this *at risk* feature with the rest of the Sprint features until it is complete. If it is not complete at the end of the Sprint, then it is easy to defer this *at risk* feature to the next Sprint, since it never got integrated with (entangled) the other features being delivered by the Sprint Team.
Things are not always ideal, however. Sometimes you don’t know at the start of a Sprint that any particular feature is *at risk* of not being finished within the timeframe of the Sprint. You may not discover until the middle of the Sprint that some dependency or unforeseen level of work prevents you from completing that feature.
What do you do now? You have a single development branch for the Sprint Team, and at the end of the Sprint you decide you can only release eight (8) of the ten (10) features in the Sprint Backlog.
Part of the challenge is figuring out how to untangle the code. In other words, how do I remove two features from the Sprint release. It would be easy if these two features are isolated from other features in the Sprint. Often times this is not the case. You may have a situation where a client in Feature 1 calls a service provided in Feature 2. You decide you cannot deliver Feature 2 at the last minute. But you cannot simply exclude the class that implements Feature 2, because that class also implements Feature 3 that is called by Feature 4, and so on.
Things are never easy in the real world. What I propose is a modified version of cherry picking changesets as ONE way of approaching this problem.
Here is my scenario to illustrate the approach:
In my Team Project (AdvancedDevelopment), I begin with my first branch, Main. My sample application for this scenario is under a folder, Src, within this Main branch:
Before the first Sprint, I branch Main to a development branch, ScrumTeam. This will be the branch where all features for Sprint 1 will be developed:
This is a visualization of my branch hierarchy at this point:
I recognize this is a trivial example, but at the end of the Sprint I have implemented four features, as shown in this History view of the ScrumTeam branch. The last feature I am working on is Feature 4, the Divide service. There are two parts of this service. The actual Divide method implemented an a CalculatorService class, and the code in the Divide button on the client Calculator form that calls the Divide service.
This simple example illustrates a couple of key points. How do I defer Feature 4, Divide to a future Sprint. If I simply exclude the CalculatorService class, I effectively am also excluding *parts* of Features 1, 2, and 3.
Maybe I can remove the code from the class or classes that is not complete and is not ready to be delivered at the end of the Sprint. This is where the difficulty sets in. I want to remove the code, but I don’t want to lose the code. I also want to pick up where I left off in the next Sprint without having to do a lot of work reinstating this code.
First, before making any changes to the code in the ScrumTeam branch to remove Feature 4, I preserve this branch in a new branch. I branch from ScrumTeam to ScrumTeam2.
My branch hierarchy now looks like this (a three-level hierarchy)
Having preserved the changes for Feature 4 in the ScrumTeam2 branch,
The current state of the code in the ScrumTeam branch is broken, since Feature 4 is not complete.
Next, I need to remove this Feature 4 from the code I am about to release at the end of the Sprint.
I have several options at this point:
- Roll back the entire branch to a prior point in time before development on Feature 4 began. But the probability is that rolling back the entire branch will also remove enhancements for other Features I do not want to lose.
- Do a Cherry Pick merge from ScrumTeam to Main, leaving the changesets for Feature 4 behind (not part of the merge). But this may be harder than you think. There may not be a single point in time, or selection of a set of changesets that removes Feature 4 and only Feature 4. More than likely there will be remnants of Feature 4 included in the merge that you do not want, or pieces of other features left behind that you do want. Doing a cherry picking merge into Main will likely require additional work in Main fixing things up before Main becomes stable again.
- I can edit all of the files that were changed to implement Feature 4, commenting out these changes and checking them in. This is likely to be a labor intensive effort, but it may be a very viable approach to removing a feature.
It may or may not be easy to remove Feature 4 without manually editing one more classes. In my case, Feature 4 was implemented and checked-in as changeset 270, as you can see from the previous History view of the ScrumTeam branch.
If you view this changes using Changeset tracking you can see that it was also in the new ScrumTeam2 branch, that I created to preserve this change:
If you view Changeset Details for this changeset, you can see that it involves multiple files. I may not want to remove all of the changes that are in this changeset.
I determine that I want to roll-back changes to one of the affected files, Calculator.cs, but not the other. From the Solution Explorer, I can view the history for just this one file:
Next I check-out this file for edit:
Next I get the version of this file prior to the implementation of Feature 4 (Divide). This is Changeset 270:
When I get a prior version of a file from the server, I get a merge conflict dialog such as this:
Here you can see that the local version and the server version are at different change points.
A merge conflict dialog allows me to select which version I want to end up with:
Changeset 270 (on the right) does not have Feature 4 (Divide) implemented, while changeset 271 (on the left) does. It is this feature that we want to omit from the release. Therefore, I will select the code from the right panel to return this file to the state it was in when changeset 270 was checked-in.
Once all conflicts are resolved, I proceed to the next step:
After checking in this change, I have a new changeset in the ScrumTeam branch, which removes Feature 4 (Divide) from the code about to be released.:
The key point here, is that I am removing Feature 4 from a development branch and testing the remaining features before I merge the development branch to the Main branch. This allows me to keep Main as stable as possible:
Before I merge the development branch (ScrumTeam) to Main, I do one final merge from Main to the ScrumTeam branch:
The merge from Main to ScrumTeam is a forward integration of any changes that may have been made to Main since it was last branched or merged to the ScrumTeam branch. Doing this allows you to test the integration of these changes in the development branch first and then merge the development branch into the Main branch. Main remains stable, and integration changes are tested in development.
The next step is merge ScrumTeam to Main (reverse integration):
The final steps of the Sprint should be to complete testing and stabilize Main. Then release Main.
Now you are almost ready to begin the next Sprint. At this point, the new branch, ScrumTeam2 has the code for Feature 4 (Divide) where you ended the prior Sprint, but before you removed this feature from the release.
You might consider merging ScrumTeam2 to ScrumTeam, so that the next Sprint can continue using the original development folder,ScrumTeam
In conclusion, it is not always possible to know at the beginning of a Sprint exactly how long it will take to complete the feature in the Sprint Backlog. Since Sprints are time boxed, it is generally not allowed to extend the duration of a Sprint. The alternative is generally to move unfinished features to a future Sprint. This is not easy.
The tendency for some is to do a cherry picking merge from the Sprint development branch to the Main branch. But this is risky and reduces the stability of the Main branch. Another approach might be to merge the Sprint development branch (latest version including the incomplete features) to Main and then remove these features from the Main branch. Again this reduces the stability of the Main branch.
The approach I prefer is to create a new development branch to preserve the state of the unfinished features, and then to remove these features from the Sprint development branch prior to merging it in Main. This isolates the instability of this process to the development branch(es) and allows you to keep the Main branch stable.
This is not only a challenge for Scrum projects. There are many occasions where a release needs to go out the door even though some features are not complete. Effectively moving these unfinished features to a new branch and releasing the completed features is the approach taken in this article.
The hard part in all of this is really unrelated to branching. It is “How do I remove an unfinished feature from my code”. There is no easy answer here. I have suggested that in some cases you might be able to roll-back changes to individual files. In other cases you may need to individually edit files to remove remnants of an unfinished feature.
I don’t have all the answers. I tried keeping my Sprint team *after school* and making them finish on time, but that didn’t work either.
Download the latest VS ALM Rangers Branching Guidance Here: http://tfsbranchingguideiii.codeplex.com/