Wednesday, April 17, 2019

A simple branching strategy to work in CI/CD and Code Review Policy in Agile

Code review is an important step in DevOps to catch any error before the code goes into the production. In a Continuous Integration/Continuous Delivery (CI/CD) model, code review is even important. Tools exist to enforce code review policy in place at source. The idea is that any code change must first be reviewed before the changes are merged to the master branch with the assumption that the master branch only contains duly reviewed code to ensure quality. This article assumes the use of GIT for source control and Team Foundation Server (TFS) or Azure DevOps for build/release and CI/CD. 

When working as a developer, one wants to test the code before it can be reviewed. For testing, in most cases, the build and release pipelines are configured to listen to changes in the master branch. In such cases, a code review policy can overburden the developers by requiring to review a code that may not work correctly. In addition, now the developers need to wait for code review even before testing the code in the dev environment. This may become more important if the system we are developing cannot be tested in the local machines. This also has the potential for slowing down the development activity and sprint velocity which is counter-intuitive to agile. This can cause frustration among developers as well as reviewers. These can be avoided by creating a workflow where developers are able to create, build, deploy and test in a dev environment before requesting a code review. 

This workflow can be handled by creating an improvement in branching and merging strategies and by creating two build/release pipelines. For simplicity, let calls these pipelines as master and dev (e.g., dev for development). The master pipeline is triggered by the changes in the master branch while dev pipeline is triggered by changes in the dev branch. A developer can create a dev branch out of the master, make changes, builds and deploys using dev pipeline, most likely in the dev server, and makes needed tests and then creates a pull request for merger into master branch after review.  From this point on, the master pipeline kicks in and changes are reflected in all the environments such as dev, demo, uat or production as needed. 

With the above workflow, the code review policy was still enforced in the master branch and developers can make continuous changes in the code and tests before submitting the changes for review and ultimately to merge the changes to the master branch. 

In the minimum, we will be looking to three types of branches, namely master, dev and feature which are briefly described below:

Master Branch
o    Primary branch
o    Code review is always needed. 
o    Must be used to build/release in Prod environment
o    Consider this branch permanent.
o    There exist build and release definitions and CI enabled for all environments

Dev Branch
o    Secondary Branch
o    Ideally, be created from Master
o    Can be forced to use master
o    Does not require code review
o    Must not be used for build/release in Prod Environment
o    Consider this branch temporary. Things can be wiped out from this branch.
o    There exist build and release definition looking into this branch and therefore CI is enabled for this branch to deploy to Dev. For other environments, no automatic release from this branch.
o    This can also be used to quick hot fixes.
o    Just to note, if the merging of dev to master results in the elimination of branch (depending on code review request), creating a dev branch from master and pushing that branch to remote is sufficient.

Other Branches (as needed)
o    Feature branches, branches needed for pbi (product backlog item or an issue), etc
o    Can be created by anybody and can be merged to master or dev branch
o    Ideally, be created off master (but can be created from Dev)
o    Once coding is done, can be pushed to Dev branch for build/release in the dev environment
o    Once all coding is done, a pull request must be made for merger into the master branch
o    These are temporary in the remote. But you can keep it locally. So nature is semi-permanent.
o    With pull request, when this branch is merged to master, it is more than likely the branch will be removed from the remote.

Scenario/use case/process:
Some scenario related to development work is described below:

Working on a PBI 
  • Create a branch from master. Name it appropriately, use pbi or feature or certain keyword so that it can be identified easily.
  • Make necessary code changes.
  • Most likely there is dev branch. If a dev branch does not exist for the rep, create a dev branch. If there are no build and release definition for dev branch, make those as well.
  • Merge your branch to Dev (this will trigger build/release in Dev).
  • If all is well, create a pull request off your branch.


Working PBI and PBI has been postponed for future
  • Created a branch and merged code to Dev. The PBI was postponed for the time being. I need another Dev branch.
  • Keep the feature branch in place. Dev is going to be reset with the master branch. Changes made in dev will be gone.
  • Can do 'Cherry-Picking' to recover some changes and bring it to current code 

Working on the dev branch and need to remove all new changes  
  • Select the dev branch. Point to master branch and reset the dev branch to the selected point in the master branch.
  • If needed keep the local changes to a separate branch



Work on the dev branch, but there is no build or release pipeline for the dev branch
  • Clone the build definition. Rename the definition to *-Dev. In the repo, select 'dev' branch. Do the same in the release. Ensure automatic trigger is only limited to 'dev' environment.



The workflow above works, but with certain assumptions. It is safe to merge master to dev (if developers code is wiped off, they can merge the code again from the feature branch to dev at any time). Thus all the developers should know this possibility so that there is no confusion. However, to make the process frictionless, it would be a good idea to talk in the daily scrum. In most cases, the dev branch does not need to be reset as frequently, but it is ideal to have a current code in dev branch as well to avoid working on an older version of the code and to avoid merge conflict in the future.

If the master cannot be merged with Dev, force merge (this will wipe out conflicts and makes the Dev a copy of master). By forcing the merge, you are avoiding manually correcting the errors that are possibly not needed. The changes in dev can be re-applied from the feature branch if needed.

Git Extension (a tool which provides a much better experience than Git tools in Visual Studio) can be used to create, merge, reset and cherry-pick while implementing the branching strategy. This is free and available at https://git-extensions-documentation.readthedocs.io/en/latest/git_extensions.html