mcpField
C
codebase-design

codebase-design

github.com/vinvcn開発5.4k4.2k 回インストール1 日前に更新
リポジトリ

codebase-design について

codebase-designは、ソフトウェアの設計とリファクタリング向けのエージェントスキルです。明確なシーム上の小さなインターフェースに多くの振る舞いを隠す設計を扱い、モジュールの深さ、アダプター、テスト容易性の原則を示します。

主な機能

  1. 01モジュールとインターフェースの用語
  2. 02小さなインターフェースへの複雑な振る舞いの集約
  3. 03シームとアダプターの役割の特定
  4. 04削除テストによるモジュール価値の評価
  5. 05テストしやすいインターフェース設計

活用シーン

  1. 01新しいモジュールの明確なインターフェース設計
  2. 02浅い中継モジュールのリファクタリング
  3. 03テストが通るシームの選定
  4. 04依存関係や副作用がテストに及ぼす影響の評価

インストール

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

$npx skills add https://github.com/vinvcn/mattpocock-skills-zh-cn --skill codebase-design

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

同梱ファイル

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

DEEPENING.md
DESIGN-IT-TWICE.md
agents/
openai.yaml

詳細

コードベース設計

deep modules を設計します。小さな interface の背後に多くの振る舞いを置き、明確な seam 上に interface を配置し、その interface を通してテストします。コードを設計またはリファクタリングするときは、常にこの言葉と原則を使ってください。目標は、callers に leverage をもたらし、maintainers に locality をもたらし、誰にとってもテストしやすくすることです。

用語集

これらの用語を正確に使い、「component」「service」「API」「boundary」に置き換えないでください。一貫した言葉を使うことが重要です。

Module - interface と implementation を持つものすべてです。意図的に規模を限定していません。function、class、package、あるいは複数レイヤーにまたがる slice でもかまいません。避ける: unit、component、service。

Interface - caller が module を正しく使うために知っておく必要のあるすべてです。type signature に加え、invariants、ordering constraints、error modes、required configuration、performance characteristics が含まれます。避ける: API、signature(狭すぎます。type-level surface のみを指すためです)。

Implementation - module 内部のコードです。Adapter とは異なります。小さな adapter に大きな implementation が備わっている場合(Postgres repo)もあれば、大きな adapter に小さな implementation が備わっている場合(in-memory fake)もあります。seam について話すときは adapter、それ以外では implementation と呼びます。

Depth - interface がもたらす leverage です。caller(または test)が interface を学ぶために費やす単位あたり、どれだけの振る舞いにアクセスできるかを表します。多くの振る舞いが小さな interface の背後に隠れている module は deep であり、interface が implementation とほぼ同じ複雑さを持つ module は shallow です。

Seam(Michael Feathers)- 現在の場所を編集せずに振る舞いを変えられる場所です。つまり、module の interface が存在する 場所 です。seam をどこに置くかは、seam の背後に何を置くかとは別の設計上の決定です。避ける: boundary(DDD の bounded context と意味が重複するためです)。

Adapter - seam 上で特定の interface を満たす具体的なものです。内部に何があるかという実体(substance)ではなく、どの枠を埋めるかという 役割(role)を表します。

Leverage - callers が depth から得る利益です。interface を学ぶために費やす単位あたり、より多くの能力が得られます。1 つの implementation が N 個の call sites と M 個の tests で効果を発揮します。

Locality - maintainers が depth から得る利益です。change、bugs、knowledge、verification が callers に分散せず、一か所に集まります。一度直せば、あらゆる場所で修正されます。

Deep と shallow

Deep module = 小さな interface + 多くの implementation:

+------------------+
| Small Interface  | -> few methods, simple params
+------------------+
|                  |
| Deep             | -> complex logic hidden
| Implementation   |
|                  |
+------------------+

Shallow module = 大きな interface + 少ない implementation(避けてください):

+-------------------------------+
| Large Interface               | -> many methods, complex params
+-------------------------------+
| Thin Implementation           | -> mostly pass-through
+-------------------------------+

interface を設計するときは、次の点を確認してください。

  • methods の数を減らせますか?
  • parameters を簡素化できますか?
  • さらに複雑さを内部に隠せますか?

原則

  • Depth は implementation ではなく、interface の特性です。 Deep module の内部は、小さくて mock 可能かつ差し替え可能な parts で構成されていてもかまいません。ただし、それらは interface の一部ではありません。module は internal seams(implementation 内部にあり、自身の tests で使われるもの)と、interface 上にある external seam の両方を持つことができます。
  • 削除テスト。 この module を削除すると想像してください。複雑さがなくなるなら、それは単なる pass-through です。複雑さが N 個の callers に再び散らばるなら、その module は価値を発揮しています。
  • Interface はテスト対象の surface です。 Callers と tests は同じ seam を通ります。interface の背後にある内部の詳細をテストしたいなら、この module の形は適切でない可能性があります。
  • Adapter が 1 つなら仮定上の seam、2 つなら実在する seam です。 seam をまたいで変化するものが実際にない限り、seam を導入しないでください。

テスト容易性を考慮した設計

優れた interfaces なら、自然にテストできます。

  1. 依存関係を受け取り、生成しない。

    // Testable
    function processOrder(order, paymentGateway) {}
    
    // Hard to test
    function processOrder(order) {
      const gateway = new StripeGateway();
    }
    
  2. 副作用を起こさず、結果を返す。

    // Testable
    function calculateDiscount(cart): Discount {}
    
    // Hard to test
    function applyDiscount(cart): void {
      cart.total -= discount;
    }
    
  3. 小さな surface area。 methods が少ないほど、必要な tests も少なくなります。params が少ないほど、test setup も簡単になります。

関係

  • 1 つの Module は、ちょうど 1 つの Interface(callers と tests に提示する surface)を持ちます。
  • Depth は Module の特性であり、その Interface を基準に測ります。
  • Seam は Module の Interface が存在する場所です。
  • Adapter は Seam 上にあり、Interface を満たします。
  • Depth は callers に Leverage を、maintainers に Locality をもたらします。

採用しない表現

  • depth を implementation の行数と interface の行数の比として扱うこと(Ousterhout):implementation の水増しを促すためです。ここでは depth-as-leverage を使います。
  • 「Interface」を TypeScript の interface keyword や class の public methods と解釈すること:狭すぎます。ここでいう interface には、caller が知っておく必要のあるすべての事実が含まれます。
  • 「Boundary」:DDD の bounded context と意味が重複します。seam または interface と呼んでください。

さらに深く理解する

  • 依存関係を踏まえた cluster の deepening - DEEPENING.md を参照してください。Dependency の分類、Seam の規律、「追加ではなく置き換える」というテスト戦略について説明しています。
  • 別の interfaces を検討する - DESIGN-IT-TWICE.md を参照してください。sub-agents を並行して起動し、いくつかの大きく異なる方法で interface を設計したうえで、depth、locality、seam の配置を比較します。

コメント