Mar 20 2011

How CQRS can make it easier to discuss architecture

Category: Software DevelopmentJeff @ 11:33

My friend Scott has put down some great thoughts in his recent post, Why is discussing architecture so hard? What started as a simple response turned into a full blown blog post on CQRS. The following are my thoughts on how CQRS can provide some basic initial structure for a project.

~~~~~~~~~~~~~~~~~~~~~

An approach that's working well for us is adoption of CQRS (Command Query Responsibility Segregation) and EDA (Event Driven Architecture).  The basic separation of writes from reads leads to some interesting architectural options.  Also, the benefits of messaging based systems have been well documented. Pertaining to the present discussion, I want to emphasize two things: 1) how these concepts provide simple architectural structure from the get-go, and 2) how adopting this approach can help developers to leverage their existing expertise and experience with fewer derailing discussions about “over architecting.”  

We define contracts in three areas of the system:

  1. Commands
  2. Events
  3. Projections

*Commands* are messages which represent method calls on domain objects.  Client code (such as the UI) does not directly call or reference domain objects.  Instead, client code creates commands and submits them to a command processor.  This Command Processor validates the command, and then dispatches the command to a Command Handler.  A typical command handler retrieves a Domain object from a Domain Repository, and then maps the Command to a method call on the Domain object.  Note: we typically call these “Domain Commands” to avoid potential naming collisions.

*Events* are generated based on changes to objects in the Domain.  Our goal is a fully encapsulated Domain with well defined Bounded Contexts (Aggregate Roots).  The Aggregate Roots expose Domain Events which are persisted in an Event Source.  Then, a Message Publisher dispatches these Events to Event Handlers which typically create Projections (though they could also perform other tasks such as notification).  Note: we typically call these “Domain Events” to avoid potential naming collisions.

*Projections* are created by Event Handlers in reponse to Domain Events. These may be referred to as "reports" or "read models" or even "view models" (though not in the MVVM sense).  Projections are retrieved using a read-only reporting repository.  We typically generate one projection per UI screen element.  Though at times this may seem to lead to duplication when projections look similar to one another, remember that the Single Responsibility Principle is about a class having one reason to change.  Since separate UI screens may change for different reasons, we want to maintain this separation in our Projections as well.

With these three contracts in place, we have our “ridge beams” in place and things progress in the following fashion:

  • UI - Projections IN, Commands OUT
  • Domain - Commands IN, Events OUT
  • Message Publisher - Events IN, Projections OUT

UI developers use a Reporting Repository to query for Projections.  Screens are built up from these Projections for end user interaction.  User interaction leads to the creation of Commands which are submitted to the Command Processor.

Domain developers focus on modelling the business requirements in a truly Domain Driven fashion.  Business operations are methods on domain objects, dispatched to the Domain as Commands.  While state is fully encapsulated in the domain objects, they expose Domain Events which reveal their state after a mutating method call has completed successfully.  (And by fully encapsulated, I mean fully encapsulated - no property getters or setters).

I don’t have clever name for the developers who create the Event Handlers which take Domain Events and generate Projections.  This is a fairly trivial development effort, though critical of course since the UI will rely on the generated Projections in order to display system state to end users.

So we’ve come full circle in this very low detail, high altitude overview.  There is much more to discuss regarding things like asynchronous messaging, eventual consistency, event sourcing, relational vs. NoSql solutions, etc.  However, you can start building a system using these three simple contracts (“ridge beams”) without committing to major architectural choices too early in your development life cycle.  

Tags: , , , , , , ,

Comments are closed