なぜ「クリーンアーキテクチャ」が必要なのか
ソフトウェア開発の現場で長年働いていると、こんな場面に何度も出くわします。「このシステム、DBをMySQLからPostgreSQLに移行したいんだけど、どこを直せばいいかわからない」「フレームワークを新しいバージョンに上げたら、ビジネスロジックまで壊れた」——こういった悩みの根本には、ほぼ必ずといっていいほど「依存関係の混乱」があります。
クリーンアーキテクチャは、Robert C. Martin(通称 Uncle Bob)が2012年に提唱した設計思想です。MVCやレイヤードアーキテクチャなど、それまで存在していた設計パターンの良いところを統合し、「ビジネスロジックを技術的な詳細から守る」ことを最優先に据えた考え方です。20年以上システム開発に携わってきた筆者も、この思想と出会ってからは設計の悩みが大幅に減りました。本記事ではECサイトを例に、クリーンアーキテクチャの本質を丁寧に解説します。
クリーンアーキテクチャの全体像
同心円で表現される4つの層
クリーンアーキテクチャは、よく同心円(玉ねぎ)の図で表現されます。内側から順に、Entities層・Use Cases層・Interface Adapters層・Frameworks & Drivers層という4つの層で構成されています。この構造で最も重要なルールは「依存の方向は常に内側へ」という一点です。
外側の層は内側の層を知っていても構いませんが、内側の層は外側の層を一切知ってはいけません。たとえば、ビジネスロジックを担うEntities層は、DBが何であるか、Webフレームワークが何であるかを知らなくていいのです。これを徹底することで、技術的な変更がビジネスロジックに波及しない、変更に強いシステムが生まれます。
各層の役割まとめ
| 層 | 別名 | 主な役割 | ECサイトの例 |
|---|---|---|---|
| Entities | エンティティ層 | 不変のビジネスルール | 注文・商品・顧客のルール |
| Use Cases | ユースケース層 | アプリ固有の処理手順 | 注文確定・キャンセル処理 |
| Interface Adapters | インターフェース層 | 内外のデータ変換 | ControllerやRepositoryの実装 |
| Frameworks & Drivers | フレームワーク層 | 技術的な詳細 | MySQL・Stripe・メール送信 |
Entities層——変わらないビジネスルールの核心
この層が守るものとは
Entities層は、システムの存在意義そのものを表す場所です。ECサイトであれば「注文には未確定・確定・キャンセルというステータスがある」「確定済みの注文はキャンセルできない」「注文金額は明細の合計である」といったルールがここに入ります。
これらのルールは、DBがMySQLだろうとPostgreSQLだろうと、フレームワークがLaravelだろうとSymfonyだろうと、一切変わりません。だからこそEntities層は外部の何にも依存せず、最も安定した場所として機能するのです。
ECサイトのEntities設計
ECサイトの注文まわりで洗い出せるクラスは以下のようになります。
Order(注文)——集約の中心。確定・キャンセルなどのルールを持つOrderItem(注文明細)——商品1行分の情報と小計計算OrderId(注文ID)——単なる文字列ではなく「注文IDである」という意味を持つ値オブジェクトOrderStatus(注文ステータス)——pending・confirmed・cancelledの状態と遷移ルールPrice(金額)——0円以下にはなれないというルールを持つ値オブジェクト
重要なのは、これらのクラスがDBへの保存処理やHTTPリクエストの処理を一切持たないことです。「ビジネス担当者が使う言葉をそのままクラスにする」という原則を守ることで、技術者とビジネス担当者が同じ言語で会話できるようになります。これはDDDのユビキタス言語の概念とも深くつながっています。
Use Cases層——「このシステムで何ができるか」を定義する
ユースケースの粒度
Use Cases層は、アプリケーションとして何ができるかを定義する場所です。「注文を確定する」「注文をキャンセルする」「商品を検索する」——1つのユースケースクラスが1つの操作に対応するのが基本です。
ここで重要なのは、ユースケースはEntities層のルールを使いながら処理の「手順」を記述するという役割分担です。DBの具体的な操作方法は知らず、「リポジトリインターフェース越しに保存して」と指示するだけです。これが後述する依存性逆転の原則につながります。
依存性逆転の原則(DIP)
クリーンアーキテクチャで最も理解しにくいのが、依存性逆転の原則(Dependency Inversion Principle)です。Use Cases層がDBに保存したいとき、直接DB実装クラスに依存するのではなく、インターフェース(抽象)を定義して外側がそれを実装する形を取ります。
この構造により、PlaceOrderUseCaseはMySQLのことを何も知りません。DBをPostgreSQLに変えたいなら、MySQLOrderRepositoryを差し替えるだけでよく、ユースケース層は一切変更不要です。20年以上の実務経験を通じて感じることですが、この「差し替えやすさ」が長期運用プロジェクトでは圧倒的な価値を生みます。
Interface Adapters層——翻訳係としての役割
なぜ翻訳が必要か
HTTPリクエストのJSONと、ドメインオブジェクトの形式は異なります。またDBのテーブル構造と、ビジネスルールを持つEntityの構造も異なります。この変換を担うのがInterface Adapters層です。
ここにControllerやPresenter、Repositoryの実装などが入ります。この層があることで、内側の層(EntitiesやUse Cases)は「外の世界がどんな形式でデータを送ってくるか」を気にせずに済みます。
ECサイトでの変換の流れ
お客さんが「注文する」ボタンを押すと、以下のような流れでデータが変換されながら処理されます。
- HTTPリクエストのJSONを受け取る(Frameworks層)
- JSONをPlaceOrderInputというDTOに変換(Interface Adapters層)
- ユースケースが処理を実行(Use Cases層)
- Orderエンティティのルールが判定(Entities層)
- DBに保存(Frameworks層)
- 結果をJSONに変換してレスポンス(Interface Adapters層)
各層が自分の責務だけを担い、隣の層との窓口となる変換処理だけを行うことで、全体が疎結合に保たれます。
Frameworks & Drivers層——技術的詳細をここに閉じ込める
最も変わりやすい場所
Frameworks & Drivers層は、MySQL・Stripe・SendGridといったDB・外部API・Webフレームワーク本体が入る場所です。最も変わりやすく、最も外側に位置します。
重要なのは、この層の変更が内側に波及しないことです。MySQLをPostgreSQLに変えてもEntities層は壊れない。決済をStripeからPayPalに変えてもUse Cases層は壊れない。この「変更の局所化」こそがクリーンアーキテクチャを採用する最大のメリットです。
MVCとクリーンアーキテクチャの違い
視点が根本的に異なる
LaravelやDjangoといったMVCフレームワークを使い慣れている方は「MVCとどう違うの?」と感じるかもしれません。両者は対立するものではなく、視点が異なります。
| 観点 | MVC | クリーンアーキテクチャ |
|---|---|---|
| 主な関心事 | 画面・入力・データの分離 | ビジネスロジックの保護 |
| Modelの位置づけ | DBと密結合しやすい | 純粋なビジネスルール |
| テストのしやすさ | DBなしでは難しい | DBなしで単体テスト可能 |
| 向いている規模 | 小〜中規模 | 中〜大規模・複雑なロジック |
MVCのModelはビジネスロジック・DB操作・メール送信などが混在する「Fat Model」になりがちです。クリーンアーキテクチャはその課題への一つの答えであり、MVCのController部分をクリーンアーキテクチャのFrameworks層に位置づけて共存させることもできます。
クリーンアーキテクチャを採用すべきケース・避けるべきケース
どんなシステムにでもクリーンアーキテクチャを適用すべきかというと、答えはNOです。シンプルなCRUDが中心の管理画面などに適用すると、不必要にコード量が増えてチームの負担になります。
採用を検討すべき状況は以下のとおりです。
- ビジネスルールが複雑で、今後も変化が予想されるシステム
- 長期間(3年以上)保守・拡張が必要なプロジェクト
- チームが複数に分かれて並行開発する場合
- DBやフレームワークを将来的に変更する可能性がある場合
逆に、プロトタイプや短命なシステム、CRUDのみのシンプルな管理ツールには過剰設計になりがちです。設計の選択は「今のシステムに何が必要か」を見極めることが前提です。
まとめ
クリーンアーキテクチャは「依存の方向を内側に保つ」というたった一つのルールから出発します。それがEntities・Use Cases・Interface Adapters・Frameworksという4層の構造に結実し、変更に強く・テストしやすく・長期間保守できるシステムを生み出します。
最初は「コードが増えて面倒」と感じるかもしれません。しかし3年後・5年後にシステムが成長したとき、この設計が意味を持ちます。「DBを変えたいけどビジネスロジックに触れたくない」「新機能を追加したいけど既存コードを壊したくない」——そんな悩みへの根本的な答えが、クリーンアーキテクチャには込められています。