近年、Androidでは、複数のモジュールを組み合わせて1つのアプリケーションを組み上げるアプローチが増えています。マルチモジュールと呼ばれる手法です。弊社でも、マルチモジュール化に向けた取り組みを始めました。ここでは弊社におけるモノシリック構造からマルチモジュール構造への移行の取り組みについてご紹介します。
モノシリックな構成が生み出す課題
ココナラは、知識・スキル・経験を売り買いできるスキルマーケットです。ビジネスからプライベートまで、450カテゴリ以上、40万件以上のサービスが出品され、ビジネスでの課題解決や、プライベートでの悩みや困りごとなど、あらゆる局面で専門家やプロに相談・依頼ができるスキルマーケットとなっています。
ココナラでは2017年に最初のAndroidのクライアントアプリをリリースしましたが、それから現在まで、様々な機能の追加や改善を行い、200回以上のリリースを重ねてきました。当初はシンプルで扱いやすかった単一なAppモジュールという構成は、プロダクトが大きくなるにつれて徐々に肥大化していき、ビルド時間の増大を引き起こすようになりました。
また、当初は筆者1人で開発していたAndroidアプリも徐々に開発メンバーが増え、機能追加や改修の速度がどんどん早まりました。もちろんプロダクトの成長スピードが上がるのは大きなメリットですが、個々のメンバーが全体を把握することが難しくなり、ソースコードのコンフリクトもたびたび発生し、依存関係の複雑化というデメリットも生まれてしまいました。
そこで、目をつけたのがマルチモジュールです。モジュール分割によって互いの依存を排除すれば、他機能への影響を心配しないで開発が進められます。さらに、他のメンバーが開発した機能を担当することになっても、該当モジュールのみに着目すればよいのでキャッチアップが容易になることが期待できます。
今後、プロダクトがさらに成長するには、変化に強い構成が必要です。モジュール分割を行うことでソースコードの依存関係を強制し、シンプルな状態にすることにしました。
ココナラAndroidアプリにおけるベストプラクティス
モジュール分割を行うにあたり、様々なAndroidアプリにおけるマルチモジュール採用の事例を調査し、レイヤー単位での分割・機能単位での分割それぞれのメリット・デメリットを洗い出しました。また、改めてココナラAndroidアプリの機能分類を行い、機能同士の関係性を整理しました。
最終的なモジュール構成を決めるにあたって重要視したポイントが「ココナラAndroidアプリにおけるベストプラクティス」を探ることです。技術選定の場面では、たとえAndroidアプリ開発でデファクトスタンダードとされるツールや考え方であっても、ココナラというプロダクトの性質に適しているのかどうかを意識する必要があります。それは、モジュール分割においても同様でした。
最終的なモジュール分割
機能同士の関係性と共通コードの扱いを検討した結果、ココナラAndroidアプリのモジュール構成は次の図のようになりました。基本的には機能単位でモジュール分割を行い、共通利用するレイヤー部分はレイヤー単位でモジュール分割を行う形です。
機能単位での分割を基本としたのは、ココナラには主要機能が複数ありレイヤー単位で分割するよりマルチモジュールの恩恵を受けられるのではと考えたからです。それに加え、今後Play Feature Deliveryへの対応も想定していました。ココナラでは、サービス出品やサービス購入といった特定の動作の際に初めて利用する機能がいくつかあるため、このPlay Feature Deliveryを利用することにより、最初から全機能のAABをインストールするより、インストールサイズを抑えることが期待できます。
もう一つ特徴的なのが、すべてのモデルクラスを格納したモジュールと.protoファイルを格納したモジュールがそれぞれ独立してモジュール分割されている点です。一部のAPIにおいてgRPC通信を採用しているため、.protoファイルを格納しているリポジトリをgit submoduleでライブラリモジュールとして取り込んでいます。
現状のモジュール構成はこのようなものですが、今後プロダクトやチームの状況が変わることでベストプラクティスも変化していくはずです。そういった変化に対しても、チームで議論しながら、柔軟に正解を模索していきたいと思っています。
導入にあたり直面した課題
モジュール構成を決定し、いざ導入しようとした際に課題に直面しました。当初の計画では、既存機能のリプレースプロジェクトの中で該当機能と共通機能のモジュール分割を行う予定でしたが、同時期に別の大型プロジェクトとサービス全体のリブランディングプロジェクト が進行することが発覚したのです。チーム内では仕切り直したほうが良いのではという意見もありましたが、議論を重ねた結果、マルチモジュール導入を継続することになりました。その際、課題になったのがブランチワークです。
マルチモジュール化を進めつつ各プロジェクトを進行するため、まず作成したのがモジュール分割を行うためのベースブランチです。このブランチには、共通機能のモジュール分割やリブランディングに伴い一新されたカラーパレット等が含まれています。
ベースブランチに含まれる内容は、個別にベースブランチへプルリクエストを行います。ただし、この方法ではコンフリクトが発生しないように常に注意が必要であり、また、各プロジェクトで機能が作りきれないなどの問題が発生してしまいました。コードレビューに暫定的なルールを設定することで多少は状況が改善はしましたが劇的な効果は得られませんでした。
結果的に、このモジュール分割用のベースブランチを作成する手法は失敗だったと思っています。しかし、思わぬ副産物もありました。毎回、モジュール分割やコードのマージ先を判断する必要が発生したため、モジュール分割の粒度に関する議論など、今まで以上にチーム内で綿密なコミュニケーションが図られるようになったのです。難しい開発となったもののメンバー間に認識の齟齬などが発生しなかったのは積極的なコミュニケーションの結果であり、今後のチームとしての自信につながりました。
おわりに
本記事ではココナラAndroidアプリのマルチモジュール構造への取り組みについて紹介しました。機能開発と並行してマルチモジュール化を進めるのは容易ではありませんが、その過程では様々な気付きや学びがありました。まだまだマルチモジュール化は始まったばかりで、ようやく開発の中で自然に取り組めるようになったところです。今後は、新機能開発ではもちろん、既存機能の改修でも積極的に新モジュールでの開発を進めていきます。
ココナラAndroid開発チームでは、マルチモジュール構造への取り組み以外にも様々なチャレンジを継続して行っています。引き続きよりよいプロダクトを継続的に提供できるように取り組んでまいります。
またココナラでは一緒に働く仲間を募集中(エンジニア採用サイト)です。ご興味お持ちいただけた方は、ぜひご連絡をお待ちしております!
著者紹介
中田 有紀
株式会社ココナラ アプリ開発グループ Androidチーム
東京電機大学卒。インフォテック株式会社に入社し、業務系基幹システム開発の経験を積む。その後、DNPコミュニケーションデザインで、Androidアプリエンジニアとしてのキャリアをスタートさせた。2017年9月より現職