views:

373

answers:

3

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.

A: 

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
Claus Thomsen
It is a Relationship, not a relation (which would be DB specific). The Relationship itself has properties (such as whether it is active, default settings and default office). A husband and wife can have a Relationship/Marriage that would be an object too (length of marriage, number of kids, etc.)
George Mauer
My point is that is it the relationship that is active/inactive or is it the customer. It woul make a much simpler model if those where attributes of customer instead of having a "meta data" entity between them
Claus Thomsen
It is the relationship that is inactive. That's what I'm saying by the Marriage example. If building a husband-wife domain it is reasonable for a Marriage to be an object. My SiteCustomerRelationship is an object in the same exact sense. There might be a different name for it later..
George Mauer
+1  A: 

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.

Chris Holmes
In my actual model it is called a Terminal (what the domain experts call it), I renamed it Site because I thought it would be LESS confusing. FAIL. You can think of it as a Branch Location of our company.
George Mauer
Renaming it as a contract would be ok except contracts are already entities in the system as they have a slightly different meaning to our users. This is honestly the best name I could come up with.
George Mauer
Gah! Its exactly the part that Udi glosses over in the second to last section that I need. Should I refactor to bounded contexts? I haven't read that part of the book yet!
George Mauer
Is the CustomerSiteRelationship an Account then? What are they doing at your site that makes the relationship necessary to capture in the model?
Chris Holmes
They store products at our Terminals. This might imply the presence of a contract (user sense of the word). Relationships can be enabled/disabled meaning the customer cannot store product there any more. There are also defaults set up for a customer-terminal and applied on transactions between them.
George Mauer
It looks more and more like a permission thing then. Analogous to Users-Permissions-Actions. In a user account scenario, there may be X security actions a user can take, and for each user they have a permission to that action. Here, your customers can store... or not (plus related metadata).
Chris Holmes
Hmm maybe, do you know somewhere where how to handle this is discussed in depth?
George Mauer
The DDD Group on Yahoo: http://tech.groups.yahoo.com/group/domaindrivendesign/messages
Chris Holmes
+2  A: 

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.

Vijay Patel