views:

95

answers:

3

Hi - I am new to Domain Modelling so forgive me for asking a couple of elementary questions. My first question is about knowing when to model domain relationships. I find sometimes I feel like all classes appear to be related in some way to most others and I am unclear about when I should model these relationships directly (by holding a reference in one class to another).

For example, say I have a Person class that is related to a collection of Orders and each Order is related to a collection of Products (forgive the unimaginative example). Each od these entities had a corresponding table in the database. If I am writing some client logic that deals with the Products that a Person is associated with (through that persons orders) it seems temping to have a Person.Products collection, especially as I could craft some SQL to get this collection without the need to pull back the Persons Orders collection. Is this OK or bad design? If what would be the better way to handle this?

Secondly, what about situations where relationships are contextual in nature? Continuing with the previous example say that some business logic that I want to run in a person method needs to deal with all of the Person's associated Orders that contain a specific Product (i.e. a subset of the Person's Orders collection). I can construct some SQL that will return exactly this subset very easily. The question is where do I expose the results? Should I put a method on Person that takes a Product parameter and returns the Orders collection so that client code looks like this?

person.OrdersContaining(Product p)

Should entities have multiple methods like this to expose different subsets of their relationships or should a Person just have a single Orders collection and subsets be handled in some other way?

Thanks

A: 

If I am writing some client logic that deals with the Products that a Person is associated with (through that persons orders) it seems temping to have a Person.Products collection, especially as I could craft some SQL to get this collection without the need to pull back the Persons Orders collection. Is this OK or bad design? If what would be the better way to handle this?

Each first-class relationship you encode in your software makes a statement about your design intentions and your understanding of how the entities fit together. Inextricably linking People and Products that way might be considered less than optimal, since every time you get a Person, you also get their Products. That implies a relationship between People and Products that may not actually be present.

Should entities have multiple methods like this to expose different subsets of their relationships or should a Person just have a single Orders collection and subsets be handled in some other way?

I'd probably prefer an OrderService that could handle this kind of thing rather than putting it on the entity -- it would have methods like List<Order> OrdersForPerson(Person p), and so on. In some frameworks it's more idiomatic to put it on the entity, though -- Rails's ActiveRecord comes to mind here.

John Feminella
+2  A: 

I see two questions under discussion here:

People --- Order

and

People --- Order --- Product

1). Should we expose both People.getOrders() and Order.getOrdersForPerson(p)?

2). Should we expose People.getProductsOrdered()?

Instinctively, after doing OO things for many years, I would say "no" to both questions. But can I justify that? What heuristics would guide us? Some suggestions:

a). Fewer is better. Every method costs. Develpment time, testing effort, documentation. The more methods you have the harder it is to find the one you want.

b). Single Responsibilities. If we accept that exposing both People.getOrders() and Order.getOrdersForPerson(p) os overkill, which object is really responsible for the People-Order relationship. I would say it's the nature of Orders to relate the Orderer, hence Order should own the relationship.

c). Decoupling. Busy people order many things. You probably end up have a quialified getOrders() method, taking additional criteria such as when ordered, or order size. To expose that you use attributes of orders. So People.getOrders(criteria) is now expressed in terms of the detail of the order contents. If you change Order, you need to change People. Coupling is bad! This point addresses the Product question. It's clear that Orders intrinsically need to know about Products and have some level of coupling to them. People do not have that intrinsic relationship, hence don't couple them to Products.

d). Scale. People do many things. They don't just place orders. Would you expect to change the People class for each new thing they do? Add People.getTrips() People.getExpenseReimbursements(), People.getHeathCareClaims(). Surely not.

Don't fall for the "oh it's easy to implement in SQL" argument, at this level of discussion we're more concerned about devising good interfaces and getting a clean separation of resposibilities.

djna
+1  A: 

All relationships are contextual.

If a user requests that you provide a list of products that a person has purchased, they have defined a context in which a Person is associated with Product. Without a context, there are no relationships.

There is a common misconception that there is one domain model for an application. This couldn't be further from the truth. In principle, there is a different domain model for every feature.

You should approach each feature as if it’s the only feature the system is going to support. Treat existing code as reuse opportunities; no more, no less. And DRY things up with relentless Refactoring.

Doug Knesek
Very true. There are no right models, only useful ones.
CesarGon