3

I've got two cases where I can use whether an id of an Entity or pass it as reference.

1) Domain Services. Example:

class ProductService {
     public void changePrice(Product product, long newPrice) {
          // significant calculations involving several Entities here...
     }
     // versus
     public void changePrice(long productId, long newPrice) {
          Product product = productRepository.get(productId);
          // significant calculations involving several Entities here...
     }
}

2) Entity. Example:

class Order {
    public void addItem(Product product, long quantity) {
        // do stuff
    }
    // versus
    public void addItem(long productId, long quantity) {
        Product product = Registry.productRepository().get(productId);
        // do stuff
    }
    // or even maybe this ugly version?
    public void addItem(ProductRepository productRepository, long productId, long quantity) {
        Product product = productRepository.get(productId);
        // do stuff
    }
}

Which approach is better and why?

Alexey Balchunas
  • 400
  • 3
  • 10

1 Answers1

2

I like the Onion Architecture view of how to conceptually think about how to protect your domain from outside influences.

IMO, keeping the repositories outside of the domain is best. Let the layers outside of the domain resolve domain entities and then inside the domain use them.

So, I obviously would rather see the examples that use Product directly (Reference). A repository's implementation is not in the domain. The domain should not be cluttered with ids, configuration, or persistence. It should instead focus on the domain problem directly and with as much clarity as possible.

Davin Tryon
  • 66,517
  • 15
  • 143
  • 132
  • 2
    +1 for mentioning the Onion Architecture. But I disagree with the repository not being part of the domain. The interface of the repositories should be defined inside the domain. The implementations are an outside concern. That being said, the repository interfaces being defined as part of the domain should use the Ubiquitous Language, i.e. not being called anything like `ProductRepository` or `ICustomerRepository` but rather `Products` or `VIPCustomers`. – Dennis Traub Sep 15 '14 at 19:35
  • @DennisTraub Thanks for the comment. I've made a little update to your point. – Davin Tryon Sep 15 '14 at 20:21
  • In this case there is a problem I can think of. Let's say I do some validation on the Order against the Product. In that case the client of the domain can easily pass a Product that is valid and change it making the Order invalid. I started thinking that if you need the whole reference, there is a chance that you just need a deeper Aggregate (with Product inside) or define an operation in Domain Services (which should accept id rather than reference for the same reason). – Alexey Balchunas Sep 16 '14 at 06:25
  • or there is just a modelling problem here (maybe I shouldn't want to do such sort of validation). – Alexey Balchunas Sep 16 '14 at 06:31