I'm struggling with my Read Model as it is kind of a mix between domain logic and read model. Imagine getting quotes for a hotel or airline. In my instance it's shipping. To get a quote you need to read existing rate tables and then calculate the rate. You might log this as quote, to eventually turn into an order, but the getting quotes part is essentially a read, with some logic (i.e. service to get current fuel rate) to factor into the rate. The aggregate would be a Quote.
So would you use the read model to get the contract/rate table, and map that to the domain? Keep in mind the read is going to be optimized, it's not just a simple GetByID... and preferably coming from the read store for performance.
In event sourcing, read models do not represent domain entities by definition. The only source of truth is the event stream of that entity.
A read model is a model specialized for reads, that is, queries. It takes events produced by the domain and uses them to build and maintain a model that is suitable for answering the client's queries. It can draw on events from different aggregates and even different types of aggregate.
Domain-driven design is the idea of solving problems of the organization through code. The business goal is important to the business users, with a clear interface and functions. This way, the microservice can run independently from other microservices.
Event Sourcing and CQRS pattern When used with the Event Sourcing pattern, the store of events is the write model, and is the official source of information. The read model of a CQRS-based system provides materialized views of the data, typically as highly denormalized views.
So would you use the read model to get the contract/rate table, and map that to the domain? Keep in mind the read is going to be optimized, it's not just a simple GetByID... and preferably coming from the read store for performance.
By design, aggregates shouldn't need to be immediately consistent with any model state outside of the aggregate boundary -- the "next" state is a function of the current state, and the arguments passed in. In other words, the idealized aggregate doesn't depend on the read model at all, and doesn't care where the state of the arguments came from.
Which means if you are struggling with "how do I get the current Rate from that aggregate when I'm writing a Quote in this aggregate", then something is badly wrong.
But if you don't need immediate consistency (in most cases, you don't), then there are a number of possibilities.
The most straight forward is that the client gets the state that it needs from the read model, and then passes that state along to the write model. Loading the state into the command avoids "confusion", which is one of the reasons that REST has been so successful.
In some cases, you'll want the "recent" state from the other parts of the model to be more timely. In that case, you might prefer that the application query the model on behalf of the client prior to submitting the change to the aggregate. Perfectly reasonable.
In some cases, you'll want the aggregate itself to perform the query. The most common way to achieve this is via a domain service: you pass to the aggregate a query object, the aggregate invokes the query with whatever state is appropriate, gets an answer back, and then chooses for itself how to apply the result to its current work.
In all of these, the state that you are getting back from the model is recent, without necessarily being current. For instance, there are no guarantees that the other parts of the model aren't currently being changed in such a way that the query results would change.
Note that in all of these cases, the caller (in particular, the aggregate) is completely insulated from the details of the calculation provided by the domain service -- the domain service is the only piece that needs to know if the rate returned is calculated from the write model, calculated from the read model, or just pulled from a cache.
My question is should I access the read model from within the domain, and then map those to domain objects.
No. The write model should only interact with its own state, and its parameters. If you need to lookup data in the read model to process a command, then one of the parameters should be a domain service interface, where the implementation of the domain service performs the lookup and transforms the result into domain objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With