DDD, dependency handling

Boring introduction:

I know - DDD is not a technology. As I see it, DDD is the creation of an omnipresent language with the owner of a product and its reflection in the code in such a simple and structured way that it is simply impossible to interpret or lose.

But here comes the paradox in the game - to get rid of the technical side of the application in the domain model, it becomes good technical - at least in terms of design.

The last time I tried to keep an eye on DDD, it ended with a whole logical interface outside the domain objects in the "magic" services around the world and an anemic domain model.

I learned a few new ninja tricks and am wondering if I can deal with Goliath this time.


Problem:

class store : aggregateRoot { products; addProduct(product){ if (new FreshSpecification.IsSatisfiedBy(product)) products.add(product); } } class product : entity { productType; date producedOn; } class productTypeValidityTerm : aggregateRoot { productType; days; } 

FreshSpecification should indicate if the product does not smell. To do this, he must check the type of product, find the days on it, how long the product has been fresh, and compare it with producedOn . Good is simple.

But here a problem arises - productTypeValidityTerm and productType must be managed by the client. He should be able to freely add / modify them. Since I cannot directly switch from product to productTypeValidityTerm , I need to somehow request their productType .

Previously, I would create something like ProductService , which receives the necessary repositories through the constructor, query terms, executes some additional voodoo and returns a boolean value (taking the appropriate logic further from the object itself and scattering it, who knows where).

I thought it would be acceptable to do something like this:

 addProduct(product, productTypeValidityTermRepository){...} 

But then again - I could not compile a specification from several specifications under freely, which is one of their main advantages.

So - the question is where to do this? How to store information about terms?

+7
inversion-of-control domain-driven-design
source share
1 answer

At the risk of oversimplification of things: why not make the fact that the Product fresh something that the product “knows”? A Store (or any other kind of related object) does not need to know how to determine if a product is still fresh; in other words, the existence of something like freshSpecification or productTypeValidityTerm should not be known to the Store , it should just check Product.IsFresh (or perhaps some other name that better aligns with the real world, e.g. ShouldbeSoldBy , ExpiresAfter , etc. d.). Then the product could know how to actually get protductTypeValidityTerm by introducing a repository dependency.

It seems to me that you are an externalizing behavior that should be integral to your aggregates / entities of your domain, and ultimately leads (again) to an anemic domain model.

Of course, in a more complex scenario, where freshness depends on the context (for example, what is acceptable in a budget store is not considered worthy for sale in a premium store), you will need to externalize all the behavior, both from the product and from the store, and create another type for modeling this particular behavior.

Added after comment

Something in these lines for the simple scenario I mentioned: make FreshSpec part of the Product aggregate, which allows ProductRepository (the constructor introduced here) (lazy) to load it if necessary.

 public class Product { public ProductType ProductType { get; set; } public DateTime ProducedOn { get; set; } private FreshSpecification FreshSpecification { get; set; } public Product(IProductRepository productRepository) { } public bool IsFresh() { return FreshSpecification .IsSatisfiedBy(ProductType, ProducedOn); } } 

The store does not know about these internal components: all he cares about is a fresh product:

 public class Store { private List<Product> Products = new List<Product>(); public void AddProduct(Product product) { if (product.IsFresh()) { Products.Add(product); } } } 
+2
source share

All Articles