Building microservices through Event Driven Architecture part2 : domain objects and business rules
This tutorial is the second part of a series : Building microservices through Event Driven Architecture
During this journey, I will implement the domain model
This is innermost layer that holds the core domain. It contains our domain objects and business rules. and defines our External Interfaces.
Databases, network connections, filesystem, UI or special frameworks are not allowed.
The core domain have no knowledge of anything outside of themselve
Those dependencies, and their implementations are injected into our core domain using interfaces.
At the end of the previous step, we ended up with an anemic domain model. So let’s start by enriching it
RICH DOMAIN MODEL
An anemic domain model is a antipattern in the world of DDD, so in this section I will decouple the domain model from data contracts using Value Object.
An anemic domain model is a domain model where data and operations upon that data are separated from each other. In other words a class with only properties and methods that treat this properties are located in another classes.
As a result, these other classes can read the data but also modify it. So the domain class must have public setters. This is lack of encapsulation antipattern
Let us begin by validation the Title
My first test will be : The title lenght must be greater than 10 caracters and less than 60 caracters
The test will fails, so let us implement the title validation:
TITLE VALUE OBJECT
The main difference between entity and value object is how to identify them
An Entity is identified by Reference Equality and Identifier Equality
A Value Object is identified by Reference Equality and Structural Equality
- Reference Equality : Two objects are equal if they reference the same object in memory
- Identifier Equality : Two objects are equal if they have the same identity
- Structural Equality : Two objects are equal if all their members are equals
An Entity has Id field and is mutable while a Value Object have no Id Field and imutable.
A Value Object does not make sense without Entity, It must belongs to an Entity.
Consider the following situation:
- 2 vehicles of the same models, same colors, same ages, etc … are always 2 different vehicles because each vehicle has its own identifier: Vehicles is an entity.
- 2 addresses that have all their fields equals (same street number, same city, same country, etc…) is exactly the same address: adress is a Value Object
My first implementation of Title look like this:
Let us fix test
Remember that A Value Object is identified by Reference Equality and Structural Equality
So Right click Title class and select Generate Equals and GetHashCode.
Title have only one value , so select it and click OK
The Title is now a value object and it’s final implementation will look like this
Here is the unit test of Title Value Object. I should verify that 2 titles are equals if they have same values, and différent if not
URL VALUE OBJECT
All the logic to validate a Url is implemented inside a Value Object whose name is UrlValue
TYPE VALUE OBJECT
All the logic to validate a SpeechType is implemented inside a Value Object whose name is SpeechType
And Speech Domain Object look like this :
ENTITIES AND AGGREGATES
Remember that an Entity is identified by Reference Equality and Identifier Equality and has an Id field. So let us create a base Entity class : Entity<T>, and generate Equals and GetHashCode on Id Field. If 2 entities E1 and E2 have the same id, then E1==E2 should return true
A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it’s useful to treat the order (together with its line items) as a single aggregate.
An aggregate should be always in a valid state and each aggregate have a root wich is an entity, and classes that does not belongs to this aggregate can only reference the aggregate root.
So, let us create a base class AggregateRoot<T> that inherits from Entity<T>, I make it generic because T is the type of the Id field, And it can vary according to these entities
Domain Events enable communications between bounded contexts by avoiding direct calls. So a bounded context B1 raise an event and one or more bounded contexts B2…Bn subcribers to this event, should handle the event to consume it.
So let us create a base class DomainEvent
But here, because of my strategy of implementing the event sourcing, all the events produced by my bounded context will all be saved in my eventstore.
And other bounded contexts, services or other programs interested in these events will have to subscribe to a service bus.
For example, each time I create a new Speech, then I will create a SpeechCreatedEvent event
The class SpeechCreatedEvent must inherit from DomainEvent base class
The final implementation of my aggregateroot will look like this :
And because, Speech Entity is the aggregate root, So let us go ahead and inherit it from AggregateRoot<Guid>, the Id field of Speech Entity is a Guid
Let us add a few tests to cover domainEvents,
LogCorner.EduSync.Speech.Application and LogCorner.EduSync.Speech.Domain are 100% code coverage
Thank you for reading
in the next step, I will implement presentation : LogCorner.EduSync.Speech.Application
Code source is availabe here RegisterSpeechDomain