今月の記事では、先月に続いて、預金ユース・ケースのユース・ケース・テンプレートの残りの部分を記入していきます。先月の例では、単にテンプレートを埋めるだけでなく、作業を進める際に私が考えた過程についても詳しいコメントを示しました。今月説明するテンプレートの部分は、ある意味でユース・ケース記述のうちの核心部分と言えます。この部分は、そのユース・ケースの進行に伴う作業の流れを実際に記述する部分であるからです。ユーザーがこのユース・ケースに沿って作業を進めるときに、プログラムがこの作業の流れを実行します。
前回のコラムでは、私たちのユース・ケース・テンプレートの半分を説明しました。その続きから話を進めます。
- 依存関係
-
類似:
2.0. 子供による口座からの預金の引出し(同等?)
先行:
4.0. 親による口座の開設
含む:
6.1. 親による一回の預金の許可
後続:
6.0. 親による以前の預金の許可
このリストは暫定的なものです。たとえば、ユース・ケース2.0との「類似」関係は、実際には「同等」関係かもしれません。
- 前提条件
- 口座が存在していなければならない。
- 入力データ
- 子供がお金を稼いだ。
- (幸運な筋書き)
Philipはその日の雑用を終え、手に入れた2.25ドルをBank of Allenに預金することにしました。(彼に毎日働かれたら、私は無一文になっているところです。)彼は銀行に入店し、テラーに預金入金票を要求し、それに記入して、預金通帳と一緒に預金入金票をテラーに渡します。テラーは預金入金票を受け入れる前になんらかの本人確認を要求し、預金入金票を役職者に渡して承認を求めます。役職者 (親) は預金を許可して預金入金票にサインし、それをテラーに戻し、テラーはその取引を記入してPhilipの預金通帳を更新します。テラーは預金通帳をPhilipに戻し、Philipは残高が増えたことをじっくりと確認して大喜びするというわけです。私がこのシナリオの記述で (この連載の前の記事で述べた) 問題ステートメントの語彙 (たとえば、「預金通帳」や「テラー」) をそのまま使用するようにしていたことに注意してください。ここで新しい概念を導入した場合 (実際よくあることなのですが)、前に戻って、その新しい語彙を紹介するために問題ステートメントを変更しなければならなくなります。設計者にとっての重要な (そして困難な) 目標は、すべての設計文書を相互に「同期」した状態に維持することです。ある文書における変更が他の文書に影響を与える場合には、両方の文書をただちに変更する必要があります。たとえば、私は「テラーは預金取引を反映させてこづかい帳記入を行う」という言い方を意図的に避けました。これは、「預金通帳」がこの分野の語彙に含まれているのに対し、「こづかい帳」はこの分野の語彙に含まれていないためです。「こづかい帳」と呼ぼうが「預金通帳」と呼ぼうが、設計を行ううえでは違いがありません。
また、私が「システム」という語を使用しなかったことにも注意してください。システムは何もしません。すべての作業は、明確に定義された役割を担う行為者によって行われるのです。これらの行為者の一部 (子供) は、ほんものの人間です。その他の行為者の中には (テラーのように) 完全に自動化されているものがあります。その他の行為者 (役職者) は、部分的には自動化され、部分的にはほんものの人間です (役職者の責任の一部は、コンピューターではなく、親によって行われます)。重要なのは役割です。その役割が行為者によって行われるのか、自動化されているのかは、ここでは重要ではありません。
- こちらのシナリオでは、お金が口座に実際に追加されることはありません。預金は「未承認」として預金通帳に入金されます。親はあとでこの取引を承認することができます。つまり、預金は「承認を得る」までは「棚上げ」されます。テラーは預金通帳を子供に返し、その預金は預金通帳に記入されますが、親が預金入金票にサインするまでは、口座から資金を引き出すことはできません。(このシナリオは、預金を許可する親がその場にいないという点で、幸運な筋書きとは異なります。)
- このシナリオでは、親が子供のために資金を預金します (子供が取引を開始し、親がそれを許可するのとは異なります)。
ここまできて、「子供」という言葉を使いたくなくなってきました。もう少し、軽々しさのない言葉はないものでしょうか。私は、息子 だの顧客 だのという言葉でなく、子供という言葉を意図的に使用しています。設計文書全体での命名は、内部的に整合していることが重要だからです。しかし、用語をもう少し注意して選んでおけばよかったと思っています。
2番目のシナリオは、実際には新しいユース・ケースを導入しています。このユース・ケースはそれまでの私には起こったことがないものです。つまり、「親による以前の預金の許可」というものです。許可は現行のユース・ケース (「親による一回の預金の許可」という、サブケースを含みます)で行われる操作ですが、このシナリオは、真に独立のユース・ケースです。
このセクションは重要なセクションですので、これまで使用してきた形式から少しそれて、ワークフローがどのように進化するのかをお見せしましょう。幸運な筋書きを単純なリストとしてモデル化することから始めることにします。
幸運な筋書きのシナリオ:
- 子供がテラーに預金入金票を求め、それに記入します。
- 子供が預金入金票と預金通帳をテラーに渡します。
- テラーは子供が本人であることを確認します。
- テラーが預金入金票を役職者に送り、承認を求めます。
- 役職者は、預金入金票に承認済みのマークを付けてテラーに戻します。
- テラーは、子供の預金通帳に記入を行い、預金が行われたことを示します。
- テラーは、子供に預金通帳を返します。
単純なワークフローの場合には線形リストで十分ですが、ワークフローが込み入ってくると、これではうまくいきません。
ConstantineとLockwoodは、「任意の順序で:」などの語句のあとにリストを続けるなどの方法を使用して、非線形の操作を表すことを推奨しています。「同時に」のあとにリストを続けることにより、並行性を表すこともできます。
私は視覚型の人間のようで、このようにユース・ケースを言葉だけで表現するのは、わかりにくい気がします。ユース・ケースがひどく込み入っている場合、私はUMLワークフロー・ダイアグラムを使用したいと思います。単純な、幸運な筋書きの場合のUMLは、図1のとおりです。
図1. 幸運な筋書きのワークフロー・ダイアグラム
この表記法は、図を見ると多少とも想像がつくと思います。各ボックスは1つのアクティビティーに相当し、流れは矢印で表されます。丸印から開始し、目標で終了します。スイム・レーン と呼ばれる列は、アクティビティーを実行する責任を負うオブジェクト (つまりサブシステム) のクラスを識別するものです。
私はこのダイアグラムを見て、並列性を利用する余地があることに気付きました。つまり、いくつかのアクティビティー (子供の本人確認と預金の承認) は、並行して行えそうです。(また、これらのアクティビティーは、次のステップに進む前にすべてが実行されればよいのであって、その実行順序は重要でないということも分かると思います。)
図2は、この並列性を反映させるように図1に対して行う必要のある変更を示しています。一連の並列アクティビティーを開始させる (これらのアクティビティーの先頭にある) 太い水平線は、フォーク と呼ばれます。下部の水平線は、その後の作業を可能にするためにそこでアクティビティーを同期させる必要があることを表すもので、結合 と呼ばれます。
図2. 並列性を反映させて変更した、幸運な筋書き
ここで前に戻り、他の2つのシナリオを調べ、それらを幸運な筋書きのアクティビティー・ダイアグラムに組み合わせてみます。(変更後のダイアグラムは図3に示してあります。)一般に、シナリオを組み合わせることができない場合、または組み合わせてできたダイアグラムがあまりに不格好な場合、おそらく、その追加シナリオは現行ユース・ケースのシナリオではなく、独立のユース・ケースになります。しかし、今回のシナリオの組み合わせは、非常にうまくまとまっています。
親が子供のために預金するというシナリオは、親が子供になりすますことを許せば、ワークフローは幸運な筋書きと同一になるわけですから、簡単な話です。つまり、親のパスワードを使用して子供をログオンさせることができるのです。この効果については、アクティビティー・ダイアグラム (図3) とビジネス・ルール・セクション (下記) の両方にコメントを付けてあります。
2番目のシナリオ (親がその場にいない場合) は、ブランチ (図3では、1つの入力矢印と複数の出力矢印を含むひし形として示してあります) を導入する必要がありますので、これよりも少し厄介です。どの出力パスをたどるべきかを制御する条件 (ガード と呼びます) は、線に付けられるテキスト・ラベルです。マージ (これもひし形で示されますが、入力矢印が複数で出力矢印が1つです) は、条件付き振る舞いの終わりを表します。各ブランチには、マージが関連付けられていなければなりません。
フォークと結合の間の複雑な出来事は、すべて次のように表現することができます。任意の順序で、子供の本人確認を行い、親がいる場合にはその預金に承認済みのマークを付け、親がいない場合には未承認のマークを付ける。両方のアクティビティー (確認とマーク付け) が完了したあとで預金通帳を更新する。
元のシナリオの記述では、テラーが未承認の預金を保留するように指定されていたことに注意してください。ダイアグラムの作業を行っているうちに、未承認の預金は、テラーが保留するのではなく、預金通帳内で保留するようにしたほうがはるかに簡単であることが分かってきましたので、そのようにしたのです。私は前に戻って、この変更が反映されるようにシナリオ記述を変更しました。
図3. 幸運な筋書きに付け加えられた追加シナリオ
- 処置後の状態
- 新しい口座残高 = 古い口座残高 + 預金額
このユース・ケースが、同時に起きなくてもよい2つの異なる操作 (預金の要求と預金の許可) を含んでいることに注意してください。それでも、これは単一の出力が得られる単一のユース・ケースなのです。口座残高は、預金アクティビティーから承認アクティビティーまでの間に何日か経過するとしても、常に影響を受けます。
- 出力
- 更新された預金通帳
このセクションでは、出力がどのような形式になるのか (たとえば、報告書の場合) を実際に示します。これは、次回の記事でUIの作業を開始するときまでお預けにしましょう。
- 預金が有効になるには、親によって許可されなければならない。
- 利息は、許可が後日行われる場合であっても、預金が行われた日に発生し始める。
- 未許可の預金は、未許可状態のまま、親がサインするのをいつまでも待ち続ける。これらの預金が「失効」することはない。
- 親のパスワードは子供を認証する。つまり、親が子供としてログオンできる。
要件(インプリメンテーション関連)
- 預金は自動的に「保管」されなければならない。「ファイル / 保管」メニューは存在しない。明示的な「取り消し」は不必要であり、望ましくない。預金の取り消しは引出によって行う。
- 「保留」された預金は、子供が預金通帳を見たときに表示されなければならない。保留された預金はグレー表示される。
ここで「グレー表示される」と言わずに「何らかの方法で強調表示される」と言ったとすると、価値のない仕様を書く危険を冒すことになっていたでしょう。仕上げた時点で仕様があいまいであることはとても許されることではありません。いずれはすべての決定が行われなければならないわけで、とりあえずは後回しにしておくという手もあります。誤った決定を行った場合、いつでも戻って変更することができます (もちろん、仕様が正式に承認されるまでのことですが)。
何も決定しないよりは間違った決定を行うほうがまだ良いと私は思います。仕様の記述があまりにも遠回しなために、その仕様に基づいて数百もの異なるプログラムが生成可能であり、しかもそのすべてが仕様に準拠してしまうような例を、私はたくさん見てきました。この種のあいまいさは、誤った仕事を助長してしまいますので、無益というより有害です。
こののケースでは、問題は些細なものですので、決定する必要はなさそうに思えます。項目が強調表示される かぎり、どのように 強調表示するかは、どうでもよいことです。結論を言えば、この決定は、正式なUI設計プロセスまでに行うべきです。強調表示の概念を未確定のままにしておくと、その設計をインプリメントするさまざまなプログラマーが、各自の概念で強調表示をインプリメントし、そのためにUIが矛盾して使いにくくなってしまいます。
インプリメンテーションの注記
- 現在はログインの概念はありません。シナリオを見ると、Philipは一度に複数の取引は行わないようです。実際、彼は単一の取引を行うことになりますが、ログオフするのを忘れる可能性が高いのです。(これは、我が家の実験室で観察した振る舞いです -- Philipは朝はゲームをすることが多いのですが、12時間後、つまり彼が寝た後も、そのゲームが実行され続けています。)この振る舞いを見ると、預金入金票の受け入れの一部として、なんらかの認証を要求するようにしたほうが安全なようです。実際の銀行は、基本的にはこうしたやり方をしています。
- ログインに似たものとして、ガードマンに自分の身分を証明し、銀行に入ることを許されるということがあります。(これは妥当な方法ですが、私はこの方法を採用しませんでした。)このユース・ケースでは、テラーがPhilipが何者であるかを覚えておくのは何の問題もないことに注意してください。つまり、顧客に「トラステッド (信頼可能)」というラベルを付けて、認証プロセスを繰り返すことなく引き続きトランザクションを行えるようにすることは、ユース・ケースで取り扱うべき範囲に含まれることになります。「トラステッド」属性は、ログアウトによって取り消すことも、単純にタイムアウトにすることもできます。(たとえば、銀行内で2分間何のアクティビティーも行わないまま経過した場合に、非トラステッドにすることができます。)
- (この注記は実際のオブジェクト・モデル化を開始するまでは読者にとって不明瞭かもしれませんが、現時点で分からなくても心配しないでください。)子供は、大部分の場合、外部オブジェクトです。つまり、子供を表す、プログラムに基づいたオブジェクトはシステムに存在しません。子供は、システムの物理的なユーザーです。一方、子供の身元の概念は、ほぼ間違いなくモデル化されます。これは、システム内のなんらかのオブジェクトが認証を扱わなければならないためです。
- 「使用可能な資金」と「現行残高」とは異なります。(現行残高は取引が未許可であることを反映しません。)子供は、許可されているかどうかを問わず、預金を預金として扱いますので、預金通帳には両方の値を表示する必要があります。いずれにしても、「保留」とはどういうことなのかを子供に教えるのに、妨げになることはありません。
UIで保留をどのように表すのが最も良いのかは、私には確信がありません。1つの方法として、自分の預金通帳を眺めているすべての子供に預金入金票は見せるが、預金入金票が親によって許可されるまでは、その預金が正式なものとして預金通帳に表示されないようにすることができます。別の可能性として、預金を許可された預金と同じように預金通帳に表示し、その預金が保留されていることを表すなんらかのビジュアルな目印 (グレーテキスト?) を付ける方法もあります。
後者のやり方のほうが、理にかなっていますが、このことは、親が現行預金を許可するというユース・ケースが、親が保留状態の預金を許可するというユース・ケースとは、おそらくかなり違うものであるということを意味します。
親が許可するまでテラーが預金入金票を保留した場合、子供はテラーに対し、預金通帳を見て、預金通帳だけでなく保留状態の預金入金票も表示できるようにすることを要求する必要があります。 - おそらく、親の許可を扱う最善の方法は、預金入金票のUIそのものにありそうです。「許可済み」ボックスをチェックすると小さなダイアログがポップアップし、そこでサインを入力するという方法があります。別の方法として、預金入金票自体に「許可済みサイン」行を設け、そこに親がパス・フレーズを入力できるようにするというやり方もあります。(許可済みの預金入金票には、取引が許可されたことを示すなんらかの表示 -- サインの複写など -- を行う必要があります)。許可済みサイン行にはxを印刷しないようにしてください (あるいは、少なくとも、サインが確認された後はxを置き換えるようにしてください)。パス・フレーズの文字数を教えてしまってはいけません。
- ここで、アクセス制御の問題が生じます。子供の役割を果たす人は、預金を指定することができますが、預金を許可することはできません。(許可を行うことにより、口座の残高、預金通帳が更新されます。)親の役割を果たす人は、預金を指定することも預金を許可することもできます。システムはこれら2つの行為者を区別できなければなりません。そのためには、パスワード認証で十分です。
- 利息は保留状態の資金についても (たとえこれらの資金がアクセス不能であっても) 積算されます。おそらく、利息を取り扱う最良の方法は、預金通帳を、取引が日付順にソートされたリストと考えることです。許可された預金入金票は、ソートされた順序に従って取引リストに挿入されます。そして、最も新しく挿入された取引のすぐ上の時点から利息が再計算されます。こうすることにより、未許可取引が利息を発生させることはなくなります。
しかし、利息の発生は毎日表示する必要がありますので、現実世界の預金通帳や銀行ステートメントのように取引をリストしただけでは十分ではありません。実際に必要なのは1日ごとに1つの行項目です。しかし、それでは行項目が多くなってしまいます。妥当な譲歩案としては、直前の30日についてだけ1日ずつ表示し、預金通帳の残りの部分は、標準の銀行ステートメントのように定期的に (しかし毎日ではなく、) たとえば、週に1回利息記入をするという方法があります。
あるユースケースについて全体を見てきました。ユース・ケースの残りの部分を後続のコラムで示すと読者が退屈するでしょうから、私のWebサイト (参考文献を参照) に完全なユース・ケースをアップしておきます。暇なときに目を通してください。来月は、設計プロセスの続きとして、UI設計について検討します (UI設計は、きわめて重要です。これは、構築しなければならないからという理由だけでなく、ユース・ケースの妥当性検査を行ったり、便利なコミュニケーションのためのツールを備えていたりするためです)。
- この記事は、OO設計プロセスに関する私の連載記事の続きです。最初の7回は以下のとおりです。
-
www.holub.comにあるAllenのWebサイトを訪問してください。
-
ConstantineとLockwoodは、この記事とは異なる方法で非線形の操作を表すことを推奨しています。
- オブジェクトがその操作によって定義されるという概念は、Allen HolubのWhat is an Object?(JavaWorld 1999年7月) によって論じられています。このシリーズ (すべての記事の索引がhttp://www.holub.com/publications/articles/index.htmlに記載されています) の後続記事では、この哲学が実世界のシステムにどのように適用されているのかを説明しています。
- ワークフロー・ダイアグラム (およびUMLの残りの部分) については、Martin FowlerとKendall ScottのUML Distilled, 2nd Edでうまく説明されています。
Allen Holubは、1979年からコンピューター業界で働いています。 また、いろいろな雑誌 (主だったところでは、Dr. Dobb's Journal、Programmers Journal、Byte、MSJ など) で広く出版されているほか、 オンライン・マガジンJavaWorld の "Java Toolbox" 欄と、 IBM developerWorks Components zone の "OO設計プロセス (OO-Design Process)" 欄の執筆も行っています。 また、 ITworld Programming Theory & Practice ディスカッション・グループの調整役でもあります。 Allenは自分名義の本を8冊出版しており、 その中の最新の著書 (Taming Java Threads) では、 Javaスレッド化の落とし穴について述べています。 彼は、自分で覚えていないくらい長い間、 オブジェクト指向ソフトウェアの設計と構築に取り組んできました。 AllenはC++ プログラマーを8年間を務めた後、 1996年初めにC++ からJavaに乗り換えました。 今では、C++ は悪夢だったと感じており、 その記憶はありがたいことに徐々に消え去りつつあります。 1982年以来、プログラミング (初めはC、次にC++ とMFC、 現在はOO設計とJavaプログラミング) を、 自分のクラスとカリフォルニア大学のバークレー公開講座の両方で教えています。 Allenは、Javaテクノロジーとオブジェクト指向設計のトピックについて、 公開クラスと社内トレーニングの両方を提供しています。 また、 オブジェクト指向設計のコンサルティングと契約Javaプログラミングも行っています。 AllenのWebサイトはwww.holub.com です。