大半の開発チームは以下のようなコーディングのガイドラインに従っている。
また、要件を書くためのガイドラインも利用したい。例えば、ユースケースとソフトウェア要件を併記すると決めた場合は、ガイドラインでイベントフローの書き方を示す必要がある。イベントのユースケースフローは、何か重要な処理を行うときのシステムとユーザー(関係者)のやり取りの仕方を解説する。用意するガイドラインは、メインフローで何が行われ(成功シナリオ)、代替フローで何が行われているか(例外シナリオ)、そしてこれらのフローをどのようにして構造化するのかを示す必要がある。これらは、その中のフローと個々のステップの長さについても示す必要がある。従来からある宣言要件を使う場合は、ガイドラインでこれらの書き方を解説する必要がある。幸いにも、これらのガイドラインの多くは、RUPなどの評判の高い各種情報源にすでに存在するので、自分で書く必要はない[*2]。
優れたコードを開発するためには、そのシステムを動かすマシンの詳細と、そのOSの使い方を知っておく必要がある。WindowsであればMFCや.Net、LinuxであればUNIXのシステムコールを知っておく必要がある。
要件をうまく書くためには、OSではなく運用者を理解する必要がある。さらには、ユーザーインターフェイスではなくユーザーを理解する必要がある。Javaの開発者はクラスパスを考えるが、要件作成者はクラス(つまり学習会)へ足を運ばせる手立てを考える。
要件を引き出すのは人が中心の作業だ。要件は作り出すものではなく、他人から集めるものだ。これは内向的な開発者には難問かもしれないが、既存のスキルを正しく適用すればうまくできるだろう。
ユーザーは、自分が何を望んでいるのか分からない場合も多い。また、たとえ分かっていても、どうやって説明してよいのかが分からない。開発者には、彼らを支援するスキルがある。彼らは、コンパイラが表示する不可解で暗号のようなエラーメッセージを解読しなくてはならないことも多い。例えば、アプレットを書くJava開発者は次のようなメッセージを目にすることがある。
load: com.mindprod.mypackage.MyApplet.class can't be instantiated. java.lang.InstantiationException: com/mindprod/mypackage/MyApplet
これはどういう意味だろうか。もし開発者が正確に理解できない場合は、コード、コンパイラのマニュアル、そしてGoogleなどの検索エンジンまで参照して調査する。そうして、自分が書いているアプレットにデフォルトのコンストラクタがないことが何とか分かるのだ。
天気予報システム向けに要件を集めていて、関係者がシステムに対して「通常の後尾付き矢印記号で500km四方の各種高度における風速と風向を表示する」などと要求してきた場合は、詳しい調査が必要になる。同じようなシステムが出す出力を見せてもらったり、気象学の書籍を参照したり、別の関係者に要望をもっと正確に聞いた方がよいだろう。そして、希望の機能に関する十分な詳細が得られるまで調査を続ける。そして、この要件をいい換えて、より明確かつ明白にし、デザインをサポートするために十分な詳細を提供する。
要件を引き出すときのもう1つのコツは、誘導尋問のようにならないことだ。ユーザーが何を望んでいるのかはある程度予想できるかもしれないが、それを口にしてしまうと彼らが本当に望んでいるものの実像が見えなくなる可能性もある。そうするのではなく、「どのデータを独立表示させたいですか?」といった自由回答ができる質問をし、「気圧と温度を組み合わせたグラフは欲しいですか?」のような質問は避ける。
優れたプログラムを設計および書くときの基本原則には、情報隠ぺい、結合、および凝集などがある。これらはどれも、優れた要件を書くときにも当てはまる。
◎ 情報隠ぺい
これは、あるコードのユーザー/コール元は、そのデータの内部にアクセスできてはならない、あるいはその存在も知るべきでない、という原則を指している。データへのアクセスやその修正はファンクションコールを介して行わなくてはならない。こうすれば、コールするプログラムに影響を与えずにデータの内部構造を変更できる。
これは要件に当てはめても優れた原則で、ユースケースで説明している場合はなおさらだ。先に言及したように、ユースケースにはイベントの流れがある。うまく書かれていないユースケースは、イベントの流れがデータ定義だらけの場合が多い。Manage Purchase Request(購買請求管理)というユースケースのイベントの基本的な流れを見てみよう。
(1) システムが未決購買請求書をすべて表示する
(2) 未決請求書には請求に関する以下の情報が含まれる(文字制限あり):
(3) 承認責任者は、1)承認、2)拒否、3)キャンセル、4)割り当て、のいずれかを行うことができる。1)承認を選ぶ
(4) すべての作業が終了するまでこれらの処理を繰り返す
これら15行のうち、11行は未決請求にどのようなデータが関連するのかの説明に費やされている。これは重要な情報だが、ユースケースの中で起こっていることを分かりにくくする。データを別の場所に隠しておく方がよいだろう。そうすれば手順が以下のように変わる。
データが別の場所(通常はユースケースの専用要件部分か、あるいは用語解説部分)で定義されていることを示すため、未決購買依頼書は下線が引かれ、斜体で表示される。これにより、本当の機能要件を表すイベントの流れがはるかに読みやすく、理解しやすくなる。
◎ 結合および凝集
コードを書く場合、結合とはプログラム中の個々のモジュールを可能な限り独立させる、という原則を指す。1つのモジュール内の処理が別のモジュールの内部処理情報に依存してはならない。一方の凝集は、所定のモジュールの中ではすべてのコードが1つの目標の達成に向けて処理を行う必要がある、という原則を指す。これらの原則は、プログラムを理解ならびに保守しやすくする。
そして、これらの原則は要件、特にユースケースにも当てはまる。ユースケースはスタンドアロンでなくてはならない(結合がまったく、あるいはほとんどない)[*3]。各ユースケースは、機能のほとんどの部分を特定し、システムが関係者に対してどのように価値を提供するのか示す必要がある。関係者に重点を置くことは重要なことだ。その関係者のためにシステムがすることを、ユースケースの順番を気にすることなく明記できる。
1つのユースケース中の機能は、すべてが関係者の目指す1つの目標達成に向けたものであるべきだ(高い凝集性)。典型的なATMシステムでは、ユースケースの1つは「現金の引き出し」となり、もう1つは「振り込み」となる。どのユースケースも目標は1つに絞られる。これらの機能を1つのユースケースにまとめようとすると、凝集性が低下してしまう(そして望ましくない依存が生じる)。
しかし、多くのユースケース初心者は、やり過ぎて低いレベルのユースケースをあまりに多く作成してしまうので注意したい。筆者は、「データの修正」などの名称が付いた150のユースケースで構成される銀行の債権回収システム用のモデルを目にしたことがある。このプロジェクトは10人編成のチームで1年がかりの予定だった。しかしこの組織は、ユースケースがあまりに断片的であったため、作業を進行させるに当たって多くの問題を抱えてしまった。彼らは、ユーザーにとっての価値を特定しない低レベルの機能を記述していた。これらは、理解するのが困難で使いにくかった。各ユースケースは非常に凝集性が高かったが、それゆえユースケースは結合性が高かった。このレベルを「債権の回収」といった具体的な処理にまで高めると、凝集性と結合性の両方が適切なレベルになった。
Copyright © ITmedia, Inc. All Rights Reserved.