Note the specific word "prefer" at the outset of the advice.

This advice reflects the current consensus view among DDD leaders, but
there are reasons to break the rule(s) of thumb (RoT meaning, do this by
default but maybe not always). Also note the following this specific rule
in question could also lead to the need to use CQRS, and that this specific
rule in question is a good practice if working in a highly scalable
environment.

As always we select one set of tradeoffs at the cost of others. What Dan
advocates has certainly been used over years by others, and to them for
very good reasons.

Vaughn
On Apr 18, 2013 8:53 AM, "Dan Haywood" <[email protected]> wrote:

> Hi Alain,
> Thanks for taking the time to do this.  Comments within.
>
> Vaughn... this thread relates to some advice in one of your articles.
>  I've cc'ed you in case you want to commentate; as you'll see, I don't
> believe it makes sense in the case of using an ORM (as Isis does).
>
>
>
> On 18 April 2013 07:27, 张峰昌 <[email protected]> wrote:
>
>> Hi Dan:
>>
>> I have tried build two style domain model with scrum management
>> application
>> as business background, and the points I have made are more clear than
>> before.
>> Domain Concept include:Product、BacklogItem、Release、Sprint、Task etc. A
>> product have many BacklogItems、Releases、Sprints.
>>
>
>
>> 1、Large business boundary is #1 reason that make A heavy style root
>> aggregate. It's Business boundary makes root aggregate heavy or smaller
>> instead of IdentityType(Datastore or Application).
>>  For example Product as the only one root aggregate.Product is so heavy if
>> we model Product as the only root aggregate,because it needs many
>> collections such BacklogItems、Sprints、Releases.
>>
>
>
> Agreed, we should disregard this. The interesting bit of the discussion is
> the next one.
>
>
>
>> 2、Direct root aggregate Object Referenced maybe the #2 reason that make A
>> heavy root aggregate.
>>  For example,Product、BacklogItem、Release、Sprint are all root
>> aggregate.The relationships between root aggregates have two styles:
>>  (1)、Direct root aggregate Object Referenced.  BacklogItem, Release and
>> Sprint will keep a property Product(type:Product) object reference to
>> represent the relationship with Product(root aggregate)
>>  (2)、Root aggregate ID Referenced. BacklogItem,Release and Sprint will
>> keep
>> a property ProductID(type:Long) reference to represent the relationship
>> with
>> Product(root aggregate).This technique is called disconnected domain model
>> in Vaughn Vernon's paper(https://vaughnvernon.co/?p=139 ).
>>
>
>
> The PDF of this paper being:[1]
>
> The example code sample that you give below correctly explains Vaughn's
> advice, but I don't agree with it.
>
> For the benefit of others reading this thread, Vaughn says:
>
> *Prefer references to external aggregates only by their globally unique
> identifier, not by holding a direct object reference (pointer)*
>
> The reason for doing this, he says, is:
>
> *Aggregates with inferred object references are thus automatically
> smaller because references are never eagerly loaded.*
>
> and he also says:
>
> *...the disconnected domain model is actually a form of lazy loading...*
> *
> *
> which he then says provides:
>
> *... the additional benefits [of] smaller aggregates better performing
> models, scalabiliity and distribution.*
>
> As I say, I don't agree with this.
>
> Vaughn's advice would make sense if we were using Java serialization, but
> we're not; we use JDO.  If you look at how JDO works, behind the scenes it
> holds an id, and the reference is loaded lazily.  This page [2] explains
> the mechanics.
>
> So, in terms of the state, the object is the same size; it holds an Id.
>
> As for scalability, well, (as Maurizio has demonstrated), JDO can be used
> on GAE whose implementation is a scalable NoSQL store.  So we have that
> covered.
>
> As I see it, this disconnected domain model pattern arises from using
> inadequate  non-ORM persistence mechanisms.  But it doesn't make sense if
> using an ORM.  Using it we end up with a much more inconvenient model to
> work with, for no benefit.
>
> I know Vaughn from the DDD mailing list community, so I've cc'ed him on
> this for his reaction if he wishes.
>
> Cheers
> Dan
>
> [1]
> http://dddcommunity.org/wp-content/uploads/files/pdf_articles/Vernon_2011_2.pdf
> [2] http://db.apache.org/jdo/enhancement.html
>
>
>
>> Code Sample for  (1)、Direct root aggregate Object Referenced.
>> Product.java
>> @PersistenceCapable(identityType=IdentityType.DATASTORE)
>> public class Product {
>>         // {{ Description (property)
>>         private String description;
>>
>>         @MemberOrder(sequence = "1")
>>         @Named("description")
>>         public String getDescription() {
>>                 return description;
>>         }
>>
>>         public void setDescription(final String description) {
>>                 this.description = description;
>>         }
>>         // }}
>> }
>>
>> BacklogItem.java
>> @PersistenceCapable(identityType=IdentityType.DATASTORE)
>> public class BacklogItem {
>>         // {{ Description (property)
>>         private String description;
>>
>>         @MemberOrder(sequence = "1")
>>         public String getDescription() {
>>                 return description;
>>         }
>>
>>         public void setDescription(final String description) {
>>                 this.description = description;
>>         }
>>         // }}
>>
>>         // {{ Product (property)
>>         private Product product;
>>
>>         @MemberOrder(sequence = "2")
>>         public Product getProduct() {
>>                 return product;
>>         }
>>
>>         public void setProduct(final Product product) {
>>                 this.product = product;
>>         }
>> ......
>> }
>>
>>
>> Code Sample for (2)、Root aggregate ID Referenced.
>> Product.java
>> @PersistenceCapable(identityType=IdentityType.APPLICATION)
>> public class Product {
>>         // {{ ProductID (property)
>>
>> @Persistent(primaryKey="true",valueStrategy=IdGeneratorStrategy.NATIVE)
>>         private Long productID;
>>
>>         @MemberOrder(sequence = "1")
>>         @Hidden(when=When.UNTIL_PERSISTED)
>>         public Long getProductID() {
>>                 return productID;
>>         }
>>
>>         public void setProductID(final Long productID) {
>>                 this.productID = productID;
>>         }
>>         // }}
>>
>>         // {{ Description (property)
>>         private String description;
>>
>>         @MemberOrder(sequence = "1")
>>         public String getDescription() {
>>                 return description;
>>         }
>>
>>         public void setDescription(final String description) {
>>                 this.description = description;
>>         }
>>         // }}
>> }
>>
>> BacklogItem.java
>> @PersistenceCapable(identityType=IdentityType.APPLICATION)
>> public class BacklogItem {
>>         // {{ BacklogItemID (property)
>>
>> @Persistent(primaryKey="true",valueStrategy=IdGeneratorStrategy.NATIVE)
>>         private Long backlogItemID;
>>
>>         @MemberOrder(sequence = "1")
>>         @Hidden(when=When.UNTIL_PERSISTED)
>>         public Long getBacklogItemID() {
>>                 return backlogItemID;
>>         }
>>
>>         public void setBacklogItemID(final Long backlogItemID) {
>>                 this.backlogItemID = backlogItemID;
>>         }
>>         // }}
>>
>>         // {{ Description (property)
>>         private String description;
>>
>>         @MemberOrder(sequence = "2")
>>         public String getDescription() {
>>                 return description;
>>         }
>>
>>         public void setDescription(final String description) {
>>                 this.description = description;
>>         }
>>         // }}
>>
>>         // {{ ProductID (property)
>>         // this way I means smaller root aggregate,because the current
>> root
>> aggregate do not depends on other root aggregate.
>>         private Long productID;
>>
>>         @MemberOrder(sequence = "3")
>>         public Long getProductID() {
>>                 return productID;
>>         }
>>
>>         public void setProductID(final Long productID) {
>>                 this.productID = productID;
>>         }
>>         // }}
>> .........
>> }
>>
>> Best Regards
>>
>> Alain
>>
>

Reply via email to