I’ve been revisiting the work in Software Configuration Management Patterns. The patterns were useful, but teams still seemed to be struggling with branching. I’ve come to realize two things:
The patterns in the book were about tools and technology, but didn’t fully incorporate the impact of planning and team culture.
We might not have done a great job explaining how a Pattern Language approach — where the patterns work together — worked
You are a team member who wants to improve your development process. You realize that your current integration process isn’t working as well as it could. Changes take too long to get delivered, the process is frustrating the developers, and the product owners aren’t comfortable making commitments. You are using a staging approach like GitFlow and the time from start to integration seems long. You want to simplify the process, with a goal of making it faster, but you are concerned about quality. Your current process is slow, but it seems to identify issues, though to be sure, some issues slip through, and you aren’t delivering the value that you feel that you could.
You think that the SCM Patterns approach could work, so you start to change your process so that all changes go to, and all releases come from, the Main Line. Mechanically that’s easy; you can just change how your branching strategy. But you want more than speed. The things that slowed down gave you a sense of control. That control was somewhat illusory; going more slowly doesn’t always mitigate risk to the extent that you think it might, and introduces business risk, so you look to the patterns to maintain a stable Main Line.
The first step is to make it easier for developers to have confidence that what they code and test locally will also work for others and in the production environment. Having the ability to create a Developer Workspace that looks as much like the production as possible, including versions of tools is a big start. 100% match may not be easy, but you can avoid many obvious errors.
While committing from a Developer Workspace to the Main Line might be your eventual goal, you still see some benefit from using branches, albeit differently that you had in the past. Two kinds of branches you’ll use are a Release Line — which is where you will keep track of the current release in case you need to deploy a fix; you don’t expect to make changes to the code in the Release Line , but it’s there in cases your in a spot where delivery from the Main Line won’t be timely enough. For feature work you will use a short lived Task Branch.
To keep the team on the same page about the rules for using branches, you document a Codeline Policy and add some simple enforcement mechanisms in the SCM system. The mechanisms you add shouldn’t interfere with work, but rather serve as a reminder of your agreements,
The bottleneck in many processes — and where teams go wrong with Task Branches — is getting work integrated to the Main Line quickly. You want to plan work so that each Task Branch implements a Small Development Task that is likely to get completed and merged in a day or so.
For each Small Development Task developers write Unit Tests to both provide a goal (for new tests) and also confirm that your change isn’t breaking anything else. Unit Tests, while valuable, make assumptions about interfaces. To provide a sanity check that the contract the units tests assume didn’t break the team also writes some lightweight Integration Tests.
Small Development Tasks mean that you will be committing consistent units of work, but the work will not implement a complete feature. In some cases that work won’t be visible but in others in may be. To avoid unexpected behavior you can use Feature Flags to hide work in progress in certain environments. You realize that a Modular Architecture makes feature flags easier to implement.
When a Small Development Tasks is complete and the Task Branch Is ready to merge you define a Merge Request process which includes a Code Review to allow for knowledge sharing, feedback about design and implementation. In the past the team seemed to spend a lot of effort commenting on style and formatting issues rather than design (of tests and the feature) and how the work addresses the product need. You introduce Automated Checks to catch these kinds of issues, not to mention to confirm that all the automated tests pass. These automated checks can run as part of an Integration Buildthat runs as part of the Merge Request process as well as the after a merge to the Main Line.
Small Development Tasks are quicker to implement which can reduce the time from coding to start of the Merge Request, but one of the pain points in your old process was the time to get feedback and approval. You want the reviews to be prompt and relevant; reviews should be about how the code addresses the feature work and not the first time the reviewer encounters the design or the goals. Asking the team, you discover that one reason that reviews are slow and lower quality is because the team is spread too thin and it’s hard to prioritize getting context and feedback. You decide that, rather than trying to make progress on multiple parallel work items, you you start each development cycle with a Team Focus, around competing a Product Backlog Item. This makes it easier to prioritize review, and the people doing the review have the context they need to understand the problems.
You realize that when you move fast things will break. And that’s OK, since no one is perfect and most failures will be related to things you haven’t anticipated. Once issues are addressed you’d like the team to focus on doing better next time, so you want to encourage an inspect and adapt mindset, and avoid a culture of blame; you do what you can to create a Retrospective Culture. A Retrospective Culture means having retrospectives, but also incorporating the values of retrospectives into daily work.
At each step of the process change, as your implementation of the patterns improved your delivery speed improved, and the quality didn’t seem to suffer; any mistakes that happened were small and no worse than(and often less severe) that errors that survived the old process. There is still more to do, and eventually you can further streamline your process. You realize that, while there were technical changes to be made, what was holding you back before was not giving enough credit to how planning and design interacted with technical practices; Improving one can help, but working through the pipeline got the big wins.
This was a hypothetical scenario — heavily compressed— though inspired by real experiences. The value of patterns over other approaches is that patterns nudge you into considering relationships.