Object-oriented – Relations between entities in DDD

domain-driven-designobject-orientedPHP

I am a beginner on DDD, working around small, simple domains in order to get my head on all the principles of design.

I have this simple domain: institutions (Institution) and their available WiFi spots (Place) are kept in the database. No place can exist without an institution. Institution has manager user – assignee (User), which has the right to add new places, reallocate or delete existing ones.

Code can be found here. The validation on value objects is left behind for now.

This is influenced by Mathias Verraes on child entities.

Is it a correct DDD design? or at least close to it?

While being a data-centric programmer, I still wonder how would I list all the places for all the Institutions, if the rule of thumb is accessing aggregates through the aggregate root?

Is the idea of generating Uuid inside of the entity itself (Place::create) good?

Should an idea, that only assignee (User) can add/remove places be expressed on the domain itself or should it be the responsibility of client? In this case it would be wise if the assignee would know about his managed institution (institutionId in User?).

Isn't the Institution::placeById breaking any principles of DDD? Maybe it is the responsibility of the repository?

Best Answer

Is it a correct DDD design? or at least close to it?

It seems ok, though I find the naming "places" as WiFi spots a bit confusing.

While being a data-centric programmer, I still wonder how would I list all the places for all the Institutions, if the rule of thumb is accessing aggregates through the aggregate root?

You have to go thru the aggregate root to get its list of places, e.g. getPlaces(). You may use the returned places for the duration of the current transaction or inquiry, and, in the next transaction or inquiry, start over from the aggregate root to reach the tasks.

Is the idea of generating Uuid inside of the entity itself (Place::create) good?

Not especially. While a UUID is appropriate for aggregate roots, it is not really appropriate for child aggregates (i.e. not roots).

As you can see in the example you're citing, the child aggregates use a simple counter mechanism for their id's instead of a UUID. This counter is per-aggregate root, which is to say that one aggregate root's child id entries are allowed to overlap with another aggregate root's child id's.

In essence, this demands that for long term capture, a must client (also) captures the aggregate root id, and, the implementation doesn't have to generate UUID's for the various child entities.

Should an idea, that only assignee (User) can add/remove places be expressed on the domain itself or should it be the responsibility of client?

No, generally speaking business logic like this should be validated in the domain itself and not left (solely) to the client.

Isn't the Institution::placeById breaking any principles of DDD? Maybe it is the responsibility of the repository?

The responsibility of the repository is to provide persistence for the domain model. So, there is some responsibility there regarding storing of places of institutions. However, ideally, the client speaks with the domain and not the domain's repository directly as its repository is implementation detail private to the domain.

Repositories tend to be fairly primitive and the idea is that we try to layer things. The domain provides a business layer that is a wrapper around the more primitive persistence layer.

Each layer should provide the next programmer (its client) with a coherent, usable, safe, and complete abstraction. When we do this, coupling is reduced, and maintainability is enhanced. Using a layered design, it is a negative indication when a client reaches around our abstraction and touches underlying implementation (lower layers) directly -- this indicates the abstraction is incomplete, and, the client is inappropriately using knowledge of the implementation details of the layer providing the abstraction.