During my experience as a consultant, I usually come across domain models in which entities are so interconnected that my head begins to hurt just a minute after I'm trying to figure out where each aggregation symbol leads to, and often the source of all pain is the overuse of master-detail relationship.
An association in a domain model is something etheral, something that apart from its implementation, represent a logical connection between two or more abstract entities. It usually translates itself as a reference in a Object Oriented world and, for example, as a FK relationship between two tables in a relational database.
Now, let's consider a Bill - BillDetail relationship: no one would disagree if I modeled it with the following couple of classes, building a two ways master-detail association:
When we project it to a relational database schema, it becomes something like this:
Relational representation lacks a lot of the expressivity the object oriented paradigm provides: looking at the classes topology, we can explicitely see that one Bill instance holds a reference to a collection of BillDetails, and thanks to BillDetail.ParentBill property, we can walk that association in both directions while navigating the object graph; all those infos are only implicitely stored in the relational FK association.
In fact, what happens when we consider the Customer the bill belongs to? Let's start from DB schema this time, as most of us are (incorrectly) still used to do while designing a domain model:
Now, the inexperienced (but somehow smart) designer should feel that something's different between the two aforementioned examples, even though the relational representation is exactly the same: the association from a bill towards its customer is something we all agree with, but what about the mirrored association? Should we blindly equip our Customer entity with a Bills collection? Or should we simply ignore that side, perhaps providing a GetBillsByCustomer(..) service if we really need to walk from a customer to his bills?
There's a subtle differerence going on between these two examples, something that, once again, is not easy to infer if we're using the database schema as the starting point for our modeling process. A bill detail is something unuseful if taken away from its root; the "Bill" entity with all its details, encompasses the business concept of a real world "Bill". Using a DDD term, they are an Aggregate, whose root is the Bill itself. In that case, implementing a master detail relationship between the two makes a lot of sense, because you're always going to access each bill detail coming from the main Bill entity (you should never access directly each bill detail, according to what Eric Evans states in its Domain Driven Design book).
The relationship between Customer and its Bills now is clearly different! There's nothing bad on directly referencing a Bill, without coming from the Customer, actually a Bill makes a lot of sense (and has a huge business meaning) even though we don't even take care of which customer it belongs to! in other words, Customer and its Bills are not an aggregate.
Why we should avoid master-detail relationship between the two? Because associations are cool, but don't come for free: they have a great cost in terms of complexity and performance, even though we can leverage some ORM to limit the impact on the application. What could be the purpose of a "Bills" property into the Customer class? Even if we suppose to lazy load it, simply accessing it would trigger a query for every bill he has, regardless of the period, of its paying status, and so on. Does it have a business meaning? I don't think so, but that wrong design choice makes us paying its cost anyway.
In other words, a good rule of thumb is: if it's not an aggregate, limit the cohesion and try to avoid master-detail relationships because they are expensive.
I hope many of you agree with that.
