Asynchronous Processes and RobotLegs

Asynchronous processes are a common feature of ActionScript applications: we often need to initiate some asynchronous process, wait for a response and handle it. We have good language tools and design patterns for solving these sorts issues.

RobotLegs is an MVCS framework that aims to decrease inter-dependency between different parts of code, so that code is more robust, and more reusable. It does this through a combination of dependency injection and the model-view-controller (+services) design pattern. The ‘controller’ portion of RobotLegs’ MVCS implementation is achieved by offering coders a simple way of implementing the Command pattern and binding commands to events that can be called from other areas of the code.

Problematically, commands are stateless and synchronous. They are not wired up to handle asynchronicity under-the-hood. “Async Commands” amend the Command structure to attempt to solve this problem, but they still contain architectural limitations that force us to restrict the way we code to the potential of the framework. Using Commands for asynchronous processes often require us to ‘double wire’ between different application elements to solve the problem of passing data between classes.

What I am calling Processes are a redesign of the Async Command concept that seek to resolve these issues. They can be used in parallel with Commands to elegantly handle the problems of asynchronous code in RobotLegs.

The Async Pattern

The event model exists explicitly because we often need to wire up code to be triggered at an indeterminate future event. Fundamentally, client-side programming is about state and asynchronicity: events handle the asynchronicity. We handle them with this sort of pattern:

public function init():void
{
	var process:AsyncProcess = new MyAsyncProcess();
	process.addEventListener(AsyncProcessEvent.COMPLETE, onProcessComplete);
	process.init();
}

private function onProcessComplete(event:AsyncProcessEvent):void
{
	var processs:AsyncProcess = event.process;
	process.removeEventListener(AsyncProcessEvent.COMPLETE, onProcessComplete);
	
	parse(process.data);
}

Signals improves upon this structure by removing the necessity of event classes and offers some added features like automatically handling the removal of listener functions:

public function init():void
{
	var process:AsyncProcess = new MyAsyncProcess();
	process.completed.addOnce(onProcessComplete);
	process.init();
}

private function onProcessComplete(process:AsyncProcess):void
{
	parse(process.data);
}

This pattern is simple but powerful – create an object to tokenise or act-as-delegate-to the process, bind to some generic event/signal defined on the token, then initialise the process. I take the signal implementation to be a substantial improvement to the original.

The Async Pattern across different objects

A more complex case emerges if one class wants to launch a process in another class and retrieve data from its result. Ideally we want to keep the same three-step process.

class Model
{
	public var service:Service;

	public function init():void
	{
		service.completed.addOnce(onServiceComplete);
		service.init();
	}
	
	private function onServiceComplete(process:AsyncProcess):void
	{
		parse(process.data);
	}
}

interface Service
{
	function get completed:Signal;
	
	function init():void;
}

Unfortunately, this pattern is now insufficient, because it is possible for two different objects to trigger an asynchronous process from the same service at overlapping times (such that the second one is triggered before the first response).

class InitModelsCommand
{
	public var a:Model;
	public var b:Model;

	public function execute():void
	{
		a.init();
		b.init();
	}
}

In this scenario, if modelA and modelB both call init() in turn, then modelB will receive the data for modelA, then remove its listener before its own data is retrieved (assuming that modelA’s data is returned first, otherwise vice-versa).

This problem comes about because the service exposes a single Signal for multiple requests. There are two options to remedy this limitation:

// option A - the calling service tells the response where to go
interface Service
{
	function init(signal:Signal):void;
}

// option B - the service generates a response signal on a per-call basis
interface Service
{
	function init():Signal;
}

There’s not a lot between the two solutions, but I prefer Option B because it keeps together the repsonsibilities for creating and managing delegates to the asynchronous process in the same place as the process itself.

The pattern morphs to this:

class Model
{
	public var service:Service;

	public function init():void
	{
		service.init().addOnce(onServiceComplete);
	}
	
	private function onServiceComplete(process:AsyncProcess):void
	{
		parse(process.data);
	}
}

interface Service
{
	function init():Signal;
}

Here, be aware that if the signal responds within the init() method then it will not be routed to onServiceComplete. This can be handled by defining a signal that once dispatched, will dispatch immediately to any methods that are then added.

Asynchronous Processes in RobotLegs

The point of RobotLegs is to keep as few dependencies between different parts of code as possible. Ideally a model and a service shouldn’t reference each other, so RobotLegs best-practises would suggest you separate their interaction into a Command:

class InitModelCommand
{
	[Inject]
	public var model:Model;
	
	[Inject]
	public var service:Service;

	public function execute():void
	{
		service.completed.addOnce(onResponse);
		service.init();
		
		commandMap.detain(this) // if we don't do this for an async command everything could explode
	}
	
	private function onResponse(process:AsyncProcess):void
	{
		commandMap.release(this) // if we don't do this for an async command commands stay in memory
	
		model.parse(process.data);
	}
}

There several problems with this implementation. Imagine that this command is called as part of an initialisation routine, and once complete, another command should be called:

class Context
{
	public function onStartup():void
	{
		signalCommandMap.mapCommand(InitModel, InitModelCommand);
		signalCommandMap.mapCommand(InitView, InitViewCommand);
	}
}

How should InitViewCommand be called? The only place where the InitModelCommand is known to be complete is in its own onResponse command:

class InitModelCommand
{
	[Inject]
	public var initView:InitView;
	
	...
	
	private function onResponse(process:AsyncProcess):void
	{
		model.parse(process.data);
		initView.dispatch();
	}
}

This is unsatisfactory. Without this, the command is neatly encapsulated and simple to describe and understand. Once this code is added, the command takes on two responsibilities: firstly to initialise the model, and secondarily to kick-off the InitViewCommand.

The stateless command design pattern is ill-suited for asynchronous processes, and the attempt to use them leads to poor code design.

An asynchronous process for RobotLegs

The simple cases at the start of this article are instructive if we try to design a preferred architecture from the ground up. While retaining the power of RobotLegs to remove class dependencies, we want to find a way to use the simple asynchronous process pattern to wire up processes.

These design considerations have led me to what I’ve tentatively called the robotlegs-async-process-extension. It’s very early stages, and as usual I’m sharing the code more to get feedback than as a polished piece of work, but it functions to provide what I think is a superior alternative to Async Commands.

The structure is roughly like this:

class Context
{
	public function onStartup():void
	{
		// a delegate is a new concept...
		processMap.map(InitModelDelegate, InitModelProcess);
		processMap.map(InitViewDelegate, InitViewProcess);
	}
}

Class InitModelDelegate extends ProcessDelegate {}

Class InitViewDelegate extends ProcessDelegate {}

class InitProcess extends Process
{
	[Inject]
	public var initModel:InitModelDelegate;
	
	[Inject]
	public var initView:InitViewDelegate;

	public function execute():void
	{
		initModel.execute().addOnce(onModelInited);
	}
	
	private function onModelInited():void
	{
		initView.execute().addOnce(onViewInited);
	}
	
	private function onViewInited():void
	{
		complete();
	}
}

Note the features here:

  • Like the SignalCommandMap extension, a different core structure, the ProcessMap is defined that allows Processes to be defined in a way similar to Commands;
  • Rather than binding an event or signal to a Process, we bind a ProcessDelegate. We need a little bit of extra functionality in the ProcessDelegate for the structure to work satisfactorily, but this is not functionally different from the SignalCommandMap extension;
  • When a delegate is executed, it passes back a signal that the calling object binds to in order to know when the process completes (it may also send back data through this callback);
  • Processes can’t be duck-typed, because they also need to inherit the functionality from their base class Process. Process exposes a complete() method that is called when the Process completes. If complete() is called inside execute(), then the Process becomes functionally equivalent to a Command.

In fact, this is not quite the library as developed, because I have started using Notices rather than Signals, so I have ported this across to Signals since it has a much broader adoption. Notices are pared down, simple implementations of Signals that allow you to expose very simple interfaces like the SingularNotice interface. It’s a preference thing; if anyone would like the original implementation with Notices, I’m happy to publish it.

I hope that this gives you some food for thought with respect to asynchronous processes. I’d love to know what you think about the idea, the implementation, the implied critique of RobotLegs. Let me know!

15 thoughts on “Asynchronous Processes and RobotLegs

  1. TBH, It does seem a convoluted/non-transparant way to do something that can be quite easily achieved with state machines and async commands, but I must confess I didn’t have the time to look into it really thoroughly so it could be I’m probably (read: almost definitely) missing the point. One thing though, one of the advantages of option A (the caller passes the responding signal to the service) is that the caller doesn’t have to be aware of the nature of the service’s process. Whether it’s async or sync doesn’t matter, which is what I prefer.
    On the whole it seems to me this can get complicated quite fast. Process chaining using handlers tends to get messy very quickly. Not when you’re building your application, but later on when things need to change. 

    1. Thanks for the thoughts. This process was actually developed as a means to remove complexity from a system.  While I can agree that perhaps the explanation is convoluted, what in particular is convoluted about the implementation? What is significantly more complicated than working with (synchronous) commands or a Loader object (or better a URLLoader object, since the LoaderInfo madness makes Loader significantly more complicated!)?

      Perhaps the InitProcess looks too complicated? I actually wrote it out like that in order to expose the structure of things, but I would actually exploit a utility class for sequencing and write the class more like this: http://bit.ly/nWyRji.

      I agree that things can become complicated fast, which is precisely why I don’t like daisy-chaining commands, which is currently what 99% of people faced with this sort of problem do. Perhaps a more concrete example might help?

      Lastly, either option A or option B require that you conform to the Service interface, so either way you must know the same minimal information about the Service, so I’m unclear what your preference for injecting a response object is over having a returned object?

      1. Maybe I just need to see a full example to get an idea of how you’d use it concretely. Also, I’m not used thinking in a model > service flow, which fuddles my comprehension of the above post. ( I’m a command > service, command > model guy) 
        You can find an example of how I solve bootstrapping with async and sync processes here:https://github.com/creynders/robotlegs-demo-bootstrap
        (There’s definitely a ton to be improved, I’m working on a new version)

        It uses the macrobot utility, but might as well use a statemachine.
        One of the big advantages is that the commands themselves are unaware of whether the real, actual process is async or not, they (the commands) are defined as async anyway, which gives far greater implementation flexibility.
        And that’s what I meant with preferring to inject a response object over a returned one. In the latter case if the service actually covers a synchronized process instead of an async one, the process will be over before the response object is returned and therefore the caller won’t be able to react to it either. 
        For testing purposes (and to proxy remote services that have not yet been implemented) I create mock services that may or may not return their data asynchronously. Keeping my commands unaware of the process nature, means I don’t have to refactor anything, I just swap the mock service for the real one when it’s ready and everything still works as before.

        Also, the InitProcess actually still daisy chains, it’s just all contained in one class and though granted it’ll be easier to maintain than daisy chaining commands, it still has the same weaknesses and flaws.

        1. Thanks for your further thoughts! I really appreciate it, it’s great to be challenged, I really hope I’ve not wasted my time, but if I have, I’d rather realize it sooner than later :)

          To that end, I’ve created a very simple demo, http://bit.ly/qWN2bH. I tried to come up with something that reflected the way I explained the concept above, though you can see it’s very artificial. Still, it builds and does what it says on the tin!

          I’m changeable about the ‘option A and option B’ question. In fact, as I was coding I caught myself using both ways in different contexts. At least in this, I’m willing to concede that you’re probably right.

          1. Ah yes the example’s a lot clearer. Looks very promising, but I will need to use it in a “real” situation to truly get the flexibility and limitations. One last question, how would you handle service failure?

          2. That’s a very good question. Thanks again, Camille. The caveats in the original article make it clear that this is by no means a complete piece of work. I will think about it and get back to you!

    1. Hi Shaun. I believe I have, and didn’t feel like it met at least one criterion that I had for what I wanted… but I may be wrong. Frustratingly, the link you’ve just given me has gone down at the moment, so I’ll have a look later and get back to you.

      Cheers,
      Alec

    2. Heh, it’s funny, I’ve had my own library that is very similar – but is not open-source – for a while. It’s interesting to see how closely my work and theirs has converged. Not sure I like the ITask stuff though. Once you’re defining an if_ function because the language’s own if function doesn’t do it for you, you’ve lost perspective I think. Still, very interesting stuff.

      This tension between ‘option A and option B’ is a tricky one, they go down on the side of doSomething():Token rather than doSomething(token), though I’m not at all convinced that’s right (I thought I was, but I’m not).

      1. Personally I really don’t like the doSomething(token):void approach for services (application facing APIs). I prefer doSomething(…args):Token. My token is usually a Promise, which, as with your ProcessToken, supports “late” handlers.

        In direct contrast to this, the low-level internals of some of my libraries follow the Node.js style callback idiom:

        asyncMethod(arg, callback);  // async function signature
        callback(error, result); // callback signature

        But I only use that approach for internal processes that need to be really lightweight and fast.

  2. I really like your thought process here. I too have gotten frustrated by Async commands, and I think you nailed it with the fact that commands really are stateless. How ever I’m not sure I can offer much advice on your suggested implementation though, simply because it’s been a quite while since I argued with the problem…would like to investigate this further next time I have a proper RL project under my fingers.

  3. I think a lot of people are heading towards a common approach for handling async code in AS3. It’s becoming an even hotter topic as node.js becomes more popular.

    An interesting article was written from the point of view of Scala:

    http://lamp.epfl.ch/~imaier/pub/DeprecatingObserversTR2010.pdf

    Where Odersky and Co. pointed out that 1/3 of the code in a typical AS3 application is async in nature, and that 1/2 of the bugs reported during a project exist in this code.

    I’m working on a general pattern for handling async code in AS3 at the moment myself:
    https://github.com/brianheylin/AS3Futures

    Basically each request / command produces a receipt of the future outcome. Hense the receipt itself is called a Future. The code is in a workable form, and interesting to read over if you have the time

    Keep up the good articles ;)

    1. Thanks for your response Brian, I just wanted to respond to point out that I have read and appreciate your thoughts. I definitely agree that what I have been calling a ‘token’ or ‘delegate’ would be well served being named a ‘future’. Your futures implementation is interesting, though I have to say, for me it’s too verbose. It feels too much like a swiss-army knife, in that it includes functionality that is unnecessary for 99% of use-cases.

      I’m not sure I understand the point of “isolate”, I don’t think that it should be nameable, I don’t think all futures should expose progress, I don’t think that the IFuture interface should expose its own dispatcher (my view is that you expose as a listener, and define as a dispatcher, keeping everything under the hood), I think that structures to sequence processes/futures/whatever in parallel or series should be separate helpers… You get the picture, I think!

      Finally, many thanks for the article. I have put it on my reading list. After a quick skim it looks extremely interesting!

      1. Hey Alec, thanks for the comments

        The Future lib is certainly a swiss army knife, I view it as an extension of the Option monad in Scala (http://bit.ly/nCRGof), but used to represent time. It was designed to work primarily with functions, with the aim of keeping related functionality on the same screen and not fragmented across multiple classes.Moving the code over to a language like coffeescript removes a lot of the verbosity (JS / AS3 is pretty verbose to begin with)

        There is also a library for node.js that I came across that you might be interested in: 

        https://github.com/caolan/async

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>