Book review: ActionScript Graphic Cookbook by Peter Backx and Dominic Gélineau

book cover
ActionScript Graphic Cookbook
Backx, Peter and Gélineau, Dominic
2012, Packt Publishing
978-1-84969-320-2

This is a cookbook, a book of recipes; it is not a reference or teaching book; you will not have a comprehensive library at the end. This book give specific solutions to specific needs. A teaching book might show a finished chart with call-outs explaining how to create or configure the pieces, but a recipe is not an analysis: it starts with the least foundation it can and works towards a finished graphic. This book will show you how to create graphic representations of data; it will not tell you when to use a particular technique.

It is also not a users’ manual for the Data Visualization chart library from Adobe, although the recipes in the middle of the book use that library. For simple line charts (e.g. sparklines), the recipe describes how to draw the lines oneself using the ActionScript graphic primitives. For advanced rotatable 3-D charts (which Data Visualization does not support) and 3-D landscapes, it uses advanced geometry and low-level polygon fills. While these are not Flex components (the code is pure ActionScript with mostly Sprite-based classes, many recipes are connected to data, sometimes dynamically.

Each recipe presents as a set of sections: the title, Getting ready, How to do it…, How it works…, There’s more…, and See also. Besides the inconsistent use of ellipsis, the title section (which describes the need) is often perfunctory and sometimes omits a picture of the finished graph or chart (i.e. the tempting photo of the finished dish). While some How it works… sections show additional (but too few) images, a graphics book should err on their side of too many images, and certainly should always have one as part of the recipe’s description.

Within sections, some of the recipes do built on the previous one a bit: graphic enhancements, adding different data sources, or using a more complex representations. The sections cover

  • Drawing with the core ActionScript objects
  • Representing sets of data in graphs
  • Bar charts (using Adobe’s Data Visualization library)
  • Advanced charts without the Data Visualization library
  • Charting Data on Maps
  • Animation and Zooming in on Data
  • Showing Network Data Relationships Graphically
  • Rotatable 3-D Charts and Data Landscapes

The book is available in Kindle and paperback editions as well as PDF, mobi, and epub direct from the publisher. The PDF seems to be images of the pages, not text (no copy-and-paste, no external links, and no links from the table of contents). It is also available on-line from the publisher’s site once purchased. The HTML presentation, often being very wide, actually makes the chapters easier to read than the book format: the code does not need to wrap; the images are visible on the same “page” as the rest of the recipe, and the links work.

Some recipes need to import data from files or web services and include code and discussion to do so; these pedestrian routines (and some entire recipes!) distract from the topic of graphic functionality; perhaps they could have been relegated to an appendix. Some recipes, perhaps acknowledging that supporting code is large and tedious, direct the user to download files from the Packt Publishing website and “… follow along”.  The index is 12 pages long; very respectable for a 280 page book.

For its niche, it is likely the definitive reference. It does not address the relative merits of using a well-known charting library vs. using trigonometric functions and low-level drawing functions; clearly these include abstraction and performance. Cookbooks don’t offer a questionnaire; they just tell you how to make a great souffle  Joe Bob says: check it out.

The Only Good Comment Is a Useful Comment

I’ve talked about comments in The Zen of Comments, but the rising tide of ASDocs (and JDoc, etc.) brings this home: requiring comments is as pointless as requiring lines-of-code or a minimum number of check-ins. The existence of comments adds nothing to source code; they make it harder to see the code itself and are often out of date.

/**
* this is the current record id
*/
public var currentRecordId : String ="";

/**
* handle search button click
*
* @param event the mouse event from the click
*/
private function searchButtonClickHandler(event : MouseEvent) : void
{
   ...
}

/**
* @return Foo
*/
public function get foo() : Foo
{
    return _foo;
}
/** TODO: fix this
*/
public function clearGlobalList() : void
{
    this.globalList.removeAll();
}
/**
* @param control int
* @param clearAll delete extra items
*
* @return the number of deleted items
*/
public function truncateData(maximumCount : Number) : void
{
    ...
}

A bad comment is worse than no comment. The goal is to add information to the source code, nor obsolete noise, and the best way is to name the variables, objects, and methods so they are self-descriptive. As you can see from the examples above, adding ASDoc headers makes the code less readable, and the names of the variables and functions already completely describe their behavior.

Good Nomenclature is the Best Comment

or

“The proper use of comments is to compensate for our failure to express ourselves in code.” — Robert C. Martin

“If the code and the comments disagree, then both are probably wrong” –attributed to Norm Schryer

“Good code is its own best documentation. As you’re about to add a comment, ask yourself, ‘How can I improve the code so that this comment isn’t needed? ‘ Improve the code and then document it to make it even clearer” –Steve McConnell Code Complete

I’m not advocating Hungarian notation. The need to use short variable names has long past, and abbreviating types is more than silly. Perhaps it is a dogged remnant of my sordid past in Pascal: I like complete, explicit names.

  • Class names should be specific nouns and avoid words that have meanings in the context of programming (we are running out of terms for “object”!). For example,
  • Method names should start with a verb (“open”, “delete”, “calculate”) and contain the names of the classes they are going to act on, e.g. importDetail(aDetail : Detail) : void
  • Property and field names should not include their class name (no Client.clientName) unless necessary to differentiate it within the context of the class (Client.clientName and Client.accountName).

Sample Naming Patterns

  • function findFoo(criteria) : Foo returns a Foo or null/-1/empty string if not found. I use an “a” prefix on my parameters to differentiate them from local variables and class fields/properties
  • function getFoo(criteria) : Foo returns a Foo or throws an exception if not found
  • function createFoo(initial data) : Foo returns a new Foo and adds it to the list/collection/model. Throws an exception if the Foo cannot be created (e.g. the key data already exists)
  • function openFoo(initial data) : Foo returns an existing Foo that matches the data or returns a new Foo and adds it to the list/collection/model
  • function removeFoo(aFoo) : Boolean returns true if aFoo was remove and false if aFoo was not present to remove. throws an exception is aFoo was there but the method could, for some reason, not remove it
  • function calculateTotal(fooArray : Array) : Number returns a value based on the parameter. The name indicates that the result is a dynamic value that is not stored persistently and is not based on anything else
  • function composeErrorMessage(error : Error, data : Foo, user : User) : String returns text value based on the parameters. The name indicates that the result is a dynamic value that is not stored persistently and is not based on anything else
  • class DeletionConfirmationView (not DeleteView or event DeleteConfirmationView). “Delete” is a verb and indicates a function (which is going to delete something). The view is going to present a confirmation dialog for the deletion (the noun form of “delete”).
  • function foo(param : type, pleaseDoSomething : Boolean) : void The second parameter is asking the method to do something like delete child objects, suppress notifications. The please makes it clear that it is a parameter, not a field or property of the object. Calling it doSomething or even isDoSomething does not make it clear that it is a parameter

Some bad examples from the Flex framework itself:

  • property includeInLayout, visible, includeInLayout - it should be “isIncludedInLayout”.
  • properties visible and enabled are at least adjectives, not verbs.
Other bad examples
  • property countFavorites - it should be favoritesCount. The function that calculates the value might be called “countFavorites()”

An excellent book referencing the code aesthetics of various luminaries is Clean Code, Robert C. Martin, Prentice Hall 2009, ISBN 0-13-235088-2

There, There, and Everywhere

While Flash is a full participant in the world and idioms of the web, Flex is more attuned to applications (e.g.  full-screen) rather than as part of a larger web page. I come from a traditional applications development (sometimes I say that I don’t do dancing kitties”). When Adobe made the AIR runtime for the major desktops, I felt like I was home. Just as Flex and Flash allow one to Write Once, Browse Everywhere, AIR allows us to write applications that behave the same (mostly) whether running off a browser or on a desktop1.

AIR is a desktop runtime container that executes swf applications2 stored on a local drive rather than receiving the swf as part of a web page in a browser. It’s runtime library supports several classes that the Flash Player runtime library does not, specifically ones dealing with local file selection and management, HTML display, windowing, and native chrome (menus, window widgets, etc). AIR also includes installation and update protocols useful for desktop applications, which include an application profile specifying who distributed  it (i.e. who digitally signed it) and if it will modify local files, access local resources like web cams, etc. The AIR runtime will enforce these limitations (just as the Flash Player limits its swf’s’ access to servers based on the server’s crossdomain.xml file).

Even with the new ability to package, install, and execute native code modules, AIR is not designed to build low-level system tools for the desktop. It is designed to present the same sort of rich application that the Flash Player presents on the browser. These application present data in interesting ways. They connect different services together (e.g. Twitter and Google Maps). They connect to private servers and databases.

Why AIR?

We want to offer an AIR version of our applications because of the things they will notice: They will notice if your web application does not have an internet connection. The will notice if they have to browse to every file instead of dragging it. They will notice that your application reminder makes a new tab in their browser instead of a toaster message onto their desktop.

The key to offering the same application on both the Flash Player and the AIR desktop is more than reuse the same pieces; the key is to “reuse” the whole thing.

To do this, create an AIR project and a Web (Flash Player) project (e.g. DoSomthingAIR and DoSomethingWeb). Both will have just the top-level application MXML file and an implementation of IFilesManager appropriate to that environment. The majority of the application is in a core component in a DoSomethingLibrary project. It  has all the data connections and UI of the application. It can use local storage3 to keep non-confidential default settings (and even share them between the Flash Player and AIR applications on the same machine).

The only parts of the application specific to AIR or the Flash Player are:

  • Native drag and drop messages are ignored in the player (but they generate standard drag & drop messages)
  • System connectivity messages (AIR only)
  • User inactivity messages (AIR only)
  • File access operations (AIR only)

If the core application component is listening for AIR-only events, it will still run well in the Flash Player (although it will never hear those events). To handle the differences with file access operations, for example, one can create an Interface that hides the details and have an implementation class for each platform (see AIRFileManager and FlashFilesManager in Figure 1). Each application can instantiate the appropriate instance and assign it to a property of the core application component or of some common static class. The core application calls methods of that property (which is typed to the Instance) oblivious to which platform’s class is doing the work.

Converting an Existing Application

One might have an application complete or near complete before one considers a dual platform deployment.It’s easy to break the core application out so both runtime platforms can use it.

  1. Open the existing project
  2. Create a new Library project
  3. Add any swc libraries (e.g. flexlib, a3corelib) that the existing project to the new Library project. You can move any swc’s from the original project’s lib/ to the new Library project’s lib/ as well
  4. Drag the src/com/company/stuff directories from the original project down to the Libraryproject src/. You want it to move, not copy.
  5. Open the project’s main MXML file and copy everything to the clipboard
  6. In the new Library project, create a new MXML component based on Canvas in the new library project. Call it “CoreApplication”
  7. In the new CoreApplication component, paste the clipboard under the <Canvas> element of the new element and remove the <Application> elements and any attributes that apply directly to the application itself.
  8. Same and build the new library project and fix any references.
  9. Add the library project to the existingproject’s Build Path. If you add the whole project instead of just the swc reference, debugging is easy
  10. In the existing project’s main MXML file, remove everything except the <Application> elements and those properties that apply only to the application itself (e.g. viewSourceURL)
  11. In Design Mode, add an instance of the new CoreApplication component from the Custom branch of the component tree. Set the bounds to: 0, 0, 100%, 100%
  12. Build the original application again. It should work exactly the same.

Now you can create a new project for the other runtime platform (e.g. AIR) and put a CoreApplication component in it as well.

Two-For-One Is Enough

This technique allows us to deliver the same application via a browser or a desktop; it does not magically change the application. Mobile applications are fundamentally different in their presentation and flows; although the delivery mechanisms (AIR and the Flash Player) might be the same, do not try to leverage any non-trivial application’s UI into a very different environment. For this, we do need to design the parts of the application for individual reuse in a new application designed for one or more mobile environments.


If you are new to AIR, a good intermediate book is:

Adobe AIR in Action, Lott, Joseph; Rotondo, Kathryn; Ahn, Samuel; Atkins, Ashley, Manning 2009


1Windows, Mac, and Linux desktops
2As well as HTML and JavaScript
3using the SharedObject class

Telescope to Hell, or An ActionScript Builder Pattern

One of the evils that OOP freed us from was long parameter lists like this:

wm_op(hdl, 0, 0 , 230, false, false, "false", true, ptr.value)

Even with default parameters and the occasional enumeration, telescoping parameter lists like these are chronic bugs waiting to happen and to regress. The problem was that call was not self-explanatory. Using object properties allows us to see each property’s name as we assign it:

var processor : Processor = new Processor(this);
processor.x = 0;
processor.y = 0;
processor.minHeight = 230;
processor.buttonText = "false";
processor.initialValue = pointer.value;

Instead of entering dummy arguments to allow access to later parameters, the object sets its own defaults.

Every Value a Parameter

The Every-Value-A-Parameter (EVAP) style of constructor design seems to forgo much of the strength of objects. It treats objects as data structures and does not take advantage of their properties’ ability to be internally consistent. The EVAP style passes all the internal values of the object in the constructor’s parameters, and all properties are read-only from that point forward (i.e. an immutable object).

If several parameters in a long list interact with each other or are mutually exclusive, either the constructor fails to create the object (often an opaque exception) or we do not check the interaction until needed (e.g. until a query object was activated). We cannot validate the parameters one-by-one because they all come in at once.

The calling code must also have all the information about the object at once.

var foo : Foo;
if (ref.gah &gt;= 14)
   foo = new Foo(this, ref.gah, null, (container == null) ? null : container.bar);
else
    foo = new Foo(this, 2, null, (container == null) ? null : container.bar);

As shown, a symptom of  EVAP is a mass of trinary expressions (exp ? true : false)  in call parameters, or branches with alternate initializers for the same object. If one could set the new object’s attributes explicitly and individually (i.e. after it was instantiated), then the code branches would be specific to the attributes they affect.

var foo : Foo = new Foo (this);  
 
if (ref.gah &gt; 14)
   foo.gah = ref.gah;
else
   foo.gah = 2;
 
if (container != null)
   foo.bar = container.bar;

A subtler aspect is the ability to allow descendant classes, containers, or helpers to override an object’s configuration. For example, a base query object might have a base query string, but a descendant class or a wrapper class, OracleSQLQuery, might take advantage of Oracle-specific syntax or settings. If the query string must be a read-only constructor parameter, the descendant cannot override an contained object created by its ancestor; at best, it can create a new object, copy every other attribute value, and assign it to a protected reference that the ancestor will (we hope) use.

Special Mutators for Mutually Dependent Properties

Some parameters’ validity depends on other parameters (e.g. height and minHeight). An object can adjust one to fit another, but this can violate a  object’s agreement with the user: a writable parameter value will be what the user set it to.

form.height = 95;
form.minHeight = 80;
...
form.height = 75;
form.minHeight = 70;

If the object unilaterally and silently changes the second value for height to 80 (the minimum), the coder will expect it to be 75. If the object rejected the assignment because it (at the time) violated the minHeight value, then the object will remain internally consistent.
Some properties are mutually dependent, so it is more than a matter of the sequence of assignment. If the object cannot defer the dependency validation (see below), then it can offer a special mutator-like function that accepts both or all of the mutually dependent values at once. Two or three parameters are not too obtuse, especially if the function names them explicitly.

foo.setNameAndPassword(...)
foo.setPosition(x, y);

Deferred or Explicit Validation

A SQLQuery object can allow any value for its queryText and parameters properties until the moment its active property turns true. At that moment, all of the properties must be consistent with each other (i.e. the items in the parameters collection must match the references in the queryText). If something tries to change one of these values in an active query, the object must decide whether to set active to false or to reject the new value (e.g. by throwing an exception).

Another example might be a class URIString, which does not check for validity until something calls function isValid(). The user can set and clear different, mutually-exclusive parts of a URI without raising an exception because their interrelations don’t matter until the validation method runs.


Jeffrey Stylos and Steven Clarke: “Usability Implications of Requiring Parameters in Objects’ Constructors.”ICSE 2007.

Immutable Objects and Internal Consistency

Nevertheless, some objects really want to be immutable. It saves a lot of checking and binding events, allows static caching, and removes the need for a .copy() or .clone() method.

The best of both wolds is an immutable object with a (mutable) builder. The builder object takes all of the initial values as interactive, public properties, optionally validates those values when they are set or just before the builder becomes the immutable constructor’s sole parameter. One might use it like this:

    var builder : Object = ImmutableObject.createBuilder();
    builder.name = "Fred";
    builder.birthMonth = 4;
    builder.birthYear = 1960;
 
    var imm : ImmutableObject = builder.create();

The immutable class and the builder class work together:

  1. The class’ static function returns an instance of the builder class
  2. The consumer plays with the builder’s properties
  3. The consumer has the builder create an instance of the class
  4. The builder validates its properties
  5. The builder passes itself to the class’ constructor
  6. The class initializes its immutable properties (i.e. the private fields) from the builder’s properties
  7. The builder passes the new class instance to the consumer

Instead of creating a public builder class for each immutable class and ending up with lots of little class files, we can use an internal class with some casting. Note that while the client code does not have access to the ImmutableObjectBuilder class, it gets an instance of that class (into its Object-type variable), and it cannot treat it like a generic object (e.g. builder.height = 44; gives an error).

public class ImmutableObject
{
    public function ImmutableObject(builder : Object)
    {
        if (builder is ImmutableObjectBuilder)
        {
            builder.validate();
 
            initialize(ImmutableObjectBuilder(builder));
        }
        else
            throw new Error("use ImmutableObject.createBuilder().create()");
    }
 
    private function initialize(builder : ImmutableObjectBuilder) : void
    {
        _name = builder.name;
        _address = builder.address;
        _birthDate = new Date(builder.birthYear, builder.birthMonth);
        _photoUrl = builder.photoUrl;
    }
 
    public static function createBuilder() : ImmutableObjectBuilder
    {
        return new ImmutableObjectBuilder();
    }
 
    public function get name() : String
    {
        return _name;
    }
    private var _name : String = "";
 
    public function get address() : String
    {
        return _address;
    }
    private var _address : String = "";
 
    public function get birthDate() : Date
    {
        return _birthDate;
    }
    private var _birthDate : Date;
 
    public function get photoUrl() : String
    {
        return _photoUrl;
    }
    private var _photoUrl : String = null;
}
 
class ImmutableObjectBuilder
{
    public var name : String = "";
    public var address : String = "";
    public var birthMonth : int;
    public var birthYear : int;
    public var photoUrl : String = null;
 
    public function validate() : void
    {
        if ((name == null) || (StringUtil.trim(name) == ""))
            throw new Error("\"name\" is required");
 
        if ((birthMonth == 0) != (birthYear == 0))
            throw new Error("Both birthMonth and birthYear must be set");
    }
 
    public function create() : ImmutableObject
    {
        return new ImmutableObject(this);
    }
}

The downside to this pattern is that it is a little tricky to subclass.

Using the ImmutableObject shown above, the descendant class has to get an instance of the ancestor’s builder and give that reference to its builder. The descendant builder cannot descend from the ancestor build because they are both internal classes.

The descendant builder has to proxy or shadow all of the ancestor builder’s properties so the descendant builder can use its reference to the ancestor builder to initialize the ancestor part of the descendant instance. I said it was a little tricky.

In this example, the descendant builder proxies properties (e.g. name, address) to the ancestor builder’s properties, and adds one new one: role.

public class Descendant extends ImmutableObject
{
    public function Descendant(builder : Object)
    {
       if (builder is DescendantBuilder)
       {
           builder.validate();
 
                   // this calls the ancestor's initialize()
           super(builder.ancestorBuilder); 
 
                 // we have to cast because the parameter 
                 // cannot be the internal class DescendantBuilder
           initialize(DescendantBuilder(builder));  
        }
        else
            throw new Error("use Descendant.createBuilder().create()");
    }
 
    public function get role() : String
    {
        return _role;
    }
    private var _role : String;
 
    //  we can't virtualize this method because
    //     we won't have access to the AncestorBuilder
    private function initialize(builder : DescendantBuilder) : void
    {
        _role = builder.role;
    }
 
    //      static methods are not inherited, so we do not override
    public static function createBuilder() : DescendantBuilder
    {
        var ancestorClassName : String = getQualifiedSuperclassName(Descendant);
        var ancestorClass : Class = Class(getDefinitionByName(ancestorClassName));
        var ancestorBuilder : Object = ancestorClass.createBuilder();
 
        return new DescendantBuilder(ancestorBuilder);
    }
}
 
class DescendantBuilder
{
    public function DescendantBuilder(ancestorBuilder : Object)
    {
        _ancestorBuilder = ancestorBuilder;
    }
 
    public function get ancestorBuilder() : Object
    {
        return _ancestorBuilder;
    }
    private var _ancestorBuilder : Object;
 
    public function get name() : String
    {
        return _ancestorBuilder.name;    //    proxy
    }
 
    public function set name(value : String) : void
    {
        _ancestorBuilder.name = value;
    }
 
    public function get address() : String
    {
        return _ancestorBuilder.address;    //    proxy
    }
 
    public function set address(value : String) : void
    {
        _ancestorBuilder.name = value;
    }
 
    public function get birthMonth() : int
    {
        return _ancestorBuilder.birthMonth;    //    proxy
    }
 
    public function set birthMonth(value : int) : void
    {
        _ancestorBuilder.birthMonth = value;
    }
 
    public function get birthYear() : int
    {
        return _ancestorBuilder.birthYear;    //    proxy
    }
 
    public function set birthYear(value : int) : void
    {
        _ancestorBuilder.birthYear = value;
    }
 
    public var role : String = null;    //    NOT a proxy
 
    public function validate() : void
    {
        _ancestorBuilder.validate();
 
        if ((role == null) || (StringUtil.trim(role) == ""))
            throw new Error("\"role\" is required");
    }
 
    public function create() : Descendant
    {
        return new Descendant(this);
    }
}

And the obligatory sequence diagram: 

Lazy, Asynchronous Binding, or Call Once, Return Twice

The best part of binding is that it just works: your visible control (the target) gets the data (the source) to show without worrying about synchronizing it with the various steps of data retrieval.

“Getting the value” means retrieving a field, function, or accessor of an object. The target will always get the value when it is initialized in the Configuration phase (so const values work as binding sources even without the [Bindable] metatag).

The Bindable Mantra

“Hear the event, get the value”

The important and subtle implication of this is that the notification dispatcher and the (presumably changed) data are not necessarily the same thing. The normal and default behavior is that changing a value will dispatch an event to the targets bound to that value. This is the built-in behavior when properties use the [Bindable] metatag without specifying an event type; the compiler creates hidden accessors and mutators that checks for changed values (optimizing by ignoring new values that are the same as the old value) and dispatches a PROPERTY_CHANGED event.

The things that bind to the bindable property get a hidden event listener that listens for the PROPERTY_CHANGED event and assigns the source to the target whenever the listener gets an event.

Simple Binding

Target Object: a form

<Application />
    <s:List dataProvider="{foo.listData}" />
</Application>

Source Object: a data class (e.g. a model)

class Foo extends EventDispatcher
{
    [Bindable]
    public var listData : ICollection;
}

Specified Event Binding:[Bindable("foo")]

If the [Bindable] metatag specifies an event type (e.g [Bindable("event type")], then the compiler does not create hidden accessors and mutators for the property; the class must dispatch a notification event itself. One can use this to make non-accessor functions bindable: the hidden event listeners created for the targets will call the function whenever they hear the event and assign the result to the target.

A class can have many properties marked as [Bindable("foo")], and whenever it dispatches new Event("foo"), everything bound to any of those properties will retrieve the data value immediately.

Target Object: a form

<Application />
<!--   call get listData() on initialization and whenever "listDataChange" heard  -->
    <s:List dataProvider="{foo.listData}" />

<!--   call get listCount() on initialization and whenever "listDataChange" heard  -->
    <s:Label text="{foo.getListCount().toString()}" />   
</Application>

Source Object: a data class (e.g. a model)

class Foo extends EventDispatcher
{
    public static const LIST_DATA_CHANGE : String = "listDataChange";
    public static const TOTAL_COUNT_CHANGE : String = "totalCountChange";

    [Bindable("listDataChange")]
    public function get listData() : ICollection
    {
        return _listData;
    }

    public function setListData(value : ICollection) : void
    {
        if (_listData != value)
        {
            _listData = value;
            dispatchEvent(new Event(LIST_DATA_CHANGE));
        }
    }

    [Bindable("listDataChange")]
    public function getListCount() : int
    {
        if (_listData == null)
            return 0;
        else
            return _listData.length;
    }

    [Bindable("listDataChange")]
    [Bindable("totalCountChange")]    // something else dispatches this event
    public function totalCount() : int
    {
        return getListCount() + someOtherNumber;
    }
}

The Cool Bit

Because the notification can be separate from the actual data, one can return result asynchronously to a bound listener. This might be called the Data Accessor Object Pattern.

1. The target calls the source accessor
2. If the underlying object is uninitialized or stale

a. The accessor immediately returns null(which is a perfectly reasonable return value)

b. The accessor sends a request to a server

c. When the server returns data, the responder dispatches the binding event

d. The target hears the binding event and calls the accessor

3. The accessor returns the new data

Target Object: a form

<Application />
 <!--  call get listData() on initialization and whenever "listDataChange" heard -->
    <s:List dataProvider="{foo.listData}" />  
</Application>

Source Object: a data class (e.g. a model)

class Foo extends EventDispatcher
{
    public static const LIST_DATA_CHANGE : String = "listDataChange";

    [Bindable("listDataChange")]
    public function get listData() : ICollection
    {
        if (_listData == null)
        {
            var serverCall = new ServerCall(receiveListData);

            //  return null immediately; don't wait for the server
        }

        return _listData;
    }

    public function receiveListData(data : ICollection) : void
    {
        if (_listData != data)
        {
            _listData = data;

                     // make the bound targets call listData() AGAIN
            dispatchEvent(new Event(LIST_DATA_CHANGE));
        }
    }
}

… Only one, but the Collection has to want to change

Using an ArrayCollection as the data provider for a list (or any display object) is easy and powerful. Somehow, collection variables fire change events and update their binding targets not only when the whole list variable changes, but also when any element in that list changes. Lists and Grids (which love ArrayCollections) explicitly listen for COLLECTION_CHANGE events from inside their dataProvider as well as wholesale changes.

Note that only the dataProvider seems to do this: binding an ArrayCollection to any other property will not automatically get notifications when a collection item changes (although binding to arrayCollection.length will). If you use BindingUtils or variable injection to a mutator, it will only get updated when the whole value changes, not when an item changes.

Given that the elements know nothing about the Collection containing them (indeed, an object can be contained by several Collections and Arrays simultaneously), and the Collection cannot require that elements descend from some sort of CollectionItem ancestor, or implement a specific ICollectionItem interface, or even call a method in the Collection when they change, the only way the Collection can monitor elements is if it takes advantage of a protocol that most objects do anyway: the Bindable/PROPERTY_CHANGE event.

The ArrayCollection does not, despite appearances, wrap an Array; it wraps an ArrayList that wraps an Array. The ArrayList monitors every element in its array by adding a listener for PropertyChangeEvent.PROPERTY_CHANGE events on every array element that happens to implement the IEventDispatcher interface. A listener can listen for any type of event it wants to without being dependent on the event dispatcher; they are loosely coupled. As it happens, any class with a [Bindable] property is automatically an IEventDispatcher, and it dispatches the PROPERTY_CHANGE event every time a [Bindable] property changes. The class can also dispatch this event explicitly.

The ArrayList listens for these events and dispatches a COLLECTION_CHANGE event summarizing and describing the changes to the Array’s items. The ArrayCollection uses this event from the ArrayList to gather information for its own COLLECTION_CHANGE event, and the List or Grid uses the COLLECTION_CHANGE event to refresh or rebuild their ItemRenderers.

To be clear: array element objects fire PROPERTY_CHANGE events automatically for every change to their [Bindable] properties. If you want properties that are not bound or are bound to explicit event ([Bindable("readOnlyPropertyChange")]) to trigger COLLECTION_CHANGE events in the collections that hold them, those property mutators have to explicitly fire the PROPERTY_CHANGE event (in addition to any other events they dispatch).

[Bindable]
public function get foo() : String
{
    return _foo;
}
public function set foo(value : String) : void
{
    _foo = value;
}

[Bindable("readOnlyPropertyChange")]
public function get readOnlyProperty() : int
{
    return _readOnlyProperty;
}

public function clearBar() : void
{
    var oldValue : String = _readOnlyProperty;
    _readOnlyProperty = 0;

//    signal for binding/listeners directly on this object
    this.dispatchEvent(new Event("readOnlyPropertyChange"));

//    signal for binding/listeners on this object's Collection
    if (hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE ))
    {
        var event : PropertyChangeEvent =
                PropertyChangeEvent.createUpdateEvent( this, "property", oldValue, 0);
        dispatchEvent( event );
    }
}

Arrays do not detect or fire events; they are just a collection of items.

Sequence diagram of the events between Lists, ArrayCollections, ArrayLists, Arrays, and the items in Arrays

Sequence diagram of the events between Lists, ArrayCollections, ArrayLists, Arrays, and the items in Arrays

The Dark World of IExternizable

I never worked with Remote Objects much; I stuck with SOAP, REST., and AMF. What I did learn was how custom objects can represent themselves to an AMF stream, and to local-storage SharedObjects and fileStreams too.

ActionScript has built-in serialization (compatible with java.io.Externalizable interface). While this is very obvious streaming data over AMF pipelines (to LCDS, AMFPHP, Zend, etc.), it quietly makes saving and restoring data pretty painless. These operations use the streaming protocol:

  • RemoteObjects
  • Streaming objects to ByteArray.writeObject()
  • SharedObject (local storage)
  • EncryptedSharedObject

Simple Streaming

Most values and object will stream to and from AMF just fine. To effect this simple protocol, put the [RemoteClass("com.company.application.section.ClassName")] metadata tag (Flex projects only) above the class declaration so the parser knows what class to create. The class constructor must have defaults for all its arguments (or no arguments), and all public properties must writable (i.e. they must be vars or have mutators — aka “setters”).

The streamed properties that are the ones that are public var or have both a public accessor and a mutator. If a class has public properties one does not wish to stream, mark those properies with the [Transient] metadata tag.

[RemoteClass("com.company.application.section.Foo")]
public class Foo 

    public var name : String = "";
    public var id : String = "";

    [Transient]
    public var contact : Contact = null;
}

The streaming system streams and object in by creating a new instance and then setting each property in turn (it will not use the constructor’s parameters).

Streaming Read-Only and Private Properties

If some properties don’t have public mutators (i.e. they are publicly read-only), or one wants to stream non-public attributes, one can write custom serializing and de-serializing routines by implementing the interface IExternizable. It requires two methods:

[RemoteClass("com.company.application.section.Foo")]
public class Foo implements IExternizable
{
    public var name : String  = "";

    public function get id() : String
    {
        return _id;
    }
    private var _id : String = "";

    public function readExternal(input : IDataInput) : void
    {
        name = input.readObject() as String;
        _id = input.readUnsignedInt();

                // this object might need to be IExternizable too
        _contact = input.readObject() as Contact;
    }
    public function writeExternal(output : IDataOutput) : void
    {
        output.writeObject(name);   //  same sequence as readExternal()
        output.writeUnsignedInt(_id);
        output.writeObject(_contact);
    }
}

The IDataInput has no information about its data, so one cannot, for example, test to see if an integer value is less than 127 and safely call writeByte() instead of writeInt() (to save space) because readExternal() has no way of knowing if it should call readByte() or readInt(). One can stream format and version information out first, and use that information to determine the format of the rest of the data when streaming it in (although this smacks of variable record types from Days Long Past). It’s much easier to always stream the same object types in the same sequence, even writing out some empty strings and nulls as placeholders when necessary.

Any class implementing IExternizable must explicitly stream all its data because the built-in streaming is disabled . Note that the example above will stream the entire nested _contact object out as part of the Foo object stream. If  Contact implemented IExternizable, it’s readExternal() and writeExternal() would handle its streaming too.

Streaming References

If a class contains a references to another object, one can stream out an id and resolve the id after it streams in. One can resolve that id into an object reference either explicitly when both the referer and the cross-reference (e.g. the list of all Contacts) are ready, or do it as a lazy-loading accessor:

[RemoteClass("com.company.application.section.Foo")]
public class Foo implements IExternizable
{
    public var name : String  = "";

    public function get id() : String
    {
        return _id;
    }
    private var _id : String = "";

    public function get contact() : Contact
    {
        if (_contact == null)
        {
            if (_contactId != "")
            {
//
// some mechanism to find the contact by Id; it can return null
//
                _contact = Contact.lookupId(_contactId);
                _contactId = "";
            }
        }

        return _contact;
    }
    private var _contact : Contact = null;
    private var _contactId : String = "";

    public function readExternal(input : IDataInput) : void
    {
        name = input.readObject() as String;
        _id = input.readInt();
        _contactId = input.readObject() as String;
    }

    public function writeExternal(output : IDataOutput) : void
    {
         output.writeObject(name); // same sequence as readExternal()
         output.writeInt(_id);

         if (_contact == null)
            output.writeObject(""); // placeholder
        else
            output.writeObject(_contact.Id);   // just the Id
    }
}

Adding IExternizable to Existing Objects

If you add IExternizable to an object that has been saved and will be retrieved, you need to read the stream in the same sequence (and don’t fail if some new property is not in the stream). You can determine the sequence of properties before adding the writeExternal() by creating mutators for all the public properties, and then debugging while an instance comes in.

See Adobe Documentation on IExternizable

All AIR Applications Are Single-Instance

This is not an option: if one tries to launch an AIR application twice, the first instance remains and no other instances start. The first application, however, does get notification and the command-line arguments of the subsequent application executions. It’s a subtle way of communicating with a running AIR application.

If an application has to handle multiple instanciation (like a registered file reader), it has to be able to present multiple instances of some part of its user interface (or be willing to replace the current data at any time). This hearkens back to the days of Multi-Document Interface (MDI) applications. One can encapsulate the main UI as a component, and the application can create one for each “instance” the application needs to present.

Multiple Invocations of an AIR ApplicationThe NativeWindow.invoke Event Fires On Every Application Launch

The application will get an event every time the OS launches an instance of the application. It gets an event on startup, and it gets one each time the OS executes the AIR application file; subsequent executions do not start additional  instances. These events contains the command-line parameters specific to that invocation.

The Invoke event fits into the startup cycle here:

  1. FlexEvent.ADD for the application object
  2. FlexEvent.PREINITIALIZE
  3. Event.ADDED for the descendents of the application object
    (These events happen sporadically intermixed with the following events)
  4. FlexEvent.INITIALIZE
  5. FlexEvent.CREATION_COMPLETE
  6. Event.ADDED_TO_STAGE
  7. FlexEvent.APPLICATION_COMPLETE
  8. InvokeEvent.INVOKE
  9. Event.ACTIVATE

Command-line Parameters in AIR Applications

First, the simple behavior:

<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark" 
    xmlns:mx="library://ns.adobe.com/flex/mx"
    invoke="onInvoke(event)">
    <fx:Script>
        <![CDATA[
            private function onInvoke(event : InvokeEvent) : void
            {
                logText.text += "invoke: event.arguments = " + 
                    event.arguments.toString();

                if (event.currentDirectory != null) {
                    logText.text += "; event.currentDirectory = " + 
                        event.currentDirectory.nativePath;
                }
                else
                    logText.text += "; event.currentDirectory = null";


                if (event.reason != null)
                    logText.text += "; event.reason = " + event.reason;
                else
                    logText.text += "; event.reason =  null";
            }
        ]]>
    </fx:Script>

    <s:TextArea id="logText" left="10" right="10" top="105" bottom="10" />
</s:WindowedApplication>

 

Things My Event Told Me

  • InvokeEvent.arguments is an array (never null) of strings. See your operating system for the rules about special characters and quoting.
  • InvokeEvent.currentDirectory is a File instance set to the directory of the executable. Note that running from the IDE will point to the FlashBuilder.exe directory; running from a shortcut/alias will indicate the location of the shortcut, not the .air file.
  • InvokeEvent.reason is either “standard” or “login” if the  OS starts it automatically (see InvokeEventReason for constants)

Things My Event Never Told Me

  • The event does not indicate if this event is part of the application startup (i.e. the first event) or a subsequent invocation. Use a global counter.
  • The event does not indicate if this event is because the OS registered this application for a file type and the user “opened” a file of that type. The sole argument is the complete (native) path including file name, but shortcuts and the command-line can start the application can have a single argument that is a file path as well.

 

It’s an Interface; It’s a Code-Behind; It’s a … Skin?

I managed to avoid skinning components in Flex 3 (I called it “dancing kitties”). I just made the components work. I tried to ignore the changes in Flex 4 skins, but Spark components are very different than MX components, although Adobe has succeeded in making the changes apparently minor.

In Flex 2 and 3, “skins” were CSS styles and images and, rarely, bits of code that created graphics.

What Flex 4 Skins Are

Flex 4 skins are ActionScript classes that are completely responsible for presenting the data from another ActionScript class.  Custom components can inherent behavior from their class ancestors (UIComponent, Group, etc.), but builds their appearance by choosing or creating a custom skin class. The component has the properties and methods to manage the component’s behavior and data, and the skin class presents it to the user. A skin class usually descends from the ancestor class Skin (itself a child of Group) and contains other components (e.g. Labels, Images, RichTextEdit) to display and gather data, (somewhat like the way a custom item-renderer contains other components). The nesting can seem a little recursive, but it has the same advantages as any other object oriented protocol: each object does its thing with loose linkages to other objects.

It’s Code-Behind

The relationship between a component and its skin is like a code-behind pattern: specified component class variables refer to the skin class’ sub-components by name. As the skin class constructs, it passes each of its sub-compents (e.g. Buttons) to the host component. The host component does two things: first, if it finds a variable annotated with a [SkinPart], it assigns the instance to the value from the skin. Second, it calls the addPart() method so the component can add event listeners, etc. For example, if a skin class used with a Button has a sub-component with the id “labelDisplay”, that sub-component’s “text” property will get the Button.label value via the ButtonBase.setContent() method:

The Component The Skin
[SkinPart(required="false")]
public var labelDisplay : IDisplayText;   // must have a .text property
<s:Label id="labelDisplay" />
protected function setContent(value : String) : void
{
    _content = value;  //    this stores the value in the component

    if (labelDisplay != null)  // it's not required, so it could be null
        labelDisplay.text = value;
}
The Label component displays the new value

It’s an interface

And I mean with a lower-case “i”: it’s is not an ActionScript Interface It is an agreement between the component and the skin so they can work together (actually, the component requires and the skin fulfills):

  • [SkinPart(required="true")] or [SkinPart]on the component requires the skin to have a sub-component with a specific name; the class will throw an exception during creation without it
  • [SkinPart(required="false")] on the component will connect to a skin’s sub-component with a specific name if it’s present

It’s a View

So skins have evolved from being styles and bitmaps to more of a MVC-type view, and the component acts as a controller and model. The component keeps a copy of all the visible data (like label texts) so it can change and initialize skins at any time. When a skin initializes, the component gets a notification for each sub-component of the skin object, and the component can add an event listener or set its value. While the component can query the skin about constraint-based position and sizes, the less the component knows about the view, the better.

Likewise, the less the skin knows about the component, the better. The component handles all the interaction with the outside world: methods to set and filter the data, validation of property values, etc. The skin gets data values and occasionally styles and top-level dimensions. The component uses its code-behind references directly to the skin’s sub-components to set property values and get events.

Binding Optional

While binding is very cool, this protocol does not usually use events and watchers and binding stuff: the code in the component explicitly assigns values to its references of the skin’s sub-components (e.g. SkinnableTextBase.setPrompt()). The skin can bind to the component’s properties (e.g. hostComponent.title), but it’s unusual.

The Component’s View of the Skin

These are the states, properties, and methods of the component that give it access to and control over the skin.

skin class
(will inherit from ancestor classes)
.skinClass
required skin states [SkinState("xxx")]
skin sub-components
[SkinPart(required="true")]
public var closeIcon : Button;

[SkinPart(required="false")]
public var labelDisplay : IDisplayText;   // must have a .text property
add/remove event listeners to skin objects
override protected function partAdded(partName : String, instance : Object) : void
{
    super.partAdded(partName,instance);
    if (instance == closeIcon)
    {
        closeIcon.addEventListener(MouseEvent.CLICK, onCloseIcon);
        closeIcon.source = getStyle(“icon”);
    }
}

override protected function partRemoved(partName : String, instance:Object) : void
{
    super.partRemoved(partName, instance);

    if (instance == closeIcon)
        closeIcon.removeEventListener(MouseEvent.CLICK, onCloseIcon);
}
skin instance
(rarely used)
.skin
supporting methods
SkinnableComponent.invalidateSkinState();
// this forces a call to getCurrentSkinState()
other miscellaneous overrides
override protected function getCurrentSkinState() : String { 

//    translate component states into skin states
//    note: the base class' method, 
//            SkinnableComponent.getCurrentSkinState(), returns null
}

override public function styleChanged(styleProp : String) : void
{
    super.styleChanged(styleProp);

    if (styleProp == “icon”)
        closeIcon.source = getStyle(“icon”);
}
data values push values into the skin using code-behind
currentState the component sets the skin’s state to reflect some aspect (e.g. disabled)

The Skin’s View of the Component

These are the properties the skin used to receive and communicate with the host. In general, the skin assumes that the synchronization with the component will push values into the sub-components and change the skin’s state; it does not reference the .hostComponent directly.

host class [HostComponent("spark.components.Button")]
host instance
(rarely used)
.hostComponent
data values pushed into values by the component
currentState the component sets the skin’s state to reflect some aspect (e.g. disabled)

Skin State

The component can require specific skin states (e.g. “normal”, “disabled”). It uses those states to instruct the skin to change appearance, but leaves the specifics up to the skin. Adobe could have used an event, an expected method, or some other way to signal the skin; the advantage of using states is that it’s easy to set up an MXML component to respond to states. The base component’s invalidateSkinState() method (called when the component’s state change, for example) triggers a call to getCurrentSkinState(). That method examines the component’s properties and returns the skin state that fits.

For example, SkinnableTextBase requires the skin to have states “normalWithPrompt” and “disabledWithPrompt”, and uses them as appropriate in getCurrentSkinState() to have the skin show the .prompt text (using whatever sub-component the skin chooses to show it).

Object-Oriented Skins … Or Not

Adobe has been uncharacteristically forceful in their declaration that  we should not create inheritance hierarchies of skin classes; Adobe wants us to copy and paste when creating new skin classes. Part of that is political: they have lots of tools for designers to work with developers, and designers do not sub-class anything. Although I am a OOP-freak, I see their point: skins are so thin (i.e. they have very little behavior implemented in code) that the logistical overhead of having some parts in the ancestor and some in a descendant does not have much benefit to balance it. A well-designed skin class can use CSS as a replaceable properties file, and that can bundle a lot of behavior in a thin class without sub-classes.

 

Reuse … Your Brain

Components were supposed to save us; they were the silver bullet that would make code reuse actually work. The problem with reusing code is that it takes at least three times as much work to make a component that works in all cases rather than just the ones the component author had in mind, and no one wants to put the work in unless they are getting paid.

The fun part of components is figuring out the best level of encapsulation and making a piece that fits nicely into that spot. Testing, debugging, documentation, and validation are not (for most people) the fun parts. for components to be useful in more than one context, they have to be internally and externally consistent, they have to handle attribute changes in all possible combinations, and they have to handle external error conditions at every possible point. Software libraries and SDK’s distribute themselves as classes and components, and they make applications possible. For the infrastructure organizations and component vendors, this is their business.

Components built within organizations do not have the support of paying users, and so they tend not to have the fit and finish of their commercial brethren. A commenter named Tim put it well in a discussion about Agile/XP and reuse:

The first time you have to pay for it to be coded,
The second time you have to pay for it to be reusable,
The third time it’s free.

With all due respect to Agile and XP, I err towards the other end of the spectrum: I like to build software clean enough that I am not embarrassed to have others use it. I want it so obvious that I will understand it quickly when I come back to it later. I like building well-rounded components that will survive a little transplantation or changes in usage. I like to take the time to make classes that know how to clone, clear, deep-copy/assign, and test equality. In other words:

Treat Yourself As You Would Have Others Treat You

Nevertheless, managers see a component named DataManager and assume (or at least hope) they can reuse it anywhere their design calls for a data manager. They don’t want to “waste” the effort spent building it the first time. Here is when intuition fails us all: we talk of “building” software instead of “composing” it. Software is ideas made manifest (albeit in a structure that judges those ideas against a very solid and unforgiving reality).  Software is not an engine where the number of cylinders is fixed. However, composing a better component is easier than building a second house. It’s often impossible to rebuild a component exactly the same as its original because the composer/author/developer/coder can’t stop themselves from improving their idea.

Besides running the same code in different environments, the best reuse is reusing experience. Experience grows all the time (and grows faster from bad outcomes). Rather than looking at components as commodities that remove the need for experienced developers, look at components as the steps that developers can stand on to see farther.

Hierarchical Data Grids

I recently had cause to create a grid that showed rows with parent, child, and grandchild rows. Each generation’s text is indented to show the relationships, and rows with children have a plus or minus to show and hide them. While the AdvancedDataGrid can create virtual parent rows for unique values, it is not built to show actual parent and child rows.

Sample Application with source: http://flex.santacruzsoftware.com/HierarchicalDataGrids/

One way to manage parent-child relationships is to store all the raw data in one list and use a different list to display the data. Each row must indicate if they are parents and, if so,  are their children are visible. In my case, those flags were already present in the grid’s data row object (ReportRow), alternatively, one could use external lists and messages to hold this information (see The Ultimate Checkbox List Pattern). The row objects have a collection of child rows as a property, and a value that indicates what generation (level) they are.

public function onExpand(event : Event) : void
{
	this.refreshExpandedItems();
}

public function refreshExpandedItems() : void
{
	var prevSelection : Object = reportGrid.selectedItem;
	var prevScrollPosition : uint = reportGrid.verticalScrollPosition;

	this.reportData.refreshDisplayList();

	reportGrid.selectedItem = prevSelection;
	reportGrid.verticalScrollPosition = prevScrollPosition;
}

The grid’s ItemRenderer shows an expansion icon (e.g. “+” and “-”), handles indenting the text to show each row’s level, and throws a bubbling event whenever the user clicks the expansion icon. The dataChange method (or the overriden data mutator) handles indentation as well as which rows should have expansion icons.

private function onDataChange(event : Event) : void
{
	if (this.data != null)
	{
		var theRow : ReportRow = this.data as ReportRow;

		nameLabel.text = theRow.name;
		nameLabel.x = 20 + (theRow.level * INDENT_PER_LEVEL);

		if (theRow.children.length > 0)
		{
			expansionLabel.visible = true;

			if (theRow.isExpanded)
				expansionLabel.text = "-"
			else
				expansionLabel.text = "+"
		}
		else
			expansionLabel.visible = false;
	}
}

private function onExpansionClick(event : Event) : void
{
	var theRow : ReportRow = this.data as ReportRow;

	theRow.isExpanded = !theRow.isExpanded;

	var expandEvent : ExpandEvent =
		new ExpandEvent(ExpandEvent.EXPAND_PARENT, true);
	expandEvent.row = theRow;

	this.dispatchEvent(expandEvent);
}

When this event (or some other application code) marks a row as newly expanded or an expanded row as collapsed, the data object refreshes the entire display list by emptying it and iterating through the entire raw-data list and copying each parent and, if expanded, its children to the display list. Depending on one’s needs, one can recursively check the children for nested grandchildren, etc.

I created a separate class to hold and manage the data as a grid-specific model. The container holding the grid creates an instance of the data object, and that object not only manages the raw and display lists and also parses the result from a server into grid-specific row objects. It also has a bindable array collection of row objects to display; this is what the grid uses as its displayProvider.

While Flex’s update event model will likely avoid thrashing the display, one can use displayList.disableAutoUpdate() or binding with an explicit event and dispatching an explicit event to ensure that the DataGrid refreshes only once after the display list changes

[Bindable(event="displayListChange")]
public var displayList : ArrayCollection = null;

public function refreshDisplayList() : void
{
	displayList.removeAll();

	for(var counter : uint = 0; counter < rawDataList.length; counter++)
		addRow(rawDataList.getItemAt(counter) as RowData);

					//	signal that all changes are complete
	this.displatchEvent(new Event("displayListChange"));

					//	nested function
	function addRow(aRow : RowData, generationNumber : uint = 0) : void
	{
				//	put any client-side filtering tests here

		aRow.displayIndentLevel = generationNumber;
		displayList.addItem(aRow);

		if (aRow.isExpanded)
		{
			var theChildRow : RowData;

			for(var childCounter : uint = 0; childCounter < aRow.children.length; childCounter++)
			{
				theChildRow = aRow.children.getItemAt(childCounter) as RowData;

				addRow(theChildRow, generationNumber + 1);	//	recursive
			}
		}
	}
}

Sorting and Filtering

The raw data list’s sort function needs to sort without breaking the relationship between each row, its parent, and its children. One can either sort the highest level and leave the descendants unsorted; one can sort each of the generations relatives to its siblings. To filter display rows, simply omit rows from the display list rather than using a filter function on either the raw data list or the display list.

Performance

displayList.addItem(aRow) inserts a reference to the row object in the rawDataList ; it does not create a copy of the actual data. Moving a few hundred references around does not take a lot of time. Compared to redrawing the grid itself, managing the references is instantaneous.

Paging Hierarchical Data

Many Flex applications using grids show only part of the total data set (no one actually wants to see 10,000 rows). In this vein, one might want to load the children of a row if and only if the user expands it. The rawDataList will retain any children once downloaded, so repeated expansion and collapse will not overload the server, but getting the child rows the first time requires a specific protocol.

In my case, the server allowed me to get the report data passing flag indicating ParentsOnly (which gets only the top-level rows) or criteria to specify one particular top-level entity (which I used without the ParentsOnly flag to get the descendants). As I don’t get the children until needed, the item renderers need an isParent property in each item (to replace the test theRow.children.length > 0) so knows they whether to show the expansion icon at all.

The EXPAND_PARENT event listener checks the event’s ReportRow isExpanded and children == null If both are true, it has to retrieve the children from the server, insert them into the ReportRow.children property, and then call refreshExpandedItems(). This requires at least one asynchronous step, so the COMPLETE listener (as well as the fault handler) needs to clear any “Please Wait” messages. If the row is collapsing or already has its children, the listener can simply call refreshExpandedItems().

Or That

Coming from Delphi, I use properties for everything. I even create protected and private properties for use inside a class:  they are good idea, so I don’t limit them to public interfaces.

A new wrinkle I’m dealing with is bound properties that have default values. For example, a Button sub-class that has a default caption but also has a public property that the user can bind to some other value. A normal property with a default would look like this:

private static const DEFAULT_ENABLED_CAPTION : String = "Click me!";

[Bindable]
public var enabledCaption : String = DEFAULT_ENABLED_CAPTION;

One can bind this property to a child component in an MXML component or use it in the commitProperties() method of an ActionScript component. It acts as a proxy for the “real” property, and allows different values based on state (e.g. enabled and disabled captions based on the enabled property).

When one uses binding to set values, if the object configuration is null or the property enabledCaption is blank at any time, the property loses its default value and does not get a valid replacement.

    <components:MyButton enabledCaption="{configuration.enabledCaption}"
                  disabledCaption="{configuration.disabledCaption}" />

Assuming that one does not want to allow an empty string (or null), some small changes to the accessor and mutator can handle these automatic assignments by the binding mechanisms:

public static const CAPTION_CHANGE : String = "captionChange";
private static const DEFAULT_ENABLED_CAPTION : String = "Click me!";

[Bindable(event="captionChange")]
public function get enabledCaption() : String
{
    if (_enabledCaption== "")
        return DEFAULT_ENABLED_CAPTION;
    else
        return _enabledCaption;
}
public function set enabledCaption(value : String) : void
{
    if (value == null)
        _enabledCaption = "";    //  strings should not be null

    if (_enabledCaption != value)
    {
        _enabledCaption = value;
        this.dispatchEvent(new Event(CAPTION_CHANGE));
    }
}
private var _enabledCaption : String = DEFAULT_ENABLED_CAPTION;

No matter how many times the binding mechanism updates the component property (i.e. calls the mutator), the accessor will return the default value unless the binding (or some other code) sets the value to a non-null, non-blank string.

Teach Me, Bicycle-Repair Main

I finally have my car fixed. It is a 2005 Prius (second series) and would sometimes fail to allow the headlights to go into low-beams only. My mechanic could not find the cause and sent me to another mechanic. They spent several hours and determined that I needed a new (expensive) headlight switch, which they would special-order.

They estimated one (1) hour installation and I arraigned to bring the car in before work to wait while they installed it. When I arrived, they said it would be done in 1.5 hours. Hmmm.

Two hours later, I was on my way (late to my morning meeting). They cheerfully explained that they had never done this type of switch before, and that I would not have to pay for the extra time it took them. I snarled under my breath at their presumption that I should be happy that I did not have to pay for them being late.

Until I realized that, as software developers:

  • We too give estimates based on the best-case scenario (and we believe it ourselves)
  • We too have our clients/employers pay for us to learn new things
  • And we do charge them if things take us longer then we said they would

Advanced Topics Using a Message-Based Checkbox List Pattern

Fifth in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

The checkbox pattern described in the previous four blog entries allows a lot of flexibility and subtly in your applications. This post covers some of the issues I’ve dealt with, a bit of philosophical and aesthetic musing, and an example application.

Setting The Manager’s Event Listeners

Setting the  list manager’s listeners in the startup event cycle is tricky. In general, I use addEventListener() in the creationComplete event for listeners on the form, however this does not work if the checkbox list or grid is a design-time  child on the form (e.g. it’s in the MXML or created by createChildren()). By the time the creationComplete event fires, the grid has already initialized and all the item renderers have dispatched their first AmISelected events, which receive no answers because the listener is not set up yet.

Register amISelected listeners in the initialized event.

Messages vs. Interfaces

A different way of loosely linking parts of a system is interfaces. One could pass an instance of an interface that had toggleSection and amISelected methods to an item renderer. The class of that instance could be anything; the caller would not know who was executing the method and the method would not know who was calling it. Passing an instance more than one layer deep, however, creates a loosely-linked chain, and the more links in a chain, the more fragile it is.

Every container between the list manager (e.g. the form or component’s top-level container) would have to pass the instance on to every child that could hold it (probably because the children implemented an interface themselves). Components that had no interest in this interface would still be responsible for passing it on.

Messages, however, are already part of every UIComponent’s interface (because it implements IEventDispatcher): they allow listeners to hook into the messages; the message framework moves the event objects through the containership model; and the event objects themselves can change without changing the interface.

Message-Based MVC

The Ultimate Checkbox List Pattern resembles a Model-View-Controller: the item renderer would be the view; the list of selected items would be the model; and the event listeners on the list manager would be the controller. In an classc MVC pattern, the controller would push the changes into the view, and therefor would need to know how it worked (i.e. what method to call or property to push). The UCLP has the model pushing a change notification into a generic listener in the view, and then the view pulls the change information from the model; the module (and the controller, for that matter) do not know anything about the view besides a reference to the view’s notification listener.

Matching By Value vs. Matching By Reference

As shown in the sample application, one can use a more robust test to see if a Thingie is in the selected list than simply checking getIndexOf(). While the “thingie” might be a complex Value Object, this pattern also lends itself to simple data objects that might be dynamically created to wrap one or two column values. In this case, the object itself might not come from a global (i.e. singleton) store; one might have several simple instances that represent the same values, but not the same instances in memory.

For example, in the sample application (which has View Source)

 

Sample Message Based Checkbox List Application

click for SampleMessageBasedCheckboxListApplication

 

the AmISelected method checks if the data is selected, not just if the Thingie instance in the event is also on the list. Actually, the original version had a middle section that used api.business.gov to show a grid that was not even Thingie objects, but it has no crossdomain.xml, so…

Use this pattern to support your needs: if you have different representations of the same concept and you want to select or de-select the concept, then make the AmISelected check if the concept is on the list; if the objects in question are references to singleton objects on a central list (e.g. value objects), then check if the object itself is referenced by the list.

Let Me Know

Let me know what you think of this pattern. Let me know how I could explain it better. How have you improved it ?

Multiple States and Multiple Dependencies Using Message-Based Checkbox Patterns

Fourth in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

While a basic Ultimate Checkbox List Pattern uses only a single Boolean value – e.g. isSelected – its questioning event can allow more than just one answer: in addition to finding out if a row is selected (e.g. checking a checkbox), a questioning event can determine if a specific list item is visible or enabled at all. For example, the current user might not have rights to see a particular value; the page might have a terse or verbose option; some criteria might be selectable based on a separate criteria selection; or a set of items might have a maximum number of selections.

Like the selected state, the enabled state of a list item could be embedded in the item data itself, however one can choose to extend the Ultimate Checkbox List Pattern to. As each change in the list (or its proxy) makes every item check its state (see Multiple Views Using a Message-Based Checkbox Pattern), disabling any or all items is as easy as disabling one (remember that only visible items have item renderers with listeners which check state).

public class ThingieEvent extends Event
{
    public function ThingieEvent(...)
    {
        ...
    }
    public var thingie : Thingie;
    public var isSelected : Boolean = false;
    public var isEnableded : Boolean = true; // new flag public var notificationListener : Function;
}

The item renderer registers a listener the first time it checks the current item’s state by adding it to the questioning event:

...
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data as Thingie;
        theEvent.notificationListener = this.onExternalThingieChange;
        this.dispatchEvent(theEvent);
        isThingieSelectedCheck.selected = theEvent.isSelected;
        isThingieSelectedCheck.enabled = theEvent.isEnabled;
...

And whenever the item renderer’s notification listener indicates something external changed, it will check the state of the specific data currently in the item renderer.

    private function onExternalThingieChange(event : Event) : void
    {
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data as Thingie;
        this.dispatchEvent(theEvent);
        isThingieSelecctedCheck.selected = theEvent.isSelected;
        isThingieSelecctedCheck.enabled = theEvent.isEnabled;
    }

On the list manager side, the first time the item renderer asks for a selection status by dispatching a questioning event, the list manager adds the notification listener (if present) using weak references. It can add the callback as a listener directly to the data list (e.g. ArrayCollection), or it can add it to a separate IEventDispatcher object in order to proxy events explicitly from multiple sources (e.g. signal a change when the _thingieList changes and when the user changes between “terse” to “verbose”).

    private var _thingieList : ArrayCollection = new ArrayCollection();
    private var _thingieListProxy : EventDispatcher = new EventDispatcher();
      ...
        _thingieList.addEventListener(CollectionEvent.COLLECTION_CHANGE, onThingiesChange);
        context.addEventListener(Event.STATE_CHANGE, onThingiesChange); // something else that requires a change-check
      ...

    private function onThingiesChange(event : Event = null) : void
    {
        _thingieListProxy.dispatchEvent(new Event(Event.CHANGE));
    }

    private function onIsThingieSelected(event : ThingieEvent) : void
    {
        event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);
        event.isEnabled = (context.currentState == SELECTABLE_STATE) && (_thingieList.length < MAX_SELECTED_THINGIE_COUNT);
        if (event.notificationListener != null)
            _thingieListProxy.addEventListener(Event.CHANGE, notificationListener, false, 0, true);
    }

If the onThingsChange event carried information, it would link the listener and the dispatcher more tightly than we want. Using a generic Event with the type Event.CHANGE (the simplest possible notification) insures that the dispatcher can send that notification for any reason it wants; it is not restricted by any required or expected event parameters.

For those who like sequence diagrams:sequence diagram for multiple=

(Update: sample application in the final installment)

Multiple Views Using a Message-Based Checkbox Pattern

Third in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

The previous post showed how one can have an item renderer communicate with one of its containers to set and retrieve the selected (e.g. checked) state of the item renderer’s data. If, however, the same data (and its selected state) appear in more than one view, one needs to add another set of notifications to the pattern.

If something other than a particular item renderer changes the values in the thingieList, the item renderer needs to know to change the checkbox status. Rather than iterating through the children of the DataGrid or List to find all the ItemRenderers to tweak them, we can have sort of a “push” notification: the item renderer passes a listener function to the list manager the first time it asks for an item’s selected status, and external changes call that listener. To make things as generic as possible, the listener does not expect any specific type of event (i.e. the event does not contain information about the change); it simply checks its own status whenever it’s called.

This combination seems complicated, but it’s built on what we’ve done before:

  • The view dispatches an AmISelected event with a reference to its event listener function in it.
  • The list controller adds the event listener
  1. Something changes the list
  2. The list dispatches a CHANGE (or COLLECTION_CHANGE) event to all the listener functions
  3. The view listener functions dispatch an AmISelected event (without a listener reference in it)
  4. The list controller received the AmISelected event object and sets its .isSelected property based on the list
  5. The item renderer checks the .isSelected property and updates its display based on the answer


This causes a lot of events that don’t actually find any changes (i.e. every item renderer whose data have not be selected or deselected), however the cost for these events is low and the value of simplicity is high.

The item renderer registers a listener the first time it checks its data’s status:

 ...
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data.thingie;

        theEvent.notificationListener = this.onExternalThingieChange; this.dispatchEvent(theEvent); // ---- listeners execute here

        isThingieSelectedCheck.selected = theEvent.isSelected;
 ...

And the item renderer’s listener function checks the status

private function onExternalThingieChange(event : Event) : void
{
    var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
    theEvent.thingie = data.thingie;
    this.dispatchEvent(theEvent);
    isThingieSelectedCheck.selected = theEvent.isSelected;
}

On the list manager side, it adds the callback function (if present) as a listener using weak references. It could add the callback as a listener directly to the data list or to a separate IEventDispatcher object if it was going to fire events explicitly

private function onIsThingieSelected(event : ThingieEvent) : void
{
    event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);

    if (event.notificationListener != null)
        _thingieList.addEventListener(CollectionEvent.COLLECTION_CHANGE, event.notificationListener, false, 0, true);
}

By adding one notification, changes to the selection list automatically update all items whether they are visible or become visible later, so the user can can modify or clear the list without tight coupling with all the other views that add and remove items.

(Update: sample application in the final installment)

The Ultimate Checkbox List Pattern

Second in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

A common task is to put checkboxes into a list or grid. Instead of adding Boolean property values to the dataProvider items, the Ultimate Checkbox List Pattern leaves the display item alone (e.g. a pure value object) and uses membership in a separate list of items to indicate if an item is selected (checked). Often, this list of selected rows itself is very useful. Standard ActionScript events communicate between the item renderers (with a checkbox) and a container object or the form itself acting as a controller for the selected list.

The key to this pattern is anonymous communication: the list controller does not know what components are sending messages asking if this or that object is or is not selected, and the view (i.e. an ItemRenderer) does not know who is listening and answering its questions. They communicate using a custom event that adds a reference to the item, and a Boolean: isSelected. For example,

public class ThingieEvent extends Event
{
    public var thingie : Thingie;
    public var isSelected : Boolean = false;
    public var notificationListener : Function;
}

Changing the Selected State
The ItemRenderer sends an event when user interaction with its checkbox changes the selected state:

 ...
        var theEvent : ThingieEvent = new ThingieEvent(THINGIE_SELECTION, true);
        theEvent.thingie = this.data.thingie;
        theEvent.isSelected = thingieCheckBox.selected;
        this.dispatchEvent(theEvent);
 ...

The list manager might handle the event like this:

    private function onIsThingieSelected(event : ThingieEvent) : void
    {
        var existingIndex: int = _thingieList.getIndexOf(event.thingie);
        if (event.isSelected != (existingIndex != -1))
        {
            if (event.isSelected)
                _thingieList.addItem(event.thingie);
            else
                _thingieList.removeItemAt(existingIndex);
        }
    } 

    private var _thingieList : ArrayCollection = new ArrayCollection();

Getting the Selected State
When an ItemRenderer initializes itself, it needs to know if it should set the checkbox.selected attribute based on the data. It needs to ask someone outside itself if the current item should be checked. Rather than have the list manager add event listeners to every ItemRenderer, the ItemRenderer dispatches an event, waits for all the listeners to review it , and look at the event’s properties as the answer to the question.
It dispatches an event that bubbles (or is proxied up to the DataGrid or List) to some container acting as a list manager. It will set the event.isSelected property. Once the dispatchEvent() method returns, the ItemRenderer looks at that property.

 ...
    var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
    theEvent.thingie = data.thingie;

    this.dispatchEvent(theEvent); // ---- listeners execute here

    isThingieSelectedCheck.selected = theEvent.isSelected;
 ...

Note that after the .dispatchEvent(), the event has whatever value the listeners put in there. On the list manager side, the listener might look like this:

    private function onIsThingieSelected(event : ThingieEvent) : void
    {
        event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);
    }

Note that it does not cost anything to add a listener more than once, and using a weak reference prevents memory issues. The Ultimate Checkbox List Pattern uses bubbling events; if one is not fond of them, one can proxy the events through custom Column classes, then through the top-level Grid or Listbox, and then up to whatever is acting as the list manager.

An advantage to bubbling events is immunity to changes in the number of containers between the item renderer and the list manager. One can even encapsulate some set of containers into a component and embed it in another container without changing this pattern.

The Ultimate Checkbox List Pattern has several advantages over using a flag in the dataProvider item to persist checked status:

  • The dataProvider items can remain pure value object (e.g. unchanged from an loosly-linked data module)
  • The same item can have separate selection-states on an infinite number of lists
  • The list of selected items is always current and available at a high level; one does not need to iterate through the dataProvider items
  • Items remain selected even when they are not visible or if they are not in the dataProvider’s collection. One can page off and back and previously selected items are still selected.
  • Items can be selected and deselected across several different views (if the list manager tests membership using an ID instead  of object identity). E.g. one can have browse lists and search results that reflect each other’s selection (ee the next posting for details).

(Update: sample application in the final installment)

Go Ask Your Container

First in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

One of the things I had to learn moving from Windows programming to Flash/ActionScript programming was all the asynchronous patterns (aka two-part procedures). If one needs to load a resource in the middle of a process, one cannot just call a loader and wait for the results before continuing. One has to register an event listener to the loader object and put the remainder of the process into that listener function. When the loader is done loading, it calls the listener, and the rest of the process goes on its merry way. While this is indeed asynchronous programming, events themselves are not asynchronous.

Events are dispatched (aka “fired”, “launched”, “broadcast”, “thrown”) from classes implementing IEventDispatcher – usually by descending from or containing the class EventDispatcher – by calling the event handler functions (“listeners”) previously registered. The dispatcher does not care how many listeners have registered themselves or what they do: it just calls every one registered for a particular message.

Event handlers are, at their core, callback functions. One can call them explicitly, but they are designed to be registered with a dispatcher, and wait for it to call them. One should keep these callback functions very lightweight because events themselves are not asynchronous.

When one to fires an event by calling a dispatcher’s dispatchEvent method, the method literates through the list of registered listener functions, calling each one with the Event object as a parameter, and waiting for it to return before calling the next listener function. Then the dispatchEvent method itself returns. The code that calls dispatchEvent can assume that, when that call returns, all the listeners have had a chance to see and modify the Event object.

One can use events as a bidirectional messages between the dispatcher and the listeners, not just a one-way notification system; the event object can receive information from the listeners as well as send information. Combined with bubbling events that allow containers to get events without registering with the originating dispatcher, this patterns allows nested objects like ItemRenderers to ask questions of their high-level containers without each intermediate container passing the events up and the results down. This relationship is a loosely-linked one: the dispatcher does not know what object is setting the answer properties of the Event object; the listener does not know what object is dispatching the Event object. The form can add or remove containers without breaking.

The Event class already has one Boolean property that is designed for listeners to set: the defaultPrevented property. Listeners can call event.preventDefault() to set this, and the dispatching code can check the value (the dispatchEvent method itself returns this value as well).

For example, an ItemRenderer needs to know if the data it is displaying is part of the set that the user wants to focus on. The data itself does not know, but the top-level form object does. The ItemRenderer can dispatch an event containing its data object and a property for the current status.

public class AmIInUserFocusEvent extends Event
{ 
    public function AmIInUserFocusEvent(type : String = AM_I_IN_FOCUS, bubbles : Boolean = true, cancelable : Boolean = false) 
    { 
        super(type, bubbles, cancelable);
    }

    public var rowData : RowData; public var isInUserFocus : Boolean; 
}

In the ItemRenderer:

 ...
       var newEvent : AmIInUserFocusEvent = new AmIInUserFocusEvent(AM_I_IN_FOCUS, true);
       newEvent.rowData = this.data as RowData;

       this.dispatchEvent(newEvent); // ---- listeners execute here 

       if (newEvent.isInUserFocus) 
           text.styleName = "focusStyle"; 
       else 
           text.styleName = "neglectedStyle"; 
 ...

In some container that holds the item renderer’s list or grid :

 ... 
        this.addEventListener(AM_I_IN_FOCUS, onFocusQuestion);

        ....

    private function onFocusQuestion(event : AmIInUserFocusEvent) : void
    {
        event.isInUserFocus = focusList.contains(event.rowData); 
    }
 ...

To summarize, in additional to sending notifications and data out, events can also get answers. ActionScript’s built-in event framework allows loosely-coupled communication between different parts of a form, even across component bounds.

(Update: sample application in the final installment)

Distributed Dates

When you announce an event in email or put in on your web site, instead of just showing text describing the event, make it easy for your audience to save the date. With the prevalence of on-line and PDA and cell phone calendars, you can get your event on their calendar easily.

Providing the event information yourself instead of depending on your audience to copy ensures accuracy (i.e. no transcription or transposition errors) and complete: you can include the street address, contact phone number and email, directions, links to on-line maps, prerequisites, and preparation suggestions (e.g. “Bring a jacket because it gets cold in the evening”)

I’ll be talking about three different ways to communicate event information:

  • Load it on their Yahoo or Google Calendar using a link
  • Distribute it as an iCalendarFile
  • Share your public calendar

Load It on Their Yahoo or Google Calendar Using a Link

Both Yahoo and Google have a format for describing a calendar event as a URL. If you supply these as links on your web page or HTML email, users can click them and immediately add the event to their own calendars.

Yahoo Calendar Links

The Yahoo Calendar link is at the bottom of each Yahoo Calendar page as text. Note that the link represents the event as it was when the page appeared; it does not dynamically reflect any changed you make, so save any changes and then copy the link.

Google Calendar Links

The details page for a Google Calendar event has a link in the lower right corner: “Publish this event”. It will pop-up a dialog with the address selected for easy copying.

Distribute It as an iCalendar File

As with most computer things, calendar items have a standard format so every system can understand the data. The iCalendar format replaces an older format named vCalendar. You can send this file as an email attachment or as a downloadable file on your web site (example below)

Almost all calendar applications (like Outlook/Exchange, Backpack, Notes, Sunbird) will import “iCal” files (some will export as well). Some operating systems associate the .ical and .ics file extensions with the calendar program so that program automatically imports the calendar file whenever the file is “executed”.

Share Your Calendar

Both Yahoo and Google allow you to create an on-line calendar and publish it so users of those systems can merge it (subscribe) with their own calendars. Your subscribers will see events as soon as you add them with no action on their part. They will also see them in relation to their own scheduled calendar events, so they can plan and anticipate.

Here is a Yahoo Calendar that subscribes to several other calendars. All the subscribed calendars show up as items in the right-hand column.

Subscribing to a Yahoo Calendar

Instruct your users to go to their Yahoo Calendar and select the “Edit” link My Time Lines in the upper right corner of the top date display (not the top right corner of the screen)

They can select any of their group’s calendar or a friend’s calendar:

Here is a Google Calendar that subscribes to another calendar. The events are color-coded to show which calendar they come from. In this case, pink is “my” events; red is for Sign Language Club De Anza calendar’s events.

Note that subscribing to someone else’s calendar does not expose your calendar

Sharing/Publishing Your Yahoo Calendar

Insure that the calendar you are going to share is completely public (do not share your personal calendar just because it has some public events on it). If you manage a Yahoo group, you can publish that group’s calendar. You can also create a separate Yahoo account to publish.

Pick a calendar and set its publication in the Calendar | Setting | Calendar page:

Subscribing to a Google Calendar

Tell your subscribers to choose the Other calendars | Add link on the left panel. They can select a friend’s calendar or enter the calendar’s address.

You can find the address of your calendar at Settings | Calendar Details (scroll down) Calendar Address

Sharing/Publishing Your Google Calendar

Google Calendar allows you to create many calendars and publish them individually.

Specify your calendar’s publication in the Calendar | Setting (top left corner)| Calendars | Share this calendar

You can make the calendar either public or available to specific Google Calendar users.


Example of a Yahoo Calendar URL – wrapped to multiple lines for ease of reading

http://calendar.yahoo.com/?
  v=60&
  VIEW=d&
  in_loc=Adobe+HQ+-+San+Jose&
  in_csz=San+Jose%2c+CA+95110&
  type=20&
  TITLE=Silvafug+South+-+San+Jose+-+Design+and+Development+Workflow&
  ST=20090515T013000Z&DUR=0100&
  URL=http%3a%2f%2fria.meetup.com%2f12%2fcalendar%2f10232257%2f&
  DESC=For+full+details%2c+including+the+address%2c+and+to+RSVP+see%3a%0ahttp%3a%2f
     %2fria.meetup.com%2f12%2fcalendar%2f10232257
    %2f%0aFlex+3+%26+Adobe+AIR+Junkies%0aThere+are+two+sessions+this+month+12th+in+San+Francisco+and+14th+in+San+Jose.+The+presentations+will...

Example of a Google Calendar URL – wrapped to multiple lines for ease of reading

http://www.google.com/calendar/event?
 action=TEMPLATE&
 text=Silvafug+South+-+San+Jose+-+Design+and+Development+Workflow&
 dates=20090515T013000Z%2f20090515T023000Z&location=San+Jose%2c+CA+95110&
 sprop=website%3ahttp%3a%2f%2fria.meetup.com%2f12%2fcalendar%2f10232257%2f&
 sprop=name%3aFlex+3+%26+Adobe+AIR+Junkies&
 details=For+full+details%2c+including+the+address%2c+and+to+RSVP+see%3a%0ahttp%3a%2f
  %2fria.meetup.com%2f12%2fcalendar%2f10232257
  %2f%0aFlex+3+%26+Adobe+AIR+Junkies%0aThere+are+two+sessions+this+month+12th+in+San+Francisco+and+14th+in+San+Jose.+The+presentations+will+be+the+same+so+RSVP+to+the+one+that+is+a%26hellip%3b%22

Example of an iCalendar file (from Wikipedia)
Here is a simple example of an iCalendar object, “Bastille Day Party” event which occurs July 14, 1997 17:00 (UTC) through July 15, 1997 03:59:59 (UTC):

BEGIN:VCALENDARVERSION:2.0PRODID:-//hacksw/handcal//NONSGML v1.0//ENBEGIN:VEVENTDTSTART:19970714T170000ZDTEND:19970715T035959ZSUMMARY:Bastille Day PartyEND:VEVENTEND:VCALENDAR

Other References

See also toomanydaves…words by davelms

Copyright © (copyright) All Rights Already Reserved

Throwing a copyright notice on a page is a reflexive action, but as with most checklist items, it deserves more mindfulness. The point of copyright is to protect the layout of graphics and images, and the exact phrasing of text. If it’s worth protecting, then it’s worth a few moments of attention.

A copyright notice is the word “copyright” or its token © — “c” in a circle (pick one, not both) , the year of publication, and the entity holding the copyright; that’s it. No “All Rights Reserved”, no history of changes: just that.

© 2010 Richard C Haven

Most important, however, is to have content worth protecting.


Notes

Copyright notices

Use of a copyright notice © consisting of the letter C inside a circle (that is, © or U+00A9), the abbreviation “Copr.”, or the word “Copyright”, followed by the year of the first publication of the work and the name of the copyright holder was part of previous United States statutory requirements, but since 1989, when the U.S. adhered to the Berne Convention, the use of copyright notices has become optional to claim copyright, as the Berne Convention makes copyright automatic.[8] However, notice of copyright (using these marks) does have consequences in terms of allowable damages in an infringement lawsuit in some places.

http://en.wikipedia.org/wiki/Copyright

“All Rights Reserved”:

This notice became obsolete and essentially deprecated on August 23, 2000, as every country that was a member of the Buenos Aires Convention (which is the only copyright treaty requiring this notice to be used) is also a member of the Berne Convention which requires protection be granted without any formality of notice of copyright.

http://en.wikipedia.org/wiki/All_rights_reserved

Hi, I'm Biill

Another lamentably rare old-school habit is naming parameters as uniquely as if they were local variables (which they are), especially in constructors. For example:

public function MyClass(transportationBill : Bill, sponsor : Sponsor,
      submissionDate : Date, referenceId : String = "", fundingBiill : Bill = null)
{
    this.transportationBill = transportationBill;
    this.sponsor = sponsor;
    this.submissionDate = submissionDate;
    this.referenceId = referenceId;
    this.fundingBill = fundingBill;
}

All nice and compilable, except it has a silent bug that will sneak up and ruin someone’s day. Note the typo in the last, optional argument: “…Bii…”. The reference this.fundingBill = fundingBill works fine, but assigns the class attribute fundingBill to itself because no parameter has that name.

If all the constructors had a unique name, then any typos would show as compiler errors:

public function MyClass(aTransportationBill : Bill, aSponsor : Sponsor,
    aSubmissionDate : Date, aReferenceId : String = "", aFundingBiill : Bill = null)
{
    this.transportationBill = aTransportationBill;
    this.sponsor = aSponsor;
    this.submissionDate = aSubmissionDate;
    this.referenceId = aReferenceId;
    this.fundingBill = aFundingBill;    // <---- compiler error
}

The roles of each token is clear within each line: some are class attributes and some are arguments.

Note that I am not a fan of Hungarian notation: the type of each token should be described in full words, not in a vowel-less prefix. The role of each, however, can be implied with a language artifact like a grammatically correct article (e.g. indefinite (“a”) for parameters and definite (“the”) for local variables).

public function doSomething(aRequest : Request) : void
{
    if (aRequest != null)
    {
        var theValue : String = aRequest.id.toLowerCase() + aRequest.host;

        if (!this.isInProcess(theValue))
            this.submitRequest(theValue, aRequest);
    }
}

Generally Optimistic Database Updates from a Resonably Rich Client

The problem with having a data model in the client application is that its data might not match the server’s version of that data. Even if the client sends any changes to the server immediately, some other client might have changed the server’s data since the client received it. Even if the server pushes all changes to all clients immediately, you will have cases where updates get lost. Don’t even start thinking about briefcase applications.

This is the old-school Lost Update (remember? from the beginning of database class when they talked about history and transactions). In a nutshell, if two clients start with the same picture of the data (sent from the server) and both make changes and both submit those changes, one of the two changes is going to get lost, at best.

The worst thing an application can do, by far, is lose data silently. Crashing is embarrassing and annoying, but users figure out how to work around it. Getting error messages is only slightly less annoying, but the user knows something went wrong and will check to see if their data is present. If a server does not save the changes that the user thinks it did, by the time the user finds out, they won’t even remember how many changes were lost, let alone be able to recreate them. This will lose that customer, and deservedly so.

Assume that data moves in chunks (e.g.some joined rows) that represent an object in the client data model. The best thing a server can do if it receives an update and detects that the client made changes to an out-of-date version of data is to reject the update loudly: return a fault so the client knows that they have a problem. The classic way to detect this is optimistic “locking”: sending a copy of the original data along with the changes and checking all those values in the SQL UPDATE statement:

UPDATE table T1
SET Column2=:newValue2, Column3=:newValue3,...
WHERE Column2=:oldValue2 AND Column3=:oldValue3 AND ...

If anyone else changes the values on the server, the update will fail (yay). A cheaper way to catch this is to 1) make sure that a LastModified column matches the client’s value when the client updates; and 2) update the LastModified column every time the server database updates a row (some DBMS make this very easy).

UPDATE table T1
SET Column2=:newValue2, Column3=:newValue3,...,
ColumnN=:newValueN, LastModified=:now
WHERE LastUpdated=:clientVersionLastUpdated

Note that this LastModified column must be part of every update and sent down with every object.


The client has to make some decisions when it either gets an update rejected by the server or receives an update from the server to data that the user has changed.

  1. Throw away the user’s changes and do nothing else (this is the Very Bad Thing we talked about above)
  2. Automatically refresh the data from the server and re-apply the user’s changes (blindly overwriting the other changes; also a Bad Thing)
  3. Throw away the user’s changes and tell them to do it over.
  4. Show the user what changes happened to the base data and ask if they want to re-apply their changes.
  5. Have each object’s code look at the changes from the server and re-apply the user’s changes that it determines are compatible. Other changes, see 3 or 4.

Apart from 1. and 2., the options come in increasing order of work, complexity, and user friendliness.

Brumme's Law of Client Application Performance

Brumme’s Law:

  • Hitting storage costs
  • Hitting the network costs
  • Everything else is free

Haven’s Codicil to Brumme’s Law

  • Maybe updating the screen costs

Chris Brumme was a scary-smart programmer working on Borland’s Paradox for DOS (I assume he is still scary-smart working at Microsoft on the future of OS). He could debug by looking at the instruction stack in hex. He coded the interpreter/compiler for Paradox’s scripting language.

At the time, I could barely understand the issues he was dealing with, nevertheless one day we were discussing how Paradox interpreted/compiled some piece of scripting code, perhaps re-evaluating some control value in a loop. I wanted the code to run as fast as possible (Paradox was in a speed contest with FoxPro at the time). He squinted, sighed, and tried to explain in simple terms why optimizing that particular operation was not worth his time to do (or my time to test).

Just as the difference in storage cost for a single or double-linked list is less than paying the salaries of two people to argue about it for one minute, the saving from optimizing the compiled form of this common action was effectively zero compared to the cost of risking one bug or the cost of maintaining more complex code. Compiled and even interpreted code runs so fast that, apart from absurdities, the code execution itself will not be the bottleneck.

Optimize the slow part, not the fast part

Even in high-level code itself, tactical optimization is rarely worth it. Careful “tuning” might gain 5% to 10% in performance at the risk of de-stabilizing the operation itself. Putting that effort into refactoring and re-designing some core data-retrieval or communication procedure (i.e. avoiding one web service call or bundling several sets of configuration data into one transfer package) can offer ten times that improvement.

Put out the net, then jump

I came to ActionScript from Delphi: a Windows tool. In Windows, most things are synchronous, even database calls. We would amuse ourselves by building a database query component that used a thread to make it wait asynchronously for the result.

Learning ActionScript and Flex meant that I had to learn how to deal with lots of asynchronous processes. Lots of code gets broken into a before-the-call method and an after-the-call listener. I hate using global variables (see below) to pass data between these two pieces; I always prefer to use the event itself to pass data between the two (e.g. event.target).

Be that as it may, it’s easy to follow the pattern of coding for asynchronous events without really understanding them. I’ve seen a lot of sample code that starts an object’s operation before setting the listeners that will process the result.

var theLoader : Loader = new Loader();
theLoader.load(new URLRequest("http://www.site.com"));
theLoader.addEventlistener(Event.COMPLETE, onCompletion);

If you call .load() before you set the listener, the load might complete before you registered the listener. Now, the realities of ActionScript (e.g. single-threading) probably make it impossible that this will happen under normal circumstances, however good coding is important.

var theLoader : Loader = new Loader();
theLoader.addEventlistener(Event.COMPLETE, onCompletion);
theLoader.load(new URLRequest("http://www.site.com"));

All the Code's a Stage

And all the variable merely players.
They have their initialization, and their finalization
… but variables play only one part.

Do not re-use variables. They are not roll-over minutes, they are not precious stones to be hoarded and handed down to one’s children. They are tokens, they are buckets, they are references, they are bits of source code that you should name clearly so their role is obvious.

Comments are not a sop for poor naming. Different people use comments differently, but if it takes a comment to explain what variable “obj” is and what it is going to do, then “obj” is not a good name. The compiler enforces consistent use of a variable’s name, bit it cannot ensure that the variable’s comment will move with the variable and-goodness me!-stay current.

I name variables based on what they are and what’s going to happen to them: groupCount, SaveButton, editableUserInfo, originalSessionId. I even have a cute name for the for loop counting variable: “counter”. My variable names are so obvious, any idiot can figure out what’s going on without thinking (even me, two months later).

If this sort of naming makes it hard to re-use a variable for some other purpose later in the function — good! The cost of one bug caused by confusion caused by an ambiguously named variable is orders of magnitude greater that any savings. Also count the cost of every programmer and tester who reads the code having to figure out what the variable “obj” means in this specific part of the function, and the cost of them misunderstanding and introducing new bugs.

And the “savings” of reusing variables is tenuous at best: even if the compiler didn’t optimize, even if the variable does not end up being in a CPU register or turned into address offsets, we’re talking about maybe four bytes of memory. Re-using variables is trying to outsmart your compiler.

“Trying to outsmart a compiler defeats much of the purpose of using one.”
- Kernighan & Plauger

o = new Wall();
o1 = new Lover();
o.atWall(o1);
o.chinkSize = 4;
o.color = DARK_AND_DAMP;
o1.trembles();
o1.color = PALE;
o1.whispers("are you there?");
o2 = = new Lover();
o.atWall(o2);
o2.color = FAIR;
o2.pining = true;
o2.whispers("what?");

compared to

theWall = new Wall();
girlSweetheart = new Sweetheart();
boySweetheart = new Sweetheart();
theWall.atWall(girlSweetheart );
theWall.atWall(boySweetheart );
theWall.chinkSize = 4;
theWall.color = DARK_AND_DAMP;
boySweetheart.trembles();
boySweetheart.color = PALE;
boySweetheart.whispers("are you there?");
girlSweetheart.color = FAIR;
girlSweetheart.pining = true;
girlSweetheart.whispers("what?");

Isn’t true love worth four bytes ?

MVC Frameworks for Flex

The Model-View-Controller pattern is a convenient way to remember which elements of an application need to know about which other elements. The most common frameworks that implement that pattern in Flex are:

  • Cairngorm
  • PureMVC
  • Matte

Several very able commentators have compared these frameworks:


http://www.asserttrue.com/articles/2007/10/17/silvafug-application-frameworks-presentation

http://mate.asfusion.com/forums/topic.php?id=598

http://www.slideshare.net/Antonos/mvc-pattern-flex-implementation-of-mvc-presentation

My humble contributions to this decision are the following sequence diagram for PureMVC and Cairngorm:


The Lazy Reference Accessor Pattern (example in ActionScript3)

When de-serializing objects from SQL storage, the references between the objects appear as foreign key values. Once each object is initialized with its data, one could immediately use the foreign key values to lookup the other objects and store references to them. Even if the objects do not have reciprocal or circular references, loading the types of objects in the correct sequence — target objects loaded before references to those targets — is fussy and creates a dependency between the schema and the loader. One can wait to do these lookups until after all of objects load, but that implies that one will load all objects.

If one goes a step further, the references can remain null until someone actually needs them. Moreover, an object can supply the foreign references (key values) without retrieving the referenced object at all. This can avoid performing the lookup at all even if the object is re-serialized (which requires those foreign key references).

The pattern stores both the reference to the object and the foreign key value that identifies the object (i.e. its key) and uses accessors and mutators to ensure that only one of the two values is active at a time. The referenced-object accessor do the actual lookup if the object reference does not already exist, and the foreign key mutator will store the new foreign reference key value and clear any existing reference object rather than doing a lookup immediately. Note that both mutators optimize by checking to see if the current value already matches the desired value.


<rant>

The optimization of checking to see if the current value already matches the desired value is common in Delphi classes; I don’t know why ActionScript3 classes do not do this as a Best Practice. The [Bindable] metatag’s implicit accessors and mutators do this sort of optimization; why not do it when coding by hand?

</rant>


private var _otherObjectId : uint = 0;
private var _otherObject : OtherObjectVO = null;
public function get otherObjectId () : uint
{
    if (_otherObject != null)
        return _otherObject.id;
    else
        return _otherObjectId;
}

public function set otherObjectId(value : uint) : void
{    // use the accessor, not the variable
    if (this.otherObjectId != value)
    {
         _otherObjectId = value;
        _otherObject = null;
    }
}

public function get otherObject() : OtherObjectVO
{
    if ((_otherObject == null) && (_otherObjectId != 0))
        _otherObject = goGetTheOtherObject(otherObjectId);

    return _otherObject;
}

public function set otherObject(value : OtherObjectVO) : void
{
    if(_otherObject != value)
    {
        _otherObject = value;
        _otherObjectId = 0;
    }
}

While the otherObject() accessor prevents unnecessary lookups during the object’s de-serialization, the otherObjectId() accessor prevents an unnecessary lookup at the end of an object’s life when it’s being serialized.

With objects that have many references that its client might not every need (e.g. configuration objects), the Lazy Reference Accessor pattern can eliminate unnecessary object loading, saving memory, time, and data access.

Where the Real Power Is

I am a manager for a team of developers. One might think that they work for me and I have power over them. I have a boss and so on. But if the real goal is to deliver the product or service of the organization, then the real power is with the people who do the work.

I learned from my father that the real power in an organization is the organization chart turned upside down, at least as far as “power” means actually producing something. It seems obvious when one thinks about it: boxes (people) on the organization chart connected to lots of other boxes are too busy maintaining those connections to do anything else.

So a rational organization rewards maangers that enable their direct reports to do their job better. In other words, my job as a manager is to serve my developers.

I serve them by making sure their computers work and that their chairs are comfortable and that they have the text editor they like and that they get lunch if I ask them to work through the day.

I serve them by making sure they understand their goals and restrictions and priorities. I serve them by removing obstacles from their way. I serve them by keeping my bosses away; my job is to answer their questions and make sure the rest of the company knows what we are doing.

Tech managers do not have to motivate or control staff. Developers want to work, and they want to deliver, and they love seeing their work in use. Managers need to get them on stage in front of the right audience and let them shine.

It Works On MY Machine

Joel’s 12-Point list, points 2 and 3 talk about building the application cleanly and regularly. He is talking about building it on a build machine. I emphasis this because, as a manager, I have to gently remind my happy minions that “it works on my machine” is more of a problem than an explanation.

If the coder is working on several different projects, they might find that some library for project A has a namespace collision with a library B. VMWare or the like is often a good solution: each project has their own environment. As the software is running on the same “machine”, installing it into each virtual environment seems like an ethical choice.

More likely, the coder has to solve the problem by making their development machine as stark and drear as the build machine, which inspires one to ask: Why did the coder tart up their machine? Most likely, the developer updated their libraries, either to the most recent version (so the build machine needs and update) or to a beta version (so the developer needs to Not Do That Anymore).

  • Plan and confirm updates to software and libraries across the whole development team, and don’t forget the build machines and the occasional coders (e.g. managers).
  • Name and version your internal libraries like you were selling and supporting them, because you will do the latter no matter what.
  • Embed as much application and library version information into your application’s bug reporting protocol (you do have one, right?) as you can.

Decoding Bug Reports

Defect Status Translations

What They Say What They Mean
Can Not Reproduce You’re an idiot
Duplicate You’re a lazy idiot
Reopened Dev testing is something that happens to other people, right?
As Designed You don’t understand the product
Test Case Error You don’t understand how to use the product
Redesign You have no human friends, do you?
Deferred It’s a stupid idea

Other Terminology

What They Say What They Mean
Thank you for your input Go Away
What I hear you saying is…. What I want you to say is…
No work on your part I’ve already committed you
I have tables and charts to back me up The truth is depressing
No more layoffs Attrition
We have full confidence in your judgement We haven’t found a replacement for you yet
Go as far as you can with this We have found a replacement for you
We’re all on board waaaay behind you
Can you live with this schedule? You do not have a choice either
I want to be fair We’re all screwed