A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns

What I've loved most about developing an open-source project is the ideas that I get from others who look at the work and either A) validate ideas, B) suggest that something stinks, or C) call a royal WTF and force people (e.g., me)  to explain ideas more fully.  It's usually during these explanation attempts that light bulbs start to come on and ideas are refactored and become more substantiated (or at least more defendable).  The S#arp Architecture forums have been a gold mine, IMO, for the discussion of the practical application of balanced DDD techniques on real-world projects.  After feedback that I've already gotten on my recent post concerning application services and CQS and listening to and adding my two cents concerning ideas on the S#arp forums, I'd like to share a few ideas (that I shared on the forum) concerning drawing the line among application layers, the management of DTOs and View Models, and a general discussion of separation of concerns.  (As Chris Carter correctly (and a tad bluntly) explained, don't take these ideas at face value...use them as a point of discussion and contemplation to come to your own conclusions with your project team...and let me know what you think.)

Every great developer knows that any problem can be solved by adding another layer of abstraction.  ;)

Obviously, with additional layers of abstraction and indirection, we also introduce complexity and additional objects which need to be maintained.  Over the past year, I have had struggles concerning just how far the "DTO paradigm" should be taken to effectively separate layers from the domain and "best practices" for how they should be used.  I don't think the answer can be found in a best practice (but I also hate to leave it simply at "it depends").  I truly feel that the most important practice is for a project development team to decide, and firmly agree upon, which approach will be taken on a project and for the agreed upon approach to be followed with discipline (and enforced via code reviews) by the team.

On a couple of recent projects, the biggest problems we ran into weren't concerning which approach to leveraging DTO for layer separation was "best," but on coming to a firm layering decision and having the team discipline to adhere to those practices.  Because of these "gray" areas, which we didn't come to a firm team agreement on, there were inconsistent practices used by the developers which led to rot, particularly between the controller (or code-behind) and application services layer.

So while we can discuss which approach is best or most effective, I think the greater concern is for the team to pick a direction, to stick to it, and to diverge or refactor as a team decision.

But as I said, I don't want to leave it at "it depends." ;)  So after reading everyone's ideas here and contemplating further on past projects and the ideas I recently put forth in http://devlicio.us/blogs/billy_mccafferty/archive/2010/03/05/better-application-services-and-cqs-with-s-arp-architecture-1-0-q3-2009.aspx, here are a couple of ideas that I've been trying to adhere to (and/or will be adhering to on my next project).  The layers referenced below may be viewed in a package diagram here for better clarity of what's discussed.

  • Usually, one object should be used to populate a form while a second should be used to collect data from a form.  The former would contain information for default/selected values along with drop-down values, for examples, while the latter would encapsulate which options were selected when the user submitted the form.  Personally, I use a <EnityName>FormViewModel to populate the form and use an entity to collect from the form...but I see it equally valid to instead use an intermediary DTO to collect from the form if further separation is warranted.  Additionally, I feel it is OK for a FormViewModel object to have references to domain objects to make it easier to transfer data to the form for input population.  This is an arguable point and would be just as valid to only pass DTOs in the view model for a cleaner separation between view and domain, with the acceptance that there will be more objects and maintenance that comes with that approach.
  • I believe that view models should be maintained either in the application services layer OR in a separate ViewModels class library if a project team feels the additional separation is warranted (although I can't envision much reason to do so).  (I'll be modifying my sample project post to reflect the former.)  Either way, they should not be maintained in .Core to keep a very clean separation from domain concerns.  While the name "ViewModel" implies that they are a view concern, they only describe what should be displayed, not how it should be displayed.  Accordingly, there is still a very clear separation of concerns between the view layer (which the user interacts with) and the view model classes.  Furthermore, the application services expose methods which should be usable by any type of client.  In line with this, a ViewModel or FormViewModel class does not impart a particular mechanism for the implementation of the view layer - again, it only describes what data should be available to the view.  So even if view model classes are maintained in app services, this does not preclude there use by various client types; e.g., they could be equally consumed by ASP.NET, ASP.NET MVC, Spark, SilverLight, etc.  (The only caveat is that if the view model classes maintain references to domain objects, then it will be more difficult to expose them for serialization via web services and WCF. Accordingly, a project team should firmly decide if ViewModels may contain references to domain objects.)
  • I believe that DTOs should be maintained in a separate assembly and have no reference to .Core or be maintained in .Core if warranted with the acceptance of decreased "shareability."  DTOs should almost always be serializable; i.e., transferable via web services and WCF.  This allows the DTOs class library to be easily shared with a consumer of web services which may expose these objects, for easier deserialization.  Some of the motivations for deciding when to use DTOs would be to provide a clean separation between the view and app services (if a project team feels its warranted), to expose data to web service consumers, and to better enable Command/Query Separation.
  • Repositories may return Entities, Value Objects or DTOs, in addition to other "basic" types; e.g., primitives, arrays, etc.  Ideally, repositories would not be used by domain objects (even via their interfaces) and would have their interfaces maintained in the application services layer.  If the repository interfaces are maintained in .Core, then this forces DTOs to be maintained in .Core as well with the possibility that domain references may "leak" into DTOs.  If the repository interfaces are maintained in .ApplicationServices, then DTOs may be maintained in a cleanly separated library without worrying about the line between DTOs and domain objects being grayed.  But data interfaces (and DTOs) may be maintained in .Core if the team feels the simplification is warranted.

With all this said, I still think the most important decision is deciding a path to take for your project, having the project team agree upon it, and maintaining the discipline to stay on course.

Your feedback on these ideas is most welcome!

Billy McCafferty


Posted 03-06-2010 9:41 AM by Billy McCafferty

[Advertisement]

Comments

Paco wrote re: A Few Thoughts on DDD, DTOs, View Models, CQS, Repositories and Separation of Concerns
on 03-06-2010 3:17 PM

I don't get what this has to do with CQS. I see only one model for both the command and the query concern.

Billy McCafferty wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-06-2010 4:33 PM

Fair enough...I removed "CQS from the post title. ;)

Joe Wilson wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-06-2010 7:47 PM

I nodded in agreement the whole way through.

My personal preference is view models that don't reference to the domain model.  You're right to point out the overlap and duplication this causes, but I see them as separate concerns and easily translated with AutoMapper in the application services layer.  One is the internal application model and the other is the external usage in the UI layer.

I'm also glad to see the new emphasis on the application services layer.  I like keeping my view models in that assembly.  The consuming UI has to have a reference to that assembly anyway.

I'm still digesting the idea of repository interfaces in the application services project instead of core.  I haven't run into the DTO problem you describe, but my repos return domain entities, not DTOs, and I haven't needed to separate out DTOs into an isolated assembly yet.  If I needed WCF integration, I would decorate my view models and app services with WCF attributes.  But in my mind, view models are just DTOs on the way to or from a view in the UI.

9eFish wrote A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns - Billy McCafferty - Devlicio.us - Just the Tasty Bits
on 03-07-2010 9:57 PM

9efish.感谢你的文章 - Trackback from 9eFish

Cadred (dotNET) wrote dotNET News
on 03-08-2010 11:55 AM

dotNET News

Martin Aatmaa wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-08-2010 5:20 PM

"If the repository interfaces are maintained in .ApplicationServices, then DTOs may be maintained in a cleanly separated library without worrying about the line between DTOs and domain objects being grayed.  But data interfaces (and DTOs) may be maintained in .Core if the team feels the simplification is warranted."

I have found it beneficial to make a distinction between two "types" of DTOs:

1) DTOs that serve to decouple the Domain (.Core) and the View.

2) DTOs that serve as a complement to the Domain (.Core) and represent flattened read-optimized views of the domain

In the case of 1), these DTOs should be maintained either in the Controllers layer, or in the ApplicationServices layer (if more than one client is able to share the same DTO). These DTOs would be populated by automapping domain entities to and from the DTOs. These DTOs would not be known to the Domain layer (including the Repo interfaces in the Domain layer).

In the case of 2) these DTO's should be maintained in the Domain layer. They would be populated via Repos (whose interfaces live in the Domain layer), and can be consumed directly via the View/Client layers.

The latter type of DTO is treading the CQRS territory. Looking forward to seeing that pattern set gain more traction, as I see a lot of simplification possible there.

James Broome wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-09-2010 5:36 AM

Billy,

I disagree with the statement about view models, that they are solely describing 'what' should be displayed and not 'how'. I still believe that view models are totally presentation specific (as I stated in the Sharp Arch discussion that led to this post) and therefore should live with the Controllers - i.e. with another presentation layer, the controllers and view models would be replaced. I'd like to give some real world examples to back this up.

1. On the Fancy Dress Outfitters project, we had a requirement to be able to "theme" parts of the site. This would be controlled in a content management system, however our CMS definitions and content items were treated as as domain objects just like any other entity - i.e. to build up a view you needed data from a product database and data from a CMS database. All this was bound to a  view model to build up the view. In this case, themeing was controlled via CSS files and utimately it was up to the application to translate the selected theme into the path for the CSS file. This file path was passed into the view to be rendered out in a <link> element in the HTML.

2. On the same project (and every other web project I've worked on) we've added Google Analytics code to the web page. The Google Analytics account ID is stored in some form of configuation source (web.config, database etc) and so needs to be passed to the view in order to render the analytics javascript code. We pass through the analytics code to as part of the view model.

3. All public web pages should specify meta data, page titles etc. This isn't always an exact copy of other pieces of view data - e.g. meta descriptions could come from CMS sources, or extracts of page content etc. Again, this is all passed into the view via the view model.

What I'm getting at is if we agree that a view should be as "dumb" as possible, and be given everything it needs to display, then there are numerous situations where a view model contains information on "how" something is being rendered, or more specifically in these examples, be tied in to a particular presentation context (an HTML page). If I was to build a WPF presentation layer on top of my application, then all the examples above would be redundant. This would mean either refactoring my view models to try and maintain all types of presentation specific properties, or accepting that view models are tied to a particular presentation layer (and therefore live with the controllers).

Peter wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-09-2010 10:45 AM

To me, the ViewModel doesn't make sense in the application services layer since "what should be displayed" may be different depending on the consuming client.  That's not a concern I'd want the "surface area" of my application to have.  Rather, I'd have it concerned with the relevant information to accomplish some task.  This is a subtle difference.  We don't want to say what _should_ be displayed in the view.  We want to provide a report on the state of the application to support the client in making decisions.  

corey coogan wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-09-2010 11:02 AM

Great post Billy.  Concerning your last point, specifically "Ideally, repositories would not be used by domain objects", would you mind adding a little more here.

I realize that when I'm using NHibernate, my app service can load up an aggregate root and interact with those behaviors.  Assuming I have lazy loading enabled, my object could typically go without accessing a repository interface.

What about cases where my domain object has operations that may or may not need real time data?  How do you handle that?  Do you just handle this through lazy loaded objects and composition?  It's often times very enticing to just have a repository for a case where you need check inventory or something like that.

I had discussions with Vauhn on the DDD group the other week about this same thing.  I was defending the Repository interfaces in Core while he keeps them with his service layer, much like you are describing.

Thanks,

cc

Billy McCafferty wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-09-2010 11:32 AM

Great discussion here!

@Joe,

After considering it further, and in light of well written arguments to this effect, I moved repository interfaces back to .Core for domain services to consume.

Repositories need to be able to return reporting objects (as DTOs), which flatten the domain model.  If not, then you may end up traversing an immense amount of the domain model to simply show a few columns on a listing page.  If you allow a repository to return a DTO to encapsulate the reporting information, then this can reduce potentially hundreds - if not thousands - of queries, into one.

@Martin,

Terrifc explanation!!  In light of the way you describe, the DTOs in the domain layer could be called "QueryDtos" to better represent exactly why they exist.

@James Broome,

These are great arguments that have me thinking.  My gut reaction is that application services should not be platform-specific...or at least not know that they are.  In other words, I believe that application services are *ideally* platform agnostic.  With that said, there's a difference between what's ideal, what's practical, and what the expectations are for the front-end platform to differ.  E.g., if it's known from the get-go that multiple front ends will be communicating to the application services (ASP.NET, ASP.NET MVC, WCF, RESTful services), then application services should only expose objects which are platform agnostic and easily serializable with likely no direct exposure of the domain layer itself.  On the other hand, if you're creating a CMS which inherently deals with *how* information is displayed, not just *what* information is to be displayed, then objects will inevitably carry such information all the way up through the layers from the repositories.  So I can see complete validation of your arguments, but in context of the needs of the application.  This is one of the immense challenges of creating an application framework (S#arp) which is opinionated enough to get people going very quickly, without being too preferential to a particular application type.

@Peter,

I agree that it's quite likely that different consuming clients would require different information to be displayed.  With that said, the information would either be gathering directly within the consuming client (e.g., within controllers using repositories directly) or by adding additional application services which expose the needed information for consumers.  With smaller projects, I believe that controllers communicating directly with repositories is a great approach and keeps things simple.  With that said, if it's expected that the application is going to get quite larger, I've shot myself in the foot a couple of times by not having a proper separation between the front-end (which includes the controllers) and the application services, or "surface area," of the application.

@corey coogan,

I can see valid arguments for having domain services interact with repository interfaces.  But as a rule, I find that the more objects in the domain layer which interact directly with repositry interfaces, the harder it is to maintain and keep a clean separation of concerns.  For S#arp 1.5, we've ended up keeping the repository interfaces in the .Core layer (mostly for upgrading concerns), but also to accommodate the needs of domain services which may need to interact with repositories and/or for simpler applications which do not require such austere separation measures.

corey coogan wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-09-2010 12:25 PM

So as usual, it depends.

Billy McCafferty wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-09-2010 3:10 PM

Exactly! ;)

k wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-11-2010 8:01 AM

k

social bookmarks wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-15-2013 12:40 AM

ADYmnD Wow, great blog article.Really thank you! Really Cool.

bookmarks wrote re: A Few Thoughts on DDD, DTOs, View Models, Repositories and Separation of Concerns
on 03-15-2013 4:28 AM

yUexrK Very good blog article.Much thanks again. Cool.

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)