" /> Roger Gonzalez: June 2006 Archives

Main | August 2006 »

June 26, 2006

Motorcycle Safety Foundation

As some people know, I have a weekend gig working as an instructor for the MSF Beginner RiderCourse in Alameda, CA. Its a lot of fun, and if you have any interest, I encourage you to give it a try. If you do sign up for the course, tell Angela that I sent you!

June 17, 2006

Modular Applications (part 2)

So, back to where we were going before the digression on ApplicationDomain. One effective way of partitioning an application is to create an application shell that dynamically loads modules.

What exactly should a module look like?

There are a couple choices here. One possibility would be to just build a SWC, and extract out the SWF, and use it as a "bag of classes" via getDefinition. Not particularly elegant.

Another possibility would be to build the module as an application. This is probably somewhat wasteful, because most applications carry some runtime infrastructure with them.

Or, perhaps just build something extending a Flash class like Sprite or MovieClip. Not a bad possibility, but you'll probably need to just use it as a bag of classes again, unless you intend to use your modules as pure visual elements.

My preference is to build a new base class (lets call it "ModuleBase"!) that takes advantage of the semi-secret and bizarre [Frame] metadata that the Flex compiler uses to build multiframe Flash movies.

What? You've never heard of [Frame]? Take a peek in mx.core.Application's source, and you'll see:

[Frame(factoryClass="mx.managers.SystemManager")]

or take a look in mx.core.SimpleApplication, and you'll see:

[Frame(factoryClass="mx.core.FlexApplicationBootstrap")]

This metadata is a hint to the compiler that the class containing the metadata would like to be bootstrapped by the cited factory.

In other words, when you build an application based on mx.core.Application, that isn't actually the "root" class of the SWF. The root class is actually a compiler-generated subclass of mx.managers.SystemManager that overrides the info() method. Turn on "keep-generated-actionscript" during your compile, and you can see what the compiler generates.

The rules are a bit weird, but basically: if the [Frame] metadata exists on the base class of your application, a subclass of the factory will be generated. If the metadata is directly on your application class, it will be honored, but no subclass will be generated; its assumed that you've already written the appropriate factory.

When a frame factory class has been specified, the compiler will basically create a multi-frame movie, where the factory class is on the previous frame. It can arbitrarily daisy-chain these frames; you could (although why?) build a 10-frame bootstrapped movie this way. Note that the metadata is actually just an inline alias for the "frames" compiler configuration option, which lets you explicitly specify the frame classes.

I personally like the notion of module SWFs being multiframe, because (a) it allows the module to use RSLs (which must be loaded before the main class), (b) it allows some interaction with the loaded content as soon as the INIT event fires, and (c) the generated factory subclass is how the compiler generates some information like the list of embedded fonts.

Its really just personal preference. The one thing I do believe is useful, though, is to have the root class of the SWF be a factory class. So, if you do extend Sprite or MovieClip, consider implementing some sort of interface that can be used to create the classes within your module.

To explore this concept, I've written the beginnings of a module system, with a demo that exercises it.

Here is a ZIP file containing the demo.

The demo uses a small utility library built around a ModuleManager singleton that handles the complexities of loading modules. Any given module URL is either in an unloaded or loaded state. After requesting that a module be loaded, an IModuleInfo interface is available. Once the module is loaded, a factory can be obtained that can be used to create an instance of whatever the module implements. The modules rely on a factory class to issue a "ready" event when it is safe to invoke the create() function.

The demo exploits this system by having a shell application that loads an XML file containing elements that correspond to SWF file names; for example, if a "square" element is encountered, it tries to find "square.swf", load it as a module, and then invoke the IRenderer interface on the module. Each module is simply expected to implement this small interface to draw itself.

The code for this demo is pretty simple, and will evolve over time, hopefully into an actual supported library. For now, its just a small skunkworks project, so enjoy your advanced peek!

ApplicationDomain

ApplicationDomains are pretty much a neverending source of confusion and suffering, but they provide an interesting palette of class definition partitioning.

Anyone building an application that dynamically loads SWF files needs to learn and love the AppDom rules...

The Rules

AppDoms are containers for AS3 definitions

Generally classes, but also functions and namespaces. You will use the "getDefinition" call to get a reference to one of these definitions, which you might then cast to a Class or a Function.

AppDoms are hooked together into a tree, linked by "parentDomain" pointers.

The topmost AppDom is the system domain, and it contains the built-in Flash types like Sprite, TextField, etc.


If a definition already exists in a parent AppDom, the definition in the child is ignored.

This always surprises people. As developers, we're used to thinking of definitions as following the most local scope. Some reasons why we didn't do it that way include:


  • The app doing the loading should be the master of the things it loads

  • Flex applications loading Flex applications would would double the memory use if the child used its own class definitions.

  • It reduces some security worries about classes being replaced.

  • It simplifies the implementation of manager singletons (the static parent version is used by the children)

  • Its closer to the old AS2 behavior, where classes were defined via some code that looked something like "if (!_global.Classname) {_global.Classname = ...}", which is a model that the Flex frameworks expects.

  • You can mimic the benefits of the "child wins" behavior by simply rooting a new AppDom on the System domain.

You may or may not find the above arguments compelling. Its still a source of controversy, even internally.

AppDoms live within a single SecurityDomain

Crossing a security boundary isn't allowed.without explicit trust.

Usage

Ok, good. So there's the rules. How do you use them? Lets say that you're dynamically loading a SWF:

var myLoader:Loader = new Loader();

You have some options. Perhaps..

myLoader.applicationDomain = new ApplicationDomain()

This creates a new domain, rooted on the System domain. What this means is that the classes in this domain are guaranteed to not collide It also means that you can't talk to them in a strongly typed manner, all you can do is use "getDefinition", and talk to them as Object (or other base Flash types).

myLoader.applicationDomain 
         = new ApplicationDomain(ApplicationDomain.currentDomain)

This creates an ApplicationDomain as a child of the current application. This is the default for the Flex framework, as it allows strongly typed references to the child classes. For example, a dynamically loaded Flex application will be of type IFlexDisplayObject.

myLoader.applicationDomain = ApplicationDomain.currentDomain

This means that new classes will actually be added to the current application context. This is normally used for Runtime Shared Libraries (RSLs), and isn't especially useful otherwise. The basic issue is that dangling ("externs") references to classes must be fulfilled before the Actionscript Bytecode (ABC) block containing the references is ever initialized. This is usually carefully choreographed by ensuring that RSLs are dynamically loaded on the first frame of the application, before any of the classes that depend on the RSL are ever seen. Its hard to imagine any non-RSL case where adding classes to the current AppDom would be better than loading into a child AppDom.

Here's where stuff gets weird...

ApplicationDomain.currentDomain is nutty. It isn't what you think it should be. Heck, it isn't what I thought it would be, and I helped design ApplicationDomain!

The definition of ApplicationDomain.currentDomain is the ApplicationDomain that contains the code that is calling ApplicationDomain.currentDomain.

This is all well and good, until you make a utility function to do something like:


function create(className:String):Object
{
var clazz:Class
= Class(ApplicationDomain.currentDomain.getDefinition(className);

return new clazz();
}

and then you use that utility function both in a parent application and in a dynamically loaded child application. The child's version is ignored (since its in the parent), and the meaning of "current" shifts to mean the parent! So, its basically impossible for the child to call a shared utility function to get a definition from its own domain unless you pass a handle to currentDomain in, which is often rather inconvenient.

This weirdness has never failed to surprise us. In fact, we're shipping with a deferred bug in the FlexModuleLoader class (used bySimpleApplication) that exhibits exactly this problem - it tries to find the application class, but fails if both the parent and child are derived from SimpleApplication. Oops. We'll send the fix for this out in the first updater.

The solution to this nightmare is to ensure that the code calling ApplicationDomain.currentDomain is unique to that particular SWF. The only class that you can generally assume to be unique is the root class of the SWF (for MXML-based Applications, its a compiler-generated subclass of SystemManager. For Actionscript-based code extending SimpleApplication, its a compiler-generated subclass of FlexApplicationBootstrap.) If you extend Sprite or MovieClip, its up to you, as the compiler doesn't generate a unique subclass, you're just getting a one-frame movie based on your class.

In my next post, I'll get back to discussing modular applications that take advantage of ApplicationDomain to partition classes cleanly for dynamic loading.

Modular Applications (part 1)

There are lots of crazy ways that one can imagine partitioning an application into multiple independently downloadable chunks. At one end of the spectrum, perhaps every single class is in a separate file, downloaded on demand by a classloader. This would be pretty inefficient, obviously - class references have significant "locality of reference"; if you need one class, odds are pretty good that there are a bunch of other classes that you will also need immediately, and it would be much more efficient to package them all together.

Determining a good packaging scheme is a pretty hard decision for the compiler to make automatically. Perhaps you would run some sort of profiler on your application during development, and monitor the class references over time. By seeing when things are referenced, in what order, and more interestingly seeing when things aren't referenced, you could build up statistics to use for computing the optimal partitioning scheme for how many SWFs your application should be built from, and what classes should be in which. I don't know about you, but while that sounds like a fun research problem, it doesn't seem like its very practical, and I'd hate to have to tell my deadline-obsessed boss how long it would take to "get it working". (Not to mention the fact that the Flash AVM+ gets really grouchy if it touches an Actionscript Bytecode (ABC) block that contains unknown type references.)

Lets look at a much more practical way of partitioning things.

Many applications can be factored as containing two categories of functionality: "stuff needed immediately at startup", and "stuff needed later".

There are lots and lots of applications that fit this model. Games, for example; you have the core game engine, and a bunch of individual levels. Or Portals and Portlets; some basic shared functionality, and a data-driven set of little mini-apps that follow a common API. Or maybe some giant insurance application with 1500 pages of data entry forms, of which a particular run will only touch a few of them. Or maybe a content-heavy application where it is desireable to be able to independently update parts of the content without having to force users to re-download everything on every visit.

I call these independent pieces of late-loaded functionality "modules", and I call the application that loads these modules the "shell".

Ignoring the "how" for now, lets look at some general issues here.

The thing is, the shell needs to be able to talk to the modules, and the modules need to be able to talk to the shell. If the shell has a hard type reference to a module class, then it will link it in. Similarly, if the module class has a hard type reference to a shell class, it will link it in. And the way that ApplicationDomains work (I'll get to this in a subsequent post), there are only two options here: either a class reference is "the same", and shared (and thus was inefficient to download twice) or else it is different (and despite the classes having the same name, they're treated as unrelated, and can't communicate with each other).

The best way to handle this is simply to make the shell and modules communicate through interfaces. This way, the shell doesn't have a hard type reference to the module, just to some common interface that the module will implement. Similarly, the module won't bake in the implementation of the shell class(es), just an interface defining the allowed API that modules are allowed to call.

This also reduces the need to recompile modules when the shell changes (or vice versa). Implementation changes are generally more common than interface changes, so as long as the interface is stable, you don't need to constantly rebuild everything.

Sidebar: yes, you could also use "externs" (or "external-library-path") to build modules that automatically exclude the shell classes - since the module is loaded into a child ApplicationDomain of the shell, it should be safe to extern the shell classes, and thus the module could actually refer directly to implementation classes in the shell code. However, since the opposite doesn't make sense (the shell can't extern module classes) I think its more symmetric (and aesthetically pleasing) to just use interfaces in both cases.

At this point, we need to digress, and get in-depth with ApplicationDomain for a bit. We'll get back to Shell/Module applications afterwards.

Multi-SWF Applications

In most cases, the Flex compiler constructs applications by building a two-frame Flash movie, where the first frame contains a preloader (with download progress bar graphic) and the second frame contains the bulk of the application. This allows the application to start up fairly quickly so that the user isn't staring at a dead window during SWF download.

However, the application is still fundamentally a single monolithic SWF file. This has a few benefits, but several down sides.

The main benefits are simplicity of deployment (one file) and more reliable downloading (single HTTP transaction).

Some disadvantages include the need to wait for entire download before starting, the fact that any trivial change will require the entire application be recompiled, inefficiencies due to the fact that not necessarily all the data downloaded was really required to support a given run of the application, and that for advanced users, it becomes difficult to create certain desireable ApplicationDomain configurations.

I believe that in the future, most Flex applications will be built in a manner where functionality is split into multiple SWF files, loaded on-demand or incrementally. This will inevitably result in added complexity (partitioning decisions, multi-file deployment) and more failure modes (load errors) that increases with the number of SWF files, but I think it will be possible to use techniques to help make the advantages greatly outweigh the disadvantages.

We're not there yet. The Flex frameworks is by design a fairly monolithic blob of code. Once you touch mx.core.Application, you're already going to pull in much of the functionality. This is why typical MXML applications start off with a fairly high initial download size, but don't greatly increase. You're payng a one-time cost for the framework code.

Also, the compiler gives you absolutely no help. The dependency tree from a given class will be relentlessly followed and linked in. You can play some games by building Runtime Shared Libraries (RSLs) that will help with code sharing between applications, but fundamentally, you're still needing to download all those classes (and assets) in the dependency tree of your application.

So, what to do? Well, we can start experimenting with alternate architectures for applications. The good news is that the Flex compiler does in fact provide a bunch of kind of weird low-level features that can let you build some very different types of applications.

In my next post, I'll talk about one particular type of application architecture, built from a "shell" and a set of "modules".

June 16, 2006

Howdy

As I watch Flex roll through the GMC builds, heading inexorably towards release, I realize that there's a lot of insider knowledge that might be of interest to hardcore Flex/Flash folks - undocumented APIs, clarifications of why we made certain design decisions, details on subtle bugs that we deferred fixing and why they're hard or risky, insight on weird player behavior, and so forth. A bunch of this knowledge only exists in my head, and since I risk lanesplitting a motorcycle across the Bay Bridge twice a day, it would probably be a good idea for me to share some of this information with the community ASAP, just in case!

A little about me, so that you can decide whether you want to read this blog. I work on the Flex compiler team. Everybody on my team tends to touch on code all over the product, but my main area of expertise is the low level construction of SWF files; how bytecode blocks are linked together with assets and put together to form something that the Flash player can consume. As such, a lot of the code that I provide here will be low-level Actionscript, without fancy MXML effects or deep use of the Flex Frameworks components. Before Macromedia (Adobe), I was doing a lot of network software development for the web, but my background is really rooted in game development, writing AI software for distributed defense simulators, and robotics. The applications I write don't look like traditional Flex applications. You might have seen one of them (a fishtank running the Boids algorithm) used as a benchmark for the Flash player, up on the big screens at the conferences to demonstrate how fast the new VM is. In short, if you're looking for how to write sophisticated and pretty business applications, this isn't for you. If you want to learn how to exploit crazy un- and semi-documented tricks in Flash and Flex, keep reading.

Next up, I'll share some of my thoughts on how Flex applications will be built in the future.