はじめに
AI コーディングエージェントに「この機能を実装して」と頼むと、実装自体は進みます。しかし、完了の定義が曖昧だと、最後に次の確認が残ります。
- 通常動作は満たしたが、エラー時の動きが未確認
- 認可や利用条件が本文に出てこない
- テストは通ったが、何を確認したテストか分からない
- no-regression の観点が抜けている
この問題を減らすために、実装前に「完成条件」を短く宣言する Sprint Contract(本記事での独自の呼び名)を置くようにしました。
詰まったポイント
AI に実装を頼むと、最初に見える happy path はかなり速く作れます。
一方で、依頼文が薄いと次のような抜けが起きます。
- ログイン済み前提なのに、未ログイン時の扱いがない
- API 失敗時に画面へ何を出すか決まっていない
- 既存の保存形式や設定値との互換性を見ていない
- テストが「正常に保存できる」だけで、重複実行や invalid input を見ていない
実装後にこれを直すと、コードだけでなくテスト、UI 文言、エラー処理まで戻ることになります。
原因
原因は、実装タスクを「作るもの」だけで渡していたことでした。
人間なら会話の中で補完する前提条件でも、AI に渡すときは明示しないと抜けます。特に次の観点は、依頼文に入っていないと後回しになりがちです。
- 通常動作
- 利用前提や認可
- invalid input
- エラー処理
- 重複操作や再実行
- 既存機能の no-regression
そこで、作業開始前にこれらを完成条件として宣言するようにしました。
Sprint Contract の最小テンプレート
自分の運用では、実装前に次の形で書きます。
完成条件:
- 通常動作:
- 前提条件・認可:
- invalid input:
- エラー処理:
- 重複操作・再実行:
- no-regression:
検証:
- 手動確認:
- 自動テスト:
- 実行コマンド:
すべてを埋める必要はありません。該当しないなら 該当なし と書きます。
重要なのは、実装前に「今回は見ない」と決めた観点も明示することです。未定義のまま進めるより、後でレビューしやすくなります。
記入例
たとえば、設定画面に「通知を有効化する」トグルを追加するなら、次のように書けます。
完成条件:
- 通常動作:
- 設定画面で通知トグルを変更できる
- 保存後に再表示しても値が維持される
- 前提条件・認可:
- ログイン済みユーザーの設定だけを更新する
- 他ユーザーの設定 ID を指定しても更新しない
- invalid input:
- boolean 以外の値はサーバー側で拒否する
- エラー処理:
- 保存失敗時は画面に短いエラーメッセージを出す
- スタックトレースや内部パスは出さない
- 重複操作・再実行:
- 同じ値で保存しても余計な副作用が出ない
- no-regression:
- 既存のプロフィール保存が壊れない
検証:
- 自動テスト:
- 正常保存
- 他ユーザー ID の拒否
- invalid input の拒否
- 実行コマンド:
- npm run test
- npm run build
この状態で AI に渡すと、実装後の自己チェックやテスト追加の観点が揃います。
テスト観点も先に渡す
テストを後から「いい感じに書いて」と頼むと、happy path だけになることがあります。
実装前に、最低限次を渡します。
テスト観点:
- normal: 有効な入力で保存できる
- boundary: 空文字、最大長、0件など境界値を扱う
- invalid: 不正な型や範囲外の値を拒否する
- authorization: 他ユーザーのデータを更新できない
- idempotency: 同じ操作を2回しても副作用が増えない
- regression: 既存の主要フローが壊れない
全部のテストを毎回書く必要はありません。小さい変更なら normal と regression だけで足りることもあります。
ただし、認可、課金、外部 API、永続データを触る変更では、invalid、authorization、idempotency を省くと後で戻りやすいです。
AIへの依頼文に混ぜる例
実際に頼むときは、完成条件と対象範囲を一緒に渡します。
次の範囲だけ実装してください。
対象:
- src/settings/notification.ts
- src/settings/notification.test.ts
完成条件:
- 通知設定を保存できる
- boolean 以外の入力は拒否する
- 保存失敗時に内部例外をユーザーへ出さない
- 同じ値で2回保存しても結果が変わらない
- 既存の設定読み込みテストが通る
検証:
- npm run test
- npm run build
触らない:
- 認証まわり
- package.json
- unrelated formatting
ここまで書くと、AI は「何を作るか」だけでなく「何を壊してはいけないか」も見ながら作業できます。
注意点
Sprint Contract を細かくしすぎると、実装前の準備だけで重くなります。
自分は次の基準で粒度を変えています。
| 変更の種類 | 完成条件の粒度 |
|---|---|
| 文言修正、単純な表示変更 | 通常動作と no-regression だけ |
| フォーム、設定、保存処理 | invalid input とエラー処理を追加 |
| ユーザーデータ | 認可と所有権チェックを追加 |
| 外部 API | quota、失敗時表示、手動更新との分離を追加 |
| DB migration | rollback ではなく復旧方針、nullability、index、transaction を追加 |
すべてのタスクに最大のチェックリストを使うのではなく、失敗したときの影響が大きい部分に厚く使います。
まとめ
AI に実装を任せる前に完成条件を宣言すると、実装後のレビューが楽になります。
自分の運用では、少なくとも次を先に書くようにしました。
- 通常動作
- 前提条件・認可
- invalid input
- エラー処理
- 重複操作・再実行
- no-regression
- 検証コマンド
AI に「作るもの」だけ渡すのではなく、「完了と見なす条件」まで渡す。これだけで、実装後に戻る回数を減らせました。