I have an application that I\'m trying to build with at least a nominally DDD-type domain model, and am struggling with a certain piece.
My entity has some business logi
You've actually struck on a question that there has been quite a bit of discussion on. There are believers on both sides of the tracks so you need to decide for yourself what makes the most sense.
Personally I don't have my entities use services as it creates a whole lot of work around the "How do I cleanly get services into my entities?" question.
It looks to me like CalculateFinancialGains() is more of a service level call. This does lead to Ticket being very anemic but I assume it has other behavior? And if it doesn't that's probably a smell...
This question is actually an example of a discussion that is in the book "Clean Code" (pp 96-97). The underlying question is whether or not to use a procedural approach or a object oriented approach. Hope I'm not in violation repeating a couple parts here, but here is what Bob Martin states for guidance:
Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.
The compliment is also true:
Procedural code makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.
My understanding that a DDD "Value type" would be what Bob Martin calls a data structure.
Hope this helps and doesn't just add to the noise :)
Given what we've seen of the classes, I don't think they're really services in the blue book sense, and I would keep the calculators in Ticket
.
Neither FinancialCalculatorService
or RateCalculationService
has dependencies on domain entities - they both operate on primitive values. Applications shouldn't have to worry about how to calculate the financial gain that would result from a ticket, so it's valuable to encapsulate that information inside the ticket itself.
If they really don't have dependencies on domain entities, consider thinking of them as 'standalone classes' rather than 'services' (once again, in blue book terminology). It's certainly appropriate for Ticket
depend on strategy objects (FinancialCalculator
and RateCalculator
) that do not themselves have exotic dependencies and do not themselves modify the state of domain entities.
Update for Edit 2. I think one of the advantages of making the calculators separate classes is that you can test them independently of Ticket
. Strictly speaking, tickets aren't responsible for performing those calculations, they're responsible for making the right calls to those collaborating classes. So I'd be inclined to make them inject-able / mock-able as they were in your initial example.
Have your service accept the Ticket
entity as a parameter. Services should be stateless and the same service should be able to provide its services to any number of entities.
In your situation I would pull the FinancialCalculatorService
and RateCalculatorService
out of your entity and make the methods on each service accept the Ticket
entity as a parameter.
Take a second and read pg. 105 of Domain-Driven Design by Eric Evans
i would say services use entities, not the other way around.
another thing, not sure on your domain, but are you certain ticket is an entity and not a value object?