This document details foodtruacker, a project implementing Domain-Driven Design (DDD), CQRS, and Event Sourcing. It uses ASP.NET Core and focuses on improving maintainability in complex business domains. The project uses a simplified fictional business case for illustrative purposes. This detailed explanation covers the motivations, features, implementation details, and relevant technologies.
foodtruacker - Implementation of DDD, CQRS and Event Sourcing
This event-driven project utilizes principles, frameworks and architectures — all centered around the idea of enhancing maintainability when dealing with systems reflecting complex business domains. The application's Web API is built upon Microsoft's ASP.NET Core framework and implements Domain-driven Design, as well as the CQRS and Event Sourcing patterns. A fictional business case lays the foundation of this project and is the result of an event storming workshop.
Please note: The fictional business domain introduced to this project is heavily simplified and should only be seen as a provider of relatable use cases.
Motivation
Since it is not always best to use CRUD-operations and POCO-objects in projects with rather complex business domains, I decided to create this project as a practical implementation of my research on — and interest in — the Domain-driven Design (DDD) approach of developing software.
Since the fictional business case introduced to this project is heavily event-driven, I decided to also implement the CQRS and Event Sourcing patterns. Both caught my attention while doing the research for this project and go well together with DDD.
Features
Overview
This project consists of one executable Web API application and several functional components, each provided via class libraries. The code is organized by namespaces. In ASP.NET Core applications created in Visual Studio the namespaces, by default, are automatically created from the projects' folder structure. See the below diagram for a grasp overview of the folder (and namespace) structure of this project:
Introduction
Event Storming
A flexible workshop format for collaborative exploration of complex business domains, invented by Alberto Brandolini. It is an extremely lightweight methodology for quickly improving, envisioning, exploring and designing business flows and processes within your organization.
The workshop consists of a group of people with different expertise using colored sticky notes to collaboratively layout relevant business processes. It is mandatory for an EventStorming workshop to both have the right people present and to have enough surface area to place the sticky notes on. Required people typically include those who know the questions to ask (typically developers) and those who know the answers (domain experts, product owners).
The aim of this workshop is to have its participants learn from each other, reveal and refute misconceptions and, e.g. in this GitHub project, do the groundwork for the development of an event based software solution reflecting a correlating business domain.
Domain-driven Design (DDD)
An approach to software development that centers the development on programming a domain model that has a rich understanding of the processes and rules of a correlating business domain. The term „Domain-driven Design“ was coined by Eric Evans in his book of the same title.
DDD aims to ease the creation of complex applications and focusses on three core principles:
Eric Evans’ book defines a few common terms for Domain-Driven Design:
Domain Model
A system of abstractions that describes the processes and policies of a business domain and is used to handle required tasks associated to that domain.
Ubiquitous Language
Words and statements for certain elements of the business domain. In order to guard again misconception, all team members should adopt certain terms, typically those used by the domain experts.
Bounded Context
A conceptual boundary within which a particular domain model is defined and applicable. This typically represents a subsystem or a field of work. It is mainly a linguistic delimitation, with each bounded context having its own Ubiquitous Language.
E.g.: Customer Management where a user is called „customer“.
Eric Evans’ book further differentiates certain parts of the domain model. To name a few:
Entity
An object which is defined by its identity rather than its attributes.
E.g.: A person will always remain the same person, no matter the choice of jacket, hair color or language spoken at a certain moment.
Value Object
An object which is defined solely by the value of its attributes. Value Objects are immutable and do not have a unique identity. Value Objects can be replaced by other Value Objects with the same attributes.
E.g.: When focussing on a person, a broken pair of sunglasses can easily be replaced with a new, equally looking pair of sunglasses.
Aggregate
A cluster of one or more Entities and optional Value Objects, unified to be a single transactional unit. One Entity will form the base of the Aggregate and is thereby declared Aggregate root. All its collaborating Entities’ and Value Objects’ properties may only be accessible through this single base Entity. An Aggregate must always be in a consistent state. In object-oriented programming, this is typically done by using private setters and protected getters.
E.g: In a car sales context, one car (Entity) is defined by its vehicle identification number. This car might have four wheels (Value Objects), which might need to be replaced after a certain time.
Domain Event
An object that is created as a result of activity within the Domain Model. It is used to hold and forward information related to this activity. Domain Events are typically created for those activities the domain experts consider relevant.
Hexagonal architecture (Ports & Adapters)
An architecture pattern used in software design, proposed by Alistair Cockburn in 2005. The pattern aims to achieve a high degree of maintainability and describes an application in three layers. Each layer communicate with the adjacent layer(s) using interfaces (ports) and implementations (adapters):
The key rule in this architecture pattern is that dependencies can only point inwards. Nothing in an inner circle can know anything at all about something in an outer circle. Any dependencies willing to pointing outwards, e.g calling a database from the Application Layer, need to be instantiated via inversion of Control (IoC) or Dependency Injection (DI).
CQRS using MediatR (a pre-built messaging framework)
CQRS stands for Command/Query Responsibility Segregation and was first described by Greg Young in 2010. It is based upon the Command Query Separation (CQS) principle and allows for separation of read and write operations. CQS states:
The improvement from CQRS over CQS is that those commands and queries are treated as models rather than methods. These models can be dispatched as objects at one point, to then be handled by their required, respective handlers at another point in the system, each returning their response models for clear segregation of each action.
The mediator pattern allows to implement Command/Queries and Handlers loosely coupled, utilizing a mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator.
The MediatR framework is an open source implementation of the mediator pattern, created by Jimmy Bogard. It will be utilized in this project for communication between the Framework Layer and the Application Layer. It will also be used for projecting data from the Command database to the Query database.
Event Sourcing
An architectural design pattern for storing every change in the state of an application, rather than storing just the current state of the data in a domain. This pattern was introduced by Greg Young and has since seen numerous adoptions.
The pattern intends to capture every change to the state of an application as an event object. These event object are then stored, in the sequence of occurrence, in an append only manner. This not only allows for the recreation of the current state of an object over the sequence of events that have happened so far, but ultimately allows to go back in time and recreate the objects state for any given time.
A bank account can be a good example of the Event Sourcing principle. Every time money is withdrawn or deposited, instead of just updating the current balance, the amount of change is recorded. The current balance is then calculated by going over the sequence of events, with their corresponding information on how much money was withdrawn or deposited each time.
Event Sourcing plays well with Domain-driven Design, since it is a great fit for storing Domain Events, triggered by the Domain Model with every change request.
Event Sourcing also greatly benefits from CQRS. Instead of having to make a Query against the Event Sourcing database, which would have to go through all recorded events related to the object being requested in order to recreate the current state, this Query can be made against a dedicated Query Database. This Query Database gets updated by its own event handlers, listening to the same events being dispatched right after being appended to the Event Sourcing Database. These updating processes are called Projections.
This separation of databases also lays ground for a huge potential in scalability and performance optimization. Multiple instances of the Query database can be created and hold in sync simply by having their event handlers listening for the events being dispatched from the Event Sourcing Database Client right after a relevant change to the state of an application occurred. The choice of database type as well as the degree of data-denormalization, optimized per query, can greatly enhance performance.
This constant updating of the read model can either happen synchronously or asynchronously. The latter comes at the cost of eventual consistency, with the read model being out of sync with the write model for a tiny time gap (usually milliseconds).
Shared Kernel
A common library for the Domain Layer, which contains common Domain-driven Design specific base classes, Domain Entities, Value Objects, etc. which are shared across Bounded Contexts.
Getting started
To get this project up and running as is, feel free to follow these steps:
Prerequisites
Setup
Launch https://localhost:5001/swagger/index.html in your browser to view the Swagger documentation of your API.
Use Swagger, Postman or any other application to send a POST-request to https://localhost:5001/api/Administration/Register to register your initial admin account. Send the following object:
Look into the console application or whichever output is re-configured for the application's logs. After any successful registration of a user, there should be an email-verification link - provided by the EmailService - written into the logs. Copy and paste this url into your browser and hit enter to complete registration. Feel free to change or build upon this unproper implementation of an email service ;-)
You are all set. Login next.
Launch http://localhost:2113/ in your browser to view the EventStoreDB GUI. Open the "Stream Browser" tab to see all stored events.
Tests can be executed by running:
Technologies
This project utilizes the following Technologies / NuGet packages:
Resources / Recommended Reading
Alberto Brandolini:
https://www.eventstorming.com
Vaughn Vernon:
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_1.pdf
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_2.pdf
https://dddcommunity.org/wp-content/uploads/files/pdfarticles/Vernon2011_3.pdf
Alistair Cockburn:
https://web.archive.org/web/20180822100852/http://alistair.cockburn.us/Hexagonal+architecture
Robert C. Martin (Uncle Bob):
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
Cesar de la Torre, Bill Wagner, Mike Rousos:
https://docs.microsoft.com/en-us/dotnet/architecture/microservices/
Greg Young
https://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf
https://cqrs.wordpress.com/documents/building-event-storage/
https://msdn.microsoft.com/en-us/library/jj591559.aspx
Martin Fowler:
https://www.martinfowler.com/bliki/CQRS.html
Jimmy Bogard:
https://github.com/jbogard/MediatR
https://www.youtube.com/watch?v=SUiWfhAhgQw
Domain-driven Design:
https://dddcommunity.org
https://thedomaindrivendesign.io
https://dotnetcodr.com/2013/09/12/a-model-net-web-service-based-on-domain-driven-design-part-1-introduction/
https://dotnetcodr.com/2015/10/22/domain-driven-design-with-web-api-extensions-part-1-notifications/
Hexagonal Architecture:
https://fideloper.com/hexagonal-architecture
https://herbertograca.com/2017/09/14/ports-adapters-architecture/
Credits
http://www.andreavallotti.tech/en/2018/01/event-sourcing-and-cqrs-in-c/
https://www.exceptionnotfound.net/real-world-cqrs-es-with-asp-net-and-redis-part-1-overview/
https://buildplease.com/pages/fpc-1/
https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-in-net-core-part-1-whats-a-mediator/
https://itnext.io/why-and-how-i-implemented-cqrs-and-mediator-patterns-in-a-microservice-b07034592b6d