SlideShare une entreprise Scribd logo
1  sur  23
Télécharger pour lire hors ligne
強いて言えば「集約どう実装す
るのかな、を考える」な話
kawasima
アーキ部 #13
CartにCartItemを追加する
Add Cart
Add Cart
Add Cart
1
1
1
{
“productId”: “mikan”,
“quantity”: 1
}
API Endpoint
AddCartItemUseCase
{
“userId”: “kawasima”,
“productId”: “mikan”,
“quantity”: 1
}
ユースケースシナリオ
1. ユーザのカートが存在することを確認する。
2. productIdが実在する商品かつ販売中の商品であることを確認する。
2a. 販売中でない場合
2a1. その旨をユーザに通知して終了
3. カートに商品と数量を追加する
3a. 既にカートの中に同一の商品があれば数量を足し合わせる
3a カート内の商品の数量が100を超える場合
その旨をユーザに通知して終了
4. カートの内容を保存する
高々100件くらい全部メモリにロード
しちゃえばいいじゃないか…
じゃあその件数上限が、数十万件に
なったら?
https://github.com/kawasima/revisiting-domain-model/blob/main/src/victim_performance.ts
ドメインを中心に据えて、外界と
のやり取りをエッジに置く設計
カート
カートアイテム
スタジアム
座席
列
番号
座席ランク
商品ID
数量
1 *
ユースケース: あるカートアイテム
の数量を変更する
ユースケース: ある座席のランクを
変更する
制約: 同一ランクの座席数上限はス
タジアム毎に決まりがある
制約: カート全体に入れることがで
きる商品数量は100個まで
1 1..*
※10万席あるスタジアムもある
A B
ドメインモデルのトリレンマ
https://enterprisecraftsmanship.com/posts/domain-model-purity-completeness/
純粋性
完全性
性能
完全性を犠牲にドメインレイヤの外
にドメインロジックを実装する
純粋を犠牲にドメインレイヤに外界
とのやり取りのコードをインジェク
トする。
全ての外界とのやり取りを業務ロ
ジックの端に追いやる。
ドメインロジックが全てドメイン層で実装されること
ドメイン層が他のレイヤに
依存しないこと
それぞれのメリット
テスト容易性と移植性が向上する。
完全性
性能
純粋性
高凝集が達成され、コードの変更容易性が向
上する。
速ければ速いほどCVRが上がる。
完全性+性能
カートアイテム追加のた
めに、わざわざ全部の
カートアイテムをロード
する必要はない。
(そもそも性能面を考える
と出来ない)
でも、参照系(カートの中
身表示ページ)では必要…
ReadとWriteを分ける
(遅延ロードを使うという
手もある…が事故多し)
https://github.com/kawasima/revisiting-domain-model/blob/main/src/victim_purity.ts
純粋性+性能
ドメインオブジェクトに、DBア
クセスを含めないようにする。
結果として、今回のユースケー
スでは、ドメインロジックはな
くなり、全てがユースケース層
に染み出す結果に。
https://github.com/kawasima/revisiting-domain-model/blob/main/src/victim_completeness.ts
DDDトリレンマ: それぞれの選択に潜む悪魔
純粋性+完全性
純粋性+性能
完全性+性能
理想論の悪魔
👿 「純粋かつ完全なるドメイン …美しい」
ただし、遅くて使い物にならないけどな
アンチドメインモデル貧血症 の悪魔
👿 「業務ロジックを発見し、濃いドメインモデルができたで〜」
こんな簡単なものに、こんな複雑な仕掛けが必要なの ?
テスタビリティの悪魔
👿 「ドメイン層がピュアでテストしやすぅ〜」
ドメイン層スッカスカでテストが簡単に書けても、ユースケースからテスト通
さんと、ほとんど品質保証の意味をなさない。
どれも追求しすぎると、悪魔に取り憑かれる
銀の弾丸(美しい解決策)はなさそう
テスト容易性と移植性が向上する。
完全性
純粋性
高凝集が達成され、コードの変更容易性が向上する。
とはいえ、性能は保った状態で、「完全性」と「純粋性」のメリット、を
少しずつでも享受できる手立てはないものか…?
所詮、どちらも直接的に顧客に不利益をもたらす品質特性ではないので、Take It Easy
高凝集について
完全性を取りに行って、ドメインモデルが貧血症を起こさないように設計出来た
ら「高凝集」になる?
→ 世の中にあるドメインモデルの例たちは、ちょっと怪しい。
https://scrapbox.io/kawasima/ドメインモデル貧血症
「複雑さ」がポイント
実際に高凝集目指すならば、複雑さを紐解かなければならない
異なる振る舞いをするものは、異なるものとしてみなす
(まぁ、ふつうはそれを型で実装する)
(ドメインサービスの乱用による)ドメイン貧血症
class User {
public exists(user: User): bool {
// 重複チェック
}
}
class UserService {
public exists(user: User): bool {
// 重複チェック
}
}
Userに自分自身の存在確認メソッドを持た
せるのは不自然。
なので、そういう場合にだけドメインサービ
スを作るといいよ。
ドメインサービスの乱用は、ドメインモデル
貧血症を招くのでほどほどに …
『ドメイン駆動設計入門』より
どこに定義するかより、同じでないものを区別することが先決では?
内包されている「複雑さ」(異なる概念)を型で表現するのが重要
重複しているかもし
れないユーザ
重複していないことが
保証されているユーザ
両者は別の概念
(なぜなら定義される
振る舞いが異なる)
// ユーザの重複チェック ; 「重複しているかもしれないユーザ」にしか適用されない
type existsUser = MaybeDuplicatedUser -> UniqueUser
// ユーザの登録; 「重複していないことが保証されているユーザ」にしか適用されない
type registerUser = UniqueUser -> RegisteredUser
Parse don’t validate
Parse don’t validate
https://sporto.github.io/elm-patterns/basic/parse-dont-validate.html
Origin: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
type alias UserInput =
{ name: Maybe String
, age: Maby Int
}
isValidUser : UserInput -> Bool
このようなバリデータだけが用意されていると、UserInput型のデータはバリデートが済
んでも、invalidな値を保持している可能性がある。
実際に、これが元で過去いくつもの脆弱性が発生している。
http://langsec.org/papers/langsec-cwes-secdev2016.pdf
type alias UserInput =
{ name: Maybe String
, age: Maby Int
}
type alias ValidUser =
{ name: String
, age: Int
}
validateUser : UserInput -> Result String ValidUser
バリデート済みであることを型によって保証する。
なので、バリデートはBooleanを返すのではなく、バリデーション済みの型にParseして返す
Type Safety Back and Forth
https://www.parsonsmatt.org/2017/10/11/type_safety_back_and_forth.html
失敗可能性を後ろへ
失敗可能性を前へ (こっちの方がいいよね、という話)
入力を型によって制約保証す
る。
Domain Modeling Made Functional
https://www.slideshare.net/ScottWlaschin/domain-modeling-made-functional-devternity-2022
Domain Expertとの対話を繰り返しながら、違うものを見つけていく
これで先の
AddCartItemUseCase
を実装してみよう
https://github.com/kawasima/revisiting-domain-model/blob/main/src/made_functional.ts
「複雑さ」を型で表現できれば、それ
を紡ぎ合わせるのがビジネスロジック
になる。
まとめ
● トリレンマにしたがい完全+純粋、純粋+性能、完全+性能な手段が考えら
れる。
● 1つのやり方に執着しすぎると、悪魔に取り憑かれるので注意しよう。
● そもそもドメインにまつわる「複雑さ」は明らかにできているのか?

Contenu connexe

Tendances

SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
なぜデータモデリングが重要なのか?
なぜデータモデリングが重要なのか?なぜデータモデリングが重要なのか?
なぜデータモデリングが重要なのか?Yoshitaka Kawashima
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean ArchitectureAtsushi Nakamura
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるpospome
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているKoichi Tanaka
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意Yoshitaka Kawashima
 
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装までドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで増田 亨
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し増田 亨
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織Takafumi ONAKA
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法yoku0825
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)Yoshitaka Kawashima
 
設計と実装で 抑えておきたい サービスクラスと例外
設計と実装で 抑えておきたい サービスクラスと例外設計と実装で 抑えておきたい サービスクラスと例外
設計と実装で 抑えておきたい サービスクラスと例外Takuya Sato
 
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのかDDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのかKoichiro Matsuoka
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう増田 亨
 
トランザクションスクリプトのすすめ
トランザクションスクリプトのすすめトランザクションスクリプトのすすめ
トランザクションスクリプトのすすめpospome
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法についてYuji Otani
 
世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計増田 亨
 
Node.js Native ESM への道 〜最終章: Babel / TypeScript Modules との闘い〜
Node.js Native ESM への道  〜最終章: Babel / TypeScript Modules との闘い〜Node.js Native ESM への道  〜最終章: Babel / TypeScript Modules との闘い〜
Node.js Native ESM への道 〜最終章: Babel / TypeScript Modules との闘い〜Teppei Sato
 

Tendances (20)

SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
なぜデータモデリングが重要なのか?
なぜデータモデリングが重要なのか?なぜデータモデリングが重要なのか?
なぜデータモデリングが重要なのか?
 
世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture世界一わかりやすいClean Architecture
世界一わかりやすいClean Architecture
 
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考えるGoのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
 
やはりお前らのMVCは間違っている
やはりお前らのMVCは間違っているやはりお前らのMVCは間違っている
やはりお前らのMVCは間違っている
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
ドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装までドメイン駆動で開発する ラフスケッチから実装まで
ドメイン駆動で開発する ラフスケッチから実装まで
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し
 
エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織エンジニアの個人ブランディングと技術組織
エンジニアの個人ブランディングと技術組織
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法MySQLで論理削除と正しく付き合う方法
MySQLで論理削除と正しく付き合う方法
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 
設計と実装で 抑えておきたい サービスクラスと例外
設計と実装で 抑えておきたい サービスクラスと例外設計と実装で 抑えておきたい サービスクラスと例外
設計と実装で 抑えておきたい サービスクラスと例外
 
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのかDDDのモデリングとは何なのか、 そしてどうコードに落とすのか
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
 
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみようドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計 ( DDD ) をやってみよう
 
トランザクションスクリプトのすすめ
トランザクションスクリプトのすすめトランザクションスクリプトのすすめ
トランザクションスクリプトのすすめ
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
 
世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計世界でいちばんわかりやすいドメイン駆動設計
世界でいちばんわかりやすいドメイン駆動設計
 
Node.js Native ESM への道 〜最終章: Babel / TypeScript Modules との闘い〜
Node.js Native ESM への道  〜最終章: Babel / TypeScript Modules との闘い〜Node.js Native ESM への道  〜最終章: Babel / TypeScript Modules との闘い〜
Node.js Native ESM への道 〜最終章: Babel / TypeScript Modules との闘い〜
 

Plus de Yoshitaka Kawashima

ブルックスのいう銀の弾丸とは何か?
ブルックスのいう銀の弾丸とは何か?ブルックスのいう銀の弾丸とは何か?
ブルックスのいう銀の弾丸とは何か?Yoshitaka Kawashima
 
ソフトウェアにおける 複雑さとは何なのか?
ソフトウェアにおける 複雑さとは何なのか?ソフトウェアにおける 複雑さとは何なのか?
ソフトウェアにおける 複雑さとは何なのか?Yoshitaka Kawashima
 
ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』Yoshitaka Kawashima
 
ソフトウェア設計における 意思決定とそのレビューの秘訣
ソフトウェア設計における 意思決定とそのレビューの秘訣ソフトウェア設計における 意思決定とそのレビューの秘訣
ソフトウェア設計における 意思決定とそのレビューの秘訣Yoshitaka Kawashima
 
システムダウンのひみつ
システムダウンのひみつシステムダウンのひみつ
システムダウンのひみつYoshitaka Kawashima
 
アンチフラジャイルの世界
アンチフラジャイルの世界アンチフラジャイルの世界
アンチフラジャイルの世界Yoshitaka Kawashima
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?Yoshitaka Kawashima
 
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 FallYoshitaka Kawashima
 
ウォーターフォールとアジャイルのフェアな比較
ウォーターフォールとアジャイルのフェアな比較ウォーターフォールとアジャイルのフェアな比較
ウォーターフォールとアジャイルのフェアな比較Yoshitaka Kawashima
 
Antifragile Java - Java Day Tokyo 2017 D1-E1
Antifragile Java - Java Day Tokyo 2017 D1-E1Antifragile Java - Java Day Tokyo 2017 D1-E1
Antifragile Java - Java Day Tokyo 2017 D1-E1Yoshitaka Kawashima
 
たとえ日本人同士でも必要な異文化理解力
たとえ日本人同士でも必要な異文化理解力たとえ日本人同士でも必要な異文化理解力
たとえ日本人同士でも必要な異文化理解力Yoshitaka Kawashima
 
SIerにとっての越境 @ DevLOVE 199
SIerにとっての越境 @ DevLOVE 199SIerにとっての越境 @ DevLOVE 199
SIerにとっての越境 @ DevLOVE 199Yoshitaka Kawashima
 
既婚プログラマの時間捻出術
既婚プログラマの時間捻出術既婚プログラマの時間捻出術
既婚プログラマの時間捻出術Yoshitaka Kawashima
 

Plus de Yoshitaka Kawashima (20)

ブルックスのいう銀の弾丸とは何か?
ブルックスのいう銀の弾丸とは何か?ブルックスのいう銀の弾丸とは何か?
ブルックスのいう銀の弾丸とは何か?
 
Are Design Patterns Dead?
Are Design Patterns Dead?Are Design Patterns Dead?
Are Design Patterns Dead?
 
ソフトウェアにおける 複雑さとは何なのか?
ソフトウェアにおける 複雑さとは何なのか?ソフトウェアにおける 複雑さとは何なのか?
ソフトウェアにおける 複雑さとは何なのか?
 
ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』ソフトウェア開発における『知の高速道路』
ソフトウェア開発における『知の高速道路』
 
ソフトウェア設計における 意思決定とそのレビューの秘訣
ソフトウェア設計における 意思決定とそのレビューの秘訣ソフトウェア設計における 意思決定とそのレビューの秘訣
ソフトウェア設計における 意思決定とそのレビューの秘訣
 
本番障害に至る病
本番障害に至る病本番障害に至る病
本番障害に至る病
 
システムダウンのひみつ
システムダウンのひみつシステムダウンのひみつ
システムダウンのひみつ
 
Mavenの真実とウソ
Mavenの真実とウソMavenの真実とウソ
Mavenの真実とウソ
 
アンチフラジャイルの世界
アンチフラジャイルの世界アンチフラジャイルの世界
アンチフラジャイルの世界
 
Atomic Architecture
Atomic ArchitectureAtomic Architecture
Atomic Architecture
 
それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?それはYAGNIか? それとも思考停止か?
それはYAGNIか? それとも思考停止か?
 
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
思考停止しないアーキテクチャ設計 ➖ JJUG CCC 2018 Fall
 
ウォーターフォールとアジャイルのフェアな比較
ウォーターフォールとアジャイルのフェアな比較ウォーターフォールとアジャイルのフェアな比較
ウォーターフォールとアジャイルのフェアな比較
 
How to find tech books
How to find tech booksHow to find tech books
How to find tech books
 
Antifragile Java - Java Day Tokyo 2017 D1-E1
Antifragile Java - Java Day Tokyo 2017 D1-E1Antifragile Java - Java Day Tokyo 2017 D1-E1
Antifragile Java - Java Day Tokyo 2017 D1-E1
 
たとえ日本人同士でも必要な異文化理解力
たとえ日本人同士でも必要な異文化理解力たとえ日本人同士でも必要な異文化理解力
たとえ日本人同士でも必要な異文化理解力
 
SIerにとっての越境 @ DevLOVE 199
SIerにとっての越境 @ DevLOVE 199SIerにとっての越境 @ DevLOVE 199
SIerにとっての越境 @ DevLOVE 199
 
Antifragile Clojure
Antifragile ClojureAntifragile Clojure
Antifragile Clojure
 
Boilerplate vs Magic
Boilerplate vs MagicBoilerplate vs Magic
Boilerplate vs Magic
 
既婚プログラマの時間捻出術
既婚プログラマの時間捻出術既婚プログラマの時間捻出術
既婚プログラマの時間捻出術
 

強いて言えば「集約どう実装するのかな、を考える」な話