モジュール化する理由
ビルド速度、所有権、再利用性を高めます。
「モジュール化する理由」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全4レッスンが含まれています。
モノリスの問題
Androidアプリが成長すると、すべてのコードが1つのappモジュールに置かれたままになることがよくあります。これがモノリスです。最初は便利ですが、時間が経つにつれて問題になります。変更のたびに同じモジュールを触る必要があり、ビルドは遅くなり、チームメンバー同士が頻繁に作業を妨げ合うようになります。
モジュール化とは、1つの大きなモジュールを、役割に集中した小さなGradleモジュールへ分割することです。このレッスンでは、なぜチームがモジュール化を行うのか、そしてどのような具体的なメリットがあるのかを学びます。
モジュールとは実際には何か
Gradleにおけるモジュールとは、独自のbuild.gradle.ktsファイルを持ち、単独でビルドできるコードの単位です。アプリにはすでに少なくとも1つ、:appモジュールがあります。すべてのモジュールはsettings.gradle.ktsで宣言します。
モジュールの追加は、includeするだけで簡単に行えます。各モジュールは独自のビルド成果物を生成し、他のモジュールに依存できます。
// settings.gradle.kts
include(":app")
include(":core:designsystem")
include(":core:data")
include(":feature:home")
include(":feature:profile")メリット1:ビルドの高速化
実用上最も大きなメリットはビルド速度です。Gradleはモジュールを並列にビルドでき、さらに重要な点として、入力に変更がないモジュールをキャッシュしてスキップできます。
:feature:profileだけを編集した場合、Gradleは他のすべてのモジュールについて、すでにビルド済みの成果物を再利用します。モノリスでは、どのような変更でもアプリ全体の再コンパイルが必要になる可能性があります。
- モジュール間の並列実行
- インクリメンタルビルド:変更された部分だけを再ビルド
- リモートキャッシュやビルドキャッシュのヒット率向上
// gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=trueメリット2:明確な境界
モジュールは境界を強制します。あるモジュールのコードから見えるのは、別のモジュールが意図的に公開したものだけです。これにより、すべてのクラスが他のすべてのクラスに手を伸ばす、絡み合ったスパゲッティコードを防げます。
公開範囲は、Gradleのapiとimplementationの設定で制御します。implementationを使うと依存関係がモジュール内に隠蔽され、利用側が誤って使うこともありません。
// feature/profile/build.gradle.kts
dependencies {
// Exposed to whoever depends on :feature:profile
api(project(":core:model"))
// Private: hidden from consumers of this module
implementation(project(":core:network"))
}メリット3:再利用
ロジックを役割に集中したモジュールにまとめると、どこからでも再利用できます。テーマ、色、再利用可能なcomposableを保持する:core:designsystemモジュールは、すべてのfeatureで共有できます。
この考え方は複数のアプリにも適用できます。企業はコードをコピーする代わりに、複数のプロダクト間で:core:networkモジュールを共有できます。
// Any feature can pull in shared building blocks
// feature/home/build.gradle.kts
dependencies {
implementation(project(":core:designsystem"))
implementation(project(":core:data"))
}メリット4:チームごとの所有権
モジュールはチームの担当範囲ときれいに対応します。決済チームが:feature:paymentsを、プロフィールチームが:feature:profileを担当します。コードが別々のフォルダーとビルドファイルに分かれているため、マージコンフリクトを減らしながら並行して作業できます。
CODEOWNERSファイルのようなツールを使えば、モジュールのパスに基づいて適切なチームへレビューを自動的に依頼できます。
# .github/CODEOWNERS
/feature/payments/ @org/payments-team
/feature/profile/ @org/profile-team
/core/designsystem/ @org/platform-teamメリット5:可視性によるカプセル化
モジュール内では、Kotlinのinternal修飾子が強力に機能します。internalなクラスや関数は自身のモジュール内でのみ参照できます。他のモジュールからは文字どおり参照できません。
これにより、公開するAPIを小さく保ちながら実装の詳細を隠せます。これは、1つの巨大なモジュールでは強制できないことです。
// In :core:data
// Public API other modules may use
fun interface UserRepository {
suspend fun loadUser(id: String): User
}
// Hidden from other modules
internal class DefaultUserRepository(
private val api: UserApi
) : UserRepository {
override suspend fun loadUser(id: String) = api.fetch(id).toUser()
}コスト:多少のオーバーヘッド
モジュール化は無料ではありません。モジュールごとに保守するbuild.gradle.ktsが増え、コードの各部分をどのモジュールが所有するかも考える必要があります。小さなアプリを過度にモジュール化すると、メリットがないまま作業だけが増えます。
目安としては、ビルド時間が問題になったとき、チーム間で作業がぶつかるとき、または明確に再利用できるレイヤーがあるときにモジュール化します。趣味で作る週末アプリに30個ものモジュールが必要になることは、ほとんどありません。
一般的なモジュール構成
一般的で拡張しやすい構成では、モジュールをapp、feature、coreのレイヤーに分けます。:appモジュールがすべてをつなぎ合わせ、featureにはユーザー向けの画面を、coreモジュールには共有インフラを配置します。
// Conceptual project tree
// app/ <- single entry point, wires features
// feature/
// home/
// profile/
// settings/
// core/
// designsystem/ <- theme + reusable composables
// data/ <- repositories
// network/ <- Retrofit/Ktor
// model/ <- shared data classesConvention Pluginで構成を整理する
モジュールが多い状態で、同じGradle設定をあちこちにコピー&ペーストするのは危険です。チームでは共有設定をconvention plugin(build-logicモジュール内)に切り出します。各モジュールは何十行もの設定を繰り返す代わりに、1つのプラグインを適用するだけになります。
このパターンは、Now in Androidのような大規模なオープンソースアプリで確認できます。今は目的だけ覚えておきましょう。ビルドファイルを小さく、統一された状態に保つことです。
// feature/home/build.gradle.kts
plugins {
// One convention plugin sets up Android + Compose + Kotlin
id("myapp.android.feature")
}
android { namespace = "com.myapp.feature.home" }考え方:レイヤーで捉える
最も役立つメンタルモデルは、依存関係が下向きに流れるというものです。featureはcoreに依存し、coreはfeatureに依存しません。:appモジュールは最上位に位置し、アプリを組み立てるために必要なすべてのものに依存します。
この方向性を一貫して保てば、モジュールグラフがきれいになり、循環依存も避けられます。循環依存については後のレッスンで詳しく学びます。
// Allowed: app -> feature -> core
// Forbidden: core -> feature (upward) or feature -> feature (sideways)
// app/build.gradle.kts
dependencies {
implementation(project(":feature:home"))
implementation(project(":feature:profile"))
}確認問題
成長したAndroidアプリをモジュール化することで、チームが日常的に得られる最も具体的なメリットは次のうちどれですか?
まとめ:モジュール化する理由
チームがモノリスをモジュールに分割する理由を学びました。
- 並列実行とインクリメンタルキャッシュによるビルドの高速化
api/implementationとinternalによる明確な境界- デザインシステムやネットワークなどのcoreレイヤーの再利用
- マージコンフリクトを減らすチームごとの所有権
追加のビルドファイルというコストと、「依存関係は下向きに流す」という原則、つまりapp -> feature -> coreも確認しました。次は、featureモジュールとcoreモジュールの間に実際の境界を定義します。
よくある質問
「モジュール化する理由」レッスンは無料ですか?
はい。「モジュール化する理由」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全4レッスンが含まれています。
「モジュール化する理由」で何を学びますか?
ビルド速度、所有権、再利用性を高めます。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Android Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「モジュール化する理由」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAndroid Academyレッスンでコードを書いて実行できますか?
はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。