I frequently recommend the ALM Ranger’s Branching and Merging Guidance to clients as a base of understanding when evolving a strategy that best meets the client’s source control needs. When working with agile methodologies like Scrum, the right strategy can help you raise the bar on quality and efficiency while cutting potential waste.
So, what’s the big deal on a branching and merging strategy using Scrum instead of waterfall? The short answer is simplicity and continuous integration. Overall I stress the importance of simplicity. It is one of the principles of the Agile Manifesto; Simplicity–the art of maximizing the amount of work not done–is essential.
Let’s start with the simplest strategy: Develop on the Mainline. For a small team and simple projects this may be all that you need. You should Label all important builds and releases; anything you might go back to.
• Ensures that all code is continuously integrated
• Ensures that developers pick up each others’ changes immediately
• Avoids “merge hell” and “integration hell” at end of the project
For more complex projects you’ll want more isolation of stable released and potentially releasable code from day-to-day development activity. The Basic Branch Plan addresses that. Main contains stable code for testing and potentially releasable increments meeting the team’s definition of done.
The Development branch provides isolation for day-to-day development work. As code is developed, unit tested and integration tested it can be merged into Main for functional and user acceptance testing. Everyone codes and checks in to Development. Enabling continuous integration or gated check-in builds ensures that everything builds and stays integrated as it is checked in. CI builds should include some test automation like all unit tests. Nightly builds should include automated integration tests. Consider also including layer validation and code analysis.
While labels on Main is a simple way to track releases, a release branch provides isolation for code actually put into production. This helps for rapid response in the event show stopping issues/bugs are discovered. It also provides an easy audit trail if you include a snapshot of everything required to rebuild the release including component code and relevant architectural artifacts.
Additional releases can be supported by labels identifying specific release drops on a continuous release branch or by additional peer release branches from Main. Your specific operational requirements should be your guide as to which option is best.
As a general guideline, always strive for simplicity. Branching is easy while merging is hard, especially if you don’t do it often. So, check in development work frequently; at least every day. When checking in, as a best practice, you should associate your check-in with one work item. Check-ins against multiple work items make things hard to track later on and suggests not focusing on one sprint backlog item at a time.
For releases, if a hotfix is required, you can quickly create a HotFix branch from Release, make the code fix, test it, and put in to production. Always follow up with a merge back to Main and from Main to Development so your whole code base is up to date. At this point, the HotFix branch is done, it has served its purpose so turn it off by locking. Here is a Basic Branch Plan, Web Option where the HotFix branch is created only if needed.
For packaged software planning for Service Packs and Hot Fixes might be more appropriate by creating the branches along with the release branch as detailed in the ALM Rangers guidance.
Don’t try to “boil the ocean” by having too many things going on at once. How does this show up in source control? Feature branches are a typical smell. Typically feature branches are an indication that product backlog items haven’t been decomposed sufficiently to produce working increments of functionality in a single sprint. Occasionally there may be times when you need the isolation of a branch within a sprint; so do it if you need to but frequently merge other development activity to keep changes small and more easily managed when you integrate back. Good decomposition of PBI’s and SBI’s minimizes the need for feature isolation. Get it in one sprint.
And, don’t create test branches. You need good test environments, either physical or virtualized where you can deploy new builds at least daily for functional and user acceptance testing but branching for test is extra work and complexity. Labels provide everything you need.
For multiple Scrum teams integrating work continuously is really important, in order to avoid “merge hell,” but requires some hard work. You should try to all work from the same Development branch. It will require extra work frequently getting latest and merging changes from other teams. This realistically works when there is some functional separation in PBI’s that each team works on and good scrum of scrums interaction. There probably will come a time when you need separate team branches. That implies even more hard work for frequent merging and scrum of scrums communication. Continuous integration is a must do. Don’t defer team integration until the end of a sprint.
Here are some architectural considerations to compliment an agile source control strategy:
-
Keeping Your Application Releasable
-
Continuous Integration
-
Continuous Delivery Strategies
-
Hide new functionality until it is finished
-
Make all changes incrementally as a series
-
Use branch by abstraction for large-scale changes
-
Use components to decouple parts of application
-
-
You benefit by having deployable code for functional testing throughout the sprint
Abstraction Layers
-
Improves your architecture, avoids brittle implementations
-
May require refactoring of existing code
-
then you can more easily implement constantly improving technology
-
-
Create new implementation
-
Update abstraction layer to delegate to new implementation
-
Remove old implementation
-
-
Do you use Interface-driven Programming?
-
Objects should depend on interfaces not concrete types
-
Don’t write your class to use AzureStoragePersonRepository
-
Write the class to code against IPersonRepository
-
-
Dependencies
-
Build-time and run-time
-
Components – you control the code
-
May be frequently updated
-
Need to avoid “Dependency Hell”
-
Dividing your codebase into Components
-
Not necessarily the same as N-Tier
-
Pipelining components
-
-
-
Libraries – you don’t control the code
-
Usually less frequently updated
-
Architectural benefits
-
Loosely coupled, well-encapsulated, collaborating components is good design
-
More efficient collaboration and feedback when working on large systems
-
Avoids the use of complex branching strategies
-
Minimizes serious problems in integrating large applications
Continuous Integration
-
Why is this important?
-
Your code always builds
-
Automated tests validate quality
-
You can deploy working software
-
-
Everybody checks in to Mainline at least once a day
-
If you are not merging into Mainline at least every day you are not doing continuous integration
Keeping your branching structure clean and simple sounds easy but involves work and attention to detail. Detail in right sizing PBI’s and SBI’s, and detail in frequent check-in and merging. Combined with some architectural best practices you’ll benefit with continuously integrated, high quality potentially shippable code.