As I promised a week ago I’m going to continue CQRS clarification. If you didn’t see the first part you definitely should. You can find it here.

In the previous post, I tried to explain what CQRS really is. Now I wanna go further and show you guys the code!

The simplest implementation that you’ve ever seen

class Service {

WriteModel writeModel = new WriteModel();



public void command() {

writeModel.setValue(100);

}



public ReadModel query() {

return new ReadModel(writeModel);

}

}

Yes. That’s all. Yes. This is CQRS folks. But let me check…

We have C — Command. We have Q — Query. We have R — Responsibility and we have the last but not least S — Separation. That’s all. We achieve mythical CQRS pattern in just a few lines of code.

Going deeper

But let’s discuss something. In software design, things cannot be that simple, right? This is not the exception. The whole rumor about CQRS is created by the last letter — S.

S — separation is the key

What makes CQRS such a powerful technic is that we can manipulate separation level. At the first paragraph we separated the model but we also put everything in the same API. What’s worse we have everything at the same class and ReadModel is directly dependent on WriteModel. Separation is weak. We could change it a bit to look like this:

Decoupling interfaces

class CommandService {

WriteModel writeModel = new WriteModel();



public void command() {

writeModel.setValue(100);

}

} class QueryService {



public ReadModel query() {

return new ReadModel(new WriteModel());

}

}

In the example above we can separate the interfaces for Query and Command. And this is actually the part when CQRS is getting useful. Now, we have separated interfaces but still our read and write models are tightly coupled. So, what next?

Decoupling models

class Database {

private WriteModel writeModel = new WriteModel();

private ReadModel readModel = new ReadModel();



public WriteModel getWriteModel() {

return writeModel;

}



public ReadModel getReadModel() {

return readModel;

}

} class QueryService {

private Database database;



public ReadModel query() {

return database.getReadModel();

}

} class CommandService {

private Database database;



public void command() {

database.getWriteModel().setValue(100);

}

}

In the code above we have two independent models. A separate model for reading and another one for writing. Now Command and Query are independent APIs but the problem that comes with it is:

How Read Model will know that something changed in Write Model?

Database class, which I created above, is only a mock of a real database. As you see we delegate model’s dependency to a database. In the world of relational databases WriteModel would be mapped to TABLE and ReadModel can be mapped to VIEW.

Furthermore the database view can be materialised and refreshed only when something had changed in WriteModel. And this is how we can simply achieve command and query separation.

Decoupling datasources

Is that all? Of course not. In the first part of this article, I also mentioned that the highest level of separation includes separation of datasources. But for now we still have one datasource and coupling on the database level. Actually database VIEW, even materialised, is nothing more than a snapshot of some aggregations and joins on WriteModel. But what’s the goal to decouple write and read sources?

In real life, we usually need a very advance search mechanism. Very often performing fetch operations on database is not sufficient. This is the place where we need search engine like Elasticsearch. But you know what?

We are saved!

Thanks to that we use CQRS approach from the very beginning and we decoupled our APIs and models to read and write parts. Now we can simply move our ReadModel to Elasticsearch cluster without too much effort. Let’s do that.

class Database {

private WriteModel writeModel = new WriteModel();



public WriteModel getWriteModel() {

return writeModel;

}

} class CommandService {

private Database database;



public void command() {

database.getWriteModel().setValue(100);

}

} class Elasticsearch {

private ReadModel readModel = new ReadModel();



public ReadModel getReadModel() {

return readModel;

}

} class QueryService {

private Elasticsearch elasticsearch;



public ReadModel query() {

return elasticsearch.getReadModel();

}

}

And that’s it. Models didn’t change. Interfaces didn’t change. Unfortunately, once again we encounter the same basic problem:

How Read Model will know that something changed in Write Model?

The missing part is synchronization. Once we fully decouple our datasources we have to think more carefully about synchronization between them. In the previous example this was done by a database engine which takes care about data consistency. But this time everything is in our hands.

Unfortunately synchronization is the tricky part. I don’t want to cover any it’s strategies in this article but if you are interested I attached some useful resources:

To sum up

If you want to migrate traditional application to CQRS you have to follow these steps: