incremental-implementation について
複数ファイルにまたがる機能開発やリファクタリング向けの、コーディングエージェント用スキルです。小さな垂直スライスごとに実装、テスト、検証、コミットし、動作する状態を保ちながら進めます。
主な機能
- 01小さな垂直スライスで実装
- 02各段階でテストと検証
- 03高リスクの作業を先に処理
- 04範囲を絞りビルドを維持
- 05各段階をロールバックしやすくする
活用シーン
- 01複数層にまたがる機能の段階的開発
- 02複数ファイルの変更の分割
- 03既存コードの段階的なリファクタリング
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ addyosmani/ agent-skills --skill incremental-implementationインストール後、Claude Code で/incremental-implementationを入力して読み込まれたか確認します。
詳細
段階的な実装
概要
小さな垂直スライスに分けて構築します。一つ実装したら、テストし、動作を確認してから、次に進みます。機能全体を一度に実装するのは避けてください。各段階の終了時に、システムが動作し、テスト可能な状態であることが重要です。この実行規律によって、大規模な機能も管理しやすくなります。
使用する場面
- 複数のファイルにまたがる変更を実装するとき
- タスクの分解に基づいて新機能を構築するとき
- 既存のコードをリファクタリングするとき
- テストする前に約100行を超えるコードを書きそうなとき
使用しない場面: スコープがすでに最小限である、単一ファイル・単一関数の変更。
インクリメントサイクル
┌──────────────────────────────────────┐
│ │
│ Implement ──→ Test ──→ Verify ──┐ │
│ ▲ │ │
│ └───── Commit ◄─────────────┘ │
│ │ │
│ ▼ │
│ Next slice │
│ │
└──────────────────────────────────────┘
各スライスで、以下を行います。
- 実装 — 機能の最小限の完成形を実装します
- テスト — テストスイートを実行します(テストがなければ作成します)
- 確認 — スライスが期待どおりに動作することを確認します(テストの成功、ビルドの成功、手動確認)
- コミット -- わかりやすいメッセージを付けて進捗を保存します(アトミックコミットの指針は
git-workflow-and-versioningを参照してください) - 次のスライスへ進む — 最初からやり直さず、前の成果を引き継ぎます
スライスの戦略
垂直スライス(推奨)
スタックを通る一つの経路を、最後まで構築します。
Slice 1: Create a task (DB + API + basic UI)
→ Tests pass, user can create a task via the UI
Slice 2: List tasks (query + API + UI)
→ Tests pass, user can see their tasks
Slice 3: Edit a task (update + API + UI)
→ Tests pass, user can modify tasks
Slice 4: Delete a task (delete + API + UI + confirmation)
→ Tests pass, full CRUD complete
各スライスで、エンドツーエンドで動作する機能を提供します。
コントラクトファーストのスライス
バックエンドとフロントエンドを並行して開発する必要がある場合:
Slice 0: Define the API contract (types, interfaces, OpenAPI spec)
Slice 1a: Implement backend against the contract + API tests
Slice 1b: Implement frontend against mock data matching the contract
Slice 2: Integrate and test end-to-end
リスクファーストのスライス
最もリスクが高い、または不確実な部分から取り組みます。
Slice 1: Prove the WebSocket connection works (highest risk)
Slice 2: Build real-time task updates on the proven connection
Slice 3: Add offline support and reconnection
スライス1が失敗した場合、スライス2と3に投資する前に問題を発見できます。
実装ルール
ルール0:シンプルさを優先する
コードを書く前に、次のように問いかけます。「動作するものの中で、最もシンプルなのは何か?」
コードを書いた後、以下の観点から見直します。
- もっと少ない行数で実現できますか?
- これらの抽象化は、その複雑さに見合う価値を生み出していますか?
- シニアエンジニアがこれを見て、「どうして単に……しなかったのか」と言うでしょうか?
- 想定上の将来要件に対応しようとしているのか、それとも現在のタスクに対応しようとしているのか?
SIMPLICITY CHECK:
✗ Generic EventBus with middleware pipeline for one notification
✓ Simple function call
✗ Abstract factory pattern for two similar components
✓ Two straightforward components with shared utilities
✗ Config-driven form builder for three forms
✓ Three form components
早まった抽象化より、よく似たコードが3行あるほうが望ましいです。まずは素朴で明らかに正しい実装にします。テストによって正しさが証明された後にのみ、最適化します。
ルール0.5:スコープを守る
タスクに必要な部分だけを変更します。
以下のことはしないでください。
- 変更箇所に隣接するコードを「整理」する
- 変更しないファイルのインポートをリファクタリングする
- 十分に理解していないコメントを削除する
- 「役に立ちそう」という理由で仕様にない機能を追加する
- 読むだけのファイルで構文をモダナイズする
タスクのスコープ外で改善すべき点に気づいたら、記録するだけにして、修正はしないでください。
NOTICED BUT NOT TOUCHING:
- src/utils/format.ts has an unused import (unrelated to this task)
- The auth middleware could use better error messages (separate task)
→ Want me to create tasks for these?
ルール1:一度に一つのことに取り組む
各インクリメントでは、論理的に一つのことだけを変更します。複数の関心事を混在させないでください。
悪い例: 新しいコンポーネントの追加、既存コンポーネントのリファクタリング、ビルド設定の更新を一つのコミットで行う。
良い例: 変更ごとに一つずつ、合計3つの別々のコミットにする。
ルール2:コンパイル可能な状態を保つ
各インクリメントの後、プロジェクトがビルドでき、既存のテストがすべて成功する必要があります。スライスの合間に、コードベースを壊れた状態のままにしないでください。
ルール3:未完成の機能には機能フラグを使う
機能がユーザー向けにまだ準備できていないものの、インクリメントをマージする必要がある場合:
// Feature flag for work-in-progress
const ENABLE_TASK_SHARING = process.env.FEATURE_TASK_SHARING === 'true';
if (ENABLE_TASK_SHARING) {
// New sharing UI
}
これにより、未完成の作業を公開せずに、小さなインクリメントをメインブランチにマージできます。
ルール4:安全なデフォルト
新しいコードでは、安全で保守的な動作をデフォルトにします。
// Safe: disabled by default, opt-in
export function createTask(data: TaskInput, options?: { notify?: boolean }) {
const shouldNotify = options?.notify ?? false;
// ...
}
ルール5:ロールバックしやすくする
各インクリメントは、個別に元に戻せるようにします。
- 追加的な変更(新しいファイル、新しい関数)は簡単に元に戻せます
- 既存コードの変更は最小限に抑え、対象を絞ります
- データベースのマイグレーションには、対応するロールバック用マイグレーションを用意します
- あるコミットで何かを削除して同じコミットで置き換えるのは避け、別々に行います
エージェントとの作業
エージェントに段階的な実装を指示する場合:
"Let's implement Task 3 from the plan.
Start with just the database schema change and the API endpoint.
Don't touch the UI yet — we'll do that in the next increment.
After implementing, run the repository's test and build commands to
verify nothing is broken."
各インクリメントで対象となる範囲と、対象外の範囲を明確にしてください。
インクリメントのチェックリスト
各インクリメントの後、リポジトリ独自のコマンドで確認します(test-driven-development スキルの「Discover the Stack First」セクションを参照してください)。
- 変更が1つのことに取り組み、それを完全に実現している
- 既存のテストがすべて引き続き成功する(リポジトリのテストコマンド:
npm test、./gradlew test、pytest、など) - ビルドが成功する(リポジトリのビルドコマンド)
- スタックで型チェックが使われている場合、型チェックが成功する(
npx tsc --noEmit、mypy、など) - リントが成功する(リポジトリのリントコマンド)
- 新しい機能が期待どおりに動作する
- 変更が内容の分かるメッセージとともにコミットされている
注記: 変更が影響する可能性のある検証コマンドは、その変更後に実行してください。実行が成功したら、その後コードが変更されていない限り、同じコマンドを繰り返す必要はありません。変更のないコードに対して再実行しても、新しい情報は得られません。
よくある合理化
| 合理化 | 実態 |
|---|---|
| 「テストは最後にまとめて実行しよう」 | バグは積み重なります。スライス1のバグによって、スライス2〜5も誤ったものになります。各スライスをテストしてください。 |
| 「一度にすべてやるほうが速い」 | 何かが壊れて、変更した500行のうちどの行が原因か分からなくなるまでは、そう感じるものです。 |
| 「この変更は小さいから、個別にコミットする必要はない」 | 小さなコミットにはコストがかかりません。大きなコミットはバグを見えにくくし、ロールバックを困難にします。 |
| 「機能フラグは後で追加しよう」 | 機能が完成していないなら、ユーザーに見える状態にすべきではありません。今すぐフラグを追加してください。 |
| 「このリファクタリングは小さいから一緒に含めてもよい」 | リファクタリングと機能を混在させると、どちらもレビューやデバッグが難しくなります。分けてください。 |
| 「念のため、ビルドコマンドをもう一度実行しよう」 | 実行が成功した後は、コードが変更されていない限り、同じコマンドを繰り返しても何も得られません。安心のためではなく、その後に編集した場合に再実行してください。 |
危険信号
- テストを実行せずに100行を超えるコードを書く
- 1つのインクリメントで、関連のない変更を複数行う
- 「これもさっと追加しよう」と作業範囲を広げる
- 速く進めるためにテスト/検証の手順を省略する
- インクリメント間でビルドやテストが壊れたままになる
- コミットされていない変更が大量に蓄積する
- 3つ目のユースケースで必要になる前に抽象化を構築する
- 「ついでに」タスクの範囲外のファイルに手を加える
- 一度しか使わない処理のために新しいユーティリティファイルを作成する
- コードを変更する間を置かず、同じビルド/テストコマンドを2回続けて実行する
検証
タスクのすべてのインクリメントを完了した後:
- 各インクリメントを個別にテストし、コミットした
- テストスイート全体が成功する
- ビルドが問題なく完了する
- 仕様どおり、機能がエンドツーエンドで動作する
- コミットされていない変更が残っていない
関連項目
インクリメントごとの検証は、ローカルな確認です。タスクの完了を宣言する前に、最終関門としてプロジェクト全体のDefinition of Doneを適用してください。これはタスクにかかわらず、すべてのインクリメントが満たすべき基準です。../../references/definition-of-done.mdを参照してください。