Curing domain model anemia with effective and clean tips from the real world

Abstract

The speaker is suggesting some options to prevent anemic objects with simple and effective methods:

  • Avoid primitive obsession, i.e. create classes to represent the domain models (e.g. OrderNumber, Money, etc…).
  • Differentiate value objects from entities.
    • Value objects are equals based on the value of their content.
    • Entities may be equals even if some of their properties have changed, e.g. a Person is an entity and can have their attributes changed, like changing their first name.
  • Create invariant to ensure the domain objects are valid throughout the whole flow.
  • Avoid anything that can change the internal data of the rich domain object.
    • No setters (unless the framework makes it mandatory).
    • Return immutable collection.
    • Prefer having explicit methods that tell the consumer what it does, e.g. applyDiscount.
  • Prefer static factories to constructor.
    • This can give some flexibility in case we want to extend the class in question to several flavors, i.e. we would only change at this static constructor, compared to the constructor.
  • Add some persistence annotation to represent how the object is represented in the persistence layer, i.e. use @Entity, @Id, etc…

Reviews

2024-09-28

Why did I want to read/watch this? I mostly use the “classic” way of designing my project: with immutable value objects and entities, and use some “service” classes that will perform the operations on the domain objects. I got some feedback that using rich domain objects may be better in the long run, thus looking for such type of resources.

What did I get out of it? Quite an interesting topic, and I mostly concur on his explanations. However, there are still some points I’m not quite in phase:

  • Putting persistence annotations directly in the domain objects, i.e. polluting infrastructure details in the domain models.
    • Sure enough, by adding the persistence annotations directly in the domain models will avoid us to implement a second entity and mapper (so some overhead). But, by doing so, we are having some coupling between the model in the domain layer and the entity in the persistence layer. That means that the persistence layer may influence the domain layer and pollute with implementation details, e.g. we have to change the data model in the database to improve some performance.
  • Always using static factories to create the objects is a bit weird for me as:
    • java has some performance improvement to use constructors,
    • most of the case, the models are rarely changed in the way he described, i.e. transforming into an interface, so we mostly do not encounter his situation.
  • The speaker is speaking highly of the library Guava, which I avoid at all cost.

It’s a shame the presentation was too short to demonstrate how those rich domain objects are manipulated without any service objects, how the port are injected, etc… as I still struggle to understand how everything is interlocked. Maybe I’m still too inexperienced in this way of designing a project?