My application following CQRS strategy separates Read model from Write model. I have a Product and multiple Purchase orders related to that Product.
The PurchaseOrder read model is in Elasticsearch and with product name attached. Now if I change the product name in the write model then I need to update all the PurchaseOrder's productName field accordingly in the read model(using Elasticsearch's bulk update API).
My question is: As I have millions of PurchaseOrders, will this productName sync be a performance issue? Or any suggestions for modeling such kind of syncing?
Although I do not believe that changing a product name on existing orders is a good idea (the invoice might have been generated and the product name in the order should match the one in the invoice), the question still has merit.
You may want your PurchaseOrder to only keep the ID (and perhaps the version?) of the Product, so that you can avoid such a mass update. This approach, on the other hand, requires a call to the Product aggregate root every time you want to translate the ID of the product in its own name. The impact of such a read can obviously be mitigated by using a cache.
I guess it really depend on the number of occurrences of such two circumstances to happen and I would then optimize the most occurring one.
Related
What is the DDD way of handling the following scenario:
user enters Order Create screen and starts creatingnew Order with OrderItems
user chooses ProductX from products catalog and adds quantity
OrderItem for ProductX is created on Order and user goes on adding another product
in the meantime, before Order is saved, admin changes price for ProductX
Assuming Product and Order/OrderItem are separate aggregates, potentially even separate bounded contexts, how is this handled?
I can think of several options:
optimistic concurrency combined with db transactions, but then if we broaden the question to microservices where each microservice has its own db - what then?
joining everything into one giant AR but that doesn’t seem right.
introduce a business rule that no product prices are updated during the point of sales working hours but that is often not possible (time triggered discounts, e.g.)
What is the proper DDD/microservices way of solving this?
What is the proper DDD/microservices way of solving this?
The general answer is that you make time an explicit part of your pricing model. Price changes made to the product catalog have an effective date, which means that you can, by modeling time in the order, have complete agreement on what price the shopper saw at the time of the order.
This might introduce the concept of a QuotedPrice as something separate from the Catalog price, where the quote is a promise to hold a price for some amount of time.
To address this sort of problem in general, here are three important papers to review:
Memories, Guesses, and Apologies -- Pat Helland, 2007
Data on the Outside vs Data on the Inside -- Pat Helland, 2005
Race Conditions Don't Exist -- Udi Dahan, 2010
I think one way to solve this through is Events. As you said, Product and Order can are very least separate aggregates, I would keep them loosely coupled. Putting them into one single aggregate root would against Open/Close and Single Responsibility Principle.
If a Product changes it can raise a ProductChanged event and likewise of an Order.
Depending on whether these Domain-Objects are within the same service or different service you can create a Domain-Event or an Integration event. Read more about it here.
From the above link:
A domain event is, something that happened in the domain that you want other parts of the same domain (in-process) to be aware of. The notified parts usually react somehow to the events.
I think this fits perfectly to your scenario.
I have multiple Orders which have related Payments and related InvoiceCorrections.
I want to fetch all orders where the
order->payments->sum('amount')differs from(order->amount - order->invoiceCorrections->sum('amount')).
What would be the best way to archive this, while keeping a good performance?
The payments should have their own column containing correction information which gets updated via a model observer, otherwise your queries are going to get very complex and messy very fast.
Two questions
1) How to model aggregate and reference between them
2) How to organise/store events so that they can be retrieved efficiently
Take this typical use case as example, we have Order and LineItem (they are an aggregate, Order is the aggregate root), and Product aggregate.
As LineItem needs to know which Product, so there are two options 1) LineItem has direct reference to Product aggregate (which seems not a best practice, as it violate the idea of aggregate being a consistence boundary because we can update Product aggregate directly from Order aggregate) 2) then LineItem only has ProductId.
It looks like 2nd option is the way to go...What do you think here?
However, another problem arises which is about building a Order read/view model. In this Order view model, it needs to know which Products are in Order (i.e. ProductId, Type, etc.). The typical use case is reporting, and CommandHandler also can use this Product object to perform logic such as whether there are too many particular products, etc. In order to do it, given the fact that those data are in two separate aggregate, then we need 1+ database roundtrips. As we are using events to build model, so the pseudo code looks like below
1) for a given order id (guid, order aggregate id), we load all the events for it; -- 1st database access
2) then build a Order aggregate, then we know which ProductId are referenced in Order;
3) for the list of ProductIds, we load all events for it; -- 2nd database access
If we build a really big graph of objects (a lot of different aggregates), then this may end up with a few more database access (each of which is slow)...What's your idea in here?
Thanks
Take this typical use case as example, we have Order and LineItem (they are an aggregate, Order is the aggregate root), and Product aggregate.
The Order aggregate makes sense the way you have described it. "Product aggregate" is more suspicious; do you ask the model if the product is allowed to change, or are you telling the model that the product has changed?
If Product can change without first consulting with the order, then the LineItem must not include the product. A reference to the product (aka the ProductId) is ok.
If we build a really big graph of objects (a lot of different aggregates), then this may end up with a few more database access (each of which is slow)...What's your idea in here?
For reads, reports, and the like -- where you aren't going to be adding new events to the history -- one possible answer is to do the slow work in advance. An asynchronous process listens for writes in the event store, and then publishes those events to a bus. Subscribers build new versions of the reports when new events are observed, and cache the results. (search keyword: cqrs)
When a client asks for a report, you give them one out of the cache. All the work is done, so it's very quick.
For command handlers, the answer is more complicated. Business rules are supposed to be in the domain model, so having the command handler try to validate the command (as opposed to the domain model) is a bit broken.
The command handler can load the products to see what the state might look like, and pass that information to the aggregate with the command data, but it's not clear that's a good idea -- if the client is going to send a command to be run, and you need to flesh out the Order command with Product data, why not instead have the command add the product data to the command directly, and skip the middle man.
CommandHandler also can use this Product object to perform logic such as whether there are too many particular products, etc.
This example is a bit vague, but taking a guess: you are thinking about cases where you prevent an order from being placed if the available inventory is insufficient to fulfill the order.
For real world inventory - a physical book in a warehouse - that's probably the wrong approach to take. First, the model itself is wrong; if you want to know how much product is in the warehouse, you should be querying the warehouse, not the product. Second, a physical warehouse is not constrained by your model -- calling the addProduct method on a warehouse aggregate doesn't cause the product to magically appear there.
Third, it probably doesn't match very well with what your domain experts want anyway. If the model says that the warehouse doesn't have enough product, do you think the stake holders want the system to
tell the shopper to buy the product somewhere else, or...
accept the order, and contact the supplier for a new delivery.
Hint: when in doubt, carefully review how amazon.com does it.
I need some help in designing car booking application.
There is a document with information about car (title, model, brand, info, etc.)
Problems I'm stuck with are:
How to store available booking days? (I suppose I could use nested
free date range objects in array)
How to store price per day (it's possible to have individual price
per day)?
Booking days and prices could change often. So the third question is: "how to update them cleverly (partially), so I shouldn't read the document, and then store it". I'm looking at script solution using
update api (http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-update.html), but it looks ugly. Maybe there are other approaches?
Thanks,
Alex
with the introduction of the range datatypes, there is no need to use a real nested object, if you meant that.
That might also help you with storing the prices, but that could just be any object I suppose (it depends if you want to search for that as well).
Update API was made for exactly that use-case, that you do not need to get the whole document, so that shounds like a plan.
We are using Microsoft CRM 4.0 to run a consulting business. Its working pretty well but we want to simplify the way we are doing some things. What we want to do is create an Order (salesorder) with multiple Order Products (salesorderdetal). So good so far.
Next I want to be able associate each Order Product (salesorderdetail) with a Service Activity (serviceappointment), this representing that this billable line item in the order is actually going to be fulfilled as a consuting engagement.
The problem is, I can't seem to be able to create an association between the Order Product (salesorderdetail) and Service Activiy (serviceappointment). It simply doesn't appear in the drop downlist.
Can anyone think of a reason for this? I've seen some posts about relating field mapping between Quote Product, Order Product, Opportunity Product and Invoice Product, but that isn't quite what I am after.
Any suggestions gratefully received - even if it is an explaination of why its not possible.
I created a simple 1:N mapping from Case to Invoice. The Case records its ID and Title in custom fields in the Invoice. Unfortunately this does not allow for product creation as children of the Invoice, so that should be created as a custom code workflow.