mcpField
C
clean-architecture

clean-architecture

github.com/wondelai開発2.5k7.3k 回インストール7 週間前に更新
リポジトリ

clean-architecture について

ソフトウェアの設計、レビュー、依存関係管理に使うアーキテクチャフレームワークです。コードの依存をビジネスルールの内側へ向ける原則を中心に、レイヤー、境界、コンポーネント原則、SOLID を扱います。

主な機能

  1. 01依存関係ルールと同心円レイヤー
  2. 02エンティティとユースケースのモデル化
  3. 03インターフェースアダプターとフレームワーク境界
  4. 04コンポーネントの凝集度と結合度の原則
  5. 05SOLID 原則
  6. 06アーキテクチャの診断とスコアリング

活用シーン

  1. 01新規システムのモジュール境界の設計
  2. 02ビジネスロジックとフレームワークや DB の依存確認
  3. 03コンポーネント間の循環依存の特定
  4. 04クラスやモジュールの SOLID 違反のレビュー

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wondelai/skills --skill clean-architecture

インストール後、Claude Code で/clean-architectureを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
adapters-frameworks.md
boundaries.md
component-principles.md
dependency-rule.md
entities-use-cases.md
solid-principles.md

詳細

クリーンアーキテクチャのフレームワーク

ビジネスルールをフレームワーク、データベース、デリバリーの仕組みから独立させるための、規律あるソフトウェア構成のアプローチです。システムアーキテクチャの設計、モジュール境界のレビュー、依存関係の管理に関する助言を行う際に、これらの原則を適用してください。

中核となる原則

ソースコードの依存関係は内側、つまり高レベルのポリシーに向かう必要があります。 内側のサークルにあるものは、外側のサークルについて何も知ってはなりません。この単一のルールにより、テスト可能で、フレームワーク、UI、データベース、外部のあらゆる要素から独立したシステムが実現します。重要なのはビジネスルールです。データベース、Webフレームワーク、デリバリーの仕組みは詳細にすぎません。詳細がポリシーに依存していれば、判断を先送りし、実装を置き換え、ビジネスロジックを単独でテストできます。

スコアリング

目標:10/10。 アーキテクチャが満たす「クイック診断」の7項目それぞれに1点を付与し(0~7点)、その後0~10の範囲に換算します。6~7項目を満たす場合は9~10(依存関係ルールが守られ、ビジネスロジックがフレームワークとDBから独立している)、4~5項目の場合は6~8(コアはテスト可能だが、一部の詳細が内側に漏れている)、2~3項目の場合は3~5(フレームワークまたは永続化の仕組みが構造を決めている)、0~1項目の場合は0~2(境界がなく、ビジネスルールがコントローラーとORMモデルに存在する)です。スコア、失敗した診断項目、および各項目の修正に必要な具体的な依存関係の逆転を報告してください。

1. 依存関係ルールと同心円

中核となる概念: アーキテクチャを同心円として構成します。最も内側にエンティティ(エンタープライズのビジネスルール)、その外側にユースケース(アプリケーションのビジネスルール)、さらに外側にインターフェースアダプター、最外側にフレームワークとドライバーを配置します。ソースコードの依存関係は常に内側を向きます。

有効な理由: 高レベルのポリシーが低レベルの詳細に依存しなければ、ビジネスロジックに触れることなく、データベース、Webフレームワーク、APIの形式を切り替えられます。これにより、スタック内で最も変化しやすい部分に対するシステムの耐性が高まります。

主なポイント:

  • 内側のサークルでは、外側のサークルに属する名前を参照できません。外部のクラス、関数、変数、データ形式は使用できません。
  • 境界を越えるデータは、外側のサークルに決められるのではなく、内側のサークルにとって最も使いやすい形式にする必要があります。
  • 依存関係の逆転(インターフェースを内側で定義し、外側で実装すること)が、このルールを徹底する仕組みです。
  • サークルの数は固定ではありません。通常は4つですが、ルールは変わりません。
  • フレームワークは詳細であり、アーキテクチャではありません。最外側のサークルに配置します。

コードへの適用例:

コンテキストパターン例
レイヤーの方向内側のサークルでインターフェースを定義し、外側で実装するユースケース内のUserRepositoryインターフェース、アダプター内のPostgresUserRepository
データの受け渡し境界を越えるのはORMエンティティではなくDTOユースケースはActiveRecordモデルではなく、UserResponse DTOを返す
依存関係の方向インポートの矢印は常に内側を向くコントローラーはユースケースをインポートする。ユースケースがコントローラーをインポートすることはない

内側のサークルから外側へのインポートがある場合は、references/dependency-rule.mdを参照してください。そこでは、4つのサークルのコード例、データの受け渡しに関するルール、および問題を修正するための4段階の依存関係逆転手順を確認できます。

2. エンティティとユースケース

中核となる概念: エンティティは、ソフトウェアがなくても存在する、企業全体のビジネスルールをカプセル化します。ユースケースには、エンティティとの間でデータの流れを調整する、アプリケーション固有のルールが含まれます。

効果がある理由: ビジネスが何をするか(エンティティ)と、アプリケーションがそれをどのように調整するか(ユースケース)を分離することで、エンティティを複数のアプリケーションで再利用でき、コアとなるビジネスルールを変更せずにアプリケーションの動作を変更できます。

主なポイント:

  • エンティティはデータベースの行ではありません。重要なビジネスルールをカプセル化したオブジェクト、または純粋関数です
  • ユースケースはリクエストモデルを受け取り、レスポンスモデルを返します。フレームワークのオブジェクトは決して受け取りません
  • 各ユースケースは、単一のアプリケーション操作です(CreateOrder、ApproveExpense)
  • インタラクターパターン:ユースケースクラスは入力境界インターフェースを実装し、出力境界インターフェースを呼び出します
  • ユースケースへの変更がエンティティに影響することは決してありません。エンティティへの変更は、ユースケースに波及する場合があります

コードへの適用例:

コンテキストパターン例
エンティティ設計重要なビジネスルール、フレームワークへの依存ゼロOrder.calculateTotal() は税ルールを適用します。HTTP については何も知りません
リクエスト/レスポンス境界を越えるシンプルなデータ構造CreateOrderRequest { items, customerId } — ORM モデルは使いません
単一責任操作ごとに 1 つのユースケースPlaceOrder、CancelOrder、RefundOrder を個別のクラスにします
インタラクター入力ポートを実装し、出力ポートを呼び出しますPlaceOrderInteractor implements PlaceOrderInput

インタラクターを設計するとき、またはエンティティとユースケースのどちらに含めるべきかを判断するときは、references/entities-use-cases.md を参照してください。リクエスト/レスポンスモデルの例を含む、エンタープライズビジネスルールとアプリケーションビジネスルールの詳しい解説があります。

3. インターフェースアダプターとフレームワーク

中核となる概念: インターフェースアダプターは、ユースケース/エンティティにとって都合のよい形式と、外部機関が必要とする形式との間でデータを変換します。フレームワークとドライバーは最外層であり、外部世界とつなぐグルーコードです。

効果がある理由: Web フレームワーク、ORM、メッセージキューを外側の円に閉じ込めておけば、いずれかを置き換える際の変更は局所的なものになります。データベースは細部であり、Web も細部です。細部はアプリケーションの骨格ではなく、ビジネスルールに対するプラグインであるべきです。

主なポイント:

  • コントローラーは HTTP をユースケースの入力に変換し、プレゼンターはユースケースの出力をビューモデルに変換します
  • ゲートウェイはユースケースが定義したリポジトリーインターフェースを実装します。内側の円が契約を定義し、外側がそれを満たします
  • ビジネスルールは、データが SQL、NoSQL、フラットファイルのどれに保存されているかや、配信が HTTP であるかを知りません
  • フレームワークには用心してください。フレームワークは依存させようとします。距離を保ちましょう

コードへの適用例:

コンテキストパターン例
コントローラー配信手段 → ユースケースの入力OrderController.create(req) が CreateOrderRequest を構築し、インタラクターを呼び出します
プレゼンターユースケースの出力 → ビューモデルOrderPresenter.present(response) が JSON/HTML 用にフォーマットします
ゲートウェイデータベースごとに実装するリポジトリーインターフェースSqlOrderRepository implements OrderRepository
フレームワーク境界フレームワークから内側を呼び出し、逆方向には呼び出しませんExpress のルートハンドラーがコントローラーを呼び出します。コントローラーが Express をインポートすることはありません

コントローラー、プレゼンター、ゲートウェイを接続するとき、またはデータベース/Web は細部だと説明するときは、references/adapters-frameworks.md を参照してください。プラグインアーキテクチャと、フレームワークを境界に閉じ込める方法について解説しています。

4. コンポーネントの原則

中核となる概念: コンポーネントはデプロイの単位です。3つの凝集性の原則がコンポーネントに含めるものを規定し、3つの結合性の原則がコンポーネント間の関係を規定します。

有効な理由: 構成が不適切なコンポーネントは、1つの変更によって無関係なコードの再デプロイが必要になる連鎖的な影響を生みます。これらの原則に従うことで、変更が局所化され、リリースを独立させられます。

重要なポイント:

  • REP(再利用/リリース等価の原則):コンポーネント内のクラスは、ひとまとまりとしてバージョン管理・リリースできる必要があります
  • CCP(共通閉鎖の原則):同じ理由で同じタイミングに変更されるクラスは、まとめて配置します — コンポーネントに対するSRPです
  • CRP(共通再利用の原則):ユーザーが使わないクラスに依存することを強制してはいけません
  • ADP(非循環依存の原則):コンポーネントグラフに循環があってはいけません — DIPまたは新しいコンポーネントによって循環を解消します
  • SDP(安定依存の原則):安定性の方向に依存します
  • SAP(安定抽象化の原則):安定したコンポーネントは抽象的にし、不安定なコンポーネントは具体的にします

コードへの適用:

コンテキストパターン例
コンポーネントのグループ化一緒に変更されるクラスをグループ化する(CCP)注文関連のすべてのユースケースを1つのコンポーネントにまとめる
循環の解消DIPを適用して依存関係の向きを反転するインターフェースを新しいコンポーネントに切り出し、循環を解消する
安定性の指標不安定性 I = Ce / (Ca + Ce)依存元が多く、依存先がない → Iは0に近く(安定)なる

クラスをデプロイ可能なコンポーネントにグループ化するときや依存関係の循環を解消するときは、references/component-principles.mdを参照してください。REP、CCP、CRP、ADP、SDP、SAPの各原則を、不安定性の指標とともに詳しく解説しています。

5. SOLIDの原則

中核となる概念: クラスとモジュールのレベルにおける5つの原則 — 単一責任、オープン・クローズド、リスコフの置換、インターフェース分離、依存性逆転 — は、依存関係ルールを実現するための中位レベルの構成要素です。

有効な理由: 各原則は依存関係が破綻する特定のパターンに対処し、コードベースをレガシーコードの悪夢に変えてしまう硬直性、脆弱性、変更困難性を防ぎます。

重要なポイント:

  • SRP:モジュールが変更される理由は1つです — 1つのアクターに対応します(「1つのことをする」という意味ではありません)
  • OCP:既存のコードを変更するのではなく、新しいコードを追加して振る舞いを拡張します — ストラテジーパターンやプラグインパターンを使います
  • LSP:サブタイプは、クライアントに知られることなく、基底インターフェースを通じて利用できなければなりません — 想定外の例外や無視されるメソッドによって違反されます
  • ISP:クライアントは使わないメソッドに依存すべきではありません — 肥大化したインターフェースは不要な結合を生みます
  • DIP:高水準モジュールと低水準モジュールは、どちらも高水準モジュールが定義する抽象に依存します

コードへの適用:

コンテキストパターン例
SRP違反クラスが複数のアクターに対応するEmployeeが給与(CFO)、レポート(COO)、永続化(CTO)を扱う
ストラテジーによるOCP新しいクラスを通じて新しい振る舞いを追加するShippingStrategyを実装するExpressShippingを追加する。Orderは変更しない
LSP違反サブタイプが期待される振る舞いを変えてしまうSquare extends RectangleはsetWidth()/setHeight()の契約を破ります
ISPの適用肥大化したインターフェースを役割ごとのインターフェースに分割する1つのMultiFunctionDeviceではなく、Printer、Scanner、Faxを使う
DIPの配線高水準側がインターフェースを定義し、低水準側が実装するOrderServiceはStripeClientではなくPaymentGatewayに依存する

特定のクラスにSRP/OCP/LSP/ISP/DIPを適用するときや、違反を診断するときは、references/solid-principles.mdを参照してください。各原則をコード例と、それによって防げる問題とともに詳しく解説しています。

6. 境界と境界の構造

核心となる概念: 境界とは、重要なものと詳細にすぎないものを分ける線であり、ポリモーフィズムによって実現されます。依存関係は内側を指して境界を越え、制御フローはどちらの方向にも境界を越えることがあります。

有効な理由: 境界を設けるたびに、意思決定を先送りしたり、実装を差し替えたりする選択肢が得られます。戦略的な境界の配置によって、システムが何年にもわたって保守しやすいものになるか、苦労するものになるかが決まります。

重要なポイント:

  • 完全な境界では両側に相互インターフェースを使い、部分的な境界ではより単純な戦略やファサードを使います
  • Humble Object パターン:境界に近いテストしにくい部分と、テストしやすいロジックの部分に境界コードを分割します
  • サービスが自動的にアーキテクチャ上の境界になるわけではありません。肥大化した共有データモデルを持つマイクロサービスは、ネットワーク呼び出しを行うモノリスです
  • テストは最も隔離されたコンポーネントです。依存関係は内側に向かい、テストに依存するものはありません
  • 早すぎる境界の導入にはコストがかかりますが、境界がない場合も同様です。変化しやすい箇所に境界を設けてください

コードへの適用:

コンテキストパターン例
完全な境界と部分的な境界相互ポート、または単独のストラテジーユースケースで PlaceOrderInput/PlaceOrderOutput を定義します。単純なケースでは ShippingStrategy を使用します
Humble Objectテスト可能なロジックとインフラストラクチャを分離しますPresenterLogic(テスト可能)が ViewModel を生成し、View(Humble Object)がそれをレンダリングします
プラグインとしての Mainコンポジションルートがシステムを組み立てますmain() がすべての具象実装を接続し、アプリを起動します

境界をどこに設けるか、完全な境界と部分的な境界のどちらを選ぶか、または Humble Object パターンを適用するかを判断する際は、references/boundaries.md を参照してください。境界としてのサービス、テストの境界、そして究極のプラグインとしての Main についても説明しています。

よくある間違い

間違い問題が起きる理由対処法
ORM がビジネスロジックに漏れ出すエンティティがスキーマに結合し、DB の変更によってビジネスルールの書き換えが必要になりますドメインエンティティと永続化モデルを分離し、アダプターレイヤーでマッピングします
コントローラーにビジネスルールを記述するHTTP なしではテストできず、エンドポイント間で重複しますロジックをユースケースインタラクターに移し、コントローラーは変換と委譲のみを行います
フレームワーク優先のアーキテクチャフレームワークが構造を決定し、差し替えるには全面的な書き換えが必要になりますフレームワークをプラグインとして扱い、ビジネス上の機能ごとにコードを構成します
コンポーネント間の循環依存変更の影響が予測不能に波及し、独立したリリースができませんDIP を適用するか、共有の抽象化コンポーネントを抽出します
機能ごとに巨大なユースケースを1つ作る数千行に及ぶ肥大化したオーケストレーターになります単一の操作に集中したユースケースに分割します
「単純だから」と境界を省く結合が気づかないうちに蓄積し、やがて莫大なコストになります変化しやすい箇所に、先回りして境界を設けます
マイクロサービスなら自動的に優れたアーキテクチャになると考える分散モノリスは、適切に構成されたモノリスよりも悪いものですサービス内外の両方で依存関係ルールを適用します。サービスはデプロイの境界であり、アーキテクチャ上の境界ではありません

クイック診断

質問いいえの場合対応
DB、ウェブサーバー、フレームワークなしでビジネスルールをテストできますか?ルールがインフラストラクチャに結合していますエンティティとユースケースをインターフェースの背後に切り出し、外側のレイヤーをモックします
すべてのソース依存関係が内側を向いていますか?依存関係ルールに違反しています境界インターフェースを導入し、問題の依存関係を逆転させます
ビジネスロジックに触れずにデータベースを交換できますか?永続化の詳細が内側に漏れていますリポジトリパターンを使い、アダプターで永続化を分離します
ユースケースは受け渡しの仕組みに依存していませんか?ユースケースが HTTP/CLI/キューを認識していますユースケースのシグネチャではプレーンな DTO を使います
フレームワークは最外周のサークルに限定されていますか?フレームワークがアーキテクチャそのものになっていますフレームワークの呼び出しをインターフェースの背後でラップし、端に配置します
コンポーネントグラフに循環はありませんか?循環依存が存在しますADP を適用し、DIP または新しいコンポーネントを使ってすべての循環を解消します
Main(コンポジションルート)がすべての依存関係を配線していますか?内側のサークルで具象クラスがインスタンス化されています構築処理を Main に移し、DI またはファクトリーを使います

さらに読む

ソフトウェアアーキテクチャに関する Robert C. Martin の決定版ガイドに基づいています。

著者について

Robert C. Martin(「Uncle Bob」) は、1970 年からプログラミングに携わっているソフトウェアエンジニアであり、アジャイルマニフェストの創設時の署名者で、Clean Code、The Clean Coder、Clean Architecture、Clean Agile の著者です。彼の SOLID 原則は、オブジェクト指向設計における基礎的な用語であり、彼の著作は、アーキテクチャとは依存関係を管理し、ビジネスルールをインフラストラクチャの詳細から独立させることだと論じています。

コメント