株式会社ログラス テックブログPublicationへの投稿🐘DDDで集約を跨いだ情報でロジックを構築するための「getter高階関数パターン」の紹介Yuito Sato2024/10/01に公開4件DDD関数型tech株式会社ログラス テックブログPublication株式会社ログラスは「良い景気を作ろう。」をミッションに、企業経営を推進する次世代型経営管理クラウド「Loglass 経営管理」を開発し提供しています。Discussiondog_cat_fox2024/10/03自分だと orderLines を作って Order.create に渡してしまいそう。 動かしてなくてすみませんがこんな感じです。 val newOrder = Order.create( orderLines = dto.lineParams.map { param -> val product = productIdMap[param.productId] ?: throw NotFoundException() OrderLine.create(param, product) } ) これだと OrderLine が外に露出しているので DDD 的にあんまり良く無いんですかね。 Yuito Sato2024/10/03質問ありがとうございます。 DDD的というよりかは自然言語としてどのような文章が成立するかで考えると責務をどこに置くべきかわかりやすいかなと思いました。 「化粧水を2個、洗顔料を1個で注文を作る」という文章通りにロジックを書くならば入力は化粧水2個と洗顔料1個であり、出力は注文です。このとき文章を見ると注文金額の計算は外から隠蔽されているので注文作成が注文明細の小計計算の責務を持つべきなのではと思っています。 返信を追加coppla2024/10/04ドメインサービスをむやみに利用させないアイデアとして非常に参考になりました。サービスは意味が広く慎重に管理しないとすぐ肥大化していくので。。。 ちょっと気になったのが、本来サービスに隔離すべき Entity を越境した依存関係が不用意に Entity へ集約されてしまった神 Entity ができてしまうのではないか、と感じました。(このあたりはトレードオフだとは思いますが) 「getter高階関数」と定義している部分は、リポジトリの抽象に依存するという内容を言い換えたものと理解したので、私だったら Read だけができる IReadProductRepository に依存したドメインサービスの実装を検討します。 class CreateOrderService( private val orderRepository: IOrderRepository, private val productRepository: IReadProductRepository, ) { fun create( lineParams: List<CreateOrderLineParam>, ): Order { // Order 作成処理 } } 普段 Kotlin を使わないので、このような実装はできないという前提があったのなら申し訳ありません。 Yuito Sato2024/10/05コメントありがとうございます。CreateOrderSeviceというのはドメインサービスでProductRepossiotry全体の依存ではなくRead処理だけの依存に限定したものですね。たしかにコード量が増えるデメリット以外では依存を限定できるのでこちらのほうが単純なドメインサービスより良いですね。 もちろんこのような実装はKotlinでも可能です。 返信を追加
dog_cat_fox2024/10/03自分だと orderLines を作って Order.create に渡してしまいそう。 動かしてなくてすみませんがこんな感じです。 val newOrder = Order.create( orderLines = dto.lineParams.map { param -> val product = productIdMap[param.productId] ?: throw NotFoundException() OrderLine.create(param, product) } ) これだと OrderLine が外に露出しているので DDD 的にあんまり良く無いんですかね。 Yuito Sato2024/10/03質問ありがとうございます。 DDD的というよりかは自然言語としてどのような文章が成立するかで考えると責務をどこに置くべきかわかりやすいかなと思いました。 「化粧水を2個、洗顔料を1個で注文を作る」という文章通りにロジックを書くならば入力は化粧水2個と洗顔料1個であり、出力は注文です。このとき文章を見ると注文金額の計算は外から隠蔽されているので注文作成が注文明細の小計計算の責務を持つべきなのではと思っています。 返信を追加
Yuito Sato2024/10/03質問ありがとうございます。 DDD的というよりかは自然言語としてどのような文章が成立するかで考えると責務をどこに置くべきかわかりやすいかなと思いました。 「化粧水を2個、洗顔料を1個で注文を作る」という文章通りにロジックを書くならば入力は化粧水2個と洗顔料1個であり、出力は注文です。このとき文章を見ると注文金額の計算は外から隠蔽されているので注文作成が注文明細の小計計算の責務を持つべきなのではと思っています。
coppla2024/10/04ドメインサービスをむやみに利用させないアイデアとして非常に参考になりました。サービスは意味が広く慎重に管理しないとすぐ肥大化していくので。。。 ちょっと気になったのが、本来サービスに隔離すべき Entity を越境した依存関係が不用意に Entity へ集約されてしまった神 Entity ができてしまうのではないか、と感じました。(このあたりはトレードオフだとは思いますが) 「getter高階関数」と定義している部分は、リポジトリの抽象に依存するという内容を言い換えたものと理解したので、私だったら Read だけができる IReadProductRepository に依存したドメインサービスの実装を検討します。 class CreateOrderService( private val orderRepository: IOrderRepository, private val productRepository: IReadProductRepository, ) { fun create( lineParams: List<CreateOrderLineParam>, ): Order { // Order 作成処理 } } 普段 Kotlin を使わないので、このような実装はできないという前提があったのなら申し訳ありません。 Yuito Sato2024/10/05コメントありがとうございます。CreateOrderSeviceというのはドメインサービスでProductRepossiotry全体の依存ではなくRead処理だけの依存に限定したものですね。たしかにコード量が増えるデメリット以外では依存を限定できるのでこちらのほうが単純なドメインサービスより良いですね。 もちろんこのような実装はKotlinでも可能です。 返信を追加
Yuito Sato2024/10/05コメントありがとうございます。CreateOrderSeviceというのはドメインサービスでProductRepossiotry全体の依存ではなくRead処理だけの依存に限定したものですね。たしかにコード量が増えるデメリット以外では依存を限定できるのでこちらのほうが単純なドメインサービスより良いですね。 もちろんこのような実装はKotlinでも可能です。
Discussion
自分だと
orderLinesを作ってOrder.createに渡してしまいそう。動かしてなくてすみませんがこんな感じです。
これだと
OrderLineが外に露出しているので DDD 的にあんまり良く無いんですかね。質問ありがとうございます。
DDD的というよりかは自然言語としてどのような文章が成立するかで考えると責務をどこに置くべきかわかりやすいかなと思いました。
「化粧水を2個、洗顔料を1個で注文を作る」という文章通りにロジックを書くならば入力は化粧水2個と洗顔料1個であり、出力は注文です。このとき文章を見ると注文金額の計算は外から隠蔽されているので注文作成が注文明細の小計計算の責務を持つべきなのではと思っています。
ドメインサービスをむやみに利用させないアイデアとして非常に参考になりました。サービスは意味が広く慎重に管理しないとすぐ肥大化していくので。。。
ちょっと気になったのが、本来サービスに隔離すべき Entity を越境した依存関係が不用意に Entity へ集約されてしまった神 Entity ができてしまうのではないか、と感じました。(このあたりはトレードオフだとは思いますが)
「getter高階関数」と定義している部分は、リポジトリの抽象に依存するという内容を言い換えたものと理解したので、私だったら Read だけができる
IReadProductRepositoryに依存したドメインサービスの実装を検討します。普段 Kotlin を使わないので、このような実装はできないという前提があったのなら申し訳ありません。
コメントありがとうございます。CreateOrderSeviceというのはドメインサービスでProductRepossiotry全体の依存ではなくRead処理だけの依存に限定したものですね。たしかにコード量が増えるデメリット以外では依存を限定できるのでこちらのほうが単純なドメインサービスより良いですね。
もちろんこのような実装はKotlinでも可能です。