I have a WPF application where I want to apply MVVM for the presentation layer and DDD for the whole application. I am very confused with how I should apply the architecture. Can you give me some advises as it feels like I have completely messed up at the moment with the following design try:
I have 4 layers:
Presentation Layer
: This is where my WPF client application lies in.Application Layer
: This is where I have my services that's supposed communicate with domain services for business rules and does CRUD. It works simply as an anti-corruption layer betweenPresentation
andDomain
layers.Domain Layer
: This is where I have my aggregates, domain objects, and some services that reveals business rules, such asIsTooOld(Person person)
Infrastructure Layer
: This is the lowest layer, infrastructure lies in here,IRepository
,IEntity
etc..
Let's achieve a simple scenario with those DDD based layers: Have a Person object in a database, map it, CRUD the database, check persons' birthday and show it to the user.
Presentation Layer
I'll start with the WPF part. I create the following classes :
PersonView
: XAML view of the personPersonViewModel
:ViewModel
that provides functionality for thePersonView
.PersonView
binds to this and thisViewModel
provides values fromPersonModel
PersonModel
: This is the MVVM model that myPersonViewModel
is tightly coupled to.
Domain Layer
This is good enough for the presentation layer. I now want to connect to the database to retrieve a person object to present it.
I must create:
PersonEntity
inDomain Layer
: An aggregate for the database entity, used for mappings with the database. It lies inDomain
layer.Person
inDomain Layer
: This is the domain model of DDD. I'll put some logic here and I don't want to send around entity objects as DDD suggests.
Application Layer
Ok, I already have 3 person models that are pretty similar to each other. How about some more for data access and the services?
PersonService
inApplication Layer
: When my presentation layer wants to communicate with this layer it needs to convert itsPersonModel
(MVVM model) toPerson
(domain model). This service in application layer then convertsPerson
(domain model) it intoPersonEntity
(entity object) and does CRUD with the database. This service uses also anotherPersonService
(see below) in Domain layer to check/apply some business rules.PersonService
inDomain Layer
: This layer works only withPerson
domain object. It has business-related rules likebool IsTooOld(Person person)
.
To summarize, I've ended up with 7 classes for a simple scenario :
Presentation.WpfClient.View.PersonView
Presentation.WpfClient.ViewModel.PersonViewModel
Presentation.WpfClient.Model.PersonModel
Application.ApplicationServices.PersonService
Domain.Application.Services.PersonService
Domain.Application.Models.Person
Domain.Application.DbEntities.PersonEntity
(the reason I've created this is that I can't use mapping for complex domain objects so I just put some data annotations here instead of mapping domain objects)
This feels very very awkward. I'm not sure how I should re-structure it and benefit both domain driven design and MVVM patterns. I'm really stuck and I'm really looking forward for any advises or real life examples for applying both MVVM and domain driven design. I'm also open for any feedback for naming conventions or strategies for minimizing this much of work for simple operations.
I still have two concrete questions though :
Should I remove models from presentation layer (MVVM models) and use only models from domain layer (DDD models) ? Isn't it violation of MVVM at this point?
Should I merge my entity (database) models with domain models? Isn't it violation of DDD?
Update
Decisions I've taken:
- Use domain model for MVVM's model (removed
PersonModel
) - Use external mappings for the same model to the database (removed
PersonEntity
added PersonMappings). Using persistence model is far more costly than simply mapping it. See : http://enterprisecraftsmanship.com/2016/04/05/having-the-domain-model-separate-from-the-persistence-model/ from Vladimir's answer.
Finally it looks like this:
Presentation.WpfClient.View.PersonView
Presentation.WpfClient.ViewModel.PersonViewModel
Application.ApplicationServices.PersonService
(crud with some application related logic)Application.ApplicationServices.Mappings
(I have the repository abstractions and mappings here)Domain.Application.People.Person
(person object in it's bounded context, object is smart enough to handle domain logic)