はじめに
JavaやC#などのオブジェクト指向言語によるシステム開発に従事したことのある人の多くは、いくつかのフレームワークを利用した経験もあるのではないでしょうか。良く考えられたフレームワークをうまく利用すると、開発効率を上げるだけでなく、再利用性や拡張性、保守性の向上なども期待できて、まったく良いこと尽くめです。
広く利用されているフレームワークの多くは汎用的なメカニズムやユーザ・インタフェース等に関わるものがほとんどですが、残念ながら、特定の対象領域(ドメイン)を抽象化/フレームワーク化した「ドメイン・フレームワーク」にはなかなか触れる機会がありません。
この記事シリーズでは、単純なゲームを題材に、ドメイン・フレームワークとはどういったものであるのか、ドメイン・フレームワークを導入するとどんな利点が得られるのか、といった事について解説していきます。
モデリング題材
以前、オージス総研様主催の「OBJECT DAY」というイベントの「体験UMLモデリング」というセッションに弊社の有志メンバーによって構成されたチームで参加させていただいたことがあります。その際のモデリング題材は「Greedゲーム」という簡単なゲームでした。Greedゲームの課題は、もともとはOOPSLA '89で実施されたオブジェクト指向プログラミング・コンテストの課題で、その様子は"Object Lessons - Lessons Leaned in Object-Oriented Development Projects" (Tom Love, 1993 SIGS)などに記述があります。この記事シリーズでも、Greedゲームを具体的な題材としてドメイン・フレームワークを考えていきたいと思います。
Greedゲームの仕様(ルール)は以下のようなものです:
- Greedゲームは2人以上のプレイヤーによって競われるサイコロ・ゲームです。
- 各プレイヤーはサイコロを振って出た得点の合計が早く5,000点を超える事を目指します。
- Greedゲームでは、壺(カップ)から振り出される5個のサイコロを使います。
- プレイヤーは自分の番(ターン)の最初の振り(ロール)で100点以上の得点を出さなくてはなりません。
- そのターンの最初の振りの得点が100点未満だった場合、そのプレイヤーのそのターンは「破産(bust)」とみなされ、得点はプレイヤーの合計得点として加算されず、次のプレイヤーのターンに移ります。
- 破産した場合、そのプレイヤーは次に順番が回ってくるまで待たなければなりません。
- 最初の振りで100点以上の得点が出た場合、プレイヤーは現在の得点でそのターンを終了するか続けるかを選択することができます。
- 続ける場合、プレイヤーはそのターンで得点にならなかったサイコロのみを振り直すことができます。
- プレイヤーは、すべてのサイコロが得点に関係するか破産するまで振りを続けられます。
- 特別に、最初の振りですべてのサイコロが得点になった場合は、5個すべてのサイコロを振り直すことができます。
- サイコロの振り直しで得点が増えなかったら破産となり、そのターンで得た得点はプレイヤーの合計得点として加算されず、次のプレイヤーのターンに移ります。
- 破産していなければ、プレイヤーはいつでも得点をキープしてそのターンを終了することができます。
振り出されたサイコロの目は以下のようなルールで得点計算されます:
- 3つのサイコロで目が揃った場合、100×[揃った目]が得点。
- 1の目が3つ揃った場合は1000点。
- 1の目は単独で100点。
- 5の目は単独で50点。
得点計算の例(最初の振り出しの時):
44446 = 400点。4と6のサイコロを振り直せる。
11111 = 1000 + 100 + 100 = 1200点。5個すべてのサイコロを振り直せる。
12315 = 100 + 0 + 0 + 100 + 50 = 250点。2と3のサイコロを振り直せる。
最終的に、すべてのプレイヤーが同じ回数のターンを終えた時、合計得点が5,000点以上になっていたプレイヤーが勝者となります。あるプレイヤーの合計得点が5,000点以上になったとしても、その後のターンで他のプレイヤーがより大きい合計得点でターンを終了した場合は、前者のプレイヤーの方が負けということになります。
概念モデルの例
前述の「Greedゲーム」をコンピュータを使ってプレイできるようにするという観点で、まずは対象領域(問題領域)の本質的な構造や振る舞いを理解するためのモデル(概念モデル)を作成します。Greedゲームの概念モデルの概略を示すクラス図の例を 図 1 に示します(本記事では、概念モデルをどうやって作成していくかについては解説を省略します)。
図 1 Greedゲームの概念モデルの例 ※クリックして拡大表示
この概念モデルを読み解くにはいくつかのポイントがあります。
ポイントその1 ― 基本的な視点の確認
- この課題の目標は何か?
・コンピュータを使ってGreedゲームをプレイできるようにすること。 - では、「Greedゲームをプレイする」とはどういう事なのか?
・Greedゲームのルールに従って、複数のプレイヤーがゲーム開催中のさまざまな局面を経て得られた得点を競うこと。
・すなわち、「ゲームをプレイする」とは、各局面の実行記録(履歴)情報を作り出すことに他ならない…と考える。
ポイントその2 ― ゲーム局面の発見
- Greedゲームの局面を「ゲーム」「ラウンド」「ターン」「ロール」という概念で捉える。
・「ロール」 ― 「サイコロを一回振る」という局面を表現する。
・「ターン」 ― 「あなたの番」の概念。複数の「ロール」によって構成される。
・「ラウンド」 ― プレイヤー毎の「ターン」が一巡する間の局面を表現する。
・「ゲーム」 ― 1回のGreedゲーム全体を表わす局面。複数の「ラウンド」によって構成される。
ポイントその3 ― ライフサイクルの異なるオブジェクトの区別
- 以下の三種類のライフサイクルを意識してクラスを整理している。
・ゲームが開始される前から定義/登録されているモノ(クラス図中、青色系で表示)。
・ゲーム実行中に生成され、ゲーム終了後も(記録として)残るモノ(クラス図中、黄色系で表示)。
・ゲーム実行中の間だけ必要になるモノ(クラス図中、赤色系で表示)。
ポイントその4 ― その他
- 「壺(カップ)」の概念はこの時点で(本質的でないものとして)捨象されている。
- ゲーム実行中の進行を司るものとして「Greed競技場」という場の概念を導入。
- ゲーム開始前のプレイヤー登録やルールを管理する「主催者」という概念を導入。
概念モデルの利点・欠点
概念モデルは対象領域(問題領域)の本質的な構造や特性を捉えて理解を深めるために有効です。この段階では、実現手段(HOW)の詳細にとらわれず、そもそも「どんなもの(WHAT)を相手にしなければならないのか」を整理しながら理解を深めることに注力します。システム開発の早い段階で問題領域に対する理解をしっかり深めておくことは、後のさまざまな工程に良い影響をもたらします。そのため、概念モデルは「理解のしやすさ」を最も重視して作成されます。
一方で、概念モデルは現在対象となっている世界「そのままの姿」を素直に捉えたモデルであるため、基本的に抽象化/一般化や類似の問題領域に対する再利用性や拡張性の考慮などは薄くなります。たとえば、上述のGreedゲームの概念モデルは基本的にGreedゲーム専用の構造になっているので、「すごろく」や「ポーカー」など他のゲームに直接適用/流用することは困難です。これは、概念モデルを構成する要素が「Greedゲーム」「すごろく」「ポーカー」などの「類似のゲーム一般に共通する部分(ドメイン・フレームワーク)」と「Greedゲーム固有の都合による部分」とが明確に分離されていないためです。
ドメイン・フレームワーク化されていない概念モデルをベースに(概念モデルを「分析モデル」と呼んで)、設計、実装…といった詳細化の工程に進んで行ってしまう開発プロジェクトも多く見かけます。この場合、大きな問題が無ければそれなりの期間/工数で正しく動作するシステムが出来上がってしまうので、一見するとその開発プロジェクトは成功したかのように思えてしまうのですが、そのようにして作られたモジュール群は後に類似の問題領域の別システムの開発のために流用(再利用)してみようとしてもあまり上手くいきません。再利用性や拡張性が活かせないのであれば、オブジェクト指向で開発する意義の半分ほどを失うと言ってもオーバーではないでしょう。オブジェクト指向は魔法ではないので、単に「クラス」という単位でモジュールをまとめれば自然に再利用性や拡張性が上がる…というわけではないのです。
では、どうすればドメイン・レベルの再利用性/拡張性が上げられるのか…ということになるのですが、それについては本記事の第2回の方で議論していきたいと思います。
第2回につづく
関連情報:
- 豆蔵ソフト工学ラボ:誤解しがちなモデリングの技:
http://labo.mamezou.com/special/sp_002/ - 豆蔵ソフト工学ラボ:組込み開発のためのモデリングワンポイントレッスン
http://labo.mamezou.com/special/sp_006/ - 豆蔵ソフト工学ラボ:システム開発地図:
http://labo.mamezou.com/special/sp_015/