CQRS: Can the write model consume a read model? - domain-driven-design

When reading about CQRS it is often mentioned that the write model should not depend on any read model (assuming there is one write model and up to N read models). This makes a lot of sense, especially since read models usually only become eventually consistent with the write model. Also, we should be able to change or replace read models without breaking the write model.
However, read models might contain valuable information that is aggregated across many entities of the write model. These aggregations might even contain non-trivial business rules. One can easily imagine a business policy that evaluates a piece of information that a read model possesses, and in reaction to that changes one or many entities via the write model. But where should this policy be located/implemented? Isn't this critical business logic that tightly couples information coming from one particular read model with the write model?
When I want to implement said policy without coupling the write model to the read model, I can imagine the following strategy: Include a materialized view in the write model that gets updated synchronously whenever a relevant part of the involved entities changes (when using DDD, this could be done via domain events). However, this denormalizes the write model, and is effectively a special read model embedded in the write model itself.
I can imagine that DDD purists would say that such a policy should not exist, because it represents a business invariant/rule that encompasses multiple entities (a.k.a. aggregates). I could probably agree in theory, but in practice, I often encounter such requirements anyway.
Finally, my question is simply: How do you deal with requirements that change data in reaction to certain conditions whose evaluation requires a read model?

First, any write model which validates commands is a read model (because at some point validating a command requires a read), albeit one that is optimized for the purpose of validating commands. So I'm not sure where you're seeing that a write model shouldn't depend on a read model.
Second, a domain event is implicitly a command to the consumers of the event: "process/consider/incorporate this event", in which case a write model processor can subscribe to the events arising from a different write model: from the perspective of the subscribing write model, these are just commands.

Having read a lot about the topic and having thought hard about it myself, I attempt to answer my own question.
First, a clarification about the terms used. The write and read models themselves never have any dependency to one another. The corresponding command and query components might have instead. I will therefore call the entirety of the command component and its write model the command side, and the entirety of one particular query component and its read model a query side (of which there might be many).
So consider a command handler that is responsible for evaluating and executing a business policy. It takes a command DTO, validates it, loads part of the write model into memory, and applies changes to it in one atomic transaction. The question specifically was, whether this handler is allowed to query one of the query sides in order to inform its decision about what to do in the write model.
The answer would be a resounding NO. Here's why:
The command side would depend on one particular query side (it doesn't matter if you hide the dependency behind an interface – it is still there), so the query side cannot change independently.
Who actually guarantees that the command handler runs when it has to? The query side is certainly not the one responsible for it, and clients aren't either.
The command request is prolonged by performing a nested query request, which might be detrimental to the performance.
Instead, we can do the following:
Work with domain events raised by the write model, register a domain event handler in the command side that evaluates the policy. This way it is guaranteed that the policy will be executed whenever it has to be.
If the performance allows it, this domain event handler can simply load as much of the write model as it requires to evaluate the business condition. Don't prematurely optimize – maybe the entities are small and can easily be loaded into memory.
If the performance does not allow it, denormalize the write model and maintain the required statistics using domain events. No one says that the write model cannot itself contain query-oriented data. Being a write model simply says that it is a model designed to do writes, and this necessarily must include some means to read as well.
Finally, if applying the policy is not an integral part of the domain logic itself, but rather just a use case, consider putting the responsibility of calling it into a client or another microservice, where it is totally fine to first query one of our query sides, and afterwards calling our command side with the appropriate parameters.

Related

Test Axon aggregate's behaviour with non-aggregate events

I'm trying to ensure an aggregate field is unique on creation. I'm trying to handle the eventually consistency of the projections by using the following flow:
Command creates a new aggregate
Aggregate issues creation event
Event handler attempts to materialize the projection and if there is a uniqueness violation, it emits a UniqueConstraintViolationEvent
Aggregate consumes this event and marks itself as deleted
I'm trying to use the AggregateTestFixture to test this, but it doesn't appear to allow you to preform any assertions without issuing a command (whenThenTimeElapses seems to allow assertions, but I get a NPE when asserting the aggregate has been deleted). Is there a way to use the test fixture for this case, or is it not designed to account for non-aggregate events. If not, is there another way to verify that the aggregate has been removed?
I'm not confident that this is actually the correct approach. I've also considered dispatching a command in (3) or using a saga to manage the interaction. If I dispatch a command instead of an event, it seems to simply force me to write more boilerplate to emit the UniqueConstraintViolationEvent from the aggregate. Likewise, if I use a saga to model this interaction, I'm unsure how to end the saga's lifecycle without having the projection materializer emit a success event that the saga consumes.
You are looking at a Set Based Validation scenario, which is a little more cumbersome when dealing with a CQRS system. This blog explains some of your options nicely I feel, thus I'd pick and choose from there.
As a form of guideline, note that the Aggregate guards it's own consistency boundary. Extending that boundary by asserting uniqueness among an entire set of Aggregate is thus not desirable. Simply put, not a single Aggregate instance's problem.
Hence, I would perform this uniqueness check prior to issuing the command, by consulting a lightweight query model containing the desired constraint.

How to Implement DDD repository pattern using raw JDBC or Mybatis?

let's say I have a complex aggregate root (AR)
in a user transaction, I multiple this AR:
ar.doSomeThing1();
ar.doSomething2();
ar.doSomething3();
ar.doSomething4();
then I use a repository to persistent all the change
arRepo.update(ar)
My question is How to Implement arRepo.update use row JDBC or Mybatis?
the main difficulty is :
arRepo does not know what changed, the only way is to update all the ar data in the database.
The main principle is that your DDD core should know nothing about JDBC, TCP or ORM. Everything it knows should be expressed in terms of a Ubiquitous Language.
But that doesn't mean it shouldn't know what changed. You may use sort of event sourcing and save events under AR from which necessary updates could be derived.
Maybe that gets not very object-oriented, but you may give it a try. Effectively, AR can be represented as a decision maker, who gets requests for changing its state, decides whether to accept these requests or reject, and then stores a list of state-changing events.
You then need to reduce this event list to a read model somewhere, but that's not the responsibility of AR, if you use this approach.
When I mention decision making, I mean a pure function that doesn't go to a disk or a network for data. It means, that all necessary data should be gathered prior to decision making and persisted afterwards. That goes to application layer.
And this application layer is who interacts with repositories or network adapters. It may also handle transactions and so on. Next, calculating an SQL UPDATE query is an implementation detail of a repository. But as long as a state changes are expressed in terms of ubiquitous language, it can well be known to aggregates and domain core.

Read model for aggregate in DDD CQRS ES

In CQRS + ES and DDD, is it a good thing to have small read model in aggregate to get data from other aggregate or bounded context?
For example, in order validation (In Order aggregate), there is a business rules which validate order only if customer is not flagged. The flag information is put in read model (specific to the aggregate) via synchronous domain events.
What do you think about this ?
is it a good thing to have small read model in aggregate to get data from other aggregate or bounded context?
It's not ideal. Aggregates, due to their nature, are not good at enforcing consistency that involves state outside of themselves.
What this usually means is that the business is going to need some way to respond when two aggregates produce an unacceptable state.
You also have the option of checking for the flag before you run the placeOrder command on the aggregate. That check for the flag could be done in the command handler, or in the client -- basically, you have was of "validating" that the command should succeed before passing it to the aggregate.
That said, if it were critical to try to consult the read model while processing the command, a way to do it would be to use a "domain service"; you pass a service provider to the aggregate as part of the command, and let the interface abstract away the fact that running the query requires looking outside of the aggregate.
That gives you some of the decoupling you need to keep the aggregate testable.
It's doable, but not in the form of a read model, rather a Value Object in the Aggregate (since we're on the Write side).
If you already have a CustomerId in Order, you just have to compose a VO with it and a Flagged member.
Of course, this remains prone to all the problems of cross-aggregate communication since the data originates from Customer. Order has to be kept in sync with the flagged status of its Customer, which can require quite a bit of work.
In any case, you should probably first determine with your domain expert whether immediate consistency is an absolute requirement (in which case you have to somehow wrap Customer + Order in a transaction) or if you can afford a small delay in Flagged freshness when enforcing that invariant.
If the latter, you can choose between duplicating Flagged in the Order aggregate or the first option given by #VoiceOfUnreason - the main difference being probably that if the data is in the aggregate, you'll get it for free at the Domain level should you need it in multiple occasions, instead of duplicating the check in multiple use cases/command handlers at the application level.

Showing data on the UI in the Hexagonal architecture

I'm learning DDD and Hexagonal architecture, I think I got the basics. However, there's one thing I'm not sure how to solve: how am I showing data to the user?
So, for example, I got a simple domain with a Worker entity with some functionality (some methods cause the entity to change) and a WorkerRepository so I can persist Workers. I got an application layer with some commands and command bus to manipulate the domain (like creating Workers and updating their work hours, persisting the changes), and an infrastructure layer which has the implementation of the WorkerRepository and a GUI application.
In this application I want to show all workers with some of their data, and be abe to modify them. How do I show the data?
I could give it a reference to the implementation of WorkerRepository.
I think it's not a good solution because this way I could insert new Workers in the repository skipping the command bus. I want all changes going through the command bus.
Okay then, I'd split the WorkerRepository into WorkerQueryRepository and WorkerCommandRepository (as per CQRS), and give reference only to the WorkerQueryRepository. It's still not a good solution because the repo gives back Worker entities which have methods that change them, and how are these changes will be persisted?
Should I create two type of Repositories? One would be used in the domain and application layer, and the other would be used only for providing data to the outside world. The second one wouldn't return full-fledged Worker entities, only WorkerDTOs containing only the data the GUI needs. This way, the GUI has no other way to change Workers, only through the command bus.
Is the third approach the right way? Or am I wrong forcing that the changes must go through the command bus?
Should I create two type of Repositories? One would be used in the domain and application layer, and the other would be used only for providing data to the outside world. The second one wouldn't return full-fledged Worker entities, only WorkerDTOs containing only the data the GUI needs.
That's the CQRS approach; it works pretty well.
Greg Young (2010)
CQRS is simply the creation of two objects where there was previously only one. The separation occurs based upon whether the methods are a command or a query (the same definition that is used by Meyer in Command and Query Separation, a command is any method that mutates state and a query is any method that returns a value).
The current term for the WorkerDTO you propose is "Projection". You'll often have more than one; that is to say, you can have a separate projection for each view of a worker in the GUI. (That has the neat side effect of making the view easier -- it doesn't need to think about the data that it is given, because the data is already formatted usefully).
Another way of thinking of this, is that you have a "write-only" representation (the aggregate) and "read-only" representations (the projections). In both cases, you are reading the current state from the book of record (via the repository), and then using that state to construct the representation you need.
As the read models don't need to be saved, you are probably better off thinking factory, rather than repository, on the read side. (In 2009, Greg Young used "provider", for this same reason.)
Once you've taken the first step of separating the two objects, you can start to address their different use cases independently.
For instance, if you need to scale out read performance, you have the option to replicate the book of record to a bunch of slave copies, and have your projection factory load from the slaves, instead of the master. Or to start exploring whether a different persistence store (key value store, graph database, full text indexer) is more appropriate. Udi Dahan reviews a number of these ideas in CQRS - but different (2015).
"read models don't need to be saved" Is not correct.
It is correct; but it isn't perhaps as clear and specific as it could be.
We don't need to create a durable representation of a read model, because all of the information that describes the variance between instances of the read model has already been captured by our writes.
We will often want to cache the read model (or a representation of it), so that we can amortize the work of creating the read model across many queries. And various trade offs may indicate that the cached representations should be stored durably.
But if a meteor comes along and destroys our cache of read models, we lose a work investment, but we don't lose information.

Business Process to "Transfer" a one-to-many association

Introduction To Domain
I have a Salesman. A Salesman gets BusinessOpportunity's. Both make sense in my domain to be ARs.
There are two ways to model this:
A Salesman aggregate is unaware of its business opportunities, or
A Salesman is aware of his list of opportunities (using an OpportunityId of course)
A BusinessOpportunity, I believe, always needs to know its SalesmanId.
The Question
I have a business process that I plan on implementing using a Process Manager pattern. It is a "TransferAllBusinessOpportunities" process. It means taking 1 salesman and "transferring" all of his/her opportunities to the other.
How should we do this? and how should we model the domain?
I can think of a process state machine if we model this as a bidirectional association, but its quite involved. I don't know how to do it if we only have a unidirectional association because we'd then need to resort to the read model to get the list of business opportunities to transfer and I'm worried that we should keep everything in the write-side model. What do you think about that?
Any help is very much appreciated. Attached a diagram below to help visualize if that helps.
A quick roundup of the questions:
How would you tackle this problem?
How would you model the domain to best tackle this?
Is it ok to use the read model in a command handler to execute the business process?
Thanks again.
Meta-answer: you need to read what Greg Young has to say about set validation. You'll be in a better position to explore your requirements with your domain experts.
I don't know how to do it if we only have a unidirectional association because we'd then need to resort to the read model to get the list of business opportunities
Extracting the data from the read model should be your first resort. What's the problem?
Basic outline
Query the read model for the set
Create command(s) to update the write model based on the set
Dispatch the commands to the write model
the write model gets the set data it needs from the command (not from the read model)
The first resort won't always satisfy your requirements, but it's a good starting point for thinking about the use case. What problems could occur if you implemented this simple way? what would those problems cost the business?
Also: I said commend up above, but it might not be. One thing that you didn't describe is what part of the model "decides" the transfer. Is the model allowed to reject the command to transfer the opportunity? Under what circumstances? which aggregate holds the state that determines if the transfer is allowed?
It might be that the transfer isn't being described as a command, so much as it is by an event, describing a decision made by some human sales manager.
I'm worried that we should keep everything in the write-side model
Maybe. Is there a business invariant that needs the state of the set? So far, it doesn't sound like it, which strongly implies that the set does not belong in the write model. You want to strip down your aggregates as far as you can without losing the ability to enforce the invariant.
Is it ok to use the read model in a command handler to execute the business process?
Is it "ok"? Judging from what I have read in various places, a number of people think so. Personally, I'm not convinced. Roughly, you are looking at two broad outlines
Create a thin command
Send the command to the command handler
Query the read model to flesh out the missing details
Process the fleshed out command
vs
Query the read model
Use the query results to construct a fat command
Send the command to the command handler
Process the command
I've yet to see an example where the business would care about the distinctions between these two implementations; the latter implementation is easier to predict (you don't need to know anything about the state of the read model, just the state of the aggregate and the state of the command).

Resources