This must have come up a gazillion times, but I just wanted clarity. Let's say we have an order with a number of line items. The user stories involve "create new order", "add item to order" and crucially "edit item in order". Before DDD I would have exposed the following DAO methods (on respective DAOs):
Order getOrder(Long id)
LineItem getLineItem(Long id)
and Order would have Order.getLineItems()
However, DDD introduces aggregate roots and the thing the customer cares about and views as atomic is the Order; the LineItem is clearly part of the composite Order. This implies that the aggregate root is the Order which means loading a LineItem directly is a no-no. The Repository would offer:
Order getOrder(Long id)
Fine, data persistence aside, I still need the ability to allow a client to edit a particular LineItem. You can imagine the Order screen:
a href="edit.html?id=lineItem.id"
The question is what is this ID? I thought IDs inside aggregate roots were invisible to the outside world, and I thought this level of manipulation of an AR's contents was a no-no. The quote "Nothing outside the Aggregate boundary can hold a reference to anything inside, except to the root Entity. The root Entity can hand references to the internal Entities to other objects, but they can only use them transiently (within a single method or block)." from the very useful "http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/05/15/domain-driven-design-supple-design-patterns-series.aspx" makes the use case of "edit a lineitem" really quite hard to implement :)
I can't believe the LineItem is an AR as that essentially means the pattern is "anything you want to handle independently is an AR" which seems bogus.
I know I need to read DDD by Eric Evans again :) but what are your thoughts?
Col
If this was possible to hold a reference to a Entity inside an Order:
LineItem li = aOrder.GetItem(itemid);
li.Qty = 30;
You would be changing the Order. If the Order had invariants over the number of items or price it would be more complex to enforce them.
Instead:
aOrder.GeItem(itemid, out description, out baseprice, out ...)
To change a line item:
aOrder.Change(itemid, description, baseprice, ......);
In other words, accessors return values (not entities) mutators receive values or aggregate roots (special entities).
Does that make sense?
Nuno
AR root = loadRoot()
Child child = root.getChild(childId) // child is "detached" or cloned
// update the child
root.updateChild(child)
Is that valid?
Col
Excerpts from Nuno Lopes's message of 2011-10-14 10:08:50 +0100:
However, even keeping it simple in the Order domain I can easily imagine the need for polymorphic line items - my order has three items, each item can be customised but the customisation is different depending on the line item.
To be explicit, I have an object which the domain considers atomic however it is a composite and there is a need to edit its constituent parts. These parts are non-trivial and aren't structurally identical therefore exposing the structure via a method on the root isn't possible. To make things even more complicated; those parts are actually designed by an external DSL which the client updates so the codebase doesn't even know the structure of the node ;).
For example, imagine the an instance of the DSL is:
--- start
pathway 1 starts with
node "a" and node "b"
when "a" and "b" finish then start node "c"
node "a" contains fields "field1" and "field2"
node "b" contains fields "field1" and "field3"
--- end
The "pathway" is the unit that the domain talks about however there is a need to edit individual nodes - editing nodea requires editing the default fields plus "field1" and "field2", editing node c requires editing the default fields. You can see how I couldn't possibly capture the structure of those nodes in public API on the Pathway object.
I can see an argument for saying the Node is an AR and Pathway is also a "super" AR but I don't know if that makes any sense in DDD....
Am I completely off base here?
Col
Excerpts from Jimmy Bogard's message of 2011-10-14 11:04:56 +0100:
Excerpts from Michael Brown's message of 2011-10-14 19:53:15 +0100:
Let's try to unpack it in a few problems:
1. Aggregates are about maintaining invariants, not about structure, so if there's no order level invariants depending on line item state you could have both order and line items as roots of different aggregates if both externally addressable.
2. If you have complex graphs inside an entity and need to make arbitrary changes on it which invariants are you maintaining? You may not even have (in this part of the system) enough behavior to justify using DDD. You could just do a simple transaction script over a graph library and get done with it.
3. If these changes require complex validation (i.e. aren't entirely arbitrary) and dictate more then structure (e.g. different changes have different effects in other system parts) then you may have a decent domain modeling problem. In such situations I prefer to model the changes as a DSL of value objects and have an apply command using an interpreter internally to process the DSL. Most of my tests and objects end up driven by the interpreter and the values (i.e. dsl fragments).