DTO's Part 1: Real-World Flex, ColdFusion, and Java Can Be Painful!

This is the first blog entry in a series (that'll be completed in an asynchronous manner...) about managing data with Flex. I've been talking to a number of ColdFusion and Java developers that encounter the same problems with using Flex in a real-world, non-classroom situation where managing data and instances becomes problematic. Through this series, we'll be exploring solutions to these problems.

One thing I won't be doing is providing much example code. It seems that when design issues are dicussed, we tend to get focused on details of code too easily, ignoring the concepts at hand.

Architectural disclaimer: We're talking architecture in these blog entries, so you should approach any implementations discussed with a "Does my app have the problem this architecture solves?" mentality. Heck, I don't use everything discussed within on every Flex app I write!

DTO's Part 1: Real-World Flex, ColdFusion, and Java Can Be Painful!

Java and ColdFusion both play very nicely with Flex, allowing you to map server-side Java classes and ColdFusion components to client-side ActionScript 3 classes. When you work with this in a training class, all is happy in the world. In enterprise Flex applications, especially those not using the expensive bits of LiveCycle Data Services, there's a wealth of problems that aren't presolved for you.

After your Flex training, you go back to work, go to build your first Flex application, decide it's going to be a new CRM system where Person has-many Address, cook up a quick service tier, do the [RemoteClass] bits to associate ActionScript 3 classes with your model, edit a bit of data, aaaaand....foomp. BlazeDS, LiveCycle Data Service, or ColdFusion all suddenly go into a loop.

What happened?

Those neat-o bits (we'll call them the "Serializer") that turn Java classes or CFCs into Actionscript 3 classes and vice versa? They just went nuts.

If a server-side Person has-a Collection of Address instances, and each address has-a reference back to its Person, the serializer encounters the Person, starts turning it into AMF (the binary format used by the Serializer), encounters its Address Collection, crawls into it, starts converting it to AMF, encounters its Person references, crawls to it, starts turning it into AMF, encounters its Address Collection...and hilarity ensues.

What really happened?

You tried to use your domain model (or "design model," for the Rational purists) as your network transport model. In client-server development, the two are often not interchangeable.

In friendlier terms, the way your server-side objects are built is focused on server-side processing and business logic. It's often handy and sometimes appropriate for a Person to know about its associated Addresses and vice-versa. However, it's not at all how the same entities should be represented when they're sent over a wire.?

We've found a Design Force

We've encountered a constraint on our system known as a design force: our domain model is not suitable for transport over a network.

I shot a fish in a barrel with the circular refrence issue: that's only one aspect of our domain model that may be unsuitable for transport. The Serializer follows all getter methods, so there's ample room for it to try to serialize things you may not want sent of the wire (getDefaultSuperSecretEncrpytionKey()? getSomeServiceThatsBeenWiredToThisInstance()?).

What can we do about it?

We could break our domain model down to only use one-way associations and never include anything we don't want serialized.

That's weak, though: our domain model suddenly takes into account knowledge of a network transport format quirk. That's about the same as it having knowledge of which RDBMS implementation might be used to persist its state.?

What should we do about it??

The "persistence" bit in the last paragraph was a hint. Much like the force for the (in?)famous DAO pattern, where we abstract knowledge of persistence implementation, we've hit a force where we need to abstract knowledge of our transport format within other classes.

In Comes DTO

The Data Transfer Object pattern is one solution to our force. In short (and summarizing a few different conflicting definitions from Fowler, J2EE Core, etc.), a Data Transfer Object is an object that is simply the "state" of our business objects, exactly in format needed to go over the wire.

When we shift an application to using DTO, it no longer sends full-sized Person or Address instances over the wire. Instead, we created PersonDTO and AddressDTO classes ("VO" fans, my names are simply suggestions, not rules) that are optimized "versions" of the Person and Address classes intended to be sent over the wire.

Once an application is shifted to using DTO, our server-side services only send and receive DTO instances, and the client side may or may not implement its own doman model. In smaller Flex applications, I've gotten away with having the client side only deal in DTO instances, a very anemic approach to modeling.

Designing your DTOs

Instead of sending our domain objects back and forth over the wire, we'll change our approach to use DTO implementations. When I first began using the DTO pattern, I felt a pretty straightforward pain: it's no fun typing all of those blasted properties again. However, it gives you a great opportunity to think about exactly how your domain objects need to be represented as they go down the wire This doesn't just stop with keeping the Serializer from blindly following getters - it's a funny thing to think about, but when you write an app that transfers a few million DTOs a day, and you chop a few hundred bytes off of their contents, your servers may thank you when they come under load.

Using our Person and Address example, an approach I'd take would be to define a PersonDTO as having all of the properties of a normal Person Collection of AddressDTO instances, but only giving the AddressDTO personId property instead of the full circular reference. (We'll look at a technique for re-assembling the two-way relationship on the Flex side in a later blog post.)

So when to build DTO's?

Obviously, outbound DTO creation and inbound DTO "upsizing" to domain objects has to take place at the outward facing methods of your remote services. I'm not completely sold on any specific way of doing it.

For quick and dirty apps, I've done it all by hand via helper functions that perform my translation.

One common approach is to use an "Assembler" class, responsible for assembling inbound DTO instances into domain objects and possibly "disassembling" them into their DTO representations for outbound messages.

In more "enterprise" situations, I've used conventions, metadata, and AOP to perform all of this automatically, and only defined DTOs for classes on an as-needed basis. We'll build towards this solution as these blog entries continue - it's not nearly as intimidating as it sounds!

Next time...

We'll take a look at how to automate a lot of the drudgery in sending / receiving DTOs.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Great post, thanks for sharing your insights on this Joe! Can't wait for your future posts on this topic!
# Posted By Kurt Bonnet | 2/20/08 2:00 PM
© 2008 Firemoss, LLC
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.