クックパッドアプリにおける DI の歴史@ksfee684
View Slide
自己紹介● 加藤 恭平(@ksfee684)● モバイル基盤部所属● Android アプリプロジェクトの開発効率化、基盤技術開発
● クックパッドアプリの DI フレームワークの変遷● クックパッドアプリにおける各 DI フレームワークの解説○ 選定理由○ 利用方針■ フレームワーク移行に伴った変更アジェンダ
今日はなさないこと● DI フレームワーク利用方法の説明● DI フレームワークの必要性● DI フレームワークごとの比較○ 選定理由で少し出てきますが、全体通して比較はありません
DI フレームワークの変遷RoboGuice(? ~ 2018)Toothpick(2018 ~ 2019)KOIN(2019 ~ 2020)Dagger(2020 ~)移行を担当見直し見直し
RoboGuice (?~2018)
RoboGuice● https://github.com/roboguice/roboguice○ Google Guice をAndroid に転用したもの● リフレクションベースの DI フレームワーク● 恐らくクックパッドアプリに入った最初の DI フレームワーク
利用方針● 主にインスタンス生成を省略するために利用● Activity や Fragment から値を注入● DI フレームワークの利用ルールはなく、開発者の裁量にあわせて利用○ 複雑に絡み合うオブジェクトの依存関係
RoboGuice の課題点● 当初はリリースされるはずであった RoboGuice4 に乗り換える予定だった● 雰囲気が怪しくなり乗り換えを考え始める
Toothpick (2018~2019)
Toothpick● https://github.com/stephanenicolas/toothpick● アノテーションプロセッサを利用した DI フレームワーク● 依存グラフを持つ Scope が木構造のような親子関係を持つ○ ApplicationScope, ActivityScope
Toothpick の選定理由● 移行にあたって利用方針の見直しは行われないことに● 乗り換え先として Dagger, Toothpick が上がる○ 元々 RoboGuice を上手く活用できておらず、 Dagger の複雑さと学習コストに対して得られるものが少ない○ 縦横無尽な利用方法を整備する上では Dagger の方が強制力がある○ Toothpick の方が移行が容易● 構造がシンプルで移行が比較的容易な Toothpick を選定
Toothpick の課題点● アノテーションプロセッサを利用するようになりビルド時間が増加● 移行当初 Toothpick がまだ発展途上で不安な箇所がいくつかあった○ アノテーションプロセッサによるコード生成
KOIN (2019~2020)
KOIN● https://github.com/InsertKoinIO/koin● Kotlin ベースのジェネリクスと Delegated Properties を利用した DI フレームワーク● 依存グラフは実行時に Map 上で構築される○ Lazy Properties として Map に対してオブジェクトをリクエストする
KOIN の選定理由● アノテーションプロセッサを利用しない DI フレームワークを探し始める○ 移行の容易さ、DI フレームワークの利用の見直しも同時に行う● KOIN, Kodein, Dagger が候補に上がる● 導入のしやすさが決め手に○ 巨大な Map 構造を築くだけで、初学者にも理解しやすい○ パフォーマンス面も申し分なし○ アノテーションプロセッサによるコンパイル時間の増加を回避できる○ Kotlin コードが拡充しつつあった
移行に合わせた利用方針の見直し1● Toothpick 移行時に先送りになっていた利用方針の見直し○ 複雑に絡み合っていたオブジェクトの依存関係を整理○ VIPER + レイヤードアーキテクチャ上で DI フレームワークを活用する■ マルチモジュールも意識した構成に
オブジェクトの依存関係の整理● 単純にオブジェクト生成を省略していたものは DI フレームワークの利用をやめる○ DI フレームワークを利用するオブジェクトのルールを設定● 縦横無尽に注入される Context をやめる○ ApplicationContext? ActivityContext?● xxHolder の削除○ シングルトン制約を DI フレームワークが担うように
VIPER + レイヤードアーキテクチャにおける利用● VIPER + レイヤードアーキテクチャの上で扱うオブジェクトの生成を DI フレームワークを介して行うように● オブジェクト間はすべてインタフェースを介して会話○ オブジェクト生成をすべて任せることで、実体を知らずに済むように○ テスト実行時にオブジェクトのすり替えが可能に
RecipeDataSourceVIPER + レイヤードアーキテクチャにおける利用ServerRecipeDataSourceRecipeContract.ViewRecipeActivityRecipeContract.InteractorRecipeInteractorRecipeContract.PresenterRecipePresenterRecipeContract.RoutingRecipeRoutingVIPERレイヤードアーキテクチャ
RecipeDataSourceVIPER + レイヤードアーキテクチャにおける利用MockRecipeContract.ViewRecipeActivityRecipeContract.InteractorRecipeInteractorRecipeContract.PresenterRecipePresenterRecipeContract.RoutingMockVIPERレイヤードアーキテクチャ
KOIN の課題点● 依存グラフが不十分でもコンパイル時に気づくことができない○ リリース後に Crashlytics で実行時エラーに気づく○ 開発者がアプリ実行まで問題に気づけず生産性が落ちる● クックパッドアプリと Scope の相性が悪い○ ライフサイクルとのひも付きが不十分
Dagger (2020~)
Dagger● https://github.com/google/dagger● アノテーションプロセッサを利用した DI フレームワーク● Google によってメンテナンスが行われている Android 公式フレームワーク
Dagger 選定理由● 課題を解決するために残された最後の手段○ コンパイル時の依存グラフチェック、依存注入タイミングの改善● KOIN 導入段階で利用方針を整理したため Dagger の機能を活用できるようになった● Hilt の導入○ 移行開始当初存在を知らなかった
移行に合わせた利用方針の見直し2● KOIN で自由に依存注入していた箇所をなくす○ エントリーポイントを Activity, Fragment, Service, BroadcastReceiver に限定○ グローバルな値として参照していた箇所を排除
そして次の時代へ…
Dagger Hilt● 実は移行を進めているタイミングで知らなかった …● 更にアノテーションプロセッサによるコードジェネレーションが強まる○ アノテーションだけつければ良くなる時代へ○ 初学者の学習コスト軽減● クックパッドアプリを題材に移行を試みたブログを書いたのでよければ○ https://ksfee.hatenablog.jp/entry/2020/06/17/033304