Archive for the 'ActionScript 2' Category

What is SWX, how does it work, and where is it going?

I do some of my best thinking (and singing) in the shower. So it's no surprise that this morning, while in the shower, I decided to review my plans and roadmap for SWX. Here's a direct-from-the-shower look at what SWX is, how it works (with a few examples to get you up and running), and roadmap of where SWX is heading.

Some of the contents of this post will be familiar to my friends at Yahoo! UK, where I presented SWX earlier this month. (Thank you guys for your amazing support, it means a lot!)

Definitions

Let's start at the beginning with some definitions. When I first embarked on SWX, the technology and implementation were one and the same. Several months on, SWX has matured and simply bundling everything in the SWX ecosystem as "SWX" is not sufficient. To that end, here are some definitions of SWX-related concepts to start us off with a common vocabulary for talking about SWX.

  • SWX: Native data format for Flash. It is a subset of the SWF format. SWX SWFs are regular SWF files that are used to store just data.
  • SWX RPC: RPC protocol encoded in SWX. Allows you to call methods on server-side classes and get the results in SWX format.
  • SWX PHP: SWX RPC implementation in PHP. SWX PHP is currently the only implementation of SWX RPC but there will be Python, Ruby, J2EE, .Net, etc. implementations in the future.
  • SWX Tools: The SWX Service Explorer & SWX Data Analyzer. These tools come bundled with SWX PHP and will work with any future implementations of SWX RPC.
  • SWX AS: A high-level ActionScript library that handles 
the client-side queuing and execution of SWX RPC calls. You don't have to use the ActionScript library to work with SWX RPC as SWX is native to Flash but the library does provide you with useful functionality such as cross-domain access, queueing of data calls, etc.
  • SWX APIs: APIs for Flickr, Twitter, etc. I am as excited about the SWX APIs as I am about the SWX data format and SWX RPC as they provide Flash developers with a very easy way to create mashups. In fact, if you hit the Public SWX RPC gateway (see below) at swxformat.org, you can use these APIs with ActionScript alone (no server-side programming is necessary.)
  • Public SWX RPC gateway: Open SWX RPC endpoint. The Public SWX RPC Gateway
is at http://swxformat.org/php/swx.php. You can use the public SWX
APIs from this gateway in your own applications without having to
write any server-side code whatsoever.

Supported platforms and technologies

Swx Supported Platforms

You can create and load SWX SWF files with any version of Flash (5+) as they are simply SWF files. As far as manually creating SWX files go, SWX is supported on Flash 5+.

SWX PHP, the current SWX RPC implementation that I'm working on, creates SWX files that are compatible with Flash 7+ Flash 6+, Flash Lite 2.0 and Flash Lite 2.1. Currently, SWX PHP does not support Flash 9/AVM2 but it will eventually do so.

SWX AS, the SWX ActionScript library, compiles on Flash 7+ Flash 6+ and MTASC.

You can use SWX PHP currently to create applications that run on mobile phones (Flash Lite 2.0/2.1), the Nintenso Wii, Sony PS3, and devices like the Nokia N800 internet tablet and the Chumby.

You can also wrap SWX-based applications to create desktop versions using Adobe Air.

SWX (SWF Data Format)

SWX is the native data format for Flash. Data is stored as SWF bytecode (you can't get more native than that on the Flash Platform) that is interpreted by the Flash Player. The SWX format is a subset of the SWF format (just like JSON is a subset of JavaScript).

SWX is open. I am in the process of writing an Internet Draft (I-D) for SWX which I hope will become an informational RFC.

You loadMovie() SWX data files and they are ready to use the moment they are loaded. You don't need to deserialize or massage the data in any way before using it as it is stored in native Flash objects.

Why do we need a new data format?

When I first announced SWX, Patrick Mineault questioned whether SWX was reinventing the wheel. Why, he asked, do we need SWX when there is AMFPHP? (AMFPHP is a PHP implementation of a Flash Remoting gateway).

To start with, comparing SWX and AMFPHP is like comparing apples and oranges. As I stated earlier, SWX is a new data format for Flash and SWX RPC is a remote procedure call protocol encoded in SWX. As such, we can compare SWX to AMF (the data format) and SWX RCP to Flash Remoting (the RPC protocol) and SWX PHP (my PHP implementation of SWX RPC) to AMF PHP.

So the real question becomes, does the Flash Platform need a new data format and a new RPC protocol? I believe it does and here are some reasons why:

  • Existing formats are non-native, complicated, require parsing and/or writing plumbing code e.g., XML, variable-encoded strings (LoadVars, loadVariables), Flash Remoting, etc.
  • SWX files have low processor overhead when parsed by the Flash Player as they are native (SWF bytecode)
  • SWX RPC is the only RPC solution for Flash Lite 2.0 and 2.1 (and thus for mobile Flash applications). Flash Remoting does not work with Flash Lite.
  • Most important: SWX, being native, has inherent advantages such as cross-platform data exchange (via allowDomain support for SWF files), simplicity (no ActionScript library is necessary to use it), etc.

It's my first belief that every platform can benefit from a native data format that does not require parsing. The main advantage of SWX over other data formats and of SWX RPC over other RPC solutions is ease of use. I hope that this ease of use will spur a wealth of development of data-driven applications and mashups on the Flash Platform by developers who may traditionally have shied away from creating such applications because it was just too darn hard to do so.

SWX RPC

SWX RPC is a remote procedure call protocol encoded in SWX format. You use it to call methods on server-side classes (called services in SWX RPC) and get the results returned to you in SWX format.

SWX RPC is open. I am in the process of writing an Internet Draft (I-D) for SWX RPC which I hope will become an informational RFC.

SWX RCP is stateless, lightweight, and uses HTTP as the transfer protocol.

A typical SWX RPC call involves parameters sent from Flash to the SWX RPC endpoint (gateway) in JSON format. These consist of serviceClass, method, and args parameters that define the method on the service class that you want to call on the back-end and the arguments that you want to send to that method. The resulting data is returned to Flash in the result property.

SWX PHP

SWX PHP is a SWX RPC implementation in PHP. It is open source.

SWX PHP is written in pure PHP. It doesn't require any extensions and runs under both PHP 4 and 5. (As such, it runs without problems even on shared hosting accounts.)

SWX PHP has a SWX RPC endpoint (gateway) and an assembler that creates and returns SWX files. Your service classes contain business logic only.

SWX PHP comes with service classes (APIs) for Flickr, Twitter, Ten Word Review, Nabaztag, etc. There is a publicly accessible instance of SWX PHP running on swxformat.org at http://swxformat.org/php/swx.php. You can access these APIs from this public gateway without hosting your own instance of SWX PHP if you want to build mashups using just these APIs.

SWX PHP uses Amfphp as a library and this means that you can also hit SWX PHP services via Flash Remoting, JSON and XML-RPC. (In other words, you're not locked into using SWX RPC and you can switch easily between these various technologies if you want to.)

SWX PHP comes with a plain vanilla installer (unzip it into your web folder on the server and go) and as a MAMP Bundle (everything you need to get up and running with SWX PHP on OS X). I am planning on creating Windows and Linux bundles as well in the future. In the meanwhile, I recommend using WAMP on Windows and XAMMP on Linux is you want to quickly get up and running with a server (Apache + PHP, etc.) on your development machine.

SWX PHP adheres to SWX’s core philosophy of Systemwide Simplicity.

Systemwide simplicity

A system is only as simple as its most complicated part. It's not enough to just simplify individual components and processes, you must also simplify the relationships and interactions between components and sub-processes. Systemwide Simplicity takes a wider approach to simplicity that involves understanding and supporting the entire user experience.

It is thus my aim to make it as easy as humanly possible for Flash developers to start creating data-driven Flash applications from the moment they arrive on the SWX homepage to the moment they first get data into Flash using SWX RPC.

How simple is SWX? Moo card example

SWX is so simple that instructions for getting data into Flash using it easily fit on to a Moo card. (In fact, I've just ordered two sets of Moo cards with just this example on them -- ask me for one if you see me around!)

To get a list of the most recent 100 photos from Flickr into Flash, do the following:

  • Open up the SWX Data Analyzer
  • In Flash, create a new FLA and create a movie clip on the Stage. Give it the instance name loader.
  • Write the following code on to the frame that the loader movie clip is on:
loader.serviceClass = "Flickr";
loader.method = "swxPhotosGetRecent";
loader.debug = true;
 
loader.loadMovie("http://swxformat.org/php/swx.php", "GET");

That’s it! Test your movie and look in the SWX Data Analyzer to see the results being loaded in to Flash from Flickr. That’s how simple SWX is.

If you want to display the results from within Flash, create a long, single-line dynamic text field on stage and give it the instance name status. Add the following code to the timeline:

function onEnterFrame()
{
    status.text = loader.result.photo[0].src;
}

Initially, the status text field will display undefined until the data is loaded and then it will display the URL of the first photo from the list of recent photos that is loaded from Flickr. Notice how you can access the results as native Flash objects the moment they’re loaded. No deserialization or massaging of the data is necessary!

Read the next section to see a better way of handing results using SWX AS and the SWX Class in ActionScript.

Building a complete web application (back-end and front-end) with SWX PHP

In the next ten minutes you are going to learn everything there is to know about exactly how SWX PHP works by building a very simple, but complete, data-driven Flash application. You will be using Flash to create the client and PHP (with SWX) for the server.

Installing SWX PHP

If you haven’t done so already, download and install SWX PHP on to your computer. Before installing SWX PHP, you will need to have a web server running PHP on the machine you’re installing it on.

If you’re on a Mac, running OS X, download and install the SWX PHP MAMP Bundle. This will have you up and running with everything you need using a simple installer.

If you’re on Windows, I suggest installing WAMP and, on Linux, XAMMP. Both of these are single-click installers that provide you with a turnkey development environment with a web server (Apache) and PHP.

Once you’ve installed a web server and PHP, just download SWX PHP and unzip it into your web root. Start your web server and hit the web root in your browser to access the SWX PHP Start Page.

Swxphp Start Page


Getting Started

The application you’re going to build is a simple calculator that uses a server-side method to add two numbers together.

To start, you're going to create a PHP service class. In SWX you place service classes under the php/services folder.

SWX Service Explorer

To see what services are already in the services folder, you can use the SWX Service Explorer that comes with SWX PHP. Open that now and you will see that there are several services there already.

Swx Service Explorer

Creating the Calculator service class in PHP

Create a new file using your text editor of choice under php/services/ and call it Calculator.php.

Add the following code to Calculator.php and save the file:

 
<?php
    class Calculator
    {
        function addNumbers($n1, $n2)
        {
            return $n1 + $n2;
        }
    }
?>

This is a very simple server-side service class that has a single method called addNumbers(). This method takes two numbers as arguments and returns their sum.

At this point, it would be nice if you could test the server-side method you just created without having to create a Flash client. SWX Service Explorer lets you do just that.
Testing server-side methods with the SWX Service Explorer

Return to the SWX Service Explorer (or open it if you didn't earlier) and you will see the Calculator class you just created. Click on it and you will see the addNumbers() method that you just created. Enter two numbers in the $n1 and $n2 fields and press the call button to test out the method. You should see the sum returned in the results area.

Your server-side service method is working correctly. Now let’s call it from Flash.

  1. Open up Flash and create a new FLA (ActionScript 2). You can set the publish setting to Flash 7 or 8.
  2. On Frame 1 of the new FLA, create a movie clip instance and give it the instance name dataHolder.
  3. Create a new layer and call it Actions. On the Actions layer, add the following code:
dataHolder.serviceClass = "Calculator";
dataHolder.method = "addNumbers";
dataHolder.args = "[35, 7]";
dataHolder.debug = true;
 
dataHolder.loadMovie("http://localhost:8888/php/swx.php", "GET");

That's it! That's all the code you need to call the addNumbers method on the Calculator service class in PHP and pass it the numbers 35 and 7 as arguments. The loadMovie calls the SWX gateway and passes to it any of the properties you set on your movie clip. In this case, since we are sending a small number of arguments, we use the GET HTTP encoding method. We could just as easily have used POST.

SWX Data Analyzer

Before testing the movie, open the SWX Data Analyzer in a separate browser window.

Swx Data Analyzer

SWX Data Analyzer is a debugging tool that shows you the SWX data that arrives inside your Flash movie.

To make SWX data that loads into the Flash player appear in Analyzer, you turn debug mode on. That's what the line dataHolder.debug = true does.

Now, test your movie and then look in the Analyzer. If all went well, you should see the number 42.

Accessing the result property

That's great, but now let's display that result in Flash. You're going to implement a quick hack to get it working and we can evolve the application later to improve it.

Add a TextField instance to the Stage and give it the instance name status.

Next, create an onEnterFrame handler that prints out the value of the result property of the dataHolder movie clip into the status text field.

The complete script at this point is shown below:

dataHolder.serviceClass = "Calculator";
dataHolder.method = "addNumbers";
dataHolder.args = "[35, 7]";
dataHolder.debug = true;
 
dataHolder.loadMovie("http://localhost:8888/php/swx.php", "GET");
 
<strong>function onEnterFrame()
{
    status.text = dataHolder.result;
}</strong>

Test the movie and you should see the number 42 appear in the status text field.

Now stop for a moment and take a deep breath: You now know exactly how SWX RPC works!

You didn't import any classes, you aren't using an API, you didn't include any external code whatsoever. SWX is completely native to the Flash platform and, if you want to, you can make use of it by using only built-in Flash features like you did here.

Compare this to other technologies like Flash Remoting. Do you actually know exactly how Flash Remoting works? There are numerous classes, lots of code, etc. There's some magic involved that you don't really understand. Not so with SWX RPC. With SWX RPC, your data arrives in native Flash format.

It's important for a technology to be so simple that you can actually conceptualize it completely. However, that doesn't mean that the above method is the way you'd want to use SWX PHP on a daily basis.

For one thing, take a look at how you set the arguments. It's a string. In fact, what you did was serialize the arguments you're sending in JSON format. It's not confusing or difficult to this by hand if you are sending simple arguments like two numbers but what if you wanted to send an array of complex objects over? It would get tiresome and impractical very quickly.

The example you just created uses the No API method. In other words, you used pure Flash. No additional classes.

However, to make your life easier, you may want to use just a little API. Specifically, a method to serialize your arguments into JSON format for you would be nice. The SWX AS minimal API provides just such a method. Modify the code sample so that it matches the listing below:

<strong>import org.swxformat.SWX;</strong>
 
dataHolder.serviceClass = "Calculator";
dataHolder.method = "addNumbers";
dataHolder.args = <strong>[35, 7]</strong>;
dataHolder.debug = true;
 
<strong>SWX.prepare(dataHolder);</strong>
 
dataHolder.loadMovie("http://localhost:8888/php/swx.php", "GET");
 
function onEnterFrame()
{
    status.text = dataHolder.result;
}

Notice the lines that have been added and the line that had changed (in boldface). The prepare() static method of the SWX class simply serializes your arguments into JSON format for you. Notice that the args property in your dataHolder is no longer a string but an ActionScript array with two numbers inside it.

This is definitely far better than manually serializing your arguments by hand but it's still not ideal, is it? For one thing, that onEnterFrame function we're using is not a good practice. It would be really nice if we could have an event handler called when the data arrives instead of polling for it. The SWX AS Full API provides that functionality (and a few more).

Modify the code listing so that it matches the one below:

import org.swxformat.SWX;
 
<strong>var swx:SWX = new SWX();
swx.gateway = "http://localhost:8888/php/swx.php";
swx.encoding = "GET";
swx.debug = true;
 
var callParameters:Object =
{
    serviceClass: "Calculator",
    method: "addNumbers",
    args: [35, 7],
    result: [this, resultHandler]
}
 
swx.call(callParameters);
 
function resultHandler(event:Object)
{
    status.text = event.result;
}</strong>

When you run the above example, you should again see 42 in the status text field. Let's look at what has changed.

When using the SWX AS Full API, you actually instantiate the SWX class and set some properties there (such as the gateway URL, encoding method and whether you want debug information for calls).

Instead of putting call-related parameters directly into a movie clip (you can delete the dataHolder movie clip now as you aren't using it any more), you create a callParameters object and specify the serviceClass, method, and args properties there. But you can do more, you can also specify a result handler that will get called once the data has loaded.

The result handler receives an event object as an argument. That event object has a result property that points to the loaded data.

The SWX AS Full API doesn't stop there. You can also specify a timeout handler to handle calls that take too long.

Modify the listing so that it matches the one below:

import org.swxformat.SWX;
 
var swx:SWX = new SWX();
swx.gateway = "http://localhost:8888/php/swx.php";
swx.encoding = "GET";
swx.debug = true;
<strong>swx.timeout = 2;</strong> // seconds
 
var callParameters:Object =
{
    serviceClass: "Calculator",
    method: "addNumbers",
    args: [35, 7],
    result: [this, resultHandler],
    <strong>timeout: [this, timeoutHandler]</strong>
}
 
swx.call(callParameters);
 
function resultHandler(event:Object)
{
    status.text = event.result;
}
 
<strong>function timeoutHandler()
{
    status.text = "Call timed out!";
}</strong>
 

The default timeout duration is 30 seconds but you can override that, as shown here.

In order to make the call actually time out, modify the Calculator class in PHP too to make it sleep for 10 seconds before returning the result. The Calculator class should match the one in the listing below:

&lt;?php
class Calculator
{
    function addNumbers($n1, $n2)
    {
        <strong>sleep(10);</strong> // Make the call time out!
        return $n1 + $n2;
    }
}
?&gt;

Now test your Flash movie and, after two seconds, you should see the SWX call time out. Timed-out calls are cancelled and will not trigger the result handler at any point in the future.

Finally, there is also a fault handler that you can use in the same way. To test it out, modify the ActionScript listing so that it matches the one below:

import org.swxformat.SWX;
 
var swx:SWX = new SWX();
swx.gateway = "http://localhost:8888/php/swx.php";
swx.encoding = "GET";
swx.debug = true;
swx.timeout = 2; // seconds
 
var callParameters:Object =
{
    serviceClass: "Calculator",
    method: "addNumbers",
    args: [35, 7],
    result: [this, resultHandler],
    timeout: [this, timeoutHandler],
    <strong>fault: [this, faultHandler]</strong>
}
 
swx.call(callParameters);
 
function resultHandler(event:Object)
{
    status.text = event.result;
}
 
function timeoutHandler()
{
    status.text = "Call timed out!";
}
 
<strong>function faultHandler(event:Object)
{
    status.text = event.fault.message;
}</strong>

And modify your class so that it generates an error:

&lt;?php
    class Calculator
    {
        function addNumbers($n1, $n2)
        {
            <strong>return $n3;</strong> // $n3 does not exist!
        }
    }
?>&gt;

Test your FLA and you should get something along the lines of Error 8: Undefined variable: n3 in /htdocs/swx/trunk/php/services/Calculator.php, line 7 in the status text field in Flash.

The fault handler also returns API-specific fault codes (e.g., Flickr API error codes) back to Flash.

And that, in a nutshell, is the SWX AS Full API.

There's more to SWX that we haven't covered in this introductory article such as the LoadManager and ExternalAsset classes that the SWX AS Full API uses internally to queue and load SWX SWFs but you can find out more information about these in more advanced tutorials to be released soon (they are useful when you want to load your own external assets like SWFs, JPGs, etc.)

Beyond making your own service classes, you can also use the existing service classes in SWX to access public APIs like the Twitter API and Flickr API. In fact, why don’t you play around with the Twitter and Flickr APIs now, using the PHP Service Browser to discover how they work? You can modify the examples above to get data from any of those APIs as easily as you have done here.

There is also a screencast of this example that you can watch online.

SWX and Flash Lite (mobile applications)

SWX and SWX RPC work in Flash Lite 2.0 and 2.1! In fact, due to its low processor overhead and native support in Flash, SWX is the ideal data format for mobile applications with Flash Lite.

Check out the MiniFlickr sample application that comes with SWX PHP for an example of how to build data-driven Flash Lite applications using SWX.

Keep in mind that, due to a bug in Flash Lite, you cannot make POST requests in a loadMovie call. Instead, you must make GET requests when using SWX RPC with Flash Lite. For more information on this, see the Mobile Limitations section, below.

The MiniFlickr application makes use of the ExternalAsset and LoadManager classes that come with SWX AS to queue all load requests (data and assets such as images). This is essential in mobile development as most handsets will fail if you try to load two things at once. The SWX AS Full API handles the queueing of requests for you and gives you a general purpose load queue that you can use in your own applications. Make sure you study the MiniFlickr sample if you want to create Flash Lite applications using SWX PHP.

Swx Mobile Device Central

SWX and SWX RPC advantages for mobile development

SWX RPC is the only RPC solution for Flash Lite and, beyond that, it works really well and is simple to use. Here is a summary of some of the advantages of the SWX data format and SWX RPC for Flash Lite development:

  • Native; data is ready to use the moment it loads as native ActionScript objects.
  • No processor-intensive parsing, etc.
  • No plumbing code for deserializing requests.
  • Public gateway and APIs for mobile mashups.
  • Only RPC solution for Flash Lite.
  • Easy to understand and use.

SWX Flickr API

As of the upcoming SWX PHP Release Candidate 1, a full implementation of the Flickr API is included in SWX PHP.

You can start playing with the SWX Flickr API right now, using the Public SWX RPC gateway. Try the methods out online using the SWX Service Explorer.

  • Implements the full Flickr API, current as of August 1, 2007.
  • Liberal open source license (MIT).
  • Provides photo upload feature.
  • Actively maintained and updated.
  • Simplest way for Flash developers to work with Flickr.

Roadmap

So where is SWX, SWX RPC, and SWX PHP going?

I realized today that I was being overly ambitious with my plans for version 1 of SWX PHP.

For one thing, I had considered getting the Flash 9/AVM2 version of SWX PHP ready in time for version 1 but that involves writing a whole new assembler. I've now decided to leave this for after the 1.0 release so that I can instead concentrate on getting a polished and stable 1.0 release of SWX PHP that includes all the learning materials, screencasts, etc. that you need to get up and running with SWX RPC.

SWX PHP already fills a gaping void in RPC solutions for Flash Lite and getting SWX PHP to version 1.0 is important in getting development houses to adopt SWX PHP for production of Flash Lite applications.

Also, the SWX assembler (the bit that creates the SWX SWF files) in SWX PHP is extremely stable and has been for a while and I want the Flash 9/AVM2 version of it to be as stable when it goes into version 1 but that's not realistically going to happen in the timeframe that I have in mind.

So, instead of working on yet another implementation, I'm going to spend the next few weeks working on the Internet Drafts for SWX and SWX RPC and on documenting the heck out of SWX so that others can create implementations of SWX RPC (in fact, if anyone is interested in undertaking the Flash 9/AVM2 implementation for PHP, please get in touch).

What is important is that eventual Ruby, Python, J2EE, .Net, etc. implementations of SWX RPC are all compatible and that they all adhere to the same philosophy of simplicity. (And thus, for example, do not require extensions, etc. or place other barriers in front of developers.)

So what is the eventual release data of SWX PHP? I'm going to be aiming for the start of September and definitely before FlashForward Boston.

I will be releasing Release Candidate 1 of SWX PHP this week so keep any eye out for that on this blog.

Also expect a number of new screencasts in the coming days, showing you how to work with SWX PHP and the various APIs and how to create mobile applications using SWX PHP.

Come September, I will be embarking on a crazy schedule of conferences, starting with FlashForward Boston to present my session Let's talk about SWX, baby!

The conferences I'll be presenting SWX at include MAX Chicago, FlashForum Conference (Germany), MAX Barcelona, FITC Hollywood, Flash on the Beach (Brighton, UK), and MAX Japan.

I hope I'll get to meet and talk with some of you at these conferences. If you see me, do come up and say hello and ask me for a SWX Moo card and a SWX Moo sticker :)

SWX: A good idea

I just read that Patrick Mineault thinks that SWX is a bad idea. Although I have the utmost respect for Patrick and I love and support his work, I respectfully disagree with him. SWX is a good idea and here's why.

(I started responding to Patrick's post in the comments on his blog but it got too long so I'm posting it here instead.)

The followering are the main points Patrick makes in his post, along with my counter-points:

Now my first point is that SWX reinvents the wheel, and for no good reason. Let's list out the various ways to do asynchronous data communication in Flash. We have LoadVars, XML, Remoting, JSON, SOAP, XML-RPC, and PHPObject. One solution seems more than enough for this very simple tasks; adding another one to these 7 seems like a complete waste of time.

I remember when Flash Remoting came out that, for a long time, people would make the same argument against it: Why do we need another way to exchange data? Why did they re-invent the wheel? And the answer is the same now as it was then: We need it because the existing methods do not meet the needs of certain people.

If we were to accept Patrick's argument at face value, there would be no reason to go beyond LoadVars and we could throw XML, Remoting, JSON, SOAP, XML-RPC and PHPObject away, labeling all of them as redundant. After all, as I mentioned in my talk at the LFPUG last night, the core concept at the heart of building data-driven applications is a glorified form of automated copy and paste. We are moving information around from one place to another. In place of trucks, we use pipes to move our data. But it's transportation, not rocket science. So anything you can do with Remoting you can do with XML and LoadVars. Based on this argument, Remoting, XML, JSON, SOAP etc. all re-invent the wheel. But that's not true. Each has its specific strengths, weaknesses and use-cases. As does SWX.

Of course, it wouldn't be if in fact SWX gave some mighty good advantages over all the other solutions. To my knowledge, however, the only positive advantage to using SWX is the ability to use getBytesLoaded and getBytesTotal, which isn't available, in, say, Remoting.

SWX does have several mighty good advantages over all of the other solutions, above and beyond giving you the ability to display a determinate progress indicator as mentioned by Patrick. (If that was the only advantage, as much as I like determinate progress bars, I surely would not have invested as much time and effort into creating this as I have!) :)

Here are just a few advantages I can think of off the top of my head that SWX has over other methods:

  • It's simpler to use.
  • Data is deserialized twice only as opposed to four times.
  • You don't have to learn a new API and can reuse your existing knowledge.
  • It is useful in mobile applications with limited processing power
  • The final downloadable bundles of SWX will contain everything you need to get up and running (you don't need to buy or download additional tools).

I want to elaborate on some of the above points, starting with the advantage of having two deserialization steps instead of four. To illustrate the point, I'll use the model that Patrick presents in his article on Clearing the FUD on amfphp’s speed versus JSON and XML (which is quite ironic since I'm clearing the FUD about SWX here!) In it, Patrick accurately states the following:

In most any RPC model, there are the following steps:

  • Serialization of the request on the client-side
  • Uploading of the message to the server
  • Deserialization of the request on the server-side
  • Dispatching on the server-side
  • Serialization of the response on the server-side
  • Downloading of the message to the client
  • Deserialization of the message on the client-side

In most any RPC model, that is, except SWX. Let's look at how the above list looks in SWX.

Steps in SWX:

  • Serialization of the request on the client-side
  • Uploading of the message to the server
  • Deserialization of the request on the server-side
  • Dispatching on the server-side
  • Serialization of the response on the server-side (i.e., assembly of the SWX SWF)
  • Downloading of the message (i.e., SWF) to the client
  • Deserialization of the message on the client-side

Straight off the bat, we remove the deserialization of the request on the server as the PHON object that is sent over is evaled, following security checks. The big advantage, however, is that we also remove the deserialization step on the client side because your Flash client is receiving a native SWF. There is no deserialization. The moment the SWF is loaded, it is ready for you to use. Just access the data structure and you're off.

Among other things, this means that there's no equivalent of the Flash Remoting Mystery Time. Once the SWF is loaded, the data structure is immediately available for you to use. Any sort of deserialization on the Flash client is going to use up processor cycles and SWX, by design, is the least processor intensive method possible since it is SWF bytecode and that's as native as you get in Flash.

Of course, time will tell how SWX compares with the other options in terms of performance, etc. but my gut tells me that a fully optimized SWX will compare very favorably indeed. It is, of course, not fair to compare it on these grounds currently as we are at a very early alpha release (think: one step removed from a proof of concept) and it is currently not optimized in any way. Most importantly, though, SWX is not in a pissing contest with other formats. It is one alternative, it is simple, and it has very valid use cases. In fact, one of the first things I am planning to do is to show people how SWX can be used alongside Amfphp and the single-package distributions of SWX will actually include Amfphp (I love Amfphp, Patrick, you know that!)

If you look at the sample code on the webpage . . . The first thing you'll notice is that dataHolder is a movie clip on Stage. That means that either you must place this empty movie clip on stage manually, or you have to use createEmptyMovieClip first. Of course, if you do the latter, you have to think about depths and whatnot. The second thing you'll notice is that there is an onEnterFrame. I thought the whole reason we dropped the use of onEnterFrame for polling a movie clip is that we had all sorts of crazy issues with that, including the difference between 0 and 4 loaded bytes.

I think Patrick is missing the point here. The key thing here is that Flash developers understand movie clips and know how to work with them. That sample code is purposefully simplistic. Of course, I will be releasing utility classes that abstract that away from you if you want to use a highler level API but the important design consideration here is that you *don't* have to learn a new API to use SWX. That's the beauty of it. You can use your existing Flash knowledge to easily create data-driven applications. And for those of you who *want* to have a higher-level interface, you'll have one. But it won't be forced on you.

Also, there is nothing wrong with using an enterFrame handler. The initial states (negative, etc.) tell you the various states that the load process is in and are actually very valuable for presenting accurate status information (is it waiting for data, receiving it, etc.) And, of course, you *can* display a determinate progress bar when you start loading the data. Apart from the usability advantages of doing so, it's just plain cool! :)

The third point is that the PHON serialization that is used relies on a prototype hack . . . So we hack toString in Array, Object and even (gasp!) String. I am not even to bother to expand as to the myriad ways in which I think this is a bad approach, but you can imagine the argument.

Ah, I just knew that people would get stuck at this point :)

Just to make it perfectly clear: The PHON serialization in SWX does *not* rely on a prototype hack. The current alpha of SWX happens to contain the automatic PHON serializer as the only option. I just didn't have the time to also release an alternative utility class that doesn't rely on extending the prototype object.

As I mentioned in my talk at the London Flash Platform User Group yesterday, this automatic workflow is very cool but you would be right to have concerns about object pollution if you use this method. Whether or not this will be a problem depends on your application. For simple apps, it should be fine. But if you're uncomfortable with it (or if you're using the toString() methods of the Object, Array or String classes for other purposes in your application), then you won't have to use the automatic PHON serialization method and you can use a manual method instead. That will involve one extra line of code:

org.swxformat.PHP.serialize(dataHolder.data);

To say that PHON serialization in SWX *relies* on a prototype hack is incorrect. The automatic PHON serialization workflow happens to be the only one I had time to implement in time for the initial launch. The manual method will follow very shortly (in fact, I think I'll get it into the next release.)

The fourth issue with this hack approach is that it is not going to work in AS3, either in Flex or in Flash 9. For one thing because you can't hack prototype, for another because the AS3 bytecode is different from the AS2 bytecode.

The current workaround to using SWX with AS3/Flex 2/Flash 9 is to use LocalConnection. In fact, this is what the SWX Analyzer (which is a Flex 2 application) does. However, this is far from ideal. I haven't even looked into how SWX may be implemented in AS3 at the moment but it is on the roadmap. Patrick is correct in that it will require a re-write of the PHP-based SWF assembler to use AS3 bytecode but there is nothing in it that is inherently impossible. And, as I outlined above, nothing in SWX relies on a "prototype hack".

SWX also had the disadvantage of being impossible to debug in Charles or ServiceCapture. Aral did a nice job with his Flex debugger, but why bother when you have native tools in your hands that do the job really really well.

I fail to see how having a free, built-in debugging tool can be perceived as a disadvantage. Surely, Patrick means that SWX has an *advantage* here! :)

When working with Flash Remoting, you need to purchase a separate tool to debug your application. Both Charles and ServiceCapture are commercial applications that you have to pay for and purchase separately.

Charles costs $50 for a single user license, and ServiceCapture costs $34.99.

SWX with the built-in SWX Analyzer, in contrast, costs $0.

(And it comes in the box so you get everything you need in one download.)

On a personal note, I found Charles to be highly annoying when I was evaluating it. Both the cumbersome interface and the constant "buy me now" nagging in the evaluation version. However, I do love ServiceCapture and I've bought multiple licenses for it over the years. It is far more than a remoting debugger (although it is wonderful for that purpose) and there is no reason why you cannot use ServiceCapture alongside SWX for its other features, such as the very useful network bandwidth throttling feature.

I could go on: SWX doesn't have anything for batched calls, or for typed objects, and I can hardly see how it could be put to use on a serious RIA.

It's true that SWX doesn't have batched calls, typed objects (yet) and that it may not be your first choice for a "serious RIA". But it's not for "serious RIAs". In fact, I'm fucking sick of "serious RIAs" and look forward to using SWX in fun projects that are in no way serious :)

You might argue that SWX is not meant to be used in RIAs, it's better for smaller projects, but that's why we have LoadVars and XML. Honestly I really don't see the point.

The whole idea behind SWX is that it is far easier to use than both LoadVars or XML that it is in a different class altogether when it comes to simplicity.

With LoadVars, you need to serialize your data into some custom format and then deserialize it yourself. This is a lot of useless plumbing code that no one should have to write. I had to write routines to deserialize complex arrays before but that was in Flash 5 when we had no other choice. Life is way too short for you to spend it writing this sort of useless code. All it does is bloat your application and take time away from actually creating your application and having fun with it.

XML. Where should I start? Have you ever worked with XML in Flash. It's not pretty is it? Until E4X in AS3, using XML in Flash was akin to pulling teeth without anesthetic. Another helping of firstChild, lastChild, bastardChild anyone? No, I didn't think so. Of course some people used helper classes that mixed in object-style look-up functionality to XML structures but how many people, really, even knew about these. In my experience, very few. Many people I see end up converting the XML structure into an object structure and then using that. Umm, but that's exactly what you get with SWX without doing any work whatsoever -- a native Flash object, as complex as you like, delivered to you piping hot in a tasty SWF shell! :)

SWX offers a huge advantage over both LoadVars and XML: simplicity. And the fact that you don't have to worry about serialization and deserialization.

In conclusion, I just want to state that SWX definitely has valid use cases: They're just not the same as those for Amfphp.

SWX, first and foremost, is built with an overriding focus on simplicity. It may be 2007 but, unfortunately, we still don't have an intuitively simple way to create data-driven apps in Flash. The closest thing we have is remoting (and I'd argue, Amfphp is the simplest one to get up and running with) but too many developers are still afraid to dive into the depths of even that. With SWX, you don't need to know anything new to get the advantages of Remoting without the extra hassle.

If you're building a mashup, or a FlashLite 2 application, take a look at SWX. If you want to have fun with Flash and create data-driven applications without the hassle of learning new APIs and downloading extra classes and all that unnecessary stuff, then SWX may be the right choice for you.

Like anything new technology, it will take a little time for it to mature. As I've mentioned in several places, it is currently not optimized in any way so this really isn't the time to be running benchmarks on it with other, mature technologies that have been around for ages.

SWX is growing and changing daily and I hope you will be part of its story. Pretty soon it will be up and running and getting up to all sorts of mischief and then we'll really start having some fun! :)

Don't forget that SWX is a tiny, new-born baby right now. It just opened its eyes to the world yesterday. Let's give it a chance instead of trying to strangle it in its cradle.

OSFlash Zeroi project makes logging in ActionScript more flexible

Ralf Bokelberg and Sönke Rohde have released Zeroi on OSFlash.

Zeroi is a logging abstraction layer that lets you use any logging system (SOS, admin tool, luminic box, ...) in your MTASC projects, without code changes in your application. Here's how it works, according to Ralf's email to the OSFlash mailing list:

Inside your app you only use trace statements. The traces are forwarded to the logging system of your choice. That's what the name Zeroi stands for: Zero Impact.

Sönke Rohde added the possibility to configure your logging system by using XML. You can filter logs on a class or package basis, e.g. suppress every log from class XY with a loglevel <= WARN

Find out more about Zeroi on OSFlash.

User Interface Design Principles for Web Applications

Three years ago, I wrote up a blog post regarding the design decisions I took when designing and developing the user interface for a Rich Internet Application for enterprise SMS messaging. At the time, I documented what I called "emerging usability design patterns." Today, I was writing the Flex Quick Start tutorial for Validators when I realized that everything I was writing there about usable validation hadn't changed since my original blog post. Reading my post again, I further realized that all of the other points were still valid and had been validated in the projects I had undertaken since the one that prompted the original post. As such, I decided to revisit the article and expand upon it.

I hope you will find it to be a useful resource.

About the project that prompted the design principles

I was hired by a company called Telrock who had a design brief for an SMS messaging Rich Internet Application (codename, Opal) which they wanted to be "Outlook for SMS". The brief stated that the application should look and behave like Outlook in every way. This was, of course, a reflection of Opal's target audience: enterprise users already familiar with using Outlook for their email.

I could understand the business need behind wanting to emulate it Outlook, but I was worried that Outlook's multi-pane interface was overly complicated for the modest requirements of SMS. Email and SMS are very different media. Emails can run into the thousands of words and contain complex attachments whereas SMS messages are limited to 160 characters.

Outlook: powerful but complicated.Outlook: powerful but complicated

We also had strict limits on screen real-estate: Opal had to be usable on 800x600 screens and scale intelligently (like a desktop application) when resized. I knew that there would be several factors that would affect the usability of the whole application and raised these with my client.

This brings me to the first principle which has both nothing to do with the design itself and yet everything to do with the process that will ultimately determine the design:

User Interface Design Principles

1. The Client Is Not The User

The client may think she knows what the user wants, but she cannot. This is because the client is not the user.

This brings me to the second principle:

2. Don't Give The Client What She Thinks The User Wants

If the client does not know what the user wants and you give her what she is asking for, you are doing her a disservice. You will ultimately be delivering an application that does not meet user's needs. Your client may initially be happy that you have given her exactly what she asked for but will she remain happy when the product is rejected by users?

I have seen too many designers and developers who are aware of these two principles but proceed to reach the wrong conclusion from it. Namely, that they know the user better. Which brings us to our next principle, which is, simply:

3. You Do Not Know What Your User Wants

You may be a user interface designer or developer with many years of experience but you do not know what users want. Which users? Those specific users who will be using the current application that you are building. Why? Because every application is unique. You may have built similar applications but, unless you have built exactly this application before, you do not know what the users of this application want.

So, who does know what your users want?

4. Only Users Know What Users Want

It's a basic concept but one that is alien to much of our industry. Only users of your application will know what works and what doesn't. It's surreal that, given this, most of us in our industry go out of our ways to delay asking them what they think of our applications. This brings me to the most imporant principle of all:

5. Test Early, Test Often, Then Test Again

Usability testing is not rocket science. In fact, it's quite a simple recipe:

Ingredients:

  1. Two rooms
  2. One or more representative users
  3. A computer running your application
  4. A usability tester
  5. A video camera (no tape)
  6. A TV screen

Take two rooms and place a computer running your application in one of them. In that room, place a representative user and a usability tester who will ask the user to perform various tasks in your application. Place a camera in the room to relay your user's actions to your design/development team who should be watching from the second room. (Ideally, having the rooms next to each other means that you don't have to run too much cable between the two but you can just as easily use wireless technologies or even broadcast the feed over the Internet to a development team across the globe.)

Leave to simmer then repeat.

Notice that you do not even need to record the test. If you do, chances are those tapes will become paperweights like most artifacts that are created during development. Remember: Agile is good.

Doing usability testing does not involve a large upfront financial investment. You can put together the above setup for around $1,000 these days. What it does involve, however, is buy-in to a User-Centered Product Development (UCPD) approach from the highest levels at both your and your client's organization.

Following a UCPD approach involves capturing measureable Usability Requirements alongside your Functional Requirements. You will have to set aside time to carry out usability testing at every iteration in your development process. You cannot do this without a budget. And you won't have a budget unless you have buy-in at the highest levels.

The above principles are perhaps the most important ones as they will determine your development process and your development process will largely decide whether your project succeeds (is accepted by your users) or fails (is rejected by your users.)

Alongside these process-related principles are design principles. These do not, in any way, replace testing. They are intended to give you a good starting point when designing your user interface, before you go to your users and say, "What do you think?"

6. Talk One Language

There should only ever be a single term or phrase used to refer to any given item in the application. An item here may refer to a concept, a business function or task or even a widget or individual interface element. You will find that the use of a metaphor for the project, as advocated by eXtreme Programming (XP), will ease this task tremendously.

7. Respect User Effort

Try to limit the user's physical toil while using the application. Repetitive Strain Injuries (RSI) are a fact of life today and we, as application designers, have to accept responsibility for the ergonomics of our applications.

8. Make difficult decisions

It is your job as the user interface designer to layer the user interface and make important decisions about its organization. Don't leave these decisions to the user just because it makes your life easier. If your application has a huge preferences section, treat this as a Design Smell and review the design to see if you have left decisions that you can make to the user.

9. Let The User Work

Users must be able to perform their most frequent, most important tasks without any resistance. For an SMS Messaging application, for example, this would include reading, replying to and forwarding messages and quickly checking the various mailboxes.

10. Prevent, Don't Scold

Whenever possible the UI should prevent the user from making a mistake instead of alerting the user to the mistake after the fact. This must be achieved without the UI getting in the way of the user.

11. Give Sufficient Feedback

The UI should give the user sufficient feedback for user actions. (This ties in nicely with Steve Krugs "Don't Make Me Think" philosophy: The user should never have to think "did that work?") Related to Don't Lose The User.

12. Show, Don't Tell

Although this may seem to contradict the Give Sufficient Feedback principle, it is actually meant to compliment it. Whenever possible, meaningful visual cues (when appropriate to the audience) should be chosen instead of lengthy textual descriptions. This can also pertain to actually teaching a user to do something in an application by showing them.

13. Don't Lose The User

The UI should protect the user's sense of spatial positioning. The user should never feel "lost" within the application.

14. Don't Sell What You Can't Deliver

Users must not be given Graphical User Interface (GUI) expectations that cannot be met (or can only be partially met) within a Web User Interface (WUI). Whenever OS or GUI expectations are set, they must be fully met. That said, the application must try and meet OS expectations as much as possible, especially for ergonomic features such as keyboard shortcuts and navigation but also for expected auxiliary helpers such as tooltips.

Don't Sell What You Can't Deliver is the main principle behind why Adobe chose to create a new component style called Halo in Flash and Flex instead of trying unsuccessfully to emulate either the Windows XP or Mac OS X look and feel.

15. Don't Keep Them Waiting

The application must perform fast enough to be considered usable within the given engineering limits for the application.

16. Innocent Until Proven Guilty

The user should be warned about a validation error on a control only if they have had a chance to interact with that control. (In other words, you should not perform validation on controls that are in their initial state and initially display a form full of validation errors.) Similarly, resetting a form should remove all validation errors.

17. Usability Approach to Accessibility

There is a trend I am noticing in our field that I find very worrisome and it concerns accessibility. Many people appear to be on a quest for the Magic Button of Accesibility (MBA). This is how an MBA works in an ideal world:

You gather usability requirements for your application for a given target audience. This target audience involves people with good eyesight, hearing, and motor control. Based on the usability requirements for this specific audience, you expand resources in designing a good user experience for this specific audience. You then spend further resources in developing your application, going back to users within this specific audience to get their feedback and to alter your design accordingly. Finally, right before you deliver your application, you press the Magic Button of Accessibility.

The Magic Button Accessibility magically makes the experience of your application as good for various other audiences. These include people who have various levels of sight, hearing, and motor control. Isn't it amazing that the MBA can transform a carefully crafted experience for a single audience into equally pleasurable experiences for many other audiences.

Unfortunately, the Magic Button of Accessibility doesn't exist because it cannot exist.

The MBA is an extreme example of the check-the-checkbox mentality to accessibility that is pravalent in our field today. I call this Checkbox Accessibility: For the most part, we do not really care what sort of experience users with accessibility requirements will have with our applications as long as we can check a checkbox on some form that says that our application is compliant with a set of rules.

If we can run our applications through a program that checks for this, all the better. After all, software is cheap compared to devoting extra time to design and develop an equally good experience for various other audiences. Checkbox Accessiblity is head-and-shoulders better than no accessibility but it does not guarantee a good experience for users with accessibility requirements.

The other approach to accessibiltiy is to see it as usability with different audiences. In other words, you cannot make your application truly accessible for users with disabilities without designing for those users. I call this the Usability Approach to Accessibility.

Having a usability approach to accessibility means that you have to gather usability requirements for disabled users just like you do for users without disabilities. You have to usability test with disabled users. And you have to realize that "disabled users" doesn't refer to a single audience but to multiple audiences, including those with accessibility requirements in sight, hearing and motor function.

Of course, just like usability with an audience of non-disabled users, usability for disabled users costs time and money and will require buy-in at the highest levels of your organization. If you are serious about accessibility, however, anything less is just not good enough.

These are general points of advice that can apply to any application. Based on these overall guidelines, the following are examples of high-level design decisions that were taken and applied in Opal. Keep in mind that Opal was developed in Flash MX but the issues are the same regardless of whether you are building an application in MTASC/SWFMill/FlashDevelop, Flash 8, Flash 9, Flex 1.5 or Flex 2. Each of those tools and technologies provides different features, components, programming models and development workflows but the end result, regardless of which technologies are used, is always evaluated by your users.

Principles applied: examples

The SMS Character Count gives users sufficient feedback and the message textbox allows users to see a whole SMS message without scrolling.

Respect User Effort: eliminating scrolling

The message preview textbox displays a full SMS message without scrolling. It meant that sacrifices had to be made with some of the other form elements on the Message Tabs. Reading an SMS message is both an important and frequently-performed task and so the other sacrifices were justified (also see Make difficult decisions.)

Give Sufficient Feedback: SMS character count

A custom SMS character count widget shows users exactly how many characters they have left before they need to send a message as two or more SMS messages. This is an especially important piece of information for users as they are charged for each SMS message sent.

Prevent Don't Scold: Form validations

All forms implement client-side validation. Submit buttons (such as "Send Message" or "Add Contact") gray out until the form passes client-side validation. This does not remove the need for server-side validation and all form submissions are validated server-side for correctness and security before being processed. Client-side validation exists solely to improve the user experience and does not provide any security whatsoever.

The Send Business Card screen doesn't let users hit the send button before they have filled in all required fields.

Let The User Work: Mailbox Tabs and Message Action Tabs

The Mailbox Tabs allow users to quickly switch mailboxes.A composite tab-based interface exposes the critical, frequent tasks to users. Mailbox Tabs give users single-click access to their mailboxes. They also expose context-sensitive message actions for each mailbox. Users can immediately see the actions that they can perform on a message in a given mailbox tab.

Implementing a context-sensitive menu that hides possible actions until it is triggered would have ranked at the opposite end of the usability spectrum and been ignored by most new users.

Show, Don't Tell: Menu Bar and Tool Bar as teaching methods for migrating Outlook users.

Menu Bar and Tool Bar allow Outlook users to migrate easily to Opal.A menu bar and tool bar remind users of the ones in Outlook without creating operating system specific expectations.

The menu and tool bars implement Show, Don't Tell.

When an Outlook user first changes to a given mailbox using the menu or tool bar, the Mailbox tab animates to the chosen mail box, thereby showing the user that they could also have clicked on the tab (although the tab control is a well-known GUI component in its own right.) The same goes for when the user selects a Message Action (eg. Reply).

Don't Lose The User and Don't Sell What You Can't Deliver: Screen-based RIAs vs. Multiple-Window-based RIAs.

Opal uses a screen-based approach instead of a full window-based one so as not to confuse users with unfulfilled operating system expectations.It is very important to note the differences between Graphical User Interfaces (as used by desktop applications such as Outlook) and Web User Interfaces (as used by Rich Internet Applications such as Opal). It is equally important to manage client's expectations as to the limitations of Web User Interfaces, even those termed "Rich" and developed using Flash.

The greatest difference between a WUI and a GUI is usually the most overlooked: WUI applications run from within a GUI application which, in turn, runs inside a window-based operating system. Past usability studies have shown that especially beginning users have problems with the concept of multiple windows, preferring usually to keep a single window up at a time. Even in multitasking operating systems like Windows XP or OS X, novice users sometimes prefer to start up a single application, shut it down and start another application and so on. The perceived complexity of the system is heightened when the user is confronted with an interface (an RIA such as Opal) within a GUI application (the web browser) that itself contains windows.

Firstly, we rob our novice user of the comforts of his single window existence. Secondly, the new windowing system works in a different way and contains its own rules and limits. It is thus important to implement a screen-based interface in RIAs so that you Don't Lose The User and Don't Sell What You Can't Deliver.

Even if an RIA developer takes pains to develop a Multi-Window Interface that mimics a certain dominant OS, the interface is still being presented to the user in the document area of a GUI application (the web browser). This is contrary to OS expectations wherein users expect not to see windows within documents. Perhaps this is one area where application browsers such as Central will have an impact on user expectations. It remains, however, that the only way a multi-window interface can provide a high-level of usability in an RIA is if the application can run in its own OS window and not as a document within a web browser and thus access the windowing abilities of whatever OS it happens to be running on. As this is currently not a possibility with Flash, we decided to go with a screen-based system in the application.

Although modal pop-ups are sparingly used due to issues of screen real-estate and Outlook migration expectations, users are visually shown that these dialog boxes are modal screens via the graying out of lower screens. Although this removes the OS expectations surrounding non-modal multiple-window interfaces, the graphic similarity of the dialog screens to windows still leads certain users in testing to attempt to move windows around.

Don't Keep Them Waiting: The name of the game is performance.

If there was one issue we kept running into during development, it was performance. Flash is not the fastest kid on the block and it is possible to run into issues when client's expectations are not managed as to the limitations of RIAs. Although RIAs can recreate a lot of the desktop application experience from within a web application, there are limits.

Flash 9 and ActionScript 3 have made great strides in performance and it is important to keep in mind that this project was being published for the Flash 6 player.

A detail from the custom Grid component.One issue, for example, was that the speed of the setSize() method on the Macromedia DRK Data Grid was resulting in unacceptable redraw times when the application was resized. This resulted in a very risky two-weeks in which I wrote a completely new Data Grid component that implemented the DRK Data Grid interface and could be plug-and-play replaced into application. The resulting Data Grid offered a 10x performance boost and brought redraw rates back within acceptable limits.

I hope that this article has challenged how you think about usability and accessibility and that you will find it to be a useful resource in designing and developing web applications. As always, I value your feedback so please feel free to leave a comment and share your thoughts.

Some notes on migrating applications from Flex 1.5 (AS2) to Flex 2 (AS3)

I'm going to use this post to document issues I've found while migrating my Flex 1.5 (ActionScript 2) applications to Flex 2 (ActionScript 3). I've decided to include the error message you will receive for a given issue as the title, along with the reason and a solution to the issue. This is not meant to be an exhaustive list and I'll keep updating it as I find time and uncover new ones.

Call to a possibly undefined method init through a reference with static type mx.containers:Form.

Reason: When using code-behind in Flex 1.5, you would override the init() event handler and listen for the "childrenCreated" event. (This was the Flex 1.5 equivalent of using the onLoad() event handler in Flash.) With Flex 2, the init() method no longer exists.

Here's an example of the old ActionScript 2/Flex 1.5 code:

[as]function init ():void
{
super.init();
addEventListener ( "childrenCreated", onLoad );
}[/as]

Solution: In Flex 2, your should override the initialize() event handler and listen for the FlexEvent.CREATION_COMPLETE event. The Flex 2 equivalent is shown below:

[as]override public function initialize():void
{
super.initialize();
addEventListener ( FlexEvent.CREATION_COMPLETE, creationCompleteHandler );
}

private function creationCompleteHandler ( event:FlexEvent ):void
{
onLoad();
}[/as]

Implicit coercion of a value with static type Object to a possibly unrelated type flash.events:Event.

Reason: You are defining an event as a simple Object instance -- eg. dispatchEvent ( { type: "orderProcessed" } );

Solution: Create an instance (or subclass) of the mx.events.Event class instead -- eg. dispatchEvent ( new Event ( "orderProcessed" ) );

Access of possibly undefined property length through a reference with static type mx.controls:List. (or ComboBox, DataGrid, etc.)

Reason: In Flex 1.5, components that took data providers would proxy data provider method calls to the data provider object. This meant that you could reference methods of a component's data provider directly through the component -- eg. myListBox.getItemAt(0);. This is no longer the case.

Solution: Reference the data provider of a component through the dataProvider property. eg. myListBox.dataProvider.getItemAt(0);

A file found in a source-path must have an externally visible definition. If a definition in the file is meant to be externally visible, please put the definition in a package.

and

Unable to locate specified base class 'org.osflash.arp.samples.pizza.flex2.view.OrderFormClass' for component class 'OrderForm'

Reason: You have not updated your ActionScript class to use the new package keyword. In ActionScript 3, you define a classes' package separately, not in the class signature.

Solution: Use the package keyword to define the package for your class -- package org.osflash.arp.samples.pizza.flex2.view { public class OrderForm { //... } }.

Attempting to initialize non-public inherited property 'ordersLb' from MXML.

Reason: You have declared components inherited from an MXML file as private properties. In order for code-behind to work in Flex 2, you have to declare components as public in your classes. This is a current limitation in the code-behind feature in Flex 2 and will hopefully be improved in future releases (I'm still holding my breath on an implementation of partial classes in a future revision of ActionScript 3.)

Solution: Declare components inherited from MXML documents as public in your classes.

Type was not found or was not a compile-time constant: Void.

Reason: In ActionScript the Void datatype has been replaced with the void datatype (lowercase "v")

Solution: Replace "Void" with "void"

A constructor can only be declared public.

Reason: In ActionScript 3, you cannot have a private constructor. This will affect you when migrating Singletons to AS3.

Solution: Make the constructor public. You can add some logic to your class to throw an error if it detects multiple intances of a Singleton class being created but, unfortunately, due to this limitation, you cannot have a true Singleton in AS3.

(Run-time error) ArgumentError: Error #1063: Argument count mismatch on org.osflash.arp.samples.pizza.flex2.view::OrderFormClass/::validateForm(). Expected 0, got 1.

Reason: Your event handler in ActionScript 2 did not take any arguments. In AS2, you could get away with creating event handlers that ignored the event object that was sent to them. You cannot do this in AS3 however, as it results in a run-time error.

Solution: Make sure your event handlers define an event parameter of type Event (or subclass of Event.)

(Warning) return value for function 'functionName' has no type declaration.

Reason: You will see this warning if you were not in the habit of explicitly declaring your public methods by using the public access modifier. In ActionScript 2, methods defaulted to being public. In ActionScript 3, they default to the new access modifier "internal".

Solution: Get into the habit of using access modifiers on all your method signatures -- eg. public function myFunction ():void {};

Resistence is futile: Assimilating _root in FAME

In my previous post on FAME, I mentioned my preference for remapping the scope of the document class to make it _root. Playing with it a little more, it became apparent that I didn't take it far enough. Merely remapping "this" to the document class' scope is not enough because we are not taking the prototype chain into consideration. Instead, what we need to do is fully assimilate _root, in true Borg-style, using a trick dating back to the days of the Rebel Alliance :)

Here's an updated example:

class Application extends MovieClip
{
	var tf:TextField;
 
	function Application ( target )
	{
		Flashout.log("Application instance. Initially: " + this);
		Flashout.log ("Assimilating " + target );
		Flashout.log ("We are FAME, you will be assimilated. Resistence is futile..."); 
 
		// Assimilate the target
		target.__proto__ = this.__proto__;
		target.__constructor__ = Application;
 
		this = target;		
 
		Flashout.log ("Assimilation complete. We are " + this );
 
		// Creates a TextField sized 100x600 at pos 100, 100
		createTextField("tf", 0, 100, 100, 800, 600);
 
		// Write out who we are
		tf.text = String ( "We are " + this );
	}
 
	// Example of a private method in the Application class
	private function onEnterFrame ()
	{
		// Move the text field around randomly
		tf._x += Math.random() < .5 ? -1:1 * Math.random();
		tf._y += Math.random() < .5 ? -1:1 * Math.random();
	}	
 
	static function main ()
	{
		// Create an Application instance and
		// have it assimilate _root.
		var test:Application = new Application( _root );
	}
}

If all goes well, you should get a textfield that randomly spasms around your screen and the following in your Flashout Logs:

Application instance. Initially: [object Object]
Assimilating _level0
We are FAME, you will be assimilated. Resistence is futile...
Assimilation complete. We are _level0

Finally, FAME!

I finally found some more time to play with FAME and got Flashout working (thanks to Alex's tip on using the -clean option to make Eclipse see the plugin on my Windows machine.) Skimming through Carlos Rovira's excellent introduction to FAME (Towards Open Source Flash Development) was very helpful but I did notice something in the test code that I would do differently.

In the article, the sample document class Test looks like this:

ActionScript:
  1. class Test {
  2.  
  3. private var scopeRef:MovieClip;
  4. function Test(scope:MovieClip) {
  5. scopeRef = scope;
  6. // --- Creates a 'tf' TextField size 100x600 at pos 100, 100
  7. scopeRef.createTextField("tf", 0, 100, 100, 800, 600);
  8. // --- Write some text into it
  9. scopeRef.tf.text = "Hello FlashWeek!!!!";
  10. }
  11. // --- Main Entry Point
  12. static function main() {
  13. var test:Test = new Test(_root);
  14. }
  15. }

The static main function (the entry point) instantiates the Test class' constructor and passes a reference to _root, which the Test instance uses when creating the text field. I would do this a little differently, like this:

ActionScript:
  1. class Test extends MovieClip
  2. {
  3. private var tf:TextField;
  4. function Test(scope:MovieClip)
  5. {
  6. // Redefine scope
  7. this = scope;
  8. // Creates a TextField sized 100x600 at pos 100, 100
  9. createTextField("tf", 0, 100, 100, 800, 600);
  10. // Write some text into it
  11. tf.text = "Hello FlashWeek!!!!";
  12. }
  13. // Main Entry Point
  14. static function main()
  15. {
  16. var test:Test = new Test(