上流工程を1から — 要件定義で勝負がつく理由
要件定義→基本設計→詳細設計という流れは、なぜこの順番なのか。間違いを見つけるのが遅れるほど直す費用が指数的に膨らむ「分岐の掛け算」の構造を、比喩・式・動く図・コードで前提知識ゼロから解きほぐします。
比喩: 基礎の寸法を1cm間違えた家
家を建てるとします。設計図の段階で柱の位置を1本ずらすのは、消しゴムと10分の仕事です。基礎のコンクリートを打った後で同じことをするなら、はつって打ち直しになります。内装が終わって家具が入った後なら、住人に引っ越してもらうところから始めなければなりません。
間違いそのものは同じ大きさなのに、直す費用だけが後になるほど跳ね上がる。 ソフトウェア開発で「上流工程が大事」と言われるのは、精神論ではなくこの構造の話です。上流とは、川の流れでいう水源に近い側、つまり何を作るかを決める側を指します。下流は、それを実際に組み立てる側です。
上流工程とは、何を決める場所か
日本の業務システム開発では、上流を大きく3段に分けます。呼び名は現場によって揺れますが、決めている内容はどこでもほぼ同じです。
1. 要件定義は「何を実現するか」を決めます。ここで書くのは業務の話であって、技術の話ではありません。「経理担当者が月末に3日かけている突合作業を、当日中に終わらせる」といった、利用者から見た結果を書きます。機能要件(何ができるか)と非機能要件(どれだけ速いか、落ちないか、守られているか)の両方を含みます。
2. 基本設計(外部設計)は「利用者から見える形」を決めます。画面の遷移、帳票の項目、外部システムとの受け渡し電文、データベースに持つ実体(テーブル)とその関係。利用者と合意できる粒度まで具体化するのがこの段です。
3. 詳細設計(内部設計)は「作り手から見える形」を決めます。クラスやモジュールの分割、処理の手順、エラー時の分岐、性能を出すための索引の張り方。利用者には見えないが、作り手が迷わないために要る情報です。
この3段が上から順に並ぶのは、下の段が上の段を前提にしているからです。テーブル設計は業務のルールを前提とし、モジュール分割はテーブル設計を前提とする。前提が動けば、その上に載っているものは全部揺れます。
なぜ後になるほど高くつくのか — 分岐の掛け算
「後で直すと高い」を、気合いの問題ではなく数の問題として見てみます。
1つの要件は、基本設計に落ちる時点で複数の画面・複数のテーブルに分岐します。1つのテーブルは詳細設計で複数のモジュールに分岐し、1つのモジュールは実装で複数のファイルと関数になり、1つの関数には複数のテストケースが紐づきます。そして本番に出た後は、蓄積されたデータ、書かれた手順書、利用者の身についた操作、他システムとの連携という形で、さらに広がって固着します。
つまり工程が1つ進むごとに、元の1件が触るべき箇所の数が数倍に増える。この「数倍」が段ごとに掛け算されるので、費用は足し算ではなく累乗で伸びます。
は要件定義の段でその場で直した場合の費用、 は工程を1つ下るごとに触る箇所が何倍に増えるかという分岐の倍率、 はその間違いが作り込まれた工程から発見された工程までの距離(何工程ぶん下ってから見つかったか)です。式が言っているのは一行で、「見つけるのが1段遅れるごとに、費用は 倍される」ということだけです。
が仮に3なら、要件の取り違えを本番(5段下)で見つけたときの費用は 倍になります。この 243 という数字自体を信じてはいけません。 は工程の粒度・システムの結合の強さ・自動テストの有無で大きく変わりますし、Boehm が1981年に示した有名な費用曲線も、その具体的な倍率の根拠については後年批判があります。信じるべきは倍率の値ではなく、足し算ではなく掛け算で効くという構造のほうです。
もう一段だけ現実に寄せます。実際に効いてくるのは「見つかったときの費用」ではなく、見つかる確率も込みの期待値です。
は 番目の間違いがそこまで生き延びる確率、 はその発見距離。上流のレビューや試作は を小さくするための投資であって、間違いをゼロにするための投資ではありません。間違いは必ず起きる前提で、見つかる場所を手前にずらす。 上流工程の目的を一行で言えばこれです。
コードで見る、発見が1段遅れるということ
費用モデルをそのまま書くと10行です。
PHASES = ["要件定義", "基本設計", "詳細設計", "実装", "テスト", "本番"]
def rework_cost(made_at, found_at, c0=1.0, k=3.0):
"""made_at 工程で作り込んだ間違いを found_at 工程で直す相対費用"""
return c0 * k ** (found_at - made_at)
for i, phase in enumerate(PHASES):
print(f"要件の取り違えを{phase}で発見: {rework_cost(0, i):7.1f}")
ここで見てほしいのは出力の数字ではなく、found_at - made_at という引き算が指数に載っている点です。費用を下げる手は原理的に2つしかありません。 を下げる(モジュールを疎に保ち、影響範囲を狭くする)か、 を下げる(早く見つける)か。上流工程の作業は、ほぼ全部が後者の を削る活動です。
最大の敵は「間違い」ではなく「曖昧さ」
要件定義で本当に危険なのは、間違った記述ではありません。間違いはレビューで反論されます。危険なのは、関係者全員が違う意味で読めてしまう記述です。誰も反論しないまま合意され、実装の段になって初めて解釈が割れます。
「柔軟に検索できること」「大量アクセスに耐えること」「必要に応じて通知する」— これらは要件ではなく願望です。要件に書き換える鍵は検証可能性、つまり「完成したかどうかを、誰が測っても同じ答えになる形で書けているか」です。
- ✗ 大量アクセスに耐えること
- ○ 同時接続200、平均応答1秒以内、ピーク時5分間で応答成功率99%以上
数値だけでなく測り方まで書くのがコツです。「平均応答1秒」は、どこからどこまでを測るのか(利用者の体感か、サーバ内の処理時間か)で倍以上ずれます。
そして曖昧さが最も残りやすいのが非機能要件です。機能は使えないとすぐ苦情が来ますが、性能・可用性・運用のしやすさ・移行のしやすさ・セキュリティは、後から「足す」ことができません。応答1秒と応答10秒では、そもそも持つべきデータ構造が変わるからです。IPAの「非機能要求グレード」のように、可用性・性能拡張性・運用保守性・移行性・セキュリティ・システム環境という項目立てを最初から埋めていく方法が広く使われているのは、放っておくと全員が忘れる領域だからです。この領域が実際にどう運用へ効いてくるかは可観測性 — ログ・メトリクス・トレースの実務で扱っています。
ただし、上流に時間をかけすぎても失敗する
ここまでの話は「最初に全部決めろ」という意味ではありません。全部決めきろうとする現場は、決められない項目を待って止まります(分析麻痺)。しかも市場も業務も、決めている最中に動きます。
実務的な線引きは、完成度ではなく可逆性で引きます。
- 不可逆な決定は手前で決める: データモデル、外部システムとの契約、認証・権限の考え方、扱う個人情報の範囲。後から変えると移行作業が発生する種類のもの。
- 可逆な決定は後ろに倒す: 画面のレイアウト、文言、内部のアルゴリズム、ライブラリ選定。差し替えても他所に波及しないもの。
アジャイル開発は上流工程を否定したのではなく、この仕分けをして、可逆な決定の を短い反復で回収するやり方です。反復していても、データモデルの取り違えは高くつきます。前節の と の式は、開発手法を問わず効いています。
現場ではこう使う
誰が、いつ: 業務システムのSE・テックリード・PdMが、キックオフ直後の要件定義工程、設計レビュー、そして変更要求(CR)が来た瞬間に使います。特に重要なのは3つ目で、「その変更はどの層の前提を動かすか」を判断するのがこの知識の使いどころです。画面文言の変更と、キーの持ち方の変更は、見た目の作業量が同じでも が違います。
実際に触るもの:
- 要件一覧のID採番とトレーサビリティ(RTM: Requirements Traceability Matrix)。要件ID → 設計項目 → テストケースIDを一本の表で結ぶ。JiraやBacklogなら課題タイプとリンク種別("relates to" / "blocks")で代用します。
- 受入基準を Given/When/Then の形で要件に添える。「何をもって完了とするか」が曖昧なまま実装に入らないための最小の防具です。
- IPA 非機能要求グレードの項目表。6分類を埋めるだけで、抜けやすい非機能の議論が始まります。
- ADR(Architecture Decision Record)。「なぜその設計にしたか」を1決定1ファイルで残す。半年後に前提が変わったとき、覆してよい決定かどうかを判断できます。
知らないと事故になる落とし穴:
- 「等」「など」「柔軟に」を要件書に残す。この3語は、後で必ずスコープ争いになります。レビューで語句検索して潰すだけでも効きます。
- 非機能を最後に回す。性能と可用性は設計の骨格を決めます。作り終えてから「実は24時間無停止です」と言われると、作り直しになります。
- 口頭合意を残さない。議事録に「決定事項」「保留事項」「決めた人」を書く。保留を書かないと、保留していたこと自体が忘れられます。
- 承認者を決めない。関係部署が3つあると、要件は3通りに分裂します。最終的に誰が首を縦に振れば確定なのかを、最初に1人(または1会議体)に定めます。
- テストケースを要件に紐づけない。紐づいていないと「テストは全部通ったのに、要件が1つ実装されていない」が検出できません。
- スコープ拡大を無記録で受ける。1件ずつは小さくても、記録がないと納期の遅れが誰の判断の結果か説明できなくなります。
面接や設計レビューでよく問われる問いは「曖昧な要件が来たらどうしますか」です。筋の通る答えは、①誰の何の業務が困っているかまで遡る ②完成の判定方法(数値と測り方)に書き換える ③それが不可逆な決定に触れるかを見る ④触るなら手前で決め、触らないなら後ろに倒す、の4段です。「お客様に確認します」だけで止まると、確認すべき項目を自分で作れないと見なされます。
機械学習を含むシステムでは、この上流の議論に「データがそもそも取れるか」「精度が落ちたと誰が気づくか」が加わります。その領域の設計順序はMLシステム設計 — モデルの外側の9割に、効果を数字で判定する側の話は統計的検定とABテスト — p値の使い方と誤用にまとめてあります。
まとめ
- 上流工程は要件定義→基本設計→詳細設計と並ぶ。下の段が上の段を前提にするので、上が動くと下は全部揺れる
- 手戻り費用が高いのは、工程が進むごとに「触る箇所の数」が掛け算で増えるから。効くのは倍率の値ではなく累乗という構造
- 費用を下げる手は2つだけ。結合を弱めて を下げるか、発見を早めて を下げるか
- 要件定義の敵は間違いより曖昧さ。検証可能な形(数値+測り方)に書き換える
- 全部決めきるのではなく、不可逆な決定だけを手前に集める
次回は、この要件定義そのものをどう書くか — 曖昧さの潰し方と、要件をテストへ落とす手順を掘り下げます。
コメント
コメントにはログインが必要です