はじめに
完了条件による自走(/goal)、コンテキストエンジニアリング、エージェントのオーケストレーション、仕様駆動開発。AI駆動開発の手法を追いかけてきて思うのは、どれもテストが揃っているほどよく機能する、ということです。
なぜそうなるのかを、仕様書の維持コストの話から整理してみました。結論は「テストを書け」という古い話です。ツールの紹介はしません。TDDのようにテストを書く過程そのものが設計を駆動する効果も、この記事ではスコープ外です。
仕様書を最新に保つのは、無理では
出発点はこの素朴な疑問でした。
実装は進み続けるのに、ドキュメントを100%追従させ続けるのは現実的に難しい。気づけば半年前の設計のまま取り残される。そして厄介なことに、ドキュメントは腐っていても、見た目では分からない。読み手がそれを信じる場合、古い仕様書は「ない」より悪い。
なぜこうなるのか。仕様書とコードの同期は、強制されない限り確率的にしか起きないからです。人間がやっても漏れるし、AIにドキュメント更新を任せても、やるときとやらないときがある。運用ルールやレビューの頑張りで確率を上げることはできても、1にはならない。そして一度でも同期が漏れた瞬間、その文書は「正しいかどうか読み手には判別できない文書」に格下げされます。
これは根性の問題ではなく構造の問題なので、構造で解くしかありません。
CIが同期を強制するものだけが、仕様の正でいられる
答えはシンプルで、実コードとの同期が機械的に強制される成果物だけを、現行仕様の正として扱う。それ以外の文書は、どれだけ立派でも「生成日時つきのスナップショット」として扱う。
境界線は文書の媒体ではなく、同期の強制力で引きます。テストは腐りません。正確に言うと、腐った瞬間にCIが赤くなるので、腐ったまま放置されることが構造的にできない。散文の仕様書にはこの性質がない。それだけの違いですが、この違いがすべてです。
別の言い方をすると、テストには間違いが蓄積できない。振り返ってみると、テストが間違っていて困った経験は仕様書が古くて困った経験よりもはるかに少ないです。テストの書き手が優秀だからではなく、間違ったテストは書いた瞬間に赤くなり、その場で直されるか捨てられるからです。資産として生き残った時点で、実装との突き合わせを一度は通過している。散文の仕様書にはこの淘汰圧がかからないので、間違いが何年でも生存します。「テストは正しい」からではなく、間違いが留まれない構造だから正でいられる、という順番です。
ただしテストの側にも弱点はあって、それは間違いではなく空虚化として現れます。モックが厚すぎて実質何も検証していないテスト、実装をなぞっただけのテスト、assertが緩くて緑になるだけのテスト。間違ってはいないけれど、本来守りたかった振る舞いを検証していない。テストの品質問題は正誤ではなく検証力の問題として出る、と押さえておくと後述の肥大化の話と繋がります。
「じゃあ仕様の最新化を諦めるのか」と言われそうですが、逆です。最新化のコストを払う対象を、機械が同期を検証できるものに限定する、という話です。散文で網羅的な「生きているべき文書」だけを持たない。
では、コードが仕様の正か
ここで一つ反論が立ちます。同期が強制されるものが正なら、コードそのものが最有力では?コードは自分自身と常に同期しているし、迷ったらコードを読めばいい、と。
実際、私の経験もこの反論を半分だけ支持しています。既存システムを調べるときは、まずドキュメントが正しいかの確認から始まり、結局ソースを読むことになる。ただ、ソースを読んでも終わりませんでした。挙動として正しいのは分かる。でもそれが意図された仕様なのかは、コードのどこにも書いていない。結局gitのログやPR、Slackの過去ログやNotion等を漁って、当時の判断を発掘することになります。
つまり半分正しくて、半分違う。コードから読み取れるのは「どう振る舞っているか(does)」であって、「どう振る舞うべきか(should)」ではない。両者が一致している保証はどこにもなくて、一致していない部分にはすでに名前がついています。バグです。コードだけを仕様の正とすると、動いている挙動がすべて正しい仕様になってしまい、バグと仕様の区別が原理的につかなくなる。
つまりコードは「最後の砦としての仕様」ではあるけれど、shouldを語れない以上、単独では仕様の正になれません。shouldはコードから独立に持つ必要があります。そしてshouldを、CIで検証可能な形式で表現したものがテストです。前節の基準(同期の強制)とこの節の区別(does/should)の交点に、テストがちょうど収まります。
生き残る3点セット
では、何を資産として持つのか。3つに整理してみました。
どう振る舞うべきか
受け入れ基準、E2E、本体のテスト、スキーマ。先ほどのshouldを担う資産で、外から観測可能な挙動の定義です。コードの従属物ではなく、独立した資産として扱います。
なぜそうしたか/しなかったか
いわゆるADR、意思決定の記録です。これが散文でも腐らないのは、時点が固定されているから。「2026年7月、この制約下でこう決めた」は、後からコードが変わっても嘘になりません。更新するのではなく追記していく文書です。
そして見落とされがちなのが「しなかったか」の側。意図的に対応しなかった範囲、切り捨てたエッジケース、やらないと決めた要求。これはコードにもテストにも痕跡が残らないのに、引き継ぎや問い合わせでよく聞かれる類のものです。「これはバグですか?」という問い合わせには、やらない決定が記録されていないことから生まれるものが少なくない、という実感があります。書かれないのは当然で、作った機能は形が残るけど、作らなかった機能は決めた瞬間にしか存在しないからです。だから意識的に書くしかない。
ユビキタス言語
このシステム独自の言葉の定義。DDD由来の概念ですが、AI時代に用途が一段格上げされたと感じています。エヴァンスの時代はチーム内の認識合わせの道具だったものが、今はコンテキストを共有しない実装者への入力になった。ドメイン語彙はコードからもテストからも復元しにくいのに、変化は遅く、寿命はシステムより長い。リプレースしても生き残ります。だから例外的に、手で保守する価値のある散文です。
まとめると、手で保守する永続文書はADRとユビキタス言語だけ。挙動の正はテストに任せ、FAQや影響範囲調査みたいな派生情報は、保存せずに、テスト・ADR・ユビキタス言語からAIにその都度作らせる。挙動の質問はテストから、「なぜ」や「これはバグ?」はADRから引けます。その都度作り直すものは、古くなりようがありません。
なお、実装前に開発者/AIと合意するスコープ単位の実装指示、いわば「瞬間の仕様書」は普通に書きます。ただしそれはマージされたらテストや受け入れ基準に吸収されて役目を終える使い捨ての中間生成物で、永続的な保守対象にはしない。
なぜ「解釈する他者」の話なのか
ここまでの話は、実は読み手を選びません。仕様を渡す相手がAIでも、協力会社でも、隣のチームでも、3ヶ月後の自分でも成立します。共通点は、書き手とコンテキストを共有していないこと。
散文の仕様書は、書き手が思っているよりずっと広い解釈の余地を持って相手に届きます。コンテキストを共有していない相手ほど、その余地は広がる。不具合の多くは能力の問題ではなく、この解釈の自由度から生まれてしまうと思っています。
テスト、とりわけ受け入れ基準としてのテストが強いのは、品質保証の道具である以前に契約言語だからです。「この受け入れ基準が緑なら合意」には解釈の余地がほぼない。しかも相手は実装前に自分で実行して答え合わせができる。齟齬が受け入れ段階ではなく実装段階で解消される。AIエージェントに/goalで「テストが全部通るまで」と渡すのも、構造としては同じことをしています。検証可能な完了条件とは、機械に対する契約です。
AI駆動開発の各種手法を剥いでいくと、ほぼすべてが「解釈する他者に、解釈余地のない形で意図を渡す」という同じ一点に行き着きました。
なお、この話が一番効くのは、書き手と実装者の間のコンテキスト共有が薄い状況です。組織や契約の境界を仕様がまたぐ場合や、実装者が頻繁に入れ替わる場合。逆に、同じ文脈に浸かった少人数チームなら、散文と会話で回る場面も多いはずで、そこに都度この体制を持ち込むのは過剰だとも思います。それでも、ADRとテストだけは残しておいて損がありません。今日のチームの共有文脈は、メンバーの入れ替わりと時間経過で必ず薄まっていくからです。
ただし、ゼロになったのは生成コストだけ
「じゃあテストをAIで量産だ」となりそうなところに、一つ留保を置きます。
AIで変わった経済性は生成コストだけです。実行コストと維持コストは変わっていない。むしろ量産によって悪化する側です。テストは一度書かれると消えにくく、コード量に比例して増え、いつか実行時間の壁に当たる。粒度の大きいテストほどこの壁は近い(単体テストとE2Eでは、1件あたりの実行時間が2桁違うという計測もあります)。この観点は自動テストの肥大化とどう向き合うかという記事が丁寧に整理していて、ここまでの結論に効いてくる指摘です。
なので「テストを書け」は「無限に書け」ではありません。増え続けるテストの管理とセットです。
- 契約層(受け入れ基準)は薄く保つ。契約の価値は本数に比例しない。ジャーニー単位の少数精鋭でよくて、細部の検証はより小さく安いテストサイズへ委譲する
- 増やす仕組みには、間引く仕組みを対にする。同じバグしか検知できないテストが何本あっても安心は増えない。重複候補の検出はそれこそAIが得意な仕事
- 網羅性は「証明するもの」ではなく「どこを網羅していないか言える状態を保つもの」と割り切る。全数テストはそもそも不可能なので
生成のコストが桁で下がった今、書く判断より書かない判断と消す判断のほうが人間の仕事として残る、とも言えます。
まとめ
振り返ってみて、自分なりに得た整理はこうです。新しい手法はどれも、根元をたどると検証可能な資産、つまりテストに寄りかかっていました。
結論は「テストを書け」。20年前と同じです。変わったのは2点だけ。一つは経済性で、仕様からテストへの翻訳コストがほぼゼロになり、「わかっているけど割に合わない」という言い訳が消えました。もう一つは用途で、テストが品質保証の道具から、コンテキストを共有しない実装者、つまりAIや他チームや未来の自分への契約言語に格上げされました。
書くべき理由が増えて、書かない理由が減った。残っている仕事は、どう振る舞うべきか・なぜそうしたか/しなかったか・ユビキタス言語の3つを資産として育てること、そして増え続けるテストを管理すること。ひとまず個人としては、ここを現実解に置きつつ実務に取り組んでいきます。