Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
熟成されたアプリのmulti module化(halfway)
Search
Tomoya Miwa
April 12, 2019
Programming
1.1k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
熟成されたアプリのmulti module化(halfway)
Tomoya Miwa
April 12, 2019
More Decks by Tomoya Miwa
See All by Tomoya Miwa
基礎から学ぶ大画面対応(Learning Large-Screen Support from the Ground Up)
tomoya0x00
0
8.6k
Re:VIEWで書いた「Compose で Android の edge-to-edge に対応する」をRoo Codeで発表資料にしてもらった
tomoya0x00
0
750
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
510
できる!ComposeでCollapsingToolbar
tomoya0x00
0
1.1k
Compose の LazyColumn パフォーマンス改善で取り組んだこと
tomoya0x00
0
2.5k
ComposeのMutableStateってどうやってLocal Unit Testすれば良いの??
tomoya0x00
0
1.3k
意外と簡単?Navigation rail導入のお話
tomoya0x00
0
1.7k
Kotlin Coroutines Flow を触ってみた話し
tomoya0x00
2
920
Android for Carsのお話し
tomoya0x00
1
1.1k
Other Decks in Programming
See All in Programming
baseline으로 마이그레이션, 리팩토링 안전하게 맡기기
fornewid
1
870
Engineering Biometric UX Across Android Versions | DroidKnights 2026
ryunen344
1
170
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
3
1.4k
Zero-Tap Sign-In対応、結局何をすればいいの?
mitohato14
0
1.5k
複数ドメインを一つのアプリに統合するFlutterの設計と運用_FlutterKaigi2026登壇資料(須永高弘)
takahirosunaga
0
140
Kotlinize Is Not Just Converting to Kotlin
chigichan24
1
220
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
570
Performance Optimization With LLMs
xleitix
0
240
PyConTW 2026 - AI Coding 不只是工具升級, 區域醫院醫療資訊系統協作開發與資訊團隊轉型實踐
cclai999
0
230
Long Living Tokens, Die, Die, Die! (or: The One Ring is Banned in Modern)
sylph01
0
400
Inertia Rails: The One-Person Framework with React & Friends
skryukov
0
380
LLM 101
dalinaum
0
460
Featured
See All Featured
jQuery: Nuts, Bolts and Bling
dougneiner
66
8.7k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
A designer walks into a library…
pauljervisheath
211
25k
Fashionably flexible responsive web design (full day workshop)
malarkey
409
67k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4.6k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
620
A better future with KSS
kneath
240
18k
Being A Developer After 40
akosma
PRO
92
590k
What the history of the web can teach us about the future of AI
inesmontani
PRO
2
780
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
760
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
2
430
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周りの 話しを皆様から聞きたい!!
ありがとうございました