[モダンアプリ勉強会] DDDのことはじめ
by
坂本 勇人
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
DDDのことはじめ 2026/07/27 坂本 勇⼈
Slide 2
Slide 2 text
⾃⼰紹介 ● 名前 ● ● ● 坂本 勇⼈(Sakamoto Yuto) 所属 ● クラウド事業統括本部 ● モダンアプリコンサルティングチーム 普段のお仕事 ● お客さんのスクラムに参加して要件定義から開発までのお⼿伝いをしてます ● 実装するのが好きですが、アーキ考えてるのも好き
Slide 3
Slide 3 text
本⽇のスコープ
Slide 4
Slide 4 text
はじめに 本⽇は⼩難しいことを、できるだけ⼩難しくなく話すつもりです ⼩難しく感じる部分もあるかもしれませんが、 できるだけわかりやすく説明できるよう頑張ります 構成要素にも触れますが、思想やメリットに重きを置いてます これから⼊⾨したいという⽅を対象としています
Slide 5
Slide 5 text
⽬次 1. オープニング 2. ドメインとは / DDD とは 3. メリット → 本当に守れる?(⼊⼝‧永続化‧Repository) 4. いつ DDD する? 5. 構成要素(Entity → Value Object → Aggregate) 6. 集約の切り⽅ 7. クロージング
Slide 6
Slide 6 text
DDDのイメージ DDDに関して - よく聞くけど難しそう - 学習コスト⾼そう - 維持するの⼤変そう こんなイメージありませんか?
Slide 7
Slide 7 text
DDD できちんと設計するのは難しい
Slide 8
Slide 8 text
なにが難しい? DDD の考え⽅(概念構造として捉える)は共通でも、 設計の答えは⼀つに決まらない (画⼀的な正解がない)
Slide 9
Slide 9 text
なにが難しい? 他にも ● エンジニア間でルールとして徹底するのが難しい ● 技術的課題解決との両⽴には、DDD だけでは⾜りないことも多い
Slide 10
Slide 10 text
だけど...
Slide 11
Slide 11 text
「ドメインを概念構造として捉える」という考え⽅は役にたつ
Slide 12
Slide 12 text
本⽇持ち帰って欲しいもの ● DDD ってどういうもの? ● DDD のメリット ● DDD を始めるための構成要素 ○ Entity ○ Value Object ○ Aggregate(集約)
Slide 13
Slide 13 text
今⽇話さないこと 戦略的 DDD ● サブドメイン ● Bounded Context 集約を跨ぐようなロジックの実現⽅法 ● Domain Service ● Domain Event
Slide 14
Slide 14 text
今⽇話さないこと その他の周辺技術‧実装 ● Repository の具体実装(ORM‧SQL‧UoW など) ● Clean Architecture や CQS などとの組み合わせ
Slide 15
Slide 15 text
考え⽅とメリット
Slide 16
Slide 16 text
ドメインってなに? ビジネス⽤語からイメージする 「お客様のビジネス全体に関する知識」 とは範囲が異なる
Slide 17
Slide 17 text
ドメインってなに? 業界の知識のすべてをコードに⼊れるわけではない
Slide 18
Slide 18 text
ドメインってなに?(例) 例えば 図書館の本の管理システム があったとして… 図書館業務の知識全体 ≠ 本の管理システムが担うドメイン (アプリにとって必要な領域に絞る)
Slide 19
Slide 19 text
ドメイン駆動設計(DDD) とは? ドメイン(システムが扱う問題領域)の概念構造を、ソースコードに反映す るアプローチ → ドメインモデリング ドメインの知識をクラス‧メソッド‧名前で表現する ● プロパティ ● 振る舞い ● 不変条件
Slide 20
Slide 20 text
本棚のアプリのドメインモデリングをしてみる
Slide 21
Slide 21 text
概念の構造化 本棚の管理アプリには 本棚 と 本 の概念がある 別の持つ概念なのでそれぞれを クラス として表現する Bookshelf / Book
Slide 22
Slide 22 text
プロパティの付与 本棚‧本には、それぞれ 固有のプロパティ がある それをクラスに 内包する 例: 本棚 → 容量 ∕ 本 → 管理番号‧タイトル
Slide 23
Slide 23 text
所有関係の整理 本棚の管理アプリでは本は 本棚に⼊っている ものとする (野良の本は存在しない) なので 本は本棚が管理 する Bookshelf.books: Book[]
Slide 24
Slide 24 text
振る舞いの定義 本棚から本を 出し⼊れ できる 出し⼊れできるよう、addBook() / removeBook() という振る舞いを作る
Slide 25
Slide 25 text
不変条件の追加 本棚には容量を超えた本は⼊れられない addBook() で容量を超えていないか検証する 守らなければいけないルール=不変条件
Slide 26
Slide 26 text
寄り道:不変条件(invariant) ビジネス上、絶対に壊してはいけない約束 違反すると、ドメイン的に 「壊れた状態」 本棚の例: 現在の冊数 ≦ 容量 → 容量オーバーした本棚は存在してはいけない
Slide 27
Slide 27 text
全体の流れ
Slide 28
Slide 28 text
完成図
Slide 29
Slide 29 text
何がうれしいか 概念構造を表現したコードの中で、 守るべきルールを コードの中に閉じ込めやすい (どう閉じ込めるか は、後ほど説明)
Slide 30
Slide 30 text
何がうれしいか ● オブジェクトが 「実務上で何を表しているか」 を理解しやすい ● コードとビジネスの構造が近くなることで 変更に強くなる ○ アプリの機能が変わってもドメインは影響を受けづらい
Slide 31
Slide 31 text
不変条件:さっきのコードで本当に守れる? 例えば先ほどBookshelfの addBook() に容量チェックを書いたが、 これで 本当に容量超過は防げる?
Slide 32
Slide 32 text
不変条件:さっきのコードで本当に守れる? → このままでは守れない addBook() を書いただけでは 不⼗分 本と本棚を 別々に 操作 できると、 そのルールを守る処理が コード上で必ず通る形になっていない (どこかでチェックしても、別の更新経路ですり抜けうる)
Slide 33
Slide 33 text
ルールを守るには? ルールをチェックする処理が、必ず通る道を作る必要がある
Slide 34
Slide 34 text
更新可能なまとまりを制限する ● Book / Bookshelf を 別々に 更新できる → addBook() をすり抜けたBookができてしまう ● Bookshelfしか更新できない → Bookを追加するためには addBook() しなければいけない Bookshelfの形でしか更新できなくすることでルールを守らせる → 整合が保証されたまとまり= 集約
Slide 35
Slide 35 text
更新のまとまり
Slide 36
Slide 36 text
Repository とは データの永続化を担うレイヤ 受け取るのは必ず 集約(Aggregate) ● BookshelfRepository.save(bookshelf) → OK ● BookRepository.save(book) → NG
Slide 37
Slide 37 text
ここまでのまとめ ● 守るべきルール(不変条件) がある ● 更新経路が 複数 だとルールが破れる ● 集約 + Repository で守る
Slide 38
Slide 38 text
いつやる? では、この⼿の設計を、いつやる価値があるか?
Slide 39
Slide 39 text
いつ DDD を検討するか 2つの段階に分けて考える 考え方 実装 内容 概念構造として捉える Entity / 集約 / Repository まで整える 度合い 常に 役に立つ 規模・難易度 次第
Slide 40
Slide 40 text
いつ DDD を検討するか 本棚の例は、向いている寄り 観点 向いている 過剰になりやすい ルール 複雑なルールがある (本棚の容量など) 入力チェック程度で足りる 更新 入口が複数ある CRUD 1本で問題ない 知識 仕様が 属人化 している CRUDで回せる程度 寿命 長く運用 する 使い捨て
Slide 41
Slide 41 text
全部DDDしないといけない? いきなり「全部 DDD」ではなくても良い ● 容量ルール‧本の所在 がある → 集約までやる価値あり ● 本棚のマスタ登録 → Entity 1個 + CRUD でも⾜りる 複雑なところから。シンプルな部分はシンプルなままでも良い
Slide 42
Slide 42 text
概念構造の構成要素
Slide 43
Slide 43 text
構成要素に名前を付けると 先ほど話題に出した 集約(Aggregate) と呼ばれる構造物は、その中⾝を構 成する要素が存在します 中⾝に名前を付けると… 集約の中⾝ = Entity‧Value Object
Slide 44
Slide 44 text
Entity とは 「もの」 を表す 本棚‧本‧貸出履歴のように、業務上の実体をイメージしやすい (必ずしも現物とは限らない)
Slide 45
Slide 45 text
Entity の特性 ● 同⼀性(ID) で区別される ○ ● 属性を持つ ○ ● IDが同じであれば同⼀のオブジェクト プリミティブな値(例: title: string)、またはValueObject 状態が変わる(Mutable)
Slide 46
Slide 46 text
Entity のコード例(Book)
Slide 47
Slide 47 text
Value Object とは 「値や概念‧ルール」 を表す Entityの属性を、ルール付きの型にするイメージ ● 形式チェックが必要なメールアドレス ● 前後関係の保証が必要な期間(From - To)
Slide 48
Slide 48 text
Value Object の特性 ● 値の等価性で⽐較(ID による同⼀性はない) ● プリミティブな値を 1つ以上 内包し意味とルールを閉じ込める ○ ● 複数の値間で整合をとる必要がある場合2つ以上の値を所有する 値が変わらない(Immutable) ○ Value Objectに内包されている値は直接書き換えない ○ Entityの所有するValue Objectに変更を加えたい場合、新しいValue Objectと差し替え る
Slide 49
Slide 49 text
Value Object のコード例(Capacity)
Slide 50
Slide 50 text
Value Object(補⾜) EntityのIdも Value Object として表現することが多い BookId と BookshelfId の取り違えを防ぐ⽬的がある (TypeScriptの場合要ブランド化)
Slide 51
Slide 51 text
集約(Aggregate)とは 整合性を守るべきまとまりのこと 単⼀のEntityを 集約ルート とし、集約 内の整合性が保証される境界 本棚のアプリでの本棚 Repository で扱える単位
Slide 52
Slide 52 text
集約(Aggregate)の特性 ● 1つの集約につき、集約ルートととなるEntityが必ず1つ存在する ● 外部からの⼦の操作は必ず 集約ルートを経由する ○ ● Bookshelfの books は addBook/removeBook で操作する ⼦となるEntityが存在しないEntityは、そのEntityをルートとする単独の 集約と⾔える ○ 単独で整合が保証されており読み書きが可能である
Slide 53
Slide 53 text
ドメインオブジェクト と物理モデルは別 ドメインオブジェクト は ドメイン上の概念 テーブル‧カラムとは 必ずしも 1:1 にならない 1:1 である必要もない
Slide 54
Slide 54 text
ドメインオブジェクト と物理モデルは別ーズレの例
Slide 55
Slide 55 text
集約のコード例(Bookshelf)
Slide 56
Slide 56 text
集約の切り⽅ 判断基準: 常に⼀緒に整合性を保つべき不変条件があるか 親⼦関係がある ≠ 必ず 1 集約 パターン 例 同一集約内 本棚 + 本 + 容量 分ける 組織とメンバー (跨いだ不変条件がない)
Slide 57
Slide 57 text
本⽇のまとめ 1. DDD = ドメインの概念構造をコードに反映する 2. 守りたいルールは 「必ず通る道」 で守る → 集約 + Repository 3. メリット = バイパスしにくい / 読みやすい / 変更に強い 4. 考え⽅は常に有⽤、実装は複雑なところから 5. 構成要素 = Entity / Value Object / Aggregate 集約は迷ったら 不変条件 で切る
Slide 58
Slide 58 text
No content