ボトムアップドメイン駆動設計 後編 / bottomup-ddd-2

E37b4344ef4bfd0fc4826c04971e54fb?s=47 nrs
October 28, 2018

ボトムアップドメイン駆動設計 後編 / bottomup-ddd-2

# URL
前編: https://speakerdeck.com/nrslib/bottomup-ddd-1
解説記事: https://nrslib.com/bottomup-ddd/
勉強会情報: https://ddd-community-jp.connpass.com/event/103428/
Twitter: https://twitter.com/nrslib

# 概要
2018/10/23 GMO Yours で行われた「ボトムアップドメイン駆動設計」の登壇資料後編です
口頭での解説前提のためわかりづらい部分もあるかと思いますがご了承ください。

E37b4344ef4bfd0fc4826c04971e54fb?s=128

nrs

October 28, 2018
Tweet

Transcript

  1. Masanobu Naruse BOTTOM UP DOMAIN DRIVEN DESIGN The later part

  2. もくじ • はじめに • 値オブジェクト • エンティティ • ドメインサービス •

    リポジトリ • アプリケーションサービス • ファクトリ • トランザクション • 集約 • アーキテクチャ • ドメイン駆動設計への誘い 2
  3. 閑話休題 3 アプリケーションが 作れるようになりました ここから後半です

  4. ファクトリ FACTORY

  5. ファクトリ | 採番 5 サンプルの採番

  6. ファクトリ | 採番 6 独自の採番システムを使いたい

  7. ファクトリ | 採番 7 例えば採番テーブル

  8. ファクトリ | 採番 8

  9. ファクトリ | 採番 9 テストできない!

  10. ファクトリ | 採番 10 ユーザがユーザの作り方を 知っているのはおかしい ユーザの知識と ユーザを作る知識は別物

  11. ファクトリ | 採番 11 そこで ファクトリ

  12. ファクトリ | 採番 12

  13. ファクトリ | 採番 13 採番処理

  14. ファクトリ | 採番 14 オブジェクトの構築

  15. ファクトリ | 採番 15

  16. ファクトリ | 採番 16 生成処理をカプセル化

  17. ファクトリ | 採番 17 テストも勿論できます

  18. ファクトリ | 採番 18 テストも勿論できます メモリ上の値を利用

  19. ファクトリ | リポジトリによる採番 19 リポジトリに 採番処理を持たせるパターンも よく見ます

  20. ファクトリ | リポジトリによる採番 20

  21. ファクトリ | リポジトリによる採番 21

  22. ファクトリ | リポジトリによる採番 22 シンプル

  23. ファクトリ | リポジトリによる採番 23 反面、採番処理とデータ永続化の技術が 異なると若干違和感を感じるかも

  24. ファクトリ | リポジトリによる採番 24 反面、採番処理とデータ永続化の技術が 異なると若干違和感を感じるかも APIで採番

  25. ファクトリ | リポジトリによる採番 25 反面、採番処理とデータ永続化の技術が 異なると若干違和感を感じるかも APIで採番 RDBで永続化

  26. ファクトリ | 自動採番 26 ところで DB の AutoIncrement 機能 って便利ですよね

  27. ファクトリ | 自動採番 27

  28. ファクトリ | 自動採番 28

  29. ファクトリ | 自動採番 29

  30. ファクトリ | 自動採番 30 ここで SetUserId される

  31. ファクトリ | 自動採番 31 ここで SetUserId される 不安定な状態のエンティティを存在させることになるけど 統一してあれば大丈夫・・・だと思う

  32. トランザクション TRANSACTION

  33. トランザクション 33 いわゆる一般的な トランザクションの話

  34. トランザクション 34 実はいままでのサンプルコードは 致命的な不具合があります

  35. トランザクション 35

  36. トランザクション 36 ユーザ A

  37. トランザクション 37 User Name: nrs で登録 ユーザ A

  38. トランザクション 38 User Name: nrs で登録 ユーザ A

  39. トランザクション 39 User Name: nrs で登録 ユーザ A ユーザ B

  40. トランザクション 40 User Name: nrs で登録 User Name: nrs で登録

    ユーザ A ユーザ B
  41. トランザクション 41 User Name: nrs で登録 User Name: nrs で登録

    ユーザ A ユーザ B
  42. トランザクション 42 User Name: nrs で登録 User Name: nrs で登録

    ユーザ A ユーザ B User Name: nrs のデータが 二つ出来てしまう
  43. トランザクション | ユニークキー 43 重複してはいけない ならば UserName カラムに ユニークキー制約をつけよう

  44. トランザクション | ユニークキー 44

  45. トランザクション | ユニークキー 45 ユニークキーを付けたなら

  46. トランザクション | ユニークキー 46 ユニークキーを付けたなら 重複確認もいらないのでは?

  47. トランザクション | ユニークキー 47

  48. トランザクション | ユニークキー 48 わかりやすい

  49. トランザクション | ユニークキー 49 わかりやすい 何もわからないコード

  50. トランザクション | ユニークキー 50 わかりやすい 何もわからないコード 重複を許さないという情報は重要なファクター

  51. トランザクション | トランザクションスコープ 51 整合性が必要な処理を表す方法 トランザクションスコープ

  52. トランザクション | トランザクションスコープ 52

  53. トランザクション | トランザクションスコープ 53

  54. トランザクション | トランザクションスコープ 54 このスコープは整合性が求められる処理と主張している

  55. トランザクション | トランザクションスコープ 55 C# じゃないしなぁ・・・ と思った方

  56. トランザクション | トランザクションスコープ 56 例えば Spring フレームワーク

  57. トランザクション | トランザクションスコープ 57 例えば Spring フレームワーク

  58. トランザクション | トランザクションスコープ 58 例えば Spring フレームワーク

  59. トランザクション | トランザクションスコープ 59 例えば Spring フレームワーク このメソッドは整合性が求めると主張している

  60. トランザクション | トランザクションスコープ 60 言語にもフレームワークにも そんな機能ないしなぁ と思った方

  61. トランザクション | トランザクションスコープ 61 作ろう ※こんな感じのものがあればいけるかな・・・の例です

  62. トランザクション | ユニットオブワーク 62 そこまで大げさな仕組みが嫌なら ユニットオブワーク

  63. トランザクション | ユニットオブワーク 63 インターフェースを用意

  64. トランザクション | ユニットオブワーク 64 こんな感じで実装

  65. トランザクション | ユニットオブワーク 65

  66. トランザクション | ユニットオブワーク 66

  67. トランザクション | ユニットオブワーク 67

  68. トランザクション | ユニットオブワーク 68 リポジトリは Connection を受け取る

  69. トランザクション | ユニットオブワーク 69

  70. トランザクション | ユニットオブワーク 70

  71. トランザクション | ユニットオブワーク 71

  72. トランザクション | ユニットオブワーク 72 DBConnection を利用するところを UnitOfWork に切り替えるだけなので導入しやすい

  73. トランザクション | ユニットオブワーク 73 デメリット リポジトリ増加のたびに ユニットオブワークに修正が入る

  74. トランザクション | ユニットオブワーク 74

  75. トランザクション | ユニットオブワーク 75

  76. トランザクション | ユニットオブワーク 76

  77. トランザクション | ユニットオブワーク 77

  78. トランザクション | ユニットオブワーク 78 リポジトリを抽象化しちゃえば?

  79. トランザクション | ユニットオブワーク 79

  80. トランザクション | ユニットオブワーク 80 特定エンティティの リポジトリ取得

  81. トランザクション | ユニットオブワーク 81 例えばサークルの所属ユーザ情報を取得すると 特定エンティティの リポジトリ取得

  82. トランザクション | ユニットオブワーク 82 例えばサークルの所属ユーザ情報を取得すると 特定エンティティの リポジトリ取得

  83. トランザクション | ユニットオブワーク 83 例えばサークルの所属ユーザ情報を取得すると 特定エンティティの リポジトリ取得

  84. トランザクション | ユニットオブワーク 84 例えばサークルの所属ユーザ情報を取得すると SELECT * FROM t_user WHERE

    t_user.id = ‘userId’ を何度も実行する 特定エンティティの リポジトリ取得
  85. トランザクション | ユニットオブワーク 85 例えばサークルの所属ユーザ情報を取得すると SELECT * FROM t_user WHERE

    t_user.id = ‘userId’ を何度も実行する 特定エンティティの リポジトリ取得
  86. トランザクション | ユニットオブワーク 86 例えばサークルの所属ユーザ情報を取得すると SELECT * FROM t_user WHERE

    t_user.id = ‘userId’ を何度も実行する 特定エンティティの リポジトリ取得 最適化した処理が 利用できない
  87. トランザクション | ユニットオブワーク 87 ユニットオブワークに 既視感がある方

  88. トランザクション | ユニットオブワーク 88 ユニットオブワークに 既視感がある方 Entity Framework は ユニットオブワークの実装です

    ※最適化できない問題は遅延実行による SQL 生成(IQueryable)で解決
  89. 集約 AGGREGATE

  90. 集約 90 集約を学ぶために エクササイズ

  91. 集約 | エクササイズ 91 お題はサークル機能

  92. 集約 | エクササイズ 92 お題はサークル機能

  93. 集約 | エクササイズ 93 サークルを作る処理 注目すべきは

  94. 集約 | エクササイズ 94 サークルを作る処理 注目すべきは getter

  95. 集約 | エクササイズ 95

  96. 集約 | エクササイズ 96 メソッドを用意し getter を使わないようにした

  97. 集約 | エクササイズ 97

  98. 集約 | エクササイズ 98

  99. 集約 | エクササイズ 99 getter が消え ユーザがサークルを作っている

  100. 集約 | エクササイズ 100 次はこっち

  101. 集約 | エクササイズ 101

  102. 集約 | エクササイズ 102 getter

  103. 集約 | エクササイズ 103 最大人数 30 人

  104. 集約 | エクササイズ 104 最大人数 30 人 このロジックは ここ以外にも記述しそう

  105. 集約 | エクササイズ 105 最大人数 30 人 このロジックは ここ以外にも記述しそう 最大人数を

    50 人に 変更することになったら?
  106. 集約 | エクササイズ 106 最大人数 30 人 このロジックは ここ以外にも記述しそう 最大人数を

    50 人に 変更することになったら? 愚直に修正する羽目に
  107. 集約 | エクササイズ 107

  108. 集約 | エクササイズ 108 ドメインモデル貧血症

  109. 集約 109 健全なドメインモデルにするために 集約を学ぶ

  110. 集約 110 集約 と 集約ルート

  111. 集約 111

  112. 集約 112 id: CircleId users: List<User> name: string Circle users:

    List<User> users: List<User>
  113. 集約 113 User 集約 id: CircleId users: List<User> name: string

    Circle users: List<User> users: List<User>
  114. 集約 114 Circle 集約 id: CircleId users: List<User> name: string

    Circle users: List<User> users: List<User>
  115. 集約 115 Circle 集約の集約ルート id: CircleId users: List<User> name: string

    Circle users: List<User> users: List<User>
  116. 集約 116 集約は必ず集約ルート越しに触る 集約の内部のオブジェクトを直接触らない

  117. 集約 117 つまり

  118. 集約 118 アプリケーションサービスは 集約ルートを 直接のインターフェースにします

  119. 集約 119

  120. 集約 120

  121. 集約 121 サークル越しにユーザエンティティを触ってる

  122. 集約 122 サークル越しにユーザエンティティを触ってる サークルが直接のインターフェースであるべき

  123. 集約 123

  124. 集約 124

  125. 集約 125 最大人数を 50 人に変更したい

  126. 集約 126 最大人数を 50 人に変更したい 修正はここだけで OK

  127. 集約 127 実は オブジェクト指向では 当たり前の発想

  128. 集約 128 デメテルの法則

  129. 集約 129 デメテルの法則

  130. 集約 130 デメテルの法則

  131. 集約 | 整合性の境界 131 集約ってどれぐらいの粒度で作るの?

  132. 集約 | 整合性の境界 132 集約ってどれぐらいの粒度で作るの? 変更の単位

  133. 集約 | 整合性の境界 133 これまでの集約の概念図

  134. 集約 | 整合性の境界 134 これまでの集約の概念図 もし Circle 集約で User を変更したら?

    User 集約は Circle 集約に属してない
  135. 集約 | 整合性の境界 135 これまでの集約の概念図 User 集約は Circle 集約に属してない

  136. 集約 | 整合性の境界 136 ロジックはぎりぎり納得できる

  137. 集約 | 整合性の境界 137

  138. 集約 | 整合性の境界 138 Circle のリポジトリなのに User の処理が多い・・・

  139. 集約 | 整合性の境界 139 Circle が Circle 以外の変更は 担保しない場合

  140. 集約 | 整合性の境界 140 リポジトリは Circle に集中

  141. 集約 | 整合性の境界 141 整合性の境界・変更の単位として集約を設計する

  142. 集約 | 整合性の境界 142 整合性の境界・変更の単位として集約を設計する リポジトリは集約毎に作成することになる

  143. 集約 | 問題点 143 問題点

  144. 集約 | 問題点 144 変更できちゃう 問題点

  145. 集約 | 識別子による防衛 145 そもそもの問題は変更できてしまうこと

  146. 集約 | 識別子による防衛 146 変更できないようにする そもそもの問題は変更できてしまうこと

  147. 集約 | 識別子による防衛 147 変更できないようにする そもそもの問題は変更できてしまうこと

  148. 集約 | 識別子による防衛 148 識別子にしてしまえば変更できない 変更できないようにする そもそもの問題は変更できてしまうこと

  149. 集約 | 識別子による防衛 149 識別子にしてしまえば変更できない 変更できないようにする そもそもの問題は変更できてしまうこと

  150. 集約 | 非公開による防衛 150 変更をさせない仕組みとしてもう一つ

  151. 集約 | 非公開による防衛 151 そもそも getter だから悪い

  152. 集約 | 非公開による防衛 152 そもそも getter だから悪い

  153. 集約 | 非公開による防衛 153 getter をなくすと

  154. 集約 | 非公開による防衛 154 リポジトリが問題になる

  155. 集約 | 非公開による防衛 155 C# の場合は諦めるか Notification パターンで

  156. 集約 | 非公開による防衛 156 Scala 最強説

  157. 集約 | 非公開による防衛 157 Scala 最強説 ICircleRepository からはアクセスできる 他からはアクセスできない

  158. DIRECTORY

  159. ディレクトリ構成例 159 ディレクトリ構成のイメージ 明日から採用したい人のために

  160. ディレクトリ構成例 160 Domain Application UserApplicationService Model CircleApplicationService User Users Circles

    Infrastructure UserId UserName IUserRepository ICircleRepository CircleRepository Presentation(MVC) Circle CircleId UserRepository InMemory InMemoryCircleRepository InMemoryUserRepository : package : folder : object
  161. アーキテクチャ ARCHITECTURE

  162. アーキテクチャ 162 ドメイン駆動設計と 同時に語られることの多い アーキテクチャについて

  163. アーキテクチャ 163 レイヤードアーキテクチャ ヘキサゴナルアーキテクチャ オニオンアーキテクチャ クリーンアーキテクチャ

  164. アーキテクチャ | レイヤードアーキテクチャ 164 レイヤードアーキテクチャ ヘキサゴナルアーキテクチャ オニオンアーキテクチャ クリーンアーキテクチャ

  165. アーキテクチャ | レイヤードアーキテクチャ 165 レイヤードアーキテクチャ Presentation Application Domain Infrastructure UserApplicationService

    User UserRepository UserController
  166. アーキテクチャ | レイヤードアーキテクチャ 166 レイヤードアーキテクチャ Presentation Application Domain Infrastructure UserApplicationService

    User UserRepository UserController 依存の方向は下方向
  167. アーキテクチャ | ヘキサゴナルアーキテクチャ 167 レイヤードアーキテクチャ ヘキサゴナルアーキテクチャ オニオンアーキテクチャ クリーンアーキテクチャ

  168. アーキテクチャ | ヘキサゴナルアーキテクチャ 168 ヘキサゴナルアーキテクチャ

  169. アーキテクチャ | ヘキサゴナルアーキテクチャ 169 ヘキサゴナルアーキテクチャ UserController (Adapter) User UserApplicationService UserRepository

  170. UserController (Adapter) User UserApplicationService UserRepository アーキテクチャ | ヘキサゴナルアーキテクチャ 170 ヘキサゴナルアーキテクチャ

    ビジネスロジックが中心で依存は内向き
  171. アーキテクチャ | オニオンアーキテクチャ 171 レイヤードアーキテクチャ ヘキサゴナルアーキテクチャ オニオンアーキテクチャ クリーンアーキテクチャ

  172. アーキテクチャ | オニオンアーキテクチャ 172 オニオンアーキテクチャ Application Services Domain Services Domain

    Model UI Tests Infrastructure
  173. アーキテクチャ | オニオンアーキテクチャ 173 オニオンアーキテクチャ Application Services Domain Services Domain

    Model UI Tests Infrastructure User UserApplicationService UserService ドメイン駆動設計?
  174. アーキテクチャ | オニオンアーキテクチャ 174 オニオンアーキテクチャ Application Services Domain Services Domain

    Model UI Tests Infrastructure User UserApplicationService UserService ヘキサゴナルアーキテクチャの内側 ドメイン駆動設計?
  175. アーキテクチャ | クリーンアーキテクチャ 175 レイヤードアーキテクチャ ヘキサゴナルアーキテクチャ オニオンアーキテクチャ クリーンアーキテクチャ

  176. アーキテクチャ | クリーンアーキテクチャ 176 クリーンアーキテクチャ

  177. アーキテクチャ | クリーンアーキテクチャ 177 クリーンアーキテクチャ Controllers: UserController GateWays: IUserRepository UserRepository

    UseCases: IUserApplicationService(InputPort) UserApplicationService(Interactor) Entities: User
  178. アーキテクチャ | クリーンアーキテクチャ 178 クリーンアーキテクチャ ヘキサゴナルアーキテクチャの外側 Controllers: UserController GateWays: IUserRepository

    UserRepository UseCases: IUserApplicationService(InputPort) UserApplicationService(Interactor) Entities: User
  179. アーキテクチャ | クリーンアーキテクチャ 179 クリーンアーキテクチャ ヘキサゴナルアーキテクチャの外側 Controllers: UserController GateWays: IUserRepository

    UserRepository UseCases: IUserApplicationService(InputPort) UserApplicationService(Interactor) Entities: User ※詳しい話はこちらで https://nrslib.com/clean-architecture/ https://qiita.com/nrslib/items/a5f902c4defc83bd46b8
  180. アーキテクチャ | まとめ 180

  181. アーキテクチャ | まとめ 181

  182. アーキテクチャ | まとめ 182

  183. アーキテクチャ | まとめ 183

  184. アーキテクチャ | まとめ 184 レイヤードがあり ヘキサゴナルへ変遷 その実装イメージとして ヘキサゴナルの内側がオニオン ヘキサゴナルの外側がクリーン いずれも依存関係を整理し

    ドメインロジックの防衛を目指している
  185. ドメイン DOMAIN

  186. ドメイン 186 ドメインとは

  187. FINALLY

  188. ドメイン駆動設計への誘い 188 以上で終了です

  189. ドメイン駆動設計への誘い 189 今回の内容を知らなかった方は これらのパターンを実践するだけでも よりよいコードを書くことが できるでしょう

  190. ドメイン駆動設計への誘い 190 ただパターンを模倣し 形だけを真似たものは 軽量 DDD と呼ばれるものです

  191. ドメイン駆動設計への誘い 191 真のドメイン駆動設計とは異なります

  192. ドメイン駆動設計への誘い 192 ではどうすれば 真のドメイン駆動設計に たどり着けるのか

  193. ドメイン駆動設計への誘い 193 最初の方のスライドを見てみましょう

  194. ドメイン駆動設計への誘い 194 マインド パターン 感じるしかない 実装できる 用語

  195. ドメイン駆動設計への誘い 195 パターン 感じるしかない 実装できる 用語 マインド

  196. ドメイン駆動設計への誘い 196 マインドは原典で

  197. WELCOME TO DDD WORLD

  198. おわり 198 • はじめに • 値オブジェクト • エンティティ • ドメインサービス

    • リポジトリ • アプリケーションサービス • ファクトリ • トランザクション • 集約 • アーキテクチャ • ドメイン駆動設計への誘い @nrslib https://nrslib.com