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

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

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

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

こやまカニ大好き

January 12, 2022
Tweet

More Decks by こやまカニ大好き

Other Decks in Programming

Transcript

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

    :legacy をどんどん分解して右 側のようにモジュールを増やしていく想定 :legacy :app :legacy :app :featureA :featureB :ui :lib
  2. マルチモジュール化の現状 • 共通ビジネスロジックはモジュール化完了 • 画面実装モジュールも16個存在している • legacy モジュールは引き続き存在している ◦ 1,2

    年で全部無くせると思っていたが、作業が大変なものが残ってしまっている • legacy モジュールの解体作業を進めるよりも 新しい機能を別モジュールで作りやすくするという部分に注力
  3. 画面実装(VIPERシーン) モジュール 画面実装(VIPERシーン)は :feature プレフィックスをつけたモジュールで定義 • :feature:tsukurepo, :feature:bookmark のような命名になる •

    他の :feature 系モジュールや :legacy への依存は許容しない • 複数の画面(VIPERシーン)がモジュール内に含まれても良い • Dynamic Feature モジュール ではない
  4. 特殊なモジュール • :setting:base ◦ サーバの接続先設定などの interface だけが入ったモジュール • :setting:internal •

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

    :library modules :feature modules Hyperion, Flipper などの デバッグツールはここ 開発用サーバの設定 本番サーバの設定
  6. :feature モジュールの差分を 確認するのが面倒 • 動作確認のためにアプリ全体をビルドする必要がある ◦ 巨大な legacy モジュールが存在するクックパッドアプリでは特に辛い •

    画面確認のための確認手順が複雑な場合がある ◦ ユーザーのログイン状態 ◦ アプリの利用状態 ◦ APIのレスポンス ◦ などなど
  7. • ライブラリ側の Dagger Module では @InstallIn しない • アプリ側で Dagger

    Module を include し、まとめて @InstallIn する • デモアプリでは必要なコンポーネントを全て Stub する デモアプリの Stub Injection(旧)
  8. デモアプリの Stub Injection(旧) の課題 • デモアプリの Dagger Module 定義が肥大化しすぎる •

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

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

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

    でインスタンスが提供されている場合はそれを使い、 提供されていない場合は本物の実装を利用する
  12. デモアプリの Fake Inject Layer :demo :feature :app :library Stub(@DebugOverride) があれば

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

    Fake Inject layer の処理が本番コードに入ってしまっている ◦ これはかなり良くないので将来的には別の方法で解決したい ◦ デモアプリの利便性を考えて現在のクックパッドアプリではこのようにしている Fake Inject layer の難点