1

I am not sure but as long i read about ddd, domain model should never leave the application layer.. if that is true then how viewmodels can reuse behavior of domain model?

Assume the following invoice model in ddd perspective

  public class Invoice
{
    public int Id { get; set; }

    public int CustomerID { get; internal set; }

    public void ChangeCustomer(Customer customer)
    {
        if (customer.IsActive == false)
            throw new Exception("Inactive customers cannot be used");

        CustomerID = customer.Id;
        //other properties change also that need to be reflected to the user interface
    }
}

And now lets have the invoice ViewModel attempt #1. Going with this idea i have no issues to reuse domain behavior, but the domain layer must be referenced to the UI Project in this case(WPF). But is here where my fears appear that we should not use domain layer outside of application layer

 public class InvoiceVMOption1 : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyUI(string PropertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }
    Invoice underlinesource;

    public InvoiceVMOption1(Invoice underlinesource)
    {
        this.underlinesource = underlinesource;
    }

    public int InvoiceID { get => underlinesource.Id; }
    public int CustomerID
    {
        get => underlinesource.CustomerID;
        set
        {
            try
            {
                //This is a very simple example. in reality when changing customer other properties of the domain change also.
                var customer = new CustomerService().Get(value);
                underlinesource.ChangeCustomer(customer);
                NotifyUI(nameof(CustomerID));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                throw;
            }

        }
    }

}

And now lets have Invoice ViewModel option #2 Going with this idea, it means application service is responsible to construct the viewmodel and give it to the UI and then UI give back viewmodel >convert to domain > update throught repository

   /// <summary>
/// I like more this idea as it decouple viewmodel from domain layer
/// The problem here is how i can reuse the logic of changing the customer since domain model is not referenced
/// </summary>
public class InvoiceVMOption2 : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyUI(string PropertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }

    private int invoiceid;
    public int InvoiceID
    {
        get => invoiceid;
        set
        {
            invoiceid = value;
            NotifyUI(nameof(InvoiceID));
        }
    }

    private int customerid;
    public int CustomerID
    {
        get => customerid;
        set
        {
            //user select a customer from combobox binding with his id
            //here we need to let the user whenever  any of the validation that exists in domain model invoice will fail when changing customer.
            //nothing will save yet
            //after user finish this viewmodel will be sent to application layer(service) convert it to domain and update through repository
            //Problem is, how i can know if customer will fail to change without writing same code validation from domain?
            customerid = value;
            NotifyUI(nameof(customerid));
        }
    }
}
Stelios
  • 330
  • 5
  • 21
  • 1
    A view model shouldn't reuse domain model behaviour in the general case. `Invoice` should live on the server only. You would then typically use a data transfer object (DTO) to send its data to the client. In the client there will be then be a view model class that exposes the data to a view. – mm8 Mar 16 '22 at 14:02
  • Ok, but even that way(dto) case, how i can reuse validation or behavior in view model that exists in domain ? How should be done to avoid code duplication in view model. E.g when customer change in invoice some validation must perform, as also other properties change and need to be tracked in ui viewmodel. – Stelios Mar 16 '22 at 17:18
  • 1
    The whole purpose of the abstraction is to not resuse the same logic. If you want to resue the logic, you could expose your domain objects and wrap them in the view model. – mm8 Mar 17 '22 at 13:24

1 Answers1

5

The View Model is a one-way street. It is only meant to construct a data structure suited to the UI from the domain representation.

Each change at the UI is better modeled as a separate Command (if you are using CQRS) or a different API that calls a specific Application Service (if you are using core DDD).

By choosing to model each change, you represent the domain more accurately in your code. If you were to return the same view model with modifications to the data structure, you are hiding the intent of these changes. The flow pattern is also closer to CRUD because you are simply transferring data to the backend to be persisted.

Subhash
  • 3,121
  • 1
  • 19
  • 25