イテレーションで実行可能な仕様を練り上げる
前の二つのセクションで方法論のフレームワークを確立しました。情報を階層化し、各階層には三つの次元があり、階層間ではクロスバリデーションでドリフトを検出します。このセクションでは、このフレームワークを手にした状態で、具体的な要件に対して実際にどう操作するかを解説します。
重要な認知的前提があります。specは一度に書き上げるものではなく、イテレーションで練り上げるものです。座って一気に完璧なspecを書く必要はありません。起点を書き、Agentが展開し、クロスバリデーションが問題を露出させ、あなたが修正し、再検証する。収束するまでこれを繰り返します。このプロセス全体は、あなたが一方的にドキュメントを書くというよりも、あなたとAgentの間の構造化された対話に近いものです。
イテレーションの起点:ユーザーストーリー
前述の通り、情報にはvision、アーキテクチャ、feature、taskの四つの階層があります。ここでのspecイテレーションはfeature層とtask層で行います。これは上流の作業が完了していることを前提としています。プロダクトのvisionは確定しており、システムのアーキテクチャは選定されており、これらの高層情報はすでにプロジェクトコンテキストに沈殿しています。visionからuser journey、そして具体的な要件への導出プロセスはプロダクトの方法論の範疇であり、本書では詳述しません。ただし、そのプロセスも同様に重要であり、feature層で受け取る要件自体が妥当かどうかを決定します。
起点となるのは、ユーザーストーリーとして表現できる要件です。「ブログの著者として、キーワードで公開済みの記事を検索したい。以前書いた内容を素早く見つけられるようにするためだ。」
この一文を書くには、三つの意思決定が必要です。誰のためか(ブログの著者であり読者ではない)、何をするか(キーワードで公開済み記事を検索する)、なぜか(過去の内容を素早く見つける)。この一文すら書けない場合、要件に対する理解がまだ十分でなく、上流に戻って明確にすべきです。Agentに実行を開始させるべきではありません。
この一文はspecの最終版ではありません。イテレーションの種です。この段階で検索ボックスの配置、結果のソート方法、空の結果の処理方法まで考える必要はありません。これらの詳細は後のイテレーションで浮かび上がってきます。
Agentによる仕様草稿の展開
ユーザーストーリーとおおよその範囲をAgentに渡し、specの草案を生成させます。
Agentがこのプロセスで行うことは、あなたの予想より多いかもしれません。一文を単により長い記述に書き換えるだけではありません。プロジェクトコンテキストを読み込み、検索機能に関連する既存のモジュールを見つけます。この要件が影響を与えるコードの範囲を分析します。受入シナリオを生成し、正常パス、境界ケース、異常ケースをカバーしようとします。あなたが考えていなかった状況、たとえば検索語に特殊文字が含まれる場合の処理を思いつくかもしれません。技術的な方針を提案することもあります。たとえばアプリケーション層のあいまい一致ではなく、PostgreSQLの全文検索を使うことを提案するかもしれません。
Ryanの/new-feature skillはこのプロセスの一つの実装です。Agentがproject contextとCLAUDE.mdをロードし、ユーザーが記述した要件に基づいてユーザー価値ポイントを分析し、Gherkin受入シナリオを生成し、featureの規模を評価します。数分以内に三つの次元をカバーするspecの草案が出力されます。
この草案にはおそらく問題があります。あなたが気にしている境界ケースが漏れているかもしれません。検索範囲の理解があなたと異なるかもしれません(あなたはタイトルのみを想定していたのに、全文検索と理解した)。影響分析から言及すべきモジュールが漏れているかもしれません。この段階でのこれらの問題は正常なことです。次のステップでそれらを露出させます。
クロスバリデーションによるドリフトの検出
Agentにspecからtask listを導出させます。このfeatureを完了するために具体的に何をすべきか、どのファイルを変更するか、どの順序で行うか。次にtask listからchecklistを導出させます。完了後に何を確認すべきか、どうなれば合格か。
前述のクロスバリデーションの原理はすでに説明しました。実際の操作では、このステップの目的はAgentの三回の理解でspecの品質を検証することです。一回目の理解がspecを出力し(要件から方針へ)、二回目の理解がtask listを出力し(方針からステップへ)、三回目の理解がchecklistを出力しました(ステップから受入基準へ)。
三つのドキュメントを比較し、矛盾を見つけます。
checklistに「検索が中国語の分かち書きに対応していることを検証する」という項目があります。しかしspecには中国語の分かち書きについてまったく言及されていません。この項目はどこから来たのでしょうか。Agentがtaskを生成する際にプロジェクトコンテキストからプロダクトに中国語ユーザーがいると判断し、自動的にこの要件を補完した可能性があります。これは合理的な補完かもしれませんし、現在のバージョンの範囲を超えているかもしれません。いずれにせよ、その存在を認識した上で、specに追加するかchecklistから削除するかを判断する必要があります。
task listに「検索のソートを再利用するために記事一覧ページのソートロジックを修正する」というステップがあります。しかしspecの制約次元には「検索関連のコードのみを変更し、一覧ページのソートには手を触れない」と書かれています。矛盾しています。Agentがステップに分解する際に、制約の範囲を超える意思決定をしました。task listのこのステップを修正する必要があります。
三つのドキュメントが一致し、矛盾がなく、予期しない新しい内容もなければ、Agentが三つの異なる角度から同じものを見ていることを意味します。
ドキュメント層での修正
クロスバリデーションで発見された問題は、specの修正すべき箇所を直接指し示します。漏れていた受入シナリオを補い、曖昧な記述を明確にし、無視されていた制約を追加します。そしてAgentに修正後のspecからtask listとchecklistを再生成させ、もう一度確認します。
このサイクルは通常一、二回で収束します。各ラウンドのコストは低く、すべてドキュメントレベルの操作です。specの数行を修正し、Agentに二つのドキュメントを再生成させ、数分で比較します。しかしこの数ラウンドのイテレーションで食い止められた問題が、もしコーディング段階で発覚していたら、修正コストは数時間から数日に及ぶ可能性がありました。
ユーザー価値に基づく分割
イテレーションが収束しないことがあります。二、三回のクロスバリデーションを実行し、一つの矛盾を修正するたびに新しい矛盾が現れます。specは修正するたびに長くなり、受入シナリオはどんどん増え、シナリオ間の依存関係はますます複雑になります。
これは通常、specの中に複数の独立したユーザー価値が含まれており、それらの相互作用のためにAgentが一つのcontextの中で同時にうまく処理できないことを意味します。
いくつかの具体的なシグナルがあります。ユーザー価値ポイントが三つを超える、受入シナリオが七つ八つを超えてシナリオ間に複雑な依存がある、影響するモジュールが四つ五つを超える。これらは厳密な基準ではありませんが、経験上有効な警告指標です。
この場合、分割が必要です。分割はイテレーションの外にある独立したフェーズではなく、イテレーションの過程で「収束しない」という状況に遭遇した際の対処方法です。
LLMは自然言語の要件に対して非常に強い理解力を持っており、タスクの分解において非常に効果的です。分割の原則を伝えるだけで十分です。ユーザー価値に沿って分割し、各サブユニットがユーザーにとって独立して受入できる機能であるようにすること。
AILock-Stepの分割は良い例を提供しています。「ユーザー認証システム」という要件を分割しなければ、specには登録、ログイン、パスワードリセット、OAuth、権限管理という五つ以上のユーザー価値ポイントが含まれることになり、一つのcontextの中でうまく処理するのは困難です。ユーザー価値に沿って分割すると、三つの独立したfeatureになります。feat-auth-register(ユーザーが登録できる。独立して提供可能)、feat-auth-login(ユーザーがログインできる。登録の完了に依存)、feat-auth-permission(ユーザーが権限を管理できる。ログインの完了に依存)。各featureには独自のユーザーストーリーと受入シナリオがあり、独立してイテレーションできます。
技術レイヤーで分割する(feat-auth-db、feat-auth-api、feat-auth-ui)と、これは実現できません。データベースのテーブルを作成しましたが、正しいかどうかはAPIとフロントエンドが完成するまでわかりません。各サブタスクには独立した受入基準がなく、その粒度でクロスバリデーションを行うことができません。
分割後、各サブfeatureのspecは同じイテレーションサイクルに入ります。Agentが展開し、クロスバリデーションし、修正し、収束するまで続けます。ここではもう一つの確認が加わります。サブspecと元の要件とのアラインメントです。元の要件にOAuthログインが言及されているのに、分割されたfeat-auth-loginのspecにはユーザー名とパスワードによるログインしか含まれていなければ、クロスバリデーションのchecklist段階でこの漏れが露出します。
仕様準備完了の基準
クロスバリデーションが矛盾を生まなくなり、三つのドキュメントが三つの角度から同じものを記述しています。specは実行フェーズに入ることができます。
これはspecが完璧であることを意味するわけではありません。あなた自身も思いつかなかった境界ケースは、どのドキュメントにも現れません。しかしこれは、spec内部が自己整合的であり、Agentの要件理解が複数の角度で一致していることを意味します。これは合理的な確信度であり、コードを書き始めることができます。
ある次元に本当に内容がない場合(たとえばこのfeatureが既存のモジュールに影響しない場合)、明示的に「なし」と書きます。空欄と「なし」は意味が異なります。空欄はその問いについて検討されていないことを意味し、Agentはそれを漏れとして処理するかもしれません。「なし」は検討した結果、該当しないという結論に達したことを意味します。
意図アラインメント:人間にしかできない判断
上記のイテレーションサイクルでは、大部分の作業はAgentが行います。specの展開、task listの生成、checklistの生成、一貫性の確認。しかし一つの工程だけは人間にしかできません。
クロスバリデーションはドキュメント間の一貫性を検査できます。specがAと言い、task listがAと言い、checklistがAと言う。三つのドキュメントは完全に一致しています。しかしクロスバリデーションはより根本的な問いに答えることができません。Aが本当にあなたが求めているものかどうかです。
ユーザーストーリーには「ユーザーが記事を検索できる」と書かれています。Agentはこれを全文検索と理解し、対応する受入シナリオとtaskを展開しました。クロスバリデーションは通過し、三つのドキュメントは完全に一致しています。しかしあなたの頭の中にあったのはタイトル検索のみでした。このずれは自動化された確認では発見されません。なぜならAgentの三ラウンドの思考はすべて同じ理解に基づいており、ただその理解があなたのものとは異なるだけだからです。
意図はあなたの頭の中にのみ存在しています。あなたはソフトウェアの最終的な利用者であるか、利用者の代理人です。「これは私が求めているものか」という判断はあなたにしかできません。なぜなら「私が何を求めているか」という情報はAgentには取得不能であり、あなたが書いたテキストから推測することしかできないからです。
そのため、イテレーションサイクルの中で人間が担わなければならない工程があります。Agentがspecを展開した後、ユーザーストーリーと主要な受入シナリオを確認することです。ここでの「確認する」は文字通りの意味です。task listを一行ずつ精査する必要はなく、checklistを一項目ずつ確認する必要もありません。確認すべきは二つだけです。ユーザーストーリーが記述する「誰が」「何を」「なぜ」があなたの頭の中の認識と一致していること、そして主要な受入シナリオがあなたが最も重視する状況をカバーしていることです。
上位層の方向が正しければ、下位層で大きな問題が起きることはまれです。Agentのクロスバリデーションが下位層の一貫性を処理します。上位層の方向が間違っていれば、下のすべてが無駄になります。だからあなたの時間は上位層の意図確認に費やすべきです。
Ryanの経験はこれを裏付けています。specイテレーションの全プロセスで彼が実際に時間を費やしたのは一箇所だけです。spec生成後のユーザーストーリーとシナリオ記述の確認です。彼はこう述べています。「一つのuser storyと数個のシナリオ記述があれば、AIと自分の理解が一致しているかを判断できる。」その後のtask分割、checklist生成、コード実装には、ほとんど逐一介入しません。
Agentが得意とするのは別の種類の検査です。ドキュメント間の一貫性チェックです。specでは検索結果を関連度順にソートすると書かれているのに、checklistでは時間順にソートすることを検証すると書かれている。これは矛盾です。specでは五つの受入シナリオが挙げられているのに、task listは三つしかカバーしていない。これは漏れです。specでは「記事」という語を使っているのに、task listでは「投稿」と書かれている箇所がある。これは用語の不一致です。これらの検査には意図が何かを知る必要はなく、ドキュメント間の構造が整合しているかを比較するだけです。Agentはすべてのドキュメントの完全な内容を同時に処理でき、この種の検査では人間よりはるかに信頼性が高いです。
イテレーションサイクル全体における分担はこのようになります。Agentは展開、生成、一貫性チェックを担当します(これらは構造的で自動化可能な作業です)。人間は意図アラインメントの判断を担当します(これは意味的で、意図の所有者にしかできない作業です)。
イテレーション深度をやり直しコストに合わせる
前述のイテレーションサイクルには完全な形態があります。意図を書き、Agentが展開し、クロスバリデーションし、修正または分割し、人間がユーザーストーリーをレビューし、収束するまで再検証します。しかしすべてのタスクがサイクル全体を回す価値があるわけではありません。
人間の注意力はプロセス全体で最も希少なリソースです。Agentがクロスバリデーション、一貫性チェック、task listやchecklistの生成を行う部分は、あなたの時間をほとんど消費しません。しかしユーザーストーリーのレビュー、意図の一致の判断、specの修正要否の決定には、あなたの集中力が必要です。Agentの部分は自動的に実行できますが、人間の部分はできません。
どのタスクにこの集中力を投入する価値があるのか。やり直しのコストを見ます。
ボタンのテキストを変更する場合、間違えてもやり直しは一分で済みます。このタスクのために完全なspecを書いてユーザーストーリーをレビューするのは割に合いません。Agentに何を変更するかを伝え、一つの制約(他の部分は触らないこと)を加えて、Agentにクロスバリデーションで自己チェックさせれば十分です。クロスバリデーション自体を省略してもかまいません。間違えてもやり直しのコストはごくわずかだからです。
三つのモジュールにまたがる新しいfeatureの場合、間違えると一日分の作業が無駄になる可能性があります。十分かけてユーザーストーリーと主要な受入シナリオをレビューし、方向が正しいことを確認してからAgentにコーディングを開始させる価値があります。
五つ以上のモジュールにまたがる大きな要件の場合、間違えると一週間が無駄になる可能性があります。まず分割し、各サブfeatureのspecを丁寧にレビューし、それぞれ完全なクロスバリデーションサイクルを回す価値があります。
判断基準はコードの量ではなく、間違えた場合の痛みの大きさです。二行のコード変更だけでも決済フローに影響するタスクであれば、管理画面のスタイルを百行変更するタスクよりやり直しコストが一桁高い可能性があります。前者はspecを丁寧にレビューする価値があり、後者は一言伝えるだけで十分かもしれません。
同じイテレーションサイクルを非常に軽く回すことも、非常に重く回すこともできます。最も軽い場合、一文の意図と一つの制約を書き、Agentが自ら展開と自己チェックを行い、あなたはレビューせず直接実行します。最も重い場合、意図を書き、Agentが展開し、あなたが各受入シナリオを深くレビューし、複数のサブfeatureに分割し、それぞれ個別にイテレーションし、それぞれレビューします。これらは二つの異なるプロセスではなく、同じサイクルが異なるリスクレベルで異なる動作をしているだけです。サイクル自体は変わりません。変わるのは、人間がどの工程に介入し、どの程度深く介入するかです。