【ITニュース解説】TDD for Requirements
2026年09月24日に「Dev.to」が公開したITニュース「TDD for Requirements」について初心者にもわかりやすく解説しています。
ITニュース概要
システム開発では「何をすべきか」を、要件、契約、仕様、性能など各段階で「チェックできる条件」として先に定義する。これにより、具体的な成果物の形が決まり、手戻りを減らして、効率的で高品質な開発を実現できる。
ITニュース解説
システム開発では、何か新しい機能を作ったり、既存のシステムを改善したりする際、漠然とした「こうなってほしい」という「願い」からスタートする。この願いを具体的な「要件」に落とし込み、さらに「契約(外部との取り決め)」や「仕様(具体的な設計)」へと段階的に進めていくのが一般的なプロセスだ。この一連の流れの中で、それぞれのステップで「これができた」と判断するための客観的な基準、つまり「チェック可能な条件」を最初に明確に定義することの重要性について解説する。これは、テスト駆動開発(TDD)という考え方を、コードを書く手前の、より上位の段階に適用するアプローチと捉えられる。
テスト駆動開発では、まずコードが正しく動作するための「テスト」を書き、そのテストが通るように「コード」を書く。この「テストを先に書く」という考え方を、コードレベルだけでなく、システム開発全体のプロセス、つまり要件定義や設計の段階にまで拡張するのだ。
なぜ「チェック可能な条件」を先に書くことが重要なのか。もし条件を後から書くと、それは既に出来上がったものに対する「説明」になってしまう。例えば、「速く動くシステム」という願いがあり、システムが完成した後に「このシステムは速く動く」と条件を設定しても、それは単に完成品を肯定しているだけで、本当に「速い」かどうかを客観的に判断する基準にはならない。一方、最初に「1秒間に1000件のリクエストを200ミリ秒以内で処理する」といった具体的な条件を定めていれば、その条件が満たされたかどうかを誰でも客観的に確認できる。つまり、最初に条件を書くことは、目指すべきゴールを明確にし、そのゴールに向かって作業を進めるための羅針盤となるのだ。そして、この条件こそが、各段階で「合格」と判断するための「ゲート(門)」の役割を果たす。
具体的な例で考えてみよう。「コードカバレッジ(テストによって実行されるコードの割合)を落とさない」という目標があったとする。これは良い意図だが、チェック可能な条件ではないため、誰かが実際にコードカバレッジを下げてしまっても、それが意図的かどうか、許容されるかどうかを判断する具体的な基準がない。そこで、「コードカバレッジの現在の最低値を記録し、新しい変更でこの値が下がった場合は自動的に拒否する」という「ラチェット」のような仕組みを作る。この条件は「記録された値が下がるか否か」という形で明確にチェックできる。ただし、この例では、カバレッジの実際の値が86.7%あっても、記録された閾値が0のままであれば、「カバレッジが0を下回らない」という条件は満たし続けてしまう。これは、条件が「方向性(下がらないこと)」を保証するが、「レベル(86.7%以上を維持すること)」までは保証しないという限界を示している。それでも、チェック可能であるという点で、漠然とした意図よりは進歩がある。
別の例として、データベースからデータを読み込む複数の方法が混在している状況を改善する場合を考えてみよう。最終的に「データを読み込む方法は、特定のパッケージに一つだけ存在する」という目標があったとする。この「最終的な状態」を明確な条件として、修正作業を始める前に定義しておく。そうすることで、修正の途中の段階でも、その条件に近づいているか、逸脱していないかを常に確認できる。最後の修正が終わった時点で、「これで終わりか?」と主観的に判断する必要はなく、事前に定義した条件を満たしているかどうかで客観的に判断できるのだ。
さらに、パフォーマンスに関する条件も同様だ。「もっと速くする」という漠然とした願いではなく、「現在の処理時間はAミリ秒だが、これをBミリ秒に改善する」という具体的な目標を立てる。この場合、改善作業を始める前に、現在のシステムの処理速度(ベースライン)を正確に測定し、その数値を固定しておく。改善後のシステムはこのベースラインと比較され、客観的にパフォーマンスが向上したかどうかを判断する。この「ベースラインの測定」は、改善作業そのものとは別の「事前の作業」であり、手間がかかるように感じるかもしれないが、改善の効果を議論の余地なく示すためには不可欠なステップとなる。
このような「チェック可能な条件を先に書く」という考え方は、テスト駆動開発(TDD)や受け入れ基準(Given / When / Thenのような形式で、顧客と開発者が合意する条件)、非機能要件(システムの性能、セキュリティ、信頼性などの要件)の定義など、既存のさまざまな手法にも通じるものがある。
具体的に、要件から実装までの「4つのレベル」で、条件がどのような形をとるべきかを見ていこう。
- 要件(Requirement): 「速く動く」といった形容詞的な表現ではなく、「N個のエンティティを持つページのリストをMミリ秒以内に返す」のように、1つのコマンドで実行可能、または1つの数値で確認できる形にする。これにより、誰が見ても同じように「要件が満たされたか」を判断できるようになる。
- 契約(Contract): プログラムが外部サービスなどとやり取りする際の「取り決め」のことだ。具体的なデータ項目を決める前に、「成功」「拒否」「競合」「データなし」「ページ境界」といった、起こりうる「ケースのリスト」を先に書き出す。これにより、どのような情報をやり取りする必要があるか、どのようなエラーがあり得るかなど、メッセージの形が自然と決まってくる。
- 仕様(Spec): 特定の機能やモジュールがどのように動作すべきかを詳細に記述したものだ。このレベルでは、その仕様が正しく実装されたことを示す「受け入れコマンド」を、具体的な値がすべて埋め込まれた形で記述する。そして、そのコマンドが、他の部分の影響を受けずに、その仕様が対象とする範囲だけで実行できることが重要だ。これにより、仕様が満たされたかどうかを客観的に判断できる。
- パフォーマンス(Performance): 前述のように、古いバージョンのシステムから取得した「ベースライン測定値」を条件とする。このベースラインは固定された定数としてテストに含められ、新しいバージョンの結果と比較される。
これら4つのレベルすべてにおいて、条件は実装が存在する前に書かれる。そして、それぞれの条件が、次に続く作業の形や方向性を決定する役割を果たす。例えば、契約のケースリストは、どのようなデータ項目が必要かを決め、仕様の受け入れコマンドは、その機能の範囲を決定し、パフォーマンスのベースラインは、何をもって改善とするかの基準を確立する。
なぜこの順番が重要かというと、最初に書かれた条件は、作業に対する単なるチェックではなく、まだ存在しない成果物の「形を記述し、選び取る」役割を果たすからだ。後から条件を書くと、それは出来上がったものに合わせた記述になりがちで、客観的な判断基準としての力を失ってしまう。客観的な条件が最初に存在することで、意見や主観ではなく、データに基づいて「できた/できていない」を判断できるようになる。
もちろん、このアプローチにはコストも伴う。まず、条件を最初に記述するのは見た目以上に難しい。たった一文の条件を考えるのに何十分もかかることもあるし、パフォーマンスのベースライン測定のように、本作業とは別の追加作業も発生する。また、「カバレッジが0のままのラチェット」の例のように、条件が技術的には満たされていても、実質的な価値が低い場合もある。チェックが緑色であっても、それが本当に望ましい状態を意味しているとは限らないのだ。
このアプローチが常に最適であるとは限らない場面もある。例えば、まだ誰も何を作るべきか分からない「研究段階」の作業では、具体的な条件を定めることは難しい。また、「もっと使いやすくする」といった抽象的な目標で、明確な基準がない場合や、コードの変更がごくわずかで、条件を書く手間が変更そのものより大きくなるような「一回限りの小さな修正」の場合も、厳密な条件定義を省略することがある。
しかし、チェック可能な条件が最初に存在し、それが1つのコマンドで実行できる形であれば、人による確認と自動化された実行が全く同じ基準で行える。漠然とした「完了の定義」や「レビュアーの主観的な判断」では、確認する人によって判断がブレたり、作業が多ければ多いほど一貫性が失われたりする。開発のスピードが上がれば上がるほど、条件が明確でないことの弊害は大きくなる。条件が不正確であれば、その不正確な部分が、あっという間に何度も繰り返されてしまうからだ。
この「チェック可能な条件を先に書く」という考え方は、システム開発において、主観を排し、客観的で一貫性のある意思決定を可能にするための強力な手段となるのだ。