Implementing CQRS - Supporting architectures - Microsoft .NET Architecting Applications for the Enterprise, Second Edition (2014)

Microsoft .NET Architecting Applications for the Enterprise, Second Edition (2014)

Part III: Supporting architectures

Chapter 11. Implementing CQRS

Computers are useless. They can only give you answers.

—Pablo Picasso

The fundamental aspect of a CQRS solution is the neat separation between the command stack and query stack. This means that each stack is designed separately; such a distinct design potentially can lead to having two distinct domain layers and even two distinct databases.

At the end of the day, there are several different flavors of CQRS.

There are CQRS implementations in which the read domain layer is nearly empty and consists only of plain SQL queries run against the database and data-transfer objects used to carry data up to the presentation layer. In other implementations, you have a read domain model that, overall, looks like a subset of a full domain model and a full domain model for the command stack where most of the business logic is contained. The command stack can be lightweight too and sometimes result from a basic implementation of the Transaction Script pattern. In this case, you have no domain layer whatsoever.

More likely, though, the command stack of a CQRS architecture is based on a command bus and handles events on top of a domain model and a database. If two databases exist—one to store the state of the application, and one to contain data in a format highly optimized for reading—then in some way the overall architecture should include a trigger—mostly events—that keeps the databases in sync and updates the read database whenever something is written.

In the end, CQRS is an architectural point. The benefits of the architecture that we listed in Chapter 10, “Introducing CQRS,” apply as long as you keep the query and command stacks distinct. In this chapter, we’ll first review a few possible CQRS implementations and then proceed with extending the sample application with a CQRS implementation where distinct stacks are used for querying and issuing commands.

CQRS implementations

CQRS doesn’t mandate any design choice. Even though the idea of CQRS is often associated with the idea of domain models and Domain-Driven Design (DDD), actually CQRS has just one principle: keep the command and query stacks segregated. Such a core principle can be implemented at least in a couple of ways. One consists of a plain and simple separation of stacks; the other consists of designing the business logic through commands and events.

We feel that a plain and simple CQRS approach is a scenario that often gets overshadowed by the use of command buses and events. Yet it delivers all the architectural benefits of CQRS in terms of simplified design and scalability

Plain and simple CQRS

The architectural benefits of CQRS—primarily the potential for scalability and greatly simplified handling of complex business scenarios—can be delivered even without an explicit focus on domain modeling. As mentioned in Chapter 10, CQRS is not a top-level architectural pattern, but it works beautifully within a bounded context. In a given bounded context, you identify the ideal pattern to express the business logic you have and the ideal pattern to represent any data behind it that gets moved toward the presentation layer for display purposes.

That’s all of it—you have two distinct stacks to be maintained and operated separately. Let’s review the options you have in case you don’t use domain-modeling techniques and the Domain Model pattern.

Transaction script for the command stack

In Chapter 7, “The mythical business layer,” we mentioned the Transaction Script pattern as one of the simplest, but not less effective, patterns to handle business logic. The Transaction Script pattern pushes a task-based vision of the business logic. In this regard, it works very well within a stack that focuses only on the execution of commands.

As Andrea experienced in a couple of projects—especially if you’re called to help a group of corporate developers finalize a project—you might not want to start using architecture that demands significant development skills. The risk of failing, or just experiencing analysis/paralysis, is too high. Conversely, the command/query separation will deliver the simplicity and scalability that you need.

As a pattern, Transaction Script doesn’t make huge demands of developers—it basically recommends they write methods on classes that focus on a task. By carefully choosing names for those methods and classes that closely mirror the language of the business, well, you’re surprisingly halfway done.

In a Transaction Script implementation, you have nothing as complex as command processors or domain models. All you have is a screen with command buttons and a method executing requested actions. Each action ends with some database writes. Input data travels from screens down to the methods as plain data-transfer objects (DTOs). All of this is simple and effective, and the reason it is so simple is because the command stack is kept separate from the read stack.

Data-transfer objects for the query stack

In CQRS, the query stack should be as simple as possible and use the simplest technology that could possibly work. In the scenario we are considering, you don’t need (or just don’t want) a full-fledged data model for the read stack. You return data to the upper layers via data-transfer objects—typically, view model objects if you’re using ASP.NET MVC. How do you fill those objects with data?

A common approach consists of calling an ad hoc layer from the application layer that wraps up the database context. The application layer essentially sees a read layer with ad hoc query methods that return any of the following:

Image Data-transfer objects that the application layer will later assemble in view model objects for the presentation layer to display

Image Data-transfer objects that are already view model objects ready for the presentation layer to display

The first scenario is seldom practical; the second is very convenient. The first approach entails using a tool like AutoMapper, or similar handwritten code, that just maps data from database models to memory object models. The real issue here is not the use of extra code and the processing power required by a tool like AutoMapper; instead, the issue is related to design. In a CQRS scenario, the presence of an object model in the query stack is sometimes just the sign that some of the complexity of the read domain model can be moved to an additional bounded context.

Having the read stack return direct view model objects is the essence of what we referred to as a layered expression tree (LET) in the previous chapter. With LET, view model objects are arranged on the fly in the body of a highly idiomatic LINQ query.

In this simple implementation of CQRS, the read stack is based on a simple data-access layer that just performs queries. Based on the available skills and attitude of the developers, you can code this read layer on top of Entity Framework and LINQ using a LET approach to populate data-transfer objects on the fly. In this case, the read layer internally uses a database context object, except that the database context is not publicly visible outside the read layer. If you don’t use Entity Framework and LINQ, the read layer can simply consist of plain ADO.NET or SQL queries and ad hoc data types to bring data back to the client. If you’re using an ASP.NET Web Forms front end, using DataSets to carry data might even be an option.

Single database

Depending on the real complexity of the business scenario, in general you can have CQRS with a single database shared by the command and query stacks, as well as distinct databases that are each managed by stacks autonomously. That mostly depends on the complexity (specifically, the nesting level) of the queries you need to execute.

In the case of a shared database, you typically share the database context between command and read stacks, paying attention to keeping the context private in the read stack. In the read stack, you can use code like that shown here:

public class ReadStack
{
private CommandStackDatabase _context;
public ReadStack()
{
_ context = new CommandStackDatabase();
}

public OrderDto GetById(int orderId)
{
// Use _context to make the query
// and fill the expected DTO
}
}

If, for query performance reasons, you decide to maintain a separate database, you’ll need to have a separate table mapping and a separate database context.

CQRS with command architecture

As more and more people started using CQRS, it became obvious that CQRS is particularly well suited to being coupled with a command-driven strategy and events. By using commands and a command bus, you can split the steps performed in an application service into multiple commands and events sent to the bus.

Orchestrating commands in the command stack

Organizing use-cases and business logic via commands has a number of benefits:

Image It makes it easy to map commands to the steps of real business processes. At the end of the day, commands are applied because they exist in the ubiquitous language.

Image You can even draw a flowchart out of a process and discuss that with a domain expert.

Image It makes far easier to render particularly complex pieces of business logic with events generated by actions that, in turn, generate other domain events.

When you start reasoning in terms of commands, you start feeling the need for another element: events. The execution of a command might generate an event that should be processed by any number of registered handlers. Commands and events go together and represent the real essence of CQRS.

One database or two

When you have two models—one for the command stack and one for the query stack—you need to distinguish whether or not each model refers to its own database. Things are easy to manage if you have distinct databases and rely on architecture like that shown in Figure 11-1.

Image

FIGURE 11-1 CQRS architecture with distinct models and distinct databases.

When distinct databases are used to persist the state of the application and for serving the needs of presentation, you need to have something in between the two that ensures synchronization and consistent data. This is generally accomplished in one of two ways. It can be a scheduled job that operates on the write database periodically and copies data to other tables. It can also be an in-process handler that fires after the termination of each command and either synchronously or asynchronously creates read views, which can be relational tables, OLAP cubes or, why not, tabular data.

When the two stacks share the same database and you have models on both sides, you need to manage two database contexts and apply different mappings. You end up with classes analogous to the classes shown next. These two classes belong to different class libraries:

public class CommandModelDatabase : DbContext
{
...
}
public class ReadModelDatabase : IQueryModelDatabase
{
...
}

The former database context class inherits directly from Entity Framework’s DbContext class. The latter class wraps an instance of DbContext and implements a custom interface—arbitrarily named IQueryModelDatabase. The interface serves the purpose of restricting the DbContextinterface to just a few queryable collections so that the SaveChanges method, which enables changes to the underlying database, is hidden from view.

The database class for the command model also needs to override OnModelCreating to map the content of the database to the physical classes in their own model:

public class CommandModelDatabase : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{ ... }
...
}

There are a couple of remarks to make here. First, when implementing the read database class, you might want to choose composition over inheritance. Instead of inheriting from DbContext, you can simply create an internal instance. In this way, you prevent undesirable casts to DbContextsomewhere in the code. Second, the name of the class should closely reflect the actual language of the business. Quite simply, this could be Database, indicating (as in the business language) the common name for the container of the business information.

Implementing a query stack

Let’s have a closer look at a CQRS implementation that has two distinct models on top of a single database and uses commands for the organization of the business logic.

Creating a read façade

The essence of CQRS is that, as an architect, you mentally separate queries against the back end from actions that you need to write. You should plan to have separate projects for the query and command parts, and you can even have different teams as well. A read façade consists of two main components: a data model and a database context to read data and materialize elements in the domain.

The query model

As mentioned, most of the time you won’t have an object model in the query side. If you have one, however, here’s more about how to write it. The data model of the query stack has the same structure of the domain model we devised for the entire domain in Chapter 8, “Introducing the domain model,” and Chapter 9, “Implementing the domain model.” It’s the same type of collection of related classes except that the classes are fewer and simpler because they focus only on data and behavior that pertains to rendering queried data.

The read-only domain model is a class library project. Figure 11-2 offers an interior view of the class library project for the sample application.

Image

FIGURE 11-2 The QueryModel class library project.

The Order class in the read model, for example, doesn’t have any behavior and looks like a mere container of data:

public class Order
{
protected Order()
{
}
public int OrderId { get; set; }
public ICollection<OrderItem> Items { get; set; }
public Money Total { get; set; }
public OrderState State { get; set; }
public DateTime Date { get; set; }
}

The OrderItem class is nearly the same as in a full domain-model implementation. Also, the Product and Customer classes are, in our example, nearly the same except that they now lack behavior. Another difference is that in the Orders folder of the full domain model, you find a lot more classes, like OrderPaymentConfirmation, that now belong to the command stack.

The read database context

Once you have a domain model, you also have the problem of materializing instances of the classes. Entity Framework does most of the work for you. If you use Code First, as in the example, you access the database using a class derived from DbContext:

public class QueryModelDatabase : DbContext
{
public QueryModelDatabase() : base(“naa4e-11”)
{
...
}
...
}

The DbContext class provides full, read/write access to the database. To secure the read model and eradicate any chance of allowing write access to the database, you might want to use a private instance of DbContext and implement an interface to close the class. TheQueryModelDatabase class is implemented in a new class library that implements the persistence layer for the read layer. In the example, we call it IBuyStuff.QueryModel.Persistence:

public class QueryModelDatabase : IQueryModelDatabase
{
private DbContext _context;
public QueryModelDatabase()
{
_context = new DbContext(“naa4e-11”);
_products = base.Set<Product>();
_orders = base.Set<Order>();
}
...
}

The interface called IQueryModelDatabase just lists the collections of interest so that coders of the query stack are given access only to the data they need for read-only operations:

public interface IQueryModelDatabase
{
IQueryable<Order> Orders { get; }
IQueryable<Product> Products { get; }
}

In the segment of the sample application implemented so far, there’s no function that queries customers: subsequently, there’s no need to have the Customers collection in the public interface of the database context. The QueryModelDatabase class in the end represents the database to the application’s eyes and should expose only data that the application is interested in.

Packaging data for callers

Another difference you might note in a CQRS scenario is that the collections exposed as part of the database context return IQueryable. Returning IQueryable is not strictly required, but it does help in a few ways, as we discussed in Chapter 10.

Creating LET expressions

Here’s the full source code of the database context class in the query stack:

public class QueryModelDatabase : IQueryModelDatabase
{
private DbContext_context;
public QueryModelDatabase()
{
_context = new DbContext(“naa4e-11”);
_products = base.Set<Product>();
_orders = base.Set<Order>();
}

private readonly DbSet<Order> _orders = null;
private readonly DbSet<Product> _products = null;

public IQueryable<Order> Orders
{
get { return this._orders; }
}
public IQueryable<Product> Products
{
get { return _products; }
}
}

Hiding DbContext and exposing table collections as IQueryable removes the risk of finding the SaveChanges method available at some point. In addition, an IQueryable object is just what its type name says—a queryable collection of data. This enables you to write queries as shown here:

using (var db = new QueryModelDatabase())
{
var queryable = from o in db.Orders
.Include(“Items”)
.Include(“Details.Product”)
where o.OrderId == orderId
select new OrderFoundViewModel
{
Id = o.OrderId,
State = o.State.ToString(),
Total = o.Total,
OrderDate = o.Date,
Details = o.Items
};
try
{
return queryable.First();
}
catch (InvalidOperationException)
{
return new OrderFoundViewModel();
}
}

The code just rewrites the basic query we considered in one of the use-cases of the sample application in past chapters. The actual projection of data is specified at the last minute, right in the application layer. In this way, you can move around IQueryable objects and compile and run the query just when you are going to fill up view model objects. Doing so, also saves you from creating and maintaining a bunch of data-transfer objects.


Image Note

You might wonder why we insist on using the ViewModel suffix in the name of classes we use to package data for the caller. At the end of the day, we run a query against some LINQ data layer and copy data into a data-transfer object. We expect the code to run within the application layer and return the object in the context of an ASP.NET MVC application that will be ultimately passed to the view. If you run the preceding code in, say, a Web API method, you might want to use a different naming convention and use the Dto or Model suffix instead.


Packaging LET expressions in services

You can use LET expressions to call into the database context right from the application layer. To improve readability and adherence to the ubiquitous language, you can also consider having services that return IQueryable expressions for you to further concatenate.

The code below shows a sample CatalogService class that implements product-related functions:

public class CatalogServices : ICatalogService
{
public IQueryModelDatabase QueryModelDatabase { get; set; }
public CatalogServices(IQueryModelDatabase queryDatabase)
{
this.QueryModelDatabase = queryDatabase;
}

public IQueryable<Product> ProductsOnSale()
{
return from p in this.QueryModelDatabase.Products
where p.IsDiscontinued == false select p;
}

public IQueryable<Product> Available()
{
return from p in ProductsOnSale() where p.UnitsInStock > 0 select p;
}

public IQueryable<Product> RelatedTo(int productId)
{
var categoryId = (from pd in ProductsOnSale()
where pd.Id == productId
select pd.Category.Id).Single();
return from p in Available()
where p.Id!=productId && p.Category.Id == categoryId
select p;
}
}

The ProductsOnSale method is a plain query that returns all products that haven’t been discontinued and are on sale. The other two methods are built on top of ProductsOnSale and apply further restrictions. In a service, you can have ad hoc query methods if they are going to be used in several places; otherwise, you can build queries directly in the application layer.


Image Important

You really might not need a layer of services that essentially operate like read-only repositories. Probably a better way to achieve the same level of expressivity and encapsulation at a lower implementation cost is using extension methods on IQueryable<T>, where T is the type of entity—in the previous example, that would be Product.


Experimenting with the true value of LET

One beneficial aspect of LET expressions is that they dramatically reduce the need for DTOs. Building a query model without LET often requires you to define explicit DTO classes and package up data into them. This is a waste of development time and CPU cycles. Here is an example of what you can achieve with LET.

Let’s say you’re a business-unit manager. You have a dashboard accessible from the home page of your intranet account that allows you to quickly check some accounting information, such as all the unit’s invoices that still need to be collected on. You might explain this need using the following wording: from the list of invoices that the business unit has issued, I want to see all those that are unpaid and past due.

var unpaidInvoices = Database.OutgoingInvoices
.PerBusinessUnit(businessUnitId)
.PastDue()
.Select(i => new UnpaidInvoiceModel() {
InvoiceNumber = i.Number,
CustomerId = i.Customer.Id
}).ToList();

The value is all in the fact that the programming language is semantically close to the business language. This is the essence of the ubiquitous language. Interestingly, similar code can be used outside the realm of plain queries to send, for example, a gentle reminder about the invoice:

Database.OutgoingInvoices
.PerBusinessUnit(businessUnitId)
.ExpiredOnly()
.Select(i => new {InvoiceNumber = i.Number, CustomerId = i.Customer.Id})
.AsParallel()
.ForAll(i =>
bus.Send(new SendEmailReminderCommand(i.InvoiceNumber, i.CustomerId)));

The query returns data ready-made for parallel processing. Next, the ForAll method pushes a command to the bus to send an email reminder about the invoice.

Implementing a command stack

As discussed in Chapter 10, the command stack of many CQRS solutions orchestrates the use-cases of the application by having workflows defined in terms of commands and events. Let’s find out more details.

Laying the groundwork

Any external input (whether from users or external systems) becomes a command pushed to a bus. Next, the bus dispatches any commands to a registered handler for further processing. Typically, handlers are not stateless components that perform an operation and return. Processing a command, instead, starts a process that is advanced by further commands and domain events. The process that handles commands in the context of a workflow is known as a saga.

Domain events might be raised during the execution of commands to notify registered event handlers of specific situations. Integration events are, instead, notifications of occurrences in the command stack that might affect external bounded contexts.


Image Note

Semantically, domain and integration events are the same thing—plain notifications about something that just happened. However, their implementation might be different. Domain events are just messages pushed to the bus. Integration events are custom written. The purpose of integration events is to enable communication between standalone but related bounded contexts. It can be a RESTful API exposed by both contexts, a shared database used as a mailbox, an ASP.NET SignalR infrastructure, or perhaps a commercial service bus.


Devising a saga component

A saga is the logical component in which developers distill pieces of the business logic. More precisely, the saga (in cooperation with the bus) orchestrates all tasks that need be performed to implement a use-case.

Implemented as a plain class, a saga is characterized by the following features:

Image ID, to ensure uniqueness of running instances

Image Collection of properties, to hold the state of the saga

Image List of messages (commands, events, or both) that start the saga

Image List of commands the saga can handle

Image List of events the saga wants to have a chance to handle

Internally, a saga will typically hold references to repositories and might be able to invoke domain services (if any) or external services. Here’s the typical structure of a saga class for a checkout operation, such as the ones used in sample projects we considered in past chapters:

public class CheckoutSaga : SagaBase<CheckoutSagaData>,
IStartWithMessage<CheckoutCommand>,
ICanHandleMessage<CheckGoodsInStockCommand>,
ICanHandleMessage<GoodsInStockEvent>,
ICanHandleMessage<GoodsNotInStockEvent>,
ICanHandleMessage<CheckCustomerPaymentHistoryCommand>,
ICanHandleMessage<PaymentHistoryPositiveEvent>,
ICanHandleMessage<PaymentHistoryNegativeEvent>,
ICanHandleMessage<PaymentCompletedEvent>,
ICanHandleMessage<PaymentDeniedEvent>,
ICanHandleMessage<SendDeliveryRequestCommand>,
ICanHandleMessage<DeliveryRequestRefusedEvent>,
ICanHandleMessage<DeliveryRequestApprovedEvent>
{
...
}

A saga class typically inherits from a base class. At a minimum, the base class must expose an ID property to uniquely identify the saga. The saga base class might look like the code shown here:

public class SagaBase<T>
{
public string ID { get; set; }
public T Data { get; set; }
}

A commercial bus such as NServiceBus, for example, offers a Saga<T> base class that also implements some predefined behavior for saga persistence and other features. The type, T, you indicate is a plain data-transfer object made of a collection of properties that together define the state of the saga. In our example, the CheckoutSagaData class will likely contain the content of the shopping cart and information about the customer.

Designing a saga component

The implementation of a saga is tightly bound to the implementation of the bus. In general, a saga implements two types of interfaces: IStartWithMessage<T> and ICanHandleMessage<T>. Obviously, choosing names is up to you if you write the bus component yourself. Otherwise, they are mandated by the bus component you use. In NServiceBus, analogous interfaces are called IAmStartedByMessages<T> and IHandleMessages<T>.

The definition of these interfaces is basic. Here’s an example:

public interface ICanHandleMessage<T> where T : Message
{
void Handle(T message);
}

From the preceding definition of the CheckoutSaga class, it emerges that the class can handle the commands listed in Table 11-1.

Image

TABLE 11-1. Commands supported by the saga

Table 11-2 lists supported events.

Image

TABLE 11-2. Events supported by the saga

The rather interesting thing is that the implementation of the CheckoutSaga class closely matches a flowchart, like the one in Figure 11-3.

Image

FIGURE 11-3 A flowchart illustrating the behavior of the checkout saga component.

This fact clearly demonstrates the power of the command-based approach: as an architect, you can thoroughly discuss the solution with domain experts using only flowcharts, without writing a single line of code. The flowchart is something that all domain experts can understand, so the feedback you get is appropriate and gives you an excellent starting point for coding business logic. You haven’t completed a big upfront design phase, but you’re well beyond stabbing in the dark.

Orchestrating use-cases via commands

Now that you laid the groundwork for commands and events to effectively describe the checkout process of the sample I-Buy-Stuff application, let’s take a look at the actual source code. You’ll see how commands and events make up the saga and how sagas are managed from within the bus.

Starting the saga

When the user clicks to check out and pay, the underlying ASP.NET MVC application receives a request handled by a controller. All that the controller does is prepare an appropriate command and push it to the bus. Here’s a sample command class:

public class CheckoutCommand : Message
{
public string CartId { get; private set; }
public string CustomerId { get; private set; }

public CheckoutCommand(string cartId, string customerId)
{
CartId = cartId;
CustomerId = customerId;
}
}

The shopping cart is referenced through an ID. The ID can be just the session ID if you’re storing the shopping cart in memory. If the shopping cart is persisted to the database, ID is just the cart ID:

public ActionResult Checkout(string customerId)
{
var command = new CheckoutCommand(Session.SessionID, customerId);
Bus.Send(cmd);
return RedirectToAction(“done”);
}

Within the bus, processing the command leads to finding the appropriate saga type registered to handle the command. In the initialization code of your application (for example, in global.asax) you have code like that shown here:

Bus.RegisterSaga<CheckoutCommand, CheckoutSaga>();

We described the typical implementation of a bus in Chapter 10. In short, whenever the bus receives a command (or an event) that can start a saga, it creates a new saga object and assigns it a unique ID. A saga declares its (unique) trigger through the IStartWithMessage<T> interface; similarly, it declares the messages it can handle through the ICanHandleMessage<T> interface.

Inside the saga implementation

The following code shows the startup of the saga. In our example, a new instance of the CheckoutSaga component is started when the bus receives a request for the CheckoutCommand type:

public class CheckoutSaga : SagaBase<CheckoutSagaData>,
IStartWithMessage<CheckoutCommand>,
...
{ ... }

The IStartWithMessage interface has the same contract you saw earlier for ICanHandleMessage. The difference between the two is only a matter of semantics. Both interfaces are essentially markers that indicate why a given message is being processed:

public interface IStartWithMessage<T> where T : Message
{
void Handle(T message);
}

The primary concern in the implementation of the Handle method in a starter command is identifying the unique ID of the current instance of the saga. The most obvious thing you can do is use the ID of the aggregate root you’re working with. For example, if the saga involves orders, you can use the order ID as the saga ID. You get a reference to the aggregate root and save its ID in the saga.

In our example case, there’s no aggregate root yet. You can use the unique ID that identifies the shopping cart. If you persist shopping carts, you can use the ID of the shopping cart; if not, you can use the session ID or even a generated GUID.

public void Handle(CheckoutCommand message)
{
// Set the ID of the saga using the ID of the shopping cart
this.Data.Id = message.Cart.Id;
this.Data.Cart = message.Cart;
this.Data.CustomerId = message.CustomerId;

// Begin the saga by requesting a check on goods in stock
var cmd = new CheckGoodsInStockCommand(message.Cart);
cmd.SagaId = message.Cart.Id;
Bus.Send(cmd);
}

Note that whenever you create a command (or event), you need a common way to set the ID of the saga so that when the command or event is processed by the bus, the bus can deliver it to the right saga. In our sample code, we assume a common property called SagaId on all messages that the bus component is aware of. A commercial implementation of a bus—the NServiceBus product, for example—uses a different approach. It allows each saga component to tell the bus how to recognize it.

In our example, the saga implements the flowchart shown earlier in Figure 11-3. Right after instantiation, therefore, it pushes a command to check whether the ordered goods are in stock. Note that the CheckGoodsInStockCommand is placed with reference to the ID of the current saga:

public void Handle(CheckGoodsInStockCommand message)
{
// Check whether goods are in stock
var instock = ...;

// Raise an event to notify that all is OK
var theEvent = new GoodsInStockEvent(Data.CustomerId);
theEvent.SagaId = message.Cart.Id;
Bus.Send(theEvent);
}

At this point, the event is pushed to the bus and handed over to all sagas that list it in the interface. The bus goes through the list of current saga instances and gives each a chance to handle the event. Here’s some code that shows a sample implementation for other commands and events in the flowchart shown in Figure 11-3.

public void Handle(GoodsInStockEvent message)
{
// Order a payment history check
var cmd = new CheckCustomerPaymentHistoryCommand(Data.CustomerId);
cmd.SagaId = message.Cart.Id;
Bus.Send(cmd);
}

public void Handle(PaymentHistoryPositiveEvent message)
{
// Proceed with payment through the configured bank gateway. This operation is synchronous
// and may go through an anti-corruption layer or just through a plain web service call.
var success = ProceedWithPayment(Data.Cart);
if (success)
{
// Raise the PaymentCompleted event
var theEvent = new PaymentCompletedEvent( /* add transaction ID */ );
theEvent.SagaId = message.Cart.Id;
Bus.Send(theEvent);
}
}

The code snippets shown here should be enough to understand how a process triggered by a user action is implemented in a command architecture. For more details, you can have a look at the reference application that comes with the book.

Sagas and persistence

In general, a saga must be persistent and persistence of the saga is a typical responsibility of the bus. In this regard, it might completely be transparent to you if you don’t write a bus class yourself. In the sample Bus class, we simulated persistence through an in-memory dictionary—whereas, for example, NServiceBus uses SQL Server. For persistence to happen, it is key that you give a unique ID to each saga instance.

If you’re not completely convinced about the importance of saga persistence, consider the following scenario. Let’s say that the business scenario requires the user of an online store to first pay and then complete the order by specifying shipping details. So the user enters banking details, and the saga completes payment successfully. Before the user regains control of the user interface and receives the page with shipping details, the browser freezes and crashes. The user reopens the browser and is served back the page with the Checkout option. She clicks, and the unique ID of the shopping cart (or the customer ID or whatever you chose to use) makes it easy to retrieve the saga, rebuild its state, and proceed from there.

Granularity of commands

If we were discussing the checkout scenario at a higher level of abstraction, we could say that the checkout scenario is the result of three commands: validation, payment, and completion of the order. In the actual implementation, however, we used plenty of commands and events. So what’s the ideal granularity of the command? Should you go with a higher-level flowchart and hide most of the details of checking out inventory and payment history in some generic “validation” command? Or are you better off making every step explicit?

In general, the granularity of the command—defined as the data it carries and the action it takes—is defined at the level of the ubiquitous language. If domain experts talk about saving checkout information and checking the customer’s payment history, you should have those logical steps defined explicitly as commands.

Summary

In software architecture, CQRS is the Columbus egg—namely, a brilliant and surprisingly obvious solution to a nontrivial problem. Developers and architects spent years trying to understand, justify, and mechanize DDD and Domain Model layered architectures, and they struggled with domain models that could hardly accomplish both query and command scenarios, especially in complex business domains.

CQRS, all of a sudden, made it far simpler. Complex business domains became a lot more manageable, and designing software with CQRS generally results in a solution much closer to the ubiquitous language that emerges out of the requirements. When this happens, requirements get missed less often, and subsequently, writing software becomes a more reliable discipline.

CQRS is applied at an architecture level, even though it’s not the top-level architecture. You apply CQRS in a given bounded context and decide among a few options about the details related to the query and command stacks. In this chapter, we reviewed the most commonly used options and evolved the sample online store application of past chapters into a CQRS solution.

This is only the first step, though. CQRS needs to be taken one step further to unleash its true potential. This is precisely what we are slated to do in the next two chapters with the Event Sourcing architecture.

Finishing with a smile

Let’s prepare for the next chapter with a laugh at a few of Murphy’s laws somehow related to computers and programming. For more laws and details, see http://www.murphys-laws.com/murphy/murphy-computer.html:

Image A working program is one that has only unobserved bugs.

Image No matter how many resources you have, it is never enough.

Image All Constants are Variables.

Image Constants aren’t.

Image Variables won’t.