🏊‍♂️

【WHYクリーンアーキテクチャ?#2】全てのエンジニアが知るべきシステム設計の基本(ドメインモデル~インフラストラクチャー)

に公開

前回の記事では、「変更に強いシステム」の魂である 依存性のルール と、それを支える3つのものさし(凝集度・結合度・安定度)を学びました。

私たちは「依存の矢印は、不安定なものから安定なものへ向かうべきだ」というコンパスを手に入れました。しかし、ここで新たな疑問が生まれます。

「一体、私たちのシステムのどこが『不安定』で、どこが『安定』なのだろう?」

この問いに明確な答えを与えてくれるのが、クリーンアーキテクチャが示す具体的なレイヤー(層)構造です。

このという概念を無視してしまえば、たとえモジュールを機能ごとに綺麗に分けても(高凝集)、結局はビジネスルールがUIの変更に引きずられるような、脆い依存関係が生まれてしまいます。

今回は、第一章で手に入れたコンパスを片手に、クリーンアーキテクチャという名の 「設計図」 を内側の層から一枚ずつ、丁寧に読み解いていきます。

設計図を読み解くための「3つの視点」

下の画像がクリーンアーキテクチャの全体像を示す設計図です。

この内側の層から順に見ていきますが、その前に、前回の記事で手に入れた3つの「ものさし」を思い出してください。

この設計図の全ての線と円は、この3つの視点からその意味を読み解くことができます。

  • 視点1:凝集度
    • 各レイヤーのモジュールは、本当に一つの関心事に集中できているか?
  • 視点2:結合度
    • 各レイヤー間・モジュール間の連携(コミュニケーション)は、お互いの内部に踏み込まない疎な関係になっているか?
  • 視点3:安定度
    • 依存の矢印は、外側の不安定なレイヤーから、内側の安定したレイヤーへと、正しく向かっているか?

この3つの視点をコンパスとして持ちながら、各層の役割と責任を詳しく見ていきましょう。

内側から外側へ:各層の役割と責任

ドメインモデル ~システムの「名詞」と「ルール」を定義する~

ドメインモデルは、クリーンアーキテクチャの最も内側に位置する、システムの魂とも言える層です。

この層の役割は、ビジネスそのものの 「名詞(モノ)」と、それらが従うべき普遍的な「ルール」 を、具体的なコードとして定義することです。

レストランの例で言えば、以下のようなものがドメインモデルにあたります。

  • 名詞(構造的なモデル): 「注文」「顧客」「料理」
  • ルール(振る舞いに関するモデル): 「注文の合計金額を計算するロジック」「コース料理の構成ルール」「アレルギー食材をチェックするロジック」

関心事は「What」であり、「How」ではない

ここで最も重要なのは、ドメインモデルは システムが「何であるか(What)」を定義するだけで、「どのように使われるか(How)」 には一切関心がない、という点です。

例えば、「注文」モデルは、自身の合計金額を計算する方法は知っていますが、その情報がどのように画面に表示されるか、どのようにデータベースに保存されるか、といった外部の都合は全く知りません。

このように、ドメインモデルは他のどのレイヤーにも依存しないため、最も安定度が高く、システムの不変的な核として存在します

この純粋なビジネスルールをコードとして中心に置くことこそが、クリーンアーキテクチャの出発点なのです。

ユースケース ~アプリケーションの「動詞」~

ドメインモデルがシステムの「名詞(モノやルール)」だとしたら、ユースケースは、それらの名詞を使って アプリケーションが「何ができるか」を定義する「動詞」 です。

ユースケースは、ドメインモデルに定義されたルールに従いながら、具体的な目的を達成するための手順やシナリオを記述します。そして、依存関係はドメインモデルにのみ許されています。

ユースケースと「外部」を隔てる境界線

ここで非常に重要なのが、ユースケースは 「誰が」「どうやって」その操作を行うのかという、システムの「外部」の都合からは完全に独立しているという点です。

レストランの例で考えてみましょう。

  • ユースケース:「顧客の注文を受け付ける」
    • これは純粋なビジネスロジックです。注文内容を受け取り、在庫を確認し、調理場に指示を出す、といった手順を定義します。
      このユースケースを呼び出す方法は、いくつも考えられます。
  • 方法A: ウェイターが手書きのメモで注文を取る。
  • 方法B: 顧客が自身のスマホでQRコードを読み取って注文する。

ウェイターが注文を取ろうが、顧客がスマホで注文しようが、レストランの厨房で行われる 「注文を受け付ける」という本質的な手順(ユースケース)は一切変わりません。

このように、UIや外部デバイスといった不安定な「技術的な詳細」の変更から、アプリケーション固有のビジネスルール(ユースケース)を守ること。これこそが、このレイヤーが持つ重要な役割なのです。

そして、ユースケースは自分が依存しているドメインモデル(メニューなど)よりも不安定です。なぜなら、ユースケースはビジネスの要求によって変化する可能性があるからです。

しかし、UIやデータベースといった外部の技術よりは遥かに安定しています

このように、ユ-スケースはドメインモデルと外部の間に立ち、「より安定した内側(ドメインモデル)にのみ依存する」 という原則を守ります。

これにより、依存の矢印は常にシステムの中心へと向かい続けるのです。

インターフェースアダプター ~外部と内部の「通訳者」~

ユースケース層がアプリケーションの純粋なビジネスルールを定義しました。では、そのルールは一体誰が、どのように呼び出すのでしょうか?

その 外部の世界(The Outside World)と内側の世界(The Inner World) を繋ぐ「通訳」の役割を担うのが、このインターフェースアダプター層です。

インターフェースアダプター:厨房とホールを繋ぐ「唯一の窓口」
この層の役割は、レストランにおける厨房とホールを繋ぐ「唯一の窓口」そのものです。代表例であるコントローラーの仕事を見ていきましょう。

1.外部からのリクエストを「翻訳」する

ウェイター(Webフレームワーク)が、お客様からの多様なリクエストを持って「窓口(あなたのコントローラーのコード)」にやってきます。
窓口は、その曖昧なリクエストを、厨房が 一意に理解できる注文伝票(入力データ) の形式にきれいに整形します。

2.内部へ仕事を「委譲」する

窓口は、完成した注文伝票を厨房の担当者(ユースケース)に渡します。
窓口の担当者は、カルボナーラの 作り方(ビジネスロジック)は一切知りません。 ただ、適切な担当に仕事を依頼するだけです。

3.内部からの結果を「翻訳」して返す

厨房で料理が完成すると、それは窓口に戻されます。窓口は、その料理がどの注文に対するものかをウェイターが理解できる形式で伝えます。


このように、コントローラーという「窓口」は、外部の都合と内部の都合が互いに干渉しないように交通整理を行う、システムの 「防波堤」 としての役割を果たしているともいえます。

インフラストラクチャー ~移り変わる世界との「接続点」~

これまで見てきた内側のレイヤー(ドメインモデル、ユースケース)は、いわばレストランの運営マニュアルや調理手順書のようなものでした。これらは全て、具体的な道具がなくても設計できる 「ルール」 です。

インフラストラクチャー層は、これらのルールを 現実世界で実行可能にするための、全ての具体的な「道具」や「外部システム」 が集まる場所です。

レストランの例で言えば、以下のようなものがインフラストラクチャー層にあたります。

  • データベース:顧客情報や売上を記録する 「A社製の金庫」や「B社製の会計ソフト」 といった具体的な製品。
  • Webフレームワーク:ウェイターが注文を取るために使う 「iPad」や「手書きの伝票とペン」 といった具体的なツール。
  • 外部サービス:決済を行うための 「PayPayのQRコードリーダー」や「三井住友カードの決済端末」

依存性のルール、最後の砦

例えば、決済方法として「PayPay」を導入したとします。しかし、もし将来「楽天ペイ」の方が手数料が安いと分かれば、ためらわずに乗り換えるべきです。

クリーンアーキテクチャが守られていれば、「PayPayの決済端末」というインフラストラクチャーを「楽天ペイの決済端末」に入れ替えても、「会計をする」というユースケースや、「注文」というドメインモデルには一切の変更が必要ありません。

なぜなら、内側の層は 「決済を行う」という抽象的な役割を要求しているだけ で、その役割を具体的にどの会社のどの端末が担うかは全く知らないからです。内側の層と具体的な決済端末(インフラ)の間には、前章で見たインターフェースアダプターという名の『通訳者』が立っており、この詳細を吸収してくれているのです。

このように、インフラストラクチャー層は、ビジネスの根幹を守りながら、時代の変化に合わせて 最も柔軟に入れ替え可能であるべき「詳細」 の全てを引き受ける、システムの最後の砦なのです。

Discussion