What's the criteria for defining an aggregate ?
Let's go back to the basics of the big blue book:
Aggregate: A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are
restricted to one member of the AGGREGATE, designated as the root. A
set of consistency rules applies within the AGGREGATE’S boundaries.
The goal is to maintain the invariants. But it's also to manage properly local identity, i.e. the identify of objects which do not have a meaning alone.
Order
and Order line
definitively belong to such a cluster. For example:
- Delete an
Order
, will require deletion of all its lines.
- Deleting a line might require renumbering of the following lines
- Adding a new line would require to determine the line nulber based on all the other lines of the same order.
- Changing some order information, such as for example the currency, might affect the meaning of the price in the line items (or require to recalculate the prices).
So here the full aggregate is required to ensure consistency rules and invariants.
When to stop ?
Now, you describe some business rules, and argue that to ensure them, you'd need to consider the customer as part of the aggregate:
We have a business rule saying that a Customer can only have one
undelivered order at a time.
Of course, why not. Let's see the implications: the order would always be accessed via the customer. Is this real life ? When workers are filling the boxes for delivering the order, will they need to read the customer bar code and the order barcode to access the order ? In fact, in general, the identity of an Order is global not local to a customer, and this relative independence suggests to keep him outside the aggregate.
In addition, these business rules look more as policies: it's an arbitrary decision of the company to run their process with these rules. If the rules are not respected, the boss might be unhappy, but the data is not really inconsistent. And moreover, overnight "per customer one undelivered order at a time" could become "ten undelivered orders per customer" or even "independently of the customer, hundred undelivered orders per warehouse", so that the aggregate might no longer be justified.
I have an AR and I can't figure out the best way to create/edit some of the complex aggregates contained in it.
Caution: your spelling is off. AR don't contain aggregates, the naming is the other way around.
An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary.
Conceptually, the aggregate is a graph of (possibly complex) entities, with the aggregate root being one of those entities in the graph.
Also: value objects are usually immutable - you shouldn't have setters.
So when I go to add my CRUD methods to the Aggregate Root Load, I'm lost on how best to achieve this goal. I could add the following, but it doesn't seem like the DDD way to solve this problem because outside of the domain should not know what Run is right?
There are a couple possible answers to the riddle.
In this model, you seem to have a lot of properties that you need to reference to get anything done. So something like a http message that describes a change is going to have a complicated json document.
One way to turn that document into something that the model understands is to use a builder pattern. You give the application little mini factories to build up the data structures that it needs to talk to the model. That's a perfectly reasonable thing to do.
Another possible answer is to examine your model more carefully; domain models are primarily about change; they aren't glorified document stores. Information that the model doesn't need should be stored in a document somewhere else. For example, if a Run is a response to an "Order", then the Run might have a copy of the order number and a copy of the data that it actually needs to do its work, but not everything else.
(In the same vein: if you have a CustomerId in your value, you probably don't also need a Customer value. Use the id to look up the details you don't normally use.)
Unfortunately most of the Run information will be needed by the model.
If that's so, then it is, and you'll have to manage it. But push back on that assumption -- if you confuse the data you need to make a decision with the data you need to create a view, you are going to end up making more work for yourself.
Would the factories go in the domain layer?
It's a reasonable first guess - we usually start out with an assumption of one implicit collection of agnostic primitives (whatever language we happen to be coding in at the time). Evans coupled aggregates, repositories, and factories together in chapter 6 of the blue book, considering them all to be part of the domain layer.
I think it's a bit more correct to think of these factories as part of an adapter that allows the application to communicate with the model.
Best Answer
In such situations, I'd ask myself if the business logic or model is right, not what I've implemented or what is best for software. One other thing that is important for Aggregate and DDD is ubiquitous language and implementation as business logic dictates, not what is best in software sense. So stuff like copy/paste in DDD is allowed (of course, this is a broad subject and should not be taken literary).
What puzzles me is the following sentence:
You say that product is created based on information that are entered with the image. So, a user enters an image and some information about it and based on these information you create products. As I understood, Asset is not based on products but on informations contained in images. Also, I don't really think that products don't share the same information or images. Therefore it's more of a many to many relation based on information and, probably, information can be interconnected with multiple images.
Like you said, aggregates define transactional boundary. In that case you can ask yourself a business logic question (irrelevant of how you've implemented it)
If the answer is yes, ask yourself if the model is right, have you really implemented the model according to business logic. Go to the roots, the business logic defined by domain expert and business folks, not what is currently implemented.