Home >
"Eager Loading" in Actionscript 3
Last week, I wrote about the Lazy Loading design pattern. There's not much written about its opposite, Eager Loading, in ActionScript 3. The reason for this is simple–true eager loading can't be done in AS3 itself, it has to be done by the back end logic at the server. But there are situations where you need to have information about the children of an object before that object is open, yet you don't want to make one giant call to the server and parse it all at once at the beginning of the application.
One example of this is if you need to change the style of each parent item based on some characteristic of the child items, such has whether they are not started, in progress, or complete. You may not be able to get all of that information with the first database call, but you need it fast. How can you get this information loaded in the most efficient way possible?
Load the children from outside the parent objects
One way to do it is simply to churn through each object as it comes back, requesting its children from the database, adding a reference to the object to the AsyncToken if you happen to be working in Flex. This allows you to attach the "newly arrived" children to the correct parent object. If you're working in Flash, I'm not sure how you'd make this attachment, since AsyncToken doesn't seem to exist there. However, even in Flex, this can get really messy really fast.
Make your VO's "smart" enough to load their own children
So instead I have a technique that I like to think of as "faux" eager loading. I do someting "purists" will tell you you're not supposed to do–I give my Value Objects (VO's) more than just properties. I give them responsibilities (aka methods). The main responsibility I give them is that, as soon as they know what they need about themselves to ask the database about their children, they request the children on their own and handle assigning the result to the appropriate collection. Because the code that attaches the children to the parent is "in scope" to the parent, there can be no doubt about which parent the child object should be attached to.
At this point, you have another choice to make, which is whether to create a new NetConnection object (if you're in Flash) or RemoteObject, HTTPService, etc. (if you're in Flex) for each instance of your object class that is being loaded, or if you want to share one among all of the instances. I tend to be a "less is more" type of person, so I like to create a separate class for remoting where all of the properties and methods are static and use that from my VO classes to load everything (when the properties and methods are static, no matter where a class is loaded from it is essentially treated as the same "instance."). But doesn't that bring us right back to not knowing what call generated what result?
Well, no. Both Flash and Flex have what's called a "Responder." A Responder is a wonderful thing, because it lets you pass a reference to the function that is to be used to handle the faultEvent and the function to use for the resultEvent. If you pass in a reference to a method in your object's class (even a private method), that method will be called on the instance that passed the reference to the method in. So, even though each instance is defined by the same AS code and each instance is calling the same methods on the static class, when the results come back, they magically go to the handlers specific to that instance.
If you didn't check out the Lazy Loading example I posted a link to last week, I would encourage you to do that. It uses the same architecture described above, but what keeps it lazy is that Classification waits for something else to call its loadChildren() method. However, the hasChildren setter has commented out code that will automatically trigger the loadChildren() method if there are children to get. If I were writing this code today, I'd probably do this differently–I'd have the hasChildren and id properties both trigger an event, and have the private handler for that event check for both of those values before proceeding to call loadChildren. The reason for this small change is that you need to have the id before loadChildren will work. It's just sheer luck that id is populated when loadChildren is called in this instance.
The problem with this approach, of course, is that it can result in a cascade of objects all generating remote calls to the database at the same time with no way to control it. This could potentially cause problems in client-side performance or hit the server hard enough to cause performance problems there. So, while this is a relatively simple approach to code if you know your data set will remain small, sometimes you need something more robust.
Tell your "smart" vo's to load their children before the user opens them
That brings us to a hybrid approach..."smart" VO's that manage their own children in their own scope, but managed in a way that "throttles back" loading to ensure the client and the server can handle it. This can be as simple as telling all the parent objects that are currently being inspected that they should load their children or as complex as a "Manager" component that predictively loads particular branches based on what path previous users, in aggregate, have preferred to take through the application. This is neither Lazy nor Eager, but something in between. What do you think we should call it?




Facebook Application Development
The approach you describe might work well for a "Hello World" app but I would be careful implementing "smart" value object within any application of size and complexity...this design will eventually breakdown and cause problems. I find it ironic that you tagged the article with 'design patterns' and then say 'I do someting "purists" will tell you you're not supposed to do'...and by "purists" I'm sure you mean engineers who design quality code?
The approach you describe might work well for a "Hello World" app but I would be careful implementing "smart" value object within any application of size and complexity...this design will eventually breakdown and cause problems.
@Anonymous, by your tone, I would hazard to guess that your an "engineer who designs quality code". If so, it's all very well to criticize but what is your solution to this (tricky) problem?
Anonymous, I'd suggest you take a look at my earlier Blog post, http://www.insideria.com/2009/05/who-decides.html, for my view that "best practices" are always evolvint, and you have to be willing to try new things and put them forward, or the "bleeding edge" never moves forward.
By the same token, I am completely open to being told exactly how something that looks like a good idea to me today might fail. I'm completely open to expanding my view of the way things work.
As far as I know, the only reason "purists" insist that VO's should not have any behavior is because they are considered analagous to Data Transfer Objects, which are distinguished from Data Access Objects by not having any behaviors. If you have encountered specific issues due to adding behaviors to Value Objects, I would encourage you to post them so we all can learn from them.
Since there is no real "Eager Loading" design pattern in AS3, we need to forge this ground for ourselves.
Thank you for your comment.
An article about what you CAN'T do in Actionscript. Hell, I could write a million such articles. Lately this website is full of so many articles about things that aren't practical.
You guys are coming across as really having to scrape the barrel to come up with topics to write about.
Dear (second) Anonymous,
Did you have any particular topics you'd like to see covered? I am sure that with all of the regular bloggers here, we can see to it that your needs are met.
Thank you for your comment.
-Amy
I've had discussions about the idea of preemption based on usage patterns, but in real world situations it can waste more resources (not to mention developer effort) trying to track these things than you gain from it.
I tend to stick with a fairly simple (if slightly boring) approach of uniform preemption; if you've got a tree structure - then load then load the next level, or the next two (obviously the nature of the data impacts the numbers that are practical).
Another more general problem of eager loading is with limited bandwidth environments. Loading the next few everything might make a nice user experience on cable, but using a smart phone on a wireless metropolitain area network or the likes it just chokes.
Then you have to write even smarter systems than can change behaviour based on the environment -nice if you've got time, but not all (many? any?) projects do :)
Anonymous,
While I somewhat agree with you, you're a complaining ass without solutions. Amy's right, sometimes you've got to put your ideas on the line knowing that people might disagree. Without putting them out in public, they never get discussed. Go back to your quality coding hole.
Sincerely,
Anonymous