modular-design-principles について
コードベースのモジュール構造と境界を考えるための、フレームワークに依存しないスキルです。設計原則、レビューの観点、モジュールの作成・分割・統合の手順を示します。
主な機能
- 01モジュール設計の10原則
- 02境界と所有権に関する指針
- 03境界づけられたコンテキストの作成手順
- 04モジュール分割・統合の判断基準
- 05アーキテクチャ適合性レビュー項目
活用シーン
- 01既存コードベースのモジュール境界をレビュー
- 02新しい境界づけられたコンテキストを計画
- 03モジュールを分割または統合するか判断
- 04結合と所有権のリスクを監査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tech-leads-club/ agent-skills --skill modular-design-principlesインストール後、Claude Code で/modular-design-principlesを入力して読み込まれたか確認します。
同梱ファイルreferences/principles.md
詳細
モジュール設計の原則
このスキルは、あらゆるコードベースの構造と境界について考えるときに使用します。フレームワーク名、フォルダー構成、ツールには意図的に言及していません。各原則を、お使いの技術スタックに合わせて適用してください。
読み込む内容
| タスク | 場所 |
|---|---|
| 原則の表、違反例、ワークフロー(このファイル) | SKILL.md |
| 原則ごとの定義、エージェント向けルール、抽象的な例 | references/principles.md |
階層的なメンタルモデル
- コンポジションルート(アプリケーション、ホスト、ランナー):モジュールを連携させ、オーケストレーションは薄く保ちます。
- モジュール/境界づけられたコンテキスト:振る舞いとデータの所有権がまとまった単位です。それぞれ単独で理解・テストできるようにします。
- 共有カーネル(必要最小限に):安定していて、本当に横断的に使われる概念に限ります。「誰もが必要とするもの」を寄せ集めたものにしないようにします。
これを物理的にどのように配置するか(モノレポ、マルチレポ、パッケージ、ライブラリ)は、モジュール性の定義ではなく、デリバリー上の選択です。以下の原則は、その場合も適用されます。
10 の原則
| # | 原則 | 意図 |
|---|---|---|
| 1 | 明確に定義された境界 | 小さく安定したパブリックサーフェスを設け、それ以外はすべて内部にします。利用側が依存するのは内部実装ではなく、コントラクトです。 |
| 2 | コンポーザビリティ | モジュール同士の内部実装について特別な知識がなくても、単独または組み合わせて利用できます。 |
| 3 | 独立性 | 境界を越えて、隠れた共有可変状態を持たせません。各モジュールは単独でテストできるようにします(境界ではフェイクやテストダブルを使用します)。 |
| 4 | 個別のスケーリング | 必要な場合、他のモジュールを書き換えずに、リソース(コンピューティング、ストレージ、レート制限、バッチサイズ)をモジュールごとに調整できます。 |
| 5 | 明示的な通信 | モジュール間のやり取りには、偶発的な結合ではなく、文書化されたコントラクト(API、イベント、メッセージ、共有型)を使用します。 |
| 6 | 置き換え可能性 | 他のモジュールへの依存は、実装を変更できるように、インターフェースまたはプロトコルを介して表現します。 |
| 7 | デプロイの独立性 | アーキテクチャ上の明示的な判断がない限り、モジュールが同じプロセス、ホスト、リリース周期を共有することを前提にしません。 |
| 8 | 状態の分離 | 各モジュールは永続状態と名前を所有します。同じ論理データストアを暗黙に共有したり、境界を越えて曖昧なグローバル名を使ったりしません。 |
| 9 | 可観測性 | 各モジュールを単独で診断できるようにします。ログ、メトリクス、トレース、ヘルス情報を、それを出力した単位に帰属させます。 |
| 10 | 障害の独立性 | タイムアウト、バルクヘッド、サーキットブレーカー、冪等性などによって障害を封じ込め、あるモジュールの停止が無制御に連鎖しないようにします。 |
原則 8 は、しばしば最も難しい原則です。データや名前の所有権が曖昧だと、「問題が起きるまでは動く」統合上のバグが頻繁に発生します。
各原則の詳細(エージェント向けルールと抽象的な例)については、references/principles.md を読み込んでください。
典型的な違反(抽象的な説明)
- 概念の衝突 — 異なるモジュール間で同じ名前やスキーマを別のものに使用する、または重複した「グローバル」定義が時間の経過とともに乖離する。
- 永続化層への直接アクセス — 合意された契約を通さずに、あるモジュールが別のモジュールのテーブル、バケット、ドキュメントを読み書きする。
- データ所有権の集中化 — すべてのモジュールのすべてのストアを登録・公開する単一の永続化レイヤーがあり、隠れた結合を促す。
- 境界層へのロジック集中 — ドメイン/アプリケーションコードではなく、トランスポートアダプター(HTTP ハンドラー、UI、CLI)にビジネスルールがある。
- 境界層からストレージへの直接アクセス — アダプターがユースケースやアプリケーションサービスではなく、低レベルの永続化 API に依存する。
- 境界が不明確なトランザクション — 明確なトランザクション所有権や失敗時の挙動がないまま、境界をまたいで書き込みを行う。
- 内部実装の漏出 — リポジトリ、内部サービス、実装型がモジュールの公開 API として公開される。
- 薄くないファサード — 「公開」エントリーポイントが、モジュール内の適切なレイヤーに委譲せず、クエリ、マッピング、ポリシーを組み込んでいる。
境界づけられたコンテキストを作成する(ワークフロー)
システム内の一貫性のある新しい領域(新規モジュール、または抽出したドメイン)を導入するときに使用します。
- スコープと言語 — コンテキストに名前を付け、主要な名詞/動詞(共通言語)を列挙します。他のコンテキストと衝突する曖昧な名前は避けます。
- 責務 — どの判断をここだけで行いますか?明示的にスコープ外とするものは何ですか?
- 状態の所有権 — このコンテキストで信頼できる情報源となる事実は何ですか?(ストレージ技術が未定でも)概念上、どこに保存しますか?
- 公開契約 — 他のコンテキストが利用できる操作やイベントです。この契約は意図的にバージョン管理し、進化させます。
- 統合 — 隣接する各コンテキストについて、同期呼び出し、非同期メッセージ、共有読み取りモデル、バッチ同期のどれを使いますか?整合性(即時、結果整合)と失敗時の挙動を文書化します。
- 不変条件とライフサイクル — この境界内で常に成立していなければならないことは何ですか?ライフサイクルの開始/完了条件は何ですか?
- 分離性の確認 — 無関係なコンテキストを起動せずに、コアの振る舞いをテストできますか(ポートでのフェイクを使用)?
- 可観測性 — 明確な識別子を使って、リクエストやジョブがこのコンテキストを通過する様子をどのように追跡しますか?
モジュール間の連携(設計時):最小限の契約を優先します。非同期処理ではタイムアウト、再試行、冪等性を定義し、近道としての「一時的な」ストアへの直接アクセスは避けます。
分割または統合するタイミング
基本方針: 実際の問題が生じるまでは、境界を少なくします。早まった細分化より「フラットな構成のほうがよいことが多い」です。分割すると、調整、バージョン管理、運用のコストが増えます。
6 つの基準によるテスト(複数に当てはまる場合は分割を優先)
| # | 基準 | 質問 |
|---|---|---|
| 1 | 言語 | サブ領域で異なる用語が使われている、または同じ言葉の定義が食い違っていますか? |
| 2 | 変更頻度 | 部分ごとに異なる周期で変更される、または無関係な理由で変更されますか(ほとんどの編集が片側にだけ影響しますか)? |
| 3 | 規模/SLO | 部分ごとに異なるスループット、レイテンシ、可用性の目標が必要ですか? |
| 4 | 整合性 | 異なるトランザクション境界が必要ですか(1 つのアトミックな書き込みモデルをすっきり共有できませんか)? |
| 5 | 所有権 | 異なるチームによる所有や、明確な所有権の線引きによって、衝突やレビューの負荷を減らせますか? |
| 6 | 問題の兆候 | 連鎖的な影響、変更への不安、バグの担当者が不明確といった、観測可能な統合上の問題がありますか? |
凝集度/結合度(定性的な評価)。 モジュール内の高い凝集度と、モジュール間の低く明示的な結合を優先します。動機が「ファイルが大きくなった」または「フォルダーの見た目」だけなら、統合するか、分割を待ちます。
まだ統合する、または分割しないほうがよい場合
- 境界が人為的です(同じ言語、同じライフサイクル、常に相互呼び出しがある)。
- 分割すると、明確な単一ライターのルールがないまま、ロジックやデータが重複します。
- チームに、追加する単位の契約、バージョニング、運用を担う準備ができていません。
判断のための問い(簡潔版)
- 分離によって、調整コストの増加を上回るほど、意図しない結合を減らせますか?
- 自然なユビキタス言語の境界がありますか。それとも技術的な継ぎ目にすぎませんか?
境界づけられたコンテキスト内のサブユニット
外側の境界は適切でも、その内部に名前の付いたサブ領域(サブドメイン、機能領域)がある場合があります。原則はコンテキスト内でも適用されます。
オーナーシップ
- 可能な限り、各サブユニットがモデルと永続化に関する自身の範囲を所有するべきです。すべてのサブユニットのすべてのストアとリポジトリを一か所で配線する巨大な登録レイヤーは避けてください(直接参照や隠れた結合を促します)。
サブユニット間のアクセス
- 同じコンテキスト内で明示的なインターフェースを提供する内部アプリケーション APIや薄い内部ファサードを優先し、互いのストレージ型を直接インポートするのは避けてください。
- 非同期フローでは、イベントやコマンドとともに渡せるデータを求めてハンドラーがサブユニット間で問い合わせを繰り返すことのないよう、拡張されたペイロードを優先してください。
コンテキスト内の共有カーネル
- 小さく安定した共有型や列挙型は、限定された共有領域に置くことができます。ただし、実質的な結合点となる、肥大化した「utils」の寄せ集めにならないよう注意してください。
アンチパターン: すべてのサブユニットの全テーブル/ドキュメントを把握する唯一の場所となり、他のすべてがそこを直接参照する単一の「persistence」または「data」サブモジュール。これは、コンテキスト境界をまたぐ直接参照と同じ問題を、境界の内側で引き起こします。
アーキテクチャ適合性の確認
ツールの有無を前提とせず、レビューや監査に使用してください。項目は証明ではなく兆候として扱い、ドメインの専門家に確認してください。
依存関係と API の兆候
- 内向きと外向き: 依存関係は、選択したアーキテクチャ(例:ドメインを中心に置き、アダプターを外側に置く)に沿っている必要があります。インフラストラクチャ型がコアロジックに内向きに漏れているのは、問題の兆候です。
- 公開インターフェース: ストレージや内部サービスを含めずに、エクスポートされた操作/イベント/型を列挙できますか?できない場合、境界に漏れがあります。
- 隣接モジュールのインポート: モジュール Aの型やクライアントがモジュール Bで使われている場合、それらは契約の型だけですか、それとも永続化や実装の型も含まれていますか?
永続化とデータの兆候
- 直接参照: 合意された契約の外で、別のコンテキストの物理的なデータ(スキーマ、コレクション、バケット名)を参照している。
- 名前の衝突: 異なるものに同じ論理名が使われている、または文書化された対応付けルールのない共有グローバル ID が使われている。
- トランザクションのオーナーシップ: 明確なサガ、アウトボックス、または単一オーナーのルールと、文書化された障害ケースがないまま、コンテキストをまたいで書き込みが行われている。
運用上の兆候
- 責任の所在: 「この行/振る舞いをどのモジュールが所有しているかわからない」というインシデントは、オーナーシップまたは可観測性の欠如を示します。
- 連鎖障害: ある依存先の遅延や障害によって、無関係なユーザージャーニーまで停止する場合は、タイムアウト、バルクヘッド、または縮退運転の経路が不足しています。
重大度の目安(報告用)
| レベル | 意味 |
|---|---|
| P0 | データ破損のリスク、セキュリティ境界の侵害、または契約なしのコンテキスト横断永続化 |
| P1 | オーナーシップが不明確、公開 API に漏れがある、境界での障害時の意味づけが不足 |
| P2 | 可観測性の欠如、合成性に関する問題の兆候、将来の結合を増やす技術的負債 |
成熟度に関する注記: チームが数値による基準を定めない限り、評価は定性的です。推移を確認してください。時間とともに P0/P1 が減り、契約が明確になっていることが目安です。
構成を提案する前の簡易チェックリスト
- 公開 API は最小限であり、内部機能を安易にエクスポートしていません。
- モジュールごとに、名前とストレージの所有権が明確です。
- 明示的な契約がないまま、モジュール間で永続化を迂回していません。
- ビジネスルールは、アダプターだけでなく、明確なアプリケーション層/ドメイン層の背後に置かれています。
- モジュール間の呼び出しでは、失敗時の動作とタイムアウトの動作が明示されています。
- 詳細を掘り下げなくても、「どのモジュールが、なぜ失敗したのか」を可観測性で把握できます。
- コンテキストにサブユニットがある場合、各ユニットの所有権が明確です。永続化処理をひとまとめにした巨大な「すべてを登録する」構造になっていません。
スタック固有のスキルとの関係
プロジェクトに具体的な規約(フレームワークのモジュール、DI、リポジトリパターン、フォルダ構成、コード生成、CI チェック)がある場合は、実装方法について、それらのドキュメントを優先してください。境界が存在する理由と、優れたモジュール設計が最適化する対象については、このスキルを使用してください。これにより、スタック固有のアドバイスも同じ原則に沿ったものになります。