Category: Software design

CQS, CQRS, Event Sourcing. What’s the difference?

There similar but yet different concepts that confuses some developers when they see these definitions and trying to understand what is the relation between the terms. Let’s try to figure it out.

CQS

CQS stands for Command-query separation. Initially designed by Bertrand Meyer as a part of his work on Eiffel programming language. The core idea behind this concept is that

Every method should either be a command that performs an action, or a query that returns data to the caller, but not both.

Application of this principle makes software design cleaner and code easier to read and understand it intent. Usually, you apply it on source code level by creating clear interface definitions, followed by implementation which should adhere to command-query separation rules. For in-depth overview of CQS in action and it affect on design see my article CQS and its impact on design.

CQRS

CQRS stands for Command Query Responsibility Segregation. It is architectural pattern. It is related to CQS in the way that the main idea of that pattern is based on command-query separation. But unlike former CQRS applied not on a code level but on application level. Originally this pattern was described by Greg Young in his CQRS Documents.

In a nutshell it says that your write model is not the same as your read model because of different representation logic behind it: for your web pages you could have views specifically adapted for representation logic of the UI elements on it. And write model contains all data in format which best fits type of the data. If you familiar with SQL, read model is something similar to SQL Views (which is just projection of data in convenient form).

This gives you not only flexibility in separation of representational logic, but also in choosing underlying storage technologies. Write model storage could be in good old SQL and read model could be in MongoDB or any other NoSQL DBMS. In essence it is SRP (single responsibility principle) at application level.

Event Sourcing

Event sourcing is technique to store data as a series of events where these events acts as source of truth for data. The key idea here is that each change to the data is event which is stored with metadata like timestamp and relation to aggregate root (often CQRS applied with DDD where aggregate root is domain object which encapsulates access to the child objects).

In that way you have history of all changes to your data over lifetime of application. Next key aspect of such systems is that in order to get current state of domain object all events for its aggregate root should be replayed from the beginning (there some tricks like snapshots which solve performance issues with that approach when you have huge amount of data). In the same manner, current state of a whole application is a sum of all events for all aggregate roots. This is very different from the usual CRUD model where you don’t preserve previous state and override the current state (just writes new values in columns for SQL database).

With event sourcing in place you could re-build your data for particular point in time which could be very useful for data analysis. It also gives you history of every data change by design with no additional coding.

Relation

CQS is a code level principle to improve design by applying separation of concerns.

CQRS is application level architectural pattern for separating commands (writes) and queries (reads) in regards to the storage. It is based on the ideas of CQS.

Event Souring is a storage pattern to represent data changes as a stream of events with point-in-time recovery.

Conclusion

CQRS is based on CQS principle and boosted to application level. CQRS is often combined with Event Sourcing and DDD. You can implement CQRS without Event Sourcing. You can implement Event Sourcing without CQRS. Event Sourcing is opposite to the CRUD.

CQS and its impact on design

Let’s start from the abbreviation. CQS stands for Command-Query Separation. The term was invented by Bertrand Meyer during his work on Eiffel programming language in the middle of 1980x. In a nutshell, it states:

Every method should either be a command that performs an action, or a query that returns data to the caller, but not both.

Sounds good. But what does it mean in practice? Let’s look at the trivial example.

Suppose we have some service which could get user from some storage and send message to that user based on the email address:

public class User
{
    public int Id { get; set; }
    public string Email { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }
}

public interface IStorage
{
    User GetUser(string email);
}

public interface IMessageService
{
    void Send(string email, string message);
}

public class InMemoryStorage : IStorage
{
    public User GetUser(string email) =>
        new User
        {
            Id = 1,
            Email = "bruce@eternity.net",
            FirstName = "Bruce",
            LastName = "Lee",
            BirthDate = new DateTime(1940, 11, 27)
        };
}

public class EternityMessageService : IMessageService
{
    public void Send(string email, string message)
    {
        Console.WriteLine($"Sending '{message}' to {email}...");
    }
}

public class Service
{
    private readonly IStorage storage;
    private readonly IMessageService messageService;

    public Service(IStorage storage, IMessageService messageService)
    {
        this.storage = storage;
        this.messageService = messageService;
    }

    public User GetUser(string email) => storage.GetUser(email);
    public void Send(string message, string email) => messageService.Send(email, message);
}

Service exposes two public methods:

User GetUser(string email)
void Send(string message, string email)

From public API of the service you should be able to distinguish where is query and where is command methods.

For User GetUser(string email) method we expect to pass e-mail as a parameter and get back a user object as a result. It perfectly fits in the query method definition. We do not expect to see signature like void GetUser(string email). It will be very confusing: why it states GetUser and doesn’t return any value? In the same manner we expect to see the command method void Send(string message, string email) with no return value and with two input parameters message and email. This clearly states that in order to operate, method requires input and produces side effect in the form of sending a message.

Good design promotes having method signatures with clear intention.

Consumer can execute code with following snippet:

void Main()
{
    var service = new Service(new InMemoryStorage(), new EternityMessageService());
    var user = service.GetUser("bruce@eternity.net");
    // Some logic with that user...
    service.Send("A wise man can learn more from a foolish question than a fool can learn from a wise answer", user.Email)
}

Now, let’s assume that we have a new requirement:

When today is the Birthday of the user we would like to send an e-mail with congratulations.

This is a typical scenario for a lot of web sites like forums. Also, let’s assume that developer who is going to implement this change not familiar with CQS. So he decides to extend GetUser method with a new logic:

public User GetUser(string email)
{
    var user = storage.GetUser(email); 
    if (user.BirthDate.Day == serverDate.Day && user.BirthDate.Month == serverDate.Month)
    {
        Send($"Congrats with your Birthday, {user.FirstName}! We wish you could stay with us for longer", user.Email);
    }
    return user;
}

Now, running same Main() method results in following output:

Sending 'Congrats with your Birthday, Bruce! We wish you could stay with us for longer' to bruce@eternity.net...
Sending 'A wise man can learn more from a foolish question than a fool can learn from a wise answer' to bruce@eternity.net...

And bingo! We have a violation of command and query separation. The consumer of a service does not expect this method to send a message in addition to its main purpose of retrieving a user. And it is not obvious looking at the signature of this method. By reading method definitions you should be able quickly identify to which category it belongs.

Now let’s see on one of the main properties of query methods:

Any call to the same query method with the same parameters should always give the same result. In other words, query method should be idempotent.

Correct way to implement Birthday requirement would be to move this logic in Main() or to wrap it in any other command method which could accept user and message as input parameters, keeping GetUser method simple user query:

void Main()
{
    var service = new Service(new InMemoryStorage(), new EternityMessageService());
    var user = service.GetUser("bruce@eternity.net");
    if (user.BirthDate.Day == serverDate.Day && user.BirthDate.Month == serverDate.Month)
    {
        service.Send($"Congrats with your Birthday, {user.FirstName}! We wish you could stay with us for longer", user.Email);
    }
    // Other logic here...
    service.Send("A wise man can learn more from a foolish question than a fool can learn from a wise answer", user.Email)
}

It’s worth to mention opposite scenario:

Calling query method from command method is quite legit.

This is true because query does not have a side effect and does not change the state of the system.

It’s also good to mention, that there cases when you need a value back from a command. For example Send method need to return id for further tracking. If you change signature to something like int Send(string message, string email). It will no longer be pure command method, but mixture of command and query which violates CQS principle. In that case possible solution would be to create another query method for the purpose of getting tracking id: int GetTrackingId(string email). So we could always adhere to CQS by decomposing query and command methods. Sometimes the price of following pure separation is performance or changes in other layers. Like in example with Send we most probably need to preserve tracking id somewhere in order to fetch it for int GetTrackingId(string email) call. But it’s always a trade-off like with everything in software development.

NB: CQS has relation with another concept: Design by Contract (DbC) which also invented by Bertrand back in the 1986 when he was working on Eiffel design. CQS is beneficial to DbC because any value-returning method (any query) can be called by any assertion without fear of modifying program state.

Conclusion

The code we write should be readable and maintainable. That is the major quality of a good code. Applying CQS in practice lead to clear public APIs and some sort of trust in what it does. Separation in asking for program state and request to change a program state is beneficial for creating good designs. Perhaps that is the reason why more modern architectural patterns like CQRS for building distributed systems based on well-proof ideas from mid 80-x.