7 Best Practices for Weekly App Update Releases

7 Best Practices for Weekly App Update Releases
Photo by James Yarema / Unsplash

Releasing an app update can be a daunting task. It requires implementing new features, of course, but also rigorous quality assurance testing, dealing with merge conflicts (especially when multiple engineers are involved), preparing update metadata and screenshots, submitting the update to the App Store, and finally spreading the news through various channels once it's approved.

It's easy to make it happen only when it's absolutely necessary, but then you'll encounter more significant issues. For example, you may have a critical issue that needs to be fixed ASAP, and you know the fix is a one-liner. However, you can't just deploy it because one of the dependencies is outdated and doesn't compile with the current tools. Or, your team has been developing a feature for a while, and you were asked to prepare a demo build on short notice. If it takes days to prepare the release build, you might not be able to deliver the demo in time.

"If it hurts, do it more frequently, and bring the pain forward."
— Continuous Delivery, p. 26

Having said that, I believe a weekly app release cadence works really well for my team. In this article, I'll explain why this approach works and share some best practices we've learned over time.


Concepts

According to Jez Humble and David Farley, making frequent, automated releases of software is essential to address the issues outlined above.

  • Automated: The release process should be fully automated, reducing the need for manual intervention. Manual processes introduce the risk of errors, especially when executed repeatedly.
  • Frequent: Frequent releases result in smaller changes between updates, significantly reducing risks such as the number of issues, support tickets, and the effort required to address them.

If we want to release app updates as frequently as possible, how often should we do it? The answer may vary depending on your team and audience, but based on our experience, a weekly release schedule has been ideal for my team. Here's why:

  1. App Store reviews for iOS apps typically take 1-2 days, making it challenging to release daily updates, for example.
  2. Our team strives for excellence during the weekend church experiences, aiming for the most stable app state during that time.
  3. Even after automating the process, there are a few things that require manual attention, so we have to consider that overhead.

Our weekly release cadence follows this schedule:

  • Friday: Submission to TestFlight and the App Store.
  • Saturday - Sunday: Testing on TestFlight.
  • Monday: Release.

Best Practices

Here are some best practices that have proven to be valuable when releasing apps on a weekly basis. For context, my team primarily focuses on mobile apps for iOS and Android platforms.

1. Automate Almost Everything

Errors are more likely to occur when release pipelines are not fully automated. If any part of the process is manual, you must create and maintain documentation. Additionally, manual releases require experts, and you can't confidently release anything if they are out of the office.

2. Establish a Rapid Feedback Loop

Every change should trigger the feedback process as soon as possible. Below are a few CI steps we use to notify the team if there is an issue:

  • Linting: We utilize linters for Swift and Kotlin. If the new code contains bad formatting, the CI will fail and stop. Maintaining good code formatting is invaluable when you're trying to resolve a critical issue and helps you read the existing code as efficiently as possible. The best time to fix bad formatting is when you first write the code.
  • Build Checks: We detect compile errors and notify the author. A state that cannot be built is one of the most urgent issues we want to address as soon as possible.
  • Review App Builds: When changes are pushed to the remote repository and a merge request is created, an automatic review app build is generated. This allows the team to test the feature without merging the changes into the integration branch.
  • Testing: We run unit tests, UI tests, and behavior-based acceptance tests. This helps us avoid regression issues without the need for manual testing repeatedly. However, we still conduct exploratory testing from time to time, as writing and maintaining automated tests for everything can be costly.

3. Implement Multiple Environments

Testing should be possible without the risk of data destruction or incurring costs. For instance, testing features such as account deletion or payment processing with real credit card data should not be performed in the production environment.

Our team has adopted the following types of environments:

  1. Production
    This is the live environment, where the app is available to the public. Any updates or changes made to the app must be thoroughly tested before they are released to this environment, as any errors or issues in the production environment can result in a poor user experience and negative reviews.
  2. Staging
    The staging environment is an intermediary environment that sits between development and production. This environment should mimic the production environment as closely as possible so that testing in the staging environment can cover most, if not all, aspects of the production environment.
  3. Develop
    The development environment is where most of the app development work takes place. This environment is used by developers to write and test code, debug issues, and experiment with new features and functionality.

4. Always Maintain Working State

Kent Beck pioneered the concept of continuous integration in his book, Extreme Programming Explained. Without continuous integration, your app remains broken until someone validates its behavior. With continuous integration, your app is consistently proven to work.

We do code reviews for all code changes, and we also do QA testing before merging them. Using review apps is beneficial for testing features without the need to merge them initially. Consequently, we have been able to maintain our integration branch in a state ready for release whenever necessary.

5. Keep Tools and Dependencies Up-to-Date

Have you ever found yourself in a situation where you've been using an older version of Xcode to avoid compile errors, only to discover that Apple will soon require the newer version for app updates starting next month? The migration to support the latest Xcode suddenly becomes a roadblock, forcing you to halt everything you were working on.

Does it sound too real? Over time, I've learned that the best way to keep our dependencies up-to-date is to do it as often as possible. I can use the same quote here again:

"If it hurts, do it more frequently, and bring the pain forward."— Continuous Delivery, p. 26

We use the latest Xcode version from the App Store and perform the migration whenever Apple releases a new version. This does bring inconvenience from time to time, as some of these updates may disrupt your CI. However, doing it at that point is easier than waiting, let's say, a year, as a larger migration may be necessary due to the accumulation of changes over time.

We also perform dependency updates on a quarterly basis. This involves listing all major and minor dependencies and creating engineering tasks to update their versions, typically to the latest available or the version just below it.

These updates can be easily overlooked, especially from a product perspective, as they often demand significant effort, with the primary goal being to ensure that everything functions as it did before. Therefore, it's challenging to prioritize them over the next shiny new features. However, as engineers, it is our responsibility to remind the team of the importance of maintaining an up-to-date codebase. This ensures that when important changes need to be deployed, the process can be swift and smooth.

6. Create and Submit Store Builds on Fridays

On Fridays, we make a release branch from the integration branch. We then build and send store builds to TestFlight and the App Store review queue by the end of the day. Fridays are ideal for our team for the following reasons:

  1. We can test the latest integration build during our most crucial time of the week: weekend services. Automatic TestFlight app automatic updates make this process even more effortless.
  2. App Store reviews typically take 1-2 days, so there is no need to wait for their approval during our workdays.

Using a release branch is helpful when we receive an app review rejection and need to make specific tweaks while keeping the rest of the app the same.

7. Release the App on Mondays

Every Monday is reserved for the release of the app. We execute this release once it receives approval and does not encounter any reported issues during the weekend. This approach ensures that the team has maximum time to address newly discovered issues following the release. Once again, it's because the weekend services represent the most crucial time for our team.

Also, it provides enough time for the app to propagate. Over time, we've learned that we achieve 80% adoption of the new version within 4-5 days of the app's release. It takes 30 days to reach 90% adoption of the new version. Releasing the app on Monday allows enough time to reach 80% adoption by the weekend.


Conclusion

Establishing a weekly app release cadence has proven to be a game-changer for our development team. By automating key processes, fostering a culture of continuous integration, and maintaining a well-structured feedback loop, we've not only increased our release frequency but also significantly reduced the risks associated with updates. We've also leveraged the advantages of maintaining multiple environments and ensuring that our codebase, tools, and dependencies stay up-to-date. Moreover, our strategic use of Fridays for creating release branches and Mondays for app releases has streamlined our workflow and allowed us to maximize the impact of our updates.

The results have been impressive, with a faster path to adoption for new versions and the ability to address issues promptly. By implementing these best practices, we've not only embraced the idea of "releasing early and often," but we've also made it a core part of our development culture.

Weekly cadence may not be the right fit for every team, but my hope is that our experiences will provide you with some insights to explore the benefits of frequent releases and adapt the cadence that works best for your team.