はじめに
ソフトウェア設計では「責務の分離」と「依存の方向づけ」が重要です。
Robert C. Martin の Clean Architecture では、これを Layers(レイヤー) と Boundaries(境界) というキーワードで整理しています。
本記事では、レイヤーと境界の関係を整理し、実践的なコード例を交えて解説します。
1. Layers(レイヤー)
Clean Architecture の基本構造は、同心円のレイヤー で表現されます。
各レイヤーの役割
-
Entities(エンティティ)
ビジネスルールの中心。アプリがなくても成り立つ領域。 -
Use Cases(ユースケース)
アプリケーション固有のビジネスルール。シナリオや操作の流れを規定。 -
Interface Adapters(インターフェース層)
UI, DB, 外部 API をユースケースに適合させる。 -
Frameworks & Drivers(外部要素)
DB、Web フレームワーク、外部サービス。最も変わりやすい層。
2. Boundaries(境界)
レイヤー同士をつなぐ部分に 境界(Boundary) が存在します。
境界の目的は 依存の方向を制御すること です。
依存関係のルール
- 内側のレイヤーは外側を知らない
- 外側のレイヤーは内側に依存できる
- 依存は常に内向き(内側に向かう)
これを 依存関係逆転の原則(DIP) として表現します。
// 内側: UseCase
class GetUserUseCase(private val repo: UserRepository) {
fun execute(id: String): User = repo.findById(id)
}
// 境界: インターフェース
interface UserRepository {
fun findById(id: String): User
}
// 外側: DB 実装
class SqlUserRepository : UserRepository {
override fun findById(id: String): User {
// SQL 実行
return User("123", "Taro")
}
}
→ 内側(ユースケース)は外側(DB 実装)を知らず、インターフェースを境界として依存を逆転させています。
3. Layers × Boundaries の組み合わせ
- レイヤー : 責務を段階的に分離した構造
- 境界 : レイヤー間の依存を制御する仕切り
つまり、「レイヤーを切る」ことと「境界を引く」ことはセット です。
4. Partial Boundaries との関係
前回紹介した Partial Boundaries は、この「レイヤーと境界」の柔軟なバリエーションです。
- すべてのレイヤー間に完全な境界を敷く必要はない
- 将来の変更リスクが高い箇所にだけ「部分的に境界」を入れる
- これにより、コストと柔軟性のバランスを取れる
まとめ
- Layers(レイヤー) は責務を整理する構造
- Boundaries(境界) は依存を制御する仕切り
- 境界をどう引くかは設計のコストと柔軟性のトレードオフ
- 部分的に境界を導入する Partial Boundaries で現実的な落としどころを作れる