「ドメイン駆動設計(DDD)は現実世界の業務にしか使えない」
そんなふうに誤解している人はいないだろうか?
たしかに、DDDは現場の業務フローやビジネスルールをソフトウェアに落とし込むための設計手法として広く知られている。しかし近年では、ゲーム開発、メタバース、SF世界観を扱うアプリケーションなど、“現実には存在しないドメイン”を扱うプロジェクトが増えている。
では、現実に存在しないドメインをどうやって設計すればよいのか?
この記事では、ファンタジーRPGの「魔法戦闘システム」を具体例に、DDDをどう適用していくかを詳しく解説する。
現実にない世界では「物語」がドメインの出発点になる
現実に存在しないドメインには、業務知識も制度も存在しない。
だが、物語がある。
たとえば、以下のような設定があるとしよう:
- プレイヤーは魔法使い。戦闘時に「魔法」を詠唱し、敵にダメージを与える。
- 魔法には「属性(火・水・風・土)」「詠唱時間」「消費MP」がある。
- 敵には「属性耐性」や「状態異常耐性」が存在し、組み合わせに応じて効果が変化する。
- 詠唱中に敵の攻撃を受けると、詠唱がキャンセルされ、MPは半分しか戻らない。
このような“ゲームの中の物語”は、現実には存在しないが、その世界における真実=ドメインルールである。
DDDの目的は、そのルールを正しくモデルとして設計し、変更や拡張に強い形で実装することだ。
ステップ1:ユビキタス言語を物語から抽出する
まず行うべきは、登場する用語の意味を「定義」し、チーム全体で共通言語とすることだ。これは、ドメインが架空であっても変わらない。
例:
- 「魔法」=詠唱により発動し、敵や味方に効果を与える能力。属性・消費MP・詠唱時間を持つ。
- 「詠唱」=魔法を発動するための前段階。一定時間が必要で、詠唱中に攻撃されるとキャンセルされる。
- 「属性相性」=魔法の属性と敵の耐性によって、効果倍率が変動する。
このように概念の意味を明確にし、用語を設計対象に落とし込むことが、ユビキタス言語の構築であり、DDDの土台となる。
ステップ2:エンティティ・値オブジェクト・ドメインサービスで設計する
抽出したユビキタス言語をもとに、ドメインモデルを構築する。
🔹 エンティティ:状態と識別子を持つオブジェクト
-
Mage(魔法使い)
: MPや習得魔法のリスト、詠唱中ステータスなどを保持 -
Enemy(敵)
: 属性耐性や状態異常の情報を持つ
🔹 値オブジェクト:不変の属性値
-
Magic
: 属性、消費MP、詠唱時間などを持つ不変オブジェクト -
Element
: 火・水・風・土などの属性 -
CastingTime
: 詠唱にかかる時間(秒)
🔹 ドメインサービス:複数のオブジェクトにまたがるビジネスルール
-
MagicCastingService
: 詠唱成功判定や詠唱キャンセル処理などを担当 -
ElementalEffectCalculator
: 属性相性に応じたダメージ倍率の算出
ステップ3:ストーリーからユースケースを定義する
ストーリーをベースに、具体的なユースケースを設計する。
ユースケース例①:「魔法を詠唱する」
func (m *Mage) Cast(magic Magic, target Enemy) error {
if !m.HasSufficientMP(magic) {
return errors.New("MPが足りません")
}
result := magicCastingService.BeginCasting(magic, m)
if result.Failed() {
return errors.New("詠唱中にキャンセルされました")
}
damage := elementalEffectCalculator.Calculate(magic, target)
target.ApplyDamage(damage)
m.ConsumeMP(magic.Consumption())
return nil
}
ユースケース例②:「詠唱がキャンセルされた場合のMP返還」
- 詠唱中に敵から攻撃を受けた
- 詠唱失敗処理をドメインサービスで行い、MPの半分を返還
- Mageエンティティが
RollbackMP()
を呼び出す
架空世界でも「整合性」と「再利用性」は保たれる
DDDは、あくまでドメイン知識を中心にソフトウェアを設計する手法だ。
現実にあるかないかは本質ではなく、ルールがあり、一貫性のある振る舞いがあるかどうかが重要である。
むしろ、現実の制約に縛られない架空世界だからこそ、DDDを使って構造を整える価値が大きい。複雑な条件分岐やルールも、モデルとして整理され、テスト可能なコードになる。開発チーム全体で「魔法とは何か」を共有できる構造は、拡張性・保守性に直結する。