views:

142

answers:

3

Imagine you have business domain model on server application and you are going to develop rich client application.

You can use DTO to transfer data to client and changes to server or use WCF services and generate new classes on the client.

Another way is to transfer the same objects as you use on server in your business logic layer. These can be also classes used by ORM. In this case classes shouldn't contain sever-specific logic, but they can contain some common logic.

My questions are:

  • Which variant do you use and which do you recommend to use in new projects?
  • Which is better?
  • Is the second one better in some cases and how can you describe these cases?
  • How many applications use first/second approach?
  • How to choose in particular application?
+2  A: 

You should write the fewest possible classes that meet your requirements. That way you're less likely to repeat yourself, there's less to test, and there are fewer things that can go wrong when you need to change your code.

If your client code actually needs to perform domain logic, you should either:

1) Deserialize directly into domain model classes (especially if you're using an ORM that supports persistence ignorance).

// Customer is a business object / aggregate root with domain logic
ICustomer customer = customerRepository.Get<Customer>(customerId);

2) Use data transfer objects to initialize your domain model classes:

// Given a customer data transfer object
ICustomer customer = new Customer(customerDto);

I'd rather not write DTOs if I don't have to, so I prefer the first approach. But sometimes DTOs are necessary, as when you're consuming autogenerated classes produced by service proxies - or if you're a service exposing your own DTOs.

If the client shouldn't perform business logic, it never needs to know about your domain model classes. In these cases the client should use data transfer objects or custom view model classes.

Jeff Sternal
+4  A: 

We just had a hard time to find the answer to exactly this question in our project. This is the story:

We thought that reusing classes is great and will reduce many repetitive stuff. NHibernate allows to detach and reattach classes from sessions, so it seemed to be trivial.

  • First and biggest problem we had was that you can't send the whole database around, so we had to split the entity model into pieces and linked them by guids instead of normal references. This made queries very complicated.

  • We had to implement some tricks because serialization, persistency and data binding all had their issues. This rather ugly hacks went all into the same classes. They became larger and larger.

  • Attributes seem to be harmless, until you see a large list of attributes on each class and each property, because every layer adds its attributes.

  • Entities implicitly started to support two "modes": an DTO-mode and a persistency-mode. This got evident when methods like PrepareSerialization or AfterDatabaseRetrieval and others of this kind showed up. Some properties could only be used in the server, others only in the client.

Obviously, maintenance became a nightmare. Nobody took the risk of changing an entity anymore, because you had to change things in the whole system.

Then we started to switch to Dtos.

After a huge amount of work we managed to rewrite some important parts of the system to use Dtos. And - suddenly everyone got happy.

You can maintain the serialization. You can maintain the database model and optimize queries. You could make changes on the cient model without breaking anything.

Conclusion: The effort to maintaining similar classes for each layers is ridiculous compared to the loss of maintainability when the same classes are used through all the layers.

There are still some trivial entities and value-type kind of classes which are used as entities and Dtos at the same time.

I could imagine that a small application that consists of only trivial entities could live without Dtos.

Stefan Steinegger
Interesting - what kinds of behaviors were you putting into the `PrepareSerialization` and `AfterDatabaseRetrieval` methods? Do your domain model classes contain serialization, persistence, and data binding logic? Or did they contain all that logic, and you found yourself moving to DTOs to externalize some of it?
Jeff Sternal
For instance, WCF turns ILists to Arrays. So property setters have to turn them to Lists - without braking NHibernate when it uses the same property setter to assign its implementation of a persistent list. Some references are there only for transport, they are redundancy to data that is stored somewhere else and is loaded in a AfterDatabaseRetrieval method. Some types can not be serialized, eg `Type`, so it needs another string property. And so on, thousands of tiny little problems, all have a reason and a history. The conclusion is just that this classes need to server too many purposes.
Stefan Steinegger
A: 

I have to agree with the previous two answers. However, be aware of the effort of keeping the BO/DTO classes in sync (I would consider using code generation).

See my answer here for someone who wanted to go in the other direction - they wanted to consolidate the multitude of DTOs/BOs within their system.

Vijay Patel