Interface Segregation Principle and Domain Events in DDD
Domain-Driven Design is a topic that I’ve been interested in for a long time now. Recently, I’ve been spending more time around the concept of Domain Events. The literature suggests that a domain event is named in the past tense and due to that notion they are considered facts about the system’s current state. This is not what I’ve found in the wild. What I found is mostly events named in the present tense rather than in the past, I think misunderstanding here is fair due to the ambiguity of what we call event in real life. This article is an attempt to explain why I think that defining domain events in the present tense leads to high coupling and low cohesiveness.
The most important aspects of an event in my experience are the following two:
- Naming
- Internal attributes
Naming: One of the reasons to define a domain event in the past tense, is because we are trying to map every operation in terms of what was the user intent rather than what will be the final state of the system. What do I mean by this? Let’s imagine a system in which we create appointments for pets. If we describe a single operation in terms of a sequence of events we can end up with something similar to the following:
AppointmentScheduled -> PetOwnerEmailSent
This to me expresses what happened, following this sequence we can infer what is the current state base on a sequence of facts. This is how we humans communicate with each other, eg. We say something like “I scheduled an appointment for my cat”.
Now, let’s take the same example and define the events in the present tense.
ScheduleAppointment -> SendEmailPetOwner
The main issue that I see with this approach is that is not clear to me if any of the emitted events represent a successful scenario or otherwise.
What happen if we talk about this process with a domain expert? If I try to phrase this in plain English I probably would say “I will schedule an appointment for my pet and then receive an email”, but this is not accurate because the emitted event represents something that happened already or at least it should because we are not going to emit an event before executing the operation that implements the process. Right?
The reason for naming domain events in the past tense is mostly to model the real world and reduce the translation cost that occurs when we talk with a business person and go to the code to identify what just happened. However, the naming could also affect the internal attributes of the domain.
Internal Attributes: How does the naming of an event affect the definition of the internal attribute of an event? Let’s pick one of the present tense defined events. ScheduleAppointment and ask a question: How do we know this was successful to react to it? I believe the initial approach to answering that question will be to add a success
attribute at the event level, this could work, however, if we consider that domain events are a way to reduce coupling through a minimal interface and that the reason for reducing coupling is to allow flexibility to change the system by introducing this field we are segregating the underlying business logic to the consumers. Just imagine that you want to send an email to the pet owners, the component within the system that sends the email will have to check if the scheduling was successful or not, but the question reminds, didn’t we already know that the operation was successful when creating the schedule?. Why does every other consumer need to check for that information again? By introducing this field we effectively breaking the interface segregation principle which dictates that no client should be forced to depend on methods it does not use. This definition is blur though, what does it mean to not “use” something, we are using the field if we check for it, right? Yes, we are, however, if we think in terms of principles we will find that the Tell, Don’t Ask principle is at risk here; if we need to check for a flag for every single consumer then the provider will be forcing consumers to change and that’s a sign of high coupling.
In the case in which we use past tense event what will happen then? Well if we define AppointmentScheduled then we know that we can send the email without checking for anything else if our email component doesn’t receive that event then we don’t have to do anything. No check require and that’s an improvement in my book. Fewer branches reduce complexity.
As explained above the use of present tense for naming events leads to adding attributes just for exposing rules of the state. This practice segregates business logic across consumers which increases coupling and reduces cohesiveness.
I am interested in learning more heuristics behind defining domain events and would like to learn more from others, if you have any please share it in the comments.