Udi Dahan gave a very good talk yesterday evening at Zenika, there was only few attendees… perhaps because it was on a Monday evening. Whatever, there was barely not enough place already in the Italian restaurant where we moved after.
I won’t make a full report, just talk about some interesting points.
First of all, the session focused mainly on why you should do CQRS and not how. Second point, the talk was not about event sourcing, but you already now that you can do CQRS without event sourcing.
Something we should accept : Stale Data
The paradigm of usual architecture’s best practice has a serious flow : when you show data to your users, it’s already stale.
Is it important ? Yes.
Is it a problem ? Not really.
The world have worked with stale data for years, and it was handled rather gracefully until now. Computers have reduced the time span, but when the data appear on the screen, it’s stale.
Tel it to your users, they will accept it. Find with them what is acceptable. 1 second, 10 seconds, 1 minute, 1 hour, 1 day ? The users are used to it in there own business. Do it too.
What’s the purpose of queries ? To show data. Not objects.
So why should the data from the database come across 5 layers through 3 model transformations ? It’s a bit overkill to display data.
Why not just this : The UI read data from the database and displays it ?
No DTOs, no ORM, not business rules executed on each query.
You simply define a Persistent ViewModel (thank’s Udi, I like this description of the Q side), and display it directly to screen. It should be as simple as one database table per UI view.
Of course you need a way to keep the Persistent ViewModel up to date, but we’ll see that later.
On the other side, there are commands.
It should be done in 3 phases :
Is the input potentially good ? Structured correctly, no missing field, everything fit in ranges ?
This can be done without knowing current state, and be done outside of entities command handling.
Should we do this ?
Here, the decision is taken using current state.
It leads to a discussion about UI design. In order to handle the user command as well as you can, you have to capture the user intent in the command.
In CRUD applications, the new data is sent by the UI layer. You have to extract the user intent from that data to know if you can process the data.
There is a huge difference between UserMovesToNewAddress and CorrectTheMisspellingInUserAddress from a business point, but in a CRUD application you would probably end with the same Update data…
What’s the new state ?
It’s the easy part once the rules are applied.
What aren’t they for ?
Validation : commands are validated before the model is called. Do not bloat your domain model with this.
Queries : entity relationships for reading are unnecessary. You can do eager loading on your Aggregate Roots safely, they’ll never be used for queries that need only partial information.
What are they for ?
Answer to the question : should we do what this valid command is asking ?
If the answer is yes, change the state !
Maintain the query model up to date
There are two main ways to maintain query model up to date.
You can use something like views or ETL to transform data from the domain data to the shape required by the query side.
If you prefer, or when your domain persistence is not compatible with this option (OODB, Event Storage..), you can publish events from you command side, and provides handler’s on the query side that will maintain the views state in the relational database (or a cube… or whatever). A denormalization will happen here.
What do we gain from this ?
The model is deeply asynchronous, it’s not a matter of tweaking things with threads. It’s asynchronous from the ground up, at domain level.
Your user sends a command, and your design is good if you can answer : “thank you, we will come back to you soon…”. Take the time needed to fulfill your user wish, he will be happy !
By relaxing the rules, the system becomes more scalable.
Domain persistence choice
The domain is accessed only to process rules and state changes. There is no need to join tables, filter rows. So you can easily use an non relational database.
Possible options are a OODB or an Event Storage (for event sourcing).
You can still use a RDBMS with or without an ORM if you’re more familiar with these technologies.
But the persistence mechanism becomes an implementation detail from from Command side that will not interfere with your queries.
Ooops, I said it was not a complete report… but it actually is. Every point was interesting ?
After the talk we had a discussion about forecasting and other interesting subjects. Perhaps more on this later.
There was a video camera in the room, so I think the guys from Zenika will try to put it on the internet when they have time. I’ll add the link when available.
If you was here and have a picture of the event, I would be glad to put it in the blog :D