集約・トランザクション・整合性 — Q&Aサービスを題材にしたドメインモデリング設計メモ

知恵袋ライクなQ&Aサービスを題材に、バリデーションの置き場所、集約とトランザクションの関係、結果整合性のコスト、複数集約をまたぐ判断フローをまとめた設計メモ。

1. バリデーションの置き場所(3層)

性質で分類すると、置き場所が自然に決まる。

種類内容置き場所
形式的バリデーションメール形式・文字数・必須外側(ファクトリ / DTO)
ドメイン不変条件そのモデルが常に守るべきルールモデル(集約)
文脈依存ルール権限・レート制限・他集約依存ユースケース

判断の問い

原則:ドメイン不変条件はモデルに閉じ込め、「壊れたモデルは生成できない」状態にする(フィールド非公開+ファクトリ経由生成)。

アンチパターン


2. 集約 vs トランザクション

集約トランザクション
レイヤードメイン(論理)インフラ(技術)
目的整合性の境界を定義原子性を保証
決め方モデリングで先に決める集約に合わせて実装
またぎ1集約に収める技術上はまたげるが避ける

標語:集約は「ここは一瞬たりとも矛盾させない」という宣言。トランザクションはそれを守る道具。だから 1集約 ≒ 1トランザクション になるが、集約のほうが先


3. 結果整合性のコスト

「分ければ疎結合」と綺麗な顔で来るが、強整合ならDBがやってくれた面倒事を全部自前で引き受ける

結果整合性はタダじゃない。安易に集約を分けすぎると無駄に地獄を背負う。


4. 複数集約をまたぎたくなったときの対処

まず原因を切り分ける

判断フロー(上ほど安い/できるだけ上で止める)

  1. いつも一緒に変わって一瞬もズレちゃダメ? → 集約を統合
  2. 更新じゃなく表示のためのまたぎ? → CQRSの読みモデル
  3. 頻度低い & 同一DB & 競合しない? → 割り切って同一Txで複数集約を更新
  4. 疎結合・スケールが本当に必要? → Outboxで結果整合
  5. 複数サービスにまたがる長い業務フロー? → Saga

知恵袋での当てはめ

ケース判定対処
Questionの状態 と bestAnswerID同じ集約またがない(最初から統合)
ベストアンサー選定 → 回答者スコア+10別集約・ズレ許容まず同一Tx割り切り、競合し始めたらOutbox
質問一覧に回答者名・回答数を表示読み取りのまたぎCQRSの読みモデル

5. 全体を貫く指針

段階的アプローチ

  1. モジュラモノリス(集約は論理的に分け、物理は同一DB・同一Tx)
  2. 同期的ドメインイベント(プロセス内、同一Tx内ハンドラ)
  3. 本当に必要な箇所だけ Outbox + メッセージキューに昇格

補足:ステートマシンによるモデリング

状態遷移に明確な制約がある集約(知恵袋ならQuestion)は、sealed interface 風の型でステートマシン表現するとうまみが出る。

← Back to all posts