Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly design model's calculated fields in DDD? [closed]

I am becoming a big fan of DDD. So, I'm thinking of applying it correctly to my current system I develop.

Suppose we have two aggregate roots: Order and User. Order has two properties, referencing the User: owner and contractor. Owner created an Order, contractor fulfilled it.

Owners can rate the quality with which the Order was fulfilled by the contractor. So we have an Feedback entity, connected to Order, containing rating.

Now, User object contains an average rating of each user across the orders he fulfilled. And this part confuses me a little.

User rating is not just a static property, but actually an average of all ratings across Feedbacks. And it is changed (needs to be recalculated) at the moment an Order has Feedback attached.

Currently I have some services encapsulating domain logic: OrderService and UserService (I know this is actually not in compliance with DDD, but I will refactor that later). When OrderService receives a command to attach Feedback to order, it emits OrderFeedbackAttachedEvent which UserService listens for to recalculate user rating.

What doesn't satisfy me is that the knowledge about Order aggregate root is now leaked into UserService. And I don't see the way to escape it. I'm starting to think there should be some pattern to handle such cases.

Rating seem to be a perfect property of the user. But the fact that it is not a static, persistent value, but rather something, that is calculated based on other objects data, makes me doubt.

Rating isn't itself an entity either. Neither it is a value object. What is it, I wonder, in DDD? And how do I model ratings (or any other calculatable value) in my system without sacrificing performance and ease of use)?

like image 497
Vladislav Rastrusny Avatar asked Nov 11 '15 11:11

Vladislav Rastrusny


People also ask

What is tactical design DDD?

Tactical DDD is when you define your domain models with more precision. The tactical patterns are applied within a single bounded context. In a microservices architecture, we are particularly interested in the entity and aggregate patterns.

What is invariants in DDD?

In DDD, validation rules can be thought as invariants. The main responsibility of an aggregate is to enforce invariants across state changes for all the entities within that aggregate. Domain entities should always be valid entities. There are a certain number of invariants for an object that should always be true.

What are the strategies in extracting and formulating domain specific design principles?

Thus, we have developed three strategies for extracting and formulating domain-specific design principles: (1) analyze the best hand-designed visualizations in the domain, (2) examine prior research on the perception and cognition of visualizations, and, when necessary, (3) conduct new user studies that investigate how ...


2 Answers

It appears you might have at least 2 separated bounded contexts: one for ordering, and another for feedbacks.

Aknowleging Bounded Contexts allows you to see different abstractions of the same physical thing: in the "orders" context, Order seems to be a legitimate Aggregate, but it could be a Value Object in the "feedback" BC, where it would hold an order id (which value comes from the order BC through an event).

Here is a proposal :

enter image description here enter image description here

With this model, you would calculate the average rating of a contractor when handling the "FeedbackEmitted" event from the feedback aggregate in an event handler of the contractor aggregate

Hope this helps :)

like image 112
Mehdi. Avatar answered Oct 14 '22 02:10

Mehdi.


To be fair, an event emitted from another AR or another BC is not leakage. There's no problem for a User AR to handle an OrderFeedbackGiven event in my opinion. If the Feedback VO is part of the event then the client doesn't need to depend on anything else to process the event. Having a feedback bounded context might be cleaner, but I wouldn't implement a full blown BC for just that or you will have an explosion of micro-BCs...

I am worried by the fact, that after feedback was given, all feedbacks must be aggregated to calculate user rating. That creates a dependency from user to order (calling order repository to fetch rating from user service, when event was caught). Is this ok, what do you think?

I think it wouldn't matter if you did that. The application service layer is depending on the domain layer as a whole. However, there's no need to do this at all since you can calculate the moving cumulative average.

E.g. Where this.ordersFeedbackAvg is a MovingAvg value object that keeps track of the average and how many data points it was computed from.

when(OrderFeedbackGiven feedback) { this.ordersFeedbackAvg = this.ordersFeedbackAvg.cumulate(feedback.mark); }

like image 22
plalx Avatar answered Oct 14 '22 03:10

plalx