4

I'm new to DDD + CQRS, and I'm working in a project that has this implemented, but I wonder why the guy duplicates the models.

I understand, that one is for writing (commands) and one is for reading, but both implement the same fields, except that ReadModel only has getters.

Is there any advice against having the fields (id, name, socialnumber, etc) of a relational database AND getters in a model then inherit them in WriteModel and ReadModel?

For example:

Abstract UserModel

UserReadModel inherits UserModel

UserWriteModel inherits UserModel

1
  • 2
    Yeah, this seems excessive. Keep it simple, and just read and write model objects. I don't see how you're buying much from this except having immutable read objects. What purpose does that serve? – Robert Harvey Mar 13 '17 at 15:14
9

Sharing a base model is against everything that CQRS stands for. If your models (write and read) are 99% percent then it is a CRUD architecture painted to look like CQRS.

You must split the write from the read because the two models have different behaviors: the write model is concerned with ensuring the invariants and the read model is concerned with the reading and displaying the data to the user. It is normal that some of the fields are shared but only as concepts. In the write side, you create Commands that have those fields, send them to the write models (Aggregates in DDD) and generate events that have some of the fields from the commands. In the read side you read the events and create some simple persistence objects, with no behavior that ensure the invariants; they can have behavior but a different kind from the write models.

On the read side you could have mega objects that contain fields from multiple write models. The main idea of the read models is to be very fast (i.e. no JOINS), so you include in a row or document all you need to display the data to the users.

On the other side, the write side, you put in commands only the minimum information needed to maintain the invariants (i.e. you refer other Aggregate roots only by their IDs).

So, as a metaphor, the write and read models are like matter and antimatter: they should not collide; they are separated (decoupled) by events that act like a magnetic fields.

UPDATE:

The read models only see the events generated by the Aggregates (the write models); they don't query the write models as it is forbidden; so the write models have only command methods and no query methods; on the other hand, the read models have only query methods (i.e. getters) and no command methods; the read models are immutable; the only way to mutate the read models is by listening to the events and apply those events them.

2
  • I understand the differences between WriteModel and ReadModel, one ensures invariant, and the other is inmutable. But don't both objects share the same fields? For example, UserWriteModel will have always id, name, username. And the UserReadModel too. Also, I do joins in the ReadModel, to populate the relations, example User, Car, why is it bad?. – JorgeeFG Mar 13 '17 at 15:24
  • CQRS permits you to put in a row all the relational data, it permits you to have full denormalization. You just have to listen to the right/relevant events. If you use JOINS then most probable you didn't understand CQRS, which is not bad :) you just have to read more. See here: squirrel.pl/blog/2015/09/28/persistence-in-cqrs-read-models – Constantin Galbenu Mar 13 '17 at 15:33
1

Is there any advice against having the fields (id, name, socialnumber, etc) of a relational database AND getters in a model then inherit them in WriteModel and ReadModel?

Actually, there is. The read model and the write model are conceptually different, and in particular evolve largely independently of each other.

Matthias Verraes wrote:

“Don’t Repeat Yourself” was never about code. It’s about knowledge. It’s about cohesion. If two pieces of code represent the exact same knowledge, they will always change together. Having to change them both is risky: you might forget one of them. On the other hand, if two identical pieces of code represent different knowledge, they will change independently. De-duplicating them introduces risk, because changing the knowledge for one object, might accidentally change it for the other object.

I would expect the read and write models to have many common concepts in them. Value types from the domain model, for example: if you have a Money type it will likely make sense in the read model just as it does in the write model.

But, as Constantin points out, the motivation for the CQRS pattern is to allow writes to use an underlying data structure optimized for writes (for example: a history), and the reads an underlying data structure optimized for reads. So I wouldn't be in a hurry to couple the read model and write model together.

I don't see how you're buying much from this except having immutable read objects. What purpose does that serve?

Code clarity is a big one -- putting a reference to an immutable interface into your method signature clearly documents that you will not be attempting to modify the argument in any way. Thus, in your write code paths, there's no confusion about which object is going to be written -- it's always going to be the mutable one.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.