2

I am trying to refactor a large and complex application to use DDD principles as and when I get time.

I have a class, which is completely isolated from the domain (it is only used by an application service) but part of the ubiquitous language. It looks like this (an old version of it):

public class CurrencyCalculator
{
    private readonly ICurrency currency;

    public CurrencyCalculator(ICurrency currency)
    {
        this.currency = currency;
    }

    public IEnumerable<KeyValuePair<int, int>> CalculateDenominationsFor(int cost) 
    {
        var target = cost;
        foreach (var denomination in currency.AvailableDenominations.OrderByDescending(a => a))
        {
           var numberRequired = target / denomination;
           if (numberRequired > 0)
           {
               yield return new KeyValuePair<int, int>(denomination, numberRequired);
           }
           target = target - (numberRequired * denomination); 
        }
    } 
}

The class has a web front end and an application front end and is used by cashiers.

As it stands; this class exists in a class library project on its own (with currency class and interface). Is this an example of a domain service in DDD terminolgy? (main question) Should it be in a class library named: Core? (the Core of the application). If the answer is no, then what is this class - a utility?

The reason I ask is because I have improved my thinking of this domain recently. However, I cannot see how this very simple class fits in to my domain model.

Update

Before I answer; I have two further thoughts:

1) My understanding of a Domain Service is that it is used when the logic is not a natural fit for an entity and the logic spans multiple bounded contexts/aggregate roots. Is it normal to have a Domain Service, which does not reference any entities or value objects (like in this case)?

2) This specific application is CRUD based and this is the only Domain class. Therefore I am thinking about moving it from the Core project (Domain Model) to the Application Service to simplify it. I guess this would break DDD rules?

  • 1
    Seems to me an utility: 1. It's pure (has no side effects) 2. Has no domain logic 3. Either has external dependencies since ICurrency is part of the domain (the domain of the library) 4. Doesn't involves entities or value objects so it's fairly decoupled from the model. – Laiv Feb 21 '18 at 21:03
  • @Laiv, thanks. So where would I put this class. What would the naming convention be for the class library? I realise this may sound a bit pedantic, however I am trying to follow convention. – w0051977 Feb 21 '18 at 22:05
  • What's wrong with the actual name? Would you say It reflects the purpose of the class? If not. What do you think would be more descriptive and acurated name? Regarding its place. Is the component reused in other modules or projects? – Laiv Feb 22 '18 at 5:34
  • @Laiv, I thought the whole point of a Domain Service is that it is pure? Surely it does contain domain logic as it is telling the cashiers what denominations to use. – w0051977 Feb 22 '18 at 11:04
  • Before anything else, you should decide in what category is: Application, Domain or Infrastructure. If the domain model doesn't need the calculator and the calculator doesn't need the domain model, the likely category is Application (application service). But still, I get the feeling that application services interact with the top level elements of the domain model (for instance, repositories). In absence of this interaction and looking how the class has been implemented, I cannot but think in Application utils. I wonder what would @VoiceOfUnreason say regarding this question. – Laiv Feb 22 '18 at 11:40
1

Is this an example of a domain service in DDD terminolgy?

I would say yes.

Should it be in a class library named: Core? (the Core of the application).

I don't know what kind of library is Core. But it should be right along all other Entities or Services.

Thing that bothers me tho is name. CurrencyCalculator is too generic name. I would name it CurrenciesDenomination, so it is clear it is calculating denominations. And I would put it in Currencies "module" in the domain library. Most probably right next to ICurrency interface.

And it is true that the method could be turned into static method with ICurrency and cost parameters. And it could be turned into extension method. But it would still belong in domain in Currencies "module". It would NOT be an utility, whetever that means.

  • Why not services? – Rekshino Feb 22 '18 at 7:46
  • @Rekshino I don't undestand what you mean. – Euphoric Feb 22 '18 at 8:17
  • Just to be clear; you are suggesting an assembly called: com.MyApp.Core.CurrencyCalculator? Core refers to the Onion core. – w0051977 Feb 22 '18 at 8:21
  • @Euphoric Maybe it was misunderstanding on my side, I have understood from "But it should be right along all other Entities or Services", that class doesn't belong to services. – Rekshino Feb 22 '18 at 8:22
  • 1
    @w0051977 Purity and side effects have nothing to do whenever something belongs in domain or not. Things belong in domain if it is something domain expert would care about. – Euphoric Feb 22 '18 at 11:48
0

Laiv has pointed it out:

  1. It's pure (has no side effects)
  2. Has no domain logic
  3. Either has external dependencies since ICurrency is part of the domain (the domain of the library)
  4. Doesn't involves entities or value objects so it's fairly decoupled from the model.

However, I'm not sure whether it is right to see in #3 this isolated class as separate "domain".
If I look on all these points, then in terms DDD it belongs for me to services.

When an operation does not conceptually belong to any object. Following the natural contours of the problem, you can implement these operations in services.

See: DDD definition.

  • I have also my doubts regarding services. I have been searching for differences between domain and application services since DDD use to differentiate both. CurrencyCalculator is missing something, it doesn't operate with the domain. I would expect services (both domain and application) interacting with the domain – Laiv Feb 22 '18 at 7:56
  • 1
    I would add one more point to my arguments. The method CalculateDenominationsFor could be static perfectly, turning the whole class into a common Utility class. Reading a little bit more about DDD services someone might get to the conclusion that it could be a application service. It makes sense too. I guess the answer lays on whether the calculator is reused often across boundaries, models and projects within the domain/project/company. – Laiv Feb 22 '18 at 7:59
  • @Rekshino , I assume you are referring to domain services when you say: services? – w0051977 Feb 22 '18 at 8:18
  • 1
    @Laiv "it doesn't operate with the domain" But that is wrong. It is doing calculation with cost and curencies. That is a domain concern. It is something that domain expert would define. – Euphoric Feb 22 '18 at 8:19
  • 1
    @Euphoric I'm unsure about that. Reading the question I get to the conclusion that the class is not taking any business decision, it has no side-effects in the domain and there's no domain element to operate with. It's a mere converter. ICurrency (If I'm right) doesn't belong to the domain, it's one more resource for supporting the calculator. Seems to me too much isolation for to be part of the ubiquitous language. Despite the word currency and Denominations might appear marginally. – Laiv Feb 22 '18 at 8:32
0

Simple. This is a domain service. We know this because it knows about your domain. Currency is certainly a domain object. Furthermore, it encompasses a business rule. It enforces that in the event that a Cashier must give a Customer change, they do so with the least total number of legal tender. Should that rule change, say when a Customer pays with a 100 dollar bill and the change is greater than $50 Cashiers must use two 20 dollar bills instead of a 50, where else would that rule be enforced? Or what if, for some reason, a rule was made that a specific Cashier could only give 1 dollar bills as change? Now we would need more methods on this service to allow it's consumer to decide how to make change.

All of that said, I would suggest you think long and hard about what you name this service, because CurrencyCalculator certainly didn't end up exhibiting the behavior I thought it was going to exhibit when I first started reading your code. Take that with a grain of salt, but I would expect a service that calculates the change that a Cashier is supposed to give back to the Customer to somehow include those context clues in the name.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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