UnFramework – or how to work without any frameworks
Those who know me or at least subscribe to my blog know that I’m a big fan of Flex/AS3 frameworks. At this year’s Adobe MAX conference I even had my own session where I covered five major DI frameworks. Usually these frameworks provide a lot of productivity features and helpers like: IoC/DI, Event/Messaging bus, implementation of some architectural or design patterns (MVC, Command…), and many others. But what happens if we can’t or don’t want to use any of these frameworks?
Well, we fall back to pure Flex and we start missing things…
This is something that happened to me very recently when I started to play with Flex Hero and I wanted to build my first Flex mobile application. As the targeted runtimes are rather constrained in processing power I knew I would have to make certain sacrifices in order to make things as light as possible.
First I started to wonder what general architectural pattern I should follow. After looking at Flex Hero and its new MobileApplication, ViewNavigator and View concepts, I knew that I was still okay with using the Presentation Model pattern.
Next I took a look at DI frameworks – well here I really didn’t find a suitable candidate. Most of these rely heavily on reflection, metadata processing, or stage events capturing for view wiring, and these unfortunately are not really very lightweight. That is why at the end of the day I made a decision not to use any of these, and instead decided to substitute some of their features with simple helpers or pure Flex functionality.
Global Event Dispatcher
The thing I missed most thing was a global dispatcher that I could use to dispatch events from my Presentation Model or any other pure AS3 classes. The approach I took was as simple as creating a global eventDispatcher property in the default package in a eventDispatcher.as file, as follows:
// eventDispatcher.as script file package { import flash.events.IEventDispatcher; public function get eventDispatcher():IEventDispatcher { return _eventDispatcher; } } import flash.events.EventDispatcher; import flash.events.IEventDispatcher; var _eventDispatcher:IEventDispatcher = new EventDispatcher();
That step gave me access to eventDispatcher object anywhere in my code:
public class MyViewPM { public function btn_clickHandler():void { eventDispatcher.dispatchEvent(new MyEvent(MyEvent.EVENT_TYPE)); } }
RemoteObject’s handling
The next thing I wanted was a clean and simple way of handling RemoteObject calls and configuration. What I really missed here was the approach from the Swiz Framework with its ServiceHelper.executeServiceCall function where you can pass an AsyncToken object returned from the RemoteObject call together with the ResultEvent and FaultEvent handlers as the other two parameters.
Another thing I really wanted was a declarative (MXML based) configuration of my RemoteObjects and to have a services registry without the use of ServiceLocator pattern. That is why the following code is a bit more complex but I think it’s still worth it and of course very light:
// remoteService.as script file package { import com.riaspace.un.IRemoteService; public function get remoteService():IRemoteService { return _remoteService; } } var _remoteService:IRemoteService = new RemoteService(); import com.riaspace.un.IRemoteService; import mx.rpc.AsyncToken; import mx.rpc.Responder; import mx.rpc.remoting.Operation; import mx.rpc.remoting.RemoteObject; internal class RemoteService implements IRemoteService { private var configObj:Object; public function set config(value:Class):void { configObj = new value(); } public function getRemoteObject(remoteObjectId:String):RemoteObject { if (configObj) return configObj[remoteObjectId]; return null; } public function callDirectly(token:AsyncToken, resultHandler:Function, faultHandler:Function):void { token.addResponder(new Responder(resultHandler, faultHandler)); } public function call(remoteObjectId:String, methodName:String, args:Array = null, resultHandler:Function = null, faultHandler:Function = null):void { var remoteObject:RemoteObject = getRemoteObject(remoteObjectId); if (!remoteObject) throw new Error(remoteObjectId + " not configured!"); var method:Operation = remoteObject[methodName]; method.arguments = args; callDirectly(method.send(), resultHandler, faultHandler); } }
As you can see you can use the above code in multiple ways. The first one requires no additional configuration and uses only remoteService.callDirectly function:
// some AS3 class ... remoteService.callDirectly(myRemoteObject.remoteMethod(param), remoteMethod_resultHandler, remoteMethod_faultHandler); ... private function remoteMethod_resultHandler(event:ResultEvent):void { // Handle remote method call result } private function remoteMethod_faultHandler(event:ResultEvent):void { // Handle remote method call fault }
The next option requires defining a config class that should extend simple Object; the best way is to do it in MXML like this:
// RemoteServiceConfig.mxml file <?xml version="1.0" encoding="utf-8"?> <fx:Object xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"> <fx:Declarations> <s:ChannelSet id="channels"> <s:AMFChannel url="http://yourhost.tld/services/amf" /> </s:ChannelSet> <s:RemoteObject id="myRemoteObject" destination="someDestination" channelSet="{channels}" /> </fx:Declarations> </fx:Object>
After you have your configuration class defined you can set it to the remoteService.config property, most probably somewhere at the very beginning of your application lifecycle:
// Main.mxml file ... protected function mobileapplication_creationCompleteHandler(event:FlexEvent):void { remoteService.config = RemoteServiceConfig; } ...
So now you are ready to call the RemoteObject methods, and you can do that like this:
// some AS3 class ... remoteService.call("myRemoteObject", "remoteMethod", [param], remoteMethod_resultHandler, remoteMethod_faultHandler); ... private function remoteMethod_resultHandler(event:ResultEvent):void { // Handle remote method call result } private function remoteMethod_faultHandler(event:ResultEvent):void { // Handle remote method call fault }
Application context
The last thing I was really missing was some type of global application context/registry where I could read or write application objects. The approach I took goes beyond a simple singleton dynamic object. It is actually a bindable (event dispatching) singleton dynamic object
You can see it’s implementation below:
// applicationContext.as file package { public function get applicationContext():ApplicationContext { return _applicationContext; } } var _applicationContext:ApplicationContext = new ApplicationContext(); import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; import flash.utils.Proxy; import flash.utils.flash_proxy; import mx.events.PropertyChangeEvent; import mx.events.PropertyChangeEventKind; use namespace flash_proxy; internal dynamic class ApplicationContext extends Proxy implements IEventDispatcher { private var values:Object; private var contextEventHandler:IEventDispatcher; public function ApplicationContext() { contextEventHandler = new EventDispatcher(this); values = new Object(); } flash_proxy override function getProperty(name:*):* { return values[name]; } flash_proxy override function setProperty(name:*, value:*):void { var oldValue:* = values[name]; values[name] = value; var kind:String = PropertyChangeEventKind.UPDATE; dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, kind, name, oldValue, value, this)); } public function hasEventListener(type:String):Boolean { return contextEventHandler.hasEventListener(type); } public function willTrigger(type:String):Boolean { return contextEventHandler.willTrigger(type); } public function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0.0, useWeakReference:Boolean=false):void { contextEventHandler.addEventListener(type, listener, useCapture, priority, useWeakReference); } public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void { contextEventHandler.removeEventListener(type, listener, useCapture); } public function dispatchEvent(event:Event):Boolean { return contextEventHandler.dispatchEvent(event); } }
The way to use this is, of course, very simple:
// some AS3 class ... applicationContext.myObject = new MyObject(); ... // another AS3 class ... var myObject:MyObject = applicationContext.myObject; ...
The cool thing about this approach is that you can actually bind to your applicationContext.myObject without getting this nasty warning: unable to bind to property 'foo' on class 'Object' (class is not an IEventDispatcher).
Also if you would like to listen for changes done to applicationContext properties you can do it like this (in order to make code completion work you need to cast applicationContext to IEventDispatcher):
// some AS3 class ... IEventDispatcher(applicationContext).addEventListener( PropertyChangeEvent.PROPERTY_CHANGE, applicationContext_changeHandler); ...
My UnFramework approach summary
So in the end you can see there is actually life
without frameworks, especially when you are building not very complex applications that don’t require module support (in that case the singleton approach used here would fail).
Now please don’t accuse me of building yet another framework (we already have plenty of really great ones available) but I have packaged all these helper functions into a Flex Library project and pushed it into a GitHub repository. As I said this is not a framework so its called un-framework and it is available for download from here and as a swc from here.
Stay tuned for my upcoming posts where you will see these functions in action on some of my Flex Mobile apps.


Very good post,
julien
16 Nov 10 at 7:03 pm
Great tutorial on creating our own “not” framework, thanks a lot.
How about the performance impact? Is global event handler, remote service, and app contect has performance impact???
HERLoct_HENT
16 Nov 10 at 7:35 pm
Hi,
for your global event dispatcher, i believe you should only use the EventController Library (not a framework). It’s light and does the job well:
http://fla.as/ec/
Fabien
Adobe Flex Tutorial
16 Nov 10 at 8:21 pm
[...] video recording with an un-framework overview. This simple library has evolved a little bit from my previous post but I expect it will stay in this form for good I don’t think it can evolve to anything more [...]
Video with an un-framework overview at Space of Flex/AIR technologies
19 Nov 10 at 4:36 pm
In reading your post I had to pause at eventDispatcher.as and go do some googling. I did not know you could create a package-level variable that could be accessed globally like that. I was not able to find any documentation on package-level variables, although I found a section on package-level functions in Moock’s “Essential ActionScript 3.0″ page 88. Interesting.
Jamie McDaniel
30 Nov 10 at 5:41 pm
Great site keep going good work.
Raja
18 Jan 11 at 2:59 pm
This blogpost is fantastic.
Revan
29 Jan 11 at 11:10 pm
Great Tutorial…I really like RemoteObject’s handling section.
Thanks
Raja
23 Feb 11 at 9:45 am