はじめに
概念モデリングとは、システムのドメインを構成する概念を発見しその属性・振る舞い・関連を定義する活動である。例えば、段階的に理解する O/R マッピングで実例として挙げたシンプルな課題管理システムにはプロジェクト・課題・コメントの 3 概念が登場するが、これらを概念モデルとして表すと以下のようになる。
本来、概念モデリングは DDD の主要な活動の一つである。DDD の Whirlpool プロセスの図を見てみよう。Model は Code Probe と Scenario に挟まれた中心概念であり、常時フィードバックを受けて更新されることが想定されている。
にもかかわらず、日本での DDD 関連の議論においては、概念モデリングが語られることは少なく、レイヤ分割やクラス類型といったアーキテクチャ的側面への偏りが見られる。パターンカタログを眺めればわかる通り、それらの要素は DDD の実践のうちごく一部を占めるに過ぎない。こうした状況がなぜ発生したのかは不明だが、おそらく、概念モデリング活動は業務と密接に結びついているためおいそれと公開できない (「業務上の秘密」仮説)、担当工程や既存システムの都合でモデルに自由に手を出せない状況下において DDD がアーキテクチャ論として転用されている (「DDDDD ドメイン駆動設計駆動設計」仮説)、 DDD 的な活動に実際には習熟していない層が書いた記事が濫造されている (「いかがでしたか」仮説) などの要因が複合的に作用しているのだろう。
本記事では、こうした状況に一石を投じるために、架空の例に基づいて概念モデリングの有用性と楽しさをわかりやすく示すことを試みる。
鬼殺隊の概念モデリング
本記事が概念モデリングの題材として扱うのは、『鬼滅の刃』の鬼殺隊である。もし鬼殺隊に情報システムがあるとしたら、という観点で概念モデリングを進めていく。考察は『鬼滅の刃』原作に基づいている。ちなみに、筆者はこの記事を書くために原作単行本の 1-22 巻を冒頭から全て再読し、また先日 2020-12-04 に発売されたばかりの最終 23 巻も素早く入手して読了した。
始める前に、いくつか留保事項がある。
- いわゆるネタバレをしないよう固有名詞を避ける等の考慮は払ったが、記事の性質上『鬼滅の刃』原作未読の読者にとって本来は巻を追って知るはずの概念に先に出会ってしまう箇所がある
- 本記事の概念モデルは、あくまで架空の情報システムに関するものであり、例えばゲーム化のような領域とは観点が異なる
- 概念の英語命名の多くは List of Demon Slayer: Kimetsu no Yaiba characters - Wikipedia を参考にした (ただし、Hashira → Pillar のように統一感の維持目的で一部変更している)
- UML 要素の用語については筆者が使用している astah* の表記に従った
- 説明の簡便化のために、使用する UML 要素は最小限に絞った (ステレオタイプ・誘導可能性・集約・関連名・制約など多くの要素について説明対象外とした)
剣士 (クラス・属性・メソッド)
まず、情報システムの基本的な機能として、構成員の管理は必須である。剣士 (Slayer) クラスを作ろう。以下、表記は全て UML クラス図である。
剣士には、ID、名前 (name)、説明 (description)、強さ (strength)、状態 (health)、生年月日 (bornOn)、死亡日時 (diedAt) といった属性があるだろう。
UI 上のよくある要件のために、生きているか (isAlive())、戦闘可能か (isHealthy()) といったメソッドが備わっていると便利だろう。
剣士と剣 (関連)
情報システムとしては備品管理にも対応する必要がある。剣 (Sword) クラスを作ろう。剣には、ID、名前 (name)、説明 (description)、色 (color)、強さ (strength)、状態 (health)、製造日時 (manufacturedAt)、製造者 (manufacturedBy) といった属性があり、まだ使える状態か (isHealthy()) といったメソッドがあるだろう。
ここで剣士と剣の関係を考える。剣士が必ず 1 本の剣を持ち、また剣が必ず 1 名の保有者に紐付くのであれば、関連の多重度は以下のように一対一になる。クラスの間の線が関連であり、関連の端についている 1 が多重度である。
だが、上記モデルは鬼殺隊の要件を満たさない。なぜなら二刀流の剣士が存在するからだ。また、鬼殺隊では二刀流止まりだが、他の漫画では両手に加えて口でも剣を操る三刀流の例もある。であれば剣士と剣の関係は一対多関係にするのが妥当だろう。多重度 * は複数のインスタンスが紐付けられることを意味する。さらにイメージしやすいよう関連の Java での実装について先走って例示すると、一対一関係の場合は、Slayer#getSword() で Sword 型インスタンスを一個返すメソッドとなり、一対多関連の場合の場合は Slayer#getSwords() で List<Sword> のようなコレクション型を返すメソッドになる。
剣士側の多重度についても再考の余地がある。上記モデルでは全ての剣がいずれかの剣士に保有されていることが想定されているが、これでは誰にも保有されていない予備の剣を管理できない。多重度 1 ではなく、多重度 0..1 が適切だろう。この場合、実装レベルでは Sword#getSlayer() の関連ナビゲーションは値を返す場合と返さない場合がある。
鬼殺隊では過去に誰かが使っていた剣を別の誰かが引き継ぐ場合もある。さらに、他の漫画でのツインシュートのように、複数の剣士が一本の剣を共有する方向での技の進化も考えられる。とすれば、剣士と剣の関連は多対多にならざるを得ないだろう。
剣士と剣の関連自体にも、保有開始日時 (ownedAt)、保有終了日時 (releasedAt)、保有権限 (authority) などの属性が考えられる。であれば独立の剣保有 (SwordOwnership) クラスを作るのが適切だろう。
上記のような属性を持った多対多関連は、関連クラスを使って以下のようにも表記できる。
剣士の分類 (より複雑な関連)
剣士は階級と技によって分類される。技は「水の呼吸 壱ノ型」のように階層的に識別される。階級 (Grade)、呼吸法 (BreathingStyle)、呼吸技 (BreathingTechnique) クラスを作ろう。クラスの上にある端が折れたピンク色の四角はノートであり、何を書いても自由だ。
上記クラスと剣士との関連について考える。階級と剣士は単純な一対多の関係で問題ないだろう。だが、呼吸についてはそうではなく、ある呼吸法を使用していることがすなわちその系統の呼吸技を全て身につけていることは保証しない。呼吸技習熟度 (BreathingTechniqueProficiency) まで考慮したモデルは以下のようになる。
なお、物語が進むと一人の剣士が複数の呼吸法を身につける特殊な例も登場する。これを一般的にありうる事態として想定するのであれば、剣士と呼吸法の関連は多対多が適切かも知れない。
さらに、剣士と剣については以下のような概念も検討対象となりうるだろう。本記事では深追いせずに省略する。
- 剣士の特性
- 剣士はそれぞれ、鼻が利く、眠ると本領を発揮するといった特性を持っている。これらの特性が各自ばらばらではなく、系統立てて構造的に分類できるのであれば、独立の概念として切り出せる。これらの特性が鬼との相性に大きく関わるのであれば、モデル複雑化のコストは割に合うだろう。
- 刀の型式
- 作中での刀はオーダーメイドの一品物として扱われているが、製造やメンテナンスの効率を考えると最適の方式ではない。おそらく本来は刀の型式のような概念があり、それに基づいたセミオーダーメイドで製造されていると考えるのが自然だろう。
鬼殺隊の構成員 (汎化)
鬼殺隊の構成員は剣士だけではない。全構成員の一元的な管理を効率的に行いたいのであれば、剣士以外について独立にクラスを作る選択肢は取るべきではない。汎化を使って概念を整理することとし、構成員 (Member) クラスと、そのサブタイプとして、柱 (Pillar)、事後処理部隊員 (Pioneer)、刀鍛冶 (Swordsmith)、お館様 (Commander)、元鬼 (ExDemon) などのクラスを作ろう。構成員であれば誰でも持っているはずの属性・メソッド・関連はスーパータイプとしての構成員クラスが持つことになる。それぞれのサブタイプはスーパータイプの属性・メソッド・関連を継承するのに加えて、固有の属性・メソッド・関連を持つ。図上での詳しい記述は省略するが、例えば、柱は警備担当地域などについての固有の属性を、刀鍛冶は担当の刀やそのメンテナンス履歴などに対する固有の関連を持つだろう。
さらに整理の余地がある。上記モデルでは、剣士と柱は、強さや状態などについての属性・メソッドや、剣保有や呼吸技習熟度などの周辺概念に対する関連を、重複して持つことになる。これらを整理するために、中間的な戦士 (Warrior) クラスを括り出そう。
汎化の結果、どこに紐付けるべきか議論が必要な概念もある。例えば階級の付与対象が戦士 (剣士と柱のスーパータイプ) だけなのか構成員全員なのかは作中の記述からは容易には読み取れない。
また、剣についても本来はさらなる汎化が必要である。作中には剣だけでなく鎖鎌のような武器や銃を使う柱や剣士が登場する。本記事では深追いせず省略する。
鬼殺隊の組織 (ツリー構造 その 1)
鬼殺隊の組織構造を読み取ることは難しい。活動内容が警察や消防と類似していることを考えれば、おそらく地方ごとに支部があり、支部の中でも部や課に相当する大小の組織があるはずだ。だが原作ではそうした組織構造がほとんど描かれていない。そもそも、柱に何らかの組織の長としての責務があるのか、事後処理部隊は誰の命令で動いているのかといった基本的な指揮系統もよくわからない。
一旦シンプルな組織モデルを想定することとし、組織 (Organization) クラスを作ろう。組織は入れ子のツリー構造であり、上下の組織への関連を持つ (再帰関連)。構成員はいずれかの組織に所属する。
配属日時の記録・組織内での役職・複数の組織の兼務などについても対応するなら、モデルは以下のように修正される。
鬼 (ツリー構造 その 2)
鬼殺隊は鬼対策を目的とする組織であるため、鬼についての情報も管理する必要がある。鬼は血鬼術を使う。鬼 (Demon) クラスと血鬼術 (BloodDemonArt) クラスを作ろう。複数の血鬼術を使う鬼は存在する。また、鬼殺隊の呼吸とは異なり、血鬼術は鬼一代固有のものである可能性が高い。後者については不確定要素もあるが、取り急ぎ多重度は一対多としよう。また鬼には十二鬼月というシンプルな位階 (Rank) があるため、こちらも追加しておこう。
鬼に人間と同じ個体概念は適用できない。例えば、一体だと思われた鬼が実際は兄と妹によって構成されていたり、体を分裂させて複数剣士の相手をしつつ本体を逃走させたりといった場面が見られる。こうした鬼にも対応するために、Composite パターンを導入しよう。これで一体の鬼が複数の鬼によって構成されている場合も、システム上適切な形で処理できる。
鬼についても何らかの組織構造があっても良さそうなものだが、原作では鬼殺隊のそれ以上に鬼の組織構造は不明確であり、基本的には鬼舞辻無惨の下に階層構造なく各鬼がぶら下がっているように見える。もっと組織的に戦いを進めていれば、鬼殺隊の制圧もより円滑に実行できたのではないだろうか。
戦闘 (活動の記録)
鬼殺隊と鬼の概念が揃ったところで、両者の戦闘についてもシステム上で扱えるようにしよう。まず単純に以下のような戦士 (剣士と柱のスーパータイプ) と鬼が一対一で戦うモデルが考えられる。
だが、上記モデルでは『鬼滅の刃』における戦闘の場面をうまく扱えない。作中における戦闘の多くは複数戦士と複数鬼が対峙するパーティバトルである。そこで、戦士パーティ (WarriorParty) と鬼パーティ (DemonParty) クラスを導入しよう。パーティのライフサイクル (サッカーの先発メンバのように一試合ずつ組み直すのか、継続的なのか) については議論の余地があるが、一旦そこは曖昧にしたまま進めよう。
戦闘で発生した活動 (Activity) についてもシステム上で記録できるようにしよう。過去の振り返りに基づく PDCA サイクルを回せば、より効率的な鬼対策が実現できるはずだ。ざっくりしたイメージを伝えるとサッカー試合速報の構造に近い。活動は戦士に紐付く場合もあれば鬼に紐付く場合もあるだろう。
だが、上記モデルはデータ分析用としては不十分である。各活動が構造化されていないため、例えばある技の効果について分析しようにも、数値的な処理に対応できない。この問題を解決するには、参戦・技の発動・毒付与・能力向上・負傷・退却・死亡のような活動種別ごとに固有の属性を設ける必要がある。
活動種別ごとに固有の属性を設ける一つ目の手段は、活動種別ごとのサブタイプである。こちらの方法では厳密な型付けはできるが、新たな活動種別が登場するたびにサブタイプの追加が必要になる。以下にさまざまなサブタイプの例を挙げる。クラスはおそらくこれでは足りていないし、階層構造についても検討の余地が大きいだろう。さらに、各サブタイプはそれぞれ固有の属性・メソッド・関連を持つことになるだろう。が、詳しい検討は省略する。
活動種別ごとに固有の属性を設ける二つ目の手段は、汎用的な活動種別 (ActivityType) と活動 (Activity) 、さらに効果種別 (OutcomeType) と 効果 (Outcome) の組み合わせによるものである。例えば、活動種別が毒付与の活動が xx:xx に行われ、効果種別が強さ低下の効果マイナス 20% が得られる、といった構造になる。こちらの方法ではいわゆるマスタメンテナンスで活動種別と効果種別を追加できるが、厳密な型付けはできない。一つ目と二つ目のどちらを選ぶべきかは関係者と協議の上判断することになるだろう。
余談だが、作中の鬼殺隊においてこうした情報が正しく管理されていないように見える点は不可解である。数百年以上生きる鬼について偵察記録や過去の戦闘記録が残っていれば、効率的に弱点を突いたり、より相性の良い剣士に相手をさせたりといった対策が可能になる。こうした対策が十分にされていれば、あの人やあの人も命を落とすことはなかったのかも知れない。
概念モデリングの次の活動
概念モデルについてある程度議論した後どうするかについては、成果物的な観点とプロセス的な観点での説明が必要である。
まず成果物的な観点である。身も蓋もない言い方をすると、概念モデルはその後、ドメイン層クラスのソースコードと、データベース物理設計の DDL に化ける。多くの要素は機械的に変換できるが、そうではなく判断が要求される部分は各所に残る。ドメイン層ソースコードについては、適切な型付け (ここで Value Object などのクラス類型談義が登場する) を検討しなければならない。データベース物理設計については、関連・汎化・ツリー構造などをパフォーマンスを考慮した最適な形に落とし込まなければならない。汎化については Single Table Inheritance / Class Table Inheritance / Concrete Table Inheritance を場面に応じて使い分ける必要がある。ツリー構造については、モデルそのままに関連するレコードの ID を持たせる方式は RDBMS では Naive Trees アンチパターンとして知られており、多くの場合で別の方式を検討する必要がある。
次にプロセス的な観点である。初期の概念モデリング時点ではまだ潜在的な機能候補がぼんやりと洗い出された段階であり、あわせて、ユースケースや業務フローの分析を進める必要がある。それらの分析からのフィードバックを受けて、モデルがより洗練されていくこともあるだろう。ユースケースや業務フローが固まってきたら、そこからドメイン層上下の層に属するクラス (Controller、Service、Repository など) の設計が決まってくる。
概念モデリングのためのツール
関係者と上記のような議論をしながら概念モデリングを実施するには、ホワイトボードもしくは astah* のような専用ツールが適している。ホワイトボードは不確定要素が大きい段階での早さ重視の議論に向いており、対して専用ツールはある程度方針が固まった後での網羅的な議論に向いている。筆者は専用ツールとして勤務先では astah* professional を、自宅では astah* UML を使用している。Cacoo 等のドローイングツールの多くにも UML 描画機構が搭載されているが、筆者はほとんど使用していないため評価を控える。
PlantUML のようなテキストから UML 図を生成するツールや、ソースコードからの図の生成は、少なくとも概念モデリング向けにはおすすめできない。概念モデリングにおいてライブ感は意外に重要な特性である。新しい概念をひねくり出し、関連をあれやこれやと付け替え、全体的なレイアウトをざっくり整えるといった作業を関係者と議論しながらその場で素早く行うには、ホワイトボードや専用ツールのほうが適している。テキストやソースコードから間接的に生成すると、会話や思考の流れを妨げてしまう。
そもそも形式として UML クラス図を選ぶ理由についても本来は議論の余地があるかも知れないが、現時点で他により適切なツールは存在しない。E-R 図はメソッドを記述できず、また非エンジニアから見た可読性にやや難がある。独自記法はルール整備のコストを正当化する利点はなく、またツールサポートがない点でも論外である。
参考書籍
-
UML モデリングレッスン
- UML 全体に関する本ではなく、ほぼ一冊通してクラス図 (と、補助的にオブジェクト図・ステートマシン図) による概念モデリングが扱われている。EC サイト等の多彩な具体例からパターンを抽出していく説明がわかりやすい。一冊だけ選ぶとしたらこれ。
-
UML モデリング入門
- 前半では概念モデリングが詳細に論じられ、後半では業務フローやユースケースについてもあわせて解説されている。概念モデリングの成果物がプロジェクト全体の他の成果物とどう関連するのかが理解できる。
-
オブジェクト指向 UI デザイン
- 主題はデザイナー寄りのいわゆる OOUI だが、扱われているオブジェクトモデルはほぼ概念モデルそのもので、開発者が読んでも得るところが多い。概念モデルを UI としてどう表現するのかがイメージできる。
おわりに
以上、『鬼滅の刃』の鬼殺隊を題材として、概念モデリングについて説明した。例自体は奇抜かも知れないが、概念モデリングが何の役に立つのか、そしてどう楽しいのかについて、理解を助ける要素はある程度盛り込んだつもりだ。今後の DDD 談義において、この記事がアーキテクチャ的側面だけでなくモデルに関する議論を活発化する一助となることを期待する。