【15分で学ぶ】クリーンアーキテクチャ入門 #3
「依存の逆転」で境界を越える
前回の記事では、
「重要なビジネスルール(ポリシー)は、重要でない実装の詳細を知るべきではない」
という『依存性のルール』について解説しました。
しかし、ここで一つの疑問が生まれます。
「ビジネスルールがデータベースのことを知らないのに、どうやってデータを保存するの?」
この問いを解決する鍵こそが、SOLID原則の一つである
依存性逆転の原則 (Dependency Inversion Principle: DIP) です。
「処理の流れ」と「依存関係」の分離
プログラムの実行時、処理は
ビジネスルール(ポリシー)→ データベース操作(詳細)
と流れていきます。これは 処理の流れ(Flow of Control) であり、ごく自然なものです。
しかし、ソースコードの 依存関係(Source Code Dependency) も同じ方向に向いてしまうと…
- ポリシーが詳細に依存する
- 技術的な制約に引きずられて変更しにくくなる
そこで重要なのは以下の考え方です:
処理の流れ と 依存関係の流れ は、同じである必要はない。
依存関係の方向だけを 逆転 させることで、疎結合な設計が実現できます。
依存性逆転の原則とは?
上位レベルの方針は、下位レベルの詳細に依存すべきではない。
両方とも、抽象に依存すべきである。
✅ 抽象(インターフェース)を間に挟む
- 処理の流れ はポリシー → 詳細のままでOK
- 依存関係の流れ を 詳細 → ポリシー に逆転させる
具体例:ユーザーを保存する処理
❌ 悪い例:ポリシーが詳細に依存している
この場合、BusinessLogic
は MySQLDriver
を知ってしまっています。
将来、MySQL → PostgreSQLに切り替えるとき、ビジネスロジックも修正が必要になります。
→ 「依存性のルール」に違反!
✅ 良い例:抽象(インターフェース)に依存する
ステップ1:ポリシー側に「抽象(インターフェース)」を定義
// Userエンティティ(ポリシーの一部)
class User {
constructor(public name: string) {}
}
// どこに定義されるか? -> ポリシー側
interface IUserRepository {
save(user: User): void;
}
→ IUserRepository
は「save できるリポジトリが欲しい」という仕様だけを定義。
実装は含まれません。
ステップ2:依存関係を逆転させる
// どこに定義されるか? -> 詳細(インフラ)側
class MySQLUserRepository implements IUserRepository {
public save(user: User): void {
// MySQLに保存するための具体的な処理...
console.log(`Saving ${user.name} to MySQL.`);
}
}
図で表すと:
BusinessLogic
は MySQLUserRepository
の存在を知りません。
知っているのは IUserRepository
という抽象インターフェースだけ です。
これが 依存性の逆転(依存の矢印が「詳細 → ポリシー」に向いている状態)です
🆗 この構造のメリット
- データベースを PostgreSQL に変えたくなったら?
→PostgreSQLUserRepository
を作るだけでOK! - ビジネスロジックは一切変更不要!
Next
解説は以上になります。
最後の記事ではまとめと感想について語ります。
Discussion