クリーンアーキテクチャ

英語名 Clean Architecture
読み方 クリーン アーキテクチャ
難易度
所要時間 設計に1〜2週間
提唱者 ロバート・C・マーティン(Uncle Bob)
目次

ひとことで言うと
#

ビジネスロジック(ドメイン)を中心に置き、依存関係を常に外側から内側へ向けることで、フレームワークやDBの変更に振り回されない堅牢なシステムを作るアーキテクチャ。同心円の図で有名。

押さえておきたい用語
#

押さえておきたい用語
依存性逆転の原則(Dependency Inversion Principle)
上位モジュール(ビジネスロジック)が下位モジュール(DB・フレームワーク)直接依存せず、インターフェースを介して依存させる設計原則のこと。クリーンアーキテクチャの根幹をなす考え方。
エンティティ(Entity)
アプリケーション全体で共通のビジネスルールの核心となるオブジェクトのこと。外部の仕組みに一切依存せず、同心円の最も内側に位置する。
ユースケース(Use Case)
「ユーザーが商品を注文する」のようなアプリケーション固有のビジネスロジックを記述する層のこと。エンティティを使ってビジネスルールを実行する。
インターフェースアダプター(Interface Adapter)
Controller、Presenter、Gatewayなど、外部と内部をつなぐ変換層のこと。外部のデータ形式と内部のデータ形式を相互に変換する。
境界(Boundary)
各層の間に設けたインターフェースの壁のこと。この壁により依存関係が常に内側に向かい、外側の変更が内側に影響しない構造を実現する。

クリーンアーキテクチャの全体像
#

クリーンアーキテクチャ:同心円構造と依存の方向
Frameworks & Drivers(外部層)Web・DB・UI・フレームワークなど具体技術を配置最も変更されやすいが、内側に影響を与えないInterface Adapters(アダプター層)Controller・Presenter・Gateway で外部と内部を変換ユースケースが定義したインターフェースを具体的に実装Use Cases(ユースケース層)アプリケーション固有のビジネスロジックを記述UIやDBの話はしない。入出力のインターフェースを定義Entities(核)ビジネスルールの核心外部依存ゼロ・最も重要← 依存の方向は常に外側から内側へ →
クリーンアーキテクチャの設計フロー
1
Entity定義
ビジネスルールの核心を外部依存ゼロで設計
2
Use Case設計
アプリ固有のロジックと入出力IFを定義
3
Adapter実装
外部と内部をつなぐ変換層を作成
4
外部層配置
フレームワーク・DB・UIを外側に閉じ込める
差替可能を検証
外部を変更しても内側が無影響かテスト

こんな悩みに効く
#

  • フレームワークを変えたいのに、ビジネスロジックと密結合で手が出せない
  • テストを書きたいのに、DBやAPIへの依存が多くてモックだらけになる
  • コードがどこに何を書けばいいかわからず、どんどんスパゲッティ化する

基本の使い方
#

ステップ1: Entities(エンティティ)を定義する

ビジネスルールの核心となるオブジェクトを定義する。

  • アプリケーション全体で共通のビジネスルールを表現する
  • 外部の仕組み(DB、UI、フレームワーク)に一切依存しない
  • 例:「注文は合計金額が0円以上でなければならない」というルール

ポイント: ここが同心円の最も内側。最も変更されにくく、最も重要な層。

ステップ2: Use Cases(ユースケース)を定義する

アプリケーション固有のビジネスロジックを記述する。

  • 「ユーザーが商品を注文する」のようなアプリの振る舞いを定義
  • Entityを使ってビジネスルールを実行する
  • 入出力のインターフェースを定義し、外側の層に実装を任せる

ポイント: 「このアプリで何ができるか」をここに集約する。UIやDBの話はしない。

ステップ3: Interface Adapters(アダプター)を実装する

外部と内部をつなぐ変換層を作る。

  • Controller、Presenter、Gatewayなどがここに入る
  • 外部のデータ形式(JSON、DBレコード)と内部のデータ形式を変換する
  • リポジトリパターンの実装もこの層

ポイント: ユースケース層が定義したインターフェースを、ここで具体的に実装する。

ステップ4: Frameworks & Drivers(外部層)を配置する

フレームワーク、DB、Web、UIなどの具体的な技術を配置する。

  • Webフレームワーク、ORMなどの外部ツールはすべてここ
  • この層は「つなぎ」のコードだけ書く
  • 最も変更されやすいが、内側には影響を与えない

ポイント: フレームワークは「詳細」であり「方針」ではない。いつでも差し替えられる状態を保つ。

具体例
#

例1:ECサイトの注文機能で決済基盤を移行する

状況: ECサイト(月間注文数50,000件)がStripeからPayPay決済に移行することになった。

Entity層: Orderクラスに「合計金額が0円以上」「在庫が十分」などのビジネスルールを実装。決済手段には一切依存しない。

Use Case層: PlaceOrderUseCasePaymentGatewayインターフェースを定義。決済の具体実装は外側に任せる。

Adapter層: StripePaymentGatewayPayPayPaymentGatewayに差し替え。Use Case層のコードは1行も変更不要。

結果: 決済基盤の移行にかかった期間はAdapter層の実装2日のみ。クリーンアーキテクチャを適用していなかった旧システムでは同様の移行に3週間を要していた。移行コストを85%削減できた。

例2:SaaSプロダクトでDBをMySQLからPostgreSQLに変更する

状況: ユーザー数10万人のSaaSプロダクト。MySQL 5.7のEOLに伴い、PostgreSQLへの移行を決定。

Entity層・Use Case層: ビジネスロジックにSQL固有の記述は一切なし。「ユーザーを検索する」「レポートを生成する」などのユースケースは変更不要。

Adapter層: MySQLUserRepositoryPostgresUserRepositoryに差し替え。同じUserRepositoryインターフェースを実装するだけ。

テスト: Use Case層のテストはMockリポジトリでDBに依存しないため、移行前後で全462件のテストが変更なしで通過。

結果: DB移行で変更が必要だったのはリポジトリ実装の12ファイルのみ。ビジネスロジック側の変更はゼロ。

例3:モノリスからマイクロサービスへ段階的に分離する

状況: 5年間運用してきたモノリスアプリ。注文・在庫・通知をマイクロサービスに分離したい。

クリーンアーキテクチャの恩恵: ユースケース層で定義したInventoryServiceインターフェースの実装を、同一プロセス内の呼び出しからHTTP/gRPCクライアントに差し替えるだけ。

段階的移行:

  1. 在庫サービスを独立デプロイ → LocalInventoryServiceRemoteInventoryServiceに変更
  2. 通知サービスを独立デプロイ → 同様にAdapter層のみ変更
  3. 注文サービスをモノリスから分離

結果: 各サービスの分離にかかった平均期間は1サービスあたり1週間。Use Case層のコード変更は合計でわずか23行。依存逆転の原則が分離の柔軟性を担保した。

やりがちな失敗パターン
#

  1. 層を飛び越えて依存する — ユースケース層から直接DBドライバを呼んでしまうと、テスト困難で変更にも弱くなる。依存は必ずインターフェースを通すこと
  2. 過剰な設計で小さいプロジェクトに適用する — 個人の小さなツールにクリーンアーキテクチャをフル適用すると、ファイル数が爆発して本末転倒。プロジェクト規模に合わせて適用度合いを調整する
  3. データの受け渡しが冗長になる — 層をまたぐたびにDTOを作りすぎて、同じようなクラスが乱立する。本当に必要な変換だけに絞ること
  4. 「依存は内側に向ける」を誤解する — 内側の層が外側の具体的なクラスをimportしていないか形式的にチェックするだけで、設計思想を理解しない。「なぜ内側に向けるのか」をチーム全体で共有すること

まとめ
#

クリーンアーキテクチャは 「ビジネスロジックを守る」 ための設計手法。依存関係を内側に向けるというシンプルな原則を守るだけで、テストしやすく、変更に強いシステムが作れる。ただし万能薬ではなく、プロジェクト規模に合わせた適用が大事。まずはEntity層とUse Case層の分離から始めてみよう。