VOLUME 01 / CHAPTER 04
予約ボタンの外側に、仕様がある
ユースケースの目標から、事前条件・事後条件・状態遷移・例外を導く。画面が正常に動くことと、業務の約束を守ることの違いを読む。
出典照合日: · 独自解説
架空事例:青葉機材の標準機材予約を設計する。予約と通知の関係、確認中の扱い、受付番号の規則は、本書の説明用に定めたものである。UMLの用語の説明と、この会社に採用する業務ルールを区別する。
ボタンを押せることは、借りられることではない
画面の試作品には、機種、数量、期間を入力する欄と、予約ボタンがあった。入力して押すと、完了画面へ移る。営業担当者は「これなら簡単だ」と評価した。
試作品には、貸出し可能な機材が実際に存在するかを調べる処理はない。複数人が同じ最後の一台を予約しても、全員に完了と表示される。見せたかったのは入力の流れだから、それ自体は試作品の欠陥とは限らない。だが、これをもって予約機能の仕様が決まったと考えると危険である。
営業が達成したいのは、ボタンを押すことではない。顧客に対して、合意した機種と数量を指定期間に提供できると確約することである。画面の操作を列挙する前に、利用者が得る結果を置く。その結果を実現する相互作用を記述するのが、ユースケースを使う意味になる。既存テキスト第3章も、ユースケースを画面遷移図と同一視しないよう区別している。1
アクターは人物名ではなく、境界の外の役割
この予約システムを対象とするなら、営業担当者は依頼を登録するアクターとなる。契約管理システムが契約の有効性を回答するなら、外部システムも相互作用の相手になる。人間だけをアクターとして描くと、外部との要求・応答が落ちる。
一方、予約システム内部のデータベースは、今回の境界の内側にある。その内部要素を、営業と同じ外部アクターとして描けば、何をシステムの責任に含めるかが変わってしまう。会社の外か内かではなく、モデル化する対象の外か内かを見る。アクターが表すのは対象と相互作用する利用者や他システムの役割である。2
役割は権限と関係するが、同じものではない。営業担当者をアクターとして記しただけでは、自分の営業所の依頼だけを扱うのか、全社の依頼を扱えるのかは決まらない。役割を識別した後に、どの対象へどの操作を許可するかを具体化する必要がある。
また、一人の営業所長が依頼登録と例外承認の両方を行っていても、二つの仕事を同じユースケースにまとめる必然性はない。目標、開始条件、責任が違うなら、その違いをモデルへ残す。
基本フローには、成功の意味が必要になる
青葉機材の「標準機材を予約する」を、次のような相互作用として考える。
営業が機種、数量、利用期間、顧客を指定する。システムは入力の妥当性と契約条件を確かめる。指定した条件で機材を確保できるか判定する。確保できる場合は、予約を確定し、予約番号と合意内容を返す。
この短い記述にも未決定事項がある。「確保できる」とは、照会した瞬間に空いていることなのか、予約確定の時点で他の予約と矛盾しないことなのか。前者だけなら、照会後に他の営業が最後の一台を確保した場合、両者に約束してしまう。
そこで本事例では、成功時の事後条件に「指定条件の予約が一件確定し、その確保分が他の確定予約に重複して割り当てられない」を置く。これは、成功した処理の後に守るべき業務上の約束である。ロックを使うのか、競合を検出して一方を失敗させるのかは、実現方式の検討になる。要求段階で方式を選ぶ必要がある制約を除けば、まず結果の約束と実装案を分ける。1
事前条件も同様である。「営業担当者が有効な利用権限を持つ状態で開始する」と書けば、このユースケースの記述範囲を明らかにできる。しかし、実装で権限を確認しなくてもよいという意味ではない。モデルが置いた前提を、実行時に何が保証するかは別に設計する。
事後条件を正常終了だけに置くと、失敗の後に何を残すかが未定になる。確保できなかった場合には、確定予約を作らず、不成立の理由を示す。依頼記録を残すのかは、受付履歴を必要とする業務に合わせて決める。「失敗したら何も変更しない」という条件も、記録すべき不成立の履歴まで消してよいかを考えて使う。
includeとextendは、前と後を表す矢印ではない
契約条件の確認が、予約と期間変更の両方に現れる。共通の振る舞いを別のユースケースとして表現するなら、includeの関係が候補になる。includeは、一方のユースケースが他方に定義された振る舞いを含む関係である。Includeの向きは、含む側から含まれる側へ向かう。3
一方、通常の予約に加え、特定の条件で配送手配の振る舞いを挿入するモデルを考えるなら、extendが候補になる。extendでは、拡張する側から拡張される側への関係と、どの拡張点で振る舞いを加えるかを表す。4
ここで「includeは前に実行する処理、extendは後に実行する処理」と覚えてはいけない。関係が表すのは、振る舞いの包含や拡張であって、画面の前後関係ではない。共通処理をAPIとして切り出したから、自動的にユースケースのincludeになるわけでもない。内部実装の再利用と、利用者との相互作用のモデルは粒度が異なる。
さらに、extendを「必ず条件式を持つもの」と断定するのも正確ではない。参照したEclipse UML2のモデルAPIでは、Extendに条件が関連付けられていない場合は、拡張点での拡張が無条件であると説明されている。4 「条件付きの追加」という覚え方は入口にはなるが、それだけで形式上の制約をすべて言い表したことにはならない。
青葉機材に配送機能が必要かどうかは、記法からは決まらない。配送を扱わない事業なら、そのユースケースを作る必要もない。モデルの記号を使い切るために、要求を増やしてはいけない。
状態を置くと、同じ操作の意味が変わる
営業は、予約をいつでも修正できるようにしたいと言う。だが、確認中の依頼と、出庫準備が始まった確定予約では、変更の影響が違う。後者を自由に変更すると、倉庫が準備している機材や配送予定と食い違う。
本事例では、受付後の依頼を確認中として記録し、条件が整えば確定へ進める。確認中の依頼は、まだ顧客へ機材を確約しておらず、確定予約の数量には含めない。確認中の段階で仮の枠を確保する方式もあり得るが、ここでは採用しない。この前提を明示しなければ、「確認中」の読み方だけで設計が分かれてしまう。
次の表は、議論する範囲を限定した状態遷移の例である。貸出し後の返却や料金計算まで網羅した全状態表ではない。
| 現在の状態 | 受け付ける事象 | 必要な条件 | 遷移先・結果 |
|---|---|---|---|
| 確認中 | 確定の依頼 | 契約が有効で必要数量を確保できる | 確定 |
| 確認中 | 依頼の取下げ | 依頼を扱う権限がある | 取消し |
| 確定 | 出庫準備の開始 | 対象の予約内容を確認できる | 出庫準備中 |
| 確定 | 取消しの依頼 | 出庫準備開始前で、取消し条件を満たす | 取消し |
| 出庫準備中 | 変更の依頼 | 倉庫との調整が必要 | 状態を保ち、別途調整する |
| 取消し | 確定の依頼 | この予約を再利用しないという本事例の規則 | 拒否し、新しい依頼として扱う |
状態、事象、条件、結果を分けると、「いつでも変更できる」が何を省略していたかが分かる。状態が同じでも事象が違えば処理は違い、同じ事象でも条件を満たさなければ遷移しない。
UMLの状態機械では、遷移のトリガ、ガード、効果を区別する。ガードは遷移の有効性を制御する条件であり、効果は遷移に伴う振る舞いである。ガードの評価で予約を更新するように、条件の判定と副作用を混ぜない。参照したモデルAPIでも、ガードは副作用を持たない式として説明されている。5
もっとも、状態遷移表に正しい条件を書くだけで、同時実行の安全性が保証されるわけではない。二つの要求が同時に確定条件を満たすと読めた場合に、確保量の制約をどう守るかは実装と検証へ引き継ぐ必要がある。
通知できないとき、予約まで取り消すべきか
予約は確定した。予約番号も発行された。しかし、営業への通知メールは送れなかった。
基本フローを「予約を保存する、メールを送る、完了する」とだけ書いていると、メールが失敗した以上、全体を失敗にしようという実装になりやすい。ところが、予約確定と通知の成功は、業務上同じ事象ではない。本事例では、システムの予約記録を確定結果の基準とし、メールを補助的な通知と位置付けることにする。
この選択なら、通知失敗だけを理由に予約を取り消さない。画面で予約番号を確認でき、通知は再送対象として管理する。ただし、通知に法的・契約上の別の意味を持たせる業務なら、この扱いをそのまま使ってはいけない。本事例の前提から導く設計である。
今度は、予約番号を返す前に通信が切れた場合を考える。呼出し元には、確定したかどうか分からない。タイムアウトは、結果が届かなかったことを示すだけで、相手が何も実行していないことの証拠にはならない。この論点は既存テキスト第7・18章の、再試行とトランザクションの境界に接続する。1
そこで、「同じ受付の再送で、二つの予約を確定しない」「受付番号で処理結果を確認できる」という要求候補が生じる。受付番号を採番する主体、同一操作と判断する範囲、同じ番号で異なる内容が来たときの扱いまで必要になる。同じ番号の再送なら何でも成功扱いにするだけでは、数量変更を黙って無視してしまうかもしれない。
ここでは、要求の結果として何を保証するかまでを扱う。重複を識別する記録をいつ確定するか、どのトランザクションに含めるかという実装の選択は、後のデータ・分散設計につながる。ボタンを一度だけ押せるUIは補助にはなるが、通信や別経路からの再送を含む保証の代わりではない。
正常系から外れた一歩が、責任を明らかにする
「エラーならメッセージを表示する」という要求は、利用者へ何を判断させたいのかが分からない。入力を直して再度操作すればよいのか。処理結果を照会すべきなのか。倉庫へ連絡する必要があるのか。失敗の種類によって次の行動は変わる。
例えば、必要台数を確保できないのは業務上の不成立である。契約管理システムが応答しないのは、その判断に必要な情報を得られない状態である。後者を前者と同じ「貸出し不可」と表示すると、情報不足を事実として顧客へ伝えてしまう。確認中として保留する、再確認する、担当者へ引き継ぐなど、採用した業務に合う対応を定める。
例外フローを書く価値は、すべての低水準エラー番号を並べることではない。事前条件が崩れたとき、途中結果が残ったとき、外部との認識が分かれたときに、どの約束を守るかを明らかにすることにある。シラバス5-4と10-2が扱う機能とインタフェースの設計は、この受渡しの意味まで含めて考える必要がある。6
予約ボタンは、小さな入口にすぎなかった。その外側には、確約、保留、取消し、再送、通知という異なる事実がある。ユースケースから始めて、それらを状態と条件へ展開すると、画面だけでは見えなかった仕様が現れる。
知識を答案へ戻す
午前Ⅱの判別軸。 アクターは対象と相互作用する役割で、人間に限らない。includeとextendは単なる実行順序ではない。状態機械では、事象、ガード、遷移の効果を混同しない。機能名だけを問われたように見えても、何を表現するモデルかを読む。
午後Ⅰへの接続。 正常終了だけでなく、本文にある不成立、取消し、期限、外部連携失敗を拾う。本事例の通知失敗なら、予約記録が確定結果の基準であるという前提から、予約の取消しと通知の再送を分ける。実際の問題で通知が成立条件なら、逆の設計になる可能性がある。
午後Ⅱへの接続。 「例外処理を考慮した」とまとめず、どの例外でどの不整合が起こるため、結果確認や再送の扱いをどう定めたかを書く。本事例では、通信断で利用者が成否を判断できないことと、再送で二重予約しない要求の関係を説明できる。ここに示す表現は独自の論述例である。
立ち止まって考える:タイムアウトしたので、同じ予約を新しい番号でやり直してよいか
相手で既に確定している可能性があるので、無条件にはやり直せない。本事例では元の受付番号で結果を確認し、同一操作の再送として扱う。新しい番号なら別の操作と解釈され、二つの予約が成立するおそれがある。タイムアウトを処理の未実行と取り違えない。
出典と照合範囲
[1] コンプリートテキスト『午前Ⅱ 技術知識の地図』第3・5・7・18章:ユースケース、状態、通信断、再試行、トランザクションの基礎に接続した。青葉機材の予約成立条件や通知の位置付けは、本章で置いた仮定である。
[2] Eclipse UML2 5.1.0 公式モデルAPI・Actor:アクターを、対象と相互作用する利用者や他システムの役割として扱う説明を照合。Actor
[3] Eclipse UML2 5.5.0 公式モデルAPI・Include:包含する側と包含される側、および振る舞いの包含を照合。Include
[4] Eclipse UML2 5.1.0 公式モデルAPI・Extend:拡張する側から拡張される側への関係、拡張点、条件が省略された場合の扱いを照合。これはEclipseのモデルAPIの説明を参照したもので、OMG仕様書全体を検証したという意味ではない。Extend
[5] Eclipse UML2 5.5.0 公式モデルAPI・Transition:Guard、Trigger、Effectの区別とガードの副作用に関する記述を照合。表は本書の業務状態表であり、UMLのすべての遷移種別を表したものではない。Transition
[6] IPA「SAシラバス Ver.5.2」:5-4、7-1、10-2。機能要件、システム要件、インタフェース方式設計の位置付けを照合。公式PDF