0

I would like to model the following entities: "Person", "Company" and the aggregate that ties the two together "Membership". I have identified that Person and Company are aggregate roots. Thus, "Membership" would hold a reference (id) of both those aggregate roots, plus other value objects/entities that a membership holds (for example the title that the person has for that company).

In my architecture I have the following layers: Api controllers, services, domains, repository. When creating a Membership object, the controller receives two identifiers (for person and for company). Currently the service is responsible for making a call to the CompanyService - to ensure that a company with that id exists and to the PersonService - to ensure a person with that id exists. However, in the Domain model I currently have a constructor that takes in two ids, which makes it feel really anemic. Also, in a further iteration, there will be the addition of a list of references to a third aggregate root, Vehicle. Thus a vehicle can exist by itself, or it can also belong to a membership.

Is this a bad way of modelling these entities? Is there a better way? I have read about the notion of domain services and application services, but my application does not currently have that distinction and I don't know if that concept would help in this case.

Even the behaviour of the aggregate roots feels a bit dry when it comes to functionality related to the other aggregate roots it holds references for: ie. the Membership domain model would have the ability to "Link a car", setting a car for itself, but again, receiving just an identifier that it would add to a list of identifiers.

  • The notion that aggregates must only reference other aggregates by ID comes from, or was popularized by, Vaughn Vernon (i think); now, that probably works well for him, but IMO it is a mistake to present this as mandatory, as people face different kinds of problems, and work with different kinds of systems. Evans' original notion of an aggregate is more that it's a bunch of collaborating objects, with the AR acting as an (encapsulating) Facade to them all, while making sure that invariants are maintained within. It's a model element that's a larger organizational unit than class/object. (1/2) – Filip Milovanović Jun 27 at 17:46
  • Vaughn Vernon emphasizes that aggregates define a transactional boundary, but in some cases that view is too DB-centric. It's supposed to be a conceptual consistency boundary, and you may chose to translate that into actual code in different ways. And you can have nested aggregates, and references going out of an aggregate (or you may chose not to make a distinction between the two); you define these boundaries very deliberately, to your advantage (rather then following some generic rule or best practice), and organize domain behavior around these boundaries. (2/2) – Filip Milovanović Jun 27 at 17:47
  • @FilipMilovanović You haven't thought through your position thoroughly enough. The only conceivable purpose for one aggregate (A) to directly reference another aggregate (B) would be to allow for the former to invoke a method on the latter as part of it's own process (an aggregate's state is private after all). That is, the method body of A->doSomething would invoke B->doAnotherThing. This is not useful and can be refactored to A->doSomething(B). – king-side-slide Jun 28 at 16:22
  • @FilipMilovanović Systems are deterministic. Given the inputs we will know which entities are required to carryout a use-case. A and B can be loaded independently and coordinated to achieve the above. The result is a cleaner (simpler) system. – king-side-slide Jun 28 at 16:26
  • Are you sure Membership is the right name here? DDD asks you to model a system according to behavior. Notably, the above contains a lot of "this has that"-type phrases in lieu of "this does that"-type phrases. Of course this will lead to an anemic model. I'll leave you with some food for thought: When I (Person) joined my golf course (Company) I became a Member that can reserveGolfCart. – king-side-slide Jun 28 at 16:38
0

in the Domain model I currently have a constructor that takes in two ids, which makes it feel really anemic.

As you described, a membership ties together a person and a company. The important pieces here are the concept of a person and a company, not the specific object used to represent them. In that regard, PersonId and CompanyId are just as good (and more lightweight) than Person and Company. Is there any significant benefit in having the complete entity objects rather than just their IDs? And how does that trade off with the performance impact of having to load that additional data?

Using IDs to represent entities does not make a model anemic. What is important is to make sure that business rules and constraints do not leak out of domain objects.

I have read about the notion of domain services and application services, but my application does not currently have that distinction

Your controllers are effectively application services since they orchestrate the execution of business logic (look up aggregates by ID and invoke methods on them).

the Membership domain model would have the ability to "Link a car", setting a car for itself, but again, receiving just an identifier that it would add to a list of identifiers.

Once again, this is perfectly fine since the concept of "linking a car" is modeled in the Membership object. What would make this anemic, for example, is adding to the list directly in your controller, because that masks the fact that it is a domain concept.

  • Thank you for your answer :) – Mike Jul 2 at 8:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.