Modeling Events

In order to describe your business Domain accurately, you'll have to work closely with Domain Experts and define the Ubiquitous Language. This requires crafting Domain concepts using Domain Events, Entities, Value Objects, and so on. When modeling Events, name them and their properties according to the Ubiquitous Language, in the Bounded Context where they originated. If an Event is the result of executing a command operation on an Aggregate, the name is usually derived from the command that was executed. It's important that the Event name reflects the past nature of the occurrence.

Let's consider our user registration feature; the Domain Event needs to represent it. The following code shows a minimal interface for a base Domain Event:

interface DomainEvent 
{
/**
* @return DateTimeImmutable
*/
public function occurredOn();
}

As you can see, the minimum information required is a DateTimeImmutable, which is necessary in order to know when the Event happened.

Now let's model the new user registration Event using the following code. As we mentioned above, the name should be a verb in the past tense, so UserRegistered is probably a good choice:

class UserRegistered implements DomainEvent 
{
private $userId;

public function __construct(UserId $userId)
{
$this->userId = $userId;
$this->occurredOn = new DateTimeImmutable();
}

public function userId()
{
return $this->userId;
}

public function occurredOn()
{
return $this->occurredOn;
}
}

The minimum amount of information required to notify subscribers about the creation of new users is the UserId. With this information, any process, command, or Application Service — from either the same Bounded Context or a different one — may react to this Event.

As a Rule of Thumb
  • Domain Events are usually designed as immutable
  • The Constructor will initialize the full state of the Domain Event.
  • Domain Events will have getters to access their attributes
  • Include the identity of the Aggregate that performs the action
  • Include other Aggregate identities related to the first one
  • Include parameters that caused the Event (if useful)

But what happens if your Domain experts from the same Bounded Context or a different one need more information? Let's see the same Domain Event modeled with more information — for example, the email address:

class UserRegistered implements DomainEvent
{
private $userId;
private $userEmail ;

public function __construct(UserId $userId, $userEmail)
{
$this-> userId = $userId;
$this->userEmail = $userEmail ;
$this->occurredOn = new DateTimeImmutable();
}

public function userId()
{
return $this->userId;
}

public function userEmail ()
{
return $this->userEmail ;
}

public function occurredOn()
{
return $this->occurredOn;
}
}

Above, we've added the email address. Adding more information to a Domain Event can help improve performance or simplify the integration between different Bounded Contexts. Thinking from the point of view of another Bounded Context could help modeling Events. When a new user is created in the upstream Bounded Context, the downstream one would have to create its own user. Adding the user email could possibly save a sync request to the upstream Bounded Context in the case the downstream one needed it.

Do you remember the gamification example? In order to create a user of the gamification platform, probably called Player, the UserId from the e-commerce Bounded Context was probably enough. But what happens if the gamification platform has to notify the users by email about being rewarded? In this case, the email address is also mandatory. So if the email address is included in the original Domain Event, we're done. If that's not the case, the gamification Bounded Context needs to request this information from the e-commerce Bounded Context via REST or SOA integration.

Why Not the Whole User Entity?
Wondering if you should include the whole User Entity from your Bounded Context in the Domain Event? Our suggestion is that you don't. Domain Events might be used to communicate messages internally to a given Bounded Context or externally to other Bounded Contexts. In other words, what can be a Seller in a C2C e-commerce product catalog Bounded Context can be an Author of a product review in a product feedback one. Both can share the same ID or email, but Seller and Author are different concepts representing different Entities from different Bounded Contexts. So Entities from one Bounded Context have no meaning or a totally different one in another Bounded Context.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset