Grails + Axon = CQRS (part I)

I continue series of posts regarding Groovy and Grails. In the previous post there were some starter information about Groovy programming language. In this one and the next one I would like to present sample application built with Grails and Axon which demonstrates a basic usage of CQRS architecture.

Grails

Grails is a rapid application development framework for the JVM. It is largely built on top of the Spring framework, and in particular, a lot of it is built on top of Spring MVC. So if you’re building a web application that targets any other platform, Grails is not for you. Grails is specifically written as a framework for building JVM web applications.
There are lots of developer productivity gains that Grails has to offer. It’s very, very easy to quickly get an application up and running on the Grails framework because of a lot of things that Grails does to help with things like a convention over configuration and the sensible defaults. Literally, in a couple of minutes you can have a simple Grails application up and running. And from there Grails offers a lot to simplify the process of building serious enterprise web applications.

 

grails

 

CQRS

Firstly, let’s try to answer a simple question. Why we may need CQRS?
Scalability. It is definitely a hard problem.
What can we do if we need to handle a lot of  concurrent connections?
One way to deal with it is using asynchronous concepts. Grails 2.3 has some async improvements. There is an API for doing async stuff. What is more Grails 2.3 introduces Promises, a concept similar to java.util.concurrent.Future instances.
That is one aspect, do async stuff using current programming model.

The other way to deal with scalability is changing completely an architecture. Here CQRS has his place. CQRS stands for Command Query Responsibility Segregation. It very often seems to be associated with Domain Driven Design. While Domain Driven Design is mainly focused on getting an application domain model right, CQRS is a wider concept.
The basic concept behind is that the part of the application that updates the database (call it write model) has different requirements that part which reads (call it read model) and reports to the user data from the database.
CQRS embeds that concept into application architecture. It clearly separates part that process commands and the one which queries data.
Someone may ask why we need such separation, why we need two storages in one application.
If we look closer at the two models (read and write) we notice that the requirements for them are different. The command part (write) is responsible for validating and execution of commands. Whereas the query part just reads data and transfers it to the view layer. Going further, storages for those parts can be optimized specifically for the particular purpose they serve. For example read storage can store denormalized data. What is more, database tables/documents can be design to serve particular view. So that no joining is needed. At the same time the write storage can persist data in normalized form. There are only a few examples which clearly justify the model CQRS provides.

source: infoq.com
source: infoq.com

When we get an update which comes in as an command (Grails supports that providing command objects), the command is processed by command handling component. Each command should have specific processing component. The command interacts with domain model. The domain model may change and the changes go to the persist model to be stored in the database. It does not need to be a database as we know it. In most cases it should be an Event Store.
The idea behind the Event Store is that the changes are stored to the database. As a result, we never loose information. Every change is persisted, we can go back, get audit trail, produce complicated reports and so on.
When persisting data in the write model a message is produced that triggers update in the other part of the application, the read model. The message is placed on the message/event bus. The update is done asynchronously. Then using the read model and the storage on that part of the application data is queried and presented to the user. Because of asynchronous nature of the updates in the read model we must assume that data presented to the user can be stale sometimes. However, that issue is present only when we use views generated on the server side. Modern web applications use wide variety of technologies on the view layer apart of server side generated pages so it is pretty simple to trigger view refresh when data update is captured in read model. By the way, there is Grails Atmosphere Plugin which provides smooth integration with Atmosphere framework – AjaxPush/Comet framework.

Axon

Implementing a CQRS architecture requires quite a lot of “plumbing” and boilerplate code. Much of that code is project-independent and quite error-prone to do right. Axon aims at providing the basic building blocks, which are needed in most CQRS-style applications. Event dispatching, for example, is typically an asynchronous process, but you do want guaranteed delivery and, in some cases, sequential delivery. Axon provides building blocks and guidelines for the implementation of these features. Besides these core-components, Axon wants to make integration with third party libraries possible. Think of frameworks and libraries such as JMS, MQ and Spring Integration.

The above was said by Allard Buijze, the author of Axon Framework. It perfectly sums up the reasons standing behind creating the framework and the areas in which Axon can help us to develop applications compliant with CQRS model. In my opinion it is brilliant framework, very well designed, open for extension. What is more it provides simple implementation of particular CQRS building blocks like event store, event bus, etc. which can be used straightforward in our application.

Further reading:

In the next part I will present simple Grails application which uses Axon framework to implement basic CQRS model.

Stay tuned!

Leave a Reply

Your email address will not be published. Required fields are marked *