kiko - Fotolia
When it comes to reading and writing from a database, two terms are often combined: The command, which issues the create, update and delete, and the query that handles data read operations.
Applications that take data and make it available to a user are often called CRUD, an acronym for Create, Read, Update and Delete. In that case, command and query are combined, typically in a single class that writes to a single database.
There is an alternative strategy that separates command and query behavior, known as command query responsibility segregation (CQRS). Get to know this database interaction technique, including how it combines with event sourcing to solve common issues and the hurdles that adopting this approach might present. This information should help you decide if CQRS and event sourcing are right for a given application.
CQRS and event sourcing
CQRS involves breaking apart command behavior from query behavior. In object-oriented terms, this paradigm separates the responsibilities, typically into different classes. One class covers delete, create and update, while a second class is the read class. From the UI, queries go to the read class, while commands go to the class for delete, create and update writes. By creating multiple objects, we create data-connection code that is easier to maintain than CRUD as the application grows. For example, one class might call an API that reads from a cache, such as Redis, while another writes to a staging server to process updates. Data is not necessarily stored and retrieved in the same way.
Reads and writes from different places can create a timing issue. Most database theory focuses on consistency. It should be possible to keep a log of every data change. That way, at any point in time, the values that the queries display are logically correct. Caches like Redis reduce the emphasis on consistency, in exchange for availability.
Event sourcing is a technique that can help ensure consistency. Event sourcing stores a record of every write, update or delete process in a database. From there, an object -- often called an event handler -- reads these changes in order, applies them appropriately and marks them as complete once the transaction is complete. This event handler does not need to be complex -- it can be as simple as an API endpoint. Once the handler creates an event record, a central service messaging system (such as an enterprise service bus) can push notifications every time it learns about a new event.
CQRS vs. MVC
Model-view-controller, or MVC, is an established pattern for building software using database objects. MVC combines the query process and the command process into a single object, which is referred to as a model. The model receives events from the user interface, such as SEARCH or DELETE, executes the command and publishes the new information.
However, all that code fails when the infrastructure becomes more complex.
Traditional methods generate code on a server, communicating with the database directly with a query language like SQL. Traditional databases offer consistency, but often struggle to provide high availability. When an application goes web-scale and garners thousands -- or even millions -- of users, high availability is a priority. While companies may want to distribute the load onto several computers, perhaps separating the layers that were combined, that can lead to a problematic, multi-database scenario.
For example, most modern architectures push data processing off of the server and onto the client. Instead of running SQL queries directly, the client can call an API that fetches the data it needs. Software teams can develop and deploy separate APIs, each dedicated to either the command or query processes. That API carries data to a cache, such as Redis, MongoDB, CouchDB or Cassandra. The write API would go to an event handler or something similar.
While it is possible to keep both responsibilities in one class, such a class would break software engineer and Agile proponent Robert C. Martin's single responsibility and interface segregation stipulations from his SOLID principles. You could have the class keep two responsibilities and write to two different places. That approach would look wildly different and almost unrecognizable from the classic MVC pattern. In practice, developers are likely to have the model object contain two more objects: a command and a query object. This design is an implementation of CQRS, hidden through an interface.
Tradeoffs for databases
When CQRS combines with event sourcing, it guarantees an audit log of changes to the database that maintains transactional consistency. One downside of this approach is that it produces a lot more code to manage than other methods do.
With CQRS, reads from the database may experience slight delays, and there are many more infrastructure components that take more work to keep running. While this is not necessarily a prohibitive factor, it is worth considering whether your team has the resources to handle these large data volumes.
Early on in the delivery process, CQRS may slow down development. Coupling commands and queries, however, eventually leads to scalability and availability problems, which means it's important to pick the right time to make the conversion. Make sure you think hard about your team's capabilities before committing to CQRS and event sourcing.