Domain Events for UI

414 views
Skip to first unread message

radhakris...@gmail.com

unread,
May 17, 2021, 4:23:19 AM5/17/21
to DDD/CQRS
Hi,
       I am wondering what the nomenclature for read-model events should be. In our case
these read-model events reach the UI through a distributed queue but that is an implementation detail.

When a UI searches for Products there is a domain event just like there is one for a aggregate change event. These projections are dealt with in the same way write events are.

So, for example, a UI searches products based on dates. That event could be FindProducts.
Another could be 'FindOrderHistory'.

Thanks.

Harrison Brown

unread,
May 17, 2021, 5:00:00 AM5/17/21
to DDD/CQRS

For me, a “domain event” is something that’s important to the business — i.e., something relevant to the domain. So, the command model (the write side) is normally the place where domain events are raised because most of what businesses tend to care about is things that have an effect.

For the query model (read side), does the business really care that a visitor searched for a product, or clicked on a link, or opened a page? Unless you’re going to do something interesting with that event such as react to it in another context, etc. it’s quite likely that you shouldn’t be modelling things that happen in the read side as a ‘domain event’ in the same way. The right approach for most query-style things I’ve come across has simply been Google Analytics because my code doesn’t really need to care about it.

The exception to this might be if your domain is actually about search. For example, if you’re a car insurance comparison site you probably do want to think about query-style events because searching for insurance is your whole business. However, even this example might have no domain events in the query side; I’d probably model a ‘quote’ as a concept in by command model: StartQuoteCommand → QuoteWasRequested → ResultsWereReceived → SelectProductCommand → RecommendedProductWasPurchased → …

Obviously, there are some cases where you will need to do something within your own code in response to a query event — you could imagine needing to update a UI once someone has done their first three searches. Personally, I wouldn’t model this as a domain event as it will obscure things the business really cares about. This is just a quick UI optimisation so I’d just do it in some infrastructural code somewhere and not worry too much about it.

However, I can see there are cases where you do need actual domain events because you genuinely are doing something in response to them because the business really does care. An example might be that instead of simply adjusting some UI when a visitor has done some searches the marketing department says they want to start offering special promotions when a visitor has done such-and-such, or when they’ve put something in their basket and not checked out, etc. The abandoned basket case would just use domain events from a command-model (e.g., in the ‘Basket’ context/micro-service/module) but the offering of special promotions for a visitor who’s conducted certain searches is one case where I agree you have a genuine domain event coming from a query model. In such a case, I’d try and keep the nomenclature exactly like that of command models. It’s a domain event so treat it the same way.

So, in summary: unless the business really cares about it and you’re going to do something in response, it’s probably not a domain event so don’t treat it as such. FindProducts and FindOrderHistory are not domain events — they’re not a thing that happened which the business cares about — they’re just queries so make an API and move on. If you need to track things in the UI for analytical purposes (e.g., to optimise your UI or to see what parts of your app people are using or which products are most popular) use something like Google Analytics. If you need to do something in your UI in response to someone’s use of the UI, keep a quick and dirty log somewhere (e.g., in redis) and don’t worry about it. If you genuinely have a need to respond to things happening in the query model and you need to model that properly then you should indeed treat those things as a proper domain event and make then indistinguishable from domains events coming from your command model(s).

(PS. I prefer the terms ‘command model’ and ‘query model’ rather than write-side and read-side. I’ve used them above.)

(PPS. If you’re separating your code into modules/services/contexts then you can see where domain events are useful for communicating things between contexts. E.g., you might have a ProductCatalogue context with a command model that raises events like ProductWasMadeAvailable, ProductWasDiscontinued, etc. and a query model that’s used for users to search and filter products. The query model of the ProductCatalogue context might have lots of things going on but you may only actually make it raise domain events you know you care about, so it might raise ProductSearchWasConducted. You might then create another context/module/service called Promotions whose command-model would listen to ProductSearchWasConducted and offer promotions to customers who conducted certain searches. That context might also listen to events from the Orders context so it only offered promotions to customers who hadn’t purchased yet, or it might listen to events from the Payments context so it only offers promotions to customers whose accounts are in credit.)

--
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/9661ec63-2b3a-4e59-9e76-26f46d88005dn%40googlegroups.com.

radhakris...@gmail.com

unread,
May 18, 2021, 4:00:09 AM5/18/21
to DDD/CQRS
Thanks for the use cases.

> For the query model (read side), does the business really care that a visitor searched for a product, or clicked on a link, or opened a page? Unless you’re going  > to do something interesting with that event such as react to it in another context, etc. it’s quite likely that you shouldn’t be modelling things that happen in the > read side as a ‘domain event’ in the same way. The right approach for most query-style things I’ve come across has simply been Google Analytics because my > code doesn’t really need to care about it.

I realize that our distributed microservices need a uniform event structure. That is the main reason for publishing an event. The UI will
receive an event from the service. But as you point out these are not domain events per se. Just the projection. And we do use events similar
to ProductSearchWasConducted.

Thanks.

Mauro Servienti

unread,
May 18, 2021, 4:25:24 AM5/18/21
to ddd...@googlegroups.com
I’m having a very hard time understanding what’s the use case for an event such as ProductSearchWasConducted

Can you provide more details on the flow and what the uses the event for?

.m

--
Mauro Servienti
Wanna share some thoughts? Just grab a coffee and let's have a chat.

Ben Kloosterman

unread,
May 20, 2021, 6:42:53 PM5/20/21
to ddd...@googlegroups.com
Im with Harris as well i tend to just use viewxyzupdated which works well with other teams and systems as well ... KISS .  Though in most cases there are no events in off read model. 

Mohan Radhakrishnan

unread,
May 22, 2021, 2:37:26 AM5/22/21
to ddd...@googlegroups.com
We don't have DDD usecases for such events as of now. But a ProductSearchWasConducted event flows through the message bus
the same way domain events flow to other microservices. The only difference is that the subscriber to this query model event is a UI.

Thanks.

Phil Sandler

unread,
May 22, 2021, 11:26:46 PM5/22/21
to DDD/CQRS
Is there a reason why a product search isn't modelled as request/response?

I could see use cases for something like "viewxyzupdated" in an  eventually-consistent system.

Mohan Radhakrishnan

unread,
May 23, 2021, 2:54:19 AM5/23/21
to ddd...@googlegroups.com
> Is there a reason why a product search isn't modelled as request/response?

The system has a UI that issues a GET Rest request as usual. But the response isn't a Rest response. It is an event with data and metadata( correlation ID etc. )
The paradigm is different because the message bus connects to the UI asynchronously. The request can flow through multiple backend services but eventually the response event reaches the UI through the message bus. 
These query events can be audited. The event is modelled using OpenAPI. Some prefer https://www.asyncapi.com/

Thanks.

Mauro Servienti

unread,
May 23, 2021, 3:11:56 AM5/23/21
to ddd...@googlegroups.com
The interesting thing here is that you’re describing the how not why, which is what led me to ask what’s the use case.
Let me ask a different question, why are those data so hard to retrieve that they need such level of complexity to get a query response?

Going with messaging when the use case is request/response is in most cases, if not all, an anti pattern. The only use case I faced so far is the evolution of a synchronous system into an asynchronous one where the UI is generally handled last in the process and so for a while it needs to deal with a mixed sync/async scenario.

radhakris...@gmail.com

unread,
May 24, 2021, 6:43:20 AM5/24/21
to DDD/CQRS
> Let me ask a different question, why are those data so hard to retrieve that they need such level of complexity to get a query response?
This is now a system design question ? The request only reaches the API gateway. There is no service waiting behind it to send a sync. response
There are multiple instances of the service and any one can pick it up from the message bus. So the query response event has to be put back in the
message bus and it will reach the UI.

Rickard Öberg

unread,
May 24, 2021, 9:48:34 AM5/24/21
to ddd...@googlegroups.com
On Mon, May 24, 2021 at 6:43 PM radhakris...@gmail.com <radhakris...@gmail.com> wrote:
> Let me ask a different question, why are those data so hard to retrieve that they need such level of complexity to get a query response?
This is now a system design question ? The request only reaches the API gateway. There is no service waiting behind it to send a sync. response
There are multiple instances of the service and any one can pick it up from the message bus. So the query response event has to be put back in the
message bus and it will reach the UI.

So the followup question becomes: why is this preferred over using a load balancer to those services, with a request/response pattern?

cheers, Rickard
 

Mohan Radhakrishnan

unread,
May 24, 2021, 10:23:28 AM5/24/21
to ddd...@googlegroups.com
> So the followup question becomes: why is this preferred over using a load balancer to those services, with a >request/response pattern?
> Let me ask a different question, why are those data so hard to retrieve that they need such level of complexity to get a query response?

It is not complex at all because the cloud provider's queues are designed for these purposes. And the UI does not only issue queries. They send aggregate change events too. So  a service handles both writes and reads uniformly.
It is possible to have a load-balanced Rest endpoint just for queries in each service but then these services also put events into queues for other microservices. Part of the service will use async. events and the other part will serve sync. responses. It is easy for us to unify both just because the infrastructure is fast enough.

 (e.g) A credit card is used to purchase but before the purchase is sanctioned a fraud service checks something and
after some time approves the purchase. All these services use queues and async events. But the UI can also query
and view the details of the fraud and the operational user can release the payment. It is easier to have async. events everywhere. 



--
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.
Reply all
Reply to author
Forward
0 new messages