I am trying to follow Vaughn Vernon guidelines on aggregate design.
I understand that keeping aggregates as small as possible is advised for the many reasons mentioned in his series and by many DDD practitioners.
But this creates an issue handling unrelated command properties inside an aggregate host.
I have an incoming command that contains the necessary information for the system to conduct a transaction in full. The information contained in the command does not fit into a single aggregate since they are minimal.
So, I am considering this to be a long running transaction. I am controlling the entire transaction flow using the saga pattern.
Every host that wraps an aggregate involved in this long running transaction raises a domain event. That domain event is then intercepted by the saga which in turn issues the subsequent command and so on and so forth until the business transaction either gets carried successfully or fails altogether.
If we imagine a scenario where we have a command of the kind:
Send Message X from Participant Y in Conversation Z
This command for instance would be intercepted by the host of the Message aggregate.
This host would rehydrate the Message aggregate, tells it to validate the first part of the transaction:
Send Message X from participant Y.
The same host that intercepted the command would then have to raise a domain event say
MessageCreated, the issue here is that MessageCreated event would need to carry the rest of the business transaction details
In conversation Z
For the subsequent aggregate to execute the rest of the transaction.
Since Message aggregate does not care about ConversationId its host would need to keep that information (needlessly from the perspective of the aggregate).
When the aggregate approves the transaction, the host would then have to create a domain event say MessageCreated * and attach ConversationId to it.
My concern here is that by keeping information that is not necessary to the execution of the business transaction inside the host would over time accumulate with more business requirements coming along at best and would probably create coupling in logic between hosts at worst.
To my question:
Is this considered a safe approach to handle long running transaction and if not what would be a better alternative?
That irrelevant data needs to be propagated between operations for the purpose of future operations suggests some redesign may be beneficial. This is the first I've heard of the aggregate design but it seems like the general idea is operations on an aggregate should not leave any part of it in an invalid state in the context of the aggregate. The general idea behind saga is a change in state is an event, events should be broadcast when they happen, and operations should be triggered by certain events.
One way to approach this is to reconsider the decision that a message does not depend on the conversation. Ex:
Message (uuid, content, timestamp, participant id, conversation id)
Participant (uuid, first name, last name, email)
Conversation (uuid, list of message ids, list of participant ids)
Given these aggregates and events, one approach is:
Send Message X from Participant Y in Conversation Z