O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

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

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Próximos SlideShares
Are Design Patterns Dead?
Are Design Patterns Dead?
Carregando em…3
×

Confira estes a seguir

1 de 23 Anúncio

Mais Conteúdo rRelacionado

Mais de Yoshitaka Kawashima (20)

Mais recentes (20)

Anúncio

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

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

×