Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
熟成されたアプリのmulti module化(halfway)
Search
Tomoya Miwa
April 12, 2019
Programming
2
940
熟成されたアプリのmulti module化(halfway)
Tomoya Miwa
April 12, 2019
Tweet
Share
More Decks by Tomoya Miwa
See All by Tomoya Miwa
Re:VIEWで書いた「Compose で Android の edge-to-edge に対応する」をRoo Codeで発表資料にしてもらった
tomoya0x00
0
420
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
380
できる!ComposeでCollapsingToolbar
tomoya0x00
0
960
Compose の LazyColumn パフォーマンス改善で取り組んだこと
tomoya0x00
0
2.3k
ComposeのMutableStateってどうやってLocal Unit Testすれば良いの??
tomoya0x00
0
1.1k
意外と簡単?Navigation rail導入のお話
tomoya0x00
0
1.5k
Kotlin Coroutines Flow を触ってみた話し
tomoya0x00
2
840
Android for Carsのお話し
tomoya0x00
1
1.1k
コードカバレッジを⾒つつユニットテストを書く
tomoya0x00
0
400
Other Decks in Programming
See All in Programming
10 Costly Database Performance Mistakes (And How To Fix Them)
andyatkinson
0
240
ruby.wasmで多人数リアルタイム通信ゲームを作ろう
lnit
3
450
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
110
Railsアプリケーションと パフォーマンスチューニング ー 秒間5万リクエストの モバイルオーダーシステムを支える事例 ー Rubyセミナー 大阪
falcon8823
5
1.1k
5つのアンチパターンから学ぶLT設計
narihara
1
160
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
790
XP, Testing and ninja testing
m_seki
3
240
iOS 26にアップデートすると実機でのHot Reloadができない?
umigishiaoi
0
130
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
2
480
dbt民主化とLLMによる開発ブースト ~ AI Readyな分析サイクルを目指して ~
yoshyum
3
900
ふつうの技術スタックでアート作品を作ってみる
akira888
1
490
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
52
33k
Featured
See All Featured
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
181
53k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Adopting Sorbet at Scale
ufuk
77
9.4k
The Cult of Friendly URLs
andyhume
79
6.5k
What’s in a name? Adding method to the madness
productmarketing
PRO
23
3.5k
How STYLIGHT went responsive
nonsquared
100
5.6k
Why You Should Never Use an ORM
jnunemaker
PRO
58
9.4k
VelocityConf: Rendering Performance Case Studies
addyosmani
332
24k
Java REST API Framework Comparison - PWX 2021
mraible
31
8.7k
[RailsConf 2023] Rails as a piece of cake
palkan
55
5.7k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
5
280
Designing for Performance
lara
610
69k
Transcript
熟成されたアプリの multi module化(halfway) Shibuya.apk #33
自己紹介 • Android, Embedded system, BLE, iOS • DeNA Co.,
Ltd. Automotive Business Unit. • 最近、少し高めのカメラレンズ(約8.5万円)を購入 tomoya0x00 Twitter, GitHub, Qiita
比較的、泥臭い話をします
その中で皆様にとって 有益な情報があれば嬉しいです
アウトライン 熟成されたアプリとは? なぜmulti module化するのか? 最初のmodule分割 残りをmodule分割 1 4 3 2
熟成されたアプリとは?
熟成されたアプリと名乗るには 『必要な要素』 だと思ったモノに、 手を上げてください
クラスの循環参照が発生 ※Daggerのlazyで無理矢理コンパイルを通している
状態をあわらすフラグが多数存在
Rxの乱用で 処理を追うのが困難
Singletonかつ、 mutableなクラスが多数存在
レイヤーを無視した クラス間の参照
複数のアーキテクチャが混在
パッケージのトップに 色々なファイルが置いてある
複数の神クラスが存在 ※神クラス = 巨大かつ様々なクラスに依存されている
WebAPIのレスポンスを そのままいたるところで使いまわす ※なお、全てのプロパティがnullable
安心して下さい
今回お話しする 「熟成されたアプリ」は
全ての要素を満たしています!!
話を続けましょう
なぜmulti module化するのか?
理由1 機能ごとのlibrary moduleに分割し、 新規アプリで使いたい
理由2 library module間の依存関係を強制し クラス間の循環参照を撲滅したい
最初のmodule分割
準備
準備 1. 参考資料・ソースに目を通す 2. 切り出したい機能と、 仮のmodule名を一覧化する 3. ブランチかフォークか決める
参考資料・ソースに目を通す ~ その1 ~ • kgmyshinさんの マルチモジュールのすヽめ と 大きめのAndroidアプリでの 設計を考えてみる~pocket~
• レイヤーによるmodule分割と、 機能によるmodule分割
参考資料・ソースに目を通すす ~ その2 ~ • クックパッドアプリの マルチモジュール化への取り組み • 既存の全ての機能を legacy
library moduleに移動 • DroidKaigi/conference-app-2019 • 機能ごと(画面も含めて)にlibrary moduleを分割 • interfaceだけのmoduleと、実装のmoduleに分割
切り出したい機能と、仮のmodule名を一覧化する • 分析ログ • analytics-log • BLE通信 • ble •
位置情報 • location etc...
ブランチかフォークか決める ~ ブランチの場合 ~ • 既存リポジトリでブランチを切って作業 • かなり変更量大のプルリクをつくる事になる • 既存の熟成されたアプリへの影響大
• 途中でdevelopブランチへのマージは厳しい • フルのリグレッションテストを何回も実施??
ブランチかフォークか決める ~ フォークの場合 ~ • 既存リポジトリをコピーした 別リポジトリで作業 • 既存リポジトリへの影響無しに作業できる •
ただし、どこかのタイミングで 既存リポジトリの差分マージが必要
ブランチかフォークか決める ~ 結論 ~ • フォークしてモジュール分割を進め、 新規アプリ開発を優先 • モジュール分割が落ち着いたら 既存リポジトリの差分をマージ
• いずれ既存アプリも、 フォークした別リポジトリからリリース
まずは一つ moduleを分割して 様子をみる
今後のmodule分割作業の 見積もり精度が上がる
どの機能をmodule分割するか?
自分がほとんど書いた機能 (BLE通信周り) ならば、難易度が低いと判断
自分が知っている機能なら 楽勝でしょ?
考えが甘かった (結構大変だった)
一週間ぐらいかかった
最初のmodule分割で やって良かったことや学びなど
最初のmodule分割でやって良かったことや学びなど • Dep.ktとVersions.ktの導入 • 具体的なmodule分割の手順 • Android Studio様は強い味方 • 細かいTips
• ディレクトリ、BuildConfig、ProductFlavor • Dagger周り
Dep.ktとVersions.ktの導入
Dep.ktとVersions.ktの導入 multi module化すると 各library moduleにbuild.gradleがあるため、 指定するバージョンなどがバラバラになる危険性 Kotlinで各dependenciesやバージョンを記入し、 各build.gradleで使用する 参考: DroidKaigi/conference-app-2019のdependenciesディレクトリ
Kotlin + buildSrc for Better Gradle Dependency Management
Dep.ktとVersions.ktの導入 ~ Dep.kt ~ Dep.kt: 各dependenciesを記入 object Moshi { private
val version = "1.8.0" val moshi = "com.squareup.moshi:moshi-kotlin:$version" val codegen = "com.squareup.moshi:moshi-kotlin-codegen:$version" }
Dep.ktとVersions.ktの導入 ~ Versions.kt ~ Versions.kt: compileSdkVersionやversionCode(※ソースでは省略)などを記入 object Versions { const
val androidCompileSdkVersion = 28 const val androidMinSdkVersion = 23 const val androidTargetSdkVersion = 28 }
具体的なmodule分割の手順
具体的なmodule分割の手順 ~ module新規追加 ~
具体的なmodule分割の手順 ~ module新規追加 ~
具体的なmodule分割の手順 ~ module新規追加 ~
具体的なmodule分割の手順 ~ module新規追加 ~
具体的なmodule分割の手順 ~ module新規追加 ~
具体的なmodule分割の手順 ~ module新規追加 ~
名前にハイフンが入っているとダメ →後からリネームならOK
具体的なmodule分割の手順 ~ module新規追加 ~
具体的なmodule分割の手順 ~ module新規追加 ~
具体的なmodule分割作業の手順 ~ build.gradle編集 ~ • library moduleのbuild.gradle編集 • DroidKaigi/conference-app-2019の android.gradleを参考に、
library moduleで共通してapplyするBuild Script導入がお勧め • 各dependenciesの記入 • app moduleや、必要に応じて既存のlibrary moduleのdependenciesに追加
具体的なmodule分割作業の手順 ~ クラスの移動 ~
具体的なmodule分割作業の手順 ~ クラスの移動 ~
具体的なmodule分割作業の手順 ~ クラスの移動 ~
意外と楽ちん!?
具体的なmodule分割作業の手順 ~ クラスの移動 ~
具体的なmodule分割作業の手順 ~ クラスの移動 ~ • 参照できないクラスが色々あって怒られてる • Retrofit周り • library
moduleのbuild.gradleに追加 • API Responseのclass • app moduleにあるので参照できない • library moduleへ同時に移動する
より効率良くおこなうならば?
具体的なmodule分割作業の手順 ~ クラスの移動 ~ 1. 移動するクラスの依存先をリストアップ a. import文でわかる 2. Retrofitなどlibraryはbuild.gradleに追加
3. アプリ内部のクラスであれば同時に移動 a. 単純に移動できない場合は、interface抽出して 一旦依存性を切り離すなど
Android Studio様は強い味方
Android Studio様は強い味方 ~ 強力なリファクタリング機能 ~ • クラスを別moduleへ移動 • 「具体的なmodule分割作業の手順」で紹介済み •
interface抽出 • クラスからPublicなプロパティ、メソッドを選択してinterface 抽出 • ネストされたクラスの移動 • 抽出したinterfaceが、実装クラスにネストされた Enumクラスに依存している場合などに便利
Android Studio様は強い味方 ~ interface抽出 ~
Android Studio様は強い味方 ~ interface抽出 ~
Android Studio様は強い味方 ~ interface抽出 ~
Android Studio様は強い味方 ~ ネストされたクラスの移動 ~
Android Studio様は強い味方 ~ ネストされたクラスの移動 ~
Android Studio様は強い味方 ~ ネストされたクラスの移動 ~
細かいTips • 階層化にディレクトリを使うか否か • library module で BuildConfig を参照 •
Product Flavorとリファクタリング
細かいTips ~ 階層化にディレクトリを使うか否か ~
細かいTips ~ 階層化にディレクトリを使うか否か ~
Android View だとディレクトリ無視 →moduleがフラットに名前順で並ぶ
気になる場合は ディレクトリでは無く module名の接頭語で階層化
細かいTips ~ 階層化にディレクトリを使うか否か ~
細かいTips ~ library module で BuildConfig を参照 ~ • BuildConfigから参照したいプロパティの
interfaceを作成 • library moduleは上記のinterfaceに依存 • app moduleで実装をlibrary moduleに注入
細かいTips ~ library module で BuildConfig を参照 ~ interface EnvVar
{ val BUILD_TYPE: String val API_HOST: String } object EnvVarImpl : EnvVar { override val BUILD_TYPE = BuildConfig.BUILD_TYPE override val API_HOST= BuildConfig.API_HOST }
細かいTips ~ Product Flavorとリファクタリング ~ Product Flavorでソース切替している場合 現在のFlavor以外はリファクタリング対象外
Dagger周り DroidKaigi/conference-app-2019 を参考に library moduleごとに ModuleとComponentを作成
残りをmodule分割
ふむふむ、やり方はわかった
色々踏み抜いたし残りは楽勝っしょ!
module分割を続行・・・
できない
元々の依存関係がぐちゃぐちゃで interfaceの実装クラスを 各moduleに切り出せない・・・
interface抽出して 依存関係を逆転させても 実装自体の依存関係が 逆転するわけではない
どうするのか?
正攻法で立ち向かう
何が依存関係を複雑にしているのか?
何が依存関係を複雑にしているのか? • APIレスポンスを保持して提供する 神クラスが複数存在 ◦ ビジネスロジックも持っている • 分析ログ機能 ◦ 複数の神クラスに依存
2種類のリポジトリを導入
WebApiをラップするRepository • レスポンスをmodelに変換して Observableで提供 • データ更新の関数は結果を返さず、 更新のトリガーとするだけ
神クラス公開情報を保存し、提供するRepository • 神クラスのみが書き込む • 神クラス以外は読み込みオンリー • これで神クラスへの直接依存を防げる
module分割が続行可能となった
迷っているところ
multi moduleでのDagger周りの 話しを皆様から聞きたい!!
ありがとうございました