PairsのAndroidアプリの今と未来
こんにちは!Androidエンジニアのyuyakaidoです。
今朝のスペイン戦、最高でしたね!🇯🇵⚽️🇪🇸
ちなみに、Androidチームにはスペイン出身のメンバーがおり、デイリーミーティングでどう話題を切り出そうか悩んでいますが、ここはやはり開口一番ブラボー!でいってみようと思います。
さて、私はエウレカでは業務でPairsのAndroidアプリを開発しています。ここ最近は新機能の開発よりも、チーム全体の開発効率向上や中長期視点でのアプリの基盤改善といった裏方の仕事がメインになっています。
この記事ではAndroidチームが直近で取り組んでいる内容を振り返り、同時に今後の方針をまとめてみようと思います。
現状の振り返り
まずは、ビジネス観点での現状の振り返りとして、勉強会や面接でPairsについて話した際に驚かれることが多いのが、現在でも頻繁に新機能開発を行っており、毎年いくつも大きな新機能をリリースしているというポイントです。
2022年だけでも以下のように3つの大きな機能をリリースしています。
2022年7月:オンライン合コンをコンセプトにした「グループトーク」
2022年10月:プロからアドバイスがもらえる「Pairsコンシェルジュ」
2022年10月:1年以内の結婚にコミットしたい人向けの「コミットメンバーシップ」
次に、開発観点での振り返りとして、PairsのAndroidアプリは以下のようなスタイルで開発しています。
- 機能単位でのモジュール分割を軸としたマルチモジュール構成
- Single source of truthとUnidirectional data flowを基本原則としたアーキテクチャ
具体的なモジュール構成やアーキテクチャについては、以下の記事で詳細を紹介していますので、興味があれば合わせてご覧ください。
ここまででビジネス観点と開発観点からPairsの現状を振り返りましたが、そんな中でエンジニアに対して求められている期待値は、機能開発そのものを滞りなく遂行するという観点に加え、クオリティの高いアプリを継続的に開発し続けられる体制の構築という観点も入ってきます。
このような体制を作って維持していくためには、本質的なことに使える時間を最大化することが重要と考えており、そのためにAndroidチームが取り組んでいる内容を紹介します。
時間的なロスを最小化する
Androidアプリ開発をする中では、本質的ではない作業や時間というのがどうしても発生してしまいます。代表的なものでいえば、ビルド待ちという名のネットサーフィンタイムでしょうか。
ビルド待ちの間にTwitterで有益な情報や記事を発見するなど、それなりに有意義な時間になることもありますが、トータルで考えると削減できるなら削減したほうがいいのは間違いないだろうということで、Androidチームでは時間的なロスを最小化するために以下の改善に取り組んでいます。
ビルド時間を短縮するためのモジュール分割
規模が大きなアプリの宿命として、ちょっとした修正を加えただけでもキッチンに飲み物を取りに行ったりお手洗いに行ってきたりできるくらいにはビルド待ちが発生するということがあるかと思います。
実際ビルドにどのくらいの時間がかかるのかはマシンスペックやコードベースの状態など様々な要因が関係しますが、モジュール分割はビルド速度を向上させるための1手として広く採用されています。
モジュールの分割方法は、大きく分けて以下2つがあります。
- アーキテクチャのレイヤー単位で分割する方法
- 機能単位で分割する方法
Pairsではビルド時間の短縮効果を最大化するために機能単位の分割を軸として、必要に応じてアーキテクチャのレイヤー単位での分割も行うというハイブリッドなアプローチを採用しています。詳細は省いていますが、大まかには以下のようなモジュール構造になっています。
モジュール分割は2019年から徐々に進めていますが、まだ全ての機能がモジュールに分割されているわけではありません。今後も新機能開発や既存機能に手を加えるタイミングで地道にモジュール分割を進めていく予定です。
UI開発スピードをアップさせるためのJetpack Compose導入
Pairsのモバイルアプリは特定のOSに特化したデザインではなく、AndroidとiOSの中間的なデザインになっており、各OSが提供する標準UIコンポーネントに手を加えて独自のUIコンポーネントを作るということが多くなります。
こういった状況では必然的にビルド時間の長さが開発上のネックとなるため、モジュール分割だけでなく、UI開発の観点に特化した効率化が急務であるという考えに至り、この課題の解決策の1つとしてComposeを導入しました。
2022年の前半で具体的な技術検証と基盤整備を進め、2022年7月にリリースした「グループトーク」の一部でComposeを導入しました。また、2022年10月にリリースした「Pairsコンシェルジュ」と「コミットメンバーシップ」では全面的にComposeを導入しました。
実際にいくつかの機能をComposeで開発してみた所感として、以下のような観点で効率アップを実感しています。
- プレビュー機能を駆使することでUI開発のトライ&エラーが従来よりも高速に回せるようになった
- 従来では難易度が高かったアニメーションも簡単に実装できる
- Unidirectional Data Flowの考え方がベースになっているため、UI関連のバグが発生しにくい
新機能の開発でComposeを全面的に利用する中で日々新しい発見がありますが、その裏返しとして実装された時期によってアプローチが微妙に違うという事象が発生しています。これは現時点で特段ネガティブな事象として捉えているわけではありませんが、もしかするとどこかのタイミングでスタイルガイドのようなものを整備する必要があるかもしれないと考えています。
標準化された開発スタイルへの準拠
ここ数年でGoogleによる開発スタイルの標準化が一気に進んでいます。
- アプリ開発で必ず必要になるライブラリ集としてのAndroid Jetpack
- アプリ全体の指針となるアーキテクチャガイド
こういった標準化が行われる以前は、ライブラリに関しては個人や企業が善意で開発しているものを使うのが主流で、アーキテクチャに関しても古くからある設計パターンや他のプラットフォームで使われているアーキテクチャを持ち込むといった動きが盛んに行われていた記憶があります。
Android Jetpackやアーキテクチャガイドはこういった荒波を乗り越えてデファクトスタンダートとなったライブラリや設計パターンに対してGoogleが一定のお墨付きを与えたもので、この開発スタイルに積極的に乗っていくことで、Googleによる継続的なメンテナンスの恩恵が受けられるだけでなく、より本質的なことに使える時間が増えるというメリットもあると考えています。
Kotlin
これはもう説明不要でしょう。
PairsのAndroidアプリは100%Kotlinで実装されています。
HTMLは利用しているライブラリのライセンスページで使用しており、Shellは申請作業を自動化するためのスクリプトで使用していて、実質アプリ本体は100%Kotlinです。
ただ、100%Kotlinで実装されているものの、Javaから自動変換しただけでKotlinらしくないコードが少なからず残っているため、継続的な改善を行っていく予定です。また、Kotlin自体も日々進化しているため、アップデートへの追従にもリソースを割いていくつもりです。
Kotlin Coroutines
PairsはCoroutinesが登場する以前から開発されているアプリということもあり、非同期処理のハンドリングでは主にRxJavaが使われていますが、徐々にCoroutinesへの置き換えを行っています。
移行方法については、以下の理由から新機能開発を行う際はCoroutinesを利用する、既存機能に修正を加える際はKotlin Coroutinesへの移行を行う、というスタンスで徐々に移行を行っています。
- 現状の実装に具体的な課題があるわけではない
- 作業量が膨大で時間がかかる割にビジネス観点と開発観点のどちらにもそれほど大きなリターンがあるわけではない
Room
Pairsでは昔から一貫してSQLiteベースのDBライブラリを利用してきており、Googleによる継続的な機能追加やメンテナンスの恩恵を受けられるという期待からAndroid Jetpackの中でも比較的早期に採用したライブラリです。
ただ、現状のPairsはあまりオフライン環境で使いやすい状態とは言えず、今後Roomの機能を活用してオフライン環境でも使いやすいアプリにするための改善を行う予定です。
Navigation
Pairsでは新機能開発の際に原則Navigationを使って実装をするというスタイルを採用していますが、全体から見るとまだまだ限定的な利用に留まっています。
新しく開発された機能に閉じた形でNavigationを利用する形でも十分に価値を発揮してくれていますが、ディープリンクなども含めてアプリ全体がNavigationで実装されている環境でこそ真価を発揮するライブラリなので、アプリの根っこ部分にもNavigationを適用する計画を進めています。
Hilt
Pairsでは昔からDIライブラリとしてDaggerを採用していますが、2022年12月現在はHiltではなくAndroidサポートを利用しています。Hiltを利用することでAndroidサポートよりも簡潔に実装できるというメリットは理解しつつも、現時点では移行コストとのトレードオフを考慮して具体的な移行計画は立てていません。
WorkManager
Pairsではいくつかの用途でWorkManagerを利用しています。
- チャット画面で利用するスタンプのダウンロード処理
- プロフィール写真のアップロード処理
他の案件と同様に新機能の実装や既存機能に手を入れる際にWorkManagerを利用するというスタイルなため、利用範囲を拡大する余地は大いにあります。ただ、他の案件を差し置いて取り組むべき案件かどうかは精査する必要があるだろうと考えています。
開発効率を向上させる
エウレカでは日々チームを横断した情報交換をしており、開発チーム全体で開発効率を向上させるための取り組みを行っています。その中でも大きな効果が出ているものをいくつか紹介します。
開発者メニュー
Pairsアカウントには数多くのステータスが存在します。
例えば、サービス内で利用可能な仮想的な通貨であるPairsポイントや、有料会員やプレミアム会員といったアカウント種別などがあり、こういった各種ステータスによってアプリ内の挙動が切り替わるといったことが多くあります。
本来であればサービス内で実際に購入処理を行うことでステータス変更が行われますが、開発段階で毎回正規のフローで購入処理を行うというのは非効率なため、Pairsでは管理画面と呼ばれるWebサービスを通じて開発アカウントの各種ステータスを自由に変更することが可能になっています。
この機能は開発段階で毎日何度も利用しますが、毎回Webブラウザで実行するのは少し手間なため、アプリ内からも同様の機能を利用できるような仕組みを整備しており、これを開発者メニューと呼んでいます。
ステータス変更の他にも接続先の環境を切り替えるための仕組みなどもあります。
この開発者メニューはアプリの進化に合わせて日々改善を続けており、新機能開発の際は開発作業を効率化するためのアイデアを皆で出し合い、機能開発と平行して開発者メニューの開発を行っています。
Feature Flag
この記事の前半で触れたように、Pairsは毎年大きな機能をいくつも開発してきており、当然複数の機能を同時に開発するというシチュエーションもあります。機能によっては発足からリリースまで半年〜1年程度かかるものもあり、変更規模も比例して大きくなります。
これだけの規模の変更を単一のコードベースに対して加える場合、別々の機能として開発しているとはいえ、大きくコンフリクトしてしまうことは避けられません。
そこでPairsではFeature Flagと呼ばれる仕組みでアプリ内の機能を動的に切り替える可能にし、開発中のコードもどんどんマージするというスタイルで開発をしています。開発中のコードはそのままではリリースできるクオリティのものではありませんが、Feature Flagによって開発ビルドのみで表示されるように制御されています。
クロスプラットフォーム
Pairsのモバイルアプリはそれぞれ以下の言語で開発されています。
- Androidアプリ:Kotlin
- iOSアプリ:Swift
一方で、スタートアップを中心としてFlutterのようなクロスプラットフォーム開発が可能なツールの採用が増えています。スタートアップはまずは生き残ることが最重要であるため、KotlinやSwiftではなくFlutterが選ばれるというのは自然な流れです。
クロスプラットフォーム開発はスタートアップのように基本的に全てをゼロから開発する必要があるようなシチュエーションで最大の価値を発揮しますが、PairsのようにすでにKotlin/Swiftで開発されたアプリがあるようなサービスでも開発効率を向上させる余地は十分にあるのではないかと考えています。
すでにKotlin/Swiftで開発しているPairsのようなアプリの場合、スタートアップのように全てをクロスプラットフォームツールで書き直すというのはあまり現実的ではありませんが、アプリの中で特定の機能や画面をクロスプラットフォームツールで開発することで開発を加速することができるポテンシャルが大いにあるだろうと考えており、現在社内の有志メンバーで技術的な検証を進めています。
まとめ
この記事では直近でAndroidチームが取り組んできた内容と今後力を入れていきたい内容を紹介しました。
Androidチームとして2022年で一番大きな変化はComposeをUI開発の主力技術として採用したことです。ComposeによってUI開発の効率は確実に向上したことをチーム全員が実感しており、今後も力を入れて取り組んでいく予定です。
また、Composeに加えて、以下のトピックには継続的に取り組んで行きたいと考えています。
- ビルド速度を向上させるためのモジュール分割
- 本質的な時間を最大化するためのデファクトスタンダードへの追従
- 開発効率を向上させるための仕組みへの投資
もしこの記事についての疑問・質問や、PairsのAndroidアプリについてもっと突っ込んだ話が聞いてみたい場合はTwitterにて気軽にメンション・メッセージを送ってもらえればと思います!