evolutionary-modular-architecture について
プロダクトやチームの変化に応じて進化できるモジュラーモノリスを設計するスキルです。アーキテクトや開発者がドメイン境界、モジュール構成、通信、耐障害性を定め、必要に応じて個別デプロイへ移行する道筋を描けます。
主な機能
- 01DDD の境界づけられたコンテキストとコンテキストマップ
- 02集約単位のフラットなモジュール構成
- 03ポート、アダプター、トランザクショナルアウトボックス
- 04外部呼び出しのレジリエンス方針
- 05境界検証用 Node スクリプト
- 06自己完結型 HTML アーキテクチャ文書
活用シーン
- 01新しいプラットフォームやバックエンドの設計
- 02ドメインコンテキストと所有権の整理
- 03アダプターを介した外部ベンダー連携
- 04モノリスとマイクロサービスの境界検討
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tech-leads-club/ agent-skills --skill evolutionary-modular-architectureインストール後、Claude Code で/evolutionary-modular-architectureを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/architecture-template.htmlreferences/acl-and-communication.mdarchitecture-doc.mdddd.mdflat-by-aggregate.mdprinciples.mdresilience.mdstack-2026.mdscripts/validate-boundaries.mjsvalidate-structure.mjs詳細
進化型モジュラーアーキテクチャ
プラットフォームは、進化型モジュラーモノリスとして設計・構築します。最初から強固な論理境界(DDD の境界づけられたコンテキスト、集約単位でフラットに構成されたモジュール、すべての外部システムを囲む腐敗防止層、イベント駆動型の通信、デフォルトでのレジリエンス)を設けつつ、物理境界(個別のデプロイ、個別のデータベース)は後から選択できる任意のステップとして残します。まずはシンプルに始め、プロダクトとチームが必要とする場合にのみ粒度を進化させます。流行に乗ってマイクロサービスをリバースエンジニアリングすることは決してありません。
このスキルを使う場合
- 新しいプラットフォーム、バックエンド、サービスをゼロから設計する場合。
- ドメインの境界づけられたコンテキストとコンテキストマップを定義する場合。
- モジュールのフォルダーやファイルの構成を決める場合。
- モノリス、モジュラーモノリス、マイクロサービスのいずれを選ぶか判断する場合。
- 外部ベンダー(ERP、チケット管理、ストレージ、決済、AI、ID 管理、永続的ワークフローエンジン)と連携する、またはそこから切り離す場合。
- 外部呼び出しやモジュール間呼び出しのレジリエンスを高める場合。
- サーバーからクライアントへのリアルタイム更新を追加する場合。
- モダンな(2026 年版の)フルスタック TypeScript 技術スタックを選ぶ場合。
このスキルを使わない場合
- エンドポイントが数個のシンプルな CRUD の場合。フレームワークのデフォルトで十分です。
- NestJS に固有の実装詳細を深掘りする場合は、
nestjs-modular-monolithを使用してください。 - 単一のドメインモデルの貧血症をレビューまたはリファクタリングする場合は、
tactical-dddを使用してください。
すべてを規定する唯一のルール
論理境界(常に強固)と物理境界(進化可能)を分けます。 モジュール、コントラクト、状態の所有権、腐敗防止層は、最初から必須です。モジュールを個別にデプロイするか、個別のデータベースを持たせるかは、後から決める運用上の判断であり、構造上の前提条件ではありません。これにより、システムを単一のデプロイとして開始し、書き直すことなく成長させられます。
有用なイメージとしては、家に適切に区切られた部屋(モジュール)がある状態です。各部屋の中では、物が目的ごとにまとめられて見える場所に置かれています(集約単位でフラットに構成)。技術レイヤーごとのフォルダーのように、入れ子になった引き出しの奥にしまわれているわけではありません。最も重要なのは間取り(境界)です。
中核モデル(詳しく調べる場合は、該当するリファレンスを読み込む)
| トピック | 内容 | リファレンス |
|---|---|---|
| 原則 | 10 のモジュール原則(P1~P10)+ 9 の構造原則(P11~P19)+競合時の優先順位 | references/principles.md |
| DDD | 戦略的(サブドメイン、コンテキストマップ、統合パターン)+戦術的(リッチな集約、サブドメイン別の厳密さ) | references/ddd.md |
| モジュール内部 | 集約単位でフラットに構成、接尾辞、階層の深さ、フラット構成とサブドメインの判定、スキャフォールディング | references/flat-by-aggregate.md |
| 通信 | ポート&アダプター/ACL、イベント+トランザクショナルアウトボックス、SSE によるリアルタイム通信 | references/acl-and-communication.md |
| レジリエンス | バックオフ+フルジッター、サーキットブレーカー、リトライ予算、冪等性、バルクヘッド、タイムアウト | references/resilience.md |
| 2026 年の技術スタック | フロントエンド、バックエンド、データ、オブザーバビリティ、永続的ワークフロー、意思決定 | references/stack-2026.md |
| アーキテクチャドキュメント | SVG 図を含む、洗練された自己完結型 HTML アーキテクチャドキュメントの作成 | references/architecture-doc.md + assets/architecture-template.html |
| 検証 | 構造とモジュール境界の決定論的なチェック | scripts/validate-structure.mjs、scripts/validate-boundaries.mjs |
すべてのリファレンスを一度に読み込まないでください。現在のフェーズで必要な場合にのみリファレンスを読みます(読み込むタイミングは以下のワークフローに記載されています)。
ワークフロー
新しいシステムを設計する場合でも、既存のシステムをレビューする場合でも、この手順を使用してください。各フェーズには終了条件があるため、順番に進めてください。前提は明示し、ドメインが不明確な場合は推測する前に質問してください。
フェーズ 0 — スコープを定める
確認事項:新しいプラットフォームなのか、既存プラットフォーム内の新しいモジュールなのか、それともレビューなのかを確認します。ランタイム/スタックの制約も確認します(デフォルトの対象は 2026 TypeScript スタックです。references/stack-2026.md を参照してください)。明確な制約がない限り、デフォルトは単一デプロイ(モジュラーモノリス)とします。
完了条件:スコープと制約を文書化します。
フェーズ 1 — ドメインの発見(DDD 戦略設計)
references/ddd.md を読みます。ビジネス用語からサブドメインを特定し、それぞれをコア、支援、汎用に分類して、各サブドメインのユビキタス言語を明らかにします。技術レイヤーごとにグループ化しないでください。複数の境界づけられたコンテキストの解釈が成り立つ場合は、それらを提示し、黙って一つに決めないでください。
完了条件:候補となる境界づけられたコンテキストの一覧。それぞれの分類、責任の概要、主要な集約を含めます。
フェーズ 2 — 境界とコンテキストマップ
コンテキストマップを作成します。存在するコンテキスト、それらの関係(カスタマー/サプライヤー、順応者、オープンホストサービス、公開言語、共有カーネル、腐敗防止層)、およびコアとなるコンテキストを示します。状態の所有権を決定します。データベースは一つでも構いませんが、各モジュールは自分のテーブルに対する唯一の書き込み元とします。モジュール境界をまたぐ外部キーは使用せず、他のコンテキストは ID で参照します。集約はまとまりを保ちます(トランザクションを担うコアを過度に分割しないでください)。
完了条件:コンテキストマップとテーブル所有権マップ(各モジュールが自分のテーブルを所有)。
フェーズ 3 — モジュール内部(集約単位のフラット構成)
references/flat-by-aggregate.md を読みます。各モジュール内は技術レイヤーではなく、集約単位で構成します。ビジネス概念 1 つにつきフォルダー 1 つとし、技術レイヤーはファイルのサフィックス(.entity.ts、.service.ts、.controller.ts)で表します。階層の深さは 2 以下(フラット構成)、または 3 以下(サブドメインベース)にします。クリーンアーキテクチャの依存関係ルール(プレゼンテーション → アプリケーション → ドメイン ← インフラストラクチャ)は引き続き適用されます。レイヤーフォルダーではなく、サフィックスと同じ場所への配置で表現するだけです。6 項目の基準でフラット構成かサブドメインベースかを判断し、デフォルトではフラット構成を選びます。
完了条件:モジュールごとのフォルダーレイアウト、および根拠を添えたフラット構成/サブドメインベースの判断。
フェーズ 4 — 通信と腐敗防止層
references/acl-and-communication.md を読みます。内部サービスを含む、他チームが所有するサービスも含め、すべての外部システムをポート+アダプター(ACL)の背後に置きます。ドメインは独自の用語でポートを定義し、アダプターが外部モデルを変換して入出力します。内部モジュール間では、同期通信は一つの集約内のみ(単一の ACID トランザクション)とし、モジュール間ではトランザクショナルアウトボックスを介したイベントを使用し、コンシューマーを冪等にします。UX でプッシュが必要な場合は、サーバーからクライアントへのリアルタイム通信に SSE を追加します。
完了条件:ポートとアダプターの一覧、module.aggregate.action 形式の命名によるドメインイベントの一覧、同期/非同期の判断。
フェーズ 5 — レジリエンス
references/resilience.md を読みます。すべての外部/サービス間呼び出しを、**タイムアウト → サーキットブレーカー → 再試行(上限付き指数バックオフ+フルジッター)**でラップします。再試行するのは冪等な操作のみとし、書き込みには冪等性キーを必須とします。再試行は予算(トラフィックのおよそ 10%)で上限を設け、スライディングウィンドウのエラー率に基づいてサーキットブレーカーを作動させ、各ブレーカーに名前付きのフォールバックを設定します。長時間にわたる複数ステップのプロセスを再起動後も継続させる必要がある場合に限り、永続的な実行を追加します。
完了条件:各アダプターに適用したレジリエンスポリシーと、書き込み用の冪等性キー。
フェーズ 6 — スタックと進化
references/stack-2026.md を読みます。具体的なスタックを選び、トレードオフ(ランタイム、API スタイル、キャッシュ、リアルタイム通信方式)を明示します。次に、進化の道筋を示します。ステージ 1(明確な境界を持つモジュラーモノリス。イベント/アウトボックスはすでに導入済み)が現在の状態です。各モジュールを独立したアプリ/データベースに昇格させるのは、そのモジュール自身のメトリクスが必要性を裏付けた場合に限ります。
完了条件:スタックの表と進化に関する注記。
フェーズ 7 — アーキテクチャの文書化(HTML)
洗練された、自己完結型の HTML アーキテクチャ文書を、エレガントな手描き風の SVG 図とともに作成します。references/architecture-doc.md を読み、assets/architecture-template.html から始めます。テンプレートをコピーし、その CSS とビジュアルシステムをそのまま維持して、プレースホルダーの内容を置き換えます。標準セクション(概要、ドメイン、原則、モノリスマップ、境界付けられたコンテキスト、ACL、コミュニケーション、フロント・トゥ・バック、モジュール、レジリエンス、リアルタイム、進化、スタック)を構築し、図には連番を付けます(「図 N — ...」)。ビジュアルアイデンティティを維持します。パレット、Lato + JetBrains Mono フォント、角丸の四角形、矢印マーカー、柔らかなグラデーション、斜体のキャプションです。出力はブラウザで直接開ける 1 つの HTML ファイルです。ビルド手順は不要です。
終了条件: 一貫した図と動作するページ内ナビゲーションを備えた、単一の自己完結型 HTML ファイル。
意思決定ルール(チートシート)
- サブドメインの分類: 競争優位性 → コア、ビジネス固有だが差別化にはならない → サポート、解決済みの問題で利用するだけ → ジェネリック。
- 戦術的強度: コアではフル(リッチな集約、値オブジェクト、不変条件、イベント)。サポートでは中程度。ジェネリックでは最小限(不変条件が存在しないところでリッチさを強制するのは過剰設計です)。詳細は
references/ddd.mdを参照。 - フラット vs サブドメイン: デフォルトはフラット(深さ 2)。サブドメインベース(深さ 3)にするのは、6 つの基準のうち 4 つ以上が当てはまる場合のみです。異なるペルソナ、認可、実行モデル、スケーリング、デプロイ、障害の分離。詳細は
references/flat-by-aggregate.mdを参照。 - 同期 vs イベント: 1 つの集約の内部では同期(原子性が重要)。モジュールをまたぐ場合は outbox を介したイベント(結果整合性を許容)。
- 永続的実行: 長時間実行され、複数ステップで、再開が必須のプロセスにのみ追加します。通常のリクエストには不要です。
厳格なルール(譲れないもの)
- 各モジュールは自身のテーブルのみを書き込みます。コンテキストをまたぐリンクは id によるもので、コード内で検証されます(
enforce-module-boundaries)。 - モジュール間の直接インポートは禁止 — ファサード/コントラクトまたはイベントを介して通信します。
- すべての外部システムはポート + ACL の背後に配置します — ベンダーのモデルがドメインに漏れ出してはなりません。
- 再試行するのは冪等な操作のみ。書き込みには冪等キーを持たせます。
- モジュール原則(P1〜P10)は構造原則(P11〜P19)に優先します。 同一配置にするとモジュールをまたぐエンティティのインポートが強制される場合は、ファサード + DTO を使用します。集約を分割するとトランザクションが壊れる場合は、まとめたままにします。
自動チェック
レビューに頼るのではなく、原則を実行可能にします。CI およびマージ前にこれらを実行します(どちらも依存関係ゼロの Node ESM スクリプトです。libs/packages のルートを渡すか、自動検出させます):
node scripts/validate-structure.mjs [root]— 集約単位のフラット化(P11〜P17)を強制します。技術レイヤーのフォルダーなし、単一ファイルのフォルダーなし(__test__/を除く)、深さ ≤ 3、集約内に README なし。node scripts/validate-boundaries.mjs [root]— モジュール境界(P1、P3、P8)を強制します。モジュールをまたぐ深いインポートなし(barrel/ファサード経由のみ)、エンティティ名の重複やプレフィックスなしの名前なし、コンテキストをまたぐリレーションなし。
どちらも違反時には非ゼロで終了し、問題のあるパスを出力します。構造上の失敗はブロッキングとして扱います。境界に関する指摘は、チームが規約を採用した時点でブロッキングとして扱います。
例
例1:新しいプラットフォームを設計する
ユーザーの発言:「クライアントの ERP に仕訳を登録する買掛金プラットフォームのアーキテクチャを設計してください。」 アクション:
- フェーズ1 — サブドメインを洗い出して分類します(例:買掛金と業務運用はコア、ドキュメント/監査/ゲーミフィケーションは支援、ID/通知は汎用)。
- フェーズ2 — コンテキストマップと、1つのデータベースでモジュールごとにテーブルを所有する方式を定めます。
- フェーズ3 — モジュールごとに、集約単位でフラットな構成にします。
- フェーズ4 — ERP/チケット管理/ストレージをポートと ACL の背後に配置し、イベントはアウトボックス経由で送信し、オペレーターキューには SSE を使用します。
- フェーズ5 — ERP アダプターに回復性ポリシーを設定します(冪等性キー=支払い ID)。
- フェーズ6 — 2026 年の技術スタックと進化計画を示します(現時点では単一デプロイ)。 結果:コンテキストマップ、モジュール構成、ポート/アダプターの一覧、回復性ポリシー、技術スタックと進化計画を、対応するリファレンスに基づいて提示します。
例2:モジュールを整理する
ユーザーの発言:「billing モジュールはどのように整理すればよいですか?」
アクション:references/flat-by-aggregate.md を読み、ファイルと __test__/ を同じ場所にまとめた billing/subscription/、billing/invoice/、billing/payment/ を提案します。6つの基準で検証し(billing はフラット構成)、依存関係のルールがサフィックスによって維持されていることを示します。結果:根拠を添えたフラットなフォルダーツリーを提示します。
例3:ベンダーから切り離す
ユーザーの発言:「OMIE に縛られたくありません。」
アクション:references/acl-and-communication.md を読み、ドメインの用語で ErpLedgerPort を定義し、OmieAdapter を実装します。境界で OMIE のモデルを変換し、ERP を切り替えるときはアダプターを交換すればよいことを示します。結果:ポートインターフェースとアダプターの計画を提示し、ドメインがベンダーの型を一切インポートしないことを保証します。
アンチパターン/危険信号
- ❌ 初日からマイクロサービスや多数のデータベースを導入すること(「大規模に感じる」は理由になりません)。
- ❌ モジュール内に技術レイヤーごとのフォルダー(
core/service/、http/controller/、persistence/entity/)を作ること — これは、集約単位でフラットにする方式が置き換えるレガシーパターンです。 - ❌ あるモジュールが別のモジュールのテーブルを読み書きすること。
- ❌ ベンダー SDK の型がドメインに漏れること(ACL がない)。
- ❌ 冪等でない書き込みを再試行すること、バックオフとジッターなしで再試行すること、予算なしで再試行すること。
- ❌ 一貫性のあるトランザクション型コアを、イベント連携された断片に分割すること。
- ❌ 不変条件のない汎用サブドメインに、リッチな戦術的 DDD を無理に適用すること。
リファレンスガイド
| このファイルを読み込む | 読み込むタイミング |
|---|---|
references/principles.md | 原則の正確な文言が必要な場合、または構造とモジュール性の競合を解決する場合。 |
references/ddd.md | フェーズ1〜2:サブドメインの分類、コンテキストマップの作成、戦術的な適用度の決定。 |
references/flat-by-aggregate.md | フェーズ3:モジュールの構成、フラット構成とサブドメイン構成の選択、スキャフォールディング、ファサード、テスト。 |
references/acl-and-communication.md | フェーズ4:ポート/アダプター/ACL、イベントとアウトボックス、SSE。 |
references/resilience.md | フェーズ5:バックオフ/ジッター、サーキットブレーカー、冪等性、バルクヘッド、永続的な実行。 |
references/stack-2026.md | フェーズ0/6:具体的な技術スタックの選択とトレードオフ。 |
references/architecture-doc.md + assets/architecture-template.html | フェーズ7:HTML アーキテクチャドキュメントとその図の作成。 |
scripts/validate-structure.mjs、scripts/validate-boundaries.mjs | 検証:CI またはマージ前に構造とモジュール境界をチェックする場合。 |