Friday, May 16, 2008

Do we need Transfer Objects ?

I came across today (in german). Roman (?) refers to the old transfer object pattern in j2ee. I don't see why we need this anymore with JPA/EJB3. I think theres nothing up to using a consistent domain model on both client an server side. Its the same reason why I dont use GWT, because I cannot transfer my JPA enitites to the client and would agein have to use annoying transfer objects. Maybe it will get better if GWT can handle current Java versions. I would like to hear arguments why one still should use Transfer Objects in a client server environment. IMHO I think its completely unnecessary and overcomplicating things. Comments ?


Age said...

In our application the server-side domain contained a lot of relations to objects that were only needed on the server side. Not only did these objects have no meaning on the client side, they also caused lots of Hibernate session closed trouble with lazy collections.

Next to that there is usually a set of methods/behaviour that applies only to the server side and a set of methods that only applies to the client side.

These are situations that usually lead to people grabbing the old TO pattern of the shelf again. We went that way but of course it's far from ideal since you end up writing lots of translation code.

Of course all of this can be solved with better, more decoupled domain design :)

Fabian said...

If you have to write lots of translation code that is. We generate all of it (and more). It's certainly not an ideal pattern, but it works.

David Green said...

We still use Transfer Objects when we build JPA-based JSF web applications, however we are selective about when and where.

For example, we use Transfer Objects to represent the specification of query criteria on a search page, and a list of JPA domain model objects for the search results.

The pattern is still valid -- however overusing the pattern can result in an unmaintainable system.

Kris Hofmans said...

This is a question I've been working on a lot lately. I will give a short introduction to what I am working on: it's a flex application with a java/spring/jpa/graniteds backend.

This introduces a number of extra issues:
1) serialization/deserialization is not just java<->java but java<->actionscript
2) actionscript limitations (no abstract keyword, ...)

For the first couple of flex projects people started using dto's, but when you use a richer client you want to have some sort of state(model) in place on the client.

Other experienced this as a very tedious process, that took a lot of code to decently convert model object graphs to dto object graphs etc.

So that path others choose on the project that I'm involved with now was to generate 1:1 mappings on client & server so objects can be sent over the wire and reattached on the server without problems.

Laziness in itself isn't a real issue because granite manages this in a lazy property, if something lazy gets sent to the client it fills in the property and when it gets returned to the server it uses that information to regenerate the lazy hibernate proxy so you can actually use it in server side methods.

By default every reference in our model is defined as being lazy in our model, on a per use case base we use FETCH in HQL to fill out an object to match the specs of the usecase.

So far everything is fine and actually does a pretty decent job of not having too much overhead.

The tricky part is when multiple "version" of the same instance (match on id/type) start to live in the client-side, since we also have our @Version property on there for the optimistic locking imagine the following situation:
an object gets fetched "byId" for editing, but the object is already present in the vm on the client by a "findByDescription" basically the same object, the findByDescription returns a minimal object, not many relations are FETCH'd, so when a users selects a detail of the object the byId gets called which returns a fully filled out object, a users edits this and saves it. The version gets updated on the server, and possibly in the return on the client too, but what if the first screen allows people to press another button besides detail, for example applying business logic on the server for which the same reference you have from the findByDescription can be sent back to the server?

It would throw a optimistic locking/stale object exception.

For this I'm implementing an identity map ( with a twist (in this case the twist involves not breaking bindings in the ui to existing references).

Another solution sometimes used is a prefab-viewmodel, it's a sort of DTO, but filled with regular domain model objects specific to a view or use case, you assemble it on the server and often you only sent parts of them back.

In short, I'm a real fan of not having dto's anymore, but be prepared to spend some time on working out creative solutions since there isn't really much advise on best practices out there yet, and that's all we really need, a set of good guidelines on how to handle specific problems.

Using Mapstruct with Protobuf3