IMPORTANT - Suggested changes

44 views
Skip to first unread message

Sławek Sobótka

unread,
Sep 2, 2011, 9:49:56 AM9/2/11
to ddd-cqrs-sample
This thread is dedicated to changes that are critical (ex form the
conceptual point of view) and need to be discussed in wide forum.

So first things:

1. BaseEntity - optimistic locking of Entities
- remove filed:

@Version
private Long version

and add to to the BaseAggregateRoot
because Aggregate should be responsible for locking as a natural Unit
of Change in DDD.



2. Entities - should be always aggregated in Aggregates and never live
"free"?
previous change leads to concern: what about versioning Entities that
are not part of any Aggrgeate - live free as a "blue birds"?

suggested solution: by convention there should not exist. Promote this
kind of artifacts to Aggregates - even if does not contain any
aggregated object (actually being hermetical they can expand in future
with no harm)

Maciej Hadam

unread,
Sep 2, 2011, 5:22:30 PM9/2/11
to ddd-cqr...@googlegroups.com
I thnink that current design of enitity and aggregate is not clear.
Let's analyze the order-orderline example.
Why, moving version property to aggregate, we are deciding that orderline will not never gona have version property.
Maybe in the future some guy would think: Why i should always fill the same orderline on every new order.
And developer would prepare for him templates with orderlines. From this moment the state of the orderline in some cases wouldn't depend on order existance.

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've modelled that soultions on diagrams (i'm not sure if they will be properly displayed in group).




aggregate before.png
aggregate after the change.png

Sławomir Sobótka

unread,
Sep 3, 2011, 7:36:47 AM9/3/11
to ddd-cqr...@googlegroups.com
> I thnink that current design of enitity and aggregate is not clear.
> Let's analyze the order-orderline example.
> Why, moving version property to aggregate, we are deciding that orderline
> will not never gona have version property.
> Maybe in the future some guy would think: Why i should always fill the same
> orderline on every new order.
> And developer would prepare for him templates with orderlines. From this
> moment the state of the orderline in some cases wouldn't depend on order
> existance.

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:)

Maciej Hadam

unread,
Sep 4, 2011, 4:41:05 PM9/4/11
to ddd-cqr...@googlegroups.com
Yes, yeah, hmm ..;)

1. Yes. The orderLine should be an aggregateRoot only if the use cases requires it.
2. Is root method ... This was starting point to thinking about complex cases where we have many aggretate roots (removed in current diagram)
3. Yes. Of course base/asbtract class is in the current version of diagram. My thinking was drived by rule described by sentence: to change entity into aggregateRoot we have to add to him some ability(like versioning). There was a conflct in my mind (source from nature): why to add new ability to object i have to change his parent ;).

In attachment there is new diagram based on research, reading and your answers.
New questions (the same are on the diagram):
1. In OrderLine getId could be accomplished by position in order (local Id). Is enitityId is not synonym of global id?
2. why enitityStatus is here? Do we need it in all cases?
3. Product already has repository so it should be aggregate root?
4. how to distinguish that one association is in aggregate and another is not?
aggregateroot part2.png

Marcin Kuthan

unread,
Sep 5, 2011, 11:23:09 AM9/5/11
to ddd-cqr...@googlegroups.com
I like your proposal with interfaces (Versionable, *Aware).  

Entity inherits from ValueObject, does it?

I don't understand why do you need method isRoot(). For single bounded context aggregate root is always aggregate. If you have use case where the entity is not aggregate root, maybe it should be located in different bounded context or some additional "coordinator" is needed?

Let's assume that Order and OrderLine are both aggregates in the single bounded context. If you need lock an order for editing, and for another use case you need lock just one order line, there should be the "coordinator" for lock management. Locking is only example.


Sławomir Sobótka

unread,
Sep 5, 2011, 4:07:21 PM9/5/11
to ddd-cqr...@googlegroups.com
According to diagram:

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?

Maciej Hadam

unread,
Sep 5, 2011, 5:20:38 PM9/5/11
to ddd-cqr...@googlegroups.com
Yes, about using ID over direct references to other aggregates (it's in the spirit of modularization).
No, about using only aggregateroots (people like to simplifying things).

ps. Those interfaces that are implemented by base/abstract classes was important to me to realize the difference between the VO/EN/AG.
If you think that annotations will be better for that, that's ok.
And one think about generalization the VO type by BaseEnityty: Yep it should be the composition(but as i sad in previous sentence this was not the main point of my thoughts).

Your theoretical knowledge is awesome...

Marcin Kuthan

unread,
Sep 6, 2011, 3:32:22 AM9/6/11
to ddd-cqr...@googlegroups.com
I'm still trying to switch my mind, that leaven is not a framework :-) Sensible architect will know it, and reuse the infrastructure class examples (e.g: BaseEntity) only if they really need them.

And referring to Sławek question:

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.


Marcin Derylo

unread,
Sep 6, 2011, 1:56:46 PM9/6/11
to ddd-cqr...@googlegroups.com


W dniu wtorek, 6 września 2011, 09:32:22 UTC+2 użytkownik Marcin Kuthan napisał:
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.

I would rather keep an ID, even if it's the same BC. You can have different storage mechanisms for those aggregates - like your nice & shiny db for one of them and ugly legacy storage for the other (can't do data migration because of integration with other apps at database level). I don't think Hibernate/JPA will allow you to do such mapping with entity reference?

And yes,  actually had something like this in one of the previous project.
Reply all
Reply to author
Forward
0 new messages