Take a look at CQRS and Event Sourcing with DDD — Part 2

Furkan Bozdag
Trendyol Tech
Published in
5 min readMay 26, 2020


Once we have an idea about Event Sourcing, CQRS and DDD, we can now implement them. Since we adopt the DDD approach, we will create our project and layer structure according to.

In a simpler way, I will try to explain it without increasing confusion.

If you haven’t read the previous article, you can read it here.

Funkhu — Kemal Sunal, Şener Şen

Let’s start, Funkhu!

When we start doing Event Sourcing and CQRS, we should now consider all transactions as events. And we have to make the transition between layers loosely coupled by doing events. On the other hand, we hit from the service layer to the domain layer, and after every changes we make to the domain, we must throw the event(s). In this way, events has been thrown for all transactions that are performed, and the reliability of the transaction is also ensured. If an error occurs during the transaction, it will be easier for us to follow it because we can store every event and log the necessary about it.

So how do we implement it?

First, I start by creating the project structure. I preferred to proceed using onion architecture. Because Onion Architecutre, which is very convenient for DDD, it will provide you to separate the layers more accurately and responsibilities more. For more information on Onion Architecture, look at here.

Understanding Onion Architecture

As seen in the onion architecture diagram above, I have created a focused structure for Domain, Domain Services and Application services for Application Core as follows.

According to the above drawing, I created the layers as follows.

Api Layer: It accepts incoming requests and throws events for the application layer for commands and queries.

Application Layer: Validations, a layer without domain rules where specific things to be done in the application (mobile, web) are realized. We now use CQRS on this part. We will operate on the database with commands and queries. According to CQRS, the databases for Commands and Queries should be separated, but I went with a single database to make it simple.

Application Contracts Layer: Includes interfaces for the layer that wants to communicate.

Domain Layer: The part where we manage the domain rules, which is the main philosophy of DDD, and throw events for the changes made.

Persistence Layer: Includes infrastructure sides. I used it for database abstraction.

Persistence EFCore Layer(optional): The layer that contains the specific changes I made about the infrastructure. I made it for ORM.

An Example: Creating User Lifecycle

I used mediatR for events in all layers. If desired, message broker or alternatives can be used according to the needs.

  1. A new request comes to the controller to create the user by the client.
Api Layer

2. This incoming request is met on the Application layer and Application rules are now being processed (not Domain rules). Here, we want to add a new record to the database without having a rule.

Application Layer Command Handler
Application Layer Service

3. Transaction completed successfully. But just a second. According to Event Sourcing, changes in the domain may also require events from other layers. For this reason, we will throw events in the domain layer. Finally, We add the changes we made in the domain layer to a list as an event.

User entity

4. Not finished yet. We made changes related to the domain, but we haven’t thrown the events yet. The choice here is entirely up to you. If you want, you can throw events at the same time for changes in the domain. I will throw the changes made in the domain after the operation has been successful in the database.

Abstracted layer for repository
A mediatR extension for domain events
Console log for domain events

5. We have now throw domain events. According to our example here, when a user is created, we can send her/him a welcome email.

Application Layer — Domain Event Handler

As in the example above, we have done both CQRS and Event Sourcing only according to the desire to create a user.

I write when I learn, I learn as I write. I may have made mistakes in many places because I am just a human. I would be glad if you correct it when you see any mistakes.

You can access the source code from here. Thank you for your interest. See you in the next post :)

Follow me;



Furkan Bozdag
Trendyol Tech

I don’t know what’s happening here? | sr. software engineer