ドメインから入るか、特性から入るか ─ 二つの流派
DB を設計しようとするとき、現代の現場には二つの流派が並走している。どちらも論理的に一貫しており、どちらも実務で動いている。だが、初めて両者に触れるとき、それらは正反対のことを言っているように見える。
流派 A:ドメイン駆動 ─「DB は詳細」
代表的な発言:
- Robert Martin『Clean Architecture』第 30 章のタイトル: “The Database Is a Detail”(該当章)
- Eric Evans『Domain-Driven Design』: “The model is not the database”
- Vaughn Vernon『実践ドメイン駆動設計』: 永続化は技術詳細であり、Repository で隠蔽すべき
主張の核心:
アーキテクチャの中心は ビジネスのモデルであって、データを永続化する仕組みは詳細である。詳細はあとから差し替えられるべきで、アーキテクチャ要素として扱ってはならない。
この流派は、過去 30 年の RDB 一強時代に対する反動として育った。「DB から考え始めると、テーブルがビジネスを支配する」── 結果、ドメインロジックが SQL に滲み出し、テストできなくなり、変更コストが膨らむ。これを避けるため、Aggregate / Bounded Context / Repository という抽象を立て、永続化を意識的に下層へ追いやる。
実装上の現れ方:
// ドメイン層: DB を知らない
class Order {
constructor(
public readonly id: OrderId,
public readonly items: OrderItem[],
) {}
addItem(item: OrderItem): Order { /* ... */ }
}
// インターフェース層: 永続化の契約
interface OrderRepository {
findById(id: OrderId): Promise<Order | null>;
save(order: Order): Promise<void>;
}
// インフラ層: ここで初めて DB が登場
class PostgresOrderRepository implements OrderRepository { /* ... */ }
「PostgresOrderRepository は DynamoOrderRepository に差し替えても良い」── これがドメイン駆動の理想図。
流派 B:特性駆動 ─「ワークロードから始めろ」
代表的な発言:
- Werner Vogels (AWS CTO): “One size doesn’t fit all” ─ AWS の “purpose-built databases” 戦略
- Rick Houlihan (DynamoDB の元 Principal Engineer): “What is accessed together should be stored together”(公式講演)
主張の核心:
ワークロード(アクセスパターン・スループット・レイテンシ要件)が DB を選び、DB の特性が schema を決める。ドメインは schema の上に乗るのであって、schema を強制するものではない。
この流派は、データセンタースケールのアプリケーション(AWS / Google / Netflix)から育った。「RDB を最初に決めて正規化から始める」古典的な流儀では、書き込み 1 万 req/s で破綻する、地理分散で遅延が爆発する、スキーマ変更が運用を止める ── そうした現実から、「先にワークロードを定義し、それに合う DB を選ぶ」というアプローチが立ち上がった。
実装上の現れ方:
// アクセスパターンを先に列挙
// 1. ユーザー ID で注文一覧を取得(最新 10 件、低レイテンシ)
// 2. 注文 ID で注文詳細を取得(ホットパス、ms 以内)
// 3. 商品 ID で過去 30 日の注文を集計(バッチ、分単位 OK)
// schema はパターンに従う(例: DynamoDB)
// PK = USER#<userId> SK = ORDER#<orderId>
// GSI: PK = ORDER#<orderId> SK = ORDER#<orderId>
// 集計はストリームで OLAP DB に流す
ドメインモデルは、この schema の上で読み解かれる。
両派は対立しているのか
ここで多くの読者が立ち止まる。どちらの流儀が正しいのか?
第一印象は対立に見える。
| 観点 | ドメイン駆動 | 特性駆動 |
|---|---|---|
| 起点 | Aggregate / Bounded Context | ワークロード / アクセスパターン |
| DB の位置 | 詳細、最後に決める | 主役、最初に決める |
| schema の主 | ドメイン | DB の特性 |
| 抽象化 | Repository で隠蔽 | しない(schema を直接扱う) |
だが注意深く読むと、両派は同じレイヤーで対立しているのではない。
- ドメイン駆動が答えているのは “何を表現するか”
- 特性駆動が答えているのは “どう実装するか”
両者は同じ設計の異なる断面を扱っている。Aggregate を引くこととPartition Key を選ぶことは、競合関係ではなく、合流関係にある。
ただし合流地点で摩擦が起きる。Aggregate の整合性境界が、DB のトランザクション境界と一致するとは限らない。Repository の save() が atomic である保証は、永続化技術の特性に依存する。
このシリーズが扱うのは、まさにこの合流地点の作法だ。
graph TB
subgraph "ドメイン駆動の世界"
A[Bounded Context] --> B[Aggregate]
B --> C[Repository インターフェース]
end
subgraph "特性駆動の世界"
D[Workload] --> E[DB 種別]
E --> F[Schema / Partition Key]
end
C -.合流地点で摩擦.-> F
style A fill:#e1f5ff
style D fill:#ffe1e1
この章の要点
- ドメイン駆動(Evans / Vernon / Martin)は「DB は詳細」と主張し、永続化を抽象化で隠す
- 特性駆動(Vogels / Houlihan)は「ワークロードから始めろ」と主張し、DB を起点に置く
- 両派は対立に見えるが、答えているレイヤーが違う
- 摩擦が起きるのは「Aggregate の整合性境界」と「DB のトランザクション境界」が一致しない瞬間
次章への問いかけ
両派は別レイヤーの話だと整理した。だが、ドメイン側の “詳細” が現実には牙を剥く。それはなぜか。
まずドメイン駆動の地図を立てて、Aggregate と Bounded Context が何を要求しているかを見る。