Upgrade to Pro — share decks privately, control downloads, hide ads and more …

クックパッド Android アプリのマルチモジュール化とデモアプリの活用

クックパッド Android アプリのマルチモジュール化とデモアプリの活用

iOS/Androidアプリ開発のマルチモジュール化【アンドパッド|クックパッド|Sansan】 で発表した資料です
https://sansan.connpass.com/event/232503/

B61a8b5e5ce71ea4796afaea614bbb19?s=128

こやまカニ大好き

January 12, 2022
Tweet

Transcript

  1. Android アプリの マルチモジュール化と デモアプリの活用 こやまカニ大好き

  2. 自己紹介 こやまカニ大好き クックパッド モバイル基盤部 所属 モバイルアプリ開発の生産性を向上させ るタスクに従事 最近は WebView 大好き

  3. 今日のトピック • マルチモジュール化の取り組み • マルチモジュールプロジェクトの課題 • デモアプリの紹介

  4. クックパッドの マルチモジュール化の取り組み

  5. クックパッドアプリの規模感 • アプリ全体で 200 画面くらい(ダイアログも含む) • Kotlin 2700 ファイル、 Java

    600 ファイルくらい
  6. マルチモジュール化の歴史 クックパッドアプリでは 2018 年からマルチモジュール化に取り組んでいる 2018年のイベントで初期のマルチモジュール化について発表 【開催レポ】Cookpad.apk #1 〜筋肉はすべてを解決する〜 https://techlife.cookpad.com/entry/2018/11/01/090059

  7. 2018 年時点での構想 左側が 2018 年時点での現状 :app と :legacy が分離しただけの状態 そこから

    :legacy をどんどん分解して右 側のようにモジュールを増やしていく想定 :legacy :app :legacy :app :featureA :featureB :ui :lib
  8. マルチモジュール化の現状

  9. マルチモジュール化の現状 • 共通ビジネスロジックはモジュール化完了 • 画面実装モジュールも16個存在している • legacy モジュールは引き続き存在している ◦ 1,2

    年で全部無くせると思っていたが、作業が大変なものが残ってしまっている • legacy モジュールの解体作業を進めるよりも 新しい機能を別モジュールで作りやすくするという部分に注力
  10. • multi_module.md というファイルにモジュール構成や思想がまとめている ◦ モジュールを増やしたり分割する作業で迷う事が減る ◦ 「未定」とか「特殊」とか書かれていると課題感がわかるので良い • モジュールの分割ポリシーはプロジェクト毎に異なるので、各プロジェクトの方針 をドキュメントに残すと良い

    マルチモジュールドキュメントのすすめ
  11. マルチモジュール化の方針 以下の3種類に大まかに分類する • アプリケーションモジュール • 画面実装(VIPERシーン) モジュール • ビジネスロジックモジュール

  12. アプリケーションモジュール ビルド設定ごとに :app プレフィックスをつけたモジュールを定義する • リリース用ビルド、開発用ビルドなどそれぞれモジュールで区別する • APIサーバーの接続先設定などは各 :app モジュールが参照するモジュールを

    切り替えることによって実現する(後述)
  13. 画面実装(VIPERシーン) モジュール 画面実装(VIPERシーン)は :feature プレフィックスをつけたモジュールで定義 • :feature:tsukurepo, :feature:bookmark のような命名になる •

    他の :feature 系モジュールや :legacy への依存は許容しない • 複数の画面(VIPERシーン)がモジュール内に含まれても良い • Dynamic Feature モジュール ではない
  14. ビジネスロジックモジュール ビジネスロジックは :library プレフィックスをつけたモジュールで定義 • :library:infra, :library:ui のような命名になる • 他のモジュールとやりとりする部分は

    interface / data class で定義 • 実装クラスはできるだけ internal class で実装する
  15. 特殊なモジュール • :setting:base ◦ サーバの接続先設定などの interface だけが入ったモジュール • :setting:internal •

    :setting:external ◦ :setting:base の開発版・本番実装 ◦ :app モジュールでどちらかを選んで依存を追加する • :feature:debug_menu ◦ デバッグツール等の実装を押し込めたモジュール ◦ 開発版アプリの :app モジュールだけが依存している
  16. モジュール依存ツリー リリース版 開発版 :app:release :app:internal :feature: debug_menu :settings:external :settings:internal :settings:base

    :library modules :feature modules Hyperion, Flipper などの デバッグツールはここ 開発用サーバの設定 本番サーバの設定
  17. マルチモジュール プロジェクトの課題

  18. マルチモジュールプロジェクトの課題 • :feature モジュールの差分を確認するのが面倒 • 画面遷移の解決が難しい • リソース名の重複で上書きされるのが辛い • AndroidManifest

    の記述が分散する • gradle の共通設定をどこに書けば良いのか問題 • などなど
  19. マルチモジュールプロジェクトの課題 • :feature モジュールの差分を確認するのが面倒 • 画面遷移の解決が難しい • リソース名の重複で上書きされるのが辛い • AndroidManifest

    の記述が分散する • gradle の共通設定をどこに書けば良いのか問題 • などなど
  20. :feature モジュールの差分を 確認するのが面倒 • 動作確認のためにアプリ全体をビルドする必要がある ◦ 巨大な legacy モジュールが存在するクックパッドアプリでは特に辛い •

    画面確認のための確認手順が複雑な場合がある ◦ ユーザーのログイン状態 ◦ アプリの利用状態 ◦ APIのレスポンス ◦ などなど
  21. デモアプリの活用

  22. • 特定の :feature モジュールだけに依存する最小規模のアプリ • :demo プレフィックスを持つアプリモジュールとして実装 デモアプリの概要

  23. デモアプリの概要

  24. デモアプリの様子 本来は「ログイン」 「レシピ選択」してからでな いと遷移できない

  25. :feature:tsukurepo に同一の変更を加えて差分ビルド時間を計測した 開発版クックパッドアプリのビルド : 40秒 つくれぽ機能デモアプリのビルド : 12秒 デモアプリの効果

  26. • :feature モジュールの各画面に遷移するためのUI • APIレスポンスなどの Stub 実装 • Stub 実装を

    Inject するための仕組み デモアプリの構造
  27. RecyclerView にタイトルを列挙しているだけ 必要なパラメータを渡して画面遷移させる デモアプリのUI

  28. APIレスポンスやユーザー状態を表現する Stub 実装 JSONファイルを読み取ってパースしたり、固定の object を返却したり デモアプリの Stub 実装

  29. Stub 実装のクラスが本番クラスの代わりに Inject されるような仕組みが必要 (Dagger Hilt を使っている前提) デモアプリの Stub Injection

  30. • ライブラリ側の Dagger Module では @InstallIn しない • アプリ側で Dagger

    Module を include し、まとめて @InstallIn する • デモアプリでは必要なコンポーネントを全て Stub する デモアプリの Stub Injection(旧)
  31. デモアプリの Stub Injection(旧) :library :library :library :app 後から依存を差し替えるため、ここでは @InstallIn しない

    app モジュールで各ライブラリの Module を include
  32. デモアプリの Stub Injection(旧) ライブラリ側の Dagger Module を include すると必要なコンポーネントだ け差し替えるということができないので、

    feature モジュールに必要なコンポーネントの Stub を全て bind する :demo
  33. デモアプリの Stub Injection(旧) の課題 • デモアプリの Dagger Module 定義が肥大化しすぎる •

    ライブラリモジュールを作る際に普通に @InstallIn してしまいがち • 本番実装が internal class なのでデモアプリから参照できない • 一部だけ本番実装を使うといったことができない ◦ SharedPreferences に読み書きするだけのクラスはそのまま使いたい
  34. デモアプリの Stub Injection(新) クックパッドアプリでは Fake Inject Layer と呼んでいる 以下のような機能を満たす新しい Stub

    Injection の仕組み • Dagger Hilt の機能で実現する • Stub が必要なコンポーネントだけを Stub と差し替えられる • Stub と差し替えなかったコンポーネントは本番実装を利用する
  35. デモアプリの Fake Inject Layer • @DebugOverride という Qualifier を用意する •

    Stub したいインターフェイスについて、 @DebugOverride @BindsOptionalOf の定義を追加する ◦ これにより、@DebugOverride Optional<T> の依存を Inject してくれるようになる
  36. デモアプリの Fake Inject Layer • 元の実装を bind していた箇所を以下のように変更する ◦ @DebugOverride

    でインスタンスが提供されている場合はそれを使い、 提供されていない場合は本物の実装を利用する
  37. デモアプリの Fake Inject Layer • :demo アプリで差し替えたいインスタンスを @DebugOverride で提供する ◦

    ここでは Optional として定義する必要は無い
  38. デモアプリの Fake Inject Layer :demo :feature :app :library Stub(@DebugOverride) があれば

    Stub を使う Stub がなければ本番実装を使う Fake Inject Layer を提供 :app では何もしない Stub が必要なコンポーネントだけ @DebugOverride で上書きできる 記述量がかなり少なくて済む
  39. • @BindsOptionalOf の記述が必要になるため、ライブラリモジュールの Dagger 実装が増えた ◦ 仕組みを理解していないと謎のおまじないにしか見えない ◦ デモモジュールの実装量はかなり減った •

    Fake Inject layer の処理が本番コードに入ってしまっている ◦ これはかなり良くないので将来的には別の方法で解決したい ◦ デモアプリの利便性を考えて現在のクックパッドアプリではこのようにしている Fake Inject layer の難点
  40. まとめ • マルチモジュールプロジェクトの動作確認にはデモアプリが便利 ◦ 見た目の調整だけならかなりの部分はデモアプリで代用可能 • デモアプリの依存解決は難しい • デモアプリの依存解決は難しい…

  41. モバイルエンジニア募集中 https://cookpad.com/ct/205307 未承諾広告※

  42. おわり