The excess of time I’ve suddenly found myself with has enabled me to focus in on Flex and build some apps with Adobe’s Cairngorm pattern. Even if you haven’t yet coded much in AS 3 or Cairngorm, if you’re an avid Actionscripter you’ve probably been inundated with all of the hype surrounding it. I really wanted to put to task some of the things I’ve heard about AS 3 and Cairngorm. You can read about my experience below and you can also check out the app and the source at these links:
http://www.chrisrebstock.com/stuff/wow-stats
http://www.chrisrebstock.com/stuff/wow-stats/srcview
Cairngorm and AS 3: Together, the AS 3 and Cairngorm promised to help alleviate many of the things that bother us about developing in AS 2. Data binding was one aspect that really excited me, the prospect of having your view automatically register updates to data in your model would save a lot of complexity. Also, the documenters of Cairngorm did a pretty good job of dictating exactly what the model does (and what it shouldn’t do), too often the model gets pulled into doing things that it shouldn’t strictly be doing. In several past projects, I would often find myself bastardizing the model and including alot of functionality that really belonged in other areas of the framework. When a deadline is looming, the first instinct is often to stop adhering strictly to standard design patterns. All of the promises brought by Cairngorm when combined with the promise of AS 3 finally fixing the awful performance hits you would take in extending classes has made alot of developers pretty excited to work in AS 3.
Even though I don’t personally play World of Warcraft anymore, I thought it would be a perfect place to build a Cairngorm based Flex app, as there seemed to be a lot of interest in the population statistics in WoW but very little actual effort to document them. So here was the initial idea behind the project. I wanted to allow people to select their server (or any combination of US and EU servers), and see population statistics on that data set. I designed a 3 window usage scheme, dividing each of the main functions of the application. You would start by selecting your server set, followed by selecting the particular statistics that interested you on that data set you had previously selected. Finally, you would view the resulting charts showing graphically the statistics you had requested.
I built the model around that concept at first, downloading the XML file located on the realmstatus page of the World of Warcraft homepage:
http://www.worldofwarcraft.com/realmstatus/status.xml
Working with XML in flash is just as easy as it was before, though the package most people are used to working with is now deprecated. In the end it was pretty easy to get this part working, a simple TileList in MXML with custom HBox’s each containing a few labels and possibly a picture for each server. Creating a custom item renderer was fairly easy, and pretty well documented. Interestingly enough, there didn’t seem to be a happy medium for me on this, I remember switching back and forth between a TileList and another type for the data. One scrolled too slow and the other rendered initially too slow. Looking through the documentation, I can’t seem to find where I read that one list type renders all elements up front, and the other renders them as they are displayed. At any rate, a VBox containing a few labels and an image was enough to cause the app to choke a little. There are over a hundred World of Warcraft servers, but that isn’t all that large of a data set to be working with I thought. Perhaps I was being inefficient, but at any rate I wasn’t all that impressed with the speed of the visual list components, I imagine if efficiency is a high enough priority you may end up creating your own custom list components.
After finishing this portion of the app, I set to work on getting the actual data I would parse sort and run statistics from. I found this site, that was a gold mine of data:
http://www.warcraftrealms.com
Although you could question the accuracy of the data, I would treat it just like Alexa. Since the data is gathered from a plug in that has to be voluntarily installed in a users mods section of the WoW client, the data gathered is at best a sample of the entire user-base. At any rate, with some advice from a PHP expert (thanks Rick!) I cooked up a simple PHP script that would download and unzip the data from the warcraft realms site.
I found that when each server had its own data set, the combined uncompressed file size total was 11 megs! Keep in mind these are just CSV text files, so it was a lot of data. That large of a data set proved to be too much for Flex to handle if it was to parse all at once. It took several minutes alone for the PHP script to run and create the files, meaning I would have to set up a cron job to run after hours to keep the data up to date. It took Flex anywhere from three to five minutes to parse the entirety of the data, and I found that sorting and massaging the data for charts was proving to be overwhelming. After thinking about it for a few days, I decided to re-scope the project rather than attempt to gain efficiency in only parsing subsets of the data at a time. After all, I felt like most people would be just as interested in the combination of all servers at once as they would be with just one server at a time. So I narrowed down the focus, and instead of downloading each individual server’s data, I downloaded one combined file containing the population data for all servers combined. This proved to be much quicker to parse and work with. However, this rendered the first part of the application useless, as users at this point would no longer have control over the area of the data set they wanted to see statistics on.
Here is where I noticed the first boon of Cairngorm. In the past, a change like that after having written a thousand or so lines of code would have been catastrophic, requiring a major redesign on the code base. Instead, I just removed the XML parsing from the command class, I removed the mxml pane I had coded for the list, and I removed the list components. I had recovered from that major design change in under a few hours. Nice.
After recovering from that design change, I set to work implementing the arrays that would feed the charts. Since these arrays were really just sub sets of the data contained in the model, I came to the conclusion that they really didn’t belong in the model. Instead, I put them in a util section and made a class with a static getInstance() method, very similar to how Cairngorm models work. That decision proved to work pretty well, as I was able to access that charting data and populate those charting arrays anywhere in the application. They were outside of the view and the model in their own util folder as well. Since that code proved to be the most lengthy and complex of all, having it outside of the view and model turned out to really help with organization, and it also kept the model nice and simple.
I then set up the event firing structure. When someone clicked that they wanted to view the distribution of classes by faction, I would fire an event that would be caught in the main.mxml file. Ultimately I would like to move that event capture out of the main.mxml file and into a view helper, as they seem a bit out of place where they currently are. At any rate, that event would cause a function to be called, that initiated the arrays in the ChartingDataLocator class, changed the state of the app, and called a function in a sub mxml view component to build the charts and bind them to the data contained in the charting locator. Working with Flex Charting was pretty easy, and being able to dynamically create mxml components such as VBox’s and populate them with charts and labels seemed really natural. I felt like I smoked through that section of the application and had all three of my initial queries on the data built fairly quickly. All it took was an actionscript extension of a VBox or HBox, that would dynamically load itself with the mxml extended charting components. After completing that, my data seemed to be off. When searching for the reason my data seemed to be incorrect, the next advantage of Cairngorm became apparent. Because everything is compartmentalized, there was no question as to where I should be looking. I verified the data in the model, and then immediately knew the problem was located somewhere in the ChartingDataLocator. I found the culprit, a switch statement with no breaks in it, smooth move Chris. After running that, the data looked much better, and I set to work to try and fix the butt ugly default fonts on all my buttons, labels and charts. Let me say that working with fonts in AS 3 still sucks. I searched many different sites, they all seemed to offer similar means to embed the font, none of which worked correctly. After consulting the Flex help, I found that embedding the font using CSS seemed to work pretty well. I’d like to eventually go back and see where embedding the font in ActionScript went wrong, probably some silly property or small detail that I’m unaware of.
If you’re still reading at this point I applaud your attention span and I won’t make you suffer through any more of this today. Just know that overall my experience was positive with Cairngorm, I had only a few small gripes, mainly involving a lack of direction and strategy from Adobe involving events that only belong in the view. Even though I only had a few events that fall into this category I felt like it could get out of control very fast and cause most people to make a mini-controller just to handle view events. I also felt like developing with Cairngorm is far slower up front, requiring alot of additional code to adhere to the design pattern, but you’ll be thanking yourself for taking that extra time if you have to change the app later.
As for next steps with this app, I plan to tackle some charting effects and see how easy it is to further customize and encapsulate MXML components. I’d also like to implement some history into the app, so that you could see how the population and class bases in the game change over time. I have a feeling that the usage of particular classes swing wildly as Blizzard alternately buffs and nerfs each class.
Recent Comments