Editorial Note: Our community blog post series is authored by buddybuild users, and other respected mobile developers. This post is written by Nathan Shaughnessy, Team Lead Developer at FreshBooks.
At FreshBooks, we build tools that help self-employed professionals run their small business with speed, ease and security. Our product saves them hours wasted on tedious paperwork, so they can spend more time doing the things they love, like growing their business.
Because speed is key to our product, we like to release updates to our iOS app often. Our goal is for customers to receive updates as fast as we can build them. To accomplish this, we've created an automated build and release process where updates happen completely on their own. In this post I'll share our release philosophy and what we do to put that philosophy into practice.
How Our “Release Often” Approach Works
We currently release an update of our app every week. We do this because as soon as we've finished a new feature, made an enhancement, or even fixed the smallest bug, we want that change out and on our users’ devices.
The release process is 100% automated. No human is involved. On a particular day of the week, at a particular time of the day, a build of the app is made and tests are run. If everything goes ok, the app is submitted to Apple for review and release on the App Store. This hands-off process allows us to spend more of our time focused on actually building the app.
Here's what our release process looks like today:
This method of releasing is only possible because of the philosophy we adopted for building and releasing the app. The philosophy is quite simply:
“We want to be able to release a new version of the app at any moment, and we want the effort to release to be minimal, so that we can do it often.”
Everything we do ladders up to this philosophy.
Let's take a look at 6 principles that enable us to automate our release process:
#1. The Master Branch is Always Releasable
It stands to reason that if we want to be able to release at any moment, the app needs to be in a releasable state at all times.
We release from the master branch of our GitHub repository. This branch must always be in a releasable state. Any Pull Request that is merged into master must be able to be released immediately and installed on users devices with no issues.
Our standard practice is to merge all pull requests into the master branch. We do this because we saw a tendency for there to be many merge conflicts with source files, like the project file and storyboards when many developers are working in the codebase. As any iOS developer will tell you, resolving these conflicts can be difficult and frustrating. So to tackle this, we prefer to open pull requests against the master branch, instead of opening against Feature Branches like Git-flow would specify.
#2. We Hide Unfinished Functionality from Users
Scrum is our Agile Methodology of choice here at FreshBooks, so we break down requirements into logical chunks of work, or “stories” as we commonly call them. These stories are then merged into the master branch once completed. Considering the master branch is to be in a releasable state at all times, we use a feature flag mechanism to ensure our users can’t see anything that is still in the process of being developed.
The feature flags are a server side mechanism by which we can flip a switch to turn on, or off, some specific functionality. We will develop a whole feature behind a feature flag enabling us to build and test it all the while our users can't see it.
Once the feature is ready to go, we use the feature flag to roll out the feature. After the feature flag has been turned on for all users for a while, we remove it from the codebase so that the functionality is available to all and is no longer controlled by the feature flag.
#3. Automated Tests Give Us the Confidence to Release
Given how often we release, you might think our QA folk just spend all their time regression testing the new versions of the app. This is not the case at all!
We write a lot of automated tests and they are run as part of every build we make. If a build makes it through the whole pipeline we're confident we've got our bases covered. Our QA resources are focused more on validating new changes to the app and performing exploratory testing on the app and its functionality.
Our automated tests are a combination of unit, integration and UI tests. Together they are our guard against regressions entering the app.
#4. Internal Betas Help us Find Build Issues Fast
Each night we send a build to Internal Beta via TestFlight. We do this so that stakeholders within the company can get the latest code on their device to test. We also do it so that we can find out if we've introduced any issues since we last uploaded a build to Apple.
Each time you upload a build to Apple, they perform some processing on it and you may get some notifications that something is wrong with the build. These notifications could be something to do with build settings, or incorrectly set capabilities for the app.
We like to get these notifications as soon as we can so that we can quickly figure out what is causing the problem. We don't want to wait until we're actually submitting for review to find out there is a problem with the build.
#5. A Reliable Continuous Integration and Continuous Deployment System is Critical for Automated Releases to Work
The backbone of our automated release process is our continuous integration and continuous deployment (CI+CD) system. You guessed it: yes, we use buddybuild.
However, we weren't using buddybuild when we started doing automated releases. We started off by building our own CI+CD infrastructure. It consisted of a Jenkins Master server, with a couple of Mac minis hosting OS X virtual machines as slaves.
At first, this setup worked quite well for us. There was still only a small number of developers working on the Mobile applications here at FreshBooks. As we grew we started to encounter some real pains with our own in-house system. The biggest problems were around reliability and maintainability.
On reliability: The Mac mini's were modestly spec’d machines, and on top of each we would provision a couple of OS X virtual machines. The resources available to these virtual machines was a fraction of what the physical Mac mini’s resources were and this meant they were really underpowered. We ran into a lot of problems running builds and tests on these underpowered virtual machines. Often things would fail for no obvious reason, and many developer hours were wasted in futile investigations of the failures.
On maintainability: The maintainability issue arose from not having the expertise or capacity within the mobile teams to continually troubleshoot the system and keep it up to date with all the necessary updates to the build tools. We were spending less time building the app and more time maintaining the infrastructure to build it.
We started looking for a solution to mitigate these issues and eventually decided on buddybuild. Since moving to buddybuild, our builds have become really reliable and maintenance is near zero effort. Buddybuild has benefited us in many other ways too, including:
- Crash Reporting: We were able to drop a separate 3rd party service we were using to track crash reports and instead use buddybuild to track them.
- Provisioning Profile Management: Having to not worry if our provisioning profiles are up to date and valid has been a huge time saver for us. We don’t need to worry about creating or maintaining them now as buddybuild just handles it seamlessly.
- Deployments: Using the deployment feature we’re quickly and easily able to distribute builds to the team to test the app on real devices. It's so easy, our non-technical team members know how to get a build on their device.
#6. Submitting to Apple for Review is Automatic
At FreshBooks, we dislike using iTunes Connect. It can be slow, cumbersome and confusing at times. How you create a new version of an app, input all the necessary information for the update and submit for review isn't very intuitive. And more often than not a person doing this needs help from others.
Instead of doing all of this in iTunes Connect manually we use an open source tool called Fastlane to interface with iTunes Connect and the Apple Developer Portal. With Fastlane we can store all the information we need for the App Store (such as the app's description, keywords, screenshots etc.) inside the repository alongside the code for the app. When we’re doing a build that we want to end up on the App Store, we run Fastlane in the
buddybuild_postbuild.sh script as a custom build step and have it upload the app with all of its metadata and submit it for review. It’s also marked to automatically release on the App Store once it's approved.
We Want to Release More Often than Once a Week
As mentioned at the beginning, right now we release once a week. With the automated process we have in place, we have ambitions to release even more often in the future - perhaps as much as 2-3 times a week. We're really only limited by the amount of time it takes for an app to be reviewed by Apple.
At FreshBooks, as with many other companies, mobile is a key focus for the business. We now have many different teams completing and releasing features at different times. So, with more and more people starting to work on the mobile app, this automated release process will become even more important.
If this method of building and releasing our app sounds like something you’d like to be part of, good news: FreshBooks is hiring talented and passionate individuals. Join one of Canada's top employers. For more info and to apply head to www.freshbooks.com/careers.