On Feature Branching vs. Continuous Integration

My summary and takeaways from Martin Fowler’s Patterns for Managing Source Code Branches.

Summary

  • Having a CI pipeline, running tests on every commit is not Continuous Integration.
  • Copying Open Source best practices to commercial development without understanding their context and limitations can be harmful.
  • Feature branches hinder refactoring.
  • Slow code reviews kill Continuous Integration, and it’s a common problem.
  • If you want CI, but can’t do fast code reviews, consider alternatives. Code reviews are the most common but not the only way to warrant the quality of the code.

Semantic conflicts

When you merge your changes back to the master branch, two types of conflicts may occur. Textual conflicts are those that prevent git from merging back your work without resolving them. Semantic conflicts are more subtle and harder to spot. An example of a semantic conflict is when one developer renames or moves a function, and another developer adds new calls for the old version of the function. It’s especially dangerous for Python, and without proper automated tests, unresolved semantic conflict become runtime errors. To minimize the effect of the conflicts, Martin recommends integrating back your changes as often as possible. The rule of thumb is never to have branches that contain more than a day worth of changes.

On integration fear

Integration fear is something that a team develops after a series of unsuccessful integrations. A non-obvious consequence of an integration fear is resisting to refactoring. People don’t make big changes to the code, because they are afraid of breaking someone else’s branches. To break the vicious circle, Martin offers to follow a seemingly controversial slogan if it hurts, makes it more often.

Feature branching vs. Continuous Integration

When you create a new branch for a feature, and then merge and deploy it to production, once it is complete, it’s called “feature branching.” The biggest issue is that it prevents you from integrating back your changes to the codebase quickly. The alternative to this approach is continuous Integration, where you integrate your changes as soon as they become stable and don’t break your master. An interesting takeaway from this is that using a CI/CD tool doesn’t automatically mean that you use “continuous integration.” This misconception became so widespread, though, that people who practice “true CI/CD”, to separate themselves from those who use CI/CD tools and feature branches, invented a different term for the workflow and started calling it “trunk-based development.”

On hiding incomplete features from users

A technique when you implement everything under the hood and update the interface to expose a new feature as the last step is called the “keystone interface.” It was something we used “since forever” to implement new features, but it’s nice to learn a name for this to have a common language. If the keystone interface is impossible or cumbersome, you can resort to feature flags.

On code reviews

The key to continuous Integration is fast merges, but code reviews may slow down the process. Slow turnarounds in code reviews are a common problem and hinder the adoption of CI. Having code reviews with CI is not impossible; for example, Google practices it, but it’s essential to have a culture of quick turnarounds or to consider alternatives. Martin argues that you get away without code reviews without hurting your code quality. For example, you can replace them with pair programming. Another option is to use post-commit code reviews. If the level of trust is high, you can eliminate code reviews, he claims.

On Open Source vs. commercial development

What’s suitable for Open Source is not always the best choice for commercial development. The core difference is the “social structure.” In Open Source, a core maintainer works with multiple occasional contributors, to whom he may or may not trust. Here, feature branching and code reviews become indispensable. In the environment of commercial development, where people share the responsibility, have certain expectations about the code quality and frequency of contribution, you have more freedom to use different techniques, and CI, feature flags, and keystone interface start making more sense.