Event Semantics

115 views
Skip to first unread message

Mark Murfin

unread,
Aug 16, 2016, 8:07:29 AM8/16/16
to DDD/CQRS
I'm modelling a simple aggregate I named StatusGroup that keeps track of possible status options and other aggregates assignments to those status options. It manages invariants protecting a shared list of valid statuses and an association of aggregates to those statuses. I guess you could think of it as a kind of inventory tracking system, except that not only are the entities changing status fairly often, the available statuses they can change to also changes.

The basic class looks like

class StatusGroup
{
   
public void enableStatus(String status);
   
public void disableStatus(String status);
   
public void assignEntity(String entityID, String status)  throws IllegalArgumentException;
   
public void removeEntityAssignment(String entityID);
}

where enable/disableStatus turns that status on or off for the purposes of whether assignEntity can track the association to that status, or if an IllegalArgumentException needs to be thrown because its not a status that is currently "turned on". removeEntityAssignment just stops tracking an entity when we no longer care about its status.

The event model follows this fairly closely

public interface StatusGroupEventHandler
{
   
public void statusEnabled(String status);
   
public void statusDisabled(String status);
   
public void entityAssignedStatus(String entityID, String status);
   
public void entityAssignmentRemoved(String entityID);
}

The one non-obvious semantic attached to my domain model is that when a status is disable by calling disableStatus, all entities that are currently being tracked by the StatusGroup with that status should be untracked. If the client wants to continue to track those entities, they need to reassign them all to a new status.

SO, my question is whether I should make that consequence a semantic implication of the statusDisabled event - all projections/handlers that care about entity assignemtns should know to stop tracking entity assignments for entities with that status when they receive the statusDisabled event. OR, the StatusGroup itself could query for all entities with a status of the one being disabled and emit entityAssignmentRemoved events for all those entities before emitting the statusDisabled event.

Are there any guidelines for this sort of thing? I tend to think that the semantics should be simple, but I guess if this is a side effect of the aggregate managing its invariants, then that should extend to the event. Also, it seems to me that in a model this simple, there's no reason not to stick with one command -> one event. Thoughts?

Mark Murfin

unread,
Aug 20, 2016, 10:52:15 AM8/20/16
to DDD/CQRS
On Tuesday, August 16, 2016 at 7:07:29 AM UTC-5, Mark Murfin wrote:
The event model follows this fairly closely

public interface StatusGroupEventHandler
{
   
public void statusEnabled(String status);
   
public void statusDisabled(String status);
   
public void entityAssignedStatus(String entityID, String status);
   
public void entityAssignmentRemoved(String entityID);
}




I hope this interface isn't throwing people off. This is just a transformation of the typical pattern I see in other code that would structure an event handler like
 
class StatusEnabledEvent
{
   
public StatusEnabledEvent(String statusGroupID, String status)
   
{
     
this.StatusGroupID = statusGroupID;
     
this.Status = status;
   
}
   
   
public String StatusGroupID;
   
public Strng Status;
}

class StatusDisabledEvent
{
   
public StatusDisabledEvent(String statusGroupID, String status)
   
{
     
this.StatusGroupID = statusGroupID;
     
this.Status = status;
   
}
   
   
public String StatusGroupID;
   
public Strng Status;
}

class EntityAssignedStatusEvent
{
   
public EntityAssignedStatusEvent(String statusGroupID, String entityID, String status)
   
{
     
this.StatusGroupID = statusGroupID;
     
this.EntityID = entityID;
     
this.Status = status;
   
}
   
   
public String StatusGroupID;
   
public String EntityID;
   
public Strng Status;
}

class EntityAssignmentRemovedEvent
{
   
public EntityAssignmentRemovedEvent(String statusGroupID, String entityID)
   
{
     
this.StatusGroupID = statusGroupID;
     
this.EntityID = entityID;
   
}
   
   
public String StatusGroupID;
   
public String EntityID;
}

and then the handler implementation with one or more
void apply(StatusEnabledEvent event)
{
   
// ...
}

Danil Suits

unread,
Aug 20, 2016, 11:33:15 AM8/20/16
to DDD/CQRS
Are there any guidelines for this sort of thing?

Guidelines on domain event design?  I haven't seen any.  My guess would be to look into the work being done by the folks who are exploring Event Storming


my question is whether I should make that consequence a semantic implication of the statusDisabled event - all projections/handlers that care about entity assignemtns should know to stop tracking entity assignments for entities with that status when they receive the statusDisabled event. OR, the StatusGroup itself could query for all entities with a status of the one being disabled and emit entityAssignmentRemoved events for all those entities before emitting the statusDisabled event.

This, I feel more confident in; the aggregate itself should be responsible for reporting the cascading effects of the business rule.

My argument would be that in a different domain, you might have the alternative rule that disabling a status prevents new assignments but preserves the existing assignments.  So we ought to be able to switch between these two different ways of doing business without needing to update all of the observers too.

In other words, the aggregate should be describing everything that needs to change to maintain the invariant.



This might be an application of the principle to make the implicit explicit.




Reply all
Reply to author
Forward
0 new messages