You are right, real ERP systems works this way. I have faced this
model few months ago when consulting new system. After 3 days of
deliberating we all agreed that "order line" (actually it's not so
simple) is an AggregateRoot. Lots of domain logic was centered around
"order line".
But we did not want to introduce so complex model to this leaven
because purpose is different - education.
I guess that case You describing should be modeled in this way -
because manipulating entity without knowledge of aggregate simply
causes inconsistent state of aggregate and entity.
> I think that solution is simple.
> Remove BaseAggregateRoot and instead of it i propose to add interface
> Aggregate with operations that aggregate should implement.I see right now 1
> obligatory method: isRoot().
> So isRoot in some cases could return true in some cases false.
I don't quite understand...
So some aggregates are roots and some don't?
I guess that OrderLine should also implement Aggregate interface at
second diagram...
If thats correct... hmmm... this is not simple at all i'm afraid.
While implementing Order I don't know if somebody decide to aggregate
it in his aggregate.
In general we have leaky abstraction. Implementing aggregate (i
understand it as a microcosmos) i need to know if this aggregate is
inside other or not - can I even know?
And what for would we need to have this information - is root or not?
Also I don't want to extend "canonical" patterns language form the
Eric's "blue book" - it will be hard to explain to people.
Besides: having interface You probably end implementing base class
(which still be good OO if You respect Liskov SP) to provide: events
engine, event souring if You want, ect.
I understand interface as a pure abstraction (contract). There is
nothing abstract in Aggregates, they are concrete as hell ("jak w
mordę strzelił" in polish:)
1. I'll start at saying that I don't like this *Aware convention.
I used it few years ago and it was great that time (btw: It's also
used in Spring. So if Spring guys goes some way tat means way is not
bad:)
But now, while having annotations I consider it obsolete. Spring also
support all *Aware stuff in the new way using annotations.
2. There is definitely no "is a" relation between VO and
entity/aggregate, so inheritance is not justified. Intention of
existence VO and Entity is totally different.
3. Versionable... version is just a technical stuff and I assume that
for now there is no need to getVersion.
4. Indetificable... hmm it could be useful in some generic
machinery... potentially could be... I'm just afraid of forcing people
to pollute their "precious" model by implementing leaven stuff;)
At beginning I would like to say that base classes are not core
concepts of design. Modeler should focus on capturing domain, base
classes are minor problem in this context. We have just introduced
Base Entity/Aggregate and Repo just to make development more
comfortable.
This is very important that we don't want to force people to extends
"esoteric" classes. It must be possible to implement own VO/A/E
without extending any our classes and everything should work just
fine. I personally hate frameworks that force me to extend some base
classes. I just know that sooner or later I'll figure out that
something is f*cked up in their design;P While talking with friends -
most of them feels the same.
So... assuming that we want to provide convenient base
classes/interfaces and some people may find them usable:
0. golden rule is Liskov Substitution Principle. Wiki description is
quite autistic for me:
http://en.wikipedia.org/wiki/Liskov_substitution_principle
Simple interpretation is: use inheritance only if You will use polymorphism.
In current design Base A/E Classes are polymorphicaly used by Base
Repo. Base repo is polymorphicaly used on Aggregates. So inheritance
makes sense, because is used for something in this self-adoring island
of base classes;)
Our discussion can be generalized to the following problem: what if
one aggregate need to reference another?
There is orthodox solution in DDD that says: no problem, but only if
one Aggregate contains ID of another. Not an object but only ID that
can be used for loading one using repo.
What do You gentlemen think about that?
If the aggregate roots are located in the single bounded context, the reference should be allowed. For sure, don't define any cascading for this association. I don't understand why do I need additional lookup by the entity identifier if I want traverse to another aggregate root in the same BC.It gives you database referential integrity checking for free. If for performance reason, you don't want use object traversal, expose only "getReferenceId" like public method. But JPA mapping should still be defined based on reference.If the aggregate roots are located in different bounded context, strong reference does not make sense. Use ID then.