Aggregate or entity without business attributes

梦想与她 提交于 2020-01-25 01:21:17

问题


Regarding below excerpt, concerning cqrs and ddd, from Patterns, Principles, and Practices of Domain-Driven Design by Nick Tune, Scott Millett

Does it mean that domain model on command side can omit most of business attributes ? How would it look like for eg Customer Entity?

Could Customer entity omit FirstName, Surname etc? If so, where would these business attributes be? Only in read model in CustomerEntity?

Or maybe apart from CustomerEntity containing all business attributes there would also be CustomerAggregate wrapping CustomerEntity with 1:1 relation, and command object would operate on CustomerAggregate? (seems strange to me).

What does it mean "Customer entity desn't make sense"?


回答1:


The text you pointed means that you do not have to model a reusable Entity for your whole system or even for your whole bounded context (Do not model reusable real life things). Doing this is a bad design.

You have to model an Aggregate that performs an action. You feed the Aggregate with only, and just only, the data needed to perform that action and the aggregate response, the changes the domain suffered, is what you have to persist.

Why Entities and V.O.'s then?

To model consistency, encapsulation and decoupling is the basic part but these are implementation details. For DDD what matters is that are different roles (or concepts).

When feeding the aggregate (constructor, function call parameters, etc) the aggregate has to know if it is working with entities and/or with V.O. to build its response.

If the domain action means a change in an attribute of a entity (something with unique identification in your whole system) the response of the aggregate (once all rules and invariants has been checked) should include the new attribute value and the identification of that entity that allows persist the changes.

So, by default, every aggregate has its own entity with the unique identification and the attributes needed for the aggregate action.

One aggregate could have a Customer entity with ID and its Name. Another aggregate could have a Customer entity with ID and its Karma points.

So every aggregate has its own inner Customer entity to work with. When you feed an aggregate you pass Customer data (i.e. ID and name or ID and Karma points) and the aggregate treats that info as a entity (It is a matter of implementation details if there is a struct, class, etc internally to the aggregate to represent the entity).

One important thing: If you just need to deal with entities ID's then treat it as a V.O. (CustomerIdentityVO) because the ID is immutable and, probably, in that action you just need to write this CustomerIdentityVO in some field in persistence, not change any Customer attribute.

This is the standard vision. Once you start to identify common structures relevant to several aggregates or one aggregate that can perform several actions with the same data fed you start to refactoring, reusing, etc. It just a matter of good OOP design and SOLID principles.

Please, note that I am trying to be higly above of implementation details. I know that you almost always will have unwanted artifacts that depends of programing paradigm type, chosen programing language, etc. but this approach helps a lot avoiding the worse artifact you could have.

Recommended readings:

http://blog.sapiensworks.com/post/2016/07/29/DDD-Entities-Value-Objects-Explained http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1 http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2 https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3

and

https://blog.sapiensworks.com/post/2016/08/19/DDD-Application-Services-Explained

for a complete puzzle vision.




回答2:


If you are using Event Sourcing then it's true that you can model aggregates without adding attributes that they don't need for implementing the business logic.

Here's an example:

class Customer {

    public Guid ID { get; private set; }

    public Customer(Guid id, firstName, lastName, ...) {

        ID = id;

        this.AddEvent(new CustomerCreatedEvent(id, firstName, ....);
    }

    public void ChangeName(firstName, lastName) {
       this.AddEvent(new CustomerRenamedEvent(this.ID, firstName, lastName), 
    }
}

Custom only has ID attribute because it needs it to add it to every event that it generates. FirstName and LastName are omitted as they are not needed even when ChangeName method is called. It only records an event that this happened. If your logic requires the FirstName then you can add it. You can omit any properties that you don't need.

Your Repository in this case will save only the events and won't care about the values of the attributes of the Customer.

On the Read side you will probably need these properties as you will display them to your users.

If your aggregates are not event sourced, then you probably will need more attributes on your aggregate to implement it's logic and they will be saved to the database.

Here's an example:

class Customer {

    public Guid ID { get; private set; }
    public string FirstName { get; private set; }
    public string LastName { get; private set; }

    public void ChangeName(firstName, lastName) {
       FirstName = firstName;
       LastName = lastName;
    }
}

In this case your Repository will need these properties as it will generate a query to update the database with the new values.

Not sure what "Customer entity doesn't make sense" means.



来源:https://stackoverflow.com/questions/55890854/aggregate-or-entity-without-business-attributes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!