Charles Proxy and Cairngorm Tweaks FTW!

Application initialization seems to be an all or nothing activity these days; I haven't seen a project for some time now that loads only what it needs when it needs it. typically network and machine speeds are zippy enough that you don't have to worry too much about this kind of thing... that is until...

...a very important user is in-the-fray trying to use your app with a deluxe-ly slow wifi connection, tethered to a cellphone, or (shudders) dial-up. The response time of Flex/AIR apps that sit on top of large scale web service implementations can be significantly affected by connection speed. Here are some quick tips including a Cairngorm 'tweak' that can help smooth out bumps in the performance road.

Include Throttling in Performance Metrics
Before we try to speed things up... we first need to slow them down a bit; performance results should always be captured in nominal and pitiful conditions. To do this... you can use Charles Proxy with Throttling (sounds like a sports drink). It's a great way to get a feel for what users on the slow end of the stick are experiencing.

Any misbehaving code will be much easier to detect at slower speeds.

Use Deferred Instantiation
A complex UI (read: loading a lot of stuff) usually translates to longer initialization cycles. To get around this... Flash Player uses 'Deferred Instantiation' which boils down to creating UI elements incrementally or as the user navigates; not all at once.

You've probably run into it with the ViewStack - getting null reference errors when trying to touch a component in a view/state that hasn't been 'shown' yet? This usually leads to the discovery of the creationPolicy property... and forcing the creation of objects that the user may never touch and / or have permissions to see. Leave that property alone and use binding when compositing or creating 'from-scratch' components... you'll get more bang for your performance buck.

Load Late / Release Early
It's time for a Cairngorm mini-tweak. I'll be using WebServices.as in the com.adobe.cairngorm.business namespace (2.2.1 release). Notice what's happening in the register function... WSDLs are being loading en-masse?

      /**
       * Register the services.
       * @param serviceLocator the IServiceLocator instance.
       */
      public override function register( serviceLocator : IServiceLocator ) : void
      {
         var accessors : XMLList = getAccessors( serviceLocator );
         
         for ( var i : uint = 0; i < accessors.length(); i++ )
         {
            var name : String = accessors[ i ];
            var obj : Object = serviceLocator[ name ];
            
            if ( obj is WebService )
            {
               var webService : WebService = WebService( obj );
               webService.loadWSDL();
               
               services[ name ] = obj;
            }
         }
      }

Let's rethink this a little and load a WSDL only when it's needed. We'll probably need something to keep track if a WSDL is loaded or not. There are a lot of ways to do this - be as creative as you like.

   internal class WebServices extends AbstractServices
   {
      private var services : Dictionary = new Dictionary();
      
      // Used to keep track of WSDL load state
      private var serviceLoaded : Object = new Object(); 
      ...

...remove the en-masse load.

      /**
       * Register the services.
       * @param serviceLocator the IServiceLocator instance.
       */
      public override function register( serviceLocator : IServiceLocator ) : void
      {
         var accessors : XMLList = getAccessors( serviceLocator );
         
         for ( var i : uint = 0; i < accessors.length(); i++ )
         {
            var name : String = accessors[ i ];
            var obj : Object = serviceLocator[ name ];
            
            if ( obj is WebService )
               services[ name ] = obj;
         }
      }

Then... load the WSDL when the service is first touched.

      /**
       * Return the service with the given name.
       * @param name the name of the service.
       * @return the service.
       */
      public override function getService( name : String ) : Object
      {
         var service : WebService = services[ name ];
         
         if ( service == null )
         {
            throw new CairngormError(
               CairngormMessageCodes.WEB_SERVICE_NOT_FOUND, name );
         }

	 // load WSDL on first touch
         if ( serviceLoaded[ name ] == null )
         {
	     service.loadWSDL();         	
             serviceLoaded[ name ] = true;
         }
         
         return service;
      }

I know it doesn't seem like much... but the initialization time of a Flex app that touches an API with 30 WSDLs each having 10 - 15 methods takes about a minute and a half to load at 256kps. With these simple changes... that figure drops to < 15 seconds. If you can, spreading out initialization overhead can greatly improve actual and perceived performance.