ホーム > 読んだ > 国外

UMLモデリングのエッセンス 第2版
標準オブジェクトモデリング言語入門

書誌

text唯野
authorマーチン・ファウラー, ケンドール・スコット
editor羽生田栄一(監訳)
publisher翔泳社
year2000
price2,400
isbn88135-864-2

目次

1感想
2抄録
3正誤表

履歴

2001.5.23読了
2001.7.19公開
2002.12.9修正

感想

UML の入門書。各所で薦められている本であり、取っ付きやすさは確かに言葉通りである。本の厚さの割に要点がよくまとめられ図も適切なので、本書のようにまず学びたいことの重要となる部分(エッセンス)を押さえることのできる本はありがたい。

抄録

第1章 UMLの概要

UML (Unified Modeling Language) はそれまでに Booch、Rumbaugh (OMT)、Jacobson (俗に 3 人を three amigos と呼ぶ) らの提唱していたオブジェクト指向分析・設計論を継承したもので、現在では OMG (Object Management Group) により標準化されている。UML はモデリング言語(設計時に用いる方法を記述するための記法)でありプロセスを含む方法論ではない。(プロセス:設計時の手順における指示部分。プロセスはケースによって使い分けるということ。) UML は記法(notation:モデル中でのグラフィカルな要素)とメタモデル(meta model:記法を定義する図)についてを扱っており、これによって実用性と定義の厳密さの両立を狙っている。

UML を用いることによって明確な概念の伝達(重要な細部の強調)、(外部者を含めた)システム概要の素速い把握などが可能になる。これは情報の伝達におけるポイント(何を重要事項として強調し省くか)ということの推進につながっていく。UML を使いこなすためにはオブジェクト指向の長所を利用するためのパラダイムシフトが必要となるが、これも実際に組み合わせるべき技法はケースによって異なる。(例えば CRC カードや相互作用図、クラス図、パターン、反復型開発などはそれぞれ長所が異なる。)そして、UML は適切なシステムのためのコミュニケーションを行うために利用できる。具体的にいうと、ユースケースはスナップショット、クラス図は概念抽出、アクティビティ図はプロセスの把握――といった用途で効果を発揮する。

第2章 開発プロセスの概要

オブジェクト指向開発がプロセスとしてどう進められるのかについて。three amigos のまとめたプロセスが RUP (Rational Unified Process : ラショナル統一プロセス、以前は Objectory 法と呼ばれていた) だが、ここではその詳細には触れない。これは UML がプロセスに縛られないことにもよる。一般にオブジェクト指向開発では反復(iteration)を含んだアプローチを取ることが多く、方向付け(inception:プロジェクト範囲の決定、費用・利益の見積り) -> 推敲(elaboration:アーキテクチャの基礎を固め実装計画を練る、何をどう構築するか) -> 構築(construction:ここで反復を移行) -> 移行(transition:チューニングやベータテストなど)、といった儀式(ceremony)を繰り返す。

そして、推敲フェーズで留意すべき点としてリスク管理が挙げられる。リスクには少なくとも以下の 4 種類がある。

  • 要求リスク(顧客の望むものとのずれ)
  • 技術リスク(技術の適合性)
  • スキルリスク(人員・専門家の過不足)
  • 政治的リスク(政治的圧力)

そこで要求リスクへ対処するためにユースケース(ユーザとシステムとの相互作用)を出発点として使い、同時に専門家を交えたドメイン(対象領域)モデルの分析を行う。ドメインの理解ではクラス図、アクティビティ図、相互作用図などを用いる。(このとき推敲フェーズでは表記法よりもどんどん図と情報を書き込むことで理解を深めることができる。)重要なのは最初のドメインモデルをスケルトンとして捉えることで、それを具体化する段階では延々と分析を行わないよう期限を設けて一気に行う点となる。また、それに並行してトリッキーな部分に関してはリスクを評価できるだけのプロトタイプを作成する。(プロトタイプの段階で実装言語に縛られる必要はない。)

また、技術リスクに関しては、ポイントはコンポーネントの適合の仕方にあるのであってコンポーネントそのものにあるのではないことに注意する。これに関連してアーキテクチャの設計は分散システムにおいて特に重要となる。そのため後からの変更が困難な箇所に注力して、設計要素の変更が容易となるよう心がける。一方、技術リスクに対しては優れたインストラクタによるトレーニングまたはメンターのプロジェクトへの参加が挙げられる。また、これとは別に読書による知識の補完、読書会による知識の掘り下げなどが重要となる。推敲フェーズは全体からいうとおよそ 1/5 を占めることが多いが、人週での工数見積りができ、潜在的リスクに対する洗い出しが完了し、そのうち重要なものでは対処法までを検証済であれば終わりということができる。

次いで構築フェーズでの計画を立案する。つまり各反復内で実装すべき機能についてを煮詰める。そのために、まずユースケースの分類を高・中・低でビジネス的な重要性 -> 開発時のリスク -> 開発に必要な期間(人週)、スケジュール的なリスクの順で評価する。その上で反復の期間、工数を把握する。すると、プロジェクト速度 = 開発者人数 * 反復期間 / 負荷係数(実際の時間/見積り時間) が分かるので、全てのユースケースでこれを行い念のため 1 を加えておく。(もちろんユースケースに応じた修正は必要。)その後の移行フェーズには構築フェーズの 10-35% を当ててチューニングとパッケージングを行うようにし、更に構築フェーズの 10-20% を偶発要因のための時間として確保しておく。(構築フェーズにこの時間は含めないが顧客には含めた時間として提示する。)ここから導き出されるのがリリース計画表(release plan)となる。

構築フェーズは段階的(incremental:機能面でインクリメンタル)かつ反復的(iterative:コード面で繰り返し)に行われる。ここでコードを繰り返し修正するための技法としてりファクタリング(refactoring)がある。(反復ごとに破棄されるコードが 10% 以下なら注意する。)そして、構築と統合を頻繁に行うことで統合を後回しにしたことによる問題をなくし、統合前の単体テストを実施することで機能の後退(regression)を避ける。テストは予想よりも時間のかかる重要なものなので、効率を上げるためにも試験ツールは実行・検証までが自動で行われるようにし、単体テストと機能テストを分け、バグの発見を喜ぶ体質を作ること。(リファクタリングとは機能を変更せずに構造を変更してプログラムの使い勝手を向上させる技法のことで、そのポイントは以下の通り。リファクタリングと機能追加は同時に行わない、回帰テストを行う、短い小さなステップで行う。)

もちろん計画が予定通りに進まないこともありえるが、まずは計画を予定通りに進める習慣を付け締め切りを守ることが基本となる。その上で見直しが必要な場合は定期的に行うようにする。構築フェーズでは UML が積極的に用いられる。コーディング時の柔軟性のないコードは設計の誤りを示すので、この場合にはためらわず設計に立ち返るようにする。また、適切なメモ、コードから生成された詳細な文書を並行して行うようにし、繰り返し用いられる概念はパターンとして取り込むようにする。(パターンによってソリューションを得ることができる。)但し、最適化は移行フェーズまで行ってはならない。

第3章 ユースケース

ユースケースとは Jacobson の提唱した「ユーザの一般的な目的に照らしたシナリオ」(scenario:ユーザとシステムの対話における一連の手続き)のことで、メインシナリオと派生(バリエーション)シナリオという捉え方をする。ユースケースでは全てを取り込むのではなく必要なものに絞り、その上でリスクに応じた分割を行うことがポイントとなる。

ユースケース図

ユースケースにおいてシステムに対してユーザの果たす役割(role)をアクタ(actor)といい、主にユースケースにおいて利益の得る存在をアクタとする。アクタもあくまでユースケースのための要素なので、アクタのないユースケースもありえる。重要なのはユースケースとユーザの目的となるので、それを整理するために外界からのイベントで応答の必要なものを挙げてみるとよい。その際、ユースケース自体に類似性があり重複を避ける場合は包含(include)関係を使う。また、他のユースケースと似ているが少し違うバリエーションを記述する場合はユースケースの汎化(use case generalization)による上書き(override)を使う。更により多くの違いを基底側の拡張点として記述する場合には拡張(extend)を使う。大きなユースケースは分割し標準的なユースケースを先にこなすようにするとよい。

加えて、これらはビジネスユースケース(顧客やイベントに対するビジネス的な対応)とシステムユースケース(ソフトウェアとのやりとり)を加味して行われる。推敲フェーズにおいては初期ではビジネスユースケース、その後はシステムユースケースの役に立つことが多く、ビジネスユースケースごとのシステムユースケースを用意する。ユースケースは常に利用されるので、それに基づいて自分のスタイルを作るようにする。)

第4章 クラス図:基本的要素

クラス図(class diagram)によってシステム内のオブジェクトの型とそれらの間の静的(永続的)な関係が示される。この静的な関連には単なる関連とサブタイプとがある。クラス図を作成する際の観点には、概念的観点、仕様の観点(インターフェイス、OOP では実装よりもインターフェイスに重きを置かなければならない)、実装の観点が存在する。(観点は UML の機能ではないが明示した方がよい。)

クラス

ロールと多重度

継承

クラス図に登場する概念的観点を取り上げてみると、まず関連(クラスインスタンス間の関係)がある。関連には 2 つの関連端(association end)があり、各端点がクラスにつながりロール名(role name)というラベルを付けることができる。(ラベルのない場合はターゲットクラス名がロール名になる。)また、端点には多重度(multiplicily)があり、ここで関連するオブジェクトの数が分かる。(よく使われるものとして 1 (1..1)、* (0..*)、0..1(0 か 1) がある。)

また、仕様的観点としてはレスポンシビリティ(責務)がある。(関係を更新するというレスポンシビリティなど。ポイントとしてメソッドの命名規則なども含めることができる。仕様レベルなので、このレベルでデータ構造は含まれない。)また、関連に付いた矢印は誘導可能性(navigability)を示し、対応する機能の可能性を示している。(但し、誘導可能性は仕様と実装とで異なる場合がある。)誘導可能性が単方向の関連を単方向関連(unidirectional association)、双方向の場合を双方向関連(bidirectional association)という。(矢印がなければ関連が未知か双方向を示す。)そして、双方向関連では互いが逆の関係(inverse)にあるという制約が加わる。この関連の命名では伝統的に動詞が使い、オブジェクトに名詞を使うことが多い。関連は永続的なものなので依存関係を使ってモデル化される。

属性(attribute)は実装レベルではフィールド(データメンバ)になるもののことで、表記は通常「可視性 名前 : タイプ = デフォルト値」となる。属性と関連の違いとして属性はタイプから属性のみへの誘導可能性を持ち、属性への参照ではない「値としてのセマンティクス」を持つ点が挙げられる。(概念的観念での違いはない。)そして、操作(operation)はクラスが自分で実行されなければならないと知っているプロセスのことで、実装レベルでのメソッドに当たる。但し、通常、単なる属性へのアクセッサまでは記述しない。

操作に対する構文としては以下のものがある。

例 : + balanceOn (date : Date) : Money

可視性+ (パブリック)、# (プロテクテッド)、- (プライベート)
名前文字列
パラメータリスト方向 名前 : タイプ = デフォルト値(方向には in、out、inout があり、省略すると in と見なされる)
戻り値のタイプ各戻り値のタイプをコンマで区切って並べたリスト
プロパティ文字列操作に適用するプロパティ値

ちなみに操作ではクラスの状態の変える操作(問い合わせ : query)と変えない操作(更新 : modifier)とで区別すると役立つ場合がある。(制約の表現として {query} などと書く。{ } が制約を示す。)この場合、問い合わせは明示し更新では順序に意味を持たせるようにする。他に、Get メソッド(値の取得のみの操作)と Set メソッド(値の設定のみの操作)、操作(オブジェクトに対して起動されるもの:呼び出し)とメソッド(手続き本体)による区別などのやり方がある。(この他に言葉の違いとして C++ でのメンバ関数が Smalltalk でのメソッド、C++ のクラスメンバが UML での特性(feaure)などがある。)

これとは別にサブクラスがスーパークラスとして汎化(generalization)される場合には、(実装レベルでの is-a 的な)インターフェイスの適合性、タイプとしての置換可能性(substitutability)としていうことができ、実装言語でいえば継承となる。ポイントは仕様の観点での汎化(サブタイプ化、インターフェイスの継承)と実装の観点での汎化(サブクラス化、実装の継承)の違いで、サブクラス化はサブタイプ化の手段のひとつであり、他に委譲などを用いた実装形態があるため。

クラス図では制約の記述が多くなるが { } を使うという以外での規定は特にない。原則としてルールは使用する実装言語に表明(assertion:決して偽にならない命題)として埋め込まれるべきであるとされている。そうでなくてもクラス図は頻繁に利用されるので、情報が多いためにかえって利用しづらいこともありえる。そのため何でも全てを埋め込もうとするのではなく、モデルの観点を使い分け(分析時には概念モデル、ソフトウェアとしての段階では仕様モデル、実装技法に依存する場合に実装モデル)、あらゆるモデルを作るのではなく主要なものに絞って行うようにする。最も注意しなければならないのは、早い段階で実装詳細となり融通を失わないようにする点となる。

なお、表明を用いた設計手法として契約による設計(Disigned by Contract)があり、ここでは事前条件(リスポンシビリティの明確化、重複を避ける)、事後条件(実装からインターフェイスの分離)、不変式(invariant:インスタンス全ての操作前後において真)のことを表明として扱う。事前条件が満たされているが事後条件の満たさない状態が例外となり、これによってポリモーフィズムに伴うスーパークラスに矛盾したサブクラスの実装を防ぐことが可能になる。

第5章 相互作用図

相互作用図は振る舞いに対してオブジェクト群がどのような連携をするか説明する。通常、ある相互作用図はあるユースケースに対応して記述され、シーケンス図とコラボレーション図がある。

シーケンス図はオブジェクトごとの縦線(lifeline:生存線)を元にメッセージのやりとり(メッセージ名がラベルの矢印)を示したもので、この矢印が自分に戻る場合は自己呼び出し(self-call)という。更にオブジェクトがアクティブなとき(手続きがスタックに積まれているとき)を示すのに活性区間ボックス(activation box) を使う。また反復を * で、条件を [ ] 内に記述し、リターンは破線で示す。(煩雑を避けるためあまり使わない。)これは並行プロセスでも応用でき、その場合には羽根の半分の矢印が非同期メッセージ(呼び出し側をブロックしない)、×がオブジェクトの削除を示す。他に起こっていることを左側に記述したりしてもよい。

シーケンス図1

シーケンス図2

一方、コラボレーション図ではシーケンスの流れでメッセージにシーケンス番号を振る(小数点などを用いる)ことで実現する。利点はシーケンス図よりもオブジェクトのリンク関係を理解しやすくなる点だが、逆に流れは把握しにくくなる。名前は「オブジェクト名 : クラス名」であることが普通だが、オブジェクト名を省いても : までは消さない点で注意が必要。

コラボレーション図

相互作用図の問題としては代替手段の表現の難しさがあり、これを解決するために CRC カード(Class-Responsibility-Collaboration)を使う方法がある。カードというものを使うことで開発者の議論を促し、カードを移動させるだけで検討を行うことのできる利点がある。

全文を読まれる場合はログインしてください


Up