2

Continuous iOS App Delivery

 3 years ago
source link: https://sourcediving.com/continuous-ios-app-delivery-1a158f1f3d33
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Continuous iOS App Delivery

Tips for delivering your app more frequently with fewer problems

Image for post
Image for post

At Cookpad we now have more than 10 iOS developers working on our core application and we’re looking to have more people join us.

With this number of engineers, it is, of course, challenging to keep the code well-organised to have a solid, yet flexible architecture and enforce the preferred architecture throughout the project. However, having good quality code itself doesn’t achieve anything.

Yes, we need to deliver it to users to make a change to the world!

Though it’s a common topic to discuss, releasing an app is not always easy. For each release, you need to ensure that the following are present and correct:

  • App functionality
  • Translations
  • App Store metadata

These things usually get harder and harder to manage as the project continues because the specification gets increasingly complicated. For example, it’s likely that the business will expand to different countries, once it’s been confirmed that the product works in one country which means you need to manage more languages.

Moreover, the target of the app release is not always your customers. It also can be:

  • A developer, so that they can debug a feature on a real device
  • A product manager, so that they can try out a work-in-progress feature to confirm that what’s being built is actually what is wanted
  • QA team to test a release candidate
  • Community managers, who want to make sure that the translations are correct and check what’s new so they can write a user-friendly description for the App Store
  • Beta testers, who are a set of voluntary users, to help us get more insights on experimental features

You often end up having many different kinds of apps with different audiences, which can make release management even harder.

In this article, I’m going to lay out how we tackle the complexity of release management.

Have a foreseeable schedule

First thing first, let’s talk about release schedule. Having a regular release cycle is the most important factor in enabling app releases, constantly and at ease.

It’s a development team who should control the release schedule. Do not let others do it. I’m not suggesting that you should make it non-negotiable, instead, you should listen carefully to what your product team needs but it’s only developers who actually can make it happen in a realistic way.

Here at Cookpad, we release a new version every week on the same day regardless of the progress of the product development. If we fail to finish something up by release date. That’s that. We’ll wait for the next version for it to be released. It’s not the end of the world since we release weekly.

The key point here is to detach app release cycle from product development cycle. Even if a version doesn’t have much to show to users, there may also be internal improvements such as refactoring and updating 3rd party libraries. It’s always good to make any kind of change incrementally to minimize the risk.

Having an agreed schedule between developers and product team ahead of time also significantly reduces unnecessary communication overhead. Have you ever been asked to rush to finish your work and release unsatisfactory code, and spent a huge amount of time just to explain why it’s impossible? This is less likely to happen if you have a fixed release date.

A flexible schedule might work at the beginning but it’s soon going to be chaotic as the team grows. It’s very hard to build good automation and a QA process around a haphazard schedule. If you stick to a fixed schedule, in the end, you can release more often with fewer problems, trust me.

Let remote machine do the job

Just having automation is not enough. This should be run on a remote machine, not on your local machine. Here’s why:

  • You don’t need to worry about how others’ machines are set up. It’s hard to write a script that works on any kind of environment. Some may have a different version of Xcode toolchain. Some may not have defined required environment variables. You should spend time on provisioning remote build machines rather on making a lot of effort to make it work everywhere.
  • You can free up your local machine resource. Building a release version of app and uploading it to TestFlight usually takes very long and meanwhile, you really can’t code since your Xcode is busy and you can’t switch to a different branch (Well, you technically can but you know how troublesome it will be if you do it!). What you could do while waiting for the build is, at best, to review others code on GitHub but you’ll likely to find yourself on Twitter 😇

I can’t tell you which service you should use to have a remote build server but whatever service you choose, Fastlane match makes server provisioning lot easier. At a glance, it looks quite complicated to understand but what it does, simply put, is just managing certificates and provisioning profiles encrypted in a separate private GitHub repository and Fastlane downloads them as needed so that you don’t need to install them in your remote servers manually.

Have a flexible and easy-to-use interface

Here I’m going into a bit more advanced topic which I rarely see discussed.

As I mentioned earlier, what to build and who will be the audience can vary. You may now have just two apps, one for users and another for internal testers, but you should not expect this to remain constant… as I did 🙈

We now have 3 different internal apps and 3 external apps for the same service but targeting different audiences, which I would never dream of. I’m not going to explain what those apps are exactly for as it’s too specific to our project but here are a couple different scenarios that help you understand why we need these:

  • Build master branch and ask QA team to test it
  • Build a release candidate branch and upload it to App Store Connect
  • Build an arbitrary branch and upload it to TestFlight to make it accessible to beta testers

These are different scenarios but one of my colleagues discovered what is common. The variables are which branch to build and where to upload it. We implemented a Slack bot that takes those conditions as arguments, the command format is:

ios deploy {branch} to {destination}
Image for post
Image for post
Me asking the bot to build master branch and publish it as an internal app

The chatbot passes the arguments to Jenkins and Jenkins determines which branch to check out and which Fastlane command to run. Roughly, the entire system looks like this:

Image for post
Image for post

What’s good about this is that it’s extensible. We may need another app in the feature with different reasons but even if it will be the case, we don’t need to change the format of the command. We instead just need to extend the command to support the new destination.

Another upside of doing this in Slack is that we can make progress of these admin tasks visible to everyone and then the team can be aware of exactly what’s happening.

Get everything together

I’m intending to make this post as general and tool-agnostic as possible but I, at the same time, feel it can be too abstract to imagine how you can do it by yourself. To avoid the article being too general to be useful, I’m going to show how our typical release looks like.

Firstly, we branch off a release candidate from master, against which we run integration tests. We call this code freeze. It always happens on Wednesday and every week. On Wednesday evening, one of us runs the following command:

ios code_freeze {version}

This is going to:

  • Create a release candidate branch off from master
  • Update the version number with the specified value
  • Post a list of changes to Slack
  • Ask translators to translate new phrases
Image for post
Image for post
Image for post
Image for post

Who’s going to do this doesn’t really matter since it’s just about posting a single message to Slack.

We then run the following command right after the code freeze:

ios deploy RC-x.x.x to rc

This command builds the release candidate branch, distributes it as a new version of an internal app and ask the QA team to test it.

Image for post
Image for post

On Friday evening, if we are confident about the quality of the version, we make a release build by running:

ios deploy RC-x.x.x to release

This command builds the release candidate with the release configurations and uploads it to App Store Connect. Note that the only difference from the previous command is just the destination.

Then, once the binary has been processed, we run:

ios submit release {build_number}

This command submits the app whose build number is the one specified and posts a slack message.

Image for post
Image for post

Our app usually is approved over the weekend and if this is the case, we release the version with:

ios release release

This may be a little confusing as the first release means we are going to “release” the app while the second release specifies the app kind. This command releases the app, whose status, at this point, should be “Pending Developer Release”, posts a Slack message and create the next version on App Store Connect.

Image for post
Image for post

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK