Is there some rule of thumb, in which direction to make the association when designing domain model?
For example, we have products in the stock. Stock status of a product is a rather complex data structure, containing enumerations of multiple variations of the product either being in the stock, being out of stock or being bookable. Thus we make a seperate object of the stock status associated with the product. Now the question is, if product object should have a reference to it's stock status, or stock status have a reference to a particular product.
First solution feels like, it's not the real concern of product knowing it's stock state. Product is just a product, and maybe we should manipulate them in different context, where stocking is not a concern. In the other hand, stock status being a root feels awkward, as when thinking about stock, first we think about a product being in the stock.
How to decide, which entity acts as a root for the association?
You are assuming that both concepts are tightly coupled, meaning, they belong to the same bounded context. This means both models become dependent on each other - which may be something you don't want because it causes complexity you may not want. After all, you mentioned it yourself: "it's not the real concern of product knowing it's stock state". So why add a relation to it?
You could consider them as two separate bounded contexts - no direct relation between them, except for the product ID which links the two concepts.
Navigability is something you should simply neglect as it is something purely artificial. If two things are related, they know about each other. Actio et reactio. Gravity. Love. Try hard to find something that works only in one direction. Blackmail. Spy mirrors.
Introducing navigability indeed has only meaning in implementation phase. You try to decouple things in order to reduce dependencies, now for good. And what you actually do here is to attach role names towards the navigation. Which in turn makes the arrows superfluous.
TL;DR; Just don't use arrows in UML modeling. Leave them for the Powerpoint League.
First solution feels like, it's not the real concern of product knowing it's stock state. Product is just a product, and maybe we should manipulate them in different context, where stocking is not a concern. In the other hand, stock status being a root feels awkward, as when thinking about stock, first we think about a product being in the stock.
When we think about shopping carts, we think about products in the shopping cart. Yet most of the time, the useful way to model cart items is with a reference back to the product.
My guess would be that you need to be thinking more about Stock, and in particular about its life cycle; how tightly coupled are the lifetimes of the two different ideas? If you have a situation where a single Product has a relation to two different Stocks (one in the past, one in the present; one at this location, another at that location), then storing that relationship in the product isn't right.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am trying to design a database that would be able to keep track of orders, and tracking information with as little repetition as possible. I own a company that gets products from multiple retailers that send the products to the customers directly. So for each order, there will be multiple products and multiple tracking links.
Here is the design of the db thus far:
This still is slightly repetitive because each order will have multiple rows in the order details and tracking tables. I was just wondering if there were smarter ways to go about designing this. Is this as normalized as possible?
Thanks
What I don't understand from your model are the business rules between tracking_details and order_details. Your model shows that tracking_item and product both have a retailer. So I might guess that there is a one-to-one relationship between tracking_details and order_details. It is a very good idea to list out such business rules and draw a diagram that spells them out.
Here is a model in UML notation I did a while ago. From what I can tell if you rename Contract to order in my diagram is pretty much equivalent to your model. My diagram tries to capture things like the business rules between what is in the things in the order (I called them LineItem, you called them order_details) and how it is shipped (I called them Delivery and you called them tracking_details):
I use the free online tool umletino to draw that UML diagram.
To really understand the business rules you need them to be explicitly spelt out. For example, the business rules of my model are:
A contract has many lineitems
A contract has many deliveries
A delivery to a location contains one or many lineitems
A lineitem is a quantity of a given product within a contract
A lineitem can only be in zero or one deliveries
Altering the lineitems within a contract updates the total cost of a contract
There are some other things in that high-level UML model. The black triangles imply 'aggregation' or 'ownership'. So the diagram indicates that the Contract (you called it order) controls the life-cycle of the items it owns below it. The implies that if I delete the order I will also delete it's Deliveries (you called those tracking_details) and it's LineItems (you called those order_details).
An additional facet of the UML diagram is that it marks some tables as <<Root Entity>>. This is a concept that is basically about how not to corrupt your database model. In my model the total cost of the contract/order must equal the sum of the costs of the order_details/lineitems. Yet I could write buggy code that screws things up. I could add or update lineitems/order_details and forget to update the total cost on the order table. The big idea of root entities is that you don't have code that just writes data behind the back of the order. The code that controls the order is responsible for updating the total quality and doing the insert/update/delete of the LineItems/order_details. That single code path ensures that the total quantity of the order always matches the sum of the LineItems/order_details within the database. The Product is also marked as a root entity and it might control it's own set of aggregate entities which are not shown on that diagram which is focusing on documenting only Contract/order.
In summary, I don't see any duplication in your model. If I was working on your project what I would like to see alongside the relational model are the business rules and ideas of how to organise code to help avoid corrupting the model or breaking the business rules. I would also like to understand the lifecycle of the things in your model such as aggregation. I encourage you to list out your business rules like I listed out mine above. Then try to draw a diagram (try that free tool at the link above) that captures all of the business rules. We call that a logical model. Then make the physical data model. (Warning: I wouldn't advise going crazy with UML only use enough to capture the key business ideas.)
To implement the physical model I needed one more table than implied by boxes in the UML. I needed a join table between delivery/tracking_details and the lineitems/order_details. That table would capture which delivery/tracking_detail was tracking which things within the order. If you list out the business rules and read through them it helps you uncover such details. My model says that a lineitem/order_detail can only be in one delivery. That business rule cannot be enforce with something like a foreign key constraint. Instead the single code path of my root entity ensure that all of the business rules around orders are checked in one place then unit tested logic would update all the associated tables. If you are using an OO language then that code would be in your Contract/order class. Other classes representing other root entities such as Product would enforce their own business rules and manage their own tables.
Your data model is reasonable as far as it goes. However, I do note that TrackingDetails and OrderDetails are both at the OrderId/ProductId levels.
That suggests that TrackingDetails should really have an OrderDetailsId instead of the OrderId and ProductId.
That said, I don't know if this is reasonable from a business perspective. OrderDetails doesn't have a "quantity", so I don't know if that is an oversight or if multiple products are different rows. Also, I don't know if a quantity of more than 1 could have split tracking information. That is, someone orders 100 foos, only 50 are in stock so 50 are shipped today and 50 next week.
which form is a correct OO design?
"Matter of taste" is a mediocre's easy way out.
Any good reads on the subject?
I want a conclusive prove one way or the other.
EDIT: I know which answer is correct (wink!). What I really want is to see any arguments in support of the former form (order.fill(warehouse)).
There is no conclusive proof and to a certain extent it is a matter of taste. OO is not science - it is art. It also depends on the domain, overall software structure, etc. and so your small example cannot be extrapolated to any OO problem.
However, here is my take based on your information:
Warehouses store things. They don't fill orders. Orders request things. They don't know which warehouse (or warehouses) the things come from. So a dependency in either direction between the two does not feel right.
In the real world, and the software, something would be a mediator between the two. #themel indicated the same in the comment to your question, though I prefer something less programming pattern sounding. Perhaps something like:
ShippingPlan plan = shippingPlanner.fill(order).from(warehouses).ship();
However, it is a matter of taste :-)
In its simplest form warehouse is an inventory storage place.
But it also would be correct to view a warehouse as a facility comprised of storage space, personal, shipping docks etc. If you assume that view of a warehouse then it would be appropriate to say that a warehouse (as a facility) can be charged with filling out orders, or in expanded form:
a warehouse facility is capable of assembling a shipment according to a given specification (an order)
above is a justification (if not proof) for: warehouse.fill(order); form. Notice that this form substantially equivalent to SingleShot's and themel's suggestions. The trick is to consolidate shippingPlanner (an order fulfillment authority) and a warehouse (a inventory storage space). Simply put in my example warehouse is a composition of an order fulfillment authority and an inventory storage space and in SingleShot's those two are presented separately. It means that if such consolidation is (or becomes) unacceptable (for example due to complexity of the parts), then the warehouse can be decomposed into these two sub components.
I can not come up with a justification for assigning fill operation to an order object.
hello? warehouse? yes, please take this order and fill it. thank you. -- that I can understand.
hey, order! the warehouse is over there. do your thing and get fulfill yourself. -- makes no sense to me.
When using an ORM, is it breaking some kind of good practice to have a model class with a few non-persistent properties, which are only used for calculations, and then can be safely dropped?
Let's say we have a Product. This Product has list of possible Options. An Option may have a price impact on the Product. We also have a set of Rules, which say that when one Option is selected, then the price of another Option changes.
When we add a Product to an Order, along with a selection of Options, we first need to recalculate the price of all the Options based on the rules affecting each selected Option. Then we can calculate the final price of the Product with all its selected Options.
In this example, the Option could have a calculatedPrice property, which would only have meaning within the context of the selected Options, and could be safely dropped after the Product has been added to the Order.
Is there a more correct way to think about this problem, or is that ok?
Yes, it is perfectly fine to have #Transient properties.
Some people may consider it wrong and insist on having a separate class that is almost the same as the entity, but having the additional fields, but that is unnecessary code duplication. Your approach is what I'd do.
The other approach, which is used in a large and ghastly e-commerce system i work with, is to have a parallel structure of transient objects containing the computed information. So, in parallel to the Order, there is an OrderPrice. For each Item in the order, there is an ItemPrice. If an Item has a set of Options, then the ItemPrice will have a set of OptionPrices. The Order's ShippingOption also has a ShippingPrice, and so on. Pricing is then handled by another parallel structure of price calculators - you give an Order to an OrderPriceCalculator, and it gives you back an OrderPrice. In doing so, it will send each Item to the ItemPriceCalculator, which will send each Option to the OptionPriceCalculator, and so on.
The price objects can refer to the order objects, but not vice versa. Our system does actually persist the prices, but separately from the orders.
The advantage of this is that it separates the concerns of describing the contents of an order, describing the price of an order, and calculating the price of an order.
The disadvantage is that you have a huge number of classes, and the information you need is, inevitably, never in the objects you have to hand.
The disadvantage probably outweighs the advantage.
Update Edited to reflect clarifications requested by Chris Holmes below. Originally I was referring to a Terminal as a Site but changed it to better reflect my actual domain.
At heart, I think this is a question about modeling a many to many relationship between two root entities where the relationship itself carries some semantic meaning.
In my domain
You can think of a Terminal as a branch location of our company
A Terminal can have a relationship with any number of customers
A customer can have a relationship with any number of terminals (standard many to many)
A customer\terminal relationship means that a customer can potentially store products at the Terminal
This relationship can be enabled\disabled. To be disabled merely means you are temporarily not allowed to store product, so a disabled relationship is different from no relationship at all.
A customer can have many Offices
A Terminal that has a relationship with a customer (enabled or not) must have a default office for that customer that they communicate with
There are some default settings that are applied to all transactions between a Customer and a Terminal, these are set up on a Terminal-Customer Relationship level
I think my objects here are pretty clear, Terminal, Customer, Office, and TerminalCustomerRelationship (since there is information being stored specifically about the relationship such as whether it is enabled, default office, ad default settings). Through multiple refactorings I have determined that both Terminal and Customer should probably be aggregate roots. This leaves me with the question of how to design my TerminalCustomerRelationship object to relate the two.
I suppose I could make the traversal from Terminal to TerminalCustomerRelationship unidirectional toward the relationship but I don't know how to break the relation from the relationship to the customer, especially since it needs to contain a reference to an Office which has a relationship to a Customer.
I'm new to this stuff and while most of DDD makes perfect sense I'm getting confused and need a fresh outlook. Can someone give me their opinion on how to deal with this situation?
Please note that I say Relationship not relation. In my current view it deserves to be an object in the same way that a Marriage would be an object in an application for a wedding chapel. Its most visible purpose is that it relates two objects, but it has other properties that rightfully belong to it as well.
By your description, you definitely need a "TerminalCustomerRelationship" entity to track the associated information. I would also convert the 'IsEnabled' flag into a first class 'Event' entity with a timestamp - this gives you the ability to save a history of the state changes (a more realistic view of what's happening in the domain.)
Here's a sample application (in VS2008) that refects your problem. You can tweak/test the code until the relationships make sense. Run "bin/debug/TerminalSampleApp.exe" and right-click "Terminal->Create Example" to get started.
Let me know if you find it useful.
Names can often clarify an object's responsibilities and bring a domain model into focus.
I am unclear what a Site is and that makes the entire model confusing, which makes it difficult for me to offer better advice. If a Site were a Vendor, for instance, then it would be easy to rename SiteCustomerRelationship as a Contract. In that context it makes perfect sense for Contract to be its own entity, and have the the model look like Vendor-Contract-Customer-Office.
There are other ways to look at this as well. Udi has a decent post on this sort of many-to-many relationship here.
You should not have a object Like SiteCustomerRelationship, its DB specific.
If its truly DDD you should have a Relation like:
Aggregate<Site> Customer.Site
IEnumerable<Aggregate<Office>> Customer.Offices
and perhaps
Aggregate<Office> Customer.DefaultOffice
I am working on car dealership business domain model/UML class diagram.
I am new to modeling, so I would like to know how to validate the class diagram. It's very important for me to have an appropriate, if not 100 percent correct, class diagram to use further development (use cases, etc.).
Is it possible to build a completely incorrect model? Or are there only appropriate and less appropriate models?
If I have a Customer associated with SalesTeam modeling a customer being served by SalesTeam, is that wrong? I have seen in examples of Customer being associated with Order, Order with ItemOrder and ItemOrder with ItemInventory. Where the SalesTeam or Staff is associated with Order.
How do I validate my model and relationships?
To validate domain models, do the following.
Write use cases. During the writing, make sure you're using nouns and verbs in a consistent way. To be sure that your nouns make sense, be sure to record notes in the domain model.
Walk through each use case, following along on your domain model. At the entities there? Relationships required for navigation? Attributes of each entity?
Since it's a domain model, try to avoid describing things as classes -- they're usually real-world entities.
For example "customer entity in direct relationship with sales team entity" is something you'll learn from the use cases. For example, customers are associated with orders, but the order is created by the sales team. So, you have two navigation paths between customer and order: direct and via the sales team. Both appear (to me) to be true.
You must compare your domain model with your use cases to be sure both agree.
The short answer is that this is not very important.
Use your domain class diagrams to keep a note of what you think is in the domain, that is all. It is not your god, and it will not hurt you to change it as you go.
Domain experts should help you to validate the domain model.
As far as validating the specific relationships, as you develop the model further and investigate the collaborations between objects you will discover more and different relationships. You will need to revisit the domain model often during your analysis and development.
I don't think it matters that it's 'correct' up front (i.e. before you move onto looking at use cases and further analysis), only that it is useful - it gives you a conceptual model of the problem and what the main classes involved are. It isn't going to be finished until the software is no longer being developed or maintained.
If it represents the way you view the problem right now, it's good enough for you to start further analysis. Revise it as your view of the problem changes and you learn more.