Aggregate boundaries in ddd

The actual question is to determine the boundaries of the aggregate.

Imagine that there is an entity called packaging, and the packaging includes some resources. The package itself can be created in a separate section, and when we create it, we add resources to it. It seems that everything is clear, the packaging is an aggregate, the packaging resource is an entity. But there is a separate section for shipment, we can ship several packages within the same document for shipment. Also, when at the same time, as part of creating a new document for shipment, we can not only select already created packages, but also create new ones. Moreover, in theory, all this should be stored within a single transaction, so it turns out that the document for shipment is an aggregate, and the packaging in it is an entity. But, it seems like aggregates should not contain other aggregates and should only store links to them by id. It turns out like, we have to pull out several aggregates already, within the framework of it would seem one.

Still, what is the best way to act in such cases? Eric Evans wrote about bounded contexts, M. B. are these aggregates in different bounded contexts?

1 answers

Of course, there can't be an aggregate in another aggregate.

It happens that the first object contains the second; and it happens that the first object refers to the second.

How to distinguish it? Not easy. The difference is not formal - contains or references depends on the subject area and its requirements.

In one subject area, the wheels will be part of the car, and then the car with wheels is the unit, the wheels are the entities, and the car is the root the entity.

But in the other one, it turns out that both the wheels and the car require separate accounting, and here the wheel entities will contain a reference to the car entity.

As is often the case in DDD, to understand it, you need to look at the use cases or user stories. If in all scenarios the entities only occur together, they form an aggregate. Surely one of them has a special position, because through it you can get everything the others. It is called theroot of the aggregate.

It is aggregates that return repositories. If the package is an aggregate, the program will have a storage (repository) of packages that can load the package by its ID.

But what if the aggregates are kind of trying to become part of another aggregate? If the package is without a document, then it is an independent unit.

To link them, we go to a higher level - to services (services). Services are classes that represent processes in an object-oriented program. Unlike entities, they have no state. Their methods reflect the individual steps of multi-step processes. And they are the ones who know how to link aggregates by calling repository methods.

Your program may have a shipping service, say ShippingService, that can link documents and packages. If it is a reference, not a content, the aggregates store each other's IDs. The document stores a list package IDs, and the package is the document ID.

Repositories can contain download methods that rely on links. For example, a package repository can provide a method for loading all packages by document ID.

UPDATE

Add-on to answer the question from the comment. Let's talk about application levels. The classical three-tier model assumes the presence of levels 1) representation, 2( subject area, and 3) data access. Evans made two changes to it. He called the data access layer the infrastructure layer , and added a fourth application layer between the view and the subject area.

There is a serious problem with this level, because its purpose is not obvious. I think this happens because it only makes sense in large systems, where the domain level begins to grow at the expense of a variety of services.

Let us look at the translation of Evans ' book, p. 109:

But to distinguish the SERVICES of the operational level from the level of the subject area (models) can be more difficult. The operational level is responsible for giving the order to notify the client. And the model level determines whether the threshold is reached - however, this task does not require a separate SERVICE, but rather, it is part of the authority of the "bank account"object. The same banking program may also be involved in the transfer of funds. If you construct a SERVICE that is responsible for summing up the debit and credit in the transfer process, then it will belong to the subject area level. Money transfer is a semantic element of banking, and its implementation is a fundamental operation of the subject area. In technical services, however, such concepts of the application model should not be mentioned at all.

Many model-level and application-level services are built on the basis of collections of ENTITY OBJECTS and VALUE OBJECTS. They behave like scripts that THEY MOBILIZE the potential of the subject area to do something useful. The ENTITIES and VALUES themselves are often too small-scale to give the user convenient access to domain-level capabilities. Can note that the line between the levels of the domain and the application operations is very narrow. tonka. For example, if a banking program is able to convert and export all our financial transactions to a spreadsheet file (so that we can read it and analyze), then the SERVICE of such export belongs to the level of application operations. In the subject area of banking, there are no "file formats", and the logic of the application model is also not used here.

I've highlighted the important parts. My suggestion is not to create an application (operational level at all) at the beginning of development. Business scenarios that only have enough entities, value objects, regulations, and repositories to work with should be implemented in the subject area layer. areas. When it comes to file formats, window handles, HTTP request headers - make these services part of the presentation.

Do it in the form of classes, and not in the form of interfaces that need to be implemented. Here interfaces are not needed and only complicate the work. The presentation level sees the domain level directly - it's just a project-to-project dependency, so you can create a class of services and entities directly if you want, although it's more convenient to use containers. IoC due to complex constructors.

Interfaces are only needed for infrastructure-level services, because there you need to invert the dependency. Classically, the dependencies between the levels go up and down, but if you do this, then with any change in the infrastructure (database, SMS or email sending service) we will have to change the levels above - domain, application, and presentation.

That is why the email sending service or repository is present in the subject area areas in the form of interfaces, and is implemented in the infrastructure layer.

From your comment, I understand that in your case we are talking about a domain service. Just make it a class and call its methods from the domain level, without creating additional interfaces.

 3
Author: Mark Shevchenko, 2019-12-05 07:41:29