codebase-design について
codebase-design は、コードの設計や再構成に取り組む開発者向けのスキルです。小さなインターフェースの背後に多くの振る舞いをまとめ、継ぎ目を適切に選び、インターフェース経由でテストできる設計を重視します。
主な機能
- 01深いモジュールの設計
- 02インターフェースの複雑さの削減
- 03モジュールの継ぎ目の選定
- 04インターフェース経由のテスト
- 05依存性注入と結果指向の設計
活用シーン
- 01明確なモジュール構成への再編
- 02呼び出し側のインターフェース簡素化
- 03振る舞いのテスト容易性向上
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ niekcandaele/ skills --skill codebase-designインストール後、Claude Code で/codebase-designを入力して読み込まれたか確認します。
同梱ファイルDEEPENING.mdINTERFACE-DESIGN.md
詳細
コードベースの設計
深いモジュールを設計します。つまり、クリーンな継ぎ目に配置され、小さなインターフェースの背後に多くの振る舞いを備え、そのインターフェースを通じてテストできるモジュールです。コードを設計または再構成する際は、どこでもこの用語と原則を使ってください。目指すのは、呼び出し側にとっての活用のしやすさ、保守担当者にとっての局所性、そしてすべての人にとってのテスト容易性です。
用語集
これらの用語を正確に使ってください。「コンポーネント」「サービス」「API」「境界」に置き換えないでください。一貫した用語を使うことが重要です。
モジュール インターフェースと実装を持つものすべてです。意図的に規模を限定しない用語で、関数、クラス、パッケージ、複数の層にまたがる一連の処理のどれにも等しく当てはまります。 避ける語: unit、component、service。
インターフェース モジュールを正しく使うために呼び出し側が知っておくべきことすべてです。型シグネチャだけでなく、不変条件、順序の制約、エラーの種類、必要な設定、パフォーマンス特性も含みます。 避ける語: API、signature(範囲が狭すぎます。これらは型レベルの表面だけを指します)。
実装 モジュールの内部にあるもの、つまりコード本体です。アダプターとは異なります。小さなアダプターに大きな実装(Postgres のリポジトリ)が含まれることも、大きなアダプターに小さな実装(インメモリのフェイク)が含まれることもあります。継ぎ目が話題の中心なら「アダプター」を使い、それ以外では「実装」を使います。
深さ インターフェースにおける活用のしやすさ、つまり呼び出し側(またはテスト)が、学ぶ必要のあるインターフェースの単位あたりに実行できる振る舞いの量です。多くの振る舞いが小さなインターフェースの背後にあるとき、モジュールは深いと言えます。インターフェースが実装とほぼ同じくらい複雑なとき、モジュールは浅いと言えます。
継ぎ目 (Michael Feathers による用語) その箇所を編集せずに振る舞いを変更できる場所です。モジュールのインターフェースが置かれる位置を指します。継ぎ目をどこに置くかは、その背後に何を置くかとは別の、独立した設計上の判断です。 避ける語: boundary(DDD の境界づけられたコンテキストと意味が重なりすぎます)。
アダプター 継ぎ目にあるインターフェースを満たす具体的なものです。中身(何でできているか)ではなく、役割(どの枠を埋めるか)を表します。
活用のしやすさ 深さによって呼び出し側が得られるものです。学ぶ必要のあるインターフェースの単位あたりに、より多くの機能を利用できます。1つの実装が N 箇所の呼び出し元と M 個のテストで活用されます。
局所性 深さによって保守担当者が得られるものです。変更、バグ、知識、検証が呼び出し元に広がるのではなく、一箇所に集まります。一度直せば、すべての箇所で修正されます。
深いモジュールと浅いモジュール
深いモジュール = 小さなインターフェース + 大きな実装:
┌─────────────────────┐
│ Small Interface │ ← Few methods, simple params
├─────────────────────┤
│ │
│ Deep Implementation│ ← Complex logic hidden
│ │
└─────────────────────┘
浅いモジュール = 大きなインターフェース + 小さな実装:
┌─────────────────────────────────┐
│ Large Interface │ ← Many methods, complex params
├─────────────────────────────────┤
│ Thin Implementation │ ← Just passes through
└─────────────────────────────────┘
インターフェースを設計するときは、次の点を考えてください。
- メソッドの数を減らせますか?
- パラメーターを簡素化できますか?
- 内部にさらに多くの複雑さを隠せますか?
原則
- 深さは実装ではなく、インターフェースの特性です。 深いモジュールは、内部で小さく、モック可能で、差し替え可能な部品を組み合わせていてもかまいません。ただし、それらはインターフェースの一部ではありません。モジュールは、インターフェースにある外部の継ぎ目に加えて、内部の継ぎ目(実装内に隠され、モジュール自身のテストで使われるもの)を持つこともできます。
- 削除テスト。 モジュールを削除するところを想像してください。複雑さが消えるなら、そのモジュールは何も隠していません(単なる中継処理でした)。複雑さが N 個の呼び出し元に再び現れるなら、そのモジュールには存在意義がありました。
- インターフェースがテスト対象の境目です。 呼び出し側もテストも、同じ継ぎ目を通ります。インターフェースの先までテストしたいなら、そのモジュールはおそらく適切な形ではありません。
- アダプターが1つなら仮想的な継ぎ目です。2つあれば実際の継ぎ目です。 その継ぎ目をまたいで実際に変わるものがない限り、継ぎ目を導入しないでください。
テストしやすさを考慮した設計
優れたインターフェースは、自然なテストを可能にします。
-
依存関係は受け取り、生成しないでください。
// Testable function processOrder(order, paymentGateway) {} // Hard to test function processOrder(order) { const gateway = new StripeGateway(); } -
結果を返し、副作用を起こさないでください。
// Testable function calculateDiscount(cart): Discount {} // Hard to test function applyDiscount(cart): void { cart.total -= discount; } -
表面積を小さくします。 メソッドが少ないほど必要なテストも少なくなります。パラメーターが少ないほどテストの準備も簡単になります。
関係性
- モジュールは、呼び出し元やテストに提示する表面であるインターフェースをちょうど1つ持ちます。
- 深さはモジュールの特性であり、そのインターフェースを基準に測定されます。
- シームとは、モジュールのインターフェースが存在する場所です。
- アダプターはシームに配置され、インターフェースを満たします。
- 深さは、呼び出し元にレバレッジを、保守担当者に局所性をもたらします。
採用しない捉え方
- 実装行数とインターフェース行数の比率としての深さ(Ousterhout):実装を水増しするほど評価されてしまいます。ここでは、レバレッジとしての深さを採用します。
- 「インターフェース」をTypeScriptの
interfaceキーワードやクラスの公開メソッドと捉えること:範囲が狭すぎます。ここでいうインターフェースには、呼び出し元が知っておく必要のあるあらゆる事柄が含まれます。 - 「境界」:DDDの境界づけられたコンテキストと意味が重複します。シームまたはインターフェースを使います。
さらに掘り下げる
- 依存関係を踏まえてクラスターを深化させる — DEEPENING.mdを参照してください。依存関係のカテゴリ、シームの規律、置き換えを重視するテストについて説明しています。
- 代替インターフェースを検討する — INTERFACE-DESIGN.mdを参照してください。並行するサブエージェントを起動して、インターフェースを根本的に異なる複数の方法で設計し、深さ、局所性、シームの配置を基準に比較します。
mattpocock/skillsに基づいています。MIT © 2026 Matt Pocock。このファイルをコピーする場合は、この行を残してください。