I hear this question come up time and time again. It is something that I have been dealing with for a while now, and have some experience with doing both ways. I started writing this in response to a DDD thread, but it got rather large and so I turned it into a post. So here ya go!
I think you have to write DTO’s for any sort of long term Enterprise ‘system of systems’ solution. I fought this for some time, but since moving to an Assembler/DTO I much enjoy the freedom of being able to easily tweak my DTO “snapshot” of the aggregate root I am working with. Maintaining them is very little overhead.
I tend to think of the DTO as a message, a value object. This is necessary because once an entity leaves the boundary it can no longer function within its original meaning. Its methods may be intended to only run within a given context, which is not the same once on another tier. (Things like lazy loading are a good example) Once the DTO/Message arrives to the caller, it very well may (and probably should) be translated/assembled into another model which can represent its new semantics.
Some other advantages of DTO w/ Assembler or Builder:
-Can explicitly control the depth of the graph/tree you are serializing.
-Can flatten out the data where needed
-Can return significantly less data (maybe you only need 3 fields instead of 15)
-Not tightly coupled between remote boundaries (this could be a mess when working with a large team)
I wrote a post a while back showing a way to ‘templatize‘ the process. My current implementations are much different with LINQ now, but maybe it could stimulate some ideas for whomever.
The next thing I would like to do is remove the assembler altogether. By flagging fields with attributes or using config to specify a mapping, I could then feed dynamic methods and run a translation/builder strategy.
I know there are concerns about writing and maintaining assembler and DTO, but to me this is the least of the worry, a more challenging scenario would be the UnitOfWork (How to you intended to track remote state, concurrency etc) How about versioning? performance? scala.. well ilities in general?
These kinds of problems lead one from Request/Response, Patterns of Enterprise Architecture & DDD to a Pub/Sub Message Bus – Enterprise Integration Patterns & DDDD.
And to think all you want to do is send some frickin entities to a remote client 🙂