Transforming ArrayCollection data using a map function to keep your view seperated in an MVC app

Last night I was working on a project which involved me having to display large amounts of data in a Flex list.  However, this data needed to be transformed before being displayed.  Let me explain with a simplified example.

The problem

Suppose we need to display a huge list of Result objects, where a Result object contains a score property (lets say it is a Number).  If we just need to display the number then we provide the ArrayCollection of Results as the dataProvider to the list and set the dataField to ‘score’ and everything is nice and easy.  Now suppose that we need to do some kind of calculation on score – for example, we need to divide it by 2 before displaying it.  Again, this is no problem; we use the labelFunction in the list and add a callback function in the MXML file that divides the score by two before returning it:

   1: private function labelFunction(item:Object):String {

   2:     var result:Result = item as Result;

   3:     return result.score / 2;

   4: }

This is all fine.

Now lets suppose that we need to transform the score in a more complicated way – imagine that we are writing some kind of multiuser application and we need to divide the score by the number of users currently logged on to the application before displaying it in the list.  At this point I should point out that I tend to use PureMVC so I will explain this using PureMVC terminology, but its equally applicable to all other MVC frameworks (Mate, Swiz, Robotlegs, etc).

Lets assume that the number of users logged on is in our Model tier; we then have a couple of options on how to go about this:

Inject the number of users into the view from our mediator and continue to use labelFunction.

       1: public var userCount:Number;

       2:

       3: private function labelFunction(item:Object):String {

       4:     var result:Result = item as Result;

       5:     return results.score / userCount;

       6: }

This is an ok solution – it doesn’t break MVC encapsulation and it works fine.  However, the drawbacks are that we need to monitor when userCount changes and each time re-inject it into the view (and tell the list to update itself).  But the main problem with this is that it gives our view knowledge of something that it shouldn’t know about.

Extend Result to do the calculation itself

We can add a getter to Result that does the calculation which means we can get rid of labelFunction in the view and just set dataField to the getter (e.g. dataField=”transformedScore”).  But this just moves the problem elsewhere; now the Result object will need to know the number of users; we’d either have to inject it in via a static variable, or give the Result object knowledge of the MVC framework.  This solution is in fact much worse than our first effort.

Pre-build the ArrayCollection with transformed scores

In this method we iterate through the Results, doing our calculation on score each time and building up a new dataprovider.  This is fine from an MVC perspective; the view gets its data fully formed in the format it requires, and since the mediator is building the list there is no problem with it querying the model tier.  However, this is a bad solution for other reasons; say that you have 5000 Result objects; the mediator will need to iterate through the entire list before passing the new collection to the view, incurring a nasty performance hit.  Furthermore we will need to rebuild this list entirely if the score or the number of logged in users change.

The solution

Here, at last, is my solution to the problem.  Like all good solutions it is disarmingly simple 🙂

   1: package org.davekeen.collections {

   2:     import mx.collections.IList;

   3:     import mx.collections.ListCollectionView;

   4:

   5:     public class MappedListCollectionView extends ListCollectionView {

   6:

   7:         public var mapFunction:Function;

   8:

   9:         public function MappedListCollectionView(list:IList = null) {

  10:             super(list);

  11:         }

  12:

  13:         override public function getItemAt(index:int, prefetch:int = 0):Object {

  14:             if (mapFunction == null) {

  15:                 return super.getItemAt(index, prefetch);

  16:             } else {

  17:                 return mapFunction(super.getItemAt(index, prefetch));

  18:             }

  19:         }

  20:

  21:     }

  22:

  23: }

MappedListCollectionView extends the normal ListCollectionView (which is the superclass of ArrayCollection) adding a single property – mapFunction – which transforms an item of the array collection into another item.  So now we can do the following in the mediator:

   1: var mappedListCollectionView:MappedListCollectionView = new MappedListCollectionView(resultsArrayCollection);

   2:

   3: mappedListCollectionView.mapFunction = function(item:Object):String {

   4:     var userCount:Number = getUserCountFromModel();

   5:

   6:     var result:Result = item as Result;

   7:     return result.score / userCount;

   8: }

   9:

  10: myView.myList.dataProvider = mappedListCollectionView;

I think this is an excellent solution – it maintains encapsulation within the view, it follows Flex standards (in that its syntax is the same as filterFunction), it will work with Flex binding and COLLECTION_CHANGE events and best of all it is high performance as mapFunction is only called for the rows that are actually on the screen.

One thing to bear in mind when using this solution is that Flex databinding will only be triggered when elements of the array collection itself change, so if userCount changes you will need to manually dispatch a COLLECTION_CHANGE event on the array collection.

Hope you find this as useful as I do!

Silverstripe – overview and impressions

I have recently been doing quite a lot of work with Silverstripe, a new(ish) open-source PHP MVC framework with an integrated CMS developed by a company in New Zealand.  Silverstripe has been gaining some decent support over the last year due to its interface, usability and extensibility.

How does it work?

Silverstripe is made up of two elements.  The first, and most important, is Sapphire.  This is a PHP based MVC framework, similar in many ways to Ruby on Rails.  It provides support for views (via a custom templating language), controllers and models.  Models have a number of special static attributes which provide Sapphire with information about the model; for example, which fields should exist in the database for the model and their datatypes are contained in the $db attribute, one-to-many relationships are defined in $has_many, and many more.  Sapphire then implements a database rebuild task which brings the database up to date with any changes in the code; this can either be run in the browser or from the command line for use in deployment and build scripts.  On a lower level Sapphire’s base Object.php class implements a kind of PHPified mixin system using the concept of extensions.  Unfortunately PHP isn’t really the best language for this kind of thing, but given the limitations and as long as you remember to follow some rules this is a fairly powerful system for extending and decorating objects.

The second part of the system is the Silverstripe CMS module.  This is a web application built on Sapphire (just as any site you create will be another web application built on Sapphire) which implements a very nice AJAX based CMS for your site with a tree on the left hand side and a content area on the right hand side.  The basic CMS is sufficient for most simple sites, but it can be extended hugely using extensions, decorators and plugins.

Silverstripe

The CMS module uses the object extension system to add a number of CMS specific special attributes to the model such as $allowed_children, $icon and $default_child which set various properties and permissions on the tree when that particular model is used in the CMS, and you can override getCMSFields() in the model to specify which fields are editable for a particular page, what kind of editors to use and which database fields they link to.  For example, the following in a Silverstripe model will create a natty CMS editor with a checkbox, title and HTML editor (using tiny_mce2) which automatically populates and saves to the database.  Nice eh?

   1: static $db = array(
   2:     'YesNo' => 'Boolean',
   3:     'Title' => 'Text',
   4:     'ContentHTMLText' => 'HTMLText',
   5: );
   6:
   7: function getCMSFields() {
   8:     $fields = parent::getCMSFields();
   9:
  10:     $fields->addFieldsToTab('Root.Content.Main', array(
  11:         new CheckboxField('YesNo', 'Check for yes'),
  12:         new TextField('Title', 'Enter title'),
  13:         new HTMLEditorField('Content')
  14:     ));
  15: }

Views and the templating language

Sapphire implements its own basic templating language (in *.ss files).  Its quite limited when compared to a more mature product like Smarty, but most of the time it is sufficient for what you will need.  You can embed another templates within a template, and access methods in the controller.  Occasionally this forces you to put logic in the controller or model that really belongs in the view, but conversely it stops you overloading your views with logic that doesn’t belong there 🙂

Impressions

Silverstripe is still a fairly young system and there are a few middling to serious problems with it.  Some specific things are problems with using the draft/published versioning system together with has_many relationships, issues with deployment when using staging and live servers, lack of hierarchical URLs and a number of other things that pop up from time to time.  However, we have just deployed a global Flash/HTML solution for a large company with multiple content editors; most of the way has been plain sailing and we never encountered an issue with Silverstripe that couldn’t be worked around one way or another.

In summary Sapphire/Silverstripe is a great piece of software and I recommend it to all web developers everywhere!  Its open source so it will continue to be improved by the community and I have no doubt that Silverstripe’s major problems will be addressed in the next few iterations.  The official ‘Silverstripe book’ has just been released in English which will no doubt help bring the system to a larger market.

Silverstripe (commercial) – www.silverstripe.com

Silverstripe (open source) – www.silverstripe.org

Silverstripe book (Amazon UK) – http://www.amazon.co.uk/SilverStripe-Complete-Guide-Development-Wiley/dp/0470681837

PureMVC Tutorial – Flex, PureMVC, Jabber and XIFF 3: Part 2 – Directory structure

Introduction
Part 1 – Frameworks
Part 2 – Directory structure
Part 3 – Application and ApplicationFacade
Part 4 – Notifications, Commands & Use Cases
Part 5 – Model & Proxy
Part 6 – The Application View & Mediator
Part 7 – The Login View & Mediator
Part 8 – The Roster View & Mediator
Part 9 – The Chat View & Mediator
Conclusion, Demo & Downloads

We need to create a PureMVC-friendly folder structure for our application – right click on src and create org, then within that create davekeen, then within that create xiffer.  This will be the base package for our Jabber client.  Now we need folders for the various bits of our application.  Within xiffer create three folders named controller, view, model and events.  Finally within view create a folder called components.  We should have ended up with a folder structure that looks like this:

org
davekeen
—–xiffer
——-controller
——-events
——-model
——-view
———components

Now is a good time to explain what each folder’s contents and functions are.  If you haven’t already done so you should have a read through the PureMVC best practices and framework overview as it will make things a lot clearer.

org.davekeen.xiffer

This is the base package of our application and will contain Application.mxml (the Flex entry point) and ApplicationFacade.as (the PureMVC entry point).  The rest of the application will be contained in the other folders.

org.davekeen.xiffer.controller

The controller package contains commands which implement individual pieces of business logic.  For our Jabber client this will be things like login, logout and send message.

org.davekeen.xiffer.model

The model package contains proxies which are the bits of code that do all the dirty work.  All communication between our application and the Jabber server will happen within the proxy; in fact this is the only bit of the application that will even know that a Jabber server exists.

org.davekeen.xiffer.view.components

The components packages contains our actual MXML files – the things we’ll see on the screen.  Cliff Hall has put a lot of thought into the design of PureMVC and these components know nothing about the framework or internals of our app.  When things happen they dispatch events, and they might expose public methods which the framework can invoke.

org.davekeen.xiffer.view

The view package contains mediators which control our components.  In some MVC frameworks this folder might contain the actual objects that are displayed (i.e. subclassing DisplayObject), but PureMVC adds an extra level of abstraction.  The mediators know about PureMVC, but the components are completely self-contained and rely on their associated mediators to do any application-wide communication.

org.davekeen.xiffer.events

The majority of communication within PureMVC is done using notifications, but the only exception to this is communication from components to their mediators which is done using normal AS3 events.  Its also perfectly acceptable to put this package within the view folder.

Onto part 3…

Nike Team Kit Builder

As this was such a large project I couldn’t fit all the bits in my portfolio page, so here is a list of technologies and collaborations along with a selection of pretty screenshots.

The majority of work was performed off-site, and if you would like to see it in action you can go and create your very own team kit on the first floor of Niketown, Oxford Street, London.

UPDATE: This project has at last been modified into a web-friendly version and put online, so you can now see many of the original features and create your custom kit on Nike’s site at http://www.nike.com/nikeos/p/nikefootball/en_US/kitbuilder

Technologies

  • AS3, Flash CS3 and a lot of complex OOP
  • A custom MVC framework developed specifically for the project
  • XML and E4X
  • Papervision 3D (GreatWhite)
  • Blender
  • AMFPHP
  • MySQL, AdoDB & ActiveRecord
  • Smarty
  • Dynamic mail generation
  • Database administration and setup on OSX

Collaboration

  • Working closely with one other developer throughout the project lifecycle
  • Remote working using SVN and remote administration through VNC
  • Working with a large team of artists and designers, including 3D designers

Screenshots

Matchday/training selection screen
Matchday/training selection screen
Team formation selector
Team formation selector
Matchday player top editor
Matchday player top editor
Papervision 3D real time mapping
Papervision 3D real time mapping
Style selector
Style selector
Socks style and colour editor
Socks style and colour editor
Live preview screen
Live preview screen
Matchday/training + preview
Matchday/training + preview
Checkout and confirmation screen
Checkout and confirmation screen
Shipping details screen
Shipping details screen
   

PureMVC: First thoughts & FlashDevelop templates

For those who aren’t interested in this blog and just want to get the FlashDevelop templates for PureMVC 2.0.3 you can download them here!

I’ve been meaning to have a good play with PureMVC for a while, and finally found some time a few days ago to check it out. For those who don’t know, PureMVC is one of a few Actionscript Model-View-Controller (MVC) frameworks for Actionscript. Two big established frameworks are ARP and Cairngorm (for Flex), and there are a bunch of other less well known frameworks, lots of which are available from OSFlash.

Personally I’m looking to get a few specific things out of my MVC framework:

  • Encapsulated concerns, high cohesion and loose coupling
  • Minimum configuration & ease of coding
  • Ease of maintenance

I’ll talk about each of these things separately. At this point I should point out that I have only been working with PureMVC for a little more than a day (that’s why it says first thoughts in the title), and some of what I’m saying here might be wrong! Any discussion on these points is gratefully received.

Encapsulated concerns, high cohesion and loose coupling

PureMVC takes a slightly different approach to the MVC design pattern than the official (if there is such a thing) stance, adding a bunch of extra design patterns into the mix. The View, Model and Controller are Singletons with access provided through a central Facade which is effectively the entrypoint and hub of your application. Models are then implemented as Proxies, controllers as Commands and views as Mediators. Communication between object is mostly done using PureMVC’s own Notification system rather than AS3 Events – this seems an odd design decision, but now that PureMVC is being ported to a whole host of different languages which do not support AS3 Events (Ruby, Python, HaXe, etc) this makes sense. I haven’t yet delved into the code to see if AS3 events are being used under the hood but if they are not, and if this performance boost was required, I imagine it would be fairly easy to implement. Note that AS3 events are still used on the visual side of things (i.e. between the Views and their Mediators).

Implementing the model through a proxy makes excellent sense, and makes the implementation of the model transparent to the rest of the application. All the app needs to care about is whether the call is synchronous or asynchronous and it should be possible to swap models around to your heart’s content. In fact, I’m sure it would be possible to ammend the Proxy such that all calls are treated as asynchronous giving complete transparency to the rest of the app.

Implementing controllers through commands is tried and tested, and pretty common. Its always worked fine for me. One nice touch that PureMVC adds is to allow direct mapping of Notifications->Commands with code such as:

   1: registerCommand(STARTUP, StartupCommand);

Nice and easy 🙂

The View/Mediator decision is a little more controversial, and I’ve read more than a few bloggers who find this a serious flaw in PureMVC. I can certainly see the motivation for it and in some ways its a very elegant solution, but I’ll need to try writing a medium-large size app before I can really comment. If the coder keeps it together and organises his components, mediators and composition carefully it could be that this works well. More on this in a later blog.

Minimum configuration & ease of coding

PureMVC involves a lot of typing. Creating a Mediator from scratch is a whole lot of hassle. Luckily for you FlashDevelop users I’ve updated some templates to work with PureMVC 2.0.3 (apologies to whoever wrote these in the first place – can’t find the URL, but will link as soon as I do!). Download them here and unzip to:

C:Documents and Settings<user>Local SettingsApplication DataFlashDevelopTemplatesProjectFilesAS3Project

However, even with templates taking away a lot of the setup work, there is still a lot of typing to do. Need to get a reference to a Proxy in your Command?

   1: var userProxy:UserProxy = facade.retrieveProxy(UserProxy.NAME) as UserProxy;

Ok, maybe I’m being pedantic, but when I’m writing a large RIA application I can imagine this getting very annoying. And my initial thoughts are that this seems to be a general theme throughout PureMVC; there is often a lot of work to do in order to get a simple task done. However, my feeling is that there will be a bunch of common tasks that will be able to be automated either through utility classes or through your IDE. And if the result of this extra typing is an elegantly structured and maintainable app then I guess its all worthwhile in the end 🙂

Ease of maintenance

GIGO. PureMVC goes a long way to forcing the programmer to ‘do the right thing’, but I reckon you can still end up with a mess of spaghetti if you are not careful. At this point the potential stumbling blocks seem to me to include:

  • Badly composed view and mediators.
  • Unnecessary numbers of Proxies, Commands and Mediators.
  • De-centralised logic (i.e. business logic placed in the view, which is actually possible with PureMVC)

I can easily envisage a situation where a bug arises and the developer is hard pushed to work out if it is located in the Mediator, Command or Proxy. However, I could be wrong about this and am very much looking forward to finding out myself.

Conclusion

Well, there isn’t one yet. I’ve a couple of weeks contractual work beginning next week where with any luck the client will be happy to have PureMVC let loose on their project so once I have some more hands-on practical experience with this framework I’ll be blogging something new. More later 🙂