Modern businesses require a short time to market to keep their competitive advantage. This means the software development process needs to be agile. In order to support maximum agility and especially when working in (multiple) teams it is smart to work in branches rather than work on the main model.
In this article we are going to focus on working with feature branches whilst still being able to go through the complete DTAP flow and have the ability to apply hotfixes if the need arises.
As a quick recap, a branch is a separate version of your application model, created from a specific point in time, that allows developers to make independent changes, fixes, and updates without affecting the main version. Branches are used to isolate new features, bug fixes, and other development work, and later merge them back into the main version when they are ready to be released. This allows multiple developers to work on different aspects of the application simultaneously, promoting collaboration and efficient development.
A few major advantages when working this way:
- Improved organization: Provide a clear structure for how branches should be created, named, and merged, making it easier to manage code and track changes.
- Increased collaboration: By establishing a clear process for developing and releasing code, you make it easier for multiple team members to work together without stepping on each other's toes.
- Better quality: Creating different types of branches helps to ensure that the application is thoroughly tested and reviewed before being used in production.
- Faster releases: Streamlining the development process this way helps teams release software more quickly and with greater confidence.
- Better support for bug fixing: Separate hotfix branches make it easy to fix bugs without affecting ongoing development work.
In this article we’ll first explore the theory of working with feature branches within the Software Factory. Once the theory has been explained, we are going to focus on the how-to and work with an example. Please note, this article assumes you have one running production version of your application. Working with multiple (live) application versions is possible but outside the scope of what we are discussing.
Theory
The image below paints a picture of how to approach the development in feature branches utilizing branching and merging within the Software Factory. There are two types of branches:
- Default branches (main-, release candidate- and develop branch)
- Always available
- Infinite life-span
- Used for testing and validation purposes
- Supporting branches (feature- and hotfix branches)
- Available when required
- Temporary
- Used for development as well as testing
Main branch
Origin branch: -
Merges to: Release branch
Branches to: Release branch, Hotfix branch
DTAP: Production
The main branch is where your application model starts, (named) versions of this branch are what is running in production. No development should take place in this branch.
The only activity around this branch is monitoring and ultimately releasing new (named) versions to production.
Release candidate branch
Origin branch: Main branch
Merges to: Main branch, Develop branch
Branches to: Develop branch
DTAP: Acceptance
The Release (candidate) branch starts from the main branch and is used for pre-release testing. It primarily receives updates from the development branch and is where new features are integrated and various tests are performed. For example:
- Performance testing
- Load testing
- User acceptance testing
Develop branch
Origin branch: Release branch
Merges to: Release branch, feature branch(es)
Branches to: Feature branch(es)
DTAP: Test
The Develop branch is the final default branch. It is the destination for merging all feature branches. No development occurs within this branch. Typically, two types of tests are carried out in this branch:
- Integration testing
- Regression testing
Supporting branches
The supporting branches is where all of the development takes place. Once the development is finished these branches will be merged to their origin branch in order to get their changes (ultimately) into production. There are two types of supporting branches: Feature branches and Hotfix branches.
Feature branch(es)
Origin branch: Develop branch
Merges to: Develop branch
Branches to: -
DTAP: Development
Feature branches stem from user stories or features assigned to the development team. Each user story or feature should have its own separate Feature branch to allow for independent work and release. Having multiple user stories or features in a single Feature branch increases the likelihood of one feature not being completed, delaying the release of the others in the same branch. Within the feature branch the following activities take place:
- Development
- Validations
- Unit testing
- Code review
- Smoke testing
- Functional testing
Hotfix branch(es)
Origin branch: Main branch
Merges to: Main branch
Branches to: -
DTAP: Development
In an ideal world you would have applications that run flawlessly all of the time and have zero bugs. However reality teaches us that this is not always the case. In these cases fixes need to be applied to either the production or release candidate system in order to provide continuity for the organization. This is where hotfix branches come into play.
Within these branches (minor) fixes can be applied and tested in isolation before putting them in the production version of your application. Because of the urgent nature of these actions all prior activities should take place in these hotfix branches;
- Development / bug fixing
- Validations
- Unit testing
- Code review
- Smoke testing
- Functional testing
- Integration testing
- Regression testing
Feature branches in practice
Now we’ve covered the theory around branching and merging, let’s set it up ourselves. This paragraph assumes you know how the Software Factory works (you can find the correct buttons), if not, please refer to https://docs.thinkwisesoftware.com/docs/sf/overview#introduction-to-models-and-branches.
Initial set up
The first step is to set up the default branches: main, release candidate and develop. The main branch is the first one we set up. Once the Main branch has been created, we can create our first branch based on this Main branch. This will be our Release candidate branch. After the Release branch has been created, we’ll create a branch based on this Release branch. This will be our Develop branch. Once we have done this, we have a situation that looks like this:
First user stories
After the default branches have been created we can focus on some actual development. We have put three user-stories in our sprint and want to start working on these. As discussed in the theory, we cannot do any development in one of the default branches. This means we have to create feature branches. We’ll create three feature branches for our user stories. When we’ve done that, the branches look like this:
First user story is finished
Once the development team is underway, the first user story has been finished. Once finished this work gets merged back into the Develop branch. We end up with this scenario:
I’d like to use something you’ve made
During a stand-up meeting one of the developers of a user story being developed in Feature branch 2 finds out there is some functionality he would like to be able to use that has been made in another Feature branch that has already been finished. In order to use this functionality, he merges the latest version of the Develop branch into his own Feature branch.
Sprint review
Once the sprint is over and the time for sprint review comes. Sprint review can be done based on the Develop branch. This means all finished user stories have been merged back into the Develop branch. In this scenario unfortunately, Feature 3 has not met its Definition of Done yet. This means Feature 3 will not be delivered in this sprint and will therefore not be merged into Develop.
Release candidate and a new sprint
After sprint review, the work that has been done in this sprint has been merged back into the Release branch for some load testing and UAT. At the same time the development team starts their new sprint. They have agreed to finish feature 3 and picked up a new backlog item that will be worked on in a new Feature branch 4.
Ready, set, go!
A milestone has been reached. The first version of the application is ready for production. All tests have been passed in the Release Branch and the application can be released. This means we need to merge the changes from the Release Branch into the Main branch.
Development continues in both active Feature Branches.
Help, we have a bug
Once the application is in production, a critical bug has been found. In order to fix this we need a branch to work in since we cannot do any development in one of the Default branches. To do this, we create a Hotfix branch to apply and test the fix.
Apply the hotfix
Once the bug has been fixed, we need to merge the Hotfix branch back into the Main Branch. Since this fix could also influence future testing and development, we also need to update the Release - and Develop branches. First we merge the Hotfix branch back into the Main branch, then we merge the Main branch into the Release Branch and finally we merge the updated Release branch into the Develop branch so it can be used by current or future Feature Branches.
Next delivery to production
Whilst the application was in production and the fix was applied, the development team carried on in their feature branches. After merging their feature branches back into develop and going trough the Release branch for performance and user acceptance testing, the next release has been merged into main in order to be applied to production.
TL/DR
- Use feature branches in an agile environment
- Three default branches based on each other
- Main (production)
- Release (acceptance)
- Develop (test)
- Feature branches based on develop
- Regular development in feature branches
- Hotfix branches based on main for production issues