ドメイン駆動設計の実践
~ゲーム開発にどう活用するか~
ギルドワークス 増田 亨
TECH x GAME COLLEGE #1 2018-8-22
2018/8/22 1
自己紹介
コード例 :https://github.com/system-sekkei/isolating-the-domain
ブログ:システム設計日記 http://masuda220.jugem.jp/
https://www.slideshare.net/masuda220/
22018/8/22
本日の内容
ドメイン駆動設計の基礎知識
ゲーム開発への活用の可能性
ゲーム開発に取り入れる時の障害
障害を乗り越えていくヒント
32018/8/22
ドメイン駆動設計の基礎知識
What is Domain-Driven Design
42018/8/22
ドメイン駆動設計とは?
52018/8/22
ソフトウェア設計の
考え方とやり方の一つ
62018/8/22
ソフトウェア設計の一般原則
関心の分離
Separation of Concerns
モジュール構造
modular construction
全体を複数の関心事に分解する
それぞれの関心事を独立したモジュールとして開発
モジュールを組み合わせて全体を構築する
72018/8/22
ドメインロジックに焦点を合わせる
オブジェクト指向でモジュール化する
インクリメンタルに設計する
ドメイン駆動設計
2018/8/22 8
ドメイン駆動設計では、どのように関心を分離するか?
ドメイン駆動設計では、どのようにモジュール構造を組み立てるか?
ドメインロジックに焦点を合わせる
どういうこと?
2018/8/22 9
関心事の違い
ドメイン駆動設計 従来の設計
ドメインロジックに焦点をあわせる 入出力に焦点をあわせる
主たる関心事 主たる関心事
ドメインの状況を表す値の種類 ユーザインタフェース
値を使った計算ロジック/判定ロジック データベース
計算結果/判定結果の表現方法 通信
2018/8/22 10
ドメインロジックの構成要素
業務アプリケーション分野 ゲーム分野
ビジネスを構成する概念(用語)
顧客、商品、
販売、出荷、請求、…
ゲームを構成する概念(用語)
ゲームの世界観、キャラクタ設定、
ストーリーに登場する言葉
ビジネスの状況を表現する値
金額、数量、日付、日数、…
会員区分、商品区分、取引区分、…
ゲームの状況を表現する値
レベル, ゴールド,HP, MP, SP, Exp, …
アイテム種類,武器種類,防具種類,…
値を使った計算や判定
金額計算ルール、日数計算ルール、…
バトル開始条件の判定ルール、
ダメージやポイントの計算ルール
勝敗の判定ルール, …
2018/8/22 11
ドメインロジック以外の関心事
業務アプリケーション分野 ゲーム分野
画面の入出力
データベースアクセス
API 通信
…
ビジュアルデザイン
サウンドエフェクト
インタラクションデザイン
…
アプリケーション開発には必須要素
ドメインロジックとは別の関心事
ドメイン駆動設計では、ドメインロジックに従属すべき関心事
2018/8/22 12
ドメインロジックに焦点を合わせる理由
13
1. ソフトウェアの複雑さの原因は、
ドメインロジック(計算ロジックと判定ロジック)にある
2. ドメインロジックと入出力が混在していると、
ドメインロジックの全体像や構造が見えてこない
3. 入出力の関心事を分離して、ドメインロジックだけを対象にすると、
ドメインロジックの輪郭や構造がはっきりしてくる
4. ドメインロジックの輪郭や構造が見えてくると、計算ロジックと判定ロ
ジックの発見が進み、ロジックの整理がやりやすくなる
5. 計算ロジックと判定ロジックが整理できると、入出力の記述もシンプル
になる
6. ソフトウェア全体が、見通しがよくなり、変更が楽で安全になる
2018/8/22
ドメインロジックの関心事を
ソフトウェアの構造として
入出力から明確に分離する
2018/8/22 14
入出力+ドメインロジック
プレゼンテーション層
データソース層
アプリケーション層
15
入出力処理
ゲームルールの実行
次のアクションの指示
画面入出力
Web API
データベース入出力
メッセージ送信
ゲームの入出力設計+機能設計
計算ルール
判定ルール
ゲームロジックの分析設計実装
バトル開始条件の判定ルール、
ダメージやポイントの計算ルール
勝敗の判定ルール, …
計算・判定ルールの記述を
独立したモジュールに
分離する
2018/8/22 15
ゲーム開発でのメリット
• 計算ロジック、判定ロジックの記述が整理できる
– 同一ロジックの重複記述の防止(変更容易性)
– ロジックの組み合わせ方の見通しをよくできる
• 世界観/キャラクター設定/シナリオ構成と、計算ロジッ
ク/判定ロジックの記述を直接的に関係づける
– 全体が整合する
– 変更の対象個所、影響範囲を特定しやすい
• 入出力処理の記述がシンプルになる
– 計算や判定の記述を、ドメイン層に外だしできる
2018/8/22 16
デモ
• 入出力から分離したゲームロジックだけのモジュールとは、
どういうものか?
• ローグ classic
– ビジュアル/サウンド/インタラクション、どれも貧弱
– ゲームロジック(ゲームの概念/状況を表現する値/その値を
使った計算と判定)を表現したコードが大半を占める
• ドメインロジック+CLIの対話式のデバッガみたいなもの
– ユーザインタフェースが貧弱なので、もっと面白いゲームにす
るためには、ゲームロジックに焦点を合わせた改良になる
2018/8/22 17
オブジェクト指向でモジュール化する
どういうこと?
2018/8/22 18
ソフトウェアのモジュール
• コードを扱いやすいかたまりにグループ化し
て、グループごとに別ファイルで記述する
• モジュール間(ソースファイル間)の依存関係
を小さくする/少なくする
2018/8/22 19
モジュール化の2つのアプローチ
どういう観点でソースファイルを分割するか?
入出力処理の単位ごと
or
計算する値の種類ごと
2018/8/22 20
入出力単位のモジュール化
• 入力を起点に、出力するための処理手順の単位
でファイルを分ける
• 機能分割し、機能ごとに入力と出力を定義する
• 出力に必要な一連の処理を時系列に記述する
(手続き型、スクリプト型)
• 共通処理手順(サブルーチン)を集めたファイル
を作る
2018/8/22 21
値の種類ごとのモジュール化
• 計算や判定に登場する値(の種類)を見つける
– レベル、HP, MP, SP, Exp.、…
– 武器の種類、防具の種類、敵キャラクターの種類、…
– ダメージの判定結果、勝敗の判定結果、…
• 計算する値の種類ごとに、必要な計算(演算)を整理する
– 一致/不一致の判定
– 大小の判定
– 境界値(最大/最小)の判定
– 足し算、引き算
– 掛け算
– 割り算
– 値のリテラル表現への変換
– リテラル表現から値への変換
2018/8/22 22
値の種類ごとのモジュール化
• 計算や判定に登場する値(の種類)を見つける
– レベル、HP, MP, SP, Exp.、…
– 武器の種類、防具の種類、敵キャラクターの種類、…
– ダメージの判定結果、勝敗の判定結果、…
• 計算する値の種類ごとに、必要な計算(演算)を整理する
– 一致/不一致の判定
– 大小の判定
– 境界値(最大/最小)の判定
– 足し算、引き算
– 掛け算
– 割り算
– 値のリテラル表現への変換
– リテラル表現から値への変換
値の種類は多い
計算の種類は少ない
2018/8/22 23
値の種類に焦点を合わせる
• ドメインロジックを構成する要素
– 状態を表す値の種類
– 値を使った計算ロジック、判定ロジック
– 計算結果、判定結果を表す値の種類
• モジュール分割→値の種類ごとにソースファイルを分ける
– レベル型、HP型、MP型、SP型、Exp.型、…
– ダメージ型、勝敗型、…
– 武器種類型、防具種類型、モンスター種類型、…
– アイテム一覧型、装備一覧型、敵モンスター群型、...
• それぞれの型(値の種類)に対してあると便利なメソッドを定義する
– その型でやりたい計算・判定(の名前)
– 計算や判定に必要なパラメータ(の型)
– 計算結果、判定結果を返す時の型
public Hp gain(Hp bonus) { … }
2018/8/22 24
ゲームロジックを
値の種類ごとに整理する
↓
型の発見
↓
型をclass構文で記述する
↓
実行時にオブジェクトとして生成する
↓
必要な計算と判定を実行する2018/8/22 25
オブジェクト指向
262018/8/22
オブジェクト指向のモジュール化
考え方とやり方を学ぶ
2018/8/22 27
オブジェクト指向のモジュール化
考え方とやり方を学ぶ
• 値オブジェクト
• 区分オブジェクト
• コレクションオブジェクト
• …
2018/8/22 28
オブジェクト指向のモジュール化
考え方とやり方を学ぶ
• 値オブジェクト
• 区分オブジェクト
• コレクションオブジェクト
• …
2018/8/22 29
オブジェクト指向のモジュール化
考え方とやり方を学ぶ
• 値オブジェクト
• 区分オブジェクト
• コレクションオブジェクト
• …
ガチでやりたい人→
2018/8/22 30
インクリメンタルに設計する
どういうこと?
2018/8/22 31
最初から良い設計はできない
開発を始める時は対象領域の知識が貧弱
最初に書いたコードは、
後から見直すともっと良い書き方が見つかる
最初の要求はあいまいで、
時間とともに具体的で詳細になっていく
要求は、時間とともに変化する
2018/8/22 32
インクリメンタルに設計する
対象領域の知識を少しずつ広げ、掘り下げる
最初に書いたコードを見直しながら改善する
時間とともに具体的で詳細になっていく要求を、
時間とともにコードに反映する
時間とともに変化する要求を、
時間とともにコードに反映する
2018/8/22 33
インクリメンタルに設計する
基本的な値の種類を見つける
↓
値と値を組み合わせたロジックを置く
場所(第三のクラス)を見つける
↓
値の種類(型)をグルーピングする
342018/8/22
値と値を組み合わせたクラス
35
• ターン型
– ターンごとの状況を表す値を集めた型
– ターン before の結果を計算して、ターン after を返す
– ターン after の結果を判定して、判定結果を返す
• バトルコンテキスト型
– バトル開始時の状態を表現した型
– バトルやターンの計算・判定に必要な基本情報を表現した値の集合
• バトル型
– 進行中のバトルの状態を表す値を集めた型
– ターン型オブジェクトの履歴を持つ
– バトルの結果を判定するロジックを持つ
ターン方式のバトルのひとつの設計アイデア
2018/8/22
値の種類(型)のグルーピング
• ポイント型
– HP型、MP型、SP型に共通のメソッドの定義
• アイテム型
– 食料型、薬型、巻物型、…
class 所持品 {
List<アイテム> items;
…
所持品 add( アイテム ) { items.add(アイテム) ; }
所持品 remove(アイテム) { item.add(アイテム); }
}
型のグルーピングのひとつの設計アイデア
2018/8/22 36
インクリメンタルに設計する
• ゲームロジックの知識を広げながら深掘りしていく
– 世界観、キャラクタ設定、シナリオ、…
– ゲームルール
• 獲得した知識をコードに反映する
– 計算や判定する値の種類(型)に焦点を合わせる
– 値の種類ごとファイルを分割し、必要な計算ロジックを集める
• コードの書き方を改善する
– 型の発見、クラスの抽出
– ロジックの改善(引数の型、返す型)
– ロジックの移動
– 型と型を組み合わせた型の発見
– 組み合わせ方の改善
2018/8/22 37
ゲーム開発を
ドメイン駆動設計で進める時の障害
2018/8/22 38
障害
1. そうはいっても入出力
• ビジュアル命、サウンド命
• インタラクション命
• 通信が~
• データベースが~
2. フレームワーク
• 入力イベントのハンドラー
• 入力を起点に出力までの処理手順をスクリプティングする道具
3. 開発プロセス
• フェーズ分けと分業
• コードを書き始めるタイミング/変更のリズム
• コード変更の理由の混乱(モデルの変更? ビューの変更? 両方?)
2018/8/22 39
いくつかのアプローチ
• ドメイン駆動設計に思い切って飛び込む
– 少数精鋭かつ小規模で、徹底してドメイン駆動設計でやってみる
– 学びのための実験プロジェクト
– 効果は大きいが…
• 従来のやり方に少しずつ、こっそりと
– HPの単純な足し算・引き算のロジックをHP型に
– 勝敗判定を true/false から enum 勝敗型に
• 数値の計算ロジックは、必ず独自の型にラッピングする
• コレクションの操作ロジックは必ず独自の型にラッピングする
• boolean (true/false) 禁止 判定結果は必ず enum 型で宣言する
2018/8/22 40
いくつかのアプローチ
• ドメイン駆動設計に思い切って飛び込む
– 少数精鋭かつ小規模で、徹底してドメイン駆動設計でやってみる
– 学びのための実験プロジェクト
– 効果は大きいが…
• 従来のやり方に少しずつ、こっそりと
– HPの単純な足し算・引き算のロジックをHP型に
– 勝敗判定を true/false から enum 勝敗型に
• 数値の計算ロジックは、必ず独自の型にラッピングする
• コレクションの操作ロジックは必ず独自の型にラッピングする
• boolean (true/false) 禁止 判定結果は必ず enum 型で宣言する
実際にコードを書いて
その結果を確認しながら、議論し、決めていく
2018/8/22 41
まとめ
2018/8/22 42
ソフトウェア設計の一般原則
関心の分離
Separation of Concerns
モジュール構造
modular construction
全体を複数の関心事に分解する
それぞれの関心事を独立したモジュールとして開発
モジュールを組み合わせて全体を構築する
432018/8/22
ドメインロジックに焦点を合わせる
オブジェクト指向でモジュール化する
インクリメンタルに設計する
ドメイン駆動設計
2018/8/22 44
ドメイン駆動設計では、どのように関心を分離するか?
ドメイン駆動設計では、どのようにモジュール構造を組み立てるか?
設計のアプローチ
ドメイン駆動設計 従来の設計
ドメインロジックに焦点を合わせる 入出力に焦点を合わせる
オブジェクト指向でモジュール化 手続き型でモジュール化
インクリメンタルに設計する アップフロントに設計する
違いを理解した上で、自分たちの設計スタイルを議論し決めていく
実際にコードを書きながら2018/8/22 45

ドメイン駆動設計をゲーム開発に活かす