Event Sourcing command or event from external system?

Viewed 2494

In most cases I understand the distinction between a command and an event in a CQRS + ES system. However, there is one situation that I can't figure out.

Suppose I am building a personal finance tracking system, where a user can enter debits/credits. Clearly these are commands, and once they are validated the domain model gets updated and an event is published. However, suppose that credit/debit information also comes directly from external systems e.g. the user's florist sends a message that he has charged the user's credit card for his recurring Mother's Day delivery. In this case the message seems like it is an event (the charge has already occurred), but it is possible that the message is malformed and will be rejected. So is it really a command? But then there needs be a way to send an ACK/NACK, which isn't the case here (the florist only sends the message once he knows that the debit has taken place).

EDIT: Just to clarify, I'm not talking about the external system knowing anything about my events and/or commands. I have a component that receives data from the external system and then has to publish an event or send a command. The question is, which of event or command should my component use?

2 Answers

I found this question while wondering the same thing.

I liked Mikael's answer and upvoted it. However, I found another answer on the DDD/CQRS forum that takes a different approach, so figured I'd post it here for others who are looking too.

Here's a quote from Greg Young on a similar question about tracking external state:

In most inventory systems there are no commands.

Or to paraphrase:

Systems that exclusively track external state will have no commands.

Let's rewind and think through how your system might evolve based on this idea (let's also assume you're not building it for yourself):

  • You decide to create a personal financial tracker that records transactions from the outside world, displays graphs, aggregated totals, etc.
  • Because events are for tracking state changes, not commands, you record those. You also write projections in the event handlers for aggregating the events into totals and graph data points.
  • Then you get users. They praise the app, but usage is still low. After digging deeper, you discover that they still use other apps to track finances when, say, there's no API for the local card store for recurring Mother's Day cards, they want to "split" an external transaction into multiple, their bank has no online access, they want to track cash, etc.
  • So you add user-entered transactions. You do so by adding commands that track user-entered transactions. Now we're at the same system as your question.

Note that this variant accepts both commands and events. You wouldn't go back and convert all existing events to commands just because you now allow the user to change things. Instead, you have a system that accepts external transaction events, commands for user-entered transactions and transaction corrections (which create events that modify internal state), and projections to combine these internal and external events for display in the app.

I'm curious though. In hindsight, did the accepted answer end up being a good approach? Or would recording and handling events from the Florist directly like Greg suggests be better?

Related