要点
- Convention Plugin は 単一の関心を持つ小さな Plugin に分割し、組み合わせて使うのが良い。
- ヘルパー関数(
configureXxx()/setupXxx())の使用は必要最小限に留める。 - NowInAndroid、DroidKaigi 2024、DroidKaigi 2025 の build-logic を観察すると、ヘルパー関数への依存が徐々に減り、Plugin の組み合わせに寄っていく傾向が見える。
Convention Plugin とヘルパー関数
Android のマルチモジュールプロジェクトでは、build-logic(Convention Plugin)でビルド設定を共通化する。Convention Plugin の実装でよく使われるのが、Project の拡張関数として configureXxx() / setupXxx() を定義するパターンである 1。
|
|
初期段階では問題ない。しかし、ヘルパー関数はプロジェクトの成長とともに 関数名から予測できない処理を抱え込みやすい。configureKotlinAndroid に依存追加が紛れ込む、setupFlavor に flavor と無関係なライブラリ依存が含まれる — こうした副作用は、設定を変更しようとしたときに初めて発覚する。
OSS の build-logic を観察する
3 つの OSS プロジェクトの build-logic を比較する 2。
NowInAndroid: ヘルパー関数を広範に使用
NowInAndroid は 16 個の Convention Plugin と 13 個のヘルパー関数を持つ。Plugin の apply() からヘルパー関数を呼び出す構成である。
|
|
一方で、AndroidFeatureImplConventionPlugin は他の Convention Plugin を組み合わせている。
|
|
ヘルパー関数と Plugin の組み合わせが混在するハイブリッド構成である。configureKotlinAndroid() の中には desugaring の依存追加(coreLibraryDesugaring)が含まれており、関数名から予測しにくい副作用の一例になっている。
DroidKaigi 2024: Plugin の組み合わせ + 最小限のヘルパー関数
DroidKaigi conference-app-2024 は primitive / convention の 2 層構造を採用している。
|
|
Convention Plugin は primitive Plugin を組み合わせるだけである。
|
|
ヘルパー関数は setupAndroid() と setupDetekt() の 2 つのみ。中身は compileSdk / minSdk / lint 設定だけで、副作用は含まれていない。3 つの Plugin(AndroidPlugin、AndroidApplicationPlugin、KmpAndroidPlugin)から呼ばれる素朴な共通設定の再利用である。
モジュール側では、必要な primitive を選択して適用する。
|
|
DroidKaigi 2025: ヘルパー関数ゼロ
DroidKaigi conference-app-2025 では、ヘルパー関数が完全に消えた。precompiled script plugin(.gradle.kts)に移行し、各ファイルが直接設定を記述する。
|
|
primitive / convention の 2 層構造は維持されているが、util/ に残っているのは Version Catalog のアクセサや Compose の DSL ラッパーのみで、setup / configure 系の関数はゼロである。
3 プロジェクトの対比
| 観点 | NowInAndroid | DroidKaigi 2024 | DroidKaigi 2025 |
|---|---|---|---|
| Plugin 数 | 16 | 33(primitive 31 + convention 2) | 13(primitive 12 + convention 1) |
| ヘルパー関数 | 13 個(広範に使用) | 2 個(最小限) | 0 個 |
| Plugin の組み合わせ | 一部のみ | 全面的 | 全面的 |
| primitive / convention 分離 | なし | あり | あり |
| 副作用の混入 | あり | なし | なし |
提案: 小さな Plugin を組み合わせる
OSS の観察から導かれる設計指針は 2 つある。
1. 単一責務の小さな Plugin を作る
Plugin は 1 つの関心だけを持つ。Kotlin 設定、Compose 設定、Hilt 設定をそれぞれ独立した Plugin にする。
|
|
Plugin は apply() が冪等であることが期待されるため、「ついでにこの依存も」という追加に対して心理的な抵抗が生まれやすい。ヘルパー関数にはこの制約がない。
2. ヘルパー関数は必要最小限に留める
ヘルパー関数を禁止する必要はないが、複数の Plugin から呼ばれる internal fun Project.configureXxx() は Plugin への昇格を検討すべきである。
残してよいケース:
- Plugin 内部の
private funとして処理を整理する場合 - Version Catalog のアクセサなど、設定を持たない純粋なユーティリティ
避けるべきケース:
- 複数の Plugin から呼ばれ、中身が膨らみやすい
internal fun Project.configureXxx() - 関数名の範囲を超える処理(依存追加、タスク登録など)を含んでいる場合
判断基準は「その関数を削除したとき、呼び出し元が意図しない影響を受けるか」である。影響を受けるなら、Plugin に昇格させて責務を明示する。
libs.versions.toml の変数名を camelCase にする
DroidKaigi のプロジェクトでは、libs.versions.toml の変数名を camelCase で記述している。
|
|
camelCase にすると、Kotlin 側で libs.composeBom とそのままアクセスできる。ケバブケースの場合は libs.compose.bom とドット区切りに変換されるため、名前空間の階層が意図せず生まれる。小さな違いだが、build-logic 内で Version Catalog を頻繁に参照する場合は地味に便利である。
参考
本記事の設計指針に基づいたサンプルプロジェクトを公開している。
まとめ
- Convention Plugin は 小さく、単一責務 に作る。
- 小さな Plugin を 組み合わせ て、モジュールの要件に応じた設定を組み立てる。
- ヘルパー関数(
configureXxx()/setupXxx())は必要最小限に留める。複数の Plugin から呼ばれるヘルパー関数は、Plugin への昇格を検討する。