はじめに
Clean Architecture のレイヤーと境界を学ぶと、最後に気になるのが 「アプリ全体の起動点はどこに置くのか?」 という問題です。
これを担うのが Main コンポーネント です。
本記事では Main コンポーネントの役割 と、実装パターンを整理します。
1. Main コンポーネントとは?
-
アプリケーションのエントリーポイント
→ プログラムが最初に実行される場所(例:main()
関数、Application
クラス) -
依存の組み立て(Composition Root) を担う
→ すべての依存関係をつなぎ合わせる場所 -
ビジネスロジックの一部ではない
→ Domain や UseCase に属さず、フレームワーク寄りの存在
つまり、Main は アプリケーションの「配線係」 です。
2. Main の責務
a. フレームワークや環境の初期化
- Web サーバ起動 (Spring Boot, Ktor, Express など)
- Android の
Application.onCreate()
- iOS の
AppDelegate
b. 依存関係の組み立て(DI)
- UseCase に Repository を渡す
- Presenter に UseCase を渡す
c. 実行開始
- 最初のユースケースを呼び出す
- 最初の画面を表示する
3. コード例(Kotlin)
// Domain 層
data class User(val id: String, val name: String)
interface UserRepository {
fun findById(id: String): User
}
class GetUserUseCase(private val repo: UserRepository) {
fun execute(id: String): User = repo.findById(id)
}
// Infrastructure 層
class SqlUserRepository : UserRepository {
override fun findById(id: String) = User("123", "Taro")
}
// Presentation 層
class UserPresenter(private val useCase: GetUserUseCase) {
fun showUser(id: String) {
val user = useCase.execute(id)
println("User: ${user.name}")
}
}
// Main コンポーネント
fun main() {
// 依存を組み立てる
val repo = SqlUserRepository()
val useCase = GetUserUseCase(repo)
val presenter = UserPresenter(useCase)
// 実行開始
presenter.showUser("123")
}
→ Main は依存の接着剤(Composition Root) として働き、アプリ本体のビジネスロジックは Main を知らない。
4. Main の設計指針
-
ビジネスルールを入れない
- Main は純粋な「配線係」
-
変更に強い
- DB の切り替え、フレームワーク変更も Main で組み替えれば済む
-
小さく保つ
- 可能な限りシンプルな依存注入だけにする
-
DI コンテナを利用してもよい
- Koin, Dagger/Hilt, Spring などの DI フレームワークは Main の役割を肩代わりしてくれる
まとめ
- Main コンポーネント = アプリケーションの起動点 + 依存関係の組み立て
- ビジネスルールの一部ではなく、配線・初期化だけを担う
- Main によって依存の方向性(外から内へ)が実現される
Clean Architecture における Main は、全体を貫く「依存の逆転(DIP)」を最後にまとめ上げる ハブ として機能するのです。