A C C O U N T

B A N   T H E   R E W I N D

My name is Stephen Schieberl. I am a Creative Technology Lead at Wieden+Kennedy in Portland, Oregon. I build everything from large format installations to experimental interactive art to database-driven web sites and more.

Friend on Facebook
Ban the Rewind?

Flash has had incredible staying power as the standard in delivering rad stuff on the web. Yet the end of that run came into sight this year as HTML 5 gained popularity and Apple announced that it wouldn't support the Flash player on their seemingly-almost-as-ubiquitous portable devices. Pretty much every career Flash developer I know scrambled to translate their code into JavaScript until Apple lifted the embargo, and Adobe got on the stick in making some important updates to their player. Flash Player 10.1 and Flex SDK 4.1 both introduced some new features to usher the platform into the modern age. We just need to take advantage of them. CLOUDBURST The application I've developed for this piece is called "Cloudburst". This SWF takes a word, looks it up against delicious.com 's API, returns related tags, and uses them to generate some interesting imagery. While simple on the surface, this application showcases almost everything you should be doing with AS3. Multi-touch, server communication, memory management, custom events, and more. Click here to view the SWF in action. Download the source / Flash Builder project here Cloudburst.zip OUT WITH THE OLD, IN WITH THE NEW I've put this article and project together to share what I feel are best practices for writing ActionScript today, as well as do away with some detrimental habits. These are things I feel not only take advantage of recent improvements in Flash, but have also helped me to cut back on development time and improve stability my Flash applications. This is less a tutorial and more advice based on over ten years in active Flash development. OUT: SLOPPY CODE IN: COMMENTS AND AUTO-FORMATTING Pictured: Well-formatted code against realistically sloppy code. Click for full-size image. Click on this image here and take a moment to study the code on each side. These both do the same thing, and they both compile. But which would you have rather written when its time to open this class for the first time in a month at 3am, just hours before a deadline? If you went with the option on the left, you may be able to avoid this scenario altogether. Far and away, the most damaging mistake I see amongst Flash developers is sloppy code. Hours spent pinning down a minor issue often come down to a misspelled string, overlooking or removing a function the developer doesn't understand (yet wrote themselves), or wrong data type coercions. In the world of strong typed languages like C++ and Java, or .NET managed languages, etc; these mistakes are far less of an option. The development tools and known best practices in these communities result in far cleaner code. The Flash world needs to adopt these habits. A few rules to live by: Thoroughly comment your code! Even if you are the only developer, it's far faster to read plain English when you revisit code than have to interpret it in your mind. Use long, explicit variable names with data type pre/suffix. "velocity_pt" tells me that this property is a point with velocity coordinates. "v" tells me nothing. Datatype your properties. You'll get code hints and you won't get lost. Auto-format ON! Every IDE out there has auto-formatting. Use it! You can often customize these to fit your style. If not, adapt. Use constants. If you type the same string more than once, use a constant instead. It will save you time if that value needs to change. You'll experience fewer debugging headaches when you misspell or use the wrong case in one occurrence. Alphabetize. Listing your variables and functions in alphabetical order makes them a snap to find. More classes, less code. As soon as you hit several hundred lines, it's time to re-evaluate what you need in this class and what can be moved out to helper classes. Don't store unused code in comments. Use versioning software, like Subversion for Flash Builder / Eclipse Pictured: A screenshot from "Cloudburst", this article's example application OUT: DESIGN PATTERNS AND SINGLETONS IN: JUDGMENT AND STATIC EVENT DISPATCHERS I'm not exactly sure when it happened, but it seemed like maybe two years ago or so, I missed a memo that went out to the Flash community about design patterns. In addition to being fundamentally ambiguous, design patterns seem to have given the Flash world the impression that there is somehow a one-size-fits-all solution to every project. There is not. There is also the issue that even if a design pattern is spot on, it may not be implemented correctly and this alleged harmony between developers is not only lost, but potentially more broken than usual. Take each project on like you'd take on anything in life -- create a path to your goal using an amalgamation of your knowledge and experience. If you're working with a team, develop it together. The biggest culprit I've had to deal with is the singleton constructor. Singleton construction makes sense when you are developing a resource-hungry desktop application and you don't want a user to open multiple instances of it. It's completely superfluous Flash. It's even more absurd when someone is jamming it into a simple slideshow presentation with a few button clicks (I've seen this on several occasions). The allure of the singleton is that you can have a place to access data and functions without traversing the display object tree. To answer that, I offer a far more flexible, less complicated tool: the static event dispatcher. It's nothing new. Grant Skinner wrote an article on it in July 2007. You're probably already using Tweener and/or SWFAddress, which handle these duties. Here is an AS3 static event dispatcher: package { // Imports import flash.events.EventDispatcher; // Static event dispatcher template, rename to your class public class StaticEventDispatcher { // The event dispatcher private static var event_dispatcher:EventDispatcher; // Adds event listener public static function addEventListener(type:String, listener:Function):void { // Create event dispatcher, if needed if (event_dispatcher == null) event_dispatcher = new EventDispatcher(); // Add event listener event_dispatcher.addEventListener.apply(null, [type, listener]); } // Removes event public static function removeEventListener(type:String, listener:Function):void { // Return if no event dispatcher if (event_dispatcher == null) return; // Remove listener event_dispatcher.removeEventListener.apply(null, [type, listener]); } // Dispatches events public static function dispatchEvent(e:Event):void { // Return if no event dispatcher if (event_dispatcher == null) return; // Dispatch event event_dispatcher.dispatchEvent.apply(null, [e]); } } } If you check out the "UI" and "Feed" classes in the attached "Cloudburst" project, you'll notice that they are both based on the static event dispatcher. They also store properties and other functions related to their role. For each of these, I've also created some custom event classes. When I click on a tag in this SWF, it calls this: // Tell UI manager that this was clicked UI.dispatchEvent(new UIEvent(UIEvent.CLICK, parent.getChildIndex(this))); I have a listener on the root which responds to the "UIEvent.CLICK" event. // Initialization public function Main() { // Add UI event listeners UI.addEventListener(UIEvent.CLICK, clicked); ... } // Called when a tag is clicked private function clicked(e:UIEvent):void { // Get tag var tag_mc:Tag = tags_mc.getChildAt(e.childIndex) as Tag; // Remove other tags var children_num:int = tags_mc.numChildren; for (var i:int = 0; i < children_num; i++) { if (tags_mc.getChildAt(i) != tag_mc) Tag(tags_mc.getChildAt(i)).Remove(); } } Clicking the tag clip told the UI class to dispatch a "click" message, and included the index of the clip. When the root receives this message, it removes all clips except for the one noted in the event. There is no need for any sort of instance of "UI" to exist. Using static event dispatchers as hubs of communication for interaction, server transactions, asset management and loading, etc, provides a lightweight way to store constants, variables, and helper functions, laying the foundation for rock solid, manageable Flash development. OUT: XML IN: JSON There is absolutely no reason to use XML anymore, plain and simple. The big feeds are switching to JSON. JSON is more native to Flash than XML now with easy to use de/serializers, most notably that in as3lib . It's more sensible to translate database results to JSON. JavaScript uses it natively. And in Flash, it converts to native arrays and objects. This blog even uses JSON for its backend. It's less data, meaning faster tranfers. No more E4X and its non-Flash syntax. Long live JSON! OUT: PRELOADERS IN: EFFICIENCY Flash's original mission was to deliver "rich media" across low bandwidths by using vector graphics. Somewhere along the line, including a lot of fonts, raster graphics, and other bloat became acceptable and folks were introduced to sitting through the over-stylized preloader. With wired broadband, this became less of an issue. Now that people are getting online more with their low-powered netbooks and portable devices on mobile connections, the need for smaller, faster web applications is back. Flash has always been able to do big things in small files with some creative programming. The "Cloudburst" application attached here is only 38k, and that's almost all because there is an embedded font. The smarter way to get Flash on the web, and to compete with HTML 5, is to work more like a web page -- render the screen as soon as you can and load data and assets on demand. To aide in making frequent server communication less of a hassle, I've developed a utility called "HttpRequest", which is essentially a wrapper for the many lines of code that would usually go into using URLLoader and URLRequest. It's included in this project under core.utils. Rather than dump the entire class here, let's take a look at a sample implementation: // Build an array of objects to send to the server var my_array:Array = new Array(); my_array.push({ foo: "value1", bar: "value2" }); my_array.push({ foo: "value3", bar: "value4" }); // Make request sending data as JSON var http_request:HttpRequest = new HttpRequest( "http://www.foo.com/bar.aspx", { my_array }, URLRequestMethod.POST, true); // Add result listeners http_request.addEventListener(HttpRequestEvent.COMPLETE, onSuccess); http_request.addEventListener(HttpRequestEvent.ERROR, onError); Here, I'm building an array of objects and passing it to the HttpRequest inside an object. I'm also setting a flag telling it to interpret the data as JSON. Then I just add two listeners. The second argument, which is the data I'm sending, can be JSON, a generic object (will be parameterized), XML, plain text, or even binary data. The custom events contain pertinent messaging. The returned data, of any type, can be accessed from the HttpRequest object's "data" property. I've found this tool to be indispensable in increasing Flash's server calls to reduce a SWF's initial load. OUT: ROLLOVERS IN: MULTI-TOUCH When Steve Jobs was bashing Flash this past Summer to justify leaving it off the iPad, he did have a valid point: mouse effects do not work on touch screens. The more I thought about it, the more I realized how ultimately pointless and gimmicky rollovers are. They really haven't been cool since like 1998 when we discovered the "hover" attribute in CSS. Windows 7, iOS, Android, and Windows Phone all support multi-touch and have been implemented on mass-produced screens and devices. Apple's notebooks and mice, and even my Vaio laptop, all support at least two-points. Multi-touch gestures are here and Flash has made them extremely easy to use in Flex SDK 4.1. It's a common misconception that AIR is required to run multi-touch Flash, but if you have Flash Player 10.1 or better and a multi-touch device, you can try out the pinch gesture on the "Cloudburst" SWF, right in your browser, to zoom in and out on the tags. Read up on the Multitouch class in the AS3 reference here . OUT: WANTON OBJECT CREATION IN: WANTON OBJECT DESTRUCTION Last in this list of do's, but absolutely not least, is memory management. If you run "Cloudburst" with a memory monitor open, you'll notice it never climbs too high. No matter how many times you click to generate tags, draw all over, etc, it keeps resource usage to a minimum. It will climb to maybe 25 - 30mb of memory, then drop almost in half when the garbage collector kicks in. My secret weapon here is a template I use for all display objects called the "SelfCleaningSprite". Let's take a look: package { // Imports import flash.display.Sprite; import flash.events.Event; // Class description public class SelfCleaningSprite extends Sprite { // Initialization public function SelfCleaningSprite() { // Wait for add addEventListener(Event.ADDED_TO_STAGE, function(e:Event):void { // Remove listener removeEventListener(Event.ADDED_TO_STAGE, arguments.callee); // TO DO: Instantiate objects here // Listen for remove addEventListener(Event.REMOVED_FROM_STAGE, function(e:Event):void { // Remove all event listeners here removeEventListener(Event.REMOVED_FROM_STAGE, arguments.callee); // Remove children var children_num:int = numChildren; for (var i:int = 0; i < children_num; i++) removeChildAt(0); // TO DO: Set instances to null here } ); } ); } } } The first thing to note is that I have a listener that waits until the clip is added to the stage. I put most of the logic in here, so that class instances are not created until I actually display the object. When the object is removed from the stage, it automatically removes event listeners, removes children, and nulls all object instances. If the children of this object also use this template, they too will clean themselves. Removing this object sets off a chain reaction of cleanliness that you don't even have to think about. KEEP IT CLEAN The theme here is simply organization and cleanliness in your development. Good coding habits can take awhile to acquire and may seem like more work at first. If you take the time to really organize your logic, write comments , and make your code as close to human-readable as possible, you can stay on top of it to save time and build a better-working application in the long run.