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.9k
クックパッド Android アプリのマルチモジュール化とデモアプリの活用
iOS/Androidアプリ開発のマルチモジュール化【アンドパッド|クックパッド|Sansan】 で発表した資料です
https://sansan.connpass.com/event/232503/
こやまカニ大好き
January 12, 2022
Tweet
Share
More Decks by こやまカニ大好き
See All by こやまカニ大好き
マルチモジュールアプリの画面遷移処理実装
nein37
0
4.3k
2020年代の WebView 実装 / saikou_no_webview_2021
nein37
2
10k
Androidアプリをいつまでも楽しく開発し続けるための取り組み
nein37
6
2.1k
minSdkVersion=21にしてから1年経った話
nein37
8
1.8k
Androidアプリエンジニアの基礎知識
nein37
16
10k
クックパッドアプリのマルチモジュール化への取り組み
nein37
11
9.7k
Android のセキュリティよくなってきた話
nein37
3
2.2k
Androidアプリのデザイン整理への取り組み
nein37
1
830
Androidアプリのタブレット向けレイアウト
nein37
4
1k
Other Decks in Programming
See All in Programming
存在しないアセットへの参照と 未公開アセットでのネタバレに どう立ち向かうか / How to prevent missing assets and spoilers by assets
orgachem
0
170
(新米)エンジニアリングマネージャーのしごと #RSGT2023
murabayashi
9
5.9k
Findy - エンジニア向け会社紹介 / Findy Letter for Engineers
findyinc
2
42k
まだ日本国内で利用できないAppActionsにトライしてみた / MoT TechTalk #15
mot_techtalk
0
130
TypeScript 4.9のas const satisfiesが便利
tonkotsuboy_com
9
2.3k
WordPress(再)入門 - 基礎知識・環境編
oleindesign
1
140
Cloudflare Workersと状態管理
chimame
3
490
AWSとCPUのムフフな関係
cmdemura
0
480
NGK2023S - OCaml最高! スマホ開発にも使えちゃう?!
haochenxie
0
120
Swift Observation
shiz
4
290
Qiita Night PHP 2023
fuwasegu
0
11k
ECテックカンファレンス2023
kspace
1
380
Featured
See All Featured
Support Driven Design
roundedbygravity
88
8.9k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
15
1.2k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
224
50k
Code Review Best Practice
trishagee
50
11k
How New CSS Is Changing Everything About Graphic Design on the Web
jensimmons
214
12k
A better future with KSS
kneath
230
16k
Building a Scalable Design System with Sketch
lauravandoore
451
31k
What's new in Ruby 2.0
geeforr
336
30k
Debugging Ruby Performance
tmm1
67
11k
In The Pink: A Labor of Love
frogandcode
132
21k
Web development in the modern age
philhawksworth
197
9.6k
Teambox: Starting and Learning
jrom
124
7.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 未承諾広告※
おわり