要件定義書の書き方|正常系と異常系の「あいだ」が抜けて、静かに壊れる

要件定義書とは、何を作るかを発注側と開発側で合意する文書です。経費精算システムの刷新を題材に、教科書どおりに要件を書いて、動かして、数字が合わない日が来るまでを順に追います。抜けていたのは、正常系でも明示的な異常系でもなく、その「あいだ」でした。エラーが飛ばないので監視でも見つかりません。書き漏らしがどう現れるか、そして機能一覧の代わりに何を3列で書けばいいかを、そのまま使える表で置きます。
Total
0
Shares
要件定義書の書き方|正常系と異常系の「あいだ」が抜けて、静かに壊れる

要件定義書の書き方の話をする前に、そこで何を作ろうとしているのかから始めます。ここを飛ばすと、あとの事故の話が伝わらないからです。

題材は、経費精算システムの入れ替えです。

いまの状態はこうです。社員が紙の申請書に領収書を貼って提出し、上長が印鑑を押し、経理が金額と科目を確認して、月次で振込データを作る。月末になると、経理が数日がかりで確認しています。

新しいシステムの目玉は、AIによる読み取りです。領収書をスマートフォンで撮ると、日付・金額・支払先を読み取って、申請を自動で作る。入力の手間がほぼゼロになります。

ここで、なぜ要件定義が必要になるのかというと、作る側と発注する側が、別の会社だからです。

自分たちで作るなら、頭の中の像がずれても、作りながら直せます。外に頼むと、ずれたまま3ヶ月進みます。 だから作る前に、何を作るかを文書で合意する。

要件定義書とは、何を作るのかを発注側と開発側で合意するための文書です。業務上の目的、対象範囲、実現する機能、性能やセキュリティの条件、そして何をもって完成とするかの判定基準を書きます。

そして今回は、AIが工程の中に入ります。 ここが従来の要件定義と違うところで、あとで効いてきます。

従来のシステムは、書かれていないことをしません。 仕様書に無い動きはしない。だから仕様書の網羅性が、そのまま品質になりました。

AIは、書かれていないことをします。 役に立とうとするからです。網羅性だけでは、品質にならない。

前置きはさておき、本題に入ります。

今日は、この要件定義を教科書どおりに書いて、動かして、そこで何が起きたかという話をしていこうと思います。

① 教科書どおりに、要件を書く

教科書どおりに、要件を書く

書き方の型は確立しています。機能を洗い出し、画面を数え、非機能条件を並べる。

経費精算は業務がはっきりしているので、かなり具体的に書けます。

“`
【正常系】
・領収書を撮影 → AIが日付・金額・支払先を読み取り → 申請が作成される
・申請者が内容を確認して提出
・上長に通知 → 承認または差し戻し
・経理が科目と金額を確認 → 確定
・月次で振込データを出力

【異常系】
・画像が不鮮明で読み取れない → 手入力に切り替える
・金額が上限を超える → 申請できない旨を表示
・上長が不在 → 代理承認者に回す
・締め日を過ぎた申請 → 翌月扱いにする
“`

正常系も異常系も書きました。レビューも通りました。このとき、要件定義書は分厚い一冊になっていました。

そして、動くものができます。期待どおりに動きました。 領収書を撮ると読み取り、申請が立ち、承認が回り、月次で振込データが出る。

② 数字が合わない日が来る

数字が合わない日が来る

稼働から3ヶ月ほど経ったころ、経理から連絡が来ます。

申請したはずの精算が振り込まれていない、という問い合わせが1件あった。

調べます。申請者の画面には、申請が「提出済み」として残っています。 ところが経理側の確定一覧には、その1件がありません。前後の申請は普通に並んでいます。1件だけ、無い。

最初は表示の不具合を疑いました。次に権限、次に検索条件。どれも違いました。

原因はこうでした。その申請は、締め日を過ぎた直後の数分間に作られていました。

→ ① 締め日の締め切り処理が走り、その月の受付は閉じた
→ ② 直後に、申請者が領収書を撮影した
→ ③ AIが読み取り、申請を作成した
→ ④ 申請者の画面には「提出済み」と表示された
→ ⑤ ところが経理側は、閉じた月の申請を集計に含めない。翌月にも繰り越されなかった

申請者から見れば出した。経理から見れば受け取っていない。 どちらの画面も正しく動いています。

要件定義書には「締め日を過ぎた申請は翌月扱いにする」と書いてありました。書いてあったのに、繰り越されなかった。 なぜなら、その処理は「申請が作られたあとに締め日を過ぎた場合」を想定していて、「締め処理が走った直後に、新しい申請が作られる場合」は想定していなかったからです。

③ 抜けていたのは、正常系と異常系の「あいだ」

抜けていたのは、正常系と異常系の「あいだ」

要件定義書に不備はあります。ただし、雑だったからではありません。

正常系は書かれていました
明示的な異常系も書かれていました(読み取り失敗、上限超過、承認者不在、締め日超過)

抜けていたのは、そのあいだです。

システムとしては受け付けられない状態なのに、人が来てしまう。 このケースが、誰の頭にも浮かんでいませんでした。

そして、いちばん厄介なのはこれがエラーとして飛ばないことです。

→ 例外は出ていない
→ 画面も落ちていない
→ ログにもエラーが無い
申請者の画面には「提出済み」と正しく表示されている

壊れたものを探す仕組みは、全部すり抜けます。 見つかったのは、社員から問い合わせが来たからでした。

問い合わせが来なければ、この不具合は翌月も翌々月も起き続けていたことになります。そして、いくらだったかも分からないままです。

書類の厚さと、この抜けは無関係でした。 「これで網羅した」と言えるだけの厚さがあっても、思いつかなかったケースは、何ページ書いても書かれません。

④ もうひとつ — AIは、書かれていないことをする

もうひとつ — AIは、書かれていないことをする

同じ時期に、別の問い合わせも来ていました。私的な支出が精算されそうになった、という報告です。

領収書の画像に「〇〇商店」とだけ書かれていて、AIはそれを取引先との会食と読み取り、交際費として申請を作っていました。実際は本人の買い物です。

AIの精度は悪くありません。書かれている情報からは、そう読めます。 問題は、判断がつかないときに「作らない」という選択肢を与えていなかったことでした。

従来のシステムは、書かれていないことをしません。AIは、書かれていないことをします。 役に立とうとするからです。

ここが、AIを挟む要件定義における最大の差分です。

⑤ 直してみる — 列挙する対象を、機能から3つに変える

直してみる — 列挙する対象を、機能から3つに変える

機能から発想すると抜けます。理由は単純でした。

→ 機能から発想すると、「システムができること」が並びます
→ でも事故が起きるのは、「システムができないのに、人が来たとき」です
→ できないことは機能一覧に載らないので、発想の起点になりません

そこで、列挙する対象を3つに切り替えました。

1. 受け渡し — 誰から誰へ、何を、どれだけ渡すか

業務を「部署の役割」で分けると、絵はきれいになりますが抜けます。事故は役割の中ではなく、役割と役割のあいだで起きるからです。

書くのは組織図ではなく、渡すものの一覧です。AIを挟むなら、AIも「渡す相手」の1つとして同じ表に並べます。

2. 停止点 — どこで人の判断を待つか

そして、その承認は処理を止めて待つのか、先に進めてあとから追認するのか。

「確認ダイアログを出す」は、業務を同期的に止める設計です。毎月まとまった数の申請が流れる現場でこれをやると、承認者が律速になります。金銭が動く、取り消せない、外部に送信される——このどれかに当たるなら止める価値があります。それ以外は、止めなくていい可能性が高い。

3. 受け付けられない状態のときに、人が来るケース

冒頭の事故が、まさにここです。

→ 締め処理の直後に申請が来たら
→ 上限に達した直後に、同時申請があったら
→ 承認者が異動した直後に、その人宛の承認が回ってきたら

このリストは、機能から発想すると出てきません。「無いものを数える」という発想が要ります。

⑥ あとで知った — この抜けには、名前がついていた

あとで知った — この抜けには、名前がついていた

素朴な整理のつもりでしたが、調べると同じ分け方をする言葉が、すでにありました。

テストの世界では、カバレッジを4つに分けて呼び分けることがあります。厳密な定義があるわけではなく、緩く使われている言葉です。

正常系(happy path) — 入力が正しく、例外が起きず、期待どおりの結果が出る理想の経路
異常系(sad path) — 認証拒否のような、想定済みの失敗
境界値(edge case) — 入力の端
同時多発(corner case) — 低確率の条件が複数、同時に当たる

冒頭の事故は、4つ目でした。 「締め処理が走った瞬間」と「申請が作られた瞬間」という、それぞれ低確率の事象が同時に当たっている。だから誰も思いつかなかった。

そして、この抜けが生む結果にも名前がありました。サイレント障害(silent failure)です。定義がそのままです。

「正常系からの逸脱が、何のシグナルも出さないとき、それはサイレント障害になる」。

僕が「エラーとして飛ばないから見つからない」と書いていたものは、すでに名前が付いて、対処法まで整理されている現象でした。

その対処法が、3つ目です。突き合わせ(reconciliation)。

会計システムの文脈では、突き合わせが合わないときは記帳を止めて管理者に通知するのが期待される挙動とされています。ログを1行出して先へ進む、ではありません。

もっと分かりやすいのが、件数の突き合わせです。

送り出した件数と、返ってきた件数は一致しなければならない。一致しなければ、差分を必ず表に出す。 この規則が無いと、50件送って48件返ってきたときに、システムは「48件を処理しました」と報告します。「2件が欠けています」とは報告しません。

冒頭の事故と、まったく同じ構造です。 申請者の画面は「提出済み」と報告した。「経理に届いていない」とは報告しなかった。

新しい理屈は、ひとつも要りませんでした。

⑦ 何が変わったか

何が変わったか

3列を書き出す作業は、すぐ終わりました。機能一覧を作るのに使った時間より、はるかに短い。

そして、書き出した「受け付けられない状態のときに人が来るケース」は、十数件になりました。 そのうち、既存の要件でカバーされていたのは数件だけです。

残りのうち、実際に起こりうると判断したものを絞り込むと、その中に、冒頭の事故と同じものがありました。

つまり、あの事故は、この表を先に書いていれば防げていたことになります。機能一覧を削って、この表を1枚足すほうが、事故は減ります。

⑧ 現場で使うなら、この3列

現場で使うなら、この3列

そのまま埋められる形にします。

表1:受け渡し

渡す側受け取る側渡すもの頻度そろっていない率(実測して埋める)
申請者AI読み取り領収書の画像申請ごと読み取れない画像の割合
AI読み取り申請者日付・金額・支払先申請ごと人が直した項目の割合
申請者上長申請申請ごと差し戻しの割合
上長経理承認済み申請申請ごと経理で直した割合
経理振込処理確定データ月1回振込エラーの割合

「そろっていない率」の列が、いちばん効きます。 ここは推測で埋めず、実際に数えてください。数字が入った瞬間、どこにAIを入れるべきかがほぼ決まります。

表2:停止点

工程人が判断するか止め方理由
AI読み取り後する非同期(提案して先へ、あとで修正)取り消せる
上長承認する非同期(一括で確認)1件ずつ同期で止めると律速
経理確定する同期で止める金銭が動く。取り消せない
振込実行する同期で止める同上

同期で止めるのは、金銭が動く2工程だけ。 残りは「提案して先へ進み、あとから追認」にします。

表3:受け付けられない状態のときに、人が来るケース

状況人が来るといま何が起きるかどうする
締め処理の直後申請が作られる提出済みと表示され、集計に入らない受付を閉じ、翌月へ回す
上限到達の直後同時に申請片方だけ通る両方止めて通知
承認者の異動直後承認が回る宛先不明で滞留代理へ自動転送
AIが判断できないそのまま申請推測で作成される作らずに人へ回す

4行目が、AIを挟む場合の必須行です。 「判断がつかないときは作らない」を、明示的に書きます。

表4:突き合わせ(無いものを数える)

突き合わせるもの頻度拾う条件一致しないとき
申請者側の提出済み ⇄ 経理側の受領毎日片方にしか無い行止めて通知
承認済み件数 ⇄ 確定件数毎日件数の差止めて通知
確定金額 ⇄ 振込金額月次金額の差止めて通知

「ログを1行出して先へ進む」にしないでください。 止めて、人に通知する。これが、サイレント障害への唯一の対処です。

⑨ この書き方が効き続ける理由

この書き方が効き続ける理由

要件定義が重要になった、という言い方はやや不正確です。重要性の中身が入れ替わりました。

実装が高かった時代、要件定義の役割は手戻りを防ぐことでした。作り直しに数ヶ月かかるから、作る前に決め切る価値があった。

実装が数日になった今、手戻りのコストは劇的に下がりました。 だから「決め切る」ことの価値は、実は下がっています。

代わりに上がったのが、漏れを見つけることの価値です。作り直しは安いが、気づかない事故は安くなりません。

そして、抜けやすい場所は毎回同じです。受け渡しと、停止点と、受け付けられない状態に来る人。 この3つだけ、他の10倍の時間をかけてください。

4つ目の表は、そのうえで必ず作ってください。 上の3つは事故を減らしますが、ゼロにはできません。ゼロにできない前提で、気づける仕組みを持つ。 それが、あの分厚い一冊には書かれていなかったものです。


ちなみに、経理の月末は目に見えて短くなりました。

浮いた時間で何をしているかというと、振込が終わったあとの突き合わせです。件数と金額を並べて、片方にしか無い行を探す。

自動化した時間を、自動化が壊れていないか確認する時間に使っている。 これでいいのか、いまも少し考えています。

以上です。

You May Also Like

店舗DXの進め方|アプリを入れても、誰も触らなかった理由

店舗DXとは、店舗の業務や購買体験をデジタルで作り変える取り組みです。アパレル店舗に試着予約アプリを入れて、まったく使われなかったところから話を始めます。原因は機能ではなく、置いた場所の隣に店員が立っていたことでした。顧客が迷っている時間に伴走する設計へ切り替えると、同じ機能が動き出します。売場で何分迷っているかを測るところから、そのまま使えるチェックシートまで置きます。
View Post

デプスインタビューとは?聞き方を磨いても、買わない理由は出てこない

デプスインタビューとは、対象者1人に深く聞いて行動の背景を掘り下げる定性調査です。訪日客向けの荷物配送サービスを題材に、教科書どおりにインタビューを設計して、そのとおりに作って、1件も売れなかったところから話を始めます。原因は聞き方ではなく、買わない理由の多くが本人にも見えない状況に埋まっていることでした。聞いて分かることと置かないと分からないことの線引きと、調査設計シートを置きます。
View Post

物流DXの進め方|自動化率を上げるほど、残った仕事は難しくなる

物流DXとは、倉庫・配送・受注といった物流業務を技術で作り変える取り組みです。冷蔵と冷凍を扱う食品ECの倉庫と配送を題材に、自動化率が上がっていく過程と、その先で起きたことを追います。残った0.1%は量が少ないだけの仕事ではなく、一つひとつ理由の違う例外の集合でした。しかもエラーとして飛ばないため監視でも見つかりません。例外を工程として設計に含めるための表を、そのまま置きます。
View Post

業務フローの書き方|四角と矢印を描いても、どこが遅いか分からない

業務フローとは、仕事がどの順番で誰の手を通って進むかを表したものです。中古車販売の査定から納車までを題材に、教科書どおりのフロー図を描いて、それでも改善点が見つからないところまでを追います。図に足りなかったのは、量と待ち時間でした。工程の速さではなく、受け渡しでどれだけ情報が欠けているかを測ると、手を入れる場所が変わります。そのまま埋められる2枚の表を置きます。
View Post