はじめに
株式会社 WinTicket でネイティブアプリエンジニアをしている長田卓馬(@ostk0069)です。
WINTICKET は 2022 年 4 月に、TWA から Flutter で開発された Android アプリへのリプレースを行いました。開発期間は約 1 年です。 詳しくはWINTICKET における Flutter を利用したクロスプラットフォームアプリケーションへの取り組み をご覧ください。
今回は WINTICKET のアプリチームで採用しているリリースフローについて紹介させていただきます。
アプリ開発におけるリリースフローとは
開発したアプリを Google Play Console や App Store Connect にアップロードし、Google Play や App Store でユーザーに届けるまでの一連の流れのことを指します。 リリースフローと言っても扱っているサービスの特性、チームメンバーの人数などで多種多様のリリースフローがあります。 WINTICKETではアプリチームにおける Flutter でのiOS / Android 開発におけるリリースフローの構築しました。 Flutter を利用した開発をしている方、検討している方の参考になれば幸いです。
チームにとって理想のリリースフローを思案
リリースフローを構築する上で大事なことは、「チームの特徴を理解し何が最適か」を考えることです。
アプリチームの特徴は以下のようになります。
- アプリチームの人数が 8-9 人
- リリース頻度は週に 1 回
- Feature Flag を用いた開発、Trunk Based 開発 を採用
- GitHub の Milestone を用いた開発
これらをリリースフローに求めるものへと変換すると以下のようになります。
- メンバーが多いので誰でもリリースできるように属人化しないものが望ましい
- メンバーが多いので誰かどのような開発をしたのか振り返るタイミングがあると良い
- リリース頻度は週に 1 度なのでなるべく負担の少ないものがいい
- Feature Flag の Flag 制御をリリースフローに組み込みたい
また Flutter で開発をしているので以下の要望もあります。
- iOS、Android の共通したアプリバージョンやビルドナンバーをどう管理するか
- iOS、Android 共通のリリースノートやメタデータ(アプリの説明文やスクリーンショット)をどう管理するか
早速ではありますが実際にこれらの問題を解決したリリースフローを紹介していきます。
(※執筆時のタイミングでは iOS の App Store Connect にバイナリやメタデータをアップロードするリリースフローの構築は未完成です)
リリースフローの紹介
上記が現在採用しているリリースフローをフローチャートに起こしたものです。このフローチャートだけだとまだ不明点が多いので順番に説明していきます。
1. CLI 上でのリリース用の Pull Request の作成
make コマンドでの Pull Request の自動生成からリリースフローは始まります。「なんで Pull Request を作成するのか」と疑問に思った方もいるのではないでしょうか。
Pull Request を自動作成することで前述したこれら問題を解消しています。
- iOS、Android の共通したアプリバージョンやビルドナンバーをどう管理するか
- Feature Flag の Flag 制御をリリースフローに組み込みたい
アプリバージョンとビルドナンバーの管理についてです。
アプリバージョンとビルドナンバーは iOS、Android どちらも同一にしています。
そこで make setup-release
を叩くと以下のような shell script が動くようになっています。
上記の画像のようにコマンドを叩いた際にバージョン管理の選択肢が表示されます。リリース担当者は今回のリリースでメジャーバージョンかマイナーバージョンのどちらを上げるのかを理解しているだけで、ビルドナンバーをインクリメントできるようになっています。 iOS 開発においてはあまり問題にならないビルドナンバーですが Android 開発ではユニークな値として管理する必要があったので、管理用のスクリプトを作成しました。実際のコードに関しては GitHub Gist に公開したのでこちらを良かったら見てみてください。
Pull Request 形式にしたのはリリースノートやメタデータ(アプリの説明文やスクリーンショット)をコードベースで管理したいと考えたからです。また、リリース時の Feature Flag の状態の編集を行えるタイミングだと考えました。これらに関しては次で詳しく解説していきます。
2. Pull Request の完成
こちらが make コマンドを叩き、実際に作成されたリリース用の Pull Request です。
作成された Pull Request の差分は以下のようになっています。
アプリのバージョンをGitHubで管理しているので差分が一目瞭然です。
差分にあるようにここでは以下の問題を解決しています。
- iOS、Android 共通のリリースノートやメタデータ(アプリの説明文やスクリーンショット)の管理を行える
- Feature Flag の Flag 制御をリリースフローに組み込みたい
リリースノートやメタデータも CD でバイナリをアップロードさせる際に渡すことができるので GitHub で管理しています。
Feature Flag に関してもこのタイミングで開発中の状態から Remote Config の様な外部から操作できる状態に変更する機会を与えられます。
こうすることで以下のようにコードレビュー形式でのチェックが可能です。
- 正しいバージョン、ビルドナンバーに更新されているか
- リリースノートやメタデータに誤字脱字がないか、変更に漏れがないか
- Feature Flag の変更に漏れがないか
3. リリース間 Visual Regression Test の実施
リリース用の Pull Request を作成するのにはもう 1 つ理由があります。
それはリリースバージョンとリリース予定のバージョンの Visual Regression Test(以後 VRT)を CI 上で行うことです。
これによって先ほど挙げた課題の「メンバーが多いので誰かどのような開発をしたのか振り返るタイミングがあると良い」の対策になっています。
こちらが実際にリリース間 VRT を回した結果です。前回作成された Tag とリリース用の Pull Request のブランチの比較しています。
(赤が変更されたシナリオ、白が新規のシナリオ、黒が消去されたシナリオ、青が前バージョンから変化がないシナリオを意味します)
VRT にはreg-suitを利用しています。開発当初から VRT での UI コンポーネントのテストを書いてあり、ほぼすべての Widget に対してシナリオが記載されてます。VRT によってリリース間の UI の差分を検知でき、リリースによる UI の変更点を把握できます。
4. バイナリの作成とアップロードの自動化
ここでは作成した Pull Request が merge されると Tag を打つようになっており、また Tag をフックして Google Play Console と App Store Connect にバイナリをアップロードしてくれます。バイナリーのアップロード処理はアプリ開発者には馴染みのあるFastlaneを使用しています。ここでは Fastlane の詳しい解説は省略します。
余談にはなりますが、Tag が打たれた時にバイナリのアップロードとは別に以下の2つの処理を自動で行っています。 いずれも公開されている GitHub Actions を利用しています。
- GitHub Release の作成の自動化
- 次の Milestone の作成と close の自動化
- 利用した Milestone の作成の Workflow
- 利用した Milestone の close の Workflow
リリース作業で発生する細かい作業の自動化も行っています。
5. Google Play Console や App Store Connect での作業
ここに関してはアプリ開発したことのある方であればわかるので具体的な解説は省略します。実際に審査に提出をし、審査に通過後は公開する流れになります。 別職種のチームがリリースしたことに気づけるように Slack のチャンネルで連絡を入れるようにしているのでそれが記述されています。
審査通過後はカナリアリリースを採用しており、以下のフローになっています。
- 金曜日に審査へ提出
- 月曜日に 30%リリース
- 水曜日に 100%リリースへと変更
カナリアリリースを採用した背景や品質担保に関しては同じくアプリチームのメンバーが執筆したWINTICKET アプリ Flutter リリース戦略をご覧ください。
まとめ
以上がアプリチームで採用しているリリースフローの全容でした。
最初に挙げた 6 つの課題がこちらです。
- メンバーが多いので誰でもリリースできるように属人化しないものが望ましい
- メンバーが多いので誰かどのような開発をしたのか振り返るタイミングがあると良い
- リリース頻度は週に 1 度なのでなるべく負担の少ないものがいい
- Feature Flag の Flag 制御をリリースフローに組み込みたい
- iOS、Android のアプリバージョンやビルドナンバーの管理を行える
- iOS、Android 共通のリリースノートやメタデータ(アプリの説明文やスクリーンショット)をどう管理するか
このリリースフローを採用したことでこれら6つ全ての課題が解決されているのがわかります。
特に「メンバーが多いので誰でもリリースできるように属人化しないものが望ましい」に関してはコードレビュー形式を採用したことでエンジニアにとって一番違和感のないものとなりました。
これによってリリース時の事故を減らし、リリースフローの属人化も減らすことができると感じています。
しかし、このリリースフローはこれで完成というわけではありません。これからも運用する中で課題が挙がってきたら、都度解決策を検討し、より良いものにしていければと考えています。
「自分のチームではこういうリリースフローで運用しています」と、共有して下さる方がもしいましたらぜひ教えて頂けると嬉しいです。
ほかにも…
現在他のアプリチームのメンバーが記事を執筆しています。よければ以下の記事もご覧になってください。
- WINTICKET が考えたモダンな Flutter アプリ設計を完全解説
- WINTICKET アプリ Flutter リリース戦略
- WINTICKET Flutter アプリと Text Scale Factor の闘い