Tuesday, May 25, 2010

Five reasons to hate DTOs

I finally came to it: I hate Data Transfer Objects.


I can't explain why a lot of people still stick with this unconfortable pattern and most of them continue to ignore the cons of this choice. Now I'll try to explain my opinion by listing why I think this should be enlisted as anti-pattern.

  1. whenever you have to return or receive an object you must always copy it using almost double heap memory than normal (yeah, I know it's not really double, but it is something near it)
  2. if you should return or receive a complex structure you have two choices: deep copy the structure or use multiple interactions, in both cases you are loosing heap space and processing time
  3. almost any change to the business model interfaces will be reflected on the transfer objects AND on the code which maps the two (the latter does not apply in case you use introspection which is slower and lesser customizable) more than doubling the maintenance time and is error prone
  4. programmers tend to confuse the difference between model objects and DTOs adding utility methods to the former and business logic to the latter
  5. if in certain situations you need additional info on the client side from a returned DTO you have two choices: embed a service call into the DTO (which hides the complexity but expose to a performance hit as your users don't know they are starting another interaction) or call another service to obtain the additional infos (which adds complexity to your service interface)
Now let explain my way to replace DTOs with interfaces:
  1. if you need to return or receive almost all the informations stored in your business model object just do it, return or receive your business model object
  2. whenever you need to return a DTO, may be to reduce the informations providen by hiding some properties/methods, return an interface which your business model object will implement
  3. whenever you need to receive a DTO you have two choices: use a business model object ancestor or use a business model object component; the choice depends on your business model design, if you are used to build by composition or inheritance
  4. when you need to return a complex structure just initialize the structure before returning it (this is needed to avoid lazy initialization errors)
Four simple rules to avoid class and memory duplication with a lot of processing time spent copying datas from one object to another.

Do you see situations where this solution is not applicable? Let me know, I'm sure I can find a non DTO based solution.

3 comments:

Giuseppe Contartese said...

Hy,

Usually, I agree about you wrote on the wall, however I would like to expose a simple situation to use DTOs :
1) Think about a complex "view" on your presentation tier , view that is a three, or more joined, table query result,using a a DTO as simpler structure u can report all information reducing memory, avoiding to load all your business data model to retrieve information that you need (using a more sofisticated query ).
2) You wrote about "lazy initialization errors" but as well as u know DTOs are a design pattern used to transfer data between software application "subsystems" and not always it's a good idea, i think, to pre-load all your Database to avoid lazy init error.

Think a problem and you'll find a solution , think a solution and u never find the problem!

Unknown said...

Let me explain how to solve this "very common" problem within my hate for DTOs.

You have a complex structure to return from a business method: a Payment, the Order it refers to and the Shipment informations. Those three "tables" (business model objects in my definition) should be related in some way otherwise you shouldn't be able to "join" on them. Let say the Order is the root of the tree and have a Payment and a Shipment attached to it. A Payment also has other 10 structures attached to it and you don't want to send all those stuff out of your method.

Let define an interface, I'll name it PaymentSummaryDTO (I've put the DTO acronym in the interface name to let you see what it represent) which defines only the methods on Payment you want your client see.

Let the Payment class implements that interface.

Access your persistence tier, read out the payment, read out the order and the shipment informations too by accessing the corresponding read methods.

Now return that Payment object as a PaymentSummaryDTO instance.

What have you obtained?
# your client will be able to access the informations he needs
# you have not read out the entire database but only the informations you need to return
# you don't need to copy the informations from one object to another
# you protected your client from lazy initializations as he can't access the informations you haven't initialized (unless he uses introspection and some other bad practices)

What is the real cons? Your client needs to have your business model classes.

Giuseppe Contartese said...

Let me understand, if you have to represent ,in three different moments of your project lifecycle request, 3 or more Payments complex "views" your approach is to add more interfaces as the number of views u need ??
In this way , don't u introduce a forced contract for the model implementation...isn't ?

Thanks for your attemption and replay