Classic bank transaction example

655 views
Skip to first unread message

Simon Harris

unread,
Jul 30, 2010, 10:03:30 AM7/30/10
to DDD/CQRS
If a domain event only affects a single AR, does that mean a transfer
command would result in two events - one for the debit, and another
for the credit? This seems odd but necessary if events carry the
consequences of a command rather than the intent.

Szymon Pobiega

unread,
Jul 30, 2010, 10:52:34 AM7/30/10
to ddd...@googlegroups.com
It depneds on how do you model a money transfer. It can be implicit when one command executes behavior on two different account aggregates (debit on one and credit on another) but this way one of the most important parts of accounting logic (that every transfer should add up to zero) leaks from domain model to upper layers.

Another, explicit, solution would be to create a Transfer aggregate with references to both accounts. I didn't have opportunity to model this behavior in CQRS/EventSourcing way, but there is an excelent explanation of pros and cons associated with different money transfer modeling thechniques in Martin Fowlers Analysis Patterns book.

Hope that helps

Szymon

2010/7/30 Simon Harris <haruki...@mac.com>

Mark Nijhof

unread,
Jul 30, 2010, 11:55:29 AM7/30/10
to ddd...@googlegroups.com
I have implemented this in my example: Github -> fohjin

TransferMoneyCommand
Handler -> loads correct Account AR -> executes behavior
Domain behavior decides whether or not this transfer is permitted
- NO -> throws an exception (this is just the example)
- YES -> Fires a MoneyTransferedEvent containing the account, amount and ...
Event handler picks this up, checks if it is a local (to the bank)
account or not (actually a domain service will most likely do this
checking)
- NO -> Fires a command to send this to the external bank
- YES -> Fires a command ReceiveMoneyTransfer for the receiving AR
Money gets added by the behvior resulting in a MoneyTransferReceivedEvent
Event gets published

If anything here goes wrong the whole chain is being compensated, this
happens by again a command and events ;)

-Mark

--
Mark Nijhof
m: 0047 95 00 99 37
e:  mark....@cre8ivethought.com
w: www.cre8ivethought.com

"Walking on water and developing software from a specification are
easy if both are frozen."

-- Edward V Berard

Mark Nijhof

unread,
Jul 30, 2010, 11:55:53 AM7/30/10
to ddd...@googlegroups.com
Of course agreeing with Szymon, It all depends :)

-Mark

Stefan Moser

unread,
Jul 30, 2010, 2:39:37 PM7/30/10
to ddd...@googlegroups.com
Good example.  To address the original question, I see no problem with the command resulting in two events.  In fact, this is how accounting systems would model it, with a balancing transaction on either side.  

- Stefan

Mark Nijhof

unread,
Jul 30, 2010, 2:57:18 PM7/30/10
to ddd...@googlegroups.com
Please notice that it really is only one event for one command, only
on event will be handled and that means one command is send which
results in another event. But on AR can of course publish multiple
events per behavior (command call this behavior) all tho I haven't
really seen it yet. Either eventA or eventB is more likely.

-Mark

Simon Harris

unread,
Jul 30, 2010, 5:25:45 PM7/30/10
to ddd...@googlegroups.com
fwiw, my preferred method is to record a single event and have both ARs read it when updating their current state but vie not seen any other peoples examples where an event relates specifically to more than one AR so I was curious what others were doing.

Simon Harris

unread,
Jul 30, 2010, 5:31:32 PM7/30/10
to ddd...@googlegroups.com
On 31/07/2010, at 4:57, Mark Nijhof <mark....@cre8ivethought.com> wrote:

> But on AR can of course publish multiple
> events per behavior (command call this behavior) all tho I haven't
> really seen it yet. Either eventA or eventB is more likely.
>
> -Mark

I had a brief discussion in another thread about this. in my replication scenario, i perceive a need for events to be linked in some fashion so that conflict resolution can be more readily achieved. if events appear as discrete items, understanding what needs to be resolved will be much more difficult.

Greg Young

unread,
Jul 31, 2010, 5:39:40 AM7/31/10
to ddd...@googlegroups.com
perhaps a natural id such as "tranferid" would allow a simple linking?

--
Les erreurs de grammaire et de syntaxe ont été incluses pour m'assurer
de votre attention

Simon Harris

unread,
Jul 31, 2010, 5:46:30 AM7/31/10
to ddd...@googlegroups.com
indeed. I think I'm struggling to reconcile the cross AR nature of it in this example.

Greg Young

unread,
Jul 31, 2010, 5:51:36 AM7/31/10
to ddd...@googlegroups.com
Does it matter if its cross aggregate later?

I want to reconcile 2 events as they come down the stream. I don't
really care if they were written originally in the same transaction,
just that I can tie them together...

Simon Harris

unread,
Jul 31, 2010, 6:01:59 AM7/31/10
to ddd...@googlegroups.com
sorry poor communication. the linking bit is fine it's the actual idea that an aggregate would create events that affect other aggregates that concerns me. so that implies a command might affect multiple aggregates, which i guess it probably does.

Greg Young

unread,
Jul 31, 2010, 6:04:21 AM7/31/10
to ddd...@googlegroups.com
hmm not sure I am following you. a transfer is not affecting multiple
aggregates in the example above.

consider:

transfercreated
deposit
withdrawl
transfercompleted

where you would also be getting any error handling to occur. At no
time does one command ever affect more than 1 aggregate ...

Simon Harris

unread,
Jul 31, 2010, 6:06:33 AM7/31/10
to ddd...@googlegroups.com
sure, the source of the withdrawal and target of the deposit.

Greg Young

unread,
Jul 31, 2010, 6:08:55 AM7/31/10
to ddd...@googlegroups.com
Does that have to happen in the same transaction?

Simon Harris

unread,
Jul 31, 2010, 6:10:26 AM7/31/10
to ddd...@googlegroups.com
well a user issued a single command. semantically it's a transfer not a deposit and a withdrawal.

Greg Young

unread,
Jul 31, 2010, 6:15:45 AM7/31/10
to ddd...@googlegroups.com
I issue a command to amazon to buy something. Do they implement it
internally in their "system" (refering to their overall organization)
as a single event?

Simon Harris

unread,
Jul 31, 2010, 6:25:23 AM7/31/10
to ddd...@googlegroups.com
no but I'm guessing they record a single event which then asynchronously triggers subsequent commands in other internal systems.

Greg Young

unread,
Jul 31, 2010, 6:40:07 AM7/31/10
to ddd...@googlegroups.com
Is that not what I suggested?

Simon Harris

unread,
Jul 31, 2010, 8:03:18 AM7/31/10
to ddd...@googlegroups.com
not sure but in my mind that equates to a transfer command, a transferred event, and other systems generating deposit and withdrawal commands/events. so theres no need for a transfer command to generate multiple events.

Simon Harris

unread,
Jul 31, 2010, 8:07:07 AM7/31/10
to ddd...@googlegroups.com
or in your example, the created/completed events. in any case I don't see that as a command generating multiple events. i see it as a single command with a single event with other systems responding with subsequent commands which in turn result in more events.

On 31/07/2010, at 20:40, Greg Young <gregor...@gmail.com> wrote:

Greg Young

unread,
Jul 31, 2010, 8:22:14 AM7/31/10
to ddd...@googlegroups.com
That is exactly how I see it. I see a transferattemptcreated event ...
then I see a saga that does the actual withdrawls etc and finally some
transfercompleted or transferfailed event.

Simon Harris

unread,
Jul 31, 2010, 8:26:27 AM7/31/10
to ddd...@googlegroups.com
right. so my question was supposed to be, though clearly not articulated well enough, whether people have commands that in the same interaction generate multiple events - as opposed to eventually result in over the duration of an epic/saga.

Greg Young

unread,
Jul 31, 2010, 9:04:26 AM7/31/10
to ddd...@googlegroups.com
Sure consider "Place Order" to a stock market. It can produce multiple
events in a single consistent transaction consider:

Buy side:
A 1000 @ 1.00
B 100 @ 1.00
C 5000 @ .99
D 400 @.99

PlaceOrderCommand
S Sell 1500 @ .99

generates

Trade A-S 1000 @ 1.00
Trade B-S 100 @ 1.00
Trade C-S 400 @ .99

Make sense?

Simon Harris

unread,
Aug 1, 2010, 1:10:12 AM8/1/10
to ddd...@googlegroups.com
Indeed. Thanks. Makes perfect sense. It seems there's an implicit expectation then that event sourcing requires a transactional data store?

--
Simon Harris
w: http://www.harukizaemon.com/
e: haruki...@mac.com
m: +61 417 505 611
t: @haruki_zaemon

Simon Harris

unread,
Aug 1, 2010, 2:37:09 AM8/1/10
to ddd...@googlegroups.com
> I don't think so. As long as you have atomic writes, there is no need
> in transactions for append-only storage. You can always write batch at
> once.

Indeed, so I'll be more precise: atomicity over multiple writes. If a command can result in multiple events then atomicity is required for multiple writes which, considering most datastores I can think have either atomicity for a single write/update or fully-blown, ACID, transactions, effectively means a datastore supporting transactions.

In my case I'm looking at CouchDB which has only atomicity of a single write/update. That said it has sophisticated map/reduce views so, I'm considering writing a unit-of-work as a single document and then using map/reduce views to expose the underlying events.

I guess that means no, there's no assumption of multi-write atomicity however I am using a trick -- albeit an intentional, first-order concept -- of the datastore to achieve the same effect. The nice thing about this is I get my linking of related events for "free".

Simon Harris

unread,
Aug 1, 2010, 5:18:04 AM8/1/10
to ddd...@googlegroups.com

On 01/08/2010, at 5:03 PM, Rinat Abdullin wrote:

> Another alternative is to stream in multiple messages and then write
> the final commit message, which will contain identities of the
> messages to be considered as written.

I hadn't considered logical transactions. In my case, I think I'm still erring on the side of committing a unit of work and using views to present it as a sequence of events.

Thanks.

Rinat Abdullin

unread,
Aug 1, 2010, 1:49:02 AM8/1/10
to ddd...@googlegroups.com
I don't think so. As long as you have atomic writes, there is no need
in transactions for append-only storage. You can always write batch at
once.

--
Best regards,
*Rinat Abdullin*

Technology Leader at Lokad.com <http://www.lokad.com> | Writer at
Abdullin.com <http://abdullin.com> | Contacts <http://abdullin.com/contact/>

Rinat Abdullin

unread,
Aug 1, 2010, 3:03:46 AM8/1/10
to ddd...@googlegroups.com
Another alternative is to stream in multiple messages and then write
the final commit message, which will contain identities of the
messages to be considered as written.

Either way we can consider definite multi-write atomicity at the
logical level, as long as all events in a batch belong to the same
entity.


On Sunday, August 1, 2010, Simon Harris <haruki...@mac.com> wrote:

--

Reply all
Reply to author
Forward
0 new messages