Trunk-Based Development for Mobile Apps

Mirella Batista

--

Mobile developers, this one is for you!

Imagine the joy of a code base easily maintained in a ready-to-build state, where development teams follow a simplified code integration process and experience a marked reduction in build issues while ensuring the quality and stability of their published mobile applications. Now stop imagining because all that is achievable with trunk-based development.

In this post, I’ll introduce the concept of trunk-based development and how mobile development teams can leverage this development workflow to achieve continuous integration of their code and better control over their mobile apps even outside of the deployment cycle.

Trunk-Based Development Is a Branching Model

A branching model is a development workflow for teams collaboratively contributing to source code in a remote repository, usually hosted in GitHub. It is the agreement the team members have made for how they will collaborate on the code in their repo and how they will deploy their application. When a team follows a branching model, everyone knows what, when, and where to commit code to their application repo, which helps teams maintain a smooth cadence for development.

How Mobile Teams Benefit from Adopting a Branching Model

A mobile app developer does not have the option to push code to production at the press of a button or to have a fix immediately appear on a user’s mobile device. True continuous integration/continuous delivery (CI/CD) is impossible because of the specific characteristics of how mobile apps make (or do not make) their way to a user’s device.

When mobile development teams are ready to release their mobile application, they must submit a bundled binary to one of the distributing outlets: Apple Store, Google Play, or a company’s private app store. A mobile app then goes through checks put in place by these and will make its way to a mobile device only when an end-user decides to download and install it. Rollbacks and deploying fixes are next to impossible. Think about this: Once a mobile app has been installed on a user’s device, there is no guarantee that the user will ever update said app.

Mobile development requires a measure twice, cut once approach, and a mobile team must be deliberate in how they respond to the need for higher code quality standards. While a branching model does not replace unit testing and scanning of a mobile application’s source code for vulnerabilities, it can provide the guardrails that help mobile teams achieve the smooth workflows that enable them to produce and deliver high-quality code. As a branching model, trunk-based development simplifies team workflows, improves collaboration, helps shorten development time, and supports a cadence of continuous delivery.

Trunk-Based Development

In our GitHub repo, we’ll have a main branch. The main branch is what was previously called master and the industry has moved away from that terminology.

In a traditional branching model, a team will maintain at least a development branch and a QA branch in addition to the main branch. Developers will work on branches created off the development branch. Whenever they complete whatever they are working on, after however long it takes, they will attempt to merge to development, then development will be merged to QA, and from QA, the work will eventually be merged to Main.

Traditional Tiered Branching Model

The trunk-based development branching model is relatively straightforward compared to what I just described. It reduces the hierarchy of branches normally present in a traditional branching strategy. In trunk-based development, we think of the main branch as the trunk. We want the code in Main to be kept in a ready-to-build state, and we want to avoid experimenting on Main or committing directly to Main.

Trunk-Based Development Branching Model

When a developer gets an assignment to work on a feature or a bug, they will create a new branch cloned from Main and work on this new branch. The new branch is what we refer to as a short-lived feature branch. The name says it all: a short-lived copy. These branches are meant to be short-lived, so they don’t fall too far behind everything that continues on the Main branch as the rest of the team merges code.

Feature Flags

As developers work with a short-lived feature branch, they should make small and frequent code commits and merge often to Main. That means that developers will merge partially complete features into Main, and this is where feature flags come in! Feature flags allow a team to keep Main in a ready-to-build state while enabling them to integrate their code into Main continuously.

A feature flag is nothing but a variable serving as a toggle. Developers will combine the use of a feature flag with an if statement, wrapping new code development in an if block that executes only when a feature flag value is set to true. Otherwise, that code is dormant.

Feature Flag

Let’s say a developer is working on adding new functionality to a mobile app. This functionality will be triggered when a user taps on a button on the UI. The developer will create a feature flag named isNewButtonActive, set the value of the feature flag to true or false, and wrap up all new code in an if statement that checks for the value of the feature flag. If the isNewButtonActive value is false, the new code and functionality will remain dormant and effectively hidden. This code can be merged to Main and can be included in a production release with the feature flag set to off. Even in production, the code will remain dormant, hidden from your end-users.

Continuous Integration

Trunk-based development combined with feature flags allows developers to practice continuous code integration. The CI in CI/CD. Continuous code integration is achieved when developers limit the size of their commits and pull requests (PRs) while increasing the frequency. Because PRs will be small, reviews and approvals won’t take long. Code is continuously reviewed, discussed, and merged.

Teams should agree on guidelines that minimize the time needed to get a PR reviewed and approved. For example, a commit can be up to 100 lines of code. If a commit is more than 100 lines of code, the developer should meet personally with the reviewer and walk them through their commit. Furthermore, each commit must have a clear message describing what the code is meant to do.

Continuous integration means that large features that can take several weeks or months to develop can be broken down into small pieces of work and gradually integrated into the Main branch, behind feature flags, until complete. Doing small and frequent commits and merges helps developers to discuss and explain their code while it is still fresh in their minds and also reduces the number of merge conflicts because code does not sit isolated in someone’s computer for a long time.

Releases and Hotfixes

Trunk-based development simplifies releases and hotfixes. Teams can follow a cadence of set release dates for their mobile apps or an app can be released anytime, creating a release branch by branching off Main, provided all unfinished code is behind feature flags set to the off state.

Release Branches

Once the release branch is created, the developers continue adding code to Main while quality assurance tests are done on the version of the app in the Release branch. Fixes for issues found in the Release branch should be first merged into Main, then cherry-picked to the Release branch.

Hotfix Branches

Say a team has released their mobile app, and, despite their careful QA testing, they discover that the latest release introduced an issue into production. If it is decided that a hotfix needs to be released, a team will branch off the Release branch to create a Hotfix branch. The fix for the production issue should be merged into Main, then cherry-picked into the Hotfix branch and tested there before release.

Remote Configuration

Until now, I’ve talked about feature flag values being hardcoded and globally accessible within the app. However, teams can leverage cloud-based offerings where mobile apps can connect to and retrieve the values for the feature flags.

Remote Configuration

Remote configuration gives mobile application development teams more control over their mobile apps running on their end-user devices. Functionality for alert banners and messages in a mobile app can be triggered remotely. Complete features can be hidden from end-user devices at the flip of a toggle, and mobile apps can even have logic in place to enable AB testing.

Hopefully, those examples spark ideas of what mobile development teams can do with remote configuration. I’m not going to go into specific cloud/remote configuration services. A simple web search for “remote configuration for mobile” will return information on several cloud-based offerings available.

Technical Debt

Feature flags can eventually create a dead code path if the feature flag will no longer be used. Teams should consider this as technical debt because dead code paths are code smells and should be addressed. It is a good practice to create an item in a team’s backlog to evaluate whether a feature flag has served its purpose and whether the dead code should be cleaned up.

So there you go. I’ve explained the benefits of trunk-based development as a branching strategy for mobile development. I’ve explained how leveraging feature flags allows developers to follow a trunk-based development model and how feature flags take on a power of their own with the remote configuration secret sauce.

If you are interested in learning more about trunk-based development, I recommend: https://trunkbaseddevelopment.com/

--

--