UI mediation sucks. Mediate behaviours, not views.

7 08 2011

Code for this post can be found on Github.

In this post, we’re going to look at how the variance utility for Robotlegs allows mediation against interfaces rather than concrete classes. Apart from the gains in decoupling, we can mediate purely against behaviours, rather than specific implementation. And, as we’re talking interfaces, a UI component can implement as many interfaces (behaviours) as it likes!

Libraries used in this post:

Why use mediation at all?

Mediation is a design pattern that performs the job of managing communication between parts to decouple logic. In terms of modern MVC frameworks, mediators are typically employed to monitor UI pieces from the outside in, so that the UI has no references to the framework whatsoever. The common alternative is the Presentation Model pattern (PM) that typically involves injecting in one or more presentation models to the UI component. As such, the UI component is thus coupled to the particular PMs it uses. That said, when mediating against classes (rather than interfaces, which we’ll get to), we couple the mediator to the UI, which is suboptimal.

Why Robotlegs?

Robotlegs (RL) is a lightweight (50KB) and prescriptive library for MVCS applications. Out of the box it provides us with Mediation, IOC container and Dependency Injection via the familiar [Inject] metadata (thanks to SwiftSuspenders).

Regular (invariant) mediation

Take some UI component: (SomeComponent.mxml)

<s:VGroup>
    <fx:Script>
        //the mediator will tell me when something happens
        public function asyncReturned():void
        {
            //something happened!
        }

        private function onClick(evt:MouseEvent):void
        {
            //tell whoever's listening to do something
            dispatchEvent(new ControlEvent(ControlEvent.START));
        }
    </fx:Script>

    <s:Button label="Start" click="onClick(event)" />
</s:VGroup>

A mediator for this component might look like (SomeComponentMediator.as):

public class SomeComponentMediator extends Mediator
{
    [Inject]
    public var view:SomeComponent;

    [Inject]
    public var service:ISomeService;

    private var viewHandler:Function;
    private var serviceHandler:Function;

    //called when UI component is added to stage and mediator assigned
    override public function onRegister():void
    {
        //handle control events responding
        viewHandler = function(evt:ControlEvent):void
        {
            serviceHandler = function(evt:ServiceEvent):void
            {
                //some where later on tell the view it is done...
                view.asyncReturned();
            }
            service.addEventListener(ServiceEvent.COMPLETE, serviceHandler);

            service.doSomething();
        }

        //attach the listener
        view.addEventListener(ControlEvent.DO_ASYNC, viewHandler);
    }

    //called when UI component is removed from stage, prior to mediator being destroyed
    override public function onRemove():void
    {
       service.removeEventListener(ServiceEvent.COMPLETE, serviceHandler);
       view.removeEventListener(ControlEvent.DO_ASYNC, viewHandler);
    }
}

Via the ADDED_TO_STAGE event, Robotlegs wires up an instance of a mediator for each UI component it finds. All that it requires is that you map in the mediator:

IMediatorMap.mapMediator(SomeComponent, SomeComponentMediator);

Don’t like extending base classes or want your own implementation of mediation? No problems just implement IMediator instead.

So why covariance?

Because there are some problems here with mediating directly to views:

  • A UI component can only have one mediator;
  • The mediator is tightly coupled to the UI control.

So, what if we wanted to map to an interface instead? We could include the Robotlegs Variance Utility (as a library to our project), and tweak our mediator mapping call to:

IVariantMediatorMap.mapMediator(ISomeComponent, SomeComponentMediator);

The above example becomes:

<s:VGroup implements="ISomeBehaviour">
	<fx:Script>
		//the mediator will tell me when async returns
		public function asyncReturned():void
		{
			//something happened!
		}

		private function onClick(evt:MouseEvent):void
		{
		     //tell whoever's listening to do something
		     dispatchEvent(new ControlEvent(ControlEvent.START));
		}
        </fx:Script>

    <s:Button label="Start" click="onClick(event)" />
</s:VGroup>

Using this interface:

[Event(name="startAsync",type="ControlEvent")]
public interface ISomeBehaviour
{
	function asyncReturned();
}

And the mediator becomes:

public class SomeComponentMediator extends Mediator
{
    [Inject]
    public var view:ISomeBehaviour;

    //... (as before)

}

And voila – we’ve solved both problems in one fell swoop! A UI control can implement as many interfaces as it needs, and our mediates now mediate against a behaviour rather than a concrete UI piece.

So now what?

There’s still room for improvement. Flash has no way to enforce that the class – SomeComponent – will actually dispatch the ControlEvent. If we’re writing these interfaces – these behaviours – we want a contract that explicitly states which events should be fired. Better yet, we’d like the option to state if these events are a functional level or a type level.

Enter Signals, stage right

Signals provide an alternative to events. They are designed to be used within APIs and class libraries, rather than replacing events altogether (Flash events are well suited to UI hierarchies). Where events fire and are handled at a type (class) level, signals live at the variable level. Not only can we pass them to and return them from methods, we can also enforce their presence in types that implement our interfaces. Check out an earlier post on Signals.

By including the lightweight Signals SWC, we have access to the ISignal contract and some common implementations.

Our interface from before now becomes:

public interface ISomeBehaviour
{
    function asyncReturned();

    function get start():ISignal;
}

Our view becomes:

<s:VGroup implements="ISomeBehaviour">
    <fx:Declarations>
        <signals:Signal id="startSignal" />
    </fx:Declarations>

    <fx:Script>
        //the mediator will tell me when something happens
        public function asyncReturned():void
        {
            //something happened!
        }

        //provide access to the type-level signal
        public function get start():ISignal
        {
            return startSignal;
        }
    </fx:Script>

    <!-- Here we actually send the message to the mediator -->
    <s:Button label="Start" click="start.dispatch()" />
</s:VGroup>

We actually now have a property start, exposed from the view that implements the interface, that we can attach and remove handlers to in our mediator.

And so our mediator finally becomes:

public class SomeComponentMediator extends Mediator
{
    [Inject]
    public var view:ISomeComponent;

    [Inject]
    public var service:ISomeService;

    private var serviceSignal:ISignal;

    override public function onRegister():void
    {
        //handle control events responding
        view.start.add(function():void
        {
            serviceSignal = service.doSomething();

            serviceSignal.add(function():void
            {
                //when the service returns, notify the view
                view.asyncReturned();
            });
        });
    }

    override public function onRemove():void
    {
        serviceSignal.removeAll();
        view.start.removeAll(); //clean up any listeners
    }
}

So what now?

Grab the code on Github and have a play around. For ease of use, I’ve included the dependencies along with the source.





An introduction to Maven and Flexmojos

27 07 2011

I presented an introduction to Maven and Flexmojos last night. The talk is a varient of the one I will be giving at FITC@MAX this year.

The talk starts off discussing Maven, the hierarchical structure of projects, POMs and the build life cycle. We then discuss the Flexmojos plugin to build Flex applications. After that, we talk about repositories – both local and remote, and discuss how Nexus can perform the role of remote repository within your organisation, proxying to others on the web.

We work through 6 main examples. All code is on Github.

  1. The simplest application possible – a custom Hello World that uses the latest Flexmojos (4.0-RC1) and Flex SDK (4.5.1)
  2. Adding automated unit tests to the build
  3. Installing custom dependencies that aren’t hosted on the web
  4. Using the Flasbuilder goal to create a Flashbuilder project from a build script
  5. Starting Flex applications from the supported archetypes (templates)
  6. A basic application that has custom dependencies and its own class library.

Source files: https://github.com/justinjmoses/flexmojos-introduction





What’s the deal with Signals?

7 07 2011

Signals. Heard of them? What’s the big deal you say?

Simple. The event system in AS3 is both limited and antiquated. True, native AS3 events offer a convenient way of messaging (bubbling) withinUI hierarchies. Yet, at an abstract API level, they more often as not restrict the developer than aid them.

Chiefly, what Robert Penner has done with as3-signals is create a way to represent events as variables, rather than as magical strings firing off at the type (class) level. It sounds simple. It is. Yet the implications for your architecture is vast.

Consider the following interface of asynchronous methods:

public interface IServiceStream
{
  function open():void;
  function close():void;
}

Now, as the contract is asynchronous, we’ll need some events to notify us when methods have completed. Let’s say we have the following events:

  • OPENED
  • CLOSED
  • ERROR
  • TIMEOUT

In keeping with the native AS3 model, the best we can hope for is using the following metadata at the type level:

[Event(name="streamOpened",type="...")]
[Event(name="streamClosed",type="...")]
[Event(name="streamError",type="...")]
[Event(name="streamTimeout",type="...")]
public interface IServiceStream
{
 //...
}

There are four problems with this approach:

  1. Decorating via metadata does not enforce that implementors of the interface actually dispatch these events.
  2. We should, for completeness, define the events somewhere as static constants. This means we can no longer simply write interfaces, and need to write event implementations and deploy them with our API;
  3. We’re using magic strings, and as there is no compile-time checking of the metadata, we’re opening ourselves up to illusive runtime errors, if the wrong events are dispatched.
  4. There is nothing to specify which events fire when – and which events belong to which method, and which belong to the class itself.
The first two are fairly straightforward, so let’s focus on the latter two.

Magic Strings and No Contract

We have no way of tying the event type to the constant in some Event class it will eventually correspond to. “streamOpened” may map to ServiceStreamEvent.OPENED, and yet we cannot know this at the metadata level (not for the interface or even the implementor). From #1, it is evident that although we can put these requirements in, we cannot enforce their usage.

Method vs Type-level Events 

Anyone listening to an implementor of our interface, would listen at the type level for all events, and deal with them as they occurred.

For example:

var service:IServiceStream = new ServiceStreamImplementation(...);

service.addEventListener(ServiceStreamEvent.OPENED, function(evt:Event):void { ... } );
service.addEventListener(ServiceStreamEvent.CLOSED, function(evt:Event):void { ... } );
service.addEventListener(ServiceStreamEvent.ERROR, function(evt:Event):void { ... } );
service.addEventListener(ServiceStreamEvent.TIMEOUT, function(evt:Event):void { ... } );

//later when required
service.open();
We’ve been forced to declare all our handlers in one point, early enough to precede the calling of any event-dispatching methods. Anyone reading the code will have no real knowledge at which point the implementing class dispatches which event – hence why all the listeners need to be adding initially. As the interface writer, all we can do is say “this interface can dispatch any of these events” – we cannot even enforce that they are used. From #1 above, the metadata is not enforced, it’s just decoration.

Here is where Signals come in. Let’s rewrite the interface using simple signals.

public interface IServiceStream
{
  function open():ISignal;
  function close():ISignal;
}
Now let’s look at a partial implementation.
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

import org.osflash.signals.ISignal;
import org.osflash.signals.Signal;

public class ServiceStream implements IServiceStream
{
	public function open():ISignal
	{
		var signal:Signal = new Signal(Object);

		//do something asynchronously...
		var httpService:HTTPService = new HTTPService();
		httpService.addEventListener(ResultEvent.RESULT,
			function(evt:ResultEvent):void
			{
				//use the closure to access your signal and dispatch it async
				signal.dispatch(evt.result);
			});

		httpService.send();

		return signal;
	}

	//function close();
}

Now, the usage of this implementation can become:

var service:IServiceStream = new ServiceStreamImplementation(...);

service.open().addOnce(function(result:Object):void
{
    //do something with your returned "result"
});

In one fell swoop we fixed all four of the problems with events. We even have the convenience methods addOnce() and removeAll() from the ISignal interface. The former ensures your listener is removed after it is first used, the latter is pretty self-explanatory. If you look even closer, you’ll see we just implemented the Fluent interface for free.

Imagine this in your mediator pattern – your UIs by definition have no reference to their mediator. Now they have a prescribed way of notifying their mediators that something has occurred.

Wait a second. What about those other events?

How do you return multiple items from a regular method call – compose a type for your requirements.

You could write the following signal collection:

public class ServiceSignals
{
	public var open:ISignal = new Signal(Object);
	public var error:ISignal = new Signal(String);
	public var timeout:ISignal = new Signal();
}

and change your interface to:

public interface IServiceStream
{
  function open():ServiceSignals;
  //...
}

Better yet, you could keep your interface and simply conform your Signal collection into an ISignal with a default listener/dispatcher:

public class ServiceSignal extends Signal
{
	var open:ISignal = new Signal(Object);
	var error:ISignal = new Signal(String);
	var timeout:ISignal = new Signal();

	override public function add(listener:Function):ISignalBinding
	{
		return open.add(listener);
	}

	override public function addOnce(listener:Function):ISignalBinding
	{
		return open.addOnce(listener);
	}

	override public function dispatch(...parameters):void
	{
		open.dispatch();
	}

	override public function remove(listener:Function):ISignalBinding
	{
		return open.remove(listener);
	}

	override public function removeAll():void
	{
		open.removeAll();
	}
}

Then you could use it as such:

var service:IServiceStream = new ServiceStreamImplementation(...);

var signal:ServiceSignal = service.open();

signal.addOnce(function(result:Object):void
{
    //do something with your returned "result"
});

signal.error.addOnce(...);

signal.timeout.addOnce(...);

Perhaps you’re not a huge fan of this solution. You may find that the error & timeout signals are type-level events, and you don’t want to have to add handlers for both open() and close(). OK – so what about this implementation?

public class ServiceStream implements IServiceStream
{
	public var error:ISignal = new Signal(String);
	public var timeout:ISignal = new Signal();

	private var _time:int = 30000;
	private var timer:Timer;

	public function open():ISignal
	{
		var signal:Signal = new Signal(Object);

		//do something asynchronously...
		var httpService:HTTPService = new HTTPService();
		httpService.addEventListener(ResultEvent.RESULT,
			function(evt:ResultEvent):void
			{
				//use the closure to access your signal and dispatch it async
				signal.dispatch(evt.result);
			});

		httpService.addEventListener(FaultEvent.FAULT,
			function(evt:FaultEvent):void
			{
				error.dispatch(evt.fault.faultString);
			});

		timer = new Timer(_time,1);

		var timerHandler:Function = function(evt:TimerEvent):void
			{
				timeout.dispatch();
				timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timerHandler);
			}
		timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerHandler);

		httpService.send();

		timer.start();

		return signal;
	}

	//function close();

}

Notice how we define the handler function as a variable so we can remove it in the listener. This is replicating the ISignal.addOnce() functionality. True, we could have used weak event listeners to allow for garbage collection, however this way is closer to our approach with Signals, so we’ll keep it for consistency.

Your implementor could then be used like this:

var service:IServiceStream = new ServiceStreamImplementation(...);

service.open().addOnce(function(result:Object):void
{
    //do something with your returned "result"
});

service.error.addOnce(function(message:String):void
{
    //handle error
});

service.timeout.addOnce(function():void
{
    //handle timeout
});

service.close().addOnce(function():void
{
    //now closed
});

Whichever way you decide, Signals give you the choice you need to make the best decision for your API.





Flex code injection using conditional breakpoints

20 01 2011

So while it’s not new news, something I saw in a video from MAX 2009 on Flash Builder 4 last year really stuck with me. And, it’s been saving me day after day on this massive project.

It has to do with conditional breakpoints in FB4. On top of the normal, if x == true conditions, you can use a sneaky comma trick to inject code.

It’s simple, you enter true (1) or false (0) in the box (depending on whether you want the breakpoint to pause execution) and then add any expression(s) you want, separated by commas. The beauty is that these expression(s) is/are evaluated regardless of whether the breakpoint is executed or not. That means you can inject code into a running debug session without stopping to compile and rerun.

There are two main usages I’ve found for this feature:

Inserting Traces

I regularly find myself tracing through asynchronous operations, trying to figure out the order of events and properties at the time. Sometimes (and this evokes one very painful memory) I’m tracking multiple timers and I can’t learn anything from breakpoints, as I need to get an idea of the order of the ticks (and the corresponding events that are firing).

These scenarios make them a perfect candidate for the injected trace. Try this:

 

FB4 Conditional Breakpoint Dialog: Tracing

FB4 Conditional Breakpoint Dialog: Tracing

 

Modifying Properties

The other main use-case is the all-too-common scenario when you want to change a property mid-execution. We’ve all been there – myself just today.

FB4 Conditional Breakpoint Dialog: Property Setting

FB4 Conditional Breakpoint Dialog: Property Setting








Follow

Get every new post delivered to your Inbox.