Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
クックパッド Android アプリのマルチモジュール化とデモアプリの活用
こやまカニ大好き
January 12, 2022
Programming
1
5.6k
クックパッド Android アプリのマルチモジュール化とデモアプリの活用
iOS/Androidアプリ開発のマルチモジュール化【アンドパッド|クックパッド|Sansan】 で発表した資料です
https://sansan.connpass.com/event/232503/
こやまカニ大好き
January 12, 2022
Tweet
Share
More Decks by こやまカニ大好き
See All by こやまカニ大好き
2020年代の WebView 実装 / saikou_no_webview_2021
nein37
2
9.9k
Androidアプリをいつまでも楽しく開発し続けるための取り組み
nein37
6
2.1k
minSdkVersion=21にしてから1年経った話
nein37
8
1.8k
Androidアプリエンジニアの基礎知識
nein37
16
10k
クックパッドアプリのマルチモジュール化への取り組み
nein37
11
9.5k
Android のセキュリティよくなってきた話
nein37
3
2.1k
Androidアプリのデザイン整理への取り組み
nein37
1
810
Androidアプリのタブレット向けレイアウト
nein37
4
990
Other Decks in Programming
See All in Programming
動画合成アーキテクチャを実装してみて
satorunooshie
0
560
一口目から美味しいReactのスルメ本🦑
taro28
2
680
リーダブルテストコード / #vstat
jnchito
48
36k
Babylon.jsで作ったsceneをレイトレーシングで映えさせる
turamy
1
210
kintoneでランダム取得を作ってみた(imoniCamp 2022-07-27)
shokun1108
0
150
このタイミングで知っておきたい 開発生産性の高いエンジニア組織の特徴とは / dev-sumi-20220721-productivity-features
findyinc
7
2.7k
RustのWebフレームワーク周りの概観
hayao
0
180
Getting Started With Data Structures
adoranwodo
1
270
Automating Gradle benchmarks at N26
ubiratansoares
PRO
2
140
サーバーレスパターンから学ぶデータ分析基盤構築 / devio2022
kasacchiful
0
500
How to start contributing to Kubernetes Projects
ydfu
0
140
それ全部エラーメッセージに書いてあるよ!〜独学でPHPプログラミングが上達するたった一つの方法〜
77web
1
160
Featured
See All Featured
Clear Off the Table
cherdarchuk
79
290k
Become a Pro
speakerdeck
PRO
3
910
Practical Orchestrator
shlominoach
178
8.7k
How GitHub (no longer) Works
holman
297
140k
Visualization
eitanlees
125
12k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
37
3.3k
Side Projects
sachag
450
37k
WebSockets: Embracing the real-time Web
robhawkes
57
5.6k
Designing the Hi-DPI Web
ddemaree
272
32k
Art, The Web, and Tiny UX
lynnandtonic
280
18k
StorybookのUI Testing Handbookを読んだ
zakiyama
6
2.5k
Pencils Down: Stop Designing & Start Developing
hursman
113
9.9k
Transcript
Android アプリの マルチモジュール化と デモアプリの活用 こやまカニ大好き
自己紹介 こやまカニ大好き クックパッド モバイル基盤部 所属 モバイルアプリ開発の生産性を向上させ るタスクに従事 最近は WebView 大好き
今日のトピック • マルチモジュール化の取り組み • マルチモジュールプロジェクトの課題 • デモアプリの紹介
クックパッドの マルチモジュール化の取り組み
クックパッドアプリの規模感 • アプリ全体で 200 画面くらい(ダイアログも含む) • Kotlin 2700 ファイル、 Java
600 ファイルくらい
マルチモジュール化の歴史 クックパッドアプリでは 2018 年からマルチモジュール化に取り組んでいる 2018年のイベントで初期のマルチモジュール化について発表 【開催レポ】Cookpad.apk #1 〜筋肉はすべてを解決する〜 https://techlife.cookpad.com/entry/2018/11/01/090059
2018 年時点での構想 左側が 2018 年時点での現状 :app と :legacy が分離しただけの状態 そこから
:legacy をどんどん分解して右 側のようにモジュールを増やしていく想定 :legacy :app :legacy :app :featureA :featureB :ui :lib
マルチモジュール化の現状
マルチモジュール化の現状 • 共通ビジネスロジックはモジュール化完了 • 画面実装モジュールも16個存在している • legacy モジュールは引き続き存在している ◦ 1,2
年で全部無くせると思っていたが、作業が大変なものが残ってしまっている • legacy モジュールの解体作業を進めるよりも 新しい機能を別モジュールで作りやすくするという部分に注力
• multi_module.md というファイルにモジュール構成や思想がまとめている ◦ モジュールを増やしたり分割する作業で迷う事が減る ◦ 「未定」とか「特殊」とか書かれていると課題感がわかるので良い • モジュールの分割ポリシーはプロジェクト毎に異なるので、各プロジェクトの方針 をドキュメントに残すと良い
マルチモジュールドキュメントのすすめ
マルチモジュール化の方針 以下の3種類に大まかに分類する • アプリケーションモジュール • 画面実装(VIPERシーン) モジュール • ビジネスロジックモジュール
アプリケーションモジュール ビルド設定ごとに :app プレフィックスをつけたモジュールを定義する • リリース用ビルド、開発用ビルドなどそれぞれモジュールで区別する • APIサーバーの接続先設定などは各 :app モジュールが参照するモジュールを
切り替えることによって実現する(後述)
画面実装(VIPERシーン) モジュール 画面実装(VIPERシーン)は :feature プレフィックスをつけたモジュールで定義 • :feature:tsukurepo, :feature:bookmark のような命名になる •
他の :feature 系モジュールや :legacy への依存は許容しない • 複数の画面(VIPERシーン)がモジュール内に含まれても良い • Dynamic Feature モジュール ではない
ビジネスロジックモジュール ビジネスロジックは :library プレフィックスをつけたモジュールで定義 • :library:infra, :library:ui のような命名になる • 他のモジュールとやりとりする部分は
interface / data class で定義 • 実装クラスはできるだけ internal class で実装する
特殊なモジュール • :setting:base ◦ サーバの接続先設定などの interface だけが入ったモジュール • :setting:internal •
:setting:external ◦ :setting:base の開発版・本番実装 ◦ :app モジュールでどちらかを選んで依存を追加する • :feature:debug_menu ◦ デバッグツール等の実装を押し込めたモジュール ◦ 開発版アプリの :app モジュールだけが依存している
モジュール依存ツリー リリース版 開発版 :app:release :app:internal :feature: debug_menu :settings:external :settings:internal :settings:base
:library modules :feature modules Hyperion, Flipper などの デバッグツールはここ 開発用サーバの設定 本番サーバの設定
マルチモジュール プロジェクトの課題
マルチモジュールプロジェクトの課題 • :feature モジュールの差分を確認するのが面倒 • 画面遷移の解決が難しい • リソース名の重複で上書きされるのが辛い • AndroidManifest
の記述が分散する • gradle の共通設定をどこに書けば良いのか問題 • などなど
マルチモジュールプロジェクトの課題 • :feature モジュールの差分を確認するのが面倒 • 画面遷移の解決が難しい • リソース名の重複で上書きされるのが辛い • AndroidManifest
の記述が分散する • gradle の共通設定をどこに書けば良いのか問題 • などなど
:feature モジュールの差分を 確認するのが面倒 • 動作確認のためにアプリ全体をビルドする必要がある ◦ 巨大な legacy モジュールが存在するクックパッドアプリでは特に辛い •
画面確認のための確認手順が複雑な場合がある ◦ ユーザーのログイン状態 ◦ アプリの利用状態 ◦ APIのレスポンス ◦ などなど
デモアプリの活用
• 特定の :feature モジュールだけに依存する最小規模のアプリ • :demo プレフィックスを持つアプリモジュールとして実装 デモアプリの概要
デモアプリの概要
デモアプリの様子 本来は「ログイン」 「レシピ選択」してからでな いと遷移できない
:feature:tsukurepo に同一の変更を加えて差分ビルド時間を計測した 開発版クックパッドアプリのビルド : 40秒 つくれぽ機能デモアプリのビルド : 12秒 デモアプリの効果
• :feature モジュールの各画面に遷移するためのUI • APIレスポンスなどの Stub 実装 • Stub 実装を
Inject するための仕組み デモアプリの構造
RecyclerView にタイトルを列挙しているだけ 必要なパラメータを渡して画面遷移させる デモアプリのUI
APIレスポンスやユーザー状態を表現する Stub 実装 JSONファイルを読み取ってパースしたり、固定の object を返却したり デモアプリの Stub 実装
Stub 実装のクラスが本番クラスの代わりに Inject されるような仕組みが必要 (Dagger Hilt を使っている前提) デモアプリの Stub Injection
• ライブラリ側の Dagger Module では @InstallIn しない • アプリ側で Dagger
Module を include し、まとめて @InstallIn する • デモアプリでは必要なコンポーネントを全て Stub する デモアプリの Stub Injection(旧)
デモアプリの Stub Injection(旧) :library :library :library :app 後から依存を差し替えるため、ここでは @InstallIn しない
app モジュールで各ライブラリの Module を include
デモアプリの Stub Injection(旧) ライブラリ側の Dagger Module を include すると必要なコンポーネントだ け差し替えるということができないので、
feature モジュールに必要なコンポーネントの Stub を全て bind する :demo
デモアプリの Stub Injection(旧) の課題 • デモアプリの Dagger Module 定義が肥大化しすぎる •
ライブラリモジュールを作る際に普通に @InstallIn してしまいがち • 本番実装が internal class なのでデモアプリから参照できない • 一部だけ本番実装を使うといったことができない ◦ SharedPreferences に読み書きするだけのクラスはそのまま使いたい
デモアプリの Stub Injection(新) クックパッドアプリでは Fake Inject Layer と呼んでいる 以下のような機能を満たす新しい Stub
Injection の仕組み • Dagger Hilt の機能で実現する • Stub が必要なコンポーネントだけを Stub と差し替えられる • Stub と差し替えなかったコンポーネントは本番実装を利用する
デモアプリの Fake Inject Layer • @DebugOverride という Qualifier を用意する •
Stub したいインターフェイスについて、 @DebugOverride @BindsOptionalOf の定義を追加する ◦ これにより、@DebugOverride Optional<T> の依存を Inject してくれるようになる
デモアプリの Fake Inject Layer • 元の実装を bind していた箇所を以下のように変更する ◦ @DebugOverride
でインスタンスが提供されている場合はそれを使い、 提供されていない場合は本物の実装を利用する
デモアプリの Fake Inject Layer • :demo アプリで差し替えたいインスタンスを @DebugOverride で提供する ◦
ここでは Optional として定義する必要は無い
デモアプリの Fake Inject Layer :demo :feature :app :library Stub(@DebugOverride) があれば
Stub を使う Stub がなければ本番実装を使う Fake Inject Layer を提供 :app では何もしない Stub が必要なコンポーネントだけ @DebugOverride で上書きできる 記述量がかなり少なくて済む
• @BindsOptionalOf の記述が必要になるため、ライブラリモジュールの Dagger 実装が増えた ◦ 仕組みを理解していないと謎のおまじないにしか見えない ◦ デモモジュールの実装量はかなり減った •
Fake Inject layer の処理が本番コードに入ってしまっている ◦ これはかなり良くないので将来的には別の方法で解決したい ◦ デモアプリの利便性を考えて現在のクックパッドアプリではこのようにしている Fake Inject layer の難点
まとめ • マルチモジュールプロジェクトの動作確認にはデモアプリが便利 ◦ 見た目の調整だけならかなりの部分はデモアプリで代用可能 • デモアプリの依存解決は難しい • デモアプリの依存解決は難しい…
モバイルエンジニア募集中 https://cookpad.com/ct/205307 未承諾広告※
おわり