In my opinion, this can be considered a highly subjective question.... My suggestion is based on DDD
practices.
In the context of DDD
, the repository should always return a domain object (i.e., an Aggregate
). Aggregates are the basic element of transfer of data storage - you request to load or save whole aggregates. It's up to the application layer transform the data into a model / DTO
that makes sense for the view.
To address your concerns:
The pick list example that your describe is a great candidate for a DTO. If you create a DTO to represent two properties to support a view, you are creating a POCO object. This object is lightweight and cheap to create. You can use tools such as AutoMapper to assist with the mapping between the DTO and Domain Model. When it's time to change the view, your changes are usually isolated to the DTO object and its mapping. You have not leaked the concept of a view through your application layer into the domain layer.
The DTO will cut down on the bandwidth cost for the requesting client (i.e., you are not returning a domain entity with 30 properties and showing your entity in public)
You can use a single repository to support your Department picklist
view and CRUD operations for the Department entity.
Use one domain model. However create as many DTOs that your need to support views from that domain model or models.
At the end of the day, DDD is not cheap and it's not a silver bullet.
If you have a simple problem to solve, then use simple CRUD with a model that makes sense for you. These are just guidelines...
DDD makes sense for developing software of extremely high essential
complexity (with a lot of correlated business rules). And/or software
with clear future, where the Domain Model can outlast the
infrastructure, or where the business requirements change fast. In
other cases DDD may bring more accidental complexity than solve.
For what it's worth, here are some additional remarks on DDD concepts that will hopefully help:
Use Case Optimal Repository Queries:
Vaughn Vernon describes a pattern Use Case optimal Repository Queries
as....
Rather than reading multiple whole Aggregate instances of various types and then programmatically composing them into a single container (DTO or DPO
), you might instead want to use what is called a use case optimal query. This is where you design your Repository with a finder query methods that compose a custom object as a superset of one or more Aggregate
instances. The query dynamically places the results into a Value Object
(DDD
) specifically design to address the needs of the use case.
You design a Value Object and not a DTO because the query is domain
specific, not application specific such(as are DTOS). The custom use
case optimal Value Object is then consumed directly by the view render.
This is a similar approach to using CQRS
; however, the repository is executing off your unified domain model store and not a database designed to support your read-only views.
Vaughn Vernon also states:
If you find that you must create many finder methods for supporting
use case optimal queries on multiple repositories, it's probably a
code smell.
This could because you misjudged the Aggregate boundaries and overlooked the opportunity to design one or more Aggregates of different types.
Vaughn describes this code smell as: Repository masks Aggregate mis-design
This could also point to the need to consider using CQRS
.
DDD Query Model (aka Read Model)
The query model is a denormalized data model. It is meant for display only data and not meant to deliver domain behavior. Vaughn Vernon states:
If this kind of data model is a SQL database, each table would hold
data for a single kind of client view(display). The table can have
many columns, even a subset of those needed by any given user
interface display view. Table views can be created from tables, each
of which is used as a logical subset of the whole.
He also states to create support for an many views as needed. It's worth noting that CQRS
-based views can be both cheap and disposable ( for development and maintenance). Using Event Sourcing
, plays nice with this approach.
DDD DTOs:
One approach is having your application layer assemble DTOs
. The DTO
would be a projection a subset of your domain entity or entities to satisfy your view.
Vaughn Vernon simply states -
DTO is designed to hold the entire number of attributes that need to
be displayed in a view
DDD Repository
Martin Fowler describe the Repository pattern as:
Mediates between the domain and data mapping layers using a
collection-like interface for accessing domain objects.
Please reference these SO questions: