| name | slice-tdd |
| description | エンジニアとして手を動かす作業全般で必ず発火させる: コードを書く / テストを書く / リファクタ / バグ修正 / E2E spec 追加 / 既存仕様への小さな修正など、コードに触る作業すべて。「実装して」「テスト書いて」「リファクタして」「バグ直して」のような依頼を受けたとき、または基本設計が済んで実装フェーズに入るときに発火。基本作業は TDD(テスト先書き → 最小実装 → リファクタ → コミット)で進め、要件が大きければ適切な小ささに分割しつつサイクルを回す。発火しないのは要件定義 / 基本設計の対話中(まだ手を動かしていない時)だけ。 |
実装フェーズ — 小さく TDD する
なぜこの skill があるか
要件と設計が固まった後、実装を一気にやると「途中で詰まる」「どこで間違えたか分からなくなる」「動いてるけど未完成のものが本番に残る」といった問題が起きる。
「小さく分割しつつ TDD で進める」のがアジャイルの本質的な動き方。各単位で TDD のサイクル(レッド → グリーン → レビュー → リファクタ → コミット)を回し、テストと実装の両方からフィードバックを得てリズムよく開発する。「小さく」が先で「繰り返し」は結果。要件がもともと小さければ 1 サイクルで終わってよい。
実装方針: outside-in TDD(この skill の芯)
このプロジェクトの実装は outside-in TDD を例外なしのルール にする。
サイクルは入れ子(マトリョーシカ)
1 サイクル = レッド → グリーン → レビュー → リファクタ → コミット。ここまでで 1 つ、分割しない(グリーンで止めて次に進まない、レビューとリファクタを飛ばさない、コミットで閉じる)。
大きいサイクル(ストーリー全体を E2E で駆動)の中に、小さいサイクル(層ごと)が入れ子で並ぶ。小さいサイクルも同じ形。実装は「大きいサイクルを 1 本回す」ではなく、中の小サイクルを 1 つずつ開いて各々を回す。マトリョーシカの一番外の人形だけ開けて中を開けない(大サイクル 1 本に潰す)が崩れ。
outside-in = インタフェース先行の「設計」(各階層で同じ動き)
outside-in は「外側の層から内側へ進む」向きだが、本質は インタフェースを先に決める設計 にある。外側(入口・呼び出し側)を先に書くと「ここは何を受け・何を返すか」という 契約を先に設計させられる。その契約が、内側に何が必要かを浮かび上がらせる。だから outside-in は実装順のテクニックであると同時に 論理設計のプロセス そのもの。
この設計の動きは、どの階層でも同じように再帰する:
- ストーリーの階層では、UI / API が外に見せる契約(E2E が固定する振る舞い)を先に決める
- バックエンドの各層でも同じ — その層が外に見せる契約を先に決めて、内側に何が要るかを浮かび上がらせる(入口 → 内側のロジック → データアクセス、と外から内へ)
内側の層のサイクルも、同じ「契約を先に決める」動き。ストーリーの境界だけでなく、実装の中の各層でも これを効かせる。
これはテストの有無と無関係。outside-in は設計なので、ユニットテストを書かない層(例: 薄い入口やデータアクセス)でも効く。「この層が外に見せる契約」を先に決めるのはテストの話ではなく設計の話だから、外側から設計する。
設計(契約先行)は全ての層で再帰する。ただし TDD のレッド→グリーンのサイクルは、テストがある単位でだけ回る(テストを持たない層は外側のテストがカバーする)。この 2 つは必ずしも一致しない — 設計はどの層でも外→内、レッド→グリーンのサイクルはテストのある所で回る。だから「全層をサイクルで回せ」でも「全層にテストを書け」でもない。
境界: outside-in は方向・設計まで。テストは project の領分
outside-in が決めるのは 進む向きと、契約先行の設計 だけ。その先の「何をどうテストするか」— どの層にどのレベルのテスト(ユニット / E2E)を置くか、テストが何を担保するか、粒度 — は project 固有の流儀(implementation / e2e skill を呼んで探す)。層の名前(例: route / usecase / gateway)も project 依存なので、この skill では 例としてだけ 出す。
アンチパターン: ボトムアップ(内→外)/形だけ outside-in
- ボトムアップ: 最内層(データアクセス・純ロジック)から積み上げ、外側(入口)を最後につなぐ。「動くものから書いている」ように見えて、外側=価値が最後まで検証されず、統合の不備が終盤に噴出する。特にバックエンドの中で「依存を先に作る(データ → ロジック → 入口)」に流れやすい。それは契約を先に決める "設計" でなく、動かすための "構築" に落ちたサイン。外側の契約から設計すれば内側は後から surface する
- 形だけ outside-in: 最上位で E2E を 1 本 "書く" だけで、中は全部内側から積む。E2E を書いただけでは outside-in ではない(そのあと内側から積めば向きはボトムアップのまま)
例外がない理由
ストーリーの定義(Independent / Valuable / Small / Testable)に従えば、ストーリーには必ず外側(UI / API endpoint)がある。Valuable = ユーザー価値が届く = 外側が存在する。だから常に最外層から書ける。純関数ロジック単独ストーリーは Valuable 違反で成立しないので、outside-in が常に適用可能。
例: モック境界で刻む(層が 2 つのときの一例)
入れ子を具体化した一例。これが唯一の型ではない(層が増えれば入れ子は深くなる):
Cycle 1 — フロント側完成(外側の層)
レッド: E2E を書く (期待値は API モックの固定値) → 失敗
グリーン: フロント実装 + API モック → E2E 通る
Cycle 2 — API 側完成(内側の層)
レッド: Fixture を追加 + E2E の期待値を Fixture 値に変更 → モック API が古い値を返し失敗
グリーン: API 実装 (Fixture を読む) → E2E 通る
- E2E を最外層として固定(Cycle 1 の E2E が Cycle 2 でも生き続け、内側を実装する間もユーザー視点の動作を保証する)
- モック → 本実装への置換がレッドを作る(E2E は書き直さず期待値だけ変える)
- 層が 3 つ以上あれば入れ子は深くなり、各層でも「契約を先に決める → レビュー → リファクタ」を通す
やること
まず規模を判断する。軽微(バグ修正・spec 1 個追加・小規模リファクタ・項目 1 つ追加など)は Step 1 を skip して Step 2 から。通常〜大規模は Step 1 から。迷ったら通常として扱う。
Step 1: サイクルに刻む
ストーリー粒度の分割は story-slicing skill の責務(前段で済んでいる前提)。slice-tdd はストーリーを受け取り、TDD サイクルで実装する単位に刻む。実装順は outside-in(上記「実装方針」の通り、外側の契約から)。
1 サイクルで終わるなら 1 サイクル。複数必要なら外側 → 内側で刻む(例は「実装方針」のモック境界を参照。層が増えれば入れ子は深くなる)。やってみてストーリーが大きいと気付いたら story-slicing skill を呼んで再分割する(その都度呼ぶ、普通のこと)。
Step 2: 各サイクルを回す
各分割単位は、それ自体が入れ子の 1 サイクル。大きい単位に潰さず、開ける限り小サイクルを開いて、それぞれレッド → グリーン → レビュー → リファクタ → コミットを通す。
次のサイクルに移る前に、毎回自分に問う(記憶でなく、その場で観測できる問い):
- この単位を、もう一段小さいサイクルに開けないか(大きいサイクル 1 本に潰していないか)
- このサイクルは 外側の契約から設計 して内側へ進んだか(内→外のボトムアップ、依存先行の構築になっていないか)
- このサイクルに対応するテストを流したか(
e2e-execution を呼んで。E2E は書くだけ・終盤に溜める、になっていないか)
- グリーンになったところで code-reviewer を呼んだか(節目でまとめて 1 回ではなく、このグリーンで)
- サイクルを閉じたか(レビュー → リファクタを通した、またはリファクタを skip した理由を commit message に 1 行残した / コミットした)
各段の進め方:
レッド
失敗するテストを 1 個書く。書き始める前に、その種類に対応する流儀を呼んで取り込む(E2E spec なら e2e skill/ユニット等はそのプロジェクトのテスト規約を implementation skill 等で探す)。グリーンで implementation を呼ぶのと同じで、飛ばすと流儀が乗らず手戻りになる。粒度(どのレベルのテストか)は単位の主題で決める=project の流儀。書いたら実行し、期待した理由で失敗することを確認する(import エラー等の事故的失敗は数えない)。
そのサイクルのレッド→グリーンは、そのサイクルに対応するテストで取る。その単位が自前のテストレベルを持つなら、そのテストで回す(遅い外側の E2E に丸投げせず、内側でも都度の速いフィードバックを取る)。テストを持たない層は外側のテストがカバーする(全層にテストを作れ、ではない — どこに何を置くかは project の流儀)。
E2E を書く / 走らせる具体は後述「E2E を書く・走らせる」。
グリーン
プロダクションコードを書き始める前に implementation skill を呼ぶ(project 固有のコード規約・アーキテクチャを取り込んでから書く。飛ばすと規約が乗らず手戻りになる)。その上で 最小実装 でテストを通す(あれもこれも実装しない、今のテストだけ通す)。実行して グリーンになること を確認する。
グリーンになった直後・リファクタに入る前に、毎回 code-reviewer を呼ぶ(呼び方は後述「ペアプロ・レビュー」)。このグリーンで呼ぶ(節目でまとめて 1 回ではない)。
リファクタ
直前のレビューの指摘を入力に、テストがグリーンのまま設計を整える(重複を消す・命名を直す・責務を分ける)。グリーンの安全網があるうちに小さく片付ける — 後回しにするほど大きく危険になる。
skip しないのが原則。片付けるものが無いなら「無し」と判断して理由を commit message に 1 行 残す(コード内コメントには残さない)。あとの単位でまとめて直す、はリファクタではない — そのサイクルの中で閉じる。
コミット
ここまでを 1 コミットにする。commit message は「何をしたか」より「なぜそうしたか」を書く。
feat(reviews): 注文一覧の review_status フィルタを追加
- 注文 review 機能の Step 1 として、一覧画面に「要確認のみ表示」を実装
- バックエンドは既存の listOrders を再利用、UI 側で query param 追加のみ
Step 3: 次の単位へ
Step 2 を分割単位の数だけ繰り返す。各サイクル後に残りの単位を確認し、あれば次へ。
モックや暫定値が本番に残らない仕組み(最重要)
「モック先行 → 実装後付け」で刻むと、中間ステップが「動いている」状態でコミットされる(テストも E2E も通る)。だが未完成で、push されると「動いてるからこそ気付かないバグ」になる。防ぐために以下を マスト で守る:
- 中間ステップを TaskCreate で保持する。分割を決めた瞬間、各ステップを task list に登録し、完了ごとに TaskUpdate で completed にする。全 task が completed になるまで「終わってない」 と認識する
- モック / 暫定値には grep 可能な TODO を残す。
// TODO(slice-tdd): モック。Step 2 で実接続に置換 のように prefix を付け、完了宣言前に grep で残存チェックできるようにする
- commit はしてよいが push / 統合はしない。成果を外に出す Git 操作は
git-workflow skill の完了フローの責務。完了(テスト含む)したら下記「完了宣言前のチェック」を通してから git-workflow を呼ぶ
- 設計 md(
docs/working/<title>/)は削除しない。動作確認・レビュー・振り返りで参照されうる。削除の要否は依頼者や外側の仕組みが決める、あなたは判断しない
最終完了宣言の前に done-verifier を呼ぶ
user に「全部完了」「リリース可能」「push 可能」「タスク完了」型の発話を出す前、および完了フロー(統合・push)に入る前に、必ず Task ツール経由で done-verifier subagent を呼ぶ。例外なし(「もう確認した」「明らかに完了」を理由に skip しない)。
Red Flags — これらを出そうとしたら、done-verifier を呼ぶまで出さない: 「全部完了」「実装完了」「依頼通り出来た」「リリース / push / マージ可能」「タスク全部終わった」「ストーリー完了」。完了フロー(統合・push)に入る前も同じ。
| 言い訳 | 反論 |
|---|
| さっきテスト全部通った | コード変更後に再実行してない可能性。done-verifier が現在の状態で確認する |
| 明らかに完了している | 「明らか」は記憶ベース。実行結果ベースで確認するのが done-verifier の責務 |
| Done 1 個ずつ確認は過剰 | これが Done を観測可能形で書いた理由。検証しないなら Done を書く意味がない |
| 自分でチェックリスト通した | 自己規律には偏りがある。done-verifier は外部視点 |
完了宣言前のチェック(3 つすべてクリアしてから完了報告 → git-workflow の完了フロー):
- モック残存チェック:
grep -r "TODO(slice-tdd)" src/ で残ゼロ
- task list 残チェック: in_progress / pending が残っていないか。
[申し送り](報告対象)の task があれば、全件を完了報告に列挙してから completed にする
- done-verifier 起動: 全 Done ✅ + 全テスト グリーン + build OK + TODO 残ゼロ を確認
E2E を書く・走らせる
- 書く: E2E spec が必要なら必ず
e2e skill を呼ぶ(どう書くかは e2e の責務)
- 走らせる: 必ず
e2e-execution skill を呼ぶ(実行環境・コマンド・失敗時の対処を持っている)。実行手順を自前で組み直さない — 再発明は無駄な探索でトークンも手間も浪費し、実行を実際以上に重く見せて「流さない」言い訳を生む
なぜ都度流すか: 流さずに進めると統合の崩れが CI や終盤でまとめて噴出し、切り分けと手戻りでかえって高くつく。都度流す方が崩れを小さいうちに捕まえて結局は安く速い(グリーンごとのレビューと同じ理屈)。「重い」を理由に飛ばさない — 飛ばす方がコスト。
流すリズム: 作業中は 今触っている層に関係する E2E だけ を各サイクルで流し(軽く速く回る)、最後に全件 流す。関係分だけなら軽いので「全件は重い」は「何も流さない」の言い訳にならない。ただし project 側に抑止系(例: 作業中は全件流さない、等の実行ポリシー)があればそれに従う。
(E2E は外側のテスト。自前のテストを持つ内側の単位は、遅い E2E に丸投げせず自分のテストで回す。テストを持たない層は E2E がカバーする — 上記「レッド」段の通り。)
ペアプロ・レビュー subagent
実装は完全に一人でやらず、ペアプロ相手として subagent を呼んでレビューしてもらう。第三者ではなくペアプロ — 同じ TDD 哲学を共有しつつ別視点で見る相方。
なぜグリーンごとに呼ぶか: 小さく回してグリーンごとにレビューする方が、崩れを小さいうちに捕まえて大きな手戻りを防ぎ、結果的に安定して速い。これがペアプロの価値。だから入れ子が深くて呼び出しが増えても レビューはコストでなく投資 — 呼び出しを減らすためにサイクルを潰すのは本末転倒。呼び出し回数を惜しまない。小さいサイクルで領域は自然に重なり、別サイクルで再レビューになるのは問題ない(別の観点が出るのはむしろ価値)。
- グリーンになったら
code-reviewer(リファクタ前): 別の目を入れてからリファクタする。対象は直近の git diff。設計整合 / TDD 規律 / 責務 / 品質 / セキュリティ / リファクタ指針を点検
- E2E spec を書き終わったら
e2e-reviewer(リファクタ前): プロジェクトの E2E 流儀に照らして点検。対象は直近の spec
指摘の処理(main session の裁量で進めて OK、毎回 user に持ち込まない):
- Security: 例外なく対応。「社内向けだから」等の非対応は禁止
- Critical: 原則対応。「ゴール的に無視できる」と理由を立てれば非対応 OK、その理由は commit message に残す(コード内コメントには残さない)
- Warning: 裁量判断 / Suggestion: 任意
レビューを skip しない(「面倒だから今回は無し」を許さない)。リファクタの判断材料として別の目が要る。
動作しないとき
- テストが期待と違う理由で失敗 → デバッグ情報を集めてから対処。安易に skip / 削除しない
- テストが通らない → 設計 md を読み返す。「Done」を超える実装をしていないか確認
- 同じ問題で 3 回失敗 → アプローチを変える。同じコマンドを再試行し続けず、設計 md を読み返す・小さく分割し直す。自走を尽くしても抜けられない技術的ブロッカーのときだけ依頼者に状況を共有する(設計判断の境界とは別。設計判断の止まる/自走は次節)
自走と対話の境界
実装は基本的に自走モード。要件定義と基本設計で固まった範囲内で、開発者として判断して進める(依頼者は別業務、こまめな進捗報告は不要)。「依頼者の判断が要るかも」と感じたときの止まる/自走は下の判断軸で決める。デフォルトは自走。
2 段ゲート
1 段目 — 実装レイヤーか、要件・設計レイヤーか
- 実装レイヤー(実装手段・書き方・フォーマット・内部構造)→ 自走で決める。判断と理由は commit message に一行残す。ここで自走確定、2 段目に進まない(コードは戻せる、やり直しは自走で吸収)
- 要件・設計レイヤー(ユーザーに見える挙動・データ構造・権限・データ移行の要否)→ 2 段目へ
「形か意味か」で測る。書き方・フォーマット・配置・内部構造の整理(形)は、範囲が大きくても実装レイヤー=自走。ユーザーから観測できる挙動が変わる/データの意味・構造が変わるなら 1 箇所でも要件・設計レイヤー。「数」でなく「ユーザーから見て意味が変わるか」で測る。グレー(例: 保存形式の変更が既存データの読み出しに波及)なときだけ立ち止まって見極める。
2 段目(要件・設計レイヤーのときだけ)— 待たずに進むと手戻りするか
- 手戻りする(暫定で進めると後で作り直す/捨てる)→ その場で止まって依頼者に確認
- 後から追加で済む(暫定は生き残り上に足すだけ)→ 止まらずメイン作業を終わらせ、完了後にまとめて報告
デフォルトは「終わらせて完了後に報告」。即停止は手戻りするときの例外。
安全装置: 元に戻せない操作は無条件で即停止
判断軸とは別に、コードを revert しても取り消せない副作用が外(環境・データ・外部サービス)に残る操作は、必ず止まって依頼者に確認する(設計判断でなく安全規律)。データの削除・不可逆な上書き・データ状態を変えるマイグレーション実行、外部への送信・課金など。コードの変更・リファクタ(revert で戻る)は対象外。本番反映(push / deploy)は git-workflow の完了フローと done-verifier がゲートする。
自走で手段を選ぶときは流儀に従う
実装手段・実行手段を決めるとき、自分の使い慣れたツールや選好を持ち込まない。project の確立した流儀を e2e-execution / implementation skill を 呼んで 探して従う。流儀を変えたくなっても形・手段の話なので止まらない(自走で進めるか、完了後に「手段の見直し」として報告)。
当てはめの例
- 設計 md と矛盾: ユーザーに見える挙動が食い違う → 止まる。実装手段の記述レベルの食い違いで挙動は同じ → 自走で直し設計 md を更新
- 仕様ヌケ: ユーザーに見える挙動・データ構造・権限・移行の要否が未定義 → 手戻りするなら止まる、後から直せるなら仮決めして記録し完了後に報告。内部のエラーハンドリング・ログ等の細部 → 自走で決めて記録
- 新たな設計判断: 仕様に影響する → 止まる(
propose-options で提示)。内部構造・形のみ → 自走。後で内部に波及する重めの判断は、止めず code-reviewer に通して独立視点を入れる
- 見積もりが大きく外れた: 大きいだけなら
story-slicing で再分割し自走継続。桁違いに外れたら計画のズレとして完了後に報告
報告すべき気づきは TaskCreate に残す
自走は「黙って進める」ことではない。依頼者に報告すべき懸念(既存コード・テストの品質、別機能への波及、設計上の違和感、スコープ外と判断して触らなかった点)は、直すか否かに関わらず 完了報告に必ず載せる(直すかは依頼者が決める)。気づいた瞬間に TaskCreate で [申し送り] 付き task として記録し、完了宣言前のチェックで確実に表へ出す(記憶に頼らない)。