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.