Applications change (or should change) pretty much every day (some maybe every hour!). I think I was one of the early adopters of Microsoft’s Visual Studio Team Services (VSTS). It significantly improved my control over the code, even on projects that I was the only developer. Back then in 2013, VSTS by default used Team Foundation Version Control rather than Git and I started to use TFSC pretty much as the version control system for all my projects. These days, even Microsoft has set Git as the default version control system in VSTS.
True Story: I first learned about Team Services and then GitHub in my career! Weird right?
I personally have started to move toward Git version control in my newer projects, but I still deal with TFVC. I wanted to document some techniques I have learned to better manage my work, individually or as part of a team. In this post, by “business” I mean any stakeholder, business unit, or individual who needs a feature in the application. It can even be the developer.
As soon as the barebones of any application is created, and the business have an understanding of the project potential, change in the business requirements are inevitable. The business wants a certain feature live (let’s just say an edit to a static text in an MVC web application view - 5 minutes development), while the developer is working on another feature which would probably take a month to finish. A single code base application is doomed to stay in development, until all the features are stable enough to be pushed to production. Or even worse, there will be nasty if-then-else statements or unnecessary database configuration settings which will enable or disable unfinished features if they are deployed to production prematurely. To solve this, there are many branching strategies that can be used to manage first, how features/bugs will be developed and second, how they are deployed to testing and production environments.
The following diagram is a demonstration of how I usually implement the branching strategy in my projects. Note that I am using Team Foundation Version Control.
Team Foundation Version Control (TFVC) uses a single, centralized server repository to track and version files. Local changes are always checked in to the central server where other developers can get the latest changes.
In the image above, each rectangle is a branch and each happy face is a [happy] developer. Each solution starts by creating a Main branch. Main branch always contains the most stable development code. If a developer is starting a new user story, they can always find the most stable version of the code in the Main branch and start from there.
I think of implementing a new feature or user story as a two-step procedure. First step (blue branches) is to have a strategy to develop the features/user stories without having any conflict with other team members. The second step (green branches) is to move the implemented features/user stories to the UAT (User Acceptance Test) and Production (Prestage) environments.
Note: I am using features and user stories interchangeably. It really depends on the size of the project and project manager preferences how features are broken down and implemented. I will give some examples on how I would break the project to smaller features/user stories.
Feature/User Story Development:
Each feature/user story is implemented in a new Dev branch. Dev branches are created by branching out (blue arrows) from Main branch. This allows multiple developers/teams to work on various user stories, without worrying about conflicts (provided that user stories are defined with separation of concerns in mind!). A Dev branch does not mean only one developer will be working on that branch. Multiple developers can work on the same Dev branch to implement a certain feature/user story.
When a user story is completely developed in each Dev branch, it can be merged back to the Main branch (green arrows) and optionally, the Dev branch can be deleted. In larger teams, Dev branches can also be branched out to further Dev branches. Creating Dev branches based on each feature/user story not only builds this mentality that the application is divided into smaller components with well-defined boundaries, but also enables managing code conflicts between branches/multiple-developers much easier. For example, the diagram shows three Dev branches. Assuming there are three developers working on the same project, if they all work on the Main branch, with every code check-in, they might have to handle a code conflict because another developer might have made changes to the file. But if each developer works on a separate Dev branch, resolving conflicts would only happen once each Dev branch is merged back to the Main branch.
Now this all seem to be redundant and unnecessary. And I do agree. But as the team grows and the project gets complicated, creating some extra branches and then merging them back would significantly outweigh the headache of constantly resolving conflicts in each code check-in. Think about that .csproj file that changes every time a C# class is added to the project. And if you were thinking about why we don’t apply a policy that only one developer can change a file at a time, think about your poor colleague who is waiting for you to finally check that file in! When I am working on a small project which I am the only developer, I usually have one Dev branch. Unless I am working on two completely separate modules at the same time, which is very unlikely in the same project.
UAT (User Acceptance Test)/Production (Prestage) Deployment:
To have features and user stories to be tested and deployed in a controlled manner, I create a UAT branch from the Main branch, and a Production branch from the UAT branch. These branches are never directly modified on the developer machines. Always change sets should be moved in the following direction:
Main Branch -> UAT Branch -> Production Branch
This will allow features/user stories to be tested on the UAT environment and then deployed to production environment in a staged manner. I deliberately made UAT box smaller that the Main box and Production box smaller than the UAT box to show the flow of the features from Main branch to Production branch. For example, if there are five features in the Main branch, there could be four of them merged to the UAT branch for testing, and of those four, only two of them merged into Production branch, ready to be deployed.
Also, note that having separate branches for UAT and Production environments allows us to have different build configurations and ideally continues integration when we are ready to deploy the changes to UAT and Production environments.
I'd be happy to get some feedback about this branching strategy if you are dealing with the same branching concerns. In the next post I will explain how I manage my development work using user stories, features and tasks.