Accessibility

Table of Contents

An architectural blueprint for Flex applications

A word on interfaces

Why would you use an interface for the Controller and Services? Many developers struggle with the question of when interfaces are appropriate. Here are some of the main reasons to use interfaces:

  • An implementation class that plays multiple roles in a system may contain more public methods than one wishes to expose to any other single object. Interfaces allow a class to present one or more independent "faces" to the world, each of which is limited to the relevant functions and properties.
  • It may be impossible to identify a common superclass for all possible subclasses that could play some role. In this case, an interface is the only way to avoid requiring inheritance from a specific superclass.
  • Interfaces function as "requirements" in a way that superclasses do not, in that the compiler will complain if an interface contract is not fully implemented. When handing off work to other parties, this aspect of interfaces can be helpful.
  • It's often useful to develop a simple mock implementation of an interface for prototyping and testing, and later swap in a real one (possibly developed by someone else in the meantime).

One often sees "interface-ridden" code, where too many interfaces are actually getting in the way and providing little in the way of actual value. If the above factors are present (or are likely to be), use an interface; if they're not, maybe you shouldn't!

For example, the IController interface allows you to instantly swap in a mock controller implementation with no change to the rest of the application. Much of ReviewTube was actually developed using just such a mock IController, allowing me to work on the View and Model parts of the application even before the server side existed. A MockController class is included in the source as a simple example of this technique.

The MediaService and CommentService are exposed via interfaces, which makes it very easy to create new implementations while remaining sure that all the Controller's needs are met. If one wanted to expose other video providers besides YouTube and choose between them at runtime, it would be a piece of cake: Simply create alternate implementations of IMediaService and make use of the right one at the right time.

Tips on managing and configuring singletons

ReviewTube has a number of singletons: classes of which a single dedicated instance exists in the application. Prime examples are Session, Controller, MediaService, and CommentService, which are referenced globally from across the application.

Many of these singletons implement specific interfaces. In keeping with the whole point of using interfaces, other parts of the code should see our singletons typed as those very interfaces, typed as actual classes that implement them. For instance, when the rest of the application gets hold of the Controller, its type should be IController.

ReviewTube also needs to configure these instances by specifying their concrete classes and initial property values. What's needed is a convenient way for the developer to be able to provide these class names and values without writing a bunch of custom code—say, an XML file. (In the Java world, the popular Spring Component Framework is an example of this kind of thing.)

There's a neat way to do this in a Flex application, using a two different source files. The first is an ActionScript class named Components that exposes a static instance property. In it, one declares a property with an interface type for every globally accessible component, for instance:

package com.joeberkovitz.reviewtube.services
{
    [Bindable]
    public class Components extends UIComponent
    {
        /** Reference to singleton instance of this class. */
        private static var _instance:Components;
        
        public var controller:IController;
        
        public var mediaService:IMediaService;
        public var commentService:ICommentService;
        public var session:Session = new Session();
        
        public function Components()
        {
            super();
            _instance = this;
        }
        
        [Bindable("instanceChanged")]
        public static function get instance():Components
        {
            return _instance;
        }
    }
}

It's clear that other places in the code can refer to or bind to Components.instance.session, or Components.instance.controller to obtain references to the properties of Components.

A subclass of Components provides the actual definitions of these objects, however, in ReviewTubeComponents.mxml. As you can see, MXML is a really nice language for configuring classes and properties:

<!-- Services/Controller configuration file for ReviewTube -->

<Components
  xmlns="com.joeberkovitz.reviewtube.services.*"
  xmlns:model="com.joeberkovitz.reviewtube.model.*"
  xmlns:mx="http://www.adobe.com/2006/mxml"
  xmlns:controller="com.joeberkovitz.reviewtube.controller.*">

    <YouTubeMediaService id="mediaService"
        urlPrefix="http://www.youtube.com/"
        developerId="[YOUR DEVELOPER ID HERE]"/>
    <CommentService id="commentService"
        urlPrefix="http://rt.morrisalumni.com/flex/"/>
    <controller:Controller id="controller"
        mediaService="{mediaService}" commentService="{commentService}"/>
</Components>

This MXML subclass is just what is needed: A nice XML file that sets up all of our singletons, declaring their classes and properties. Note that the id attributes of the various objects declared here correspond to the property names in the Components superclass. Now all one has to do is stick a <ReviewTubeComponents/> element somewhere in the top-level application and all this work is done.

Be careful with singletons

Singletons are very handy access points for information that needs to be globally exposed. But they can be easily abused. It's convenient to add new properties and functions to singletons, when you want to pass information around in your program. Pretty soon, your singleton objects become ugly global grab bags.

Here are some tips:

  • Every time you want to add a new singleton, or add a property to an existing one, ask the question: "could there ever be more than one of these, in this project's lifetime?" If the answer is yes, then you're heading down the wrong path. You should be passing the information around some other way, from caller to callee or from container to child.
  • Keep singleton objects small enough that every property and function clearly belongs there. Split them up if they get too big (the Controller object in ReviewTube is a good candidate.) Coherent singletons make it obvious when the "grab bag" syndrome is starting to manifest itself.
  • Maintain as few singletons as possible.

Where to go from here

In this article, I've described the MVCS architecture, which is a large-scale set of organizing principles that can guide and shape a Flex application as it develops, delivering a number of clearly stated goals. Paramount among these goals was the isolation of concerns regarding state, presentation, action, and communication; correspondingly, this isolation is the cornerstone of MVCS.

Although there is some cost in terms of planning and overhead, I have seen this approach return the investment many times over. It's easy to prototype your project even with huge pieces missing. It's easy to change the code with limited ripple effects. It's easier to break up the work into multiple parallel tasks—the resulting View and Model layers are simpler.

Now the accompanying ReviewTube application is my attempt to illustrate in the most concrete possible way how this architecture actually works in a real-life situation. However, MVCS is not a framework. Nor is it a hard-edged specification for specific classes and APIs. Rather, it is an architectural viewpoint, with many possible ways to apply it and to adapt it. ReviewTube shows us one such realization. In our development work at Allurent, we use a different and more complex flavor of MVCS that permits much of the code to be automatically generated from a master model description.

I recommend examining many diverse frameworks such as Cairngorm 2.0, Java Server Faces, and ARP. The rich design pattern literature abounds in ideas and examples. It's all great fodder for us, the developers and architects. Take the best, but be prepared to discard anything that you cannot successfully convince yourself is helpful.

I want to demonstrate a certain attitude toward building complex applications: The attitude that one can find, compare, and rationally select architectures that are "worth it." You can tell when an architecture is worthwhile because it simplifies the entire development process and makes it easy to construct and evolve a complex project. Here's to uncovering many more of those!