Consider the domain entity, Order, which can be persisted by the OrderRepository. Orders maintain state that is stored in the database. However, it does not expose all of it directly. That is, parts of its private state is not accessible in the repository, when it should be mapped to database records. How does one go about allowing the repository access to this while restricting it for the rest of the domain?

AutoMapper and the like is not an option. Moving the repository to a separate project and declaring the members internal instead of private is not an option either.

1

The problem here is that several guidelines which can be argued to be good advice (individually) simply contradict one another when combined. This isn’t a failing of the individual guidelines, it’s more that you can’t always have your cake and eat it too.

If you subscribe to truly encapsulating everything about your domain objects that you can make private, then you inherently choose to make this information unavailable to other layers. When you’ve chosen to do so, it’s an inevitable fact of life that your persistence layer cannot read this encapsulated state.

If you keep this data private, then by logical definition only that domain model can ever use the data to persist it. This would mean that your domain needs to occupy itself with persisting its state, which means that the domain would depend on the persistence mechanic, which starts violating the other guideline whereby the domain does not depend on anything.

Simply put, if the domain hides all of its private details and the domain does not depend on anything, then the privates are truly private and no one can do anything with them.

This is an impasse. How you resolve this impasse is up to you, based on which of these conflicting constraints you’d prefer to loosen.

Personally, I take one of two stances:

  • In general, I avoid true privacy and make these values at least publically readable (not writable). Not necessarily every value, but at least the ones that are reasonably needed for sensibly persisting the domain object.
  • In specific use cases, I’ll design a properly encapsulated domain model and a mirrored “public DTO” model which essentially stores the same data but makes it all publicly gettable and settable. I allow the domain model to convert itself to this DTO. This way, you can work with your encapsulated domain model, but you can make a “snapshot” of this model in a way that it can easily be persisted.

The second bullet point I really only do for cases where the inner state is so complicated that making it public would significantly hamper a dev who’s relying on IntelliSense to only use the “true public” features. It’s not very common that I need to resort to this but it very much depends on how complex you allow your domain models to become.

1

Besides a getter method, I believe having private properties usually means you’re going to ask the object to do things for you, because it has knowledge of its internals (a principle called Tell, Don’t Ask, although not everyone who uses private properties wants to apply the principle): so you’d have a method in your entity for returning a DTO for the repository (like a factory method); but beware this is not DDD-friendly, because it violates the idea of the domain knowing nothing about external layers.

6

If you want to keep your actual state private, you can consider event sourcing the aggregate. That way you don’t persist the current state, but all events that happened in the lifetime of the aggregate. This means you don’t need any public properties, you only expose events. To load the current state, pass a list of all previous events to the aggregate.

There are various resources how to do this, but note this requires quite a different architecture than most people are used to. You will probably want to combine this with separate read-models, for example, to ensure read performance.

2

Writing information to /dev/null is a waste of everyone’s time.

If you are going to have entities whose lifecycles extend beyond a single executable session, then you need to have some mechanism for copying information from the transient data representation to a durable data representation, and vice versa.

The most straight forward approach is to use the Factory pattern (as described in Chapter 6 of the blue book). The obvious variation is described there – our persistence layer has some information, and we pass that information to a factory, and it returns to us a handle to a transient entity assembled from that information.

The same variation works in reverse – we pass a factory to the domain entity, the domain entity passes a copy of its transient data to the factory, and then returns to the caller whatever the factory produced.

In a language with generics, your design might look like

public class Order {
   public interface SomeFactory<T> {
       T build(OrderId id, Array<LineItems> items);
   }

   public <T>
   T verb(Order.SomeFactory someFactory) {
       return someFactory.build(this.id, copy(this.items));
   }
}

Then, at some location convenient to your OrderRepository, you create an implementation that extends Order.SomeFactory and uses the information to produce a representation of the information that you need to store the data correctly.


Note: you won’t find anything like this in the blue book, as far as I can tell, because (a) Evans was assuming O/RM and (b) at the time it was written Java didn’t have generics.

3