こんにちは、株式会社フィノバレーでAndroidエンジニア(兼 自称:駆け出しUXリサーチャー)をやっております、島本(id: yoi_ko)です。
COVID-19感染拡大に伴う在宅勤務が始まって以来散歩を日課にしていますが、この暑さで継続の危機に立たされています。夏は好きですが、夜も未練がましく暑いのはどうかと思います。
今回の記事では、フィノバレーの提供するデジタル地域通貨プラットフォーム「MoneyEasy」のAndroidアプリ開発において、昨年にイチから構築した CI/CD環境の概要とその経緯 について紹介したいと思います。
前提
CI/CDの構成をご紹介する前に、MoneyEasyのAndroid開発の基本的な環境について簡単に紹介します。
- コード管理:GitLab
- ブランチ戦略:
- master(リリース用)
- develop(開発用)
- feature(Issueに紐ついている作業用、developにマージしたら消す)
- APK配布:DeployGate
これは、Androidアプリ開発現場ではよく見られる構成だと思います。
ひとつ特殊なのが、MoneyEasyは プラットフォーム だということです。
弊社では、MoneyEasyを使った地域通貨として既に「さるぼぼコイン」「アクアコイン」を運用しています。
Androidアプリは、それぞれの環境ごとにリポジトリを分けてはいません。つまり、先述の両アプリは同じコードで動いています。
アプリ名やテーマカラーをはじめとして、様々な仕様上の違いがありますが、これは productFlavors
を分けることで解決しています。
環境は、大きく分けて社内開発用( DEV環境 )、アプリごとのステージング環境( STG環境 )、アプリごとの商用環境( PRD環境 )があります。
機能の新規開発やバグの修正などはDEV環境で行い、ここで実機テストを行っています。
それぞれのアプリごとの機能・デザインのテスト、およびクライアントでの確認はSTG環境で行います。
ここでのクライアントとは、さるぼぼコイン:飛騨信用組合様、アクアコイン:君津信用組合様を指しています。
最後に、リリースされているアプリが動いているのがPRD環境です。
最終的なCI/CD構成(v1.13.0時点)
まず、以下が現在動いているCI/CD構成の全体図になります。
各ステップについて簡単に説明します。
ローカル環境では、 git hook
を使って自動で以下の処理を行っています。
- commit: 開発者のローカル環境で
git commit
する際、./gradlew ktlintFormat
を実行 - push: ブランチを
git push
する際、./gradlew app:lint{DEV環境用のビルドバリアント名}
を実行
そして、GitLabでは以下のタイミングでUnit Test、UI Test、APKのビルドを行っています。
- feature branch push: pushされたfeatureブランチでUnit Testを実行
- feature -> develop merge: developにfeatureブランチがマージされた際、Unit TestとUI Testを実行
- add tag: ルールに沿った名前のタグがつけられた際、そのタグ名に応じたビルドバリアントでAPKを作成
全容についてはざっと掴んでいただけたでしょうか?
この構成に至るまでには、第1弾・第2弾と段階を踏んでいます。
次は、それぞれのステップについての詳細と経緯について、時系列で紹介していきます。
ちなみに、この構築にあたっては、2018年に出版された PEAKS(ピークス)|Androidテスト全書 を全面的に参考にしています。
この本がなければ構築できなかったと言っても過言ではありません。まさにバイブルです。
関係者の方々、本当にありがとうございました。
第1弾 目標:テスト→DeployGate配布の自動化
いきなり現在の姿とは違う目標が掲げられていますね。
理由については後述します。
まず最初にCI/CD構築のIssueが立てられたのは、2018年4月でした。
私はまだ入社しておらず、Androidエンジニアは照井さん(id: hotdrop77)だけでした。
ちょうど、Androidのフルリファクタリングが進められていた時期ですね。
照井さん一人によって成し遂げられたフルリファクタリングについては、以下の記事で紹介されています。
finnovalley.hatenablog.com
その後2018年10月に私が入社し、その年末からCI/CD構築作業をスタートしました。
当初の目的は、 「各環境に応じて「テスト → DeployGateへのアップロード」というのを1クリックでできるようにする」でした。
APKのビルドはマシンパワーを使いますし、その間コードの変更などができません。
それをすべて自動化するだけでも、大変な作業効率化に繋がると考えてのことでした。
最初に想定していたゴールはこういった形です。(実際のIssueのスクショ)
この時点で、Unit Testはいくつか存在していましたが、UI Testはまったく書いていませんでした。
このため、第1弾では UI Testの実行は省略しています。
また、検討を進めるなかで「DeployGateへのAPK自動アップロードはしない」という結論に至りました。
前述の通り、アプリをリリースするには、STG環境でクライアントに確認していただく必要があります。
ブランチのマージを契機にビルドしたAPKを自動的にDeployGateへ配布すると、クライアントには予告なくアプリを更新してしまうことになります。
それは避けたほうがよいだろうと考えてのことでした。
このため、APKのビルドは 「ルールに沿った名前のタグがつけられた際」に実行しているのです。
タグ名の命名規則は、さるぼぼコイン:sarubobo-*
、アクアコイン: aqua-*
としています。
ハイフンの後ろは、DeployGateにアップする際のVersionを指定する運用にしています。
第1弾での対応をまとめます。
- ローカル環境での静的解析の自動化
- push/merge契機でのUnit Testの自動化
- タグ打ち契機でのAPKビルドの自動化
第2弾 目標:UI Testの自動化
UI Testの自動化は、まずテストを書くところからスタートしました。
それまでUI Testというものを一度も書いたことがなく、またこの時点で画面数が相当な量になっていたため、この「テストを書く」というタスクにかなりの時間を割いています。
実装開始が2019年6月中旬、終了が2019年8月頭なので、ざっと2ヶ月弱でしょうか。
これは結構つらい作業でした。
Issueにも、その片鱗が残されています。
UI Testを実装するにあたっては、以下の記事を大変参考にさせていただきました。
これらの記事がなければ、途中で諦めていたと思います。深い感謝を捧げます。
Kyash Android で UIテストを導入した時の方針 - Konifar's WIP
RxJavaのアプリをEspressoでテストする簡単な方法 - Speaker Deck
UI Testの実行は、 Firebase Test Lab で行っています。
GitLab CIでUI Test用APK作成 -> Firebase Test Labへ投げる、の流れで処理しています。
ハマりポイントとしては、サービスアカウントの設定です。
Firebase Test Labでの実行には、適切な役割のサービスアカウントが必要になります。
Firebase TestLab管理者という名前の、一見それらしきものがありますが、これだと権限エラーになります。
正しくは 編集者 です。(とても紛らわしい…)
そんなわけで、UI Testの実装に苦しんだり、サービスアカウントの罠にハマったりしながらも、第2弾の目標はなんとか達成することができました。
- UI Testの実装
- UI Testの自動化(Firebase Test Lab)
まとめ
このように、第1弾/第2弾と段階を経て、CI/CD環境を構築しました。
DeployGateへの自動アップロードをしていないなど、ちょっとした制限はあるものの、静的解析やテストの自動化・APKのビルド対応によって、開発効率はぐんと上がったのではないかと思います。
とはいえ、APKの作成時は時間が掛かってしまっていたり、UI Test自体のメンテナンスが追いついていなかったりと、まだ課題はあります。
CI/CDのような、品質や効率に関わるタスクはどうしても機能開発に劣後してしまいがちですが、ないがしろにしてはいけないと思います。
今後も、最新の情報をキャッチアップしたり、日々変化する開発を取り巻く現状を見直したりしながら、よりよいCI/CDの形を模索していきたいです。
2020/11/18追記
ver2系以降のテスト事情については、以下記事でご紹介しています。合わせてご覧ください。