Odds and Sodds

Change is afoot in the lands of Flash and Flex

November 14th, 2011

Adobe has recently made a number of rather muddled announcements around Flash and Flex that have caused confusion and concern in the development community. In this post I hope to clarify what actually has been said and present my take on what it might actually mean for those of us on the receiving end.

Adobe has made it clear over the past while that, like the other big players, they see HTML5 as a major force for expressive and rich content on the web. Actions such as the acquisitions of PhoneGap and Typekit, the development of Edge and Wallaby and their contributions to WebKit, jQuery and the CSS3 specification have backed up their openness about where they see the future heading. Unfortunately, how they see Flash (and Flex) fitting into this vision has been a little unclear, and recent announcements have only confused matters further.

Image used under creative commons licence from Janielle Beh

Flash

The most misunderstood and misreported of the announcements is that Adobe is ceasing active development of the Flash Player plug-in for mobile browsers, i.e. there will be no new versions of the browser plug-in for your mobile phone or tablet (except for critical patches). Development of the desktop browser version of the plug-in is very much continuing, with various interesting new APIs and features already announced for Flash Player 12. Personally, I am not surprised by the announcement regarding the plug-in for mobile browsers.

As users on mobile devices we don’t really use, expect or want overly rich content on the browser because it tends to be cumbersome due to high network latency and expensive (depending on your data tariff). Rather, we go to apps whenever we want anything more than fairly static content. Without an equivalent ubiquity to that on desktop browsers, Flash Player is never going to be in any kind of position to even attempt to change that behaviour, and attempting to achieve that penetration looks like a complete non-starter considering the platforms blocking it outright and the vast resources apparently required to support it for the others

In addition to these reasons, the ubiquity of modern, HTML5-supporting browsers on mobile devices undermines one of the other strong motivations for the use of Flash Player. Namely, that it is a solution to the issue of backwards-compatibility and feature support that plagues development for desktop browsers. Few would argue that HTML5 as it currently stands on mobile devices is unable to reliably provide the (limited) richness desired for web content.

Flex

The (rather tepid) announcement regarding Flex that Adobe has made is that after the release of Flex 4.6 in a few weeks, governance of the SDK development is going to change significantly. It is going to be handed over to an open source foundation consisting of members of the current development team, developers from the community, members of the Spoon Project and contributors from enterprise companies. In some respects Adobe has in the past hinted that something like this might happen. At AdobeMAX 2010, Deepa Subramaniam mentioned that they were considering allowing community developers to submit patches that would have to pass through Adobe’s test suits before becoming candidates for inclusion, and this move seems like a logical extension of that train of thought. I feel the Flex SDK actually now requires the kind of TLC only a more open governance can provide because I think it could do with a focus on behind-the-scenes fixing and improving rather than glamorous, headline-grabbing new features.

Flex developers are understandably confused and frustrated by this announcement. As recently as AdobeMAX 2011, Adobe appeared to be giving a strong message about the future of Flex as its solution for enterprise-grade development, with a clear roadmap. The change of governance inevitably means a change of roadmap, regardless of how strong an influence Adobe might have over the new foundation. With hindsight, it is perhaps more obvious that Adobe’s enterprise-related angle has actually related to the future of Flash Player rather than Flex. However, rather than being upset by the timidity with which Adobe has approached this change and seeing it as a negative move, I think the Flex community and business and enterprises with a stake in the technology should embrace this change and realise the opportunity it potentially provides. There is a lot of money and time committed to Flex other than Adobe’s and Adobe is still fully committed to the technologies that underpin Flex, both Flash and AIR, so it is all but guaranteed for the foreseeable future at the very least.

Image used under creative commons licence from Janielle Beh

AIR

At the same time as all of this, Adobe has firmly re-stated its commitment to AIR. Most of the development of the desktop Flash Player plug-in carries over into AIR, and a whole number of new AIR features primarily targeting mobile devices have also been announced. With the recognition that users go to apps for rich content on mobile devices this makes absolute sense, given that, in my opinion, AIR is one of the best genuinely cross-platform development targets. Flex developers in particular should take heart from this, considering the close coupling between the Flex framework and the AIR API. Over time, we may start seeing the runtime shift more towards its JavaScript and HTML capabilities or, at least, applications taking more explicit advantage those capabilities, but at worst AIR would allow a smooth and transparent transition between the technologies.

Summary

Overall, my impression is that Adobe have a similar view on how HTML5 and Flash will play out in the short and long term to the one we laid out in our white paper. Namely, in the short term, the richer, more interactive and dynamic the content/application being developed requires, the clearer the choice for Flash/Flex over HTML5 is. However, over time, as tooling, developer skills and technology improve, and the spread of mobile devices continues at its current pace, HTML5 is likely to become the “better” choice rather than Flash/Flex.

The exciting prospect here is that, historically, what Adobe has excelled at is tooling rather than technology. Photoshop, Premiere, Illustrator, Flash Professional and others are unquestionably fantastic tools, and Edge has already hinted that Adobe could reach similar standards for HTML5 authoring. Adobe’s experience in bona fide IDEs comes primarily from its Flash and Flex tools so it would be reasonable to expect that any new HTML5 tools will feel fairly natural to any developers used to their existing IDEs. Again, Edge supports this view, since it is remarkably similar to the older Flash authoring tools.

It is interesting to contrast Adobe’s apparent approach to the future with HTML5 against that of Google and Microsoft. Where as Adobe appears to content to position itself strongly somewhat on the sidelines from where it might have a better vantage point to allow it to dive in when appropriate, Google and Microsoft seem, to some degree, more intent on outright dictation of the direction we’re all heading in. Regardless of how things pan out, it’s going to continue to make for a fascinating spectacle.

UPDATE: Head here for my colleague Colin’s more general thoughts relating to these announcements, they are well worth a read

UPDATE: The Flex team have added further information to their announcement that further justify my call for optimism.

A Critique of Radar Charts

September 23rd, 2011

This article presents a critique of radar charts, a chart type commonly used to display multivariate data, highlighting how they are poorly designed to effectively communicate information in the underlying data, and presents a number of more effective alternatives

Introduction

Radar charts, sometimes known as spider, start or web charts, are a two-dimensional chart type designed to plot one or more series of values over multiple common quantitative variables by providing an axis for each variable, arranged radially as equi-angular spokes around a central point. The values for adjacent variables in a single series are connected by lines, and, frequently, the polygonal shape created by these lines in filled with a colour. Beyond this there are many subtle variations that have different consequences with respect to the efficacy of the chart. These variations will be covered at appropriate points in the following critique.

Radar Chart from Wikipedia

Chart 1: Radar chart from Wikipedia

Critique

Axes and Values

The axes of radar charts represent independent scales for each of the quantitative variables under consideration. Therefore, barring occlusion, comparing values for a single variable between series is straightforward and relatively effortless since it merely consists of assessing their position along a line, something we are able to do without any thought. However, a number of distinct issues arise when attempting to compare values across different axes.

Firstly (and most easily grasped), by definition there is nothing prohibiting axes representing wildly different scales since they are nominally independent. This is shown at its extreme in Chart 2. Clearly comparison across variables is pointless in this case, yet it is something a radar chart is designed to encourage us to do. Hopefully from this extreme example you are also able to appreciate that even in subtler cases where the scales are genuinely independent, whether that be the inversion of the scale on one axis or slightly different ranges of values being represented, comparison is rather absurd. So much so that very few charting libraries or applications support this in any way.

Radar Chart by Stephen Few

Chart 2: Artificial radar chart by Stephen Few to show independent axis scales

Unfortunately, even with a common scale between axes, comparing values across them remains cumbersome and error-prone. This is because rather than the simple straight-line comparison our visual perception is hard-wired to perform that is found in “conventional” chart types, comparison in radar charts requires conscious thought to mentally project a sort of arc of rotation to map a value from one axis onto another, something we are not particularly adept at.

Radar Chart by Visiblox

Chart 3: Radar chart byVisiblox

In order to help general perception and, in particular, comparison across axes, radar charts usually display gridlines connecting axes when they share a common scale (giving them their traditional spider-web-like appearance). However, even with these gridlines it remains cumbersome to compare values on non-adjacent axes. For example, try comparing the Space and Comfort scores for Monster Truck in Chart 3. It requires a surprising amount of conscious effort, doesn’t it?

Radar Chart by Kap Lab

Chart 4: Radar chart by Kap Lab

Aside from the non-data ink gridlines inevitably add, they also introduce further issues to radar charts. Mainly, they tend to add confusion around axis value labelling by breaking the association by proximity used to associate a particular value label with a mark on an axis. This is very clearly demonstrated in Chart 1. It requires active thought to disassociate the labels from the gridlines over which they inadvertently lie. For example, what is actually the $60 gridline appears to be labelled $50 instead. Chart 3 demonstrates a commonly attempted solution to this problem that unfortunately makes the chart just as difficult to read, only in a different way. Here the labels are so far away from the axis that, once again, conscious effort is required to comprehend what should be an inconspicuous, almost sub-conscious interpretation aide for the chart.

Radar Chart by Dundas Data Visualisation

Chart 5: Radar chart by Dundas Data Visualisation

Occasionally the gridlines on a radar chart are presented as circles rather than straight connecting lines between equivalent values on adjacent axes, as in Chart 5. Conceptually, I do not understand how a chart can combine circular connections between axis values and straight line connections between series values. Surely they must adhere to the same notional underlying data space?! Otherwise the chart is fundamentally broken. If anyone feels like creating a radar chart using strictly polar data space for both gridlines and series shapes, could you please send me a link? I’ve never actually seen one, and always like a giggle…

Connecting Lines and Nominal Scales

The quantitative variables and their values represented on the various axes of a radar chart are, with the exception of some less common cases such as when plotting timeseries data, distinct and unrelated. Yet, by design, radar charts force the suggestion of some relationship between the variables by having a connecting line between values on different axis in order to create the series grouping, thereby misleading the user. To help clarify this point, the chart below is identical to Chart 5 except that the information is plotted using “conventional” cartesian coordinates rather than the (pseudo-)polar coordinates of a radar chart.

Line Chart of Radar Chart by Dundas Data Visualisation

In this more familiar, non-circular format it is hopefully much more obvious that we are in fact dealing with a nominal scale on the x axis. That is, the categories on the x axis are simply named entities that have no intrinsic order and do not represent quantitative values. As such, the relationship and incline or decline in value the connecting line implies is grossly misleading since we could arbitrarily change the relationships by rearranging the categories (something we are free to do because of their lack of intrinsic ordering). When shown this way, many of you will recognise that this kind of information is likely to be best presented as a bar chart in some form, depending on the specific purpose of the chart, as shown for Bar Chart of Radar Chart (Dundas)

Occlusion

Occlusion, in data visualisation, refers to the phenomenon where a part of the visualisation obscures another part. Clearly this should be avoided, or at least minimised, since hidden visuals prevents you from interpreting the information correctly. Unfortunately, the design of radar charts means significant occlusion is inevitable when multiple series are plotted, since they must be “on top” of each other. In cases where the fill colour of the shape of a series is relatively or completely opaque, such as Chart 5, it can be nigh on impossible to see particular values. In these cases, the gridlines are also at best partially obscured, thereby making it even more cumbersome to discern the value any any given point. In Chart 5 this is has been somewhat overcome by adding tick marks on top of the series, which, unfortunately, also adds to the overall clutter on the chart.

When transparency is used to circumvent the problems caused by solid fill colours it creates a new problem: the unavoidable tinting effect can make differentiating the underlying series or matching them to a legend very difficult. As such, the approach that suffers least from occlusion is when no fill colour is used, as in Chart 1.

Shapes

One argument given by proponents of radar charts is that we are naturally adept at seeing and evaluating simple shapes. Although this is true, it overlooks the major issue that the overall shape presented for a series on a radar chart does not leverage any of the pre-attentive attributes we perceive quantitatively. In essence, this means we are unable to attribute much genuine meaning to the shape of a series. The only patterns our visual perception can really discern in a data set presented as a radar chart are similarity and extreme outliers. Both patterns are just as easy, if not easier, to recognise in more effective alternative visualisations, such as line and bar charts, where the shapes also have quantitative perception. Consider the example radar charts above, can you reliably say anything useful about the respective series based on their shapes other than where they are similar or there is an outlier?

A further issue with the shapes presented by radar charts are that the area of the shapes increases as a square of the values rather than linearly. This can cause us to misinterpret the data since a small difference in values results in a significant difference in area, thereby exaggerating any difference when we follow our natural inclination to compare the size of the shapes.

Alternatives

There are numerous more effective alternatives to radar charts, depending on the information being presented. These include bar charts, as shown above, line charts (particularly for timeseries data), parallel coordinates charts and, quite simply, tables showing the raw figures. The latter is commonly overlooked, but when dealing with relatively small, simple data sets it is frequently the most immediate and clear way to represent the information. In more complex cases, a more effective alternative to a radar chart can be to use a concept called small multiples, devised by Edward Tufte, in conjunction with bar charts. Using this approach, individual series are separated onto individual charts, all sharing a common x and/or y axis scale to enable meaningful comparison across them. This way it is easier to gain both a higher level overview and investigate at more detail because the clutter, occlusion and related issues common to complex charts, and particularly radar charts, are removed. The following chart is a redesign of Small Multiples of Radar Chart by KapLab

Note that the x axis scale labels have been omitted because they were not present in the original example and, even after a little background research, I was unable to deduce them. As far as I can tell, the data used to create the original chart is fictional. If the genuine figures are of interest, I would suggest using Google’s Public Data Explorer.

An immediate advantage of using tables, bar columns or small multiples is that they naturally support ordering. With a radar chart, introducing ordering would require the starting point and direction to be explicitly indicated somehow since neither can be inherently deduced from the radar chart design. In the aforementioned alternatives, left-to-right or top-to-bottom ordering is immediately evident. Although ordering is rarely a strict necessity for a chart with a nominal scale, it can provide useful structure to the information that reinforces or enhances the story being told. For example, an ordering of best to worst for some value can add a great deal of clarity to a chart.

Worked Example

Based on what has been explained so far, it is hopefully clear that there are many more effective ways to represent the information shown in radar charts. To further underscore this and to show how a little more thought and effort put into the design of a chart can have a significant effect on its efficacy, here follows a worked example based on Chart 1.

As previously highlighted, the axis categories of a radar chart are frequently a nominal scale, meaning there is no relationship between their respective values. Therefore, it is immediately clear that a bar chart would be a better representation of the data shown in Chart 1.

Alternative Approach Bar Chart 1

In the particular case of Chart 1, it is a fairly safe assumption to say that the chart is ultimately trying to convey the over- and under-spend of the respective departments. As such, the following redesign focuses on the more important value, the actual spending, and its relationship to the budget, by reducing the visual salience of the budget values.

Alternative Approach Bar Chart 2

Furthermore, it can be assumed that in this case the relative over- and under-spend of the respective departments is the primary concern. By charting this difference as a percentage of the original budget and ordering the resulting bar chart from biggest overspend to biggest underspend, we have a very clear story of which departments are the worst offenders at both ends of the scale.

Alternative Approach Bar Chart 3

Conclusion

Hopefully it is clear that radar charts, despite the initial appeal due to their interesting appearance, are ultimately useless, in that they are unable to efficiently and effectively communicate information to users. Regrettably, many vendors of charting products continue to include them and users seem more interested in that first 5-second “cool” reaction than their ability to serve their purpose. Furthermore, vendors are, quite justifiably, assumed to be experts in their field, or at least to have more expertise than consumers. Therefore, so long as vendors of charting products continue to support and encourage fundamentally flawed features like radar charts, users will, unless educated otherwise, understandably continue to assume these features are perfectly suitable. Vendors then often argue that consumers request these features. And so a feedback loop of delusion has developed…

So I implore vendors of charting products to take a “brave” stance: please stop pointlessly including functionality that allows users to create flawed visualisations. Or, at the very least, stop implying they are good practice by featuring them on your websites and marketing material. You are collectively undermining the power of data visualisation by encouraging users towards cumbersome, frustrating charts that do not work, when really you should know better.

Flash On The Beach 2011

September 15th, 2011

Yesterday I spoke at the Flash On The Beach conference in Brighton as part of the Elevator Pitch session. I think the session went really well, with a great mixture of topics so (hopefully) everyone was suitably entertained.

As previously mentioned, my 3-minute talk was titled How I Learned to Stop Drawing Lines and Love Whitespace. It tries to encourage designers to create more subtle structure in designs, using whitespace, rather than excessive lines and boxes, by understanding the Gestalt Principles. For anyone interested, here are my slides and speil (I believe a video may follow in due course):


Download

Overall, the whole conference was wonderfully interesting and inspirational. The sessions I particularly enjoyed and people I would recommend checking out are:

Oh, and here’s an image of me looking suitably po-faced, in full flow:

Graham at FOTB2011
Image courtesy of Marc Thiele

Static Initialisation in Flex

July 29th, 2011

For reasons best ignored I recently investigated the different ways in which static initialisation code can be run in Flex. As well as a direct equivalent to the static initialiser blocks available in Java and C#, Flex has a couple of subtle variants that can prove useful in different circumstances.

First up, the “standard” static initialisation technique, the direct equivalent to that found in Java and C#. The block of code shown below will execute once, the first time an instance of MyClass is created before that first constructor call is executed.

public class MyClass
{
    private static var initialised:Boolean = initialise();
    private static function initialise():Boolean
    {
        trace("static initialisation block that will execute" +
              " the first time 'new MyClass()' is called anywhere");
    }
}

If the intention of your code block is to create and initialise a static variable then this approach is clear and obvious. However, if you want to run some general initialisation code you still require a dummy variable and a return type on the static function. This is because the variable initialisation is the hook required to execute the function. This technique was used throughout the Flex 3 Framework code for style initialisation on components (an approach no longer in Flex 4 because of the improvements to style initialisation).

The second technique is that used by the Automation framework that is included with the SDK. This approach allows code to be executed when an application or module is loaded. The code would look as follows:

[Mixin]
public class MyClass
{
    public static function init(root:DisplayObject):void
    {
        trace("static initialisation block that will execute" +
              " when the application or module first loads");
    }
}

The root argument will be an ISystemManager or IFlexModuleFactory instance depending on whether the class was loaded as part of an application or module. Note that for the [Mixin] to be picked up the class must be included in the application or module, i.e. it must be referenced elsewhere in code or explicitly added using appropriate compiler arguments

The final technique comes from ActionScript’s ECMAScript heritage, in particular its prototype-based object model. In this case, code is written directly into the class scope, i.e. not inside a function block. This code will be executed the first time the class is executed in any way. That is, if the class uses the [Mixin] technique then it will execute along with the mix-ins static init function, otherwise it will be the equivalent to the “standard” approach and execute the first time the class is instantiated.

public class MyClass
{
    trace("static initialisation taking advantage of prototype-based object model");
}

I know it looks odd, but it genuinely is valid!

So putting it all together in the most artificial of examples, the following class would produce the trace output 1, 2, 3, 4 (with 3 and 4 only appearing when an instance of the class is instantiated):

[Mixin]
public function MyClass
{
    trace("1");
 
    public static function init(root:DisplayObject):void
    {
        trace("2");
    }
 
    private var initialised:Boolean = initialise();
    private function initialise():Boolean
    {
        trace("3");
    }
 
    public function MyClass()
    {
        trace("4");
    }
}

Flash On The Beach 2011

July 12th, 2011

Yesterday I received the exciting news that I will be speaking at the fantastic Flash On The Beach conference in Brighton this September. As Europe’s biggest annual Flash conference it brings together leading minds from all over the industry and focuses on design and development in equal share.

Flash On The Beach 2011

I will be presenting as part of the Elevator Pitch session, which consists of an hour of 3-minute talks by different speakers on completely different topics covering the full spectrum from design to coding. By all accounts the session is always intense but fun and inspirational and it is a wonderful opportunity for new talent to gain some exposure. My talk is entitled “How I Learned to Stop Drawing Lines and Love Whitespace” and I will be posting more details about it closer to the time.

Flex, Silverlight or HTML5? Time to decide…

May 6th, 2011

Building on the experience and expertise within Scott Logic, my colleague, Colin Eberhardt, has produced an excellent whitepaper considering the three big web technologies at the moment: Flex, Silverlight and HTML5.


Recent advances in web technologies have resulted in a complex landscape for application
developers to navigate. Coupled with the recent boom in new platforms, from desktops, netbooks,
smartphones to tablets, making an informed and future proof technology choice is all the more
difficult. In this paper we will set technology bias and politics aside to navigate the similarities and
differences between Flex, Silverlight and HTML5 and give you the power to decide.

This white-paper is aimed at technical decision makers who are looking to choose the correct
technology for web application development.

Head over to Colin’s blog to download or read the full paper and to add to the conversation.

Updating Flex Sparkline to Flex 4

April 19th, 2011

In a previous post I presented a library of sparkline implementations for Flex 3. I have finally gotten round to updating it for Flex 4. The new source code, documentation and pre-compiled swf (namespace: http://www.scottlogic.com/sparkline) can be obtained from here. As before, the components are being made available under the GNU General Public License.

As you can see, the versions appear identical:

Flex 3

Flex 4

Updating to Flex 4

For those of you interested in some of the changes required to migrate code from Flex 3 to Flex 4, here follow some of the details required to update this particular code.

The main change was due to Flex 4 essentially deprecating the StyleManager class and its static methods in order to provide mechanisms allowing modules to have independent style declarations. At the forefront of this change is the new IStyleManager2 interface, an instance of which can be obtained from the static getStyleManager method on StyleManager or, preferably, the styleManager property of UIComponent. In practice, using the Sparkline class as an example, this means changing from the static Flex 3 style declaration approach:

public class Sparkline extends SparklineBase
{
    /**
     *  @private
     */
    private static var stylesInited:Boolean = initStyles();
    /**
     *  @private
     */
    private static function initStyles():Boolean
    {
        var sd:CSSStyleDeclaration = StyleManager.getStyleDeclaration("Sparkline");
        if (!sd)
        {
            sd = new CSSStyleDeclaration();
            StyleManager.setStyleDeclaration("Sparkline", sd, false);
        }
 
        sd.defaultFactory = function():void
        {
            this.lineStroke = new Stroke(0x828282, 1);
            this.markerFill = new SolidColor(0x2963a3);
            this.markerStroke = new Stroke(0x2963a3, 0, 0);
            this.markerRadius = 2;
            this.normalRangeFill = new SolidColor(0x000000, 0.1);
        }
 
        return true;
    }
 
    ...
 
}

To overriding UIComponent‘s moduleFactory property to provide the “hook” for invoking the style declaration:

public class Sparkline extends SparklineBase
{
    /**
     * @private
     */
    private var _moduleFactoryInitialized:Boolean;
 
    /**
     * @private
     */
    public override function set moduleFactory(factory:IFlexModuleFactory):void
    {
        super.moduleFactory = factory;
        if (_moduleFactoryInitialized)
            return;
        _moduleFactoryInitialized = true;
        initStyles();
    }
 
    /**
     * @private
     */
    private function initStyles():void
    {
        var sd:CSSStyleDeclaration = styleManager.getStyleDeclaration("com.scottlogic.sparkline.Sparkline");
        if (!sd)
        {
            sd = new CSSStyleDeclaration();
            styleManager.setStyleDeclaration("com.scottlogic.sparkline.Sparkline", sd, false);
        }
        sd.defaultFactory = function():void
        {
            this.lineStroke = new SolidColorStroke(0x828282, 1);
            this.markerFill = new SolidColor(0x2963a3);
            this.markerStroke = new SolidColorStroke(0x2963a3, 0, 0);
            this.markerRadius = 2;
            this.normalRangeFill = new SolidColor(0x000000, 0.1);
        }
    }
 
    ...
 
}

You will also see that as of Flex 4, getting style declarations now requires a fully qualified class name rather than just the name of the class, e.g. com.scottlogic.sparkline.Sparkline rather than Sparkline. As before, this change is required due to the underlying shift in the approach used for style management by the framework in order to support independence between modules.

The other update required was due to the changed IFill and IStroke interfaces. In particular, the begin method on IFill takes an additional targetOrigin argument of type Point that specifies intended origin of the shape drawing. Similarly, IStroke‘s apply method now takes two additional arguments, targetBounds and targetOrigin, to provide the same drawing manipulation/restriction as IFill. Fortunately, the SDK team appear to have anticipated the potential complications and frustrations arising from these changes and have implemented them so that specifying a null value for the additional arguments results in identical behaviour to that which would have occurred in the Flex 3 code.

Presentation Model (or MVVM) with Mate

January 31st, 2011

This post introduces the Presentation Model (or MVVM) architectural pattern as one approach for creating “better” large-scale Flex applications and shows how the Mate Framework can be leveraged to not only achieve this pattern but increase separation of concerns above that of a “standard” Flex application.

Background

One of the great advantages Flex is that it makes creating applications very quick and easy by allowing ad-hoc mixing of MXML and ActionScript. This is ideal for rapid prototyping and can be all that is required for small applications. It also means anyone new to the technology can easily get started and relatively quickly put together quite rich applications. However, this architectural pattern, termed Autonomous View, does not scale well for larger, real-world projects. Fortunately, there are a numerous other architectural patterns – most famously(?) Model-View-Controller (MVC) – that attempt to directly address these concerns. Furthermore, various frameworks have been developed for Flex that specifically target these patterns. For example, both Cairngorm and PureMVC were designed for developing applications using the MVC architecture. There are many articles on the web considering the merits of different architectural patterns (and related Flex-specific frameworks). This article focuses on the Presentation Model architectural pattern, and a specific implementation of it using the Mate Framework, as a particularly useful approach to application development in Flex. Note that Mate is not designed to target any particular architectural pattern and that I am merely introducing its use with the Presentation Model pattern as one of many possible approaches, not a definitive or necessarily best one.

Presentation Model (or Model-View-ViewModel)

Presentation Model is an architectural pattern derived from Model-View-Controller (MVC) and originally introduced by Martin Fowler. Since then, Microsoft has introduced the Model View ViewModel (MVVM) pattern as a specialisation of Presentation Model that extends the original concept by adding a Model to make it more relevant to modern application development. I have adopted the MVVM terminology as I believe it better defines the entities involved in the pattern (purely because of its name).

The key features of the pattern are:

  • Model is the object model representation of state (whether as real state or as a data-access layer representation of the state)
  • View is the GUI elements
  • View model contains all GUI state and logic
  • View observes the view model and updates accordingly
  • View is “aware” of the view model
  • View model has no knowledge of the view

The observation required by the view is one of the reasons Flex is particularly suited to this pattern, as its binding functionality is simple and powerful implementation of observation. Additionally, the pattern ties in neatly to the relative merits of Flex’s two languages, creating a simple conceptual model for developers:

  • View = MXML = components & layout
  • ViewModel = ActionScript = behaviour & state

The main advantages of Presentation Model (or MVVM) are the clear code separation between GUI layout and behaviour and the testability this inherently introduces (compared to Autonomous View and similar). As well as the advantages this brings in all object-oriented technologies, in Flex this is particularly useful when its Module functionality is leveraged, as it creates clear and easy cut points. The disadvantages of this pattern is that it can be relatively verbose and sometimes requires information to be passed through view model instances in order to appropriately traverse the display tree. However, as I’ll show in the worked example below, the Mate framework provides some mechanisms that can drastically reduce the latter problem.

Mate

Mate is an event-driven Flex framework that provides both dependency injection and mechanisms to “glue” your code together, thereby enabling you to produce very loosely coupled code. The worked example below assumes some basic understanding of how Mate works, so if it is unfamiliar I recommend at least running through their Getting Started tutorial. There are also other excellent introductory articles and examples.

Worked Example

Here follows a worked example showing how the Mate framework can be leveraged to not only use the Presentation Model architectural pattern, but also add further elegance by using some of its core features. As previously mentioned, Gilles Guillemin has produced an excellent set of articles introducing Mate, and he even has an article that focuses on the exact same topic as this article. Unfortunately, his Presentation Model article does not continue with the nice example application he used in his previous articles and instead uses an overly simplistic example that does not present an overly compelling case.

The example below applies the Presentation Model (or MVVM) architectural pattern to the example Gilles Guillemin created for his introductory series to Mate. That is, an application with a global count that can be increased and decreased both directly and by manipulating a dynamic number of counters. Each counter maintains a sub-total that is the sum of its two sub-counters. Additionally, there is a global countdown that on reaching 0 resets all counts at all levels.


Source code

Core code

In order to not get too bogged down in application specifics and better focus on how Presentation Model (or MVVM) and Mate are used, I will focus on the sub-counter block of the user interface and logic. As shown in the class diagram below, the entities involved are: the view, SubCounterView; the view model interface, ISubCounterViewModel; and, an implementation of the view model interface, SubCounterViewModel. The diagram also shows how I have added some unifying interfaces for views and view models and a base class for view models containing some common functionality (more detail on this later when explaining the Mate-related specifics).

The observant among you will have spotted that there are no model classes mentioned. This is because in this particular example the models are the integer counts and as such do not require a custom class type. In more real-world applications it would be normal to have custom model classes that are used by the view models to maintain state.

Presentation Model UML
Class diagram abstractly showing presentation model example

The SubCounterView MXML consists of the viewModel property, a Mate map (more detail on this later when explaining the Mate-related specifics), a Grid to neatly lay out the local and sub-total counts and a couple of buttons to increase and decrease the local count. All state, such as the two count labels, is observed from the view model using binding and all logic/behaviour, such as the count increasing and decreasing, is delegated to the view model:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns:map="maps.*"
    implements="views.IView"
>
    <mx:Script>
        <![CDATA[
            import viewModels.ISubCounterViewModel;
            import viewModels.IViewModel;
 
            [Bindable]
            private var _viewModel:ISubCounterViewModel;
            /**
             * @see IView.viewModel
             */
            public function get viewModel():IViewModel
            {
                return _viewModel;
            }
            /**
             * @private
             */
            public function set viewModel(value:IViewModel):void
            {
                if (!(value is ISubCounterViewModel))
                {
                    throw new Error("ISubCounterViewModel instance expected");
                }
                _viewModel = ISubCounterViewModel(value);
            }
        ]]>
    </mx:Script>
 
    <map:SubCounterViewMap dispatcher="{this}" />
 
    <mx:Grid width="100%">
        <mx:GridRow>
            <mx:GridItem>
                <mx:Label text="Subtotal:"/>
            </mx:GridItem>
            <mx:GridItem>
                <mx:Label text="{_viewModel.subTotal}"/>
            </mx:GridItem>
        </mx:GridRow>
        <mx:GridRow>
            <mx:GridItem>
                <mx:Label text="Amount:"/>
            </mx:GridItem>
            <mx:GridItem>
                <mx:Label text="{_viewModel.count}"/>
            </mx:GridItem>
        </mx:GridRow>
    </mx:Grid>
 
    <mx:HBox>
        <mx:Button label="+" click="_viewModel.increaseCount()"/>
        <mx:Button label="-" click="_viewModel.decreaseCount()"/>
    </mx:HBox>
 
</mx:VBox>

As can be seen in the above code and class diagram, the view is tied to a view model interface rather than concrete class. Although this may seem unnecessarily verbose it brings some powerful benefits. it allows different view models, and therefore different logic and behaviour, to be used with the same view (i.e. inversion of control). This is both a relatively common code requirement and a useful mechanism for activities such as testing. It allows for the potential case of a single view model being shared across multiple views. A final (more arguable) benefit is that it encourages the developer to focus solely on the view rather than be distracted by behavioural details.

The ISubCounterViewModel interface looks like this:

/**
 * Interface for any presentation model that is to be used
 * with the SubCounterView view.
 */
public interface ISubCounterViewModel extends IViewModel
{
	[Bindable("subTotalChanged")]
	/**
	 * The total of all grouped sub-counter's counts.
	 */
	function get subTotal():int;
	/**
	 * @private
	 */
	function set subTotal(value:int):void;
 
	[Bindable("countChanged")]
	/**
	 * The local count.
	 */
	function get count():int;
 
	/**
	 * Increases the local count.
	 */
	function increaseCount():void;
 
	/**
	 * Decreases the local count.
	 */
	function decreaseCount():void;
}

The implementation of the interface, SubCounterViewModel, then looks like this:

/**
 * Default implementation of ISubCounterViewModel.
 */
public class SubCounterViewModel extends ViewModelBase implements ISubCounterViewModel
{
	private static const SUB_TOTAL_CHANGED:String = "subTotalChanged";
	private static const COUNT_CHANGED:String = "countChanged";
 
	//------------------------------------
	//
	//           Constructor
	//
	//------------------------------------
 
	/**
	 * Constructor
	 */
	public function SubCounterViewModel(dispatcher:IEventDispatcher)
	{
		super(dispatcher);
	}
 
 
	//------------------------------------
	//
	//           Properties
	//
	//------------------------------------
 
	//----------------------------------
	//  subTotal
	//----------------------------------
 
	private var _subTotal:int;
	[Bindable("subTotalChanged")]
	/**
	 * @see ISubCounterViewModel.subTotal
	 */
	public function get subTotal():int
	{
		return _subTotal;
	}
	/**
	 * @private
	 */
	public function set subTotal(value:int):void
	{
		if (value != _subTotal)
		{
			_subTotal = value;
			dispatchEvent(new Event(SUB_TOTAL_CHANGED));
		}
	}
 
	//----------------------------------
	//  count
	//----------------------------------
 
	private var _count:int;
	[Bindable("countChanged")]
	/**
	 * @see ISubCounterViewModel.count
	 */
	public function get count():int
	{
		return _count;
	}
	/**
	 * @private
	 */
	public function set count(value:int):void
	{
		if (value != _count)
		{
			_count = value;
			dispatchEvent(new Event(COUNT_CHANGED));
		}
	}
 
 
	//------------------------------------
	//
	//           Functions
	//
	//------------------------------------
 
	/**
	 * @see ISubCounterViewModel.increaseCount
	 */
	public function increaseCount():void
	{
		count++;
		subTotal++;
 
		// inform everyone else that the count has changed
		dispatchEvent(new CountEvent(CountEvent.LOCAL_UPDATE, _subTotal));
	}
 
	/**
	 * @see ISubCounterViewModel.decreaseCount
	 */
	public function decreaseCount():void
	{
		count--;
		subTotal--;
 
		// inform everyone else that the count has changed
		dispatchEvent(new CountEvent(CountEvent.LOCAL_UPDATE, _subTotal));
	}
}

The count and subTotal properties are straightforward Bindable properties with custom binding events. The increaseCount and decreaseCount methods are also very simple: they increase or decrease both the local count and the sub-total and then dispatch an event to inform that the sub-total has changed. The assumption here is that its local knowledge of the sub-total is correct and that it will appropriately be informed if that sub-total is changed elsewhere (much as it informs “others” of any change it makes, by dispatching the CountEvent). By making this assumption and using events for functional communication rather than explicit method calls we introduce loose coupling by using the observer pattern. Normally this would require some quite messy code to introduce and handle, but, as I will show, the Mate framework provides mechanisms that elegantly support this approach.

Glueing everything together

At this point we have all the constituent parts of the application, but they are not actually combined together in any functional way. Mate’s EventMap and LocalEventMap components are a powerful mechanism whereby this glue code can be introduced with minimal impact on any of the core code and easily swapped in and out. As exemplified in the SubCounterView code, maps are introduced as a simple MXML tag and beyond that are entirely self-contained. They leverage Flex’s event mechanism by hooking into an application’s display tree, either at the global stage level in the case of EventMap or at the level of a specific DisplayObject in the case of LocalEventMap (see how the dispatcher of the SubCounterViewMap in the SubCounterView above is set to be the view). To achieve better separation of concerns (and to avoid coding using what can quickly become little more than a global variable mechanism) LocalEventMaps are always preferable to EventMaps.

The first part of pulling the parts of the application together is to appropriately combine views with their view model instances. Mate’s map components allow us to inject these dependencies Injectors tags. The Injectors component can target any class instance that is added to the display tree below the map’s dispatcher or that is created within the scope of the map. With this hook, an ObjectBuilder is used to create the desired view model before being injected into the view using the PropertyInjector. This way we can very specifically target (and easily change) any desired view/view-model combinations. Here is what combining the SubCounterView with its SubCounterViewModel looks like in the SubCounterViewMap:

<mate:Injectors target="{SubCounterView}">
    <mate:ObjectBuilder
        generator="{SubCounterViewModel}"
        constructorArguments="{scope.dispatcher}"
    />
    <mate:PropertyInjector source="{lastReturn}" targetKey="viewModel" />
</mate:Injectors>

The second part of glue code required for the fully functional application is to turn the event communication assumption(s) of the view models (see SubCounterViewModel code and explanation above) into reality. Once again, Mate’s map components form the basis, but here it is the EventHandlers tag that provides the desired hook. The EventHandlers component allows a response to any event bubbled past the map’s dispatcher (or globally, depending on both the map type and the EventHandlers own dispatcherType). This response can be any sequence of actions, such as invoking a method on a class (MethodInvoker), setting a property (PropertySetter) or even creating another event (EventAnnouncer). An example from the application above is the reset event that is dispatched when the countdown reaches zero and all counters should be reset. For the SubCounterViewModel this is handled by setting the zero value from the reset as its local count value, as shown in the following code snippet from SubCounterViewMap:

<mate:EventHandlers type="{CountEvent.RESET}" dispatcherType="global">
    <mate:PropertySetter
        generator="{SubCounterViewModel}"
        source="event"
        sourceKey="newCount"
        targetKey="count"
    />
</mate:EventHandlers>

As shown in the class diagram and SubCounterViewModel code above (and highlighted by the ObjectBuilder in the view/view-model injection code above), the view model classes all require a reference to an IEventDispatcher instance to act as its event dispatcher despite themselves also being IEventDispatcher implementations. This is the compromise required to use Presentation Model in conjunction with Mate. As previously mentioned, Mate’s key components, EventMap and LocalEventMap, hook into the display tree’s event hierarchy. Therefore, the view model classes must dispatch their events into the display tree to appropriately tie in with the maps. Hence the IEventDispatcher reference required by all view models. Fortunately this functionality is easily captured by a common base class for all view models in such a way that this becomes all but transparent to specific view model types. See the source code for the worked example for further details.

And there you have it, the Presentation Model (or MVVM) building blocks and how to combine them into an application using the Mate framework in such a way that the various concerns of the code are cleanly separated.

Testing

As mentioned in the background information, testability is one of the strong drivers behind the Presentation Model (or MVVM) architectural pattern. To highlight this, the source code for the example above includes unit tests (using FlexUnit) for, amongst others, the view model classes, thereby showing how the pattern allows testing of view-related logic. By appropriately using interfaces and inversion of control throughout, the testability of the code is further enhanced as this allows us to leverage mock objects in the unit tests. I have used Mock4AS because I happened to have it to hand, but there are several other good mocking libraries for ActionScript, such as asMock and Mockolate, so take a look at the different ones and pick your favourite (I don’t have one yet).

Summary

Hopefully this article has highlighted the reason to consider the design of your Flex application in order to improve its maintainability and testability, and has introduced the Presentation Model pattern coupled with the Mate Framework as one of the potential approaches to solving these problems. I have only introduced a small sub-set of Mate’s components and their capabilities so would encourage you to delve deeper into the documentation, tutorials and examples to gain a better understanding of the full Mate framework and its subtleties even if you are not interested in the Presentation Model pattern.

You can download the full source code for the Flex example given in this blog post here: MatePresentationModel-src.zip.

Flex Charts vs Silverlight Charts – a test of Performance

November 16th, 2010

This post follows on from the comparison of two Silverlight chart libraries produced by my colleague, Colin Eberhardt, by adding an implementation of the simple image processing tool in Flex using the Flex Charting library to the comparison. The results show that the Flex Charts perform easily as well as the Visiblox charts without the need to specifically consider performance.

Since Colin produced his comparison of the Silverlight Toolkit and Visiblox charts there has been some noted interest in how Flash stacks up against them. This seems to be part of a general drive across the development community to gain a better understanding of the relative strengths of Flash/Flex, Silverlight and HTML5. In order to contribute a little to this, I produced a comparable application to those of Colin using the charting library that is part of the free, open-source Flex 4 SDK.

Here are my Flex application and the “winning” application from Colin’s investigation side-by-side. Click and drag a line across the image to plot the RGB pixel intensities along the line in the chart above. From these examples, it is clear that there is little to differentiate them performance-wise.

Flex Chart Visiblox Chart

Get Microsoft Silverlight

[Squirrel image used royalty free from stock.xchng; hare image used under CC licence from flickr]

Implementation

For details of the implementation of the Visiblox example above, see the original post. The mark-up for the Flex example above is as follows:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx" >
    <s:layout>
        <s:VerticalLayout />
    </s:layout>
 
    <fx:Declarations>
        <s:SolidColorStroke id="axisStroke" color="#cccccc" weight="1" />
    </fx:Declarations>
 
    <s:Group width="100%" height="100%">
        <mx:CartesianChart id="chart" width="100%" height="100%" visible="false">
            <mx:horizontalAxis>
                <mx:LinearAxis id="xAxis" />
            </mx:horizontalAxis>
            <mx:horizontalAxisRenderers>
                <mx:AxisRenderer axis="{xAxis}" axisStroke="{axisStroke}"
                                 showLabels="false" tickPlacement="none" />
            </mx:horizontalAxisRenderers>
            <mx:verticalAxis>
                <mx:LinearAxis id="yAxis" />
            </mx:verticalAxis>
            <mx:verticalAxisRenderers>
                <mx:AxisRenderer axis="{yAxis}" axisStroke="{axisStroke}"
                                 tickPlacement="outside" tickStroke="{axisStroke}" />
            </mx:verticalAxisRenderers>
            <mx:series>
                <mx:LineSeries yField="red">
                    <mx:lineStroke>
                        <s:SolidColorStroke color="#aa0000" weight="1" />
                    </mx:lineStroke>
                </mx:LineSeries>
                <mx:LineSeries yField="green">
                    <mx:lineStroke>
                        <s:SolidColorStroke color="#00aa00" weight="1" />
                    </mx:lineStroke>
                </mx:LineSeries>
                <mx:LineSeries yField="blue">
                    <mx:lineStroke>
                        <s:SolidColorStroke color="#0000aa" weight="1" />
                    </mx:lineStroke>
                </mx:LineSeries>
            </mx:series>
        </mx:CartesianChart>
 
        <s:Label id="instructions" visible="{!chart.visible}"
                 horizontalCenter="0" verticalCenter="0"
                 fontSize="9" color="#cccccc"
                 text="Use the mouse to 'drag' a line across the image below." />
    </s:Group>
 
    <s:Group>
        <mx:Image id="image"
                  source="@Embed(source='squirrel.jpg')"
                  mouseDown="imageMouseDownHandler(event)"
                  mouseUp="imageMouseUpHandler(event)"
                  mouseMove="imageMouseMoveHandler(event)" />
        <s:Line id="line">
            <s:stroke>
                <s:SolidColorStroke color="#000000" weight="3" />
            </s:stroke>
        </s:Line>
    </s:Group>
</s:Application>

The above mark-up creates two Groups: one containing the CartesianChart and instructions, and the other the Image and Line. This is remarkably similar to the mark-up of Colin’s Silverlight examples, if slightly more verbose. The verboseness is the result of both Flex technicalities and my overriding the rather ugly default styles axis styles for aesthetic reasons. Note that the CartesianChart was used rather than LineChart purely because of the LineChart using the ugly ShadowLineRenderer by default for LineSeries (the CartesianChart uses the simple LineRenderer).

Unlike in Silverlight, there is no need to do anything funky with mouse event handling Flex, as the Flex component lifecycle means the UI will always have a chance to render. This means a simple mouse move event handler can be used to construct the chart’s data:

private function imageMouseMoveHandler(event:MouseEvent):void
{
	if (!_mouseDown)
		return;
 
	line.xTo = event.localX;
	line.yTo = event.localY;
 
	// compute length of line
	var length:int = Math.sqrt(Math.pow(line.xFrom - line.xTo, 2) +
				   Math.pow(line.yFrom - line.yTo, 2));
 
	// build the chart data
	var bitmapData:BitmapData = Bitmap(image.content).bitmapData;
	var chartData:Array = [];
	var xIndex:int;
	var yIndex:int;
	var pixel:uint;
	var point:Object;
	for (var i:int = 0; i < length; i++)
	{
		point= {};
		xIndex = line.xFrom + (line.xTo - line.xFrom) * i / length;
		yIndex = line.yFrom + (line.yTo - line.yFrom) * i / length;
		pixel = bitmapData.getPixel(xIndex, yIndex);
		point.red = pixel & 0xff;
		pixel >>= 8;
		point.green = pixel & 0xff;
		pixel >>= 8;
		point.blue = pixel & 0xff;
		chartData.push(value);
	}
 
	chart.dataProvider = chartData;
}

Once again, this code is very similar to that used in the Silverlight examples to construct chart data. However, notice that here we can choose to take advantage of ActionScript 3′s dynamic objects to drive our chart for simplicity’s sake. Furthermore, there has also been no need to pre-process the image data to obtain pixel information since the Image, Bitmap and BitmapData classes are designed and optimised for exactly this kind of pixel-level manipulation.

Conclusions

From the above examples it is apparent that there is little, if anything, to differentiate their relative performance. Furthermore, it would be fair to say that the outright technology choice of Flash/Flex or Silverlight has not differentiated these examples. Rather, the choice of charting library in either technology is far more significant with respect to performance. Therefore, in this case, the technology choice would have to be driven by some other factor than performance, for example, plug-in penetration, cost or existing developer expertise.

However, at a more technical level there are some interesting points to consider alongside the comparative performance of the two applications. The Silverlight examples were created with specific techniques for improving their performance. The implication is that a naive Silverlight implementation of the application is likely to have noticeable performance issues. In contrast, the Flex example has purposefully been created without any of the known performance improvement techniques, yet is still as responsive.

It is also worthwhile contrasting the respective charting libraries. The Visiblox charting library has specifically been designed for performance over flexibility, where as the Flex charting library is the opposite. The result is that although they are roughly equal in performance, the Flex charting library has many more options for customisation and extension than the Visiblox charting library. However, it should be noted that the Flex charting library is relatively mature (~4 years old) compared to the Visiblox charts (~2 months old).

You can download the full source code for the Flex example given in this blog post here: FlexChartPerformance.zip; and the full source code for the Silverlight examples given in Colin’s blog post here: ChartPerformance.zip

Logging to Server from Flex

August 6th, 2010

An issue that can crop up with Flex applications is the lack of any log information to match up against users’ bug reports. It is possible to configure the debug version of Flash Player to record trace() output, but most users do not have this setup. Additionally, it is much more desirable to maintain this kind of information server-side, where the development team have control, rather than relying on users’ whilst also clogging up their machines. A general approach to this problem is relatively obvious – send the information back to the server – but there are all sorts of ways this could be implemented. Of course, sending lots of logging information to the server creates an overhead in the application, so this should very much be considered on a case by case basis.

A solution that we use takes advantage of Flex’s native logging API, allowing it to be transparently added or removed from an application while providing us with the benefits of a decent logging framework, for example logging levels. Flex provides the ILogger class, instances of which are obtained using Log‘s getLogger() method, to log messages. In turn, these messages are sent to one or more ILoggingTargets, the most common of which, TraceTarget outputs the logging information using the trace() method. The logging API documentation provides details and examples for how to get started with this basic logging setup.

On the Flex side, our solution consists of little more than a custom ILoggingTarget implementation, RemoteTarget, that attempts to send the logging information to a specified URL and the appropriate code to initialise the target. Note that RemoteTarget uses URLLoaders rather than HTTPServices because HTTPService itself uses the logging API, thereby causing an infinite loop. Another feature worth highlighting is that our implementation stops logging if it has encounters any errors when sending the information to the server, so that, for example, an application does not repeatedly hit a server that is unavailable. All source code and examples associated with this article can be found here.

package com.scottlogic.logging
{
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.net.URLVariables;
 
    import mx.logging.AbstractTarget;
    import mx.logging.ILogger;
    import mx.logging.LogEvent;
    import mx.utils.StringUtil;
 
    /**
     * ILoggingTarget implementation that sends logging details
     * to a remote service.  The following details are sent as
     * request parameters:
     *  - level: the log level as an integer (see LogEventLevel)
     *  - category: the log category
     *  - timestamp: as milliseconds from 1st Jan 1970
     *  - message: the log message
     */
    public class RemoteTarget extends AbstractTarget
    {
        /**
         * Flag to indicate whether remote logging is enabled
         * or not.  The RemoteTarget will automatically disable
         * itself if it encounters any errors.
         */
        private var enabled:Boolean = true;
 
        /**
         * Constructor
         */
        public function RemoteTarget()
        {
            super();
        }
 
        private var _url:String;
        /**
         * The URL of the service to which to log.
         */
        public function get url():String
        {
            return _url;
        }
        /**
         * @private
         */
        public function set url(value:String):void
        {
            _url = value;
        }
 
        /**
         * @private
         */
        override public function logEvent(event:LogEvent):void
        {
            // if there has been any issue with remote logging
            if (!enabled)
                return;
            // if no url is set then do nothing
            if (!_url || StringUtil.trim(_url).length == 0)
                return;
 
            // attempt to log to the server
            try
            {
                var variables:URLVariables = new URLVariables();
                variables.level = event.level;
                variables.category = ILogger(event.target).category;
                variables.timestamp = new Date().time;
                variables.message = event.message;
                var request:URLRequest = new URLRequest(_url);
                request.method = "POST";
                request.data = variables;
                var loader:URLLoader = createLoader();
                loader.load(request);
            }
            catch (e:Error)
            {
                enabled = false;
                trace(e.message);
                trace(e.getStackTrace());
            }
        }
 
        /**
         * Creates a URLLoader with all the appropriate event listeners.
         */
        private function createLoader():URLLoader
        {
            var loader:URLLoader = new URLLoader();
            loader.addEventListener(IOErrorEvent.IO_ERROR,
                                    ioErrorHandler,
                                    false, 0, true);
            loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,
                                    securityErrorHandler,
                                    false, 0, true);
            return loader;
        }
 
        /**
         * Disables the remote logging and traces debug information
         * when there is an IO error during logging to the remote server.
         */
        private function ioErrorHandler(event:IOErrorEvent):void
        {
            enabled = false;
            trace("ERROR - IO error in RemoteTarget");
            trace(event.text);
        }
 
        /**
         * Disables the remote logging and traces debug information
         * when there is a security error during logging to the remote
         * server.
         */
        private function securityErrorHandler(event:SecurityErrorEvent):void
        {
            enabled = false;
            trace("ERROR - Security error in RemoteTarget");
            trace(event.text);
        }
    }
}

Here is a small example showing how RemoteTarget can be used:

<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="horizontal"
    applicationComplete="initialise()"
>
    <mx:Script>
        <![CDATA[
            import com.scottlogic.logging.RemoteTarget;
            import mx.logging.Log;
            import mx.logging.LogEventLevel;
            import mx.logging.ILogger;
 
            private static const LOG:ILogger = Log.getLogger("RemoteLogging");
 
            private function initialise():void
            {
                var target:RemoteTarget = new RemoteTarget();
                target.url = ""; // set logging service URL here
                target.level = LogEventLevel.INFO;
                Log.addTarget(target);
            }
        ]]>
    </mx:Script>
    <mx:Label text="Text:" />
    <mx:TextInput id="input" />
    <mx:Button label="Log Text" click="LOG.info(input.text);" />
</mx:Application>

As the information is being sent back as a standard example server-side code I have included is in Java and consists of a relatively simple HttpServlet that parses the information and mirrors it onto its own logging framework, in this case log4j.