I appreciate a straight forward answer.
Scenario 1: I need to display product information.
Product Service (PS) : Holds information about products
Pricing Service (XS) : Holds pricing information of each product
Aggregator service (AS) : Combines both product info and price.
Question: 'AS' make a call to 'PS'(With product ID) to get product info. Now, how does 'AS' fetch that specific product price, from the 'XS'?
The confusion here is, does PS Table have a DB column with ID to corresponding price in XS Table? Can we call it a foreign key? If so, does it introduce tight coupling between two services? Which is against principles of micro services.
Well you may call that field as a "foreign key" but as long as you don't enforce any constraint on it then it should be fine.
From my view it is just a reference. It doesn't bring any tight coupling it provides some binding. Which is totally fine as far as microservices architecture concerned. If you think about a little bit broader in terms of possible implementation you may see that for example you can use a totally different database like relational one for pricing service and maybe
a document database for product service. And in that case it would be more clear that what you called as "foreign key" is just the reference for the actual record.
Having said that I may still question your solution like
Why do you need a separate Aggregator service instead of directly using Product service?
And same way why do you want to have a separate Pricing Service
Would it be better if you keep the reference to product on pricing service than keeping the reference to price on product service?
But anyway foreign key part is just fine from my point of view.
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.
In the context of a Microservice architecture, a single business operation can require collaboration between two or more services.
Suppose we have an Order Management Service and a Product Catalog Service.
When the user adds an order item to an order, the Order Management Service will persist a OrderItem object which have the following attributes among many others :
OrderItem
+ Id
+ ProductId
+ ProductName
In order for the Order Management Service to fill the ProductName attribute, we have 4 choices as I see it :
Choice 1 : ProductName is given by the client app as it probably already has this data from previous requests
Choice 2 : If the architecture uses an Api Gateway, the gateway will be responsible for retrieving the ProductName from the Product Catalog Service then provide it to the Order Management Service.
Choice 3 : The Order Management Service will call directly the Product Catalog Service and asks him for the ProductName givent a product id.
Choice 4 : The Order Management Service has a duplicate (but not exhaustive) product informations in its own database and these datas will be updated each time an update event is received from the Product Catalog Service.
Among these 4 choices, the n°1 seems not ok to me as we can't trust the client to give us a correct and updated value of ProductName.
I would like to have your opinion about what you think the best choice is and why !
Thanks !
Riana
Choice 1 : ProductName is given by the client app as it probably already has this data from previous requests
Like you said, it is not the best idea because the client may have stale information. Maybe acceptable if the product information changes infrequently and/or you have a secondary verification at order processing.
Choice 2 : If the architecture uses an Api Gateway, the gateway will be responsible for retrieving the ProductName from the Product Catalog Service then provide it to the Order Management Service.
IMHO, this is not a good idea. By doing so your domain/business logic will leak into the API Gateway. The gateway now knows the relationship between Orders and Products. This API gateway configuration/scripting will need to be maintained and introduces additional coupling.
Choice 3 : The Order Management Service will call directly the Product Catalog Service and asks him for the ProductName givent a product id.
This is my preferred choice. Though I do not recommend "direct" synchronous calls. Perhaps a retrieval of the ProductName via a messaging mechanism (message queue, event bus). Chained synchronous calls will reduce the availability of your services. You can find more information at Microservice Messaging Pattern.
Choice 4 : The Order Management Service has a duplicate (but not exhaustive) product informations in its own database and these datas will be updated each time an update event is received from the Product Catalog Service.
Data duplication is generally frowned upon unless there is a really good reason for it. In this case I don't see any. Why bother splitting the databases into two for each of the services yet duplicate the data between them? Also, to have the data updated each time an update event is received indicates that some kind of event/messaging infrastructure is available, in that case, why not just use messaging?
This duplication may be justifiable for high volume, low latency look ups, but it is a slippery slope that may end up with duplicated data all over your services. Imagine the repercussions of a length or type/format change of the ProductName string...
I want to use the many to one and other DB Relationship in micro-service architecture. In monolithic architecture we can create the entity relationship easily as they belongs to same project but in micro-service architecture how we can achieve the same.
Example:
There is one userDeatil service and other is productDetail service.Now there is third service called orderDetail and an order will have userID and ProductIDs associated with it. So how can we manage the relationship between 'user and order' and 'order and product'.
I have searched over net but didn't able to get the fair idea.There is another thread having same query but not having the clear answer. Link
In my opinion your case is about how you specify your services especially how you define the bounded context of each service !!
According to the situation above-mentioned I don't see any reason why the product service should know anythings about orders (even if it s just the order-id) and backwards. One more problem I see in this case: your services will not work if one service is not available (E.g when the product service it not online, your order service will not be able to work, because he needs the product details from the product service...).
I Think you should rethink the bounded contexts of your microservices. You should keep in mind:
ensure a loose coupling of the microservices
a microservice has always to work even other Microservices are not available (Resilience / Reliability).
The DDD (domain-driven-design) paradigm with its tools provides her a great help to assist you, during the definition process of your services, you encourage these qualities.
So, the following is JUST an idea (it s not a recommendation and you should review whether it matters for your business case) :
It seems like the "order" process is your core business domain. So you have to focus on it.
The user service (i hope you mean here the customer and not a user in terms of authentication/authorization) has only the responsibility to manage the customers, and may be their adresses, bank-Accountings etc.. It should not know anything about your orders or products.
The same is valid for the product service. It owns only data about products. It has no relation either to the customer nor to the order-service.
The order service by itself deals only with orders and should own only data that belong to an order (like ship Adress and some information about the product-items ordered). I think the customer-Id is also important here to keep the relation between the order and the customer. This way you can e.g get all orders made by a certain customer-id....
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.
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.