Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying DDD to Northwind database

I would like to do some exercice and apply DDD to my Domain Model applied to Northwind database. Even if Northwind is an example I imagine that it was done to satisfy some " virtual business" requirements. So the goal is to have a Domain Model that respects DDD and the data is stored in Northiwnd database.

Consider this EF persistance model :

alt text
(source: developpeur.org)

Notice that we have only the entities and two way relations. I would like to have a real DM which respects DDD. More, my DM model doesn't need to be the mirror of my database

  1. How you would change des relations to have only one way relations or two ways when needed.

  2. Are there any many-to-one or one-to-many relations that could be changed to one to one?

  3. How would you model agregates ?

  4. How about Values Objects, services and factories if needed ?

I know that probably I shoul look at business requirements and that look how the model should change but would like to have your advaice on that.

Don't hesitate to ask for details if my question is not clear.

Thanks in advance.

like image 316
Tomasz Jaskuλa Avatar asked Mar 04 '10 17:03

Tomasz Jaskuλa


1 Answers

In general I'm tempted to answer Mu (in the Zen sense), because the scenario is wrong from a DDD perspective. In DDD we start with business requirements and Domain experts and from those we derive a Domain Model.

Although it's a controversial point, the database is almost just an incidental artifact of the business requirements (that almost always state that Entities must be persisted).

That said, I'll try to do my best.

In most cases, an Order is a pretty important business object, and obviously we need to know about the order lines, including the Products in each line, so it would seem like we need the association from order line (Order_Detail) to Product.

However, when given a particular product, we rarely need to know in which orders it was included, so that suggests a one-way relationship right there. We can navigate from order line to product, but not from product to order lines.

However, the above analysis may turn out to be false on a deeper level. Imagine the following conversation between the developer and the domain expert:

Dev: We've created this association from orders to products so that we always know everything about the products in a particular order.

Exp: That sounds good, but what about the supplier?

Dev: That is included as well.

Exp: So what happens when we change the supplier for the product?

Dev: That will be implicitly reflected in the order data as well...

Exp: That's not what we want. We want the data to reflect the order at the time we shipped it.

In this case, it turns out that there's actually an error in the database schema. The problem may be caused by reporting, because business analysists may want to run reports on how different suppliers impact earnings (what do I know).

Such a case may suggest cutting the association from order lines to product altogether. Orders should hold historic (snapshot) product data, not current product data.

We may even entroduce a ProductSnapshot Value Object that semantically mirrors a Product Entity to model this in the Domain Model.

All in all, it seems more and more reasonable to model Order as an aggregate of itself and order lines (with ProductSnapShots), but what about the relationship between orders and customers?

As I currently understand associations and aggregates, associations define aggregates. Given an order, would we like to know about the customer? Most likely. Given a customer, would you like to know about the orders? Probably.

This suggests a two-way relationship, which makes Customer the Aggregate Root. This means that you would have a CustomerRepository, but no OrderRepository. Every time you need an Order, you must get it via a Customer.

In some cases this may make perfect sense, while this could be really clunky in other situations. It really depends on the business requirements...

You might consider creating an OrderRepository as well, but that invades the Customer Aggregate Root. If you do that, it becomes vague where the responsibility for the Order lies. What happens if you nagigate from Order to Customer? Customer has a list of Orders, but are they all populated in memory if you read the Order from the OrderRepository?

Probably not, but they are likely to be if you read the Customer from the CustomerRepository. The point here is that analysis of Aggregate Roots is important, and once you have defined an Aggregate, you will have to stick with it and respect it.

That causes me to favor small aggregates over big aggregates, so in this example, I would constrain the aggregate to Order and its order lines, and have no association between Order and Customer.

Not having a formal association between Order and Customer doesn't mean that we can't relate them at all, but we need explicit services to gives us all Orders for a given Customer. We can't just navigate from one to the other.

like image 160
Mark Seemann Avatar answered Oct 17 '22 04:10

Mark Seemann