Androidチームの紹介
こんにちは、Androidチームの土谷です。
この記事ではLuupのAndroidアプリの開発体制や開発フロー、採用技術、達成したいことを紹介します。
開発体制
Androidチームは現在正社員1名、業務委託メンバーが6人となっています。
Androidチームではユーザー向けに提供するLUUPアプリだけではなく、社内向けのアプリ開発にも取り組んでいます。
社内向けアプリとは?
街を巡回して故障車両の回収やバッテリー交換をするオペレーションチームが使うアプリです。
車両の鍵を解錠/施錠したいとき、需要が多いポートへ車両の移動(再配置)などを行いたいときに使っています。
この記事は社内向けアプリではなく、ユーザー向けアプリについて紹介します。
社内向けアプリにつきましては別の記事で詳しくご紹介したいと思っておりますのでご期待ください。
開発フロー
現在のLUUPアプリの開発フローは下記のようになっています。
- 一週目の週
- 開発期間
- Featureテスト
- 二週目の月曜日
- コードブロック
- 二週目の火曜日
- Releaseテスト
- 二週目の木曜日
- Regressionテスト(簡易orフル)
- 二週目の金曜日
- リリース申請
- 三週目の月曜日
- リリース公開
- 一週目の週へ戻る
二週間に1回のリリースサイクルを目標としています。
開発期間
プロダクトマネージャー・デザイナーが仕様書(PRD)とデザインを仕込んだ機能について、開発する期間です。
一週間で作りきらなくてはならないという訳ではなく、大きい機能であれば3つ先のバージョンの必須要件にするなど柔軟な体制を取っています。
コードのリファクタリング、細かな改善などは期限なしタスクとしてスケジューリングしています。
Featureテスト
必須要件である機能を事前にQAするための期間です。
大きい機能であれば、後述するReleaseテストの週に着手を開始してしまうとリリースサイクルに間に合わないため、事前に機能確認を行います。
それと同時に新規機能であれば、QA側で項目の洗い出しも行います。
コードブロック
よくあるGit-flowのrelease branchを作成します。
基本的にはrelease branchで検出された不具合対応以外の修正は入れません。
当たり前ではありますが、コードブロックにギリギリ間に合った未QAのタスクなどは次回のリリースに回します。
Releaseテスト
上記で作成したrelease branchの結合テストを行います。
機能同士がぶつかってバグが発生していないかなどの確認します。
早めに着手完了した場合は後述するリグレッションテストに移ります。
Regressionテスト
簡易版とフル版の2つがあります。
Regressionテスト(簡易版)
厳密なレイアウト確認やアプリ内の一部遷移のテスト確認を省いた基本的な導線が問題なく動作するか確認します。
フル版よりも少ない工数で済むので、影響範囲が狭いものだけの場合に実施します。
Regressionテスト(フル版)
上記の簡易版に加えて、すべての機能が問題なく動作するか確認します。
工数的に簡易版よりも重いため、影響範囲が広い機能など入ったときのみ実施するようにしています。
リリース申請
release branch を master branch にマージします。
master branch にマージされるとGitHub Action経由でGoogle Play Consoleに自動アップロードされるようにCIが整備されています。
リリース公開
原則月曜日の午前中までに公開するようにしています。
採用技術
LUUPアプリでは、開発者の生産性やモチベーションを高く保てるようにモダンな技術の採用、モダンな開発方針をとっています。
Jetpack Compose
UIツールキットです。
既存のAndroid View + DataBindingの環境から徐々に移行しています。
肥大化しているAndroid ViewはAbstractComposeViewを使って徐々に移行するなど工夫しています。
メンバー全員でキャッチアップしながら日々勉強しています(笑)
Jetpack CameraX
カメラ機能を提供するライブラリーです。
LUUPアプリでは、開発当初からCamera2ではなくCameraXを採用しています。
QRコード読み取り画面では、CameraX + ML Kitを組み合わせて実装しています。
Koin
依存関係インジェクション(DI)です。
開発当初は、Koin or Dagger2 or Hiltのどれを採用するか悩んだ末、結果としてKoinを採用することになりました。
Dagger2は難解/複雑で学習コストが高い、Hiltは既に書かれているKoinのコードをわざわざ移植する程でもないと思ったためです。
しかし後に、Dagger2とHiltにAndroid Studioにおけるナビゲーションサポートが追加されてしまいました。
Koinを採用したことを軽く後悔しているのと、Dagger2 or Hiltに移植しようか真剣に悩み中です…。
Kotlin Coroutine
軽量な非同期プログラミングを提供するライブラリーです。
昨年の終わりくらいに、当初採用していたRxJava2をすべてCoroutineにリプレイスしました。
コードの量が減った、コード自体の可読性も上がった、学習コストも下がったといいことずくめで、完全に移行してよかったと思っています。
Spek2
テストフレームワークです。
基本的にspecification形式で書いています。
Robolectricとの相性が致命的でそういったときには渋々JUnit4でテストを書いています…。
Spek2とJUnit4が混ざるくらいなら完全にJUnitだけにすることも考えましたが如何せんレガシーすぎます。
テストコードは品質向上のためのコードだと思っていますが書いていて楽しいことも重要だと認識しているため、Spek2とJUnit4が共存している環境になっています。
Mockk
モックライブラリーです。
テスト対象のクラスの中で他のクラスに依存している実装をモックしたいときに使っています。
Truth
アサーション(検証)をするライブラリーです。
テスト対象のメソッドの戻り値を検証するときに使っています。
アーキテクチャ
開発当初からMVVMを採用しています。
Googleから推奨されているアプリアーキテクチャガイドに則って開発しています。
Androidチームが達成したいこと
現状のLUUP Androidアプリにおける課題を紹介します。
巨大なマップ画面
マップ上に表示されるポートから車体を探して乗車するLUUPアプリではホーム画面でもあり、一番よく使われる画面です。Acitivty、ViewModel、Android View(xml)で書かれています。
非常に複雑なステータスを持つ画面のため、Activityが約3000行、Android View(xml)が約1300行となっており、マップ画面に関わる修正を入れると不具合検出されることが多くなってしまっています。
これ以上巨大にならないように新規で追加される画面はComposeで実施、既存画面は少しずつComposeにリプレイスするルールを採用しています。
AbstractComposeViewで上手く関心ごとを分離することによって、Acitivtyではボタンがクリックされたなどのリスナーを受け取るだけで済むようになります。
テストコード
テストコードはできれば書くという風習です。
QAチームがかなり優秀で、同時に少し甘えてしまっている部分があると自覚しています。
「QAで検出されるだろうからテストコードは書かなくてよい」ではなく、できる限り開発段階で拾えるようにしていきたいです。
iOSアプリとの機能差分
iOSアプリが先行リリースされたこともあり、一部の機能がAndroidアプリでは実装されていなかったりします。
同時にQAチームの負担となっており、両OSで同じテスト設計書を使えない現状が起きています。
とは言え、実はその機能があまり使われていない機能もあったりますのでしっかり需要があるのか検証した上で新規機能とのリソース配分をしていきたいです。
さいごに
Androidチームでは業務委託、社員問わずメンバーを大募集しています。
上記の課題についてですが大半はリソース不足が原因だと思っており、ホントはやりたい改善系のタスクが後回しになってしまっている部分もあります。
現状だとユーザー向けアプリ、社内向けアプリの指揮を自分が取っているのですが将来的にはそれぞれの指揮を取れる人が別にいる環境が理想だと思っています。
課題だらけのAndroidチームですが少しでも興味を持っていただけた方、ぜひお気軽にお問い合わせください、お待ちしております!
Discussion