Steven Suryana
Steven Suryana

Reputation: 179

Where to put business logic in DDD that shared between domain layer and presentation layer?

I'm developing app using DDD pattern.

I have Invoice class in domain layer.

public class Invoice
{
    List<InvoiceLine> list = new List<InvoiceLine>();

    public DateTime Date { get; set; }

    public Customer Customer { get; set; }

    public decimal GrandTotal 
    { 
        get
        {
            // Simplified grand total. 
            // It's actually include tax and discount to calculate.

            decimal total = 0m;
            foreach(InvoiceLine line in Lines)
                total += line.LineTotal;

            return total;
        }
    }

    public IEnumerable<InvoiceLine> Lines
    {
        get { return list; } 
    }

    public void AddLine(InvoiceLine line)
    {
        lines.Add(line);
    }
}

I'm using mvvm pattern so i also have a viewmodel to edit invoice. My question is where should i put the business logic to calculate GrandTotal so that the business logic on domain and presentation is the same ?

Should i just duplicate the code from domain to presentation (Invoice to InvoiceViewModel)? or make a service that both domain and presentation could use?

Upvotes: 2

Views: 1138

Answers (1)

kstaruch
kstaruch

Reputation: 1319

The main goal of aggregates in DDD is to maintain consistency - in your case consistency means for example that GrandTotal will always have correct value. That said, there's no rule that states that aggregate class cannot use additional classes to obtain this consistency.

For example, you could provide a class which sole responsibility is to calculate grand total and use it in your domain and view model. I wouldn't call it service as it has nothing to do with DDD concepts. Example:

public interface IInvoiceLine
{
    decimal Amount {get;}
}

public interface ICalculateGrandTotal
{
    decimal Calculate(IEnumerable<IInvoiceLine> lines);
}

public class GrandTotalCalculator: ICalculateGrandTotal
{
    ...
}

Now you can use this calculator in both view model and domain without code duplication. In addition due to interfaces, there's no direct coupling between view model and domain classes. IInvoiceLine interface can be separately implemented by view model and domain entities.

Upvotes: 2

Related Questions