According the article of Martin Fowler and Microsoft CQRS Journey, the CQRS is a pattern applying in a BC, not the architecture for whole system. I get confused in how to get state of an aggregate from anything external in CQRS.
Should an aggregate have a command Get to return its state in write model, or a corresponding query in read model?
It's example of shopping cart service in Akka Platform Guide.
ShoppingCart is an aggregate, it has three commands: AddItem, Checkout and Get. In the command handler of Get, it replies summary of shopping cart to the command sender. In this way, each aggregate has a command Get to return its state in write model.
But I suppose the Get is a query exactly, not a command. Because in CQRS pattern, command changes the state of the aggregate and triggers events, but returns nothing. On the other side, query returns a copy of the current state of the aggregate, but changes nothing. All commands exist in write model, all queries exist in read model. If I want to get state, I shouldn't send a command to write model but a query to read model. The eventually consistence is maintained by the event projection from write model to read model.
So, the Get of ShoppingCart should be moved into read model. Anything external wants to get the state of ShoppingCart, it should send query Get to ShoppingCart and get reply Summary finally. But in this way, the state maybe is stale. Should it get problem in consistence?
Which design is necessary and better?
Putting Get in read model gets risk of consistence, putting it in write model gets semantic ambiguity otherwise. That's my confusion.
Thanks.
If you’re going to use CQRS at all then yes, you’d want to ask the query model for state about the system, not the command model. I’d avoid querying the command model as it rather defeats the point of CQRS.
And yes, if you are asynchronously projecting your query model from the command model then you will indeed have eventual consistency meaning the two won’t always be in sync. That’s normal for CQRS with async projections so you’ll need to design around that (normally my recommendation) so your system can cope with it and handle the user experience gracefully. However, you don’t have to do async projections — if you want to keep your query and command models truly separate and autonomies then you will do async, but you can get lots of benefits of CQRS without going that far. My team have created many systems with separate command and query APIs which both connect to the same database, and we’ll either use semi-complex SQL queries to get data for the query model, or we might synchronously project a query model from the command model meaning we have immediate consistency. This is a perfectly viable approach and isn’t “bad CQRS” in any way. See https://udidahan.com/2009/12/09/clarified-cqrs/
So, to summarise: Yes, you’re right that putting a Get query in the command model is odd and to be avoided. You should query the query model, but you get to decide whether you need to do (a) async projections (which will come with eventual consistency but keeps your query and command models very cleanly separated and autonomous), (b) synchronous projections (which keeps the APIs of your query and command models cleanly separated but makes them less autonomous because they’ll both need to talk to the same database) or (c) no projections at all (which means you don’t have autonomous query and command models in a full sense but does still give you the semantic benefits of CQRS). None of these options are better or worse than each other; you get to decide which is most appropriate and which tradeoffs you can make. In general, I advise people to start with (c) because you learn the pattern without taking on the burden of thinking about projections, asynchronous processes and eventual consistency. For simple cases, those async patterns are overkill.
Harrison
--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dddcqrs/b5dc55ff-436b-40b5-9a69-e234d30bffabn%40googlegroups.com.
Er, no that’s not what I’m saying. If you apply CQRS with asynchronous projections then yes, your query model will be eventually consistent with your command model — however, you don’t have to use asynchronous projections. You can apply the pattern with synchronous projections, or just from the same persistence with CQRS applied at the API level (i.e., different code reading the same database tables for querying meaning your command model isn’t involved in queries at all).
And yes, CQRS is a service-/BC-level pattern, not a whole-system architecture. That means this sentence isn’t correct: “From the external of aggregate, it doesn't know or care if the aggregate uses CQRS pattern. The query Get
is a part of protocol or API of aggregate” The aggregate pattern is to do with write consistency so only applies in your command model, so a query isn’t part of the API of an aggregate, it’s part of the API of your query model (which doesn’t have aggregates).
Thus, I’d say that whether you ”put Get
into read model or write model is a design choice in CQRS pattern” is incorrect: putting your ‘get’ queries into a separate query model _is CQRS. If you put your ‘get’ queries into your command model then you have a single model for both queries and commands and are therefore not doing CQRS.
Harrison
To view this discussion on the web visit https://groups.google.com/d/msgid/dddcqrs/305845a6-a335-4097-9769-609973c82732n%40googlegroups.com.
Er, no that’s not what I’m saying. If you apply CQRS with asynchronous projections then yes, your query model will be eventually consistent with your command model — however, you don’t have to use asynchronous projections. You can apply the pattern with synchronous projections, or just from the same persistence with CQRS applied at the API level (i.e., different code reading the same database tables for querying meaning your command model isn’t involved in queries at all)..
To view this discussion on the web visit https://groups.google.com/d/msgid/dddcqrs/305845a6-a335-4097-9769-609973c82732n%40googlegroups.com.