You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@polygene.apache.org by Niclas Hedhman <ni...@hedhman.org> on 2016/04/28 17:01:38 UTC

Aggregates and AggregateRoots

Gang,

since we are on the topic of persistence, I have some thoughts that I would
like to share.

I think code is the best way to show, and as usual we start with a usecase.

So, let's say I want to create the classic Order example with OrderItem
entities (orders can be massively big doh!!! (should really just use values
as items)). Any way, so I have the OrderItem

public interface OrderItem extends EntityComposite
{
    Property<Integer> quantity();
    Association<Product> product();
    Property<BigDecimal> pricePerItem();
    Property<BigDecimal> discount();
}

The we have the Order itself...

public interface Order extends EntityComposite
{
    Customer customer();
    BigDecimal totalSum();
    void addItem( Product p, int quantity, BigDecimal price, BigDecimal
discount );
    void removeItem( Product p, int quantity );
    Iterable<OrderItem> items();

    interface State
    {
        Association<Customer> customer();

        Property<ShippingAddress> shippingAddress();

        @Aggregated
        ManyAssociation<OrderItem> items();

        Property<Boolean> onCredit();
    }

}

Let's say that we just want to make sure an order doesn't exceed the credit
limit of the customer.

For sake of simplicity in this discussion, the current outstanding credit
is stored in the Customer itself and a simple exposed method for the
validation.

public interface Customer
{
      :
    boolean hasCreditFor( BigDecimal additional );
      :
}

We already have a validation mechanism called Constraints, but they work on
input arguments to methods. We need something similar, but work on the
entire Composite,

public class CreditLimitConstraint
    implements AggregateConstraint<Order>
{
    public boolean isValid( Order order )
    {
        if( ! order.onCredit().get() )
            return true;
        return order.customer().hasCreditFor( order.totalSum() );
    }
}

And we could annotate with a Constraint-like annotation,

@AggregateConstraints( CreditLimitConstraint.class )
public interface Order extends EntityComposite
{}

But this doesn't solve the problem. We could have code that queries for the
OrderItem instances and manipulates them directly. That is against the
principle of Aggregates. Or we could hand over a reference of an OrderItem
to another composite which use it to direct access to the aggregated
entity. Also not cool.

So, what we need is that EntityReference of an aggregated Entity to be
invalid if it is not accessed from the AggregateRoot instance.

How can we do that, in relatively simple terms?

Well, one option could be to create a new composite meta type;

public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}

And its implementation of UnitOfWorkFactory has two purposes;
  1. Only work for types that exists as @Aggregated Associations within the
same subtype.
   2. Manage the EntityReferences to be Aggregate "relative".

The second of those is a bit tricky, but effectively needs to provide a UoW
implementation that leverage the EntityReference of the owning Aggregate.
Doable, but tricky.


But hold on a second; If the Aggregate is a UnitOfWorkFactory and possibly
handles its own UnitOfWork, how does this fit with DDD on one hand and with
the current UoW system on the other hand??

Well, with DDD it is a perfect match. The Aggregate is a transactional
boundary. So it seems to suggest a good fit. Cool.
But, does DDD really tackle this, since you can't get the UnitOfWorkFactory
of the Aggregate without first having a UnitOfWork to retrieve it with.
This seems to suggest that DDD doesn't have it correct, or has made a
simplification that is somewhat unfortunate.

Could it be that there is actually a difference between the Aggregate being
a non-Entity composite and the AggregateRoot that is an entity and part of
the Aggregate??

Perhaps...

public interface Order extends EntityComposite {}  // back to normal entity

@AggregateConstraint( CreditLimitConstraint.class )
public interface OrderAggregate extends Aggregate<Order> {}

meaning

public interface Aggregate<T extends EntityComposite> extends
UnitOfWorkFactory, Composite
{
    T root();
}

(I have place EntityComposite supertypes everywhere, but that is for
clarity. Since we don't require that anymore, they shouldn't be there)

So, then how would this be used??

Aggregate<Order> aggregate = module.newAggregate( Order.class, identity );

the newAggregate method, would do
   a. create Aggregate composite,
   b. create a new unit of work
   c. read the entity from the store and populate root()
   d. if entity doesn't exists, create a entity builder internally and use
when populating state,
   e. keep the UoW open,

Since it should handle both existing and new aggregates uniformly, I think
a

    boolean isCreating();   // or similar

method should also exist on the Aggregate type.


To me, this feels a lot better. The DDD "rules" and "intents" are still in
effect and can be enforced, and we can manage to implement it in Zest, if
we choose to do so.

I am really keen on hearing thoughts on this topic.

Cheers
-- 
Niclas Hedhman, Software Developer
http://zest.apache.org - New Energy for Java

Re: Constraints (Re: Aggregates and AggregateRoots)

Posted by Niclas Hedhman <he...@gmail.com>.
Yes, that is possibly true. For entities, there is enough "management" to
ensure that the constraints are not violated (on .complete() ), but for
other composites, it becomes trickier.

However!!! I think it would be quite easy to define InvariantConstraints as,

* Invariant validation happens on return of all methods of the Composite.
Invalid invariants are only tolerated within a single method call

That would then imply two consequences;

  a. When obtaining a Property or  Association, from outside the Composite,
the InvariantConstraints are checked on mutating operations (set(), add()...

  b. When obtaining a Property or Association within the Composite, the
InvariantConstraints are NOT checked, only on method exist from Composite.

That should lead to less "anemic object" anti-pattern, which is good stuff.

With the above, there is another anomaly showing its head; newXXX() methods
become a "special case" as they would also do InvariantConstraints check.
Does this indicate that newXXX() should be part of the Composite itself,
similar to constructors on regular classes?? How would that look like?

Cheers
Niclas
On Apr 29, 2016 05:08, "Kent Sølvsten" <ke...@gmail.com> wrote:

> Interesting stuff!
>
> Now first to the constraints:
>
> @AggregateConstraints( CreditLimitConstraint.class )
> public interface Order extends EntityComposite
> {}
>
>
> It seems to me, that this  could and should be made much more general.
> Constraints on a composite level is as relevant for both values (checked
> on creation) and "plain entities" (hmmm ... probably to be checked both
> on builder completion and on UOW completion)
>
> Enforcing rules such as
> "either property A or B should be defined."
> "password must not be the same as username"
>
> The only special stuff related to aggregates, i think, is that if we
> complete a UOW involving changes to an OrderItem, constraints on the
> order itself (and possibly also constraints directly on the
> OrderItem???) should be enforced.
>
> So i think this part of your suggestion should be a separate topic
> having value in it's own right.
>
> /Kent
>
>
>
>
> Den 28-04-2016 kl. 17:01 skrev Niclas Hedhman:
> > Gang,
> >
> > since we are on the topic of persistence, I have some thoughts that I
> would
> > like to share.
> >
> > I think code is the best way to show, and as usual we start with a
> usecase.
> >
> > So, let's say I want to create the classic Order example with OrderItem
> > entities (orders can be massively big doh!!! (should really just use
> values
> > as items)). Any way, so I have the OrderItem
> >
> > public interface OrderItem extends EntityComposite
> > {
> >     Property<Integer> quantity();
> >     Association<Product> product();
> >     Property<BigDecimal> pricePerItem();
> >     Property<BigDecimal> discount();
> > }
> >
> > The we have the Order itself...
> >
> > public interface Order extends EntityComposite
> > {
> >     Customer customer();
> >     BigDecimal totalSum();
> >     void addItem( Product p, int quantity, BigDecimal price, BigDecimal
> > discount );
> >     void removeItem( Product p, int quantity );
> >     Iterable<OrderItem> items();
> >
> >     interface State
> >     {
> >         Association<Customer> customer();
> >
> >         Property<ShippingAddress> shippingAddress();
> >
> >         @Aggregated
> >         ManyAssociation<OrderItem> items();
> >
> >         Property<Boolean> onCredit();
> >     }
> >
> > }
> >
> > Let's say that we just want to make sure an order doesn't exceed the
> credit
> > limit of the customer.
> >
> > For sake of simplicity in this discussion, the current outstanding credit
> > is stored in the Customer itself and a simple exposed method for the
> > validation.
> >
> > public interface Customer
> > {
> >       :
> >     boolean hasCreditFor( BigDecimal additional );
> >       :
> > }
> >
> > We already have a validation mechanism called Constraints, but they work
> on
> > input arguments to methods. We need something similar, but work on the
> > entire Composite,
> >
> > public class CreditLimitConstraint
> >     implements AggregateConstraint<Order>
> > {
> >     public boolean isValid( Order order )
> >     {
> >         if( ! order.onCredit().get() )
> >             return true;
> >         return order.customer().hasCreditFor( order.totalSum() );
> >     }
> > }
> >
> > And we could annotate with a Constraint-like annotation,
> >
> > @AggregateConstraints( CreditLimitConstraint.class )
> > public interface Order extends EntityComposite
> > {}
> >
> > But this doesn't solve the problem. We could have code that queries for
> the
> > OrderItem instances and manipulates them directly. That is against the
> > principle of Aggregates. Or we could hand over a reference of an
> OrderItem
> > to another composite which use it to direct access to the aggregated
> > entity. Also not cool.
> >
> > So, what we need is that EntityReference of an aggregated Entity to be
> > invalid if it is not accessed from the AggregateRoot instance.
> >
> > How can we do that, in relatively simple terms?
> >
> > Well, one option could be to create a new composite meta type;
> >
> > public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}
> >
> > And its implementation of UnitOfWorkFactory has two purposes;
> >   1. Only work for types that exists as @Aggregated Associations within
> the
> > same subtype.
> >    2. Manage the EntityReferences to be Aggregate "relative".
> >
> > The second of those is a bit tricky, but effectively needs to provide a
> UoW
> > implementation that leverage the EntityReference of the owning Aggregate.
> > Doable, but tricky.
> >
> >
> > But hold on a second; If the Aggregate is a UnitOfWorkFactory and
> possibly
> > handles its own UnitOfWork, how does this fit with DDD on one hand and
> with
> > the current UoW system on the other hand??
> >
> > Well, with DDD it is a perfect match. The Aggregate is a transactional
> > boundary. So it seems to suggest a good fit. Cool.
> > But, does DDD really tackle this, since you can't get the
> UnitOfWorkFactory
> > of the Aggregate without first having a UnitOfWork to retrieve it with.
> > This seems to suggest that DDD doesn't have it correct, or has made a
> > simplification that is somewhat unfortunate.
> >
> > Could it be that there is actually a difference between the Aggregate
> being
> > a non-Entity composite and the AggregateRoot that is an entity and part
> of
> > the Aggregate??
> >
> > Perhaps...
> >
> > public interface Order extends EntityComposite {}  // back to normal
> entity
> >
> > @AggregateConstraint( CreditLimitConstraint.class )
> > public interface OrderAggregate extends Aggregate<Order> {}
> >
> > meaning
> >
> > public interface Aggregate<T extends EntityComposite> extends
> > UnitOfWorkFactory, Composite
> > {
> >     T root();
> > }
> >
> > (I have place EntityComposite supertypes everywhere, but that is for
> > clarity. Since we don't require that anymore, they shouldn't be there)
> >
> > So, then how would this be used??
> >
> > Aggregate<Order> aggregate = module.newAggregate( Order.class, identity
> );
> >
> > the newAggregate method, would do
> >    a. create Aggregate composite,
> >    b. create a new unit of work
> >    c. read the entity from the store and populate root()
> >    d. if entity doesn't exists, create a entity builder internally and
> use
> > when populating state,
> >    e. keep the UoW open,
> >
> > Since it should handle both existing and new aggregates uniformly, I
> think
> > a
> >
> >     boolean isCreating();   // or similar
> >
> > method should also exist on the Aggregate type.
> >
> >
> > To me, this feels a lot better. The DDD "rules" and "intents" are still
> in
> > effect and can be enforced, and we can manage to implement it in Zest, if
> > we choose to do so.
> >
> > I am really keen on hearing thoughts on this topic.
> >
> > Cheers
>
>

Constraints (Re: Aggregates and AggregateRoots)

Posted by Kent Sølvsten <ke...@gmail.com>.
Interesting stuff!

Now first to the constraints:

@AggregateConstraints( CreditLimitConstraint.class )
public interface Order extends EntityComposite
{}


It seems to me, that this  could and should be made much more general.
Constraints on a composite level is as relevant for both values (checked
on creation) and "plain entities" (hmmm ... probably to be checked both
on builder completion and on UOW completion)

Enforcing rules such as
"either property A or B should be defined."
"password must not be the same as username"

The only special stuff related to aggregates, i think, is that if we
complete a UOW involving changes to an OrderItem, constraints on the
order itself (and possibly also constraints directly on the
OrderItem???) should be enforced.

So i think this part of your suggestion should be a separate topic
having value in it's own right.

/Kent




Den 28-04-2016 kl. 17:01 skrev Niclas Hedhman:
> Gang,
>
> since we are on the topic of persistence, I have some thoughts that I would
> like to share.
>
> I think code is the best way to show, and as usual we start with a usecase.
>
> So, let's say I want to create the classic Order example with OrderItem
> entities (orders can be massively big doh!!! (should really just use values
> as items)). Any way, so I have the OrderItem
>
> public interface OrderItem extends EntityComposite
> {
>     Property<Integer> quantity();
>     Association<Product> product();
>     Property<BigDecimal> pricePerItem();
>     Property<BigDecimal> discount();
> }
>
> The we have the Order itself...
>
> public interface Order extends EntityComposite
> {
>     Customer customer();
>     BigDecimal totalSum();
>     void addItem( Product p, int quantity, BigDecimal price, BigDecimal
> discount );
>     void removeItem( Product p, int quantity );
>     Iterable<OrderItem> items();
>
>     interface State
>     {
>         Association<Customer> customer();
>
>         Property<ShippingAddress> shippingAddress();
>
>         @Aggregated
>         ManyAssociation<OrderItem> items();
>
>         Property<Boolean> onCredit();
>     }
>
> }
>
> Let's say that we just want to make sure an order doesn't exceed the credit
> limit of the customer.
>
> For sake of simplicity in this discussion, the current outstanding credit
> is stored in the Customer itself and a simple exposed method for the
> validation.
>
> public interface Customer
> {
>       :
>     boolean hasCreditFor( BigDecimal additional );
>       :
> }
>
> We already have a validation mechanism called Constraints, but they work on
> input arguments to methods. We need something similar, but work on the
> entire Composite,
>
> public class CreditLimitConstraint
>     implements AggregateConstraint<Order>
> {
>     public boolean isValid( Order order )
>     {
>         if( ! order.onCredit().get() )
>             return true;
>         return order.customer().hasCreditFor( order.totalSum() );
>     }
> }
>
> And we could annotate with a Constraint-like annotation,
>
> @AggregateConstraints( CreditLimitConstraint.class )
> public interface Order extends EntityComposite
> {}
>
> But this doesn't solve the problem. We could have code that queries for the
> OrderItem instances and manipulates them directly. That is against the
> principle of Aggregates. Or we could hand over a reference of an OrderItem
> to another composite which use it to direct access to the aggregated
> entity. Also not cool.
>
> So, what we need is that EntityReference of an aggregated Entity to be
> invalid if it is not accessed from the AggregateRoot instance.
>
> How can we do that, in relatively simple terms?
>
> Well, one option could be to create a new composite meta type;
>
> public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}
>
> And its implementation of UnitOfWorkFactory has two purposes;
>   1. Only work for types that exists as @Aggregated Associations within the
> same subtype.
>    2. Manage the EntityReferences to be Aggregate "relative".
>
> The second of those is a bit tricky, but effectively needs to provide a UoW
> implementation that leverage the EntityReference of the owning Aggregate.
> Doable, but tricky.
>
>
> But hold on a second; If the Aggregate is a UnitOfWorkFactory and possibly
> handles its own UnitOfWork, how does this fit with DDD on one hand and with
> the current UoW system on the other hand??
>
> Well, with DDD it is a perfect match. The Aggregate is a transactional
> boundary. So it seems to suggest a good fit. Cool.
> But, does DDD really tackle this, since you can't get the UnitOfWorkFactory
> of the Aggregate without first having a UnitOfWork to retrieve it with.
> This seems to suggest that DDD doesn't have it correct, or has made a
> simplification that is somewhat unfortunate.
>
> Could it be that there is actually a difference between the Aggregate being
> a non-Entity composite and the AggregateRoot that is an entity and part of
> the Aggregate??
>
> Perhaps...
>
> public interface Order extends EntityComposite {}  // back to normal entity
>
> @AggregateConstraint( CreditLimitConstraint.class )
> public interface OrderAggregate extends Aggregate<Order> {}
>
> meaning
>
> public interface Aggregate<T extends EntityComposite> extends
> UnitOfWorkFactory, Composite
> {
>     T root();
> }
>
> (I have place EntityComposite supertypes everywhere, but that is for
> clarity. Since we don't require that anymore, they shouldn't be there)
>
> So, then how would this be used??
>
> Aggregate<Order> aggregate = module.newAggregate( Order.class, identity );
>
> the newAggregate method, would do
>    a. create Aggregate composite,
>    b. create a new unit of work
>    c. read the entity from the store and populate root()
>    d. if entity doesn't exists, create a entity builder internally and use
> when populating state,
>    e. keep the UoW open,
>
> Since it should handle both existing and new aggregates uniformly, I think
> a
>
>     boolean isCreating();   // or similar
>
> method should also exist on the Aggregate type.
>
>
> To me, this feels a lot better. The DDD "rules" and "intents" are still in
> effect and can be enforced, and we can manage to implement it in Zest, if
> we choose to do so.
>
> I am really keen on hearing thoughts on this topic.
>
> Cheers


Re: Perstence/runtime for Aggregates and AggregateRoots

Posted by Niclas Hedhman <he...@gmail.com>.
Out of the 3 suggestions, this one is hardest to agree with, probably
because the implications are big and far-reaching.

I don't like the Aggregated.root() concept. Not because it should be an
Association, which in reality is a Property<EntityReference>, but because
it creates a two-way association for no good reason, and stores it as well.

To be analogous with @This, I think it should be;

public class OrderItemMixin
{
    @Aggregate
    private Order root;
}

As for the list if benefits, I am not convinced that any of them are
exclusive to an Aggregated interface.

I agree that the OrderItem ends up being persisted by a regular Entity
Store, and if people really guess/construct Identities explicitly, I think
it is OK to say "all bets are off". That is similar to being able to dig
into private mixins via reflection, not easy, but doable.
The important bit is that the EntityReference of the OrderItem is
AggregateRoot relative, and the Entity Reference can only be used via its
AR. The mechanism to handle that can be an implementation detail, or even a
replaceable implementation detail if people ever need to loosen the
restrictions a little bit and know what they are doing, similar to the
Property/Association handling being customizable, but I don't think has
ever happened.

Niclas
On Apr 29, 2016 05:57, "Kent Sølvsten" <ke...@gmail.com> wrote:

> A note on persistence.
>
> The OrderItem will probably be persisted in a standard EntityStore.
> But we definitely do not want the user to query for them
> And we do not want the user to load them (by key).
>
> What would happen, if we (under the hood) added a Aggregrated interface
> to the orderitem?
>
> public interface Aggregated {
>   public Property<EntityReference> root();
>  }
>
> and (under the hood) added an AggregatedMixin to the OrderItem - meaning
> the root will be persisted.
>
> This would allow the runtime to decide that
> - a unitofwork must not remove it
> - the unitofwork would be able to guard agains a direct get()
> - notification of indexers should be discarded for the OrderItem - but
> the indexer should still be able to find orders-with-items-with-product-X
> - it must never be added to an association
> - the user might modify it (he really should not, it should happen
> through the order instead) - but consistency of the whole Order is
> checked on UOW.complete() - that is, all constraints on the Order is
> checked.
>
> This way the Order itself would simply be a standard entity with a
> special-type-of-association - and the OrderItem is a "truncated entity"
> with some features removed.
>
> WDYT?
>
> /Kent
>
> Den 28-04-2016 kl. 17:01 skrev Niclas Hedhman:
> > Gang,
> >
> > since we are on the topic of persistence, I have some thoughts that I
> would
> > like to share.
> >
> > I think code is the best way to show, and as usual we start with a
> usecase.
> >
> > So, let's say I want to create the classic Order example with OrderItem
> > entities (orders can be massively big doh!!! (should really just use
> values
> > as items)). Any way, so I have the OrderItem
> >
> > public interface OrderItem extends EntityComposite
> > {
> >     Property<Integer> quantity();
> >     Association<Product> product();
> >     Property<BigDecimal> pricePerItem();
> >     Property<BigDecimal> discount();
> > }
> >
> > The we have the Order itself...
> >
> > public interface Order extends EntityComposite
> > {
> >     Customer customer();
> >     BigDecimal totalSum();
> >     void addItem( Product p, int quantity, BigDecimal price, BigDecimal
> > discount );
> >     void removeItem( Product p, int quantity );
> >     Iterable<OrderItem> items();
> >
> >     interface State
> >     {
> >         Association<Customer> customer();
> >
> >         Property<ShippingAddress> shippingAddress();
> >
> >         @Aggregated
> >         ManyAssociation<OrderItem> items();
> >
> >         Property<Boolean> onCredit();
> >     }
> >
> > }
> >
> > Let's say that we just want to make sure an order doesn't exceed the
> credit
> > limit of the customer.
> >
> > For sake of simplicity in this discussion, the current outstanding credit
> > is stored in the Customer itself and a simple exposed method for the
> > validation.
> >
> > public interface Customer
> > {
> >       :
> >     boolean hasCreditFor( BigDecimal additional );
> >       :
> > }
> >
> > We already have a validation mechanism called Constraints, but they work
> on
> > input arguments to methods. We need something similar, but work on the
> > entire Composite,
> >
> > public class CreditLimitConstraint
> >     implements AggregateConstraint<Order>
> > {
> >     public boolean isValid( Order order )
> >     {
> >         if( ! order.onCredit().get() )
> >             return true;
> >         return order.customer().hasCreditFor( order.totalSum() );
> >     }
> > }
> >
> > And we could annotate with a Constraint-like annotation,
> >
> > @AggregateConstraints( CreditLimitConstraint.class )
> > public interface Order extends EntityComposite
> > {}
> >
> > But this doesn't solve the problem. We could have code that queries for
> the
> > OrderItem instances and manipulates them directly. That is against the
> > principle of Aggregates. Or we could hand over a reference of an
> OrderItem
> > to another composite which use it to direct access to the aggregated
> > entity. Also not cool.
> >
> > So, what we need is that EntityReference of an aggregated Entity to be
> > invalid if it is not accessed from the AggregateRoot instance.
> >
> > How can we do that, in relatively simple terms?
> >
> > Well, one option could be to create a new composite meta type;
> >
> > public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}
> >
> > And its implementation of UnitOfWorkFactory has two purposes;
> >   1. Only work for types that exists as @Aggregated Associations within
> the
> > same subtype.
> >    2. Manage the EntityReferences to be Aggregate "relative".
> >
> > The second of those is a bit tricky, but effectively needs to provide a
> UoW
> > implementation that leverage the EntityReference of the owning Aggregate.
> > Doable, but tricky.
> >
> >
> > But hold on a second; If the Aggregate is a UnitOfWorkFactory and
> possibly
> > handles its own UnitOfWork, how does this fit with DDD on one hand and
> with
> > the current UoW system on the other hand??
> >
> > Well, with DDD it is a perfect match. The Aggregate is a transactional
> > boundary. So it seems to suggest a good fit. Cool.
> > But, does DDD really tackle this, since you can't get the
> UnitOfWorkFactory
> > of the Aggregate without first having a UnitOfWork to retrieve it with.
> > This seems to suggest that DDD doesn't have it correct, or has made a
> > simplification that is somewhat unfortunate.
> >
> > Could it be that there is actually a difference between the Aggregate
> being
> > a non-Entity composite and the AggregateRoot that is an entity and part
> of
> > the Aggregate??
> >
> > Perhaps...
> >
> > public interface Order extends EntityComposite {}  // back to normal
> entity
> >
> > @AggregateConstraint( CreditLimitConstraint.class )
> > public interface OrderAggregate extends Aggregate<Order> {}
> >
> > meaning
> >
> > public interface Aggregate<T extends EntityComposite> extends
> > UnitOfWorkFactory, Composite
> > {
> >     T root();
> > }
> >
> > (I have place EntityComposite supertypes everywhere, but that is for
> > clarity. Since we don't require that anymore, they shouldn't be there)
> >
> > So, then how would this be used??
> >
> > Aggregate<Order> aggregate = module.newAggregate( Order.class, identity
> );
> >
> > the newAggregate method, would do
> >    a. create Aggregate composite,
> >    b. create a new unit of work
> >    c. read the entity from the store and populate root()
> >    d. if entity doesn't exists, create a entity builder internally and
> use
> > when populating state,
> >    e. keep the UoW open,
> >
> > Since it should handle both existing and new aggregates uniformly, I
> think
> > a
> >
> >     boolean isCreating();   // or similar
> >
> > method should also exist on the Aggregate type.
> >
> >
> > To me, this feels a lot better. The DDD "rules" and "intents" are still
> in
> > effect and can be enforced, and we can manage to implement it in Zest, if
> > we choose to do so.
> >
> > I am really keen on hearing thoughts on this topic.
> >
> > Cheers
>
>

Perstence/runtime for Aggregates and AggregateRoots

Posted by Kent Sølvsten <ke...@gmail.com>.
A note on persistence.

The OrderItem will probably be persisted in a standard EntityStore.
But we definitely do not want the user to query for them
And we do not want the user to load them (by key).

What would happen, if we (under the hood) added a Aggregrated interface
to the orderitem?

public interface Aggregated {
  public Property<EntityReference> root();
 }

and (under the hood) added an AggregatedMixin to the OrderItem - meaning
the root will be persisted.

This would allow the runtime to decide that
- a unitofwork must not remove it
- the unitofwork would be able to guard agains a direct get()
- notification of indexers should be discarded for the OrderItem - but
the indexer should still be able to find orders-with-items-with-product-X
- it must never be added to an association
- the user might modify it (he really should not, it should happen
through the order instead) - but consistency of the whole Order is
checked on UOW.complete() - that is, all constraints on the Order is
checked.

This way the Order itself would simply be a standard entity with a
special-type-of-association - and the OrderItem is a "truncated entity"
with some features removed.

WDYT?

/Kent

Den 28-04-2016 kl. 17:01 skrev Niclas Hedhman:
> Gang,
>
> since we are on the topic of persistence, I have some thoughts that I would
> like to share.
>
> I think code is the best way to show, and as usual we start with a usecase.
>
> So, let's say I want to create the classic Order example with OrderItem
> entities (orders can be massively big doh!!! (should really just use values
> as items)). Any way, so I have the OrderItem
>
> public interface OrderItem extends EntityComposite
> {
>     Property<Integer> quantity();
>     Association<Product> product();
>     Property<BigDecimal> pricePerItem();
>     Property<BigDecimal> discount();
> }
>
> The we have the Order itself...
>
> public interface Order extends EntityComposite
> {
>     Customer customer();
>     BigDecimal totalSum();
>     void addItem( Product p, int quantity, BigDecimal price, BigDecimal
> discount );
>     void removeItem( Product p, int quantity );
>     Iterable<OrderItem> items();
>
>     interface State
>     {
>         Association<Customer> customer();
>
>         Property<ShippingAddress> shippingAddress();
>
>         @Aggregated
>         ManyAssociation<OrderItem> items();
>
>         Property<Boolean> onCredit();
>     }
>
> }
>
> Let's say that we just want to make sure an order doesn't exceed the credit
> limit of the customer.
>
> For sake of simplicity in this discussion, the current outstanding credit
> is stored in the Customer itself and a simple exposed method for the
> validation.
>
> public interface Customer
> {
>       :
>     boolean hasCreditFor( BigDecimal additional );
>       :
> }
>
> We already have a validation mechanism called Constraints, but they work on
> input arguments to methods. We need something similar, but work on the
> entire Composite,
>
> public class CreditLimitConstraint
>     implements AggregateConstraint<Order>
> {
>     public boolean isValid( Order order )
>     {
>         if( ! order.onCredit().get() )
>             return true;
>         return order.customer().hasCreditFor( order.totalSum() );
>     }
> }
>
> And we could annotate with a Constraint-like annotation,
>
> @AggregateConstraints( CreditLimitConstraint.class )
> public interface Order extends EntityComposite
> {}
>
> But this doesn't solve the problem. We could have code that queries for the
> OrderItem instances and manipulates them directly. That is against the
> principle of Aggregates. Or we could hand over a reference of an OrderItem
> to another composite which use it to direct access to the aggregated
> entity. Also not cool.
>
> So, what we need is that EntityReference of an aggregated Entity to be
> invalid if it is not accessed from the AggregateRoot instance.
>
> How can we do that, in relatively simple terms?
>
> Well, one option could be to create a new composite meta type;
>
> public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}
>
> And its implementation of UnitOfWorkFactory has two purposes;
>   1. Only work for types that exists as @Aggregated Associations within the
> same subtype.
>    2. Manage the EntityReferences to be Aggregate "relative".
>
> The second of those is a bit tricky, but effectively needs to provide a UoW
> implementation that leverage the EntityReference of the owning Aggregate.
> Doable, but tricky.
>
>
> But hold on a second; If the Aggregate is a UnitOfWorkFactory and possibly
> handles its own UnitOfWork, how does this fit with DDD on one hand and with
> the current UoW system on the other hand??
>
> Well, with DDD it is a perfect match. The Aggregate is a transactional
> boundary. So it seems to suggest a good fit. Cool.
> But, does DDD really tackle this, since you can't get the UnitOfWorkFactory
> of the Aggregate without first having a UnitOfWork to retrieve it with.
> This seems to suggest that DDD doesn't have it correct, or has made a
> simplification that is somewhat unfortunate.
>
> Could it be that there is actually a difference between the Aggregate being
> a non-Entity composite and the AggregateRoot that is an entity and part of
> the Aggregate??
>
> Perhaps...
>
> public interface Order extends EntityComposite {}  // back to normal entity
>
> @AggregateConstraint( CreditLimitConstraint.class )
> public interface OrderAggregate extends Aggregate<Order> {}
>
> meaning
>
> public interface Aggregate<T extends EntityComposite> extends
> UnitOfWorkFactory, Composite
> {
>     T root();
> }
>
> (I have place EntityComposite supertypes everywhere, but that is for
> clarity. Since we don't require that anymore, they shouldn't be there)
>
> So, then how would this be used??
>
> Aggregate<Order> aggregate = module.newAggregate( Order.class, identity );
>
> the newAggregate method, would do
>    a. create Aggregate composite,
>    b. create a new unit of work
>    c. read the entity from the store and populate root()
>    d. if entity doesn't exists, create a entity builder internally and use
> when populating state,
>    e. keep the UoW open,
>
> Since it should handle both existing and new aggregates uniformly, I think
> a
>
>     boolean isCreating();   // or similar
>
> method should also exist on the Aggregate type.
>
>
> To me, this feels a lot better. The DDD "rules" and "intents" are still in
> effect and can be enforced, and we can manage to implement it in Zest, if
> we choose to do so.
>
> I am really keen on hearing thoughts on this topic.
>
> Cheers


Re: Aggregates and AggregateRoots

Posted by Niclas Hedhman <he...@gmail.com>.
After thinking about this for a while, my conclusion is that on one hand I
like it a lot, but it would also mean that we need Aggregation(),
ManyAggregation(), NamedAggregation() in parallel of the existing
Associations, for something that is really the same-ish thing.

It isn't out of the question, but to me it feels like a lot of user-facing
surface area for relatively little purpose.


Could this be modified a bit??

EntityBuilder<OrderItem> builder = uowf.newAggregation( myOrder.items() );

I think this looks very neat, and should solve the "what is its
association" in the UoW part quite easily.

WDYAT?
Niclas



On Fri, Apr 29, 2016 at 7:43 AM, Niclas Hedhman <he...@gmail.com> wrote:

>
> I like this idea. It is very Zest-like, in that it is "think outside the
> box"... (There is no spoon)
>
> I want to ponder over a little bit.
>
> Cheers
> Niclas
> On Apr 29, 2016 05:28, "Kent Sølvsten" <ke...@gmail.com> wrote:
>
> Another topic is how to manage the OrderItems inside the Order.
>
> I have an idea ....
>
> You discussed a special UOWFactory as part of the aggregate composite -
> what should that UOW be used for? I guess it is just for adding/removing
> OrderItems.
> Could that be part of the relation?
>
> what if , instead of
>
>         @Aggregated
>         ManyAssociation<OrderItem> items();
>
>
> we have
>
>         ManyAggregation<OrderItem> items();
>
> An aggregation is a relation, similar to the association. But we cannot
> add items to it, instead it helps us building new parts.
>
> EntityBuilder<OrderItem> template = items().newEntityBuilder();
> template.quantity().set(1);
> template.newInstance();  // will automatically be part of the collection
>
> and the later use the aggregation to remove an item.
>
> That is OrderItems are not created independently and then added, instead
> they are created directly on the aggregation!
>
> /Kent
>
>
>
>
>
> Den 28-04-2016 kl. 17:01 skrev Niclas Hedhman:
> > Gang,
> >
> > since we are on the topic of persistence, I have some thoughts that I
> would
> > like to share.
> >
> > I think code is the best way to show, and as usual we start with a
> usecase.
> >
> > So, let's say I want to create the classic Order example with OrderItem
> > entities (orders can be massively big doh!!! (should really just use
> values
> > as items)). Any way, so I have the OrderItem
> >
> > public interface OrderItem extends EntityComposite
> > {
> >     Property<Integer> quantity();
> >     Association<Product> product();
> >     Property<BigDecimal> pricePerItem();
> >     Property<BigDecimal> discount();
> > }
> >
> > The we have the Order itself...
> >
> > public interface Order extends EntityComposite
> > {
> >     Customer customer();
> >     BigDecimal totalSum();
> >     void addItem( Product p, int quantity, BigDecimal price, BigDecimal
> > discount );
> >     void removeItem( Product p, int quantity );
> >     Iterable<OrderItem> items();
> >
> >     interface State
> >     {
> >         Association<Customer> customer();
> >
> >         Property<ShippingAddress> shippingAddress();
> >
> >         @Aggregated
> >         ManyAssociation<OrderItem> items();
> >
> >         Property<Boolean> onCredit();
> >     }
> >
> > }
> >
> > Let's say that we just want to make sure an order doesn't exceed the
> credit
> > limit of the customer.
> >
> > For sake of simplicity in this discussion, the current outstanding credit
> > is stored in the Customer itself and a simple exposed method for the
> > validation.
> >
> > public interface Customer
> > {
> >       :
> >     boolean hasCreditFor( BigDecimal additional );
> >       :
> > }
> >
> > We already have a validation mechanism called Constraints, but they work
> on
> > input arguments to methods. We need something similar, but work on the
> > entire Composite,
> >
> > public class CreditLimitConstraint
> >     implements AggregateConstraint<Order>
> > {
> >     public boolean isValid( Order order )
> >     {
> >         if( ! order.onCredit().get() )
> >             return true;
> >         return order.customer().hasCreditFor( order.totalSum() );
> >     }
> > }
> >
> > And we could annotate with a Constraint-like annotation,
> >
> > @AggregateConstraints( CreditLimitConstraint.class )
> > public interface Order extends EntityComposite
> > {}
> >
> > But this doesn't solve the problem. We could have code that queries for
> the
> > OrderItem instances and manipulates them directly. That is against the
> > principle of Aggregates. Or we could hand over a reference of an
> OrderItem
> > to another composite which use it to direct access to the aggregated
> > entity. Also not cool.
> >
> > So, what we need is that EntityReference of an aggregated Entity to be
> > invalid if it is not accessed from the AggregateRoot instance.
> >
> > How can we do that, in relatively simple terms?
> >
> > Well, one option could be to create a new composite meta type;
> >
> > public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}
> >
> > And its implementation of UnitOfWorkFactory has two purposes;
> >   1. Only work for types that exists as @Aggregated Associations within
> the
> > same subtype.
> >    2. Manage the EntityReferences to be Aggregate "relative".
> >
> > The second of those is a bit tricky, but effectively needs to provide a
> UoW
> > implementation that leverage the EntityReference of the owning Aggregate.
> > Doable, but tricky.
> >
> >
> > But hold on a second; If the Aggregate is a UnitOfWorkFactory and
> possibly
> > handles its own UnitOfWork, how does this fit with DDD on one hand and
> with
> > the current UoW system on the other hand??
> >
> > Well, with DDD it is a perfect match. The Aggregate is a transactional
> > boundary. So it seems to suggest a good fit. Cool.
> > But, does DDD really tackle this, since you can't get the
> UnitOfWorkFactory
> > of the Aggregate without first having a UnitOfWork to retrieve it with.
> > This seems to suggest that DDD doesn't have it correct, or has made a
> > simplification that is somewhat unfortunate.
> >
> > Could it be that there is actually a difference between the Aggregate
> being
> > a non-Entity composite and the AggregateRoot that is an entity and part
> of
> > the Aggregate??
> >
> > Perhaps...
> >
> > public interface Order extends EntityComposite {}  // back to normal
> entity
> >
> > @AggregateConstraint( CreditLimitConstraint.class )
> > public interface OrderAggregate extends Aggregate<Order> {}
> >
> > meaning
> >
> > public interface Aggregate<T extends EntityComposite> extends
> > UnitOfWorkFactory, Composite
> > {
> >     T root();
> > }
> >
> > (I have place EntityComposite supertypes everywhere, but that is for
> > clarity. Since we don't require that anymore, they shouldn't be there)
> >
> > So, then how would this be used??
> >
> > Aggregate<Order> aggregate = module.newAggregate( Order.class, identity
> );
> >
> > the newAggregate method, would do
> >    a. create Aggregate composite,
> >    b. create a new unit of work
> >    c. read the entity from the store and populate root()
> >    d. if entity doesn't exists, create a entity builder internally and
> use
> > when populating state,
> >    e. keep the UoW open,
> >
> > Since it should handle both existing and new aggregates uniformly, I
> think
> > a
> >
> >     boolean isCreating();   // or similar
> >
> > method should also exist on the Aggregate type.
> >
> >
> > To me, this feels a lot better. The DDD "rules" and "intents" are still
> in
> > effect and can be enforced, and we can manage to implement it in Zest, if
> > we choose to do so.
> >
> > I am really keen on hearing thoughts on this topic.
> >
> > Cheers
>
>


-- 
Niclas Hedhman, Software Developer
http://zest.apache.org - New Energy for Java

Re: Aggregates and AggregateRoots

Posted by Niclas Hedhman <he...@gmail.com>.
I like this idea. It is very Zest-like, in that it is "think outside the
box"... (There is no spoon)

I want to ponder over a little bit.

Cheers
Niclas
On Apr 29, 2016 05:28, "Kent Sølvsten" <ke...@gmail.com> wrote:

Another topic is how to manage the OrderItems inside the Order.

I have an idea ....

You discussed a special UOWFactory as part of the aggregate composite -
what should that UOW be used for? I guess it is just for adding/removing
OrderItems.
Could that be part of the relation?

what if , instead of

        @Aggregated
        ManyAssociation<OrderItem> items();


we have

        ManyAggregation<OrderItem> items();

An aggregation is a relation, similar to the association. But we cannot
add items to it, instead it helps us building new parts.

EntityBuilder<OrderItem> template = items().newEntityBuilder();
template.quantity().set(1);
template.newInstance();  // will automatically be part of the collection

and the later use the aggregation to remove an item.

That is OrderItems are not created independently and then added, instead
they are created directly on the aggregation!

/Kent





Den 28-04-2016 kl. 17:01 skrev Niclas Hedhman:
> Gang,
>
> since we are on the topic of persistence, I have some thoughts that I
would
> like to share.
>
> I think code is the best way to show, and as usual we start with a
usecase.
>
> So, let's say I want to create the classic Order example with OrderItem
> entities (orders can be massively big doh!!! (should really just use
values
> as items)). Any way, so I have the OrderItem
>
> public interface OrderItem extends EntityComposite
> {
>     Property<Integer> quantity();
>     Association<Product> product();
>     Property<BigDecimal> pricePerItem();
>     Property<BigDecimal> discount();
> }
>
> The we have the Order itself...
>
> public interface Order extends EntityComposite
> {
>     Customer customer();
>     BigDecimal totalSum();
>     void addItem( Product p, int quantity, BigDecimal price, BigDecimal
> discount );
>     void removeItem( Product p, int quantity );
>     Iterable<OrderItem> items();
>
>     interface State
>     {
>         Association<Customer> customer();
>
>         Property<ShippingAddress> shippingAddress();
>
>         @Aggregated
>         ManyAssociation<OrderItem> items();
>
>         Property<Boolean> onCredit();
>     }
>
> }
>
> Let's say that we just want to make sure an order doesn't exceed the
credit
> limit of the customer.
>
> For sake of simplicity in this discussion, the current outstanding credit
> is stored in the Customer itself and a simple exposed method for the
> validation.
>
> public interface Customer
> {
>       :
>     boolean hasCreditFor( BigDecimal additional );
>       :
> }
>
> We already have a validation mechanism called Constraints, but they work
on
> input arguments to methods. We need something similar, but work on the
> entire Composite,
>
> public class CreditLimitConstraint
>     implements AggregateConstraint<Order>
> {
>     public boolean isValid( Order order )
>     {
>         if( ! order.onCredit().get() )
>             return true;
>         return order.customer().hasCreditFor( order.totalSum() );
>     }
> }
>
> And we could annotate with a Constraint-like annotation,
>
> @AggregateConstraints( CreditLimitConstraint.class )
> public interface Order extends EntityComposite
> {}
>
> But this doesn't solve the problem. We could have code that queries for
the
> OrderItem instances and manipulates them directly. That is against the
> principle of Aggregates. Or we could hand over a reference of an OrderItem
> to another composite which use it to direct access to the aggregated
> entity. Also not cool.
>
> So, what we need is that EntityReference of an aggregated Entity to be
> invalid if it is not accessed from the AggregateRoot instance.
>
> How can we do that, in relatively simple terms?
>
> Well, one option could be to create a new composite meta type;
>
> public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}
>
> And its implementation of UnitOfWorkFactory has two purposes;
>   1. Only work for types that exists as @Aggregated Associations within
the
> same subtype.
>    2. Manage the EntityReferences to be Aggregate "relative".
>
> The second of those is a bit tricky, but effectively needs to provide a
UoW
> implementation that leverage the EntityReference of the owning Aggregate.
> Doable, but tricky.
>
>
> But hold on a second; If the Aggregate is a UnitOfWorkFactory and possibly
> handles its own UnitOfWork, how does this fit with DDD on one hand and
with
> the current UoW system on the other hand??
>
> Well, with DDD it is a perfect match. The Aggregate is a transactional
> boundary. So it seems to suggest a good fit. Cool.
> But, does DDD really tackle this, since you can't get the
UnitOfWorkFactory
> of the Aggregate without first having a UnitOfWork to retrieve it with.
> This seems to suggest that DDD doesn't have it correct, or has made a
> simplification that is somewhat unfortunate.
>
> Could it be that there is actually a difference between the Aggregate
being
> a non-Entity composite and the AggregateRoot that is an entity and part of
> the Aggregate??
>
> Perhaps...
>
> public interface Order extends EntityComposite {}  // back to normal
entity
>
> @AggregateConstraint( CreditLimitConstraint.class )
> public interface OrderAggregate extends Aggregate<Order> {}
>
> meaning
>
> public interface Aggregate<T extends EntityComposite> extends
> UnitOfWorkFactory, Composite
> {
>     T root();
> }
>
> (I have place EntityComposite supertypes everywhere, but that is for
> clarity. Since we don't require that anymore, they shouldn't be there)
>
> So, then how would this be used??
>
> Aggregate<Order> aggregate = module.newAggregate( Order.class, identity );
>
> the newAggregate method, would do
>    a. create Aggregate composite,
>    b. create a new unit of work
>    c. read the entity from the store and populate root()
>    d. if entity doesn't exists, create a entity builder internally and use
> when populating state,
>    e. keep the UoW open,
>
> Since it should handle both existing and new aggregates uniformly, I think
> a
>
>     boolean isCreating();   // or similar
>
> method should also exist on the Aggregate type.
>
>
> To me, this feels a lot better. The DDD "rules" and "intents" are still in
> effect and can be enforced, and we can manage to implement it in Zest, if
> we choose to do so.
>
> I am really keen on hearing thoughts on this topic.
>
> Cheers

Re: Aggregates and AggregateRoots

Posted by Kent Sølvsten <ke...@gmail.com>.
Another topic is how to manage the OrderItems inside the Order.

I have an idea ....

You discussed a special UOWFactory as part of the aggregate composite -
what should that UOW be used for? I guess it is just for adding/removing
OrderItems.
Could that be part of the relation?

what if , instead of

        @Aggregated
        ManyAssociation<OrderItem> items();


we have

        ManyAggregation<OrderItem> items();

An aggregation is a relation, similar to the association. But we cannot
add items to it, instead it helps us building new parts.

EntityBuilder<OrderItem> template = items().newEntityBuilder();
template.quantity().set(1);
template.newInstance();  // will automatically be part of the collection

and the later use the aggregation to remove an item.

That is OrderItems are not created independently and then added, instead
they are created directly on the aggregation!

/Kent





Den 28-04-2016 kl. 17:01 skrev Niclas Hedhman:
> Gang,
>
> since we are on the topic of persistence, I have some thoughts that I would
> like to share.
>
> I think code is the best way to show, and as usual we start with a usecase.
>
> So, let's say I want to create the classic Order example with OrderItem
> entities (orders can be massively big doh!!! (should really just use values
> as items)). Any way, so I have the OrderItem
>
> public interface OrderItem extends EntityComposite
> {
>     Property<Integer> quantity();
>     Association<Product> product();
>     Property<BigDecimal> pricePerItem();
>     Property<BigDecimal> discount();
> }
>
> The we have the Order itself...
>
> public interface Order extends EntityComposite
> {
>     Customer customer();
>     BigDecimal totalSum();
>     void addItem( Product p, int quantity, BigDecimal price, BigDecimal
> discount );
>     void removeItem( Product p, int quantity );
>     Iterable<OrderItem> items();
>
>     interface State
>     {
>         Association<Customer> customer();
>
>         Property<ShippingAddress> shippingAddress();
>
>         @Aggregated
>         ManyAssociation<OrderItem> items();
>
>         Property<Boolean> onCredit();
>     }
>
> }
>
> Let's say that we just want to make sure an order doesn't exceed the credit
> limit of the customer.
>
> For sake of simplicity in this discussion, the current outstanding credit
> is stored in the Customer itself and a simple exposed method for the
> validation.
>
> public interface Customer
> {
>       :
>     boolean hasCreditFor( BigDecimal additional );
>       :
> }
>
> We already have a validation mechanism called Constraints, but they work on
> input arguments to methods. We need something similar, but work on the
> entire Composite,
>
> public class CreditLimitConstraint
>     implements AggregateConstraint<Order>
> {
>     public boolean isValid( Order order )
>     {
>         if( ! order.onCredit().get() )
>             return true;
>         return order.customer().hasCreditFor( order.totalSum() );
>     }
> }
>
> And we could annotate with a Constraint-like annotation,
>
> @AggregateConstraints( CreditLimitConstraint.class )
> public interface Order extends EntityComposite
> {}
>
> But this doesn't solve the problem. We could have code that queries for the
> OrderItem instances and manipulates them directly. That is against the
> principle of Aggregates. Or we could hand over a reference of an OrderItem
> to another composite which use it to direct access to the aggregated
> entity. Also not cool.
>
> So, what we need is that EntityReference of an aggregated Entity to be
> invalid if it is not accessed from the AggregateRoot instance.
>
> How can we do that, in relatively simple terms?
>
> Well, one option could be to create a new composite meta type;
>
> public interface Aggregate extends EntityComposite, UnitOfWorkFactory{}
>
> And its implementation of UnitOfWorkFactory has two purposes;
>   1. Only work for types that exists as @Aggregated Associations within the
> same subtype.
>    2. Manage the EntityReferences to be Aggregate "relative".
>
> The second of those is a bit tricky, but effectively needs to provide a UoW
> implementation that leverage the EntityReference of the owning Aggregate.
> Doable, but tricky.
>
>
> But hold on a second; If the Aggregate is a UnitOfWorkFactory and possibly
> handles its own UnitOfWork, how does this fit with DDD on one hand and with
> the current UoW system on the other hand??
>
> Well, with DDD it is a perfect match. The Aggregate is a transactional
> boundary. So it seems to suggest a good fit. Cool.
> But, does DDD really tackle this, since you can't get the UnitOfWorkFactory
> of the Aggregate without first having a UnitOfWork to retrieve it with.
> This seems to suggest that DDD doesn't have it correct, or has made a
> simplification that is somewhat unfortunate.
>
> Could it be that there is actually a difference between the Aggregate being
> a non-Entity composite and the AggregateRoot that is an entity and part of
> the Aggregate??
>
> Perhaps...
>
> public interface Order extends EntityComposite {}  // back to normal entity
>
> @AggregateConstraint( CreditLimitConstraint.class )
> public interface OrderAggregate extends Aggregate<Order> {}
>
> meaning
>
> public interface Aggregate<T extends EntityComposite> extends
> UnitOfWorkFactory, Composite
> {
>     T root();
> }
>
> (I have place EntityComposite supertypes everywhere, but that is for
> clarity. Since we don't require that anymore, they shouldn't be there)
>
> So, then how would this be used??
>
> Aggregate<Order> aggregate = module.newAggregate( Order.class, identity );
>
> the newAggregate method, would do
>    a. create Aggregate composite,
>    b. create a new unit of work
>    c. read the entity from the store and populate root()
>    d. if entity doesn't exists, create a entity builder internally and use
> when populating state,
>    e. keep the UoW open,
>
> Since it should handle both existing and new aggregates uniformly, I think
> a
>
>     boolean isCreating();   // or similar
>
> method should also exist on the Aggregate type.
>
>
> To me, this feels a lot better. The DDD "rules" and "intents" are still in
> effect and can be enforced, and we can manage to implement it in Zest, if
> we choose to do so.
>
> I am really keen on hearing thoughts on this topic.
>
> Cheers