Search code examples
eventsdomain-driven-designcqrsevent-sourcingaggregateroot

How to "query" the aggregate to see if a command can be executed


I have an email draft as a aggregate root with the following commands: addToRecipient, addCcRecipient, addBccRecipient, updateBodyText, uploadAttachment, removeAttachment and in the UI I want to disable the SEND button if the draft is not ready to be sent (i.e. there is at least on to recipient and the body has text). I know I'm not allowed to query the aggregate but it is the only one that can tell me that I can or can't send the email.

If I am to apply what I know about event sourcing and CQRS, then the aggregate would emit an EmailIsReadyToBeSent event and my UserEmailDrafts read model would pick that and update the UI somehow but then, I would have to check after every command and send a canceling event i.e. EmailIsNotReadyToBeSent.

This feels very complicated, what do you think?


Solution

  • The fact that an email cannot be sent unless there is a recipient and body is bordering on applicative logic, because at the end of the day it's more a matter of fields being filled in on a form than complex domain invariants.

    Rather than relying on a full cross-tier round trip querying the read model each time something changes on the screen, I would inject some knowledge of these basic rules in the UI so that the button is instantaneously re-enabled when recipient and body are specified.

    Much like you aren't shocked when you see client-side logic doing required field validation on a form, actually. It's a perfectly valid and accepted tradeoff since the logic is simple and universal.

    Note that this doesn't prevent you from having these rules in the aggregate as well, rejecting any command that wouldn't satisfy them.