Home > Software engineering >  In DDD What is the correct approach to return a list from domain object?
In DDD What is the correct approach to return a list from domain object?

Time:06-18

I am trying to understand DDD. Infact it looks I have some missing points on OOP. Let's think that we have a domain model called Product. Based on OOP, data and behaviour must be hold together. Example maybe wrong but data and behavior are together below.

public class Product
{
    public Guid Id { get; set; }
    public double TaxRate { get; set; }
    public double Price { get; set; }
    public double GetFinalPrice()
    {
        return Price * TaxRate;
    }
}

Let's think that we need to fetch all products in a category, in this case should I add a method in Product class to return all products in a category? It doesn't look good to me, because a GetProducts behaviour cannot be in Product object.

In this case should I create a CategoryProductFetcher object and add a method Fetch for behaviour?It also sounds wrong because I will have a class for all list methods.

Could you help me about the concept or any documents that explain this? I read lots of article but all are to basic and not explaining more.

Thanks in advance

CodePudding user response:

You may need to look up some additional concepts from DDD:

  • Aggregate
  • Application Layer
  • Repositories
  • CQRS

An aggregate can only be responsible for behaviour within the aggregate. Specifically, a 'Product' aggregate (singular) can only be responsible for what goes on within that instance of a Product. It should not be responsible for retrieving other products for you.

Repositories are the intermediaries between your application layer and data storage. They provide means of retrieving aggregates ready for a command to be executed on them. They also provide means of adding new aggregates to your data storage.

The application layer will retrieve aggregates from repositories and then ask the aggregate to perform functionality WITHIN the boundary of that single aggregate instance.

CQRS is the idea that your classes in a domain model are responsible for implementing the logic within a command use case. A command use case is one that changes the state of the existing data.

CQRS then suggests that your queries should take a different path (not thru your domain objects). For example, your query module may query the database directly and project that data into DTOs for return to the client.

Asking a repository to retrieve a specific aggregate should be done performing a write operation on the same. That means, repositories should be optimized for write operations when retrieving and performing operations on aggregates than need to execute business logic and adhere to business invariants. Thus data shall be only changed through single transactions on aggregates and those aggregates shall be persisted through their respective repository.

Queries on the other hand should be optimized for read operations and can and should bypass repositories as well as aggregates and retrieve data needed for the respective use case that does not involve changing data. This data can also be combined from different aggregates.

For instance, changing a product should happen through the product aggregate's provided operations (methods) and then again be persisted through the aggregate. If, for instance, you just need to display a list of product information of a respective category go through queries that are optimized to retrieve just the data you need for that use case. As repositories are always loaded completely to make sure all business rules can performed correctly when changing the same repositories are not suited for retrieving a large amount of aggregates and the read optimized queries should be used instead.

Reading Material:

  • Related