Cairngorm was my first framework when I begin with RIA development. Probably his difficult name and the tight support of Adobe help in his early adoption. Cairngorm was borrowed from J2EE and has been in use now for a decade (since 2002) His rules are easy to follow, but probably was overkilling for many of the small applications at that time. As far as RIA becomes more complex, his benefits arise.
But before talking about the Cairngorm arquitecture, is important to note that the last version of Cairngorm, formally Cairngorm 3 becomes a collection of good practices, some libraries and a agnostic use of IoC (Inversion of control) even on top of other frameworks like Parsley or Swiz, If you don’t have previous experience with the framework probably you become confuse in how to design your application. Since all the practices encouraged by the last version are well proven and useful, I based this review on Cairngorm 2, since practices there are more prescriptive and easy to follow. Once you have the taste, then you’re free of moving to version 3 and expand your howizon.
You can download the demo application from here
You can see the running application here (select framework you’re working on for multiple choice)
Basics
Cairngorm encourages separation of concerns
- Model holds data objects and the state of the data
- Controller process business logic
- Views render data and announce gestures with events
- Views communicate with Controller using events
- Views watch Model with data bindings
- Views are graphical user interfaces or visual portions of the Flex application.
- Views usually are composites of UI controls or other views.
- Views can contain child views
- Even <mx:Application /> is a view
Classes holding the basics
We can summarize the important classes holding functionality like this:
- ModelLocator is a Singleton holding global data for global access. It does not persist data to a permanent data store by itself and does not contain business logic
In our example application the ModelLocator is the QuizModel and have array of questions but also a reference to the current user and the view state, all of them bindable and used trough the views. Here’s the list of elements on our model
public class QuizModel
{
private static var modelLocator : QuizModel;
public var questions:ArrayCollection;
[Bindable]
public var currentQuestion:Question;
[Bindable]
public var title:String;
[Bindable]
public var total:int;
[Bindable]
public var currentUser:User;
[Bindable]
public var viewState:String;
- Services is a repository of Remote Data Services around the Application (HTTPService, Webservices, Remote Object or any external service you use) A singleton named ServiceLocator create a registry to centralize the external resources used, and support simple lookup of services by name
In our example application we simulate a remote object and the LoginDelegate just return an hardcoded success, but implement a real service is trivial (in fact the code is commented)
public class LoginDelegate
{
private var responder : IResponder;
private var service : Object;
public function LoginDelegate( responder : IResponder )
{
//Currently just a Mockup, if this is a real service you want to uncoment next line
//this.service = ServiceLocator.getInstance().getRemoteObject( "LoginService" );
this.responder = responder;
}
- Commands are non visual components that process business logic and respond to business events. Each Command class represents a specific business feature with
associated business logic and processing. All commands have the same entry point, the execute method. Usually command names represent business logic, and modify the data in ModelLocator
In our example we use just two commands, LoginCommand and NextQuestionCommand, but in a more complex application you can have a long list
- Events are custom events that triggers commands to start the business logic. They use the Event Delegation Pattern where responses and reactions in a component are delegated to one or more different components. The delegation is achieved by dispatching events. Custom events are used to package data and to trigger commands in the business layer
Is advisable to use different class of events for different business logic, but sometimes the list can become very long. I.e you can use a LoginEvent with success and fail, or you can use a type of LoginEvent with a value of “success” and “fail”.
- Controller route business events to commands for processing, is a kind of registry of event-to-command. FrontController pattern provides a solution that allows the View
and Control layers to connect using event delegation
Our controller maps just two commands, but again, could be a long list
public function initialiseCommands() : void
{
addCommand( LoginRequest.LOGIN_REQUESTED, LoginCommand );
addCommand( QuizEvent.USER_SELECTION, NextQuestionCommand );
}
- Views are used to render data stored in the Model layer and announce user gestures. Views are never aware of the FrontController, Commands, or Delegates, or the Services repository
In the example we use three views: LoginForm, QuizView and Result, each one in a state of the main Application
Highligths
- Cairngorm is easy to follow with clear rules in how to build your application. My last Cairngorm app was from some years ago, but takes me only 15 minutes to recall the basics reading the documentation.
- The Quiz application need a lot of changes to be adapted. In example from Swiz to Parsley classes remains almost the same, here many aditional classes were created
- Caingorm don’t use metatags as other frameworks do, his core resides in pure ActionScript classes
- Extensively binding is comfortable with Cairngorm and the Singleton Model holds almost all the data you want to show
- Naming convention is very important. In a medium size CRUD application probably you will end with 30-50 commands to manage your database, so if you are no clear in your names, chaos is a chance
- The same is valid for events and even Value Objects … if you need to see the source code to remember a member functionality, probably it has a bad name.
- Cairngorm is better suited for medium to large application. For simple ones probably is overkilling and not neccesary.
- Adobe continue to support Cairngorm as the best practice for Flex development … but IoC have become so popular (and useful) that the version 3 advice to use it even trough other frameworks on top of Cairngorm
For further reading you can check http://sourceforge.net/adobe/cairngorm/home/