質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

トランザクション

トランザクションとは、関連・依存する処理を一連の不可分な処理単位として扱う処理方式を指します。トランザクションとして管理された処理は「すべて成功」か「すべて失敗」のいずれかであることが保証される。処理に失敗した場合は、一連の処理がロールバックされます。

Q&A

1回答

1364閲覧

DDDにおける1集約=1トランザクションの際の結果整合性について

gaku3601

総合スコア4

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

トランザクション

トランザクションとは、関連・依存する処理を一連の不可分な処理単位として扱う処理方式を指します。トランザクションとして管理された処理は「すべて成功」か「すべて失敗」のいずれかであることが保証される。処理に失敗した場合は、一連の処理がロールバックされます。

0グッド

1クリップ

投稿2020/04/06 11:51

編集2020/04/06 21:55

こんにちわ。DDD初学者のものです。
DDDにおける1集約=1トランザクションの制約において、結果整合性をどう実装すれば良いかずっと悩んでおりまして、質問させてください。

前提

仕事集約: id, title, point, userID
口座集約: id, userID, value
があったとして、仕事を依頼する際に、口座の全残高を確認し、仕事完了時にお支払いするお金(仕事集約のpoint)が全残高より少ない場合、仕事依頼を行うことができ、かつ、その時点で口座からpoint分のお金を引くという処理を実装したいと思っています。

また、ドメインイベントを利用して、仕事集約内で非同期でイベントpublish(pointを送信)して口座集約の更新を行うことを考えています。(ESは導入しません。こちらの記事の「イベントの発信と受信の流れ」の一番左のイメージ[https://codezine.jp/article/detail/10392])

この時、DDDにおける1集約=1トランザクションの原則に則って、コードを書く場合、どうすれば良いか悩んでいます。

悩んでいるポイント

仕事集約ではcommitできたが、口座集約ではerrorになった場合、お金を払っていないのに、仕事を依頼することができてしまう。
口座集約ではcommitできたが、仕事集約ではerrorになった場合、お金を払ったのに、仕事を依頼することができない。

検討した解決策1

仕事集約: id, title, point, userID
口座集約: id, userID, value, workID
のように、口座集約にworkIDをもたせる。
そして、口座を参照する際に、口座集約のworkIDが仕事集約に存在するか確認し、仕事集約に存在する場合、有効な口座引き落としと判断する。そのようなデータのみ返却する。(仕事集約を参照する際もしかり。口座集約にworkIDが存在するか確かめて返却する)
こうすれば、仕事集約がerrorになり、口座集約がcommitできた場合でも、そういったデータは参照することができないようになります。
結果として口座集約に不要なゴミデータが残りますが、readにおいて整合性は保たれた状態となります。(readで整合性を担保する)

検討した解決策2

仕事集約: id, title, point, userID, key
口座集約: id, userID, value, key
のように各集約にkeyをもたせる。
keyには同一の値が格納されるものとする。

この時、1分おきに仕事集約と口座集約でkeyのペアが存在しているか確認するワーカーを起動させておき、keyのペアが存在しないデータは削除する。
この仕組を実装すれば、仕事集約でcommitできたが、口座集約ではerrorとなった場合、一時的に不整合な状態となるが、ワーカーが起動すれば仕事集約のデータは削除されるので、整合性が保たれた状態になります。

質問

今回の仕様において、DDDにおいて整合性を保つために「検討した解決策1,2」のどちらを採用するべきでしょうか。
検討した解決策1は簡単に実装できますが、ゴミデータが残るし、参照時に必ず2つの集約を参照して取得する必要があるという、暗黙の了解が生まれる気がして、別の開発者が触った場合、バグになる可能性があるのではないかという懸念があります。
また、解決策2の場合、keyという「実装都合によるデータ」を集約に持たせる必要があり、DDDをやる上でそういったことはしたくないなと思ったりします。(解決策1のworkIDの場合、集約を口座代帳という概念にし、workIDは摘要と考えれば説明つくなと考えています。)
その上解決策2はワーカーを実装する必要があり、実装も解決策1に比べて難易度があがる気がしています。

みなさんならこういった仕様の場合どう実装されますでしょうか?解決策1、2どちらをとりますか?
それともマイクロサービスでいうsagaパターンや、2フェーズコミット等を取り入れますでしょうか?

そもそも、前提が間違っているのかもしれませんが、その場合も教えていただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

仕事集約: id, title, point, userID

口座集約: id, userID, value
があったとして

DDDに馴染んではいないのですが、考え方が逆なのではないでしょうか。

自分としては、「1つのトランザクションで操作したい単位」を1つの「集約」として定義するものであって、集約を超えたトランザクションは「集約の切り方がおかしい」ということを意味すると考えました。

投稿2020/04/06 12:08

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gaku3601

2020/04/06 12:18 編集

maisumakunさん ご回答のほど、本当にありがとうございます。 DDDにおいて、1集約=1トランザクションの考えからすると、ご回答いただいた内容はごもっともだと思います。 ただ、回答いただいた内容からモデリングを行う場合、 ユーザ集約(集約ルート): id, userID, []口座エンティティ, []仕事エンティティ 仕事エンティティ(ユーザ集約の子エンティティ): id, title, point, userID 口座エンティティ(ユーザ集約の子エンティティ): id, userID, value となってしまい、集約が大きすぎる気もしていたりします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問