User Tools

Site Tools


dddcqrsesapplication

Application structure based on DDD/CQRS/ES

Value Objects

Value Objects are classes that represent more than simply an integer value or a string value. They have no identity, as in $10 or “cat”. Some argue that value objects should not be used in commands and events. However, I don't see why not.

Events

Events are classes that represent things that happened. Optimally, DDD/CQRS/ES systems should not be CRUD systems, so events are usually more meaningful than “NameChanged”. Many argue that only the heart of an application that represents real domain knowledge should be build using DDD/CQRS/ES, and that it is overkill for CRUD applications. Some funcionalities ES gives us out of the box are

  • automatic logging of everything that happened
  • automatic ability to denormalize into any optimized read model - synchronously and asynchronously
  • optimizing application responsiveness due to the separation of reads and writes and the asynchronous nature of writing optimized read models
  • ability to simply add or change read models
  • messaging - pushing events to a message bus, thus allowing for message driven processes to be built on top of the application, or simply reacting to events asynchronously and reliably, such as sending emails

Building DDD/CQRS/ES applications really isn't that much more complicated or involved than building CRUD applications. On top of that, as soon as a CRUD application becomes a little more complex and has more and more requirements, a CRUD architecture becomes very limiting very soon. Adding things such as logging, optimized read models, messaging, (semi-) automated processes, etc. to a CRUD application will be extremely cumbersome and sub-optimal. In my opinion, you may as well go straight to the DDD/CQRS/ES architecture. I do see the value of CRUD for simple bounded contexts such as tenant and licensing management - parts of the application that do not change much and that do not require most of the above functionalities.

Domain

The domain is the heart of the application. This is where the business logic and domain knowledge resides. Domain experts need to be involved and interviewed in order to build a meaningful domain. The domain gives us the competitive advantage, containing the knowledge, experience and expertise of the domain experts involved in designing the domain. Note that the domain does not implement authorization logic. A manufacturing process knows how to manufacture a certain product, and will produce an output (Events) based on the inputs (Method Arguments) it is given. It does not verify if the person initiating the process has the right to do so. If the person gives it valid inputs, it will perform its task. An upstream component is responsible for allowing only authorized people to initiate manufacturing processes.

Aggregates

The Domain consists of Aggregates. An Aggregate is comprised of an Aggregate Root, Entities and Value Objects. Aggregate Roots are the entry point into the Aggregate. They have global identities and contain entities with local identities inside the aggregate, and Value Objects which do not have an identity. Aggregates are responsible for the implementation of the business logic and for maintaining all invariants of the domain. When applying CQRS and Event Sourcing, Aggregates only have void methods and publish Events. Events are the result of the Domain implementing its business logic. They contain everything relevant to what happened inside the method call, in order for denormalizers to comprehensively build read models from the events and other subscribers to the Events to react to them in other ways.

Domain Services

Since Aggregates are self containing and maintain the Domains invariants, Units of Work (UoW) - in Databsase Terms Transactions - are most commonly not required. In case invariants involve more than one Aggregate, a Domain Service can be introduced. The Domain Service will make calls to all Aggregates involved and maintain the invariants spanning the Aggregates. It is often said that if you need a Domain Service, then your Aggregates are poorly designed. Maybe so, maybe not. Designing Domains is more art than science, requiring a lot of experience.

CRUD Domain

If the domain happens to be purely CRUD, Aggregates could be skipped altogether. The Domain would simply consist of Events, and the Application could translate method calls from the outside directly to events. The business logic and maintenance of invariants would then reside inside the Application, not inside the Domain. This would represent a CRUD/ES application architecture style, which would have all of the above mentioned benefits of Event Sourcing, and probably is a good alternative to DDD/CQRS/ES for CRUD applications.

Commands

Commands are messages representing method calls. They can be serialized and sent across the wire, onto message buses, and so on. The application then translates the commands into method calls on Aggregates or Domain Services inside the Domain. Commands are not required. They represent one of several ways to prompt the Application to do something. The benefit of Commands are that

  • they can be sent in a fire and forget way
  • they are very well suited for the implementation of messaged based processes, where a component reacts to Events (Messages) by issuing Commands, and other processes then reacting to the Events raised by those Commands, etc.
  • they are suited for logging purposes, being able to store who issued which Commands, and what Commands led to which Events

Privileges

Privileges are at the heart of authorization.

dddcqrsesapplication.txt · Last modified: 2017/08/14 12:29 by rtavassoli