Wednesday, 26 October 2011

Data Transfer Objects - some possibilities

Plain Old Class Objects
In their simplest incarnation, Data Transfer Objects do 'what it says on the tin'. That is, they hold data, and transfer that data, typically from one layer of an application to another.

public class Product
{
public string ProductCode {get;set;}
public DateTime? PublishableFrom {get;set;}
public DateTime? PublishableUntil {get;set;}
}
Data About Data
We often want to know a bit more about what data is like, as well as what values it has. In the context of Data Transfer Objects, we can use Data Annotations to indicate this metadata. It's often safe to make it available between layers of the application.

For example, after looking at our database structures, we might annotate our Product Code
[Required, MaxLength(10)]public string ProductCode {get;set;}
In the context of Data Transfer Objects, we might use the annotations to set up 'immediate feedback' to the user for a data entry interface. Also to quickly check the data in the DataAccess layer before attempting to save it, typically avoiding a trip to the database and getting a better message for the user. The key point is that the metadata is the same between the layers, and potentially between different user interfaces for the same DTO.

There is a balance between this added consistency and performance, of course. To set up a form or page with the maximum lengths uses reflection to get the metadata - however it is a 'once per control' cost. I won't discuss here when to use annotations for this purpose, when not to, which tools would help...

Extension Methods For Other People's Classes
Extension methods allow us to add lightweight functionality to an existing class. A utility function ToDateOrEmptyString might be implemented as an extension to the Nullable<System.DateTime> class. It gives us more readable code, and a more consistent presentation (especially if our application has several alternative user interfaces but requires a specific date format).

Extension Methods For Our Data Transfer Objects
While our DTOs are primarily concerned with data, sometimes we have extension methods which can be cleanly included. A typical example on our product class might examine the PublishableFrom and PublishableUntil properties, and work out if a product IsPublishableToday().  An advantage is that we don't have to worry about serializing and deserializing a derived property, simply reuse the extension methods in all layers requiring them.

Where to Do all this work
Personally, I'd want to keep formatting as extension methods implemented in the GUI layer. However, if there are alternative GUIs, I'd let that override my usual preference. Unless the task was large enough to justify a whole new formatting layer.

More Atomic Requests
The extension method technique is intended to work with the black-box view that n-tiered architecture creates. I wouldn't have a  heavyweight extension method IsAvailable() to check whether there is any stock in, whether the logged-in user is authorised to obtain it, and so forth. So we might have a service-layer or repository layer call that returned a boolean. Or more probably our Products returned would be filtered, calling  GetProductsAvailable(), GetProductsPublishableToday(), or GetProductsAll() as appropriate/

Aggregate Data Transfer Objects
It's common to drill down into the detail of an object. So again on the theme of atomic requests, if the user wanted to view the actual levels of stock, we would consider a design with alternative Dtos for our product. In most cases we would retrieve a plain Dto just telling us about the product basics, however we would also have a more complex Dto, say ProductWithStockAvailableAndDue. I won't dwell here on possible designs for StockAvailableAndDue, or all possible ProductWithXXX aggregates.

Not One Size Fits All
It is worth considering Small, Medium, Large sizes of Dtos for a base object. Small having Id and a brief description, Medium roughly equivalent to a table row, Large being an object and its lazy loaded children. As with any design decision, it all depends on the details of the application.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.