As the old adage goes, more code equals more bugs. Many OO principles are either based upon or include some basis in writing less code. The reasons are obvious. So when it comes to DTOs, therein lies a little conundrum: writing a class that represents another class (or multiple classes) seems like you’re breaking the rules a little. Take for instance the following three domain model classes (and their base class):
The Company class mostly comprises complex properties (not all shown for brevity), whereas the Address class is all primitive types plus an enum. Contact is mostly primitive types. Just for background info, I’m using these classes within an EF Code First approach so they are not just my domain model but by data objects as well.
Suppose I have a service, CompanyService that delivers up a company (or companies). This service is consumed by an MVC controller. I have a view that displays the following information:
Company Name; Company Created Date, Company Modified Date, Company Primary Address, Principal Contact Full Name, Principal Contact Email Address
I could grab the company, use the whole object as my model and return the view. MVC calculates the required fields on the server side, EF lazy loading ensures that only the properties required are retrieved and only the necessary information gets posted into the View returned. That’s nice as I haven’t had to create any extra DTO classes to flatten my data. However, there are a couple of snags:
1. What happens when I am using the model for editing and I want to place validation attributes on my properties. Most attributes (Required, MaxLength etc.) fall into the System.ComponentModel.DataAnnotations namespace and perhaps it would be fine to use these – especially if you are already using them in a Code First manner to shape the database. But what if you want to use some of the MVC model metadata attributes? Such as ShowForDisplay, Order or IsReadOnly. You do not want a dependency on System.Web.Mvc on your Domain Model.
2. You decide you want to use an API Controller at some point – perhaps to serve some data to a client-side model instead. You grab the same company object and bam, you hit an exception:
The type System.Data.Entity.DynamicProxies.SomeClass_SomeGUID was not expected…
That clever lazy loading, change tracking Entity Framework has caught you out with its dynamic proxy classes. Your options are to disable proxy generation and eager load the child properties you want but how do you know which children you want for each scenario? You don’t. You can’t.
People can use the DRY principle to justify not writing out separate DTO classes but the simple argument is that only a ViewModel can know what needs to be shown, what can be edited and how something may need to be displayed. Granted there is an overlap with validation and certainly there will be times, often in read-only scenarios where there is a 100% mapping between the Domain Object and the DTO. This would be true in the case of the Address class above – an AddressDTO class would have the exact same properties. But in edit mode, I may need more flexibility with validation and other attributes. I may also decide to make all but Name, NameNumber and Postcode read-only and insist on using a postcode address finder utility. But I wouldn’t want the other fields to be read-only on my domain model.
If you are in a scenario where you have multiple user interfaces you may want to consider breaking out your DTO objects into a separate project. If your front-end apps transcend different technologies, it may even be worth using a fluent approach with validators/ behaviours that are specific to that technology should there be one, but separating out a DTO object from its intended target may seem like a DRY principle but caution must be paid as to who is using it and for what as developers will always look to find something that closely matches there needs and often fall into the habit of tacking their own requirements.
In short, I would recommend keeping you DTOs separate for each app. Use a mapping tool like AutoMapper to minimise coding and don’t be afraid to ‘break’ the DRY principle a little – using one DTO for returning search result and another for viewing details means that your search will be faster. If you can use inheritance to enforce a little DRYness to your DTOS, great but don’t get hung up on it.