0

We've been battling over where certain methods should live within our domain model, so looking for some adice and reasoning as to where they should go.

Say we have a Project object now that Project can have a Budget (which is essentially made up of a number of hours against certain job roles and these have a cost to them), Timesheets, Invoices, External Costs. We have a number of calculations throughout are system to work out what the total budget of the project is, what the total cost of our project is and then comparing the 2.

The question is where do these calculations live: Do they live on the Project and simply act against the Timesheet,Invoice,Externals collections on there to get the correct number. If so then we need to make sure these collections are correctly populated before performing the calculation (lots of null checking etc).

Or they could live in a separate class where the Timesheet,Invoice,Externals are passed in and the result passed back. This way we know that we'd have to have retrieved the correct data in order to perform the calculation.

2
  • I think you want to start with a different question. The question should be how does the consuming client get their work done: what is the usage model for these object(s). You're looking into implementation details before looking at consuming client usage. We want the client to be simple and the usage model foolproof so they fall into the pit of success.
    – Erik Eidt
    Commented Oct 23, 2020 at 15:53
  • 1
    Since nulls are a problem in one case and not in the other, I assume you have some kind of lazy loading going on? Also, these calculations seem to be relevant business-related concepts (that have some business logic associated with them), so one thing to seriously consider is creating objects to explicitly represent either the use cases involving these computations, or the computations themselves, and then you can place your methods in there (as well as any computation-specific state). Commented Oct 23, 2020 at 20:00

2 Answers 2

1

In Domain Driven Design, the concept of an Aggregate Root exists.

An Aggregate should always be in a valid state, meaning that all children (entities, value objects) should be loaded into the Aggregate, so that it can perform the operations without having to worry about whether the children are available.

Whether it's a good idea to add the collections depends on if you actually have behavior in the Project aggregate that requires access to the collections. It might be enough for the Project aggregate to have a TotalExternalCost property for example.

0

OOD and DDD differ on this significantly.

Object-orientation says that there is no reason to have any objects unless they have some useful (i.e. business-related instead of technical) behavior. So unless you can assign useful behavior to Timesheet, Invoice, etc., they should not exist. That leaves us with Project.calculateCost() or something similar. It doesn't matter how or on what data this is done, or where that data comes from. Again, if you do have some useful behavior in other things, you can use those in Project.

If you have to have null-checks you're doing it wrong. It either means that you use objects as essentially free-for-all data-structures, or use lots of implicitly assigned semantics. Or both. Neither is good.

Mainstream DDD is completely different from what I described above. That would say that data-structures are fine, and you should build a replica of all data in-memory, perform some procedure on them, and then push data back wherever they came from. Logic only lives in the "model" if it can be done completely "purely". Logic that needs multiple things usually then resides in Services that act on the "model" completely from the outside.

You have to decide for one, they are not compatible.

16
  • 2
    Downvote means my answer is working :) Commented Oct 23, 2020 at 14:17
  • Didn’t downvote but I am curious. DTOs didn’t seem like anything but a necessary evil due to leaving code under my control in either OO or DDD. I thought DDD was about building a ubiquitous language from a bounded context. Can you cite what Eric Evans teaches about naked data? Commented Oct 23, 2020 at 15:04
  • @candied_orange You have a point. Eric Evans in my reading of the book was not strongly for or against anemic designs. He does hint at it, with layered architecture, talking dismissively about oo. But you're right, the value, for me at least was elsewhere. However, I was careful to say "mainstream DDD". When somebody says DDD, they usually mean the Vaughn Vernon type DDD, which is the strict "entity/value object/services/repositories/aggregates" and all that technical stuff. Where entities have to be "pure", i.e. they can't use technology, i.e. they stay mostly data. Commented Oct 23, 2020 at 16:05
  • pure means no behavior huh? Can you cite that from Vaughn Vernon? Commented Oct 23, 2020 at 16:54
  • 1
    No, because you left out this part: “Instead there are a set of service objects which capture all the domain logic, carrying out all the computation and updating the model objects with the results”. If there’s no separation between the model and the service classes, it can’t be called an anemic model.
    – Rik D
    Commented Oct 25, 2020 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.