Promoting SoC Through Application Layering

Creating a layered design in an application is a fundamental element of modern software architecture. The goal is to promote the Separation of Concerns (SoC) design principle. Separation of Concerns The ideas behind SoC date back to Dijkstra's 1974 paper "On the role of scientific thought" . In computer science, separation of concerns (sometimes abbreviated as SoC) is a design principle for separating a computer program into distinct sections. Each section addresses a separate concern, a set of information that affects the code of a computer program. A concern can be as general as "the details of the hardware for an application", or as specific as "the name of which class to instantiate". A program that embodies SoC well is called a modular program. Modularity, and hence separation of concerns, is achieved by encapsulating information inside a section of code that has a well-defined interface. - Wikipedia SoC is a broad design principal th...

To Release From Main or To NOT Release From Main?

The generally accepted best practice for managing branches and releases in Git is to release from the Main/Master branch.

That strategy is great for simple and/or smaller projects (Microservices and simple applications). However, for more complex and/or monolithic applications, this strategy can create some issues.

There are often scenarios where multiple feature branches are in progress simultaneously. These branches may be released together or independently. Additionally, there may be bug fix branches interspersed with the feature branches. Each release to production must pass a full round of automated unit testing and User Acceptance Testing (UAT) before deployment.

Some questions may be: 

  • Does testing occur against Main/Master? Or does it occur against the Feature branch?
  • If a Feature branch is tested, where do you deploy from? Do you perform a Pull Request to Main/Master and release from there? If so, won't you be releasing technically "untested" code?
  • How do you test multiple Feature branches and Bug Fix branches simultaneously? Do you merge them all to Main/Master and test from there?
  • Where is the"golden copy" of the application? As in, is there a branch that represents the currently deployed application or are tags in Git sufficient to mark each release?

Microsoft has a great article on Git branching: Adopt a Git branching strategy.

Combining Microsoft's recommendations with real world experience for complex application development, using a Release branch strategy is generally a good solution.

The strategy is to create a Release branch that has all of the desired features and/or bug fixes. Before testing, do a Pull Request from Main/Master to the Release branch. Also perform Pull Requests from any complete Feature or Bug Fix branches into the Release branch. Fully test the Release branch; this should include unit testing, deployment to a QA environment for integration testing (if possible), followed by user acceptance testing (if required). When it's time to release to production, release the application directly from the Release branch. Once the Release branch is in Production, do a Pull Request from the Release branch up to Main/Master.

Below is a fairly common example showing two features being developed in parallel along with some bug fixes; and two Release branches (one for March and one for May).

There are some downsides to this strategy. 

The obvious downside being that Main/Master is never actually deployed or fully tested. In theory, this is generally acceptable, as long as each Release branch is fully tested. One solution to limit issues is to enable automated unit testing and CI/CD against Main/Master, so every Pull Request into Main/Master gets some level of testing.

Branch management also becomes more critical. Abandoned Release, Feature, and Bug Fix branches need to be pruned consistently; meaning a single individual needs to have an all-encompassing view of the application in order to keep the repository organized. Additionally, deployment pipelines can become more complicated as they must regularly release from difference branches. Again, it is critical to keep the deployment pipelines organized when using a Release branch strategy.

Overall, despite the downsides, this solution does work well for large and/or complicated applications.