Skip to content

ADR-003: ドメイン駆動設計(DDD)採用

ステータス

採用

背景

ぷよぷよゲームの開発において、複雑なゲームロジック(連鎖計算、消去判定、重力適用、スコア計算)を適切にモデル化し、保守可能なコードベースを構築する必要がある。CLAUDE.local.mdの指針に従い、中核業務領域として位置づけられるため、ドメイン駆動設計の適用を検討する。

検討事項

DDD適用の判断基準

  1. 業務領域の複雑さ: ぷよぷよのゲームルールは複雑で、多数の相互作用がある
  2. ビジネス価値: ゲームロジックはアプリケーションの核心価値
  3. 変更頻度: ゲームバランス調整、新機能追加が想定される
  4. 専門知識: ぷよぷよ特有のドメイン知識(連鎖、全消し等)

従来の開発手法との比較

Anemic Domain Model (従来手法)

// データのみのモデル
interface Puyo {
  id: string;
  color: PuyoColor;
  x: number;
  y: number;
}

// 外部のサービスクラスでロジック処理
class PuyoService {
  checkConnectedPuyos(puyos: Puyo[], targetPuyo: Puyo): Puyo[] {
    // 複雑な連鎖ロジック
  }
}

問題点: - ビジネスロジックが分散 - データとロジックの分離によるモデル貧血化 - ドメイン知識の表現が困難

Rich Domain Model (DDD手法)

// ドメイン知識を含むモデル
class Field {
  private grid: (Puyo | null)[][];

  findConnectedPuyos(position: Position, color: PuyoColor): PuyoGroup {
    // ドメインロジックを内包
  }

  detectErasableGroups(): PuyoGroup[] {
    // ゲーム特有のルールを表現
  }
}

利点: - ドメイン知識の明確な表現 - ビジネスロジックの集約 - モデルとコードの一致

決定

ドメイン駆動設計(DDD)の戦術的パターンを採用する

採用する戦術的パターン

  1. エンティティ (Entities)
  2. Game: ゲームセッション
  3. Field: ゲームフィールド

  4. 値オブジェクト (Value Objects)

  5. Puyo: 個々のぷよ
  6. Position: 座標
  7. Score: スコア
  8. PuyoPair: 組ぷよ

  9. 集約 (Aggregates)

  10. Game集約: ゲーム状態の一貫性保証
  11. Chain集約: 連鎖処理の整合性管理

  12. ドメインサービス (Domain Services)

  13. ChainDetectionService: 連鎖検出ロジック
  14. GravityService: 重力計算ロジック
  15. ScoreCalculationService: スコア計算ロジック

  16. ドメインイベント (Domain Events)

  17. PuyoPlacedEvent: ぷよ配置イベント
  18. ChainOccurredEvent: 連鎖発生イベント
  19. GameOverEvent: ゲーム終了イベント

  20. リポジトリ (Repositories)

  21. GameRepository: ゲーム状態の永続化
  22. ScoreRepository: スコア履歴の管理

ドメインモデル設計

境界づけられたコンテキスト

┌─────────────────────────────────────┐
│        ゲームプレイコンテキスト        │
├─────────────────────────────────────┤
│ ・ゲームセッション管理                │
│ ・ぷよ操作・配置                     │
│ ・連鎖・消去システム                 │
│ ・フィールド状態管理                 │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│       スコアリングコンテキスト         │
├─────────────────────────────────────┤
│ ・スコア計算                        │
│ ・ハイスコア管理                     │
│ ・統計・記録                        │
└─────────────────────────────────────┘

ユビキタス言語

日本語用語 英語用語 定義
ぷよ Puyo 色付きのゲーム要素
組ぷよ PuyoPair 2個セットの操作対象ぷよ
フィールド Field 6×12のゲーム盤面
連鎖 Chain 消去による連続反応
全消し AllClear 全ぷよ消去によるボーナス
窒息 Suffocation 配置不可能によるゲーム終了

集約の設計

Game集約

class Game {
  private constructor(
    private readonly id: GameId,
    private field: Field,
    private currentPuyo: PuyoPair,
    private nextPuyo: PuyoPair,
    private score: Score,
    private state: GameState
  ) {
    this.ensureInvariants();
  }

  handleInput(command: InputCommand): DomainEvent[] {
    // 不変条件を保ちながら状態変更
    // ドメインイベントの発行
  }

  private ensureInvariants(): void {
    // ドメインルールの検証
  }
}

不変条件(Invariants)

  1. ゲーム中は必ず現在のぷよが存在する
  2. フィールドの範囲内にのみぷよを配置できる
  3. スコアは負の値にならない
  4. 連鎖数は論理的な上限を超えない

ドメインサービスの責務

ChainDetectionService

class ChainDetectionService {
  detectChains(field: Field): ChainResult {
    // 1. 消去対象グループの特定
    // 2. 連鎖の進行計算
    // 3. 最終的な連鎖結果の生成
  }

  private findConnectedGroup(
    field: Field, 
    startPos: Position, 
    color: PuyoColor
  ): PuyoGroup {
    // 深度優先探索による連結ぷよ検索
  }
}

実装戦略

段階的実装アプローチ

  1. Phase 1: コアドメインモデル
  2. 基本エンティティ・値オブジェクトの実装
  3. 不変条件の定義・実装
  4. 基本的なドメインサービス

  5. Phase 2: 集約とイベント

  6. 集約ルートの実装
  7. ドメインイベントの設計・実装
  8. イベント駆動の状態変更

  9. Phase 3: 高度なパターン

  10. 仕様パターンの導入
  11. ドメインイベントハンドラー
  12. サガパターン(複雑な処理フロー)

テスト戦略

ドメインモデルテスト

describe('Game', () => {
  test('ぷよを配置した時に適切な状態変化が起こること', () => {
    // Given: 初期状態のゲーム
    const game = GameFactory.createNewGame();

    // When: ぷよ配置コマンドを実行
    const events = game.handleInput(new PlacePuyoCommand(position));

    // Then: 期待される状態変化とイベント発行
    expect(events).toContainEqual(
      expect.objectContaining({
        type: 'PuyoPlacedEvent',
        position: position
      })
    );
  });
});

結果

期待される効果

  1. 表現力: ビジネスルールがコードで明確に表現される
  2. 保守性: ドメイン知識の変更が局所化される
  3. テスタビリティ: ドメインロジックが独立してテストできる
  4. 拡張性: 新機能追加時の影響範囲が明確

メトリクス

  • 循環的複雑度: 平均5以下を目標
  • テストカバレッジ: ドメイン層95%以上
  • ドメイン純粋性: 外部依存0%(ドメイン層)

リスク・制約

潜在的リスク

  1. 初期実装コスト: 単純なCRUDより開発時間増加
  2. 学習コスト: DDD概念の理解が必要
  3. 過度なモデリング: 不要な複雑性の導入リスク

対策

  1. 段階的導入: 最小限のDDDパターンから開始
  2. 継続的リファクタリング: ドメイン理解の深化に応じて改善
  3. 実践的アプローチ: 理論より実装価値を重視

関連ADR

  • ADR-001: アーキテクチャ選定
  • ADR-002: フロントエンド技術スタック選定
  • ADR-004: テスト戦略
  • ADR-005: 状態管理戦略

日付: 2025-08-12
作成者: Claude Code
レビュー者: 開発チーム・ドメインエキスパート
次回見直し: 2025-11-12(3ヶ月後)