要件定義の技術 — 「言われた通り」が失敗する理由
依頼者の言葉をそのまま実装すると、なぜ動くのに使われないものができるのか。顕在要求と潜在要求、ユースケース、非機能要件の数値化、そして曖昧さをその場で炙り出す質問の型を、前提知識ゼロから解説します。
要点
- 依頼者が口にするのは解決策であって、目的ではないため、目的まで降りて検証できる形に書き直すのが要件定義である。
- 要求は顕在要求・潜在要求・暗黙の前提の3層に分かれ、事故になるのは誰も言わなかった暗黙の層である。
- 要件の良し悪しを測る基準は、読んだ人が全員同じテストを書けるかどうかである。
- A = 0.999 で T を30日(43,200分)とすれば、許される停止時間 D は43.2分になる。
- 平均200ミリ秒でも100人に1人が5秒待たされるため、応答時間は平均ではなくパーセンタイルで書く。
4分の1インチのドリルと、4分の1インチの穴
マーケティングの古典に「人はドリルが欲しいのではない、穴が欲しいのだ」という言い回しがあります。依頼者が口にするのは道具の名前で、本当に必要なのは結果のほうだ、という話です。
ソフトウェアの現場でも同じことが起きます。「CSVでダウンロードできるボタンを付けてほしい」と言われて、その通りボタンを付ける。動くものは納品され、検収も通る。ところが半年後、その機能はほとんど使われていません。改めて聞くと、依頼者がやりたかったのは「月末に経理へ数字を渡すこと」で、CSVは相談の時点で思いついた唯一の手段だっただけでした。本当に効いたのは会計システムへ自動で送る仕組みだったかもしれません。
「言われた通りに作りました」は、失敗の弁明としては最も通りやすく、最も何も救わない言葉です。要件定義とは、依頼者の言葉を鵜呑みにも無視にもせず、その裏にある目的まで降りたうえで、検証できる形に書き直す作業のことです。書き直した結果が元の言葉と同じになることもありますが、確かめたうえで同じなのと確かめずに同じなのとでは、後で起きることがまったく違います。
要求は3階建てになっている
依頼者の頭の中にあるものは、口に出される順に並んでいるわけではありません。おおまかに3つの層に分かれています。
顕在要求は、依頼者が自分で言葉にできるものです。「CSVを出したい」「ログイン画面が欲しい」。これは聞けば出てきます。ただし出てきた時点ですでに、依頼者なりの解決策の形をしています。
潜在要求は、あれば喜ぶのに自分からは言えないものです。理由は単純で、そういうものが作れると知らないからです。「毎月20分かけて手で転記している」という事実は、聞き方さえ変えれば出てきます。しかし「その転記を自動化してほしい」という要求の形では、まず出てきません。人は自分が知っている選択肢の中でしか要求を組み立てられないからです。
暗黙の前提は、当たり前すぎて言葉にする価値がないと思われているものです。「金額がずれない」「他人の給与が見えない」「保存を押したら保存される」。満たしても誰も褒めませんが、破ると一発で信用を失います。品質工学の狩野モデルはこの非対称性を、当たり前品質(あって当然、無いと不満)と魅力的品質(無くても不満ではないが、あると嬉しい)に分けて説明しています。要件定義で事故になるのは前者で、誰も言わなかったせいで誰も実装せず、リリース後に「そんなの当たり前でしょう」と言われる層です。
顕在要求だけを丁寧に拾って作ると何が起きるか。聞き取れた事例に対しては完璧に動き、聞き取れなかった事例で急に崩れるシステムができます。これは機械学習の過学習とよく似た形をしています。
「要求」と「要件」は別の言葉
日本語だと1文字違いで紛らわしいのですが、この2つは工程が違います。要件工学の国際規格 ISO/IEC/IEEE 29148 は、利害関係者の要求(stakeholder requirements)とシステム要件(system requirements)を明確に別の成果物として扱っています。
- 要求: 依頼者・利用者・運用者が「こうなってほしい」と考えていること。主語は人。
- 要件: そのためにシステムが満たさなければならない条件。主語はシステムで、満たしたかどうかを判定できる。
「経理への転記をなくしたい」は要求です。「システムは、締め日の翌営業日09:00までに、当月分の仕訳データを会計システムのAPIへ送信しなければならない」は要件です。後者は、満たしたかどうかを人によらず判定できます。要件の良し悪しを測る基準はここに尽きます — 読んだ人が全員同じテストを書けるか。
ユースケース: 主語を人に戻す
機能を箇条書きにすると、いつのまにか主語がシステムだけになり、「誰が、何のために、どういう順序で」が抜け落ちます。ユースケースは、それを人の側から書き直す形式です。最低限、次の要素があれば形になります。
- アクター: 誰が。「経理担当者」であって「ユーザー」ではない
- 事前条件: 始まる前に成立していること。「当月の売上が確定している」
- 主シナリオ: うまくいったときの手順を番号付きで。5〜9行に収める
- 代替フロー: 途中で分岐する道。「APIがタイムアウトした場合」
- 事後条件: 終わったときに成立していること。「会計システムに当月分の仕訳が1件以上存在する」
価値の大半は代替フローと事後条件にあります。主シナリオは誰が書いてもだいたい同じものになりますが、代替フローを書こうとすると「そこで失敗したらどうするんですか」という問いが必ず発生し、それが未定義であることがその場で露見します。事後条件は、検収のときに何を見れば合格と言えるかを先に決める作業です。
非機能要件: 「速い」「安全」を数字にする
機能要件が「何ができるか」なら、非機能要件は「どのくらいの品質でできるか」です。ISO/IEC 25010 は、性能効率性・信頼性・セキュリティ・保守性・使用性などの品質特性としてこれを整理しています。厄介なのは、非機能要件が設計を後戻りできない形で縛ることです。機能はあとから足せますが、「1秒以内」「無停止で更新できる」は、アーキテクチャを決めたあとで足すのが極端に高くつきます。
可用性。「落ちないシステムにしてください」は要件になりません。可用性の目標値を決めると、許される停止時間が自動的に決まります。
は許される停止時間、 は可用性の目標(0〜1の割合)、 は対象期間の長さです。つまり「達成できなかった分を、期間に掛け算する」だけの式です。(いわゆるスリーナイン)で を30日(43,200分)とすれば、 は43.2分になります。月に43分は止まってよい、という合意です。ここまで具体化して初めて、「では計画メンテナンスはその43分に含むのか」「深夜の停止も同じ扱いか」という、本当に決めるべき論点が出てきます。
応答時間。ここでの落とし穴は平均値です。平均200ミリ秒でも、100人に1人が5秒待たされていれば、その1人にとっては壊れています。だから普通はパーセンタイルで書きます。p99が300ミリ秒、とは「遅いほうから1%を除いた全部が300ミリ秒以内」という意味です。
1つの画面が裏で複数のサービスを呼ぶ構成では、これが効いてきます。1回の呼び出しが期限内に返る確率を 、1リクエストあたりの呼び出し回数を とすると、全部が期限内に返る確率は次のようになります。
は「1リクエストが丸ごと期限内に終わる確率」です。つまり、速い確率を呼び出し回数だけ掛け算すると全体の確率になる、と言っているだけの式です。各呼び出しの遅さが互いに無関係(独立)だと仮定した場合の値で、実際には共通のDBが詰まるなどして連動するため、これは楽観的な見積もりになります。それでも 、 を入れると 。個々のサービスが「99%は速い」を守っていても、画面全体では3回に2回が遅いという結果になります。「各コンポーネントのp99を決めれば全体も守られる」という直感は、この掛け算の前では成立しません。非機能要件は部品ごとではなく、利用者が体験する単位で先に決める必要があります。
こうした数値目標をリリース後に本当に守れているか観測する話は可観測性 — ログ・メトリクス・トレースの実務で扱っています。
曖昧さを検出する質問の型
要件定義でいちばん実務的な技術は、曖昧な文を見た瞬間に、決まった形の質問を返せることです。才能ではなく型で、覚えれば誰でも使えます。危険な言葉には種類があり、それぞれ隠しているものが決まっています。
| 危険な言葉 | 何が隠れているか | 返す質問 |
|---|---|---|
| すべて / 常に / 必ず | 例外の存在 | 例外は本当に0件ですか。1件でもあるなら、そのとき何が起きますか |
| 速く / 軽く / 使いやすく | 比較対象と基準の欠落 | 何と比べて速くですか。どの操作が、どの回線で、何秒以内なら合格ですか |
| 〜される(受動態) | 主語の消失 | 誰が実行しますか。失敗したとき誰が気づきますか |
| ユーザー / データ / 適切に | 用語が未定義 | 未ログインの人は含みますか。退会済みは。管理者は |
| 〜など / 〜等 | 打ち切られた列挙 | 「など」の中身を3つ挙げてください。それで全部ですか |
| 連携する / 自動で | 動作の未定義 | 何秒以内にですか。失敗したら再送しますか、諦めますか |
| 〜したい | 手段と目的の混同 | それができると、何がどう良くなりますか |
型はもう3つあります。1つ目は否定形で聞くこと。「どうなれば成功ですか」より「何が起きたら失敗ですか」のほうが具体的な答えが返ります。人は望ましい状態を漠然としか語れませんが、避けたい事故は鮮明に語れるからです。
2つ目は捨てさせる質問です。「速さと正確さ、両方は無理ならどちらを捨てますか」。合意が壊れるのはたいてい両立不能なものを両方合意したときで、この問いはそれを設計前に露出させます。答えが「両方必要です」なら、それは決定権者が別にいるという情報です。
3つ目は具体例を1件書かせること。抽象的な要求は無限に解釈できますが、実例は1つしかありません。実例を3つ集めると、2つ目か3つ目で「あ、これは例外扱いなんですけど」という言葉が出ます。その例外こそが、聞かなければ永久に出てこなかった要件です。
場合分けは足し算ではなく掛け算で増える
要件が積み上がるとき、実装とテストの量は要件の数に比例しません。掛け算で増えます。条件の種類を 個、 番目の条件が取りうる値の集合を とすると、組み合わせの総数は次のとおりです。
は 番目の条件が取りうる値の個数、 はそれを全部掛け合わせるという記号です。言い換えると、条件を1つ足すのは1行足すことではなく、既存の場合分けを丸ごと何倍かすることです。会員種別4種 × 決済手段5種 × 国3種 × 端末3種で 。ここに「初回か否か」という真偽値を1つ足すだけで360になります。真偽の条件を 個並べれば です。
だから要件定義では、条件を増やす前に消すほうが効きます。「この分岐は本当に業務として存在しますか、それとも念のためですか」。念のための分岐は、テストされないまま残り、数年後に誰も意味を説明できない仕様になります。全部の組み合わせを試せないとき、2つの条件の全ペアだけを網羅する「ペアワイズ法」のような割り切りもありますが、そもそもの を減らすほうが常に安上がりです。
検収条件を、実行できる形にする
要件が数値になったら、判定はコードにできます。「速くしてほしい」を実行可能な述語に落とすと、こうなります。
def meets_slo(latencies_ms, p=0.99, budget_ms=300):
"""観測した応答時間の列が、p分位の目標を満たすか"""
xs = sorted(latencies_ms)
idx = int(p * (len(xs) - 1)) # p分位の位置
return xs[idx] <= budget_ms # p99が300ms以内か
10行にも満たない関数ですが、これが書けるかどうかが要件の質の判定になります。書けないなら、まだ要件ではありません。同じことを日本語でやるのが Given-When-Then 形式の受入基準です。「前提として当月の売上が確定していて、もし締め処理を実行したら、そのとき会計システムに当月分の仕訳が存在する」。前提・操作・観測される結果の3点が揃っているので、そのままテストの骨組みになります。
決めないことを、決める
要件定義書に書くべきものの半分は「やらないこと」です。非目標は、今回やらないと明示的に宣言したもの。書かないと、書いていないというだけで「当然やる」と解釈されます。前提は、正しいと仮定して進めるが検証していないことです。「取引先は全社がAPIに対応している」。書き出しておけば、崩れた瞬間に何を見直せばいいかが分かります。未決定事項は、決まっていないことと、いつ誰が決めるかをセットで書きます。空欄で放置すると実装者が善意で埋め、その判断が誰にも共有されないまま仕様になります。
現場ではこう使う
誰が、いつ。プロダクトマネージャーが新機能の起案時に、テックリードが設計に入る前に、SREが本番の性能目標を切るときに、QAがテスト設計の入口で使います。受託開発なら見積もりの前が本番で、曖昧な要件のまま出した見積もりはほぼ確実に外れます。
実際に触るもの。ユースケース記述とGiven-When-Then形式の受入基準、SLO(サービスレベル目標)とエラーバジェット、ISO/IEC 25010 の品質特性を並べた非機能要件チェックリスト、意思決定を1件1ファイルで残す ADR(Architecture Decision Record)、要件とテストの対応を並べるトレーサビリティ行列。ツールなら Jira / Linear の課題テンプレート、Confluence や Notion の仕様ページ、Cucumber や pytest-bdd のように受入基準をそのまま実行できるフレームワークが典型です。
知らないと事故になる落とし穴。
- 非機能を後回しにする。「性能は後で測る」で進め、アーキテクチャ確定後に「p99 300ms」が降ってくると作り直しになります。非機能は最初のスプリントで数字にする。
- 平均値でSLOを切る。平均は最も不幸な利用者を隠します。必ずパーセンタイルで。
- 合意の証拠が議事録にしかない。「言った/言わない」は必ず起きます。要件は成果物として版管理し、変更を差分で追える場所に置く。
- 曖昧語のまま見積もる。「連携する」を工数に換算した瞬間、その見積もりは何の約束でもなくなります。曖昧語が残る項目は、見積もりではなく調査タスクとして切る。
- 要件を凍結して変更を悪とする。学んだ結果として要件が変わるのは正常です。禁じるべきは変更そのものではなく、影響範囲を評価せずに変更を差し込むことです。
設計レビューで問われる形。「この要件のどこが曖昧か、3つ挙げてください」はよく出ます。答えの筋道は上の表そのままで、比較対象のない形容詞、主語の消えた受動態、未定義の名詞を順に指摘すればよい。もう1つの定番は「非機能要件を3つ挙げて、測定方法まで言ってください」。可用性なら停止時間の定義と計測点、応答時間ならパーセンタイルと計測位置(クライアント側かサーバ側か)、セキュリティなら「何を守るか」と脅威モデルまで降りられると、要件として成立します。
機械学習を含むシステムでは、この非機能要件に「精度をどう定義するか」が加わり、扱いがさらに難しくなります。その設計はMLシステム設計 — モデルの外側の9割で、変更が本当に効いたかを数字で判定する方法は統計的検定とABテスト — p値の使い方と誤用で扱っています。
まとめ
- 依頼者が口にするのは解決策であって目的ではない。目的まで降りてから、検証できる形に書き直す
- 要求は顕在・潜在・暗黙の3層。事故の多くは、誰も言わなかった暗黙の層で起きる
- 要件の唯一の合格基準は「読んだ全員が同じテストを書けるか」
- 非機能要件は数値とパーセンタイルで。可用性は停止時間に、応答時間は利用者が体験する単位に翻訳する
- 曖昧さの検出は才能ではなく型。危険な言葉ごとに返す質問を決めておく
- 条件は掛け算で増える。増やす判断より、消す判断のほうが安い
コメント
コメントにはログインが必要です