We ran into a situation today in an application processing a large data set and seeing some really exhorbenant parsing times on the Flex side. We're transferring the data using AMF and it's still taking up to 5 times longer to parse the data than transfer it (500 ms to transfer, up to 4.5 seconds to parse it. Yikes!)
Part of the problem is that someone made a key VO bindable. The data set we're loading is about 5,000 objects in size. Each object gets parsed in a method that makes reference to properties on this vo at least 6 different times in a while loop which can loop hundreds of times depending on the data point.
When the VO is bindable, this means 6 different method calls, since bindable objects have their public properties replaced with getter and setter methods to support binding. Having these calls made from inside the while loop lead to roughly 1 million excess method calls in parsing the data alone.
There are other inefficiencies in our data parsing yet to be found, but removing the "bindable"
tag on this object lead to an immediate 30% increase in speed. Removing the tag hasn't had any noticable effects so far.
It's likely someone wanted to bind to a data provider before the data had been created and then used the data object itself as part of an MXML tag. Even though the data will never be updated and thus doesn't really need to be bindable, FlexBuilder can't tell that and produces a warning message asking that the object be bindable. Clearning up this tiny warning had disastrous results, though we didn't find them until now. :)
Since the VO itself is never updated in our application, there's no reason it ever should've been bindable. If you did need a bindable VO there are several ways to avoid our problem still. First, we could've cached the VO's values outside of our while loop, operated on them within the loop, and then updated afterwards if necessary. Second, we could've listened for a more general "loaded" event on the entire collection rather than binding to something on the individual VO's themselves, since they should all update at more or less the same time.
Finding performance bugs like this is key to enhancing user experiences in Flex. I'd heard all of the standard performance enhancements before (type your variables, don't nest for loops, etc.) but hadn't heard anyone mention anything about binding before, so this was sort of a revelation for me even though it probably should've been obvious.
If you're suffering from performance degradation and can't figure out why, look at your binding. Fire up that brand new shiny profiler and see how many times your bindable methods are being called - I bet it's more than you'd think.
Discovery Earth Live, an application we've been working on since early August '07, went officially live today. I say "officially" because it's been up on Discovery's site for a while now, and a few reporters (including Wired) broke the news early on Friday.
In summary, Earth Live is an application that allows users to view global data on a 3D surface. It's maintained and updated daily by Discovery, who provides content about climate issues directly from scientists and NASA and NOA (in the "featured stories" area) and allows users to make their own global "stories" with data sets compiled from the last 24 hours (in the "create a story" area.) Any story, whether featured or created, can then be shared on a users blog, myspace, facebook, etc. in a widgetized form. Here's an example of the widget with no layers, which is how I like it best:
Earth Live was exciting to build and features some interesting technical hurdles. We wanted to incorporate an interface that was fun to use but still conveyed the data, and that was difficult because until about half way through the project the data itself wasn't well defined. I heard someone speaking at Max this summer say something that should be obvious: data comes first, interfaces second. Making an interface for data you don't have yet is always a risky thing. In this case I think we lucked out and the interface fits the data pretty darn well, but I still wish we'd seen it sooner.
We decided early on that the globe should be a real 3d object for a number of reasons. First, this was the way our sales guy pitched it to the client. His big idea was to mask a giant repeating flat map so that it APPEARED to be a real sphere - we in the development department were having none of that. If it was going to look like a globe, then by golly it was going to BE a globe. Second, our designers convinced us that 3d globes are just more fun to use. We'd used PaperVision3d on a few projects before and read about it's recently increased performance, so we decided to give it a go.
From the beginning Discovery had been interested in using this app to support their Earth Live blog, which tracks the adventures of scientists around the globe. We'd planned on building this feature out as clickable push-pins in the globe. The feature worked but with weird bugs around the edges in PaperVision. Though John Grden assures me this is not a bug, we made the switch to Away3D - a PaperVision spinoff project contriubted to by my buddy Peter Kapelyan - and everything was fine. Away 3D also gave us some increases in performance which were greatly appreciated.
We planned the application to display two kinds of data: flat image files and KML drawings. Flat image files were easy to do in PaperVision but the KML piece was more work. Brad Umbaugh, who did most of our globe development, spent about two weeks working on the KML piece, but in the end we decided it just didn't look right and so it's not being used. The functionality is in there, hoping and waiting for an eventual upgrade in version 2.0.
Somewhere around the beginning of October we started working with the real data and Discovery came to us with an exciting proposition: how about videos? In theory it worked, but in practice the performance sucked. It sucked bad - browser crashing, slow as molasses, 2 fps bad. Brad spent a few weeks tweaking it and with the help of some other EUI staff (Jim Cheng in particular) we came up with the following system:
All of our videos are embedded in swfs.
When we load a video into the app, we immediately strip all of it's frames out into raw image files during the first pass through the video.
In the second pass, we flatten those images with any other layers on the globe at that time (though Discovery isn't currently layering any images on their videos, the capability exists.)
After this, the globe updates it's wrapper material once every frame and it looks like a video. Performance is still rough on older machines, but it's decent on most and great on anything made in the last 3 years.
One really exciting part of the app was a frantic last-minute re-design. While at MAX, with our latest development deadline just two weeks out, we received info from Discovery that the app was going to need to be 200 pixels slimmer than we'd previously thought. Patrick Hansen and I sat in the back of our booth and quickly sketched out what later developed into the new design. Brad and developer Kevin Skrenes, who was responsible for more or less all of the UI that wasn't the globe, helped us massage it over the next week and Kevin bore the brunt of the re-development effort.
During the last month Kevin and Brad transitioned off and I worked bugs and updated the widget. I went through some hurdles learning the Facebook integration process, partially defined in a post here, and finally got it all working late last week. That's right - right before the deadline. You know how it goes. :)
All in all, this was a great project. Discovery is by far one of my favorite clients ever - they're amazingly enthusiastic and easy to work with. I also want to give major credit to Bobby Jamison and Jeremy Graston, who worked on things from the design angle, and Shannon Garret, who built all of our marketing materials including the Earth Live logo.
A final note to developers: the app currently throws a run time exception you might see in the debugger:
TypeError: Error #1034: Type Coercion failed: cannot convert flash.events::Event@27513d91 to mx.events.IndexChangedEvent.
This is an Adobe issue documented on their bug base here. I'd like to find the offending piece of code that dispatches the bug and catch it, but it's not a high priority now since it's only visible to users running the debug player -- non-developers will never see it. :)
The BBC has a map on their site displaying information about the "Super Tuesday" primary voting scheduled to take place today. It also has an interesting feature that will show the state by state election results for the Presidential race back to 1956.
My favorite things about the map are that it's extremely lean (~300k) and extremely simple. It's minimally skinned and contains bare-bones functionality (with the exception of a weird button that removes half the navigation - what's the deal with that?) Most users really won't have any idea they're playing with Flash content. This app definitely could have been done in Ajax, but I bet it was a lot easier to code in Flex. All in all, it's a good example of Flash done "right" in a way that subtley enhances the normal BBC content without taking over.