👋

【15分で学ぶ】クリーンアーキテクチャ入門 #3

に公開

「依存の逆転」で境界を越える

前回の記事では、
「重要なビジネスルール(ポリシー)は、重要でない実装の詳細を知るべきではない」
という『依存性のルール』について解説しました。

しかし、ここで一つの疑問が生まれます。

「ビジネスルールがデータベースのことを知らないのに、どうやってデータを保存するの?」

この問いを解決する鍵こそが、SOLID原則の一つである
依存性逆転の原則 (Dependency Inversion Principle: DIP) です。


「処理の流れ」と「依存関係」の分離

プログラムの実行時、処理は
ビジネスルール(ポリシー)→ データベース操作(詳細)
と流れていきます。これは 処理の流れ(Flow of Control) であり、ごく自然なものです。

しかし、ソースコードの 依存関係(Source Code Dependency) も同じ方向に向いてしまうと…

  • ポリシーが詳細に依存する
  • 技術的な制約に引きずられて変更しにくくなる

そこで重要なのは以下の考え方です:

処理の流れ依存関係の流れ は、同じである必要はない。

依存関係の方向だけを 逆転 させることで、疎結合な設計が実現できます。


依存性逆転の原則とは?

上位レベルの方針は、下位レベルの詳細に依存すべきではない。
両方とも、抽象に依存すべきである。

✅ 抽象(インターフェース)を間に挟む

  • 処理の流れ はポリシー → 詳細のままでOK
  • 依存関係の流れ を 詳細 → ポリシー に逆転させる

具体例:ユーザーを保存する処理

❌ 悪い例:ポリシーが詳細に依存している

この場合、BusinessLogicMySQLDriver を知ってしまっています。
将来、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.`);
  }
}

図で表すと:

BusinessLogicMySQLUserRepository の存在を知りません。
知っているのは IUserRepository という抽象インターフェースだけ です。

これが 依存性の逆転(依存の矢印が「詳細 → ポリシー」に向いている状態)です


🆗 この構造のメリット

  • データベースを PostgreSQL に変えたくなったら?
    PostgreSQLUserRepository を作るだけでOK!
  • ビジネスロジックは一切変更不要!

Next

解説は以上になります。
最後の記事ではまとめと感想について語ります。

まとめ

Discussion