TL;DR

内容

単一責任の原則

単一責任の原則(SRP)は SOLID 原則の S にあたり、「コンポーネントを変更する理由は 1 つだけになるようにすべきである」という原則である。「1 つのことだけを行う」と解釈されがちだが、大事なのは変更する理由が 1 つしかない点である。そうであれば、ほかの理由でソフトウェアが変わるとき、そのコンポーネントを変更対象から外せる。

変更する理由は依存関係からもたらされる。ほかのすべてのコンポーネントに直接・間接に依存するコンポーネントは、依存先のどれかが変わるたびに変更の理由を抱える。どこにも依存しないコンポーネントは、自身の機能に変更が求められたときだけ変わる。SRP を守らないコードベースでは、各コンポーネントが抱える変更の理由が増え続け、あるコンポーネントの変更がほかのコンポーネントを壊すことが頻発するようになる(A Philosophy of Software Design 第2章 The Nature of Complexity)。

依存関係逆転の原則

依存関係逆転の原則(DIP)は SOLID 原則の D にあたり、「コードベース内の依存関係は、どのようなものでも向きを逆転できる」という原則である。これを使うと、ドメイン層から永続化層への依存を逆転させ、永続化層がドメイン層に依存する形にできる。

クリーンアーキテクチャ

クリーンアーキテクチャは、2012 年に Robert C. Martin が提唱した概念である。中心となるルールは「すべての依存は中心に向かうようにする」ことで、依存関係逆転の原則を使ってすべての依存をドメイン層(中心)に向ける。

一番中心にあるのはエンティティである。その外側のユースケースは、エンティティを操作するコンポーネントで、一般にサービスと呼ばれる。ユースケースは単一責任の原則を守って粒度を細かくし、肥大化したサービスになるのを避ける(手を動かしてわかるクリーンアーキテクチャ 第2章 従来の多層アーキテクチャの何が問題なのか?)。さらに外側のコントローラは、永続化や UI のようにビジネスルールを支えるコンポーネントで、アダプタを使ってデータベースなどの外部とやり取りする。

メリットは、ドメイン層のコードが、永続化やフレームワークに何が使われているかを知らなくてよいことである。開発者はドメイン層でビジネスルールの実装に集中できる。ドメイン層のコードだけでモデリングできるので、ドメイン駆動設計とも相性がよい。

デメリットは、各層がエンティティを表す独自のモデルを持つ必要があり、モデルを変換する手間がかかることである。たとえば ORM のエンティティはそのままではドメイン層で使えないので、同じエンティティを表すクラスを別々に持ち、層をまたぐたびに DTO などで変換する。ドメイン層と Web 層の間でも同じことが起きる。あえてモデルを変換せず、ドメイン層と永続化層を密結合にする戦略もある(第 9 章「境界を超える際のモデルの変換」で扱う)。

ヘキサゴナルアーキテクチャ

ヘキサゴナルアーキテクチャは、2005 年に Alistair Cockburn が考案したアーキテクチャである。六角形の中には、ドメイン層のエンティティと、それを操作するユースケースが入る。これがアプリケーションのコアである。六角形は外に向かって依存せず、「すべての依存は中心に向かう」というルールに従っている。

六角形の外にはさまざまなアダプタがあり、これを通して Web やデータベースなどの外部とやり取りする。アプリケーションを呼び出すのが受信アダプタ、アプリケーションから呼び出されるのが送信アダプタである。コアとアダプタのやり取りは、ポートと呼ばれるインタフェースを介して行う。

  • 受信ポート: 受信アダプタから呼び出され、コアのユースケースが実装する
  • 送信ポート: ユースケースから呼び出され、アダプタが実装する

1 つのポートを複数のアダプタが実装することもある。外部と実際にやり取りする送信アダプタが実装することもあれば、モックが実装することもある。ポートとアダプタでやり取りするので、ポート&アダプタとも呼ばれる。コアが何をするかを明確にするため、外部へのインタフェースであるポートはコアが定義し、所有する。アダプタがコアとどう連携するかは、ポートによって決まる。

ヘキサゴナルアーキテクチャと層

ヘキサゴナルアーキテクチャも、複数の層を持つように構成できる。以下は一例で、重要なのはコアが外部の関心事から隔離されているので自由に設計できる点である。

一番外側のアダプタ層は、外部との間でデータを変換する。その内側のアプリケーション層には、コアとやり取りするためのインタフェースとしてポートを定義する。さらに内側のドメイン層には、ビジネスルールを実装したエンティティを置く。ビジネスロジックは、ユースケースを実現するクラスとエンティティに実装される。

本書では、ユースケースを実現するクラスをドメインサービスと呼び、基本的にユースケースを 1 つだけ実装する。組み合わせて使う頻度が高く、まとめたほうが保守容易性が高い場合は、複数を実装してもよい。アプリケーションサービスは、ポートとドメインサービスの間にあり、ドメインサービスを外部から守ったり、ドメインサービス同士のやり取りを調整したりする。

これらの用語は、ドメイン駆動設計での意味と少し異なる。DDD のドメインサービスは、エンティティや値オブジェクトで表現できない重要なプロセスを表すオブジェクトであり、DDD のアプリケーションサービスは、ドメインオブジェクトを調整し、トランザクションなどアプリケーションの関心事を扱う。本書のドメインサービスは、DDD のアプリケーションサービスを取り込んだ「ユースケースを実現するもの」という位置づけである。

キーワード

自分の理解

なお、「Clean Architecture はアーキテクチャパターンではない」という点も押さえておきたい。

クリーンアーキテクチャでは責務がはっきりしているので、どこに何を実装するかを考える必要もない。

ヘキサゴナルアーキテクチャの送信アダプタは、依存関係逆転の原則で依存を逆転させている。コアがポートを定義して所有するのは依存の向きに沿っており、レイヤードアーキテクチャとは逆である(手を動かしてわかるクリーンアーキテクチャ 第2章 従来の多層アーキテクチャの何が問題なのか?のデータベース中心の設計の話)。