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

  • EduSync.Speech.Domain

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

lack of encapsulation_1

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

RegisterSpeechWithTitleLessThan10CaractersThrowsDomainException

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:

TitelValueObject

Let us fix test

TitelValueObjectGreen

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

TitelValueObjectHashcode

The Title is now a value object and it’s final implementation will look like this

0

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

TitelValueObjectUnitTest

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

SpeechTypeValueUbject

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

Entity

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

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

DomainEvents

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

AddDomainEvent

The class SpeechCreatedEvent  must inherit from  DomainEvent base class                              SpeechCreateEvent

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

SpeechEntity

Let us add a few tests to cover domainEvents,

DomainEventsUnitTest

LogCorner.EduSync.Speech.Application and LogCorner.EduSync.Speech.Domain are 100% code coverage

FinalCodeCoverage

Thank you for reading

in the next step, I will implement presentation : LogCorner.EduSync.Speech.Application

Code source is availabe here RegisterSpeechDomain

Gora LEYE

I'm a microsoft most valuable professional (MVP) .NET Architect and Technical Expert skills located in Paris (FRANCE). The purpose of this blog is mainly to post general .NET tips and tricks, www.masterconduite.com Gora LEYE

Support us

BMC logoBuy me a coffee