<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html" />
  <link rel="self" type="application/atom+xml" href="http://www.insideria.com/atom.xml" />
  <id>tag:www.insideria.com,2009://34/tag:www.insideria.com,2008://34.33895-</id>
  <updated>2009-11-16T15:22:22Z</updated>
  <title>Comments for FrameworkQuest 2008  Part 2: Get Control with Cairngorm (http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2008://34.33895</id>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=33895" title="FrameworkQuest 2008  Part 2: Get Control with Cairngorm" />
    <published>2008-12-09T14:00:00Z</published>
    <updated>2009-03-13T14:41:35Z</updated>
    <title>FrameworkQuest 2008  Part 2: Get Control with Cairngorm</title>
    <summary>Carebear? Carhorn? What? Cairngorm is the Flex Framework with the odd name that&#8217;s been around almost since the beginning of Flex. It was created by a company called iteration::two, which went on to become Adobe Consulting&#8217;s European practice around the...</summary>
    <author>
      <name>Tony Hillerson</name>
      
    </author>
    
    <category term="Adobe Feed" />
    
    <category term="Features" />
    
    <content type="html" xml:lang="en" xml:base="http://www.insideria.com/">
      <![CDATA[<strong>Carebear? Carhorn? What?</strong>

<p><a href="http://opensource.adobe.com/wiki/display/cairngorm/Cairngorm" target="_blank">Cairngorm</a> is the Flex Framework with the odd name that&#8217;s been around almost since the beginning of Flex. It was created by a company called iteration::two, which went on to become Adobe Consulting&#8217;s European practice around the same time Adobe acquired Macromedia. These guys had been using Flex very early on, and were some of the first to talk about how important it was to building business applications. They even wrote <a href="http://www.amazon.com/Developing-Rich-Clients-Macromedia-Flex/dp/0321255666/" target="_blank">the first commercially available Flex book</a>, which helped to lend Cairngorm a lot of credibility when they released it soon after.</p>

<p>So what&#8217;s a Cairngorm? The <a href="http://en.wikipedia.org/wiki/Cairngorms">Cairngorms</a> are a mountain range in Scotland and <a href="http://en.wikipedia.org/wiki/Cairn_Gorm">Cairn Gorm</a> is one of the famous peaks in that range. It&#8217;s 4000 feet above sea level, which isn&#8217;t impressive on paper to a Colorado-an like me (we have 25 peaks over 14,000 feet, and 56 over 4000m, so nyah-nyah), but then again, we have a continent underneath us to prop things up a bit. I&#8217;d love to see the Cairngorms one day and I&#8217;m sure the highland beauty, if not the mass quantities of <a href="http://en.wikipedia.org/wiki/Lagavulin">Scotch Whisky</a>, would make a suitable impression. </p>

<p>So how do you pronounce it? Most people say &#8220;CAREn-gorm&#8221;, and some say &#8220;CARn-gorm&#8221; (for American English values of &#8220;care&#8221; and &#8220;car&#8221;). I have no idea, but I think the &#8220;car&#8221; version may be closer to the Scotch pronunciation.</p>

<p>If you'd like to learn more about Cairngorm, the <a href="http://opensource.adobe.com/wiki/display/cairngorm/Developer+Documentation">documentation is here</a>.</p>

<p>Now, back to Flex land, let&#8217;s see where we left off.</p>

<strong>Reviewing our Mess</strong>

<p>In the last episode of our series on Frameworks we looked at an AIR application created using Flex, but used no Flex framework. Here are a list of problems we hope to solve with a framework.</p>
<ol>
	<li></li>
	<li>1.    Poor Organization</li>
	<li>2.    Unstructured Application State</li>
	<li>3.    Bloated Views</li>
</ol>

<strong>MVC to the Rescue</strong>

<p>Many of you have heard of the concept of the Model/View/Controller architectural pattern. When we apply this pattern to an application, the code is separated into three general concerns - the Model, the View, and the Controller.</p>

<p>The Model is responsible for holding the state of the application, which means any information that the application could display, any information that the application needs to use to contact services, and any information about a particular session with a user, like where they are in the application. </p>

<p>The View is responsible for displaying the data in the model and informing the rest of the application about user interaction, such as the click of a button.</p>

<p>There are a few rules that MVC applies to the model and the view. One is that the model should not know about the view. That means that however the data gets from the model to the view, the model can&#8217;t be the one putting it there. Conversely, the view shouldn&#8217;t act directly on the model to change its state. Another rule is that the view shouldn&#8217;t know about the controller. It doesn&#8217;t have a reference to any part of the controller, so it can&#8217;t change anything about the controller directly.</p>

<p>That leaves The Controller to somehow respond to user interaction notifications from the view and inform the model appropriately, possibly changing the state of the model. Then through some mechanism that makes sense, the view is updated to reflect the new state of the model.</p>

<p>MVC was created to help keep business logic and view logic separate so that, theoretically, changes in the one don&#8217;t require changes in the other. The principles of MVC are going to show up in all the frameworks we discuss, so keep them in mind.</p>

<p>Now let&#8217;s look at how Cairngorm does things.</p>

<strong>Cairngorm: Dramatis Personae</strong>

<p>Cairngorm is described by Adobe Consulting as a microframework, or a set of patterns available to developers to assist in building an application. Here&#8217;s a normal flow of operations and the Cairngorm classes that are exercised.</p>

<p><img src="http://www.insideria.com/upload/2008/10/image002.jpg"/></p>

<p>When the user takes some sort of action on the view, such as clicking a button, the view dispatches a <strong>CairngormEvent</strong>. This event informs the <strong>FrontController</strong>, which instantiates a <strong>Command</strong>. The command executes the business logic, and the event is responsible for passing data to the command about the user interaction.</p>

<p>The command can either take some action on the <strong>Model</strong>, or instantiate and act on a Business Delegate. The <strong>Business Delegate</strong>, or delegate for short, wraps the code required for a service call, so it acts like the service API to the rest of the application. This is important because when the service changes, the changes to the application can be minimized and ideally only the delegate needs to change. The delegate calls the service and then depending on the kind of service involved makes sure that the command is informed when the service call has returned. Then the command changes the state of the model, if necessary, and the model, through Flex&#8217;s binding, updates the view.</p>

<p>That was a whirlwind tour, but if we look at some code I think it will become a little clearer.</p>

<strong>TwitteRIA on Cairngorm</strong>

<p>First we'll look at changes to the top-level application. The Script-block has changed to this:</p>

<strong>twitteria_cairngorm/src/twitteria_cairngorm.mxml #6-13</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
&lt;mx:Script&gt;
&lt;![CDATA[
     <span class="category1">import</span> com.insideria.twitteria.model.TwitteRIAModel;

     [Bindable]
     <span class="category1">private</span> <span class="category1">var</span> model:TwitteRIAModel = TwitteRIAModel.getInstance();
]]&gt;
&lt;/mx:Script&gt;</pre>
</code>

</div></div> 

<p>Now, all we do is get an instance to the model. The model instance is bindable so that the view can bind to properties on the model. I say the model because Cairngorm only has one. The code in the model goes as far as possible in ActionScript 3 to make sure that nothing can instantiate the model except the model's class. If you haven't seen a Singleton implementation in AS3, here our Model as an example. First, there's a private class variable to hold the singleton instance:</p>


<strong>twitteria_cairngorm/src/com/insideria/twitteria/model/TwitteRIAModel.as #10</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">static</span> <span class="category1">var</span> instance:TwitteRIAModel;</pre>
</code>

</div></div> 

<p>Then, since we can't have private constructors in AS3, the constructor doesn't allow any other class to call new TwitteRIAModel() unless it passes an instance of the Private class:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/model/TwitteRIAModel.as #27-31 (formatted)</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> TwitteRIAModel(access:Private) {
      <span class="category1">if</span> (access == <span class="category1">null</span>) {
            <span class="category1">throw</span> <span class="category1">new</span> 
                 CairngormError(
                       CairngormMessageCodes.SINGLETON_EXCEPTION,
                       "<span class="quote">XCLModelLocator</span>"
                 );
       }
}</pre>
</code>

</div></div> 

<p>which is defined on line 45, outside the package, making it virtually invisible outside of this file.</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/model/TwitteRIAModel.as #45</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">class</span> Private {}</pre>
</code>

</div></div> 

<p>And finally the getInstance method returns the instance, creating it if it hasn't already been created.</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/model/TwitteRIAModel.as #33-38</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">static</span> <span class="category1">function</span> getInstance():TwitteRIAModel {
      <span class="category1">if</span> (instance == <span class="category1">null</span>) {
            instance = <span class="category1">new</span> TwitteRIAModel(<span class="category1">new</span> Private());
       }
      <span class="category1">return</span> instance;
}</pre>
</code>

</div></div> 

<p>So much for Singletons. We'll have more to say about them later. Back to the Application. Now that we have the model to hold state for the application, we can point the ViewStack at the model.</p>

<strong>twitteria_cairngorm/src/twitteria_cairngorm.mxml #23-26 (formatted)</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
&lt;mx:ViewStack selectedIndex="<span class="quote">{model.mainViewIndex}</span>"&gt;
     &lt;view:LoginView id="<span class="quote">loginView</span>" /&gt;
     &lt;view:MainView id="<span class="quote">mainView</span>" /&gt;
&lt;/mx:ViewStack&gt;</pre>
</code>

</div></div> 

<p>Also note that the LoginView and MainView here no longer share the username and password between them, nor does the LoginView inform the Application of the login event. We'll get to how those changed in a moment. For now, there's one last important line on the Application:</p>

<strong>twitteria_cairngorm/src/twitteria_cairngorm.mxml #15</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
&lt;controller:TwitteRIAController id="<span class="quote">controller</span>" /&gt;</pre>
</code>

</div></div> 

<p>The Cairngorm FrontController needs to be instantiated early in the application's lifecycle, and that's generally done by defining it in MXML right in the root application. Another thing that's usually instantiated alongside the controller is the ServiceLocator, which is generally a file that defines any services the application accesses to keep them all in the same place. Since our application doesn't use the normal HTTPService or RemoteObject you usually see in a Cairngorm application, we don't use the ServiceLocator.</p>

<p>The Controller, as mentioned above, is what takes care of capturing dispatched CairngormEvents and instantiating and executing the corresponding commands. You never actually interact directly with the controller in code, but you do wire up events to commands there, as shown here:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/controller/TwitteRIAController.as #13-17 (formatted)</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> <span class="category2">initialize</span>():<span class="category1">void</span> {
      addCommand(
           LogInEvent.LogIn_Event, LogInCommand);
      addCommand(
           LoadTimelineEvent.LoadTimeline_Event, LoadTimelineCommand);
      addCommand(
           SetStatusEvent.SetStatus_Event, SetStatusCommand);
}</pre>
</code>

</div></div> 

<p>Now whenever, for instance, a LogInEvent is dispatched, the FrontController instantiates a LogInCommand and executes it.</p>

<strong>Logging In</strong>

<p>Now lets look at logging in. Where before we just had the LoginView&#8217;s username and password bound to the MainView, we&#8217;re going to take a more scalable approach this time. What we really want is to keep the username and password around so that we can access them from anywhere we need them. That&#8217;s what the model is for. Now look at the LoginView&#8217;s login method, which before emitted an event:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/view/LoginView.mxml #7-9</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> login():<span class="category1">void</span> {
      <span class="category1">new</span> LogInEvent(usernameText.<span class="category2">text</span>, passwordText.<span class="category2">text</span>).dispatch();
}</pre>
</code>

</div></div> 

<p>Now the method dispatches a LogInEvent, which holds a username and a password. When it&#8217;s dispatched with its own dispatch method, the LogInCommand is instantiated and executed, with the event passed along.</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/command/LoginCommand.as #13-19</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> execute(event:CairngormEvent):<span class="category1">void</span> {
      <span class="category1">var</span> evt:LogInEvent = event as LogInEvent;
      model.username = evt.username;
      model.<span class="category2">password</span> = evt.<span class="category2">password</span>;
      model.mainViewIndex = TwitteRIAModel.MAIN_VIEW;
}</pre>
</code>

</div></div> 

<p>After setting the username and password properties on the model to the values on the event, the command changes the mainViewIndex property to the MAIN_VIEW constant on the model. If you remember, the ViewStack in the application had its index bound to model.mainViewIndex.</p>

<strong>twitteria_cairngorm/src/twitteria_cairngorm.mxml #23 (formatted)</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
&lt;mx:ViewStack selectedIndex="<span class="quote">{model.mainViewIndex}</span>"&gt;</pre>
</code>

</div></div> 

<p>The constants on the model help give some idea what they are used for:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/model/TwitteRIAModel.as #16-19</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">static</span> const LOGIN_VIEW:int  = 0;
<span class="category1">public</span> <span class="category1">static</span> const MAIN_VIEW:int   = 1;
[Bindable]
<span class="category1">public</span> <span class="category1">var</span> mainViewIndex:int        = LOGIN_VIEW;</pre>
</code>

</div></div> 

<p>So when the LoginCommand changes the mainViewIndex to MAIN_VIEW, the ViewStack changes to show MainView.</p>

<p>There are two examples of how the Cairngorm model holds both application state and view state. You also see can see an example of how a Cairngorm command is tasked with a specific responsibility, in this case setting credentials and making sure the view state matches the logged in view - basically taking care of what needs to be done to log in, just like the command name leads you to believe. In this way the commands and FrontController together make up the Controller part of MVC for Cairngorm.</p>

<p>I like that about Cairngorm. If you want to know how the app works and where that work is done, you just need to look through the command directory and see a list of descriptive verbs that tell you what takes place and what class does it.</p>

<strong>Loading the Timeline</strong>

<p>Now let&#8217;s look at how we load the timeline. Again, when the MainView&#8217;s creation is complete, the init method is called:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/view/MainView.mxml #14-16</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> <span class="category2">init</span>():<span class="category1">void</span> {
      <span class="category1">new</span> LoadTimelineEvent().dispatch();
}</pre>
</code>

</div></div> 

<p>Instead of doing any work inside the MainView, like we did before, now we dispatch a CairngormEvent that loads the timeline. That event corresponds to the LoadTimelineCommand.</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/command/LoadTimelineCommand.as #16-20</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> execute(event:CairngormEvent):<span class="category1">void</span> {
      <span class="category1">var</span> evt:LoadTimelineEvent = event as LoadTimelineEvent;
      <span class="category1">var</span> delegate:TwitterDelegate = <span class="category1">new</span> TwitterDelegate(<span class="category1">this</span>);
      delegate.loadTimeline();
}</pre>
</code>

</div></div> 

<p>The execute method doesn&#8217;t do that much, in fact it delegates responsibility to the TwitterDelegate. If you remember, delegates are the guys that wrap the service API and cushion the rest of the app from changes to the services. All we need to know here is that the delegate will load the timeline, and we ask it to do so.</p>
 
<p>I should make a note here that I&#8217;m breaking a bit with Cairngorm convention. Generally Cairngorm has you define one delegate for each event/command pair. That gets a little chunky for my taste, and instead I usually define one delegate for every resource I&#8217;m accessing on the service side. For instance if I had a user service with an API for creating, updating, deleting, getting a user, and getting all users, I&#8217;d have one delegate for users which would have methods to execute each of those operations. Again, this is not Cairngorm convention, this is my way of doing things. It&#8217;s not like I&#8217;m hurting Cairngorm, though, and it shows that the framework is flexible enough to meet your needs, or in this case, a matter of taste.</p>

<p>Let&#8217;s look at the delegate. In the constructor you can see more characteristic Cairngorm code:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/business/TwitterDelegate.as #20-21</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> TwitterDelegate(responder:IResponder) {
      <span class="category1">this</span>.responder = responder;</pre>
</code>

</div></div> 

<p>Notice how the argument to the constructor isn&#8217;t a Command, but an IResponder. That interface is part of the mx.rpc package that ships with Flex, and it describes two methods - result and fault. Cairngorm makes use of this interface for commands that are asynchronous, which means that they &#8220;fire and forget&#8221; calls off to the service, and expect to be called back when the service returns from the call. If you&#8217;ve been around Flex and Flash for any length of time, you know that just about everything follows this pattern of callbacks. In this case Cairngorm designed delegates to take an object that has a method, result, to callback when a service returns with a result, and fault, a method to call back if something goes wrong. It doesn&#8217;t care how that happens in the delegate or service, and the command implementing IResponder doesn&#8217;t need to know either. It just needs to know if the call worked or didn&#8217;t, and then act accordingly. The responder is set into a private property for later use.</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/business/TwitterDelegate.as #23-25 (formatted)</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
twitterService = <span class="category1">new</span> Twitter();
twitterService.setAuthenticationCredentials(
     model.username, model.<span class="category2">password</span>
);
twitterService.addEventListener(
     TwitterEvent.ON_FRIENDS_TIMELINE_RESULT,
     friendsTimelineLoaded
);</pre>
</code>

</div></div> 

<p>Next, the delegate creates an instance of Twitter, sets the credentials to the username and password the LoginCommand stored on the model, and registers some callbacks on the twitter service. Most times you&#8217;ll see RemoteObjects or HTTPServices inside delegates and things look a little different than you see here. RemoteObjects call AMF services, and they know how to deal with responders. Luckily though, the delegate is flexible enough to deal with our situation where we need to instantiate and set up the service right here.</p>

<p>Once the callbacks for each type of Twitter service call, a call of that type should call back to the method in the delegate. When we ask for the timeline, callbacks should go to the friendsTimelineLoaded method:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/business/TwitterDelegate.as #49-51</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> friendsTimelineLoaded(te:TwitterEvent):<span class="category1">void</span> {
      responder.result(te.<span class="category2">data</span> as <span class="category2">Array</span>);
}</pre>
</code>

</div></div> 

<p>And that method just calls the result method on the responder with the timeline data it gets from Twitter. This is clean, because now the command doesn&#8217;t need to know anything about the Twitter class or the TwitterEvent that comes back, it just needs to know about an array of tweets that comes to the result method.</p>

<p>By the way there&#8217;s no fault thrown from Twitterscript, so the fault method isn&#8217;t going to ever be called, but you can imagine how it would be if there were.</p>

<p>Now, when the command calls loadTimeline, the delegate does this:</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/business/TwitterDelegate.as #29-38 (formatted)</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> loadTimeline():<span class="category1">void</span> {
      <span class="category1">if</span> (useDummyData) {
            <span class="category1">var</span> te:TwitterEvent = <span class="category1">new</span> TwitterEvent(
                 TwitterEvent.ON_FRIENDS_TIMELINE_RESULT
            );
            te.<span class="category2">data</span> = getDummyData();
            friendsTimelineLoaded(te);
       } <span class="category1">else</span> {
            twitterService.loadFriendsTimeline(model.username);
       }
}</pre>
</code>

</div></div> 

<p>And there&#8217;s our old friend, the dummy data. Although this still isn&#8217;t what I&#8217;d call a good way of choosing which data to load, real or fake, at least it&#8217;s all sectioned off into the delegate and no one else needs to know how it&#8217;s done. That&#8217;s called encapsulation, and just like when the delegate wraps the service, it cushions the rest of the application from change.</p>

<p>When LoadTimelineCommand finally gets result called, it creates a new ArrayCollection to wrap the array of tweets and places it on the model.</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/command/LoadTimelineCommand.as #22-25</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> result(result:<span class="category2">Object</span>):<span class="category1">void</span> {
      <span class="category1">var</span> stati:<span class="category2">Array</span> = result as <span class="category2">Array</span>;
      model.currentTweets = <span class="category1">new</span> ArrayCollection(stati);
}</pre>
</code>

</div></div> 

<p>That&#8217;s a very Cairngorm like sequence, there. Command calls delegate, delegate calls service, service returns to delegate (or sometimes straight to command), and then on to result, which changes something on the model. Then Flex binding takes over and modifies the view.</p>

<strong>twitteria_cairngorm/src/com/insideria/twitteria/view/MainView.mxml #32</strong>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
dataProvider="<span class="quote">{model.currentTweets}</span>"</pre>
</code>

</div></div> 

<p>Since the list in the main view is bound to the model&#8217;s currentTweets property, it will reset itself to show the new list. Slick!</p>

<strong>Setting Status</strong>

<p>There&#8217;s not a lot to show for setting status, since everything works pretty much the same. In fact, that&#8217;s something you can get used to with Cairngorm - if you want to know what happens because of a user interaction, find the command that gets executed and you&#8217;ll probably learn everything you need to know about what goes on. If not, you can follow back to the delegate, but the command does the bulk of the heavy lifting on the client side. Here&#8217;s SetStatusCommand&#8217;s execute:</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> execute(event:CairngormEvent):<span class="category1">void</span> {
      <span class="category1">var</span> evt:SetStatusEvent = event as SetStatusEvent;
      <span class="category1">var</span> delegate:TwitterDelegate = <span class="category1">new</span> TwitterDelegate(<span class="category1">this</span>);
      delegate.setStatus(evt.statusText);
}</pre>
</code>

</div></div> 

<p>and result:</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;">
<code language="perl">
<pre>
<span class="category1">public</span> <span class="category1">function</span> result(result:<span class="category2">Object</span>):<span class="category1">void</span> {
      <span class="category1">new</span> LoadTimelineEvent().dispatch();
}</pre>
</code>

</div></div> 

<p>Notice how we have to dispatch the LoadTimelineEvent from the result? That&#8217;s one thing that some other frameworks try to work around. This command&#8217;s responsibility is telling Twitter what sweet new <a href="http://icanhascheezburger.com/">lolcat</a> picture we just posted or <a href="http://www.youjustgotrickrolled.com">trojan-linking in a Rick Astley</a> video, not loading the timeline, but now we&#8217;ve tied this command up with loading the timeline. We could have had the MainView dispatch the next event if we somehow alerted the view to the fact that the status had been set, but that&#8217;s a little iffy too. In any case, the next thing that needs to happen when the status is set is to reload the timeline, so we do it here, and that&#8217;s all we need to do.</p>

<p>Keep that in mind for when we move on to other frameworks, because we&#8217;re out of time for today. You&#8217;ve seen how we&#8217;ve used Cairngorm&#8217;s CairngormEvents, the command pattern, delegates, and a singleton model to clean things up considerably from where we left things off last time. Next time we&#8217;ll see another framework that aims to clean some of the framework code out of the view, and rebuild our application using PureMVC.</p>

<p style="padding-top: 15px; border-top: 1px solid #ccc;">Read the rest of FrameworkQuest 2008: 

<ul>

<li><a href="http://www.insideria.com/2008/12/frameworkquest-2008-introducti.html" target="_blank">Part 1 - Introduction</a></li>
<li>Part 2 - Get Control with Cairngorm</li>
<li><a href="http://www.insideria.com/2008/12/frameworkquest-2008-part-3-fra.html" target="_blank">Part 3 - Framework Agnostic Views with PureMVC</a></li>
<li><a href="http://www.insideria.com/2008/12/frameworkquest-2008-part-4-ioc.html" target="_blank">Part 4 - loC with Swiz</a></li>
<li><a href="http://www.insideria.com/2008/12/frameworkquest-2008-part-5-mat.html" target="_blank">Part 5 - Mate, the Pure MXML Framework</a></li>
<li><a href="http://www.insideria.com/2009/01/frameworkquest-2008-part-6-the.html" target="_blank">Part 6 - The Exciting Conclusion</a></li>
</ul></p>
<p  style="border-bottom: 1px solid #ccc; padding: 15px 0;"></p>]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2048481</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2048481" />
    <title>Comment from Alistair McLeod on 2008-12-09</title>
    <author>
        <name>Alistair McLeod</name>
        <uri>http://weblogs.macromedia.com/amcleod/</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://weblogs.macromedia.com/amcleod/">
        <![CDATA[<p>Hi Tony,</p>

<p>I presented on Cairngorm at Max Milan, showing Adobe Consulting's latest best practices in using the microarchitecture.</p>

<p>In particular, I spoke about the Presenttation Model pattern, which addresses a few of your comments, including how views get notified that data is now available from the service call. Its a lot cleaner than dispatching events from the result handler.</p>

<p>I've blogged about it here, with a link to the slide deck:</p>

<p><a href="http://weblogs.macromedia.com/amcleod/archives/2008/12/max_milan_-_fle.html">http://weblogs.macromedia.com/amcleod/archives/2008/12/max_milan_-_fle.html</a></p>]]>
    </content>
    <published>2008-12-09T15:27:05Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2048487</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2048487" />
    <title>Comment from Jonathan on 2008-12-09</title>
    <author>
        <name>Jonathan</name>
        <uri>http://www.jadbox.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://www.jadbox.com">
        <![CDATA[<p>Good article about Cairngorm, but I have honestly felt that it's very bloated of a solution for most applications.</p>

<p>I have spent a lot of time over the past two years developing flashMVC that's really easy to implement and grow with your application:<br />
<a href="http://www.jadbox.com/flashmvc/">http://www.jadbox.com/flashmvc/</a></p>

<p>Send me any feedback if you can.</p>]]>
    </content>
    <published>2008-12-09T16:17:14Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2048488</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2048488" />
    <title>Comment from Alistair McLeod on 2008-12-09</title>
    <author>
        <name>Alistair McLeod</name>
        <uri>http://weblogs.macromedia.com/amcleod/</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://weblogs.macromedia.com/amcleod/">
        <![CDATA[<p>Hi Tony,</p>

<p>Another couple of comments on your piece:</p>

<p>You said:</p>

<p><i>Generally Cairngorm has you define one delegate for each event/command pair. That gets a little chunky for my taste, and instead I usually define one delegate for every resource I’m accessing on the service side. For instance if I had a user service with an API for creating, updating, deleting, getting a user, and getting all users, I’d have one delegate for users which would have methods to execute each of those operations.</i></p>

<p>I don't think we've ever advocated one delegate per event/command pair - we advocate exactly what you have done - one delegate for each different type of service. So, we might have a UserDelegate with login(), logout() and changePassword() and a TransactionDelegate with getTransactions(), addTransaction and updateTransaction() etc.</p>

<p>Also, although a lot of the Cairngorm examples out in the wild use the command as the service responder, and the command then updates the model, this isn't what we advocate. We create specific responder class instances, which then pass the data back to our presentation model to handle; the command should not be coupled to the model.</p>

<p>Similarly, although Cairngorm does have a ModelLocator class, we don't advocate a single model unless your application is so small that it probably doesn't necessitate a framework in the first place; doing so is an abhorrent act in my eyes. The ModelLocator is very light, and is used to locate your fully typed domain model objects, such as UserVO, AccountList etc.</p>

<p>View specific model information is stored on PresentationModel objects.<br />
We also wouldn't hold view state on the ModelLocator - we store that in the Presentation Models that are responsible for a particular view. </p>

<p>Again, this above is what i covered in my talk in Milan in the Cairngorm Myths and Anti-Patterns section.</p>]]>
    </content>
    <published>2008-12-09T16:34:13Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2048497</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2048497" />
    <title>Comment from Tony Hillerson on 2008-12-09</title>
    <author>
        <name>Tony Hillerson</name>
        <uri>http://thillerson.blogspot.com</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://thillerson.blogspot.com">
        <![CDATA[<p>@Alistair - Thanks for calling that out. It sounds like some of the Cairngorm patterns I'm used to are a little old. Thanks a lot for posting the link.</p>]]>
    </content>
    <published>2008-12-09T17:42:41Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2048540</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2048540" />
    <title>Comment from Jon Toland on 2008-12-09</title>
    <author>
        <name>Jon Toland</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>Great series!!!  I'm reasonably familiar with PureMVC so this was quite enlightening.  I'm most expectant however to hear how you feel Swiz stacks up to Mate which I want to use in my next project!</p>]]>
    </content>
    <published>2008-12-10T03:33:23Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2048619</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2048619" />
    <title>Comment from Ansury on 2008-12-10</title>
    <author>
        <name>Ansury</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>"Also, although a lot of the Cairngorm examples out in the wild use the command as the service responder, and the command then updates the model, this isn't what we advocate. We create specific responder class instances, which then pass the data back to our presentation model to handle; the command should not be coupled to the model."</p>

<p>Gah, my examples are dated or wrong too.  They need to be fixed...  So are there any better example(s) out there?  I've never heard of a PresentationModel, either.  I guess I'm outdated or was misinformed here.</p>]]>
    </content>
    <published>2008-12-11T00:05:37Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2048956</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2048956" />
    <title>Comment from J on 2008-12-15</title>
    <author>
        <name>J</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>Read his blog post about it:</p>

<p><a href="http://weblogs.macromedia.com/amcleod/archives/2008/12/max_milan_-_fle.html">http://weblogs.macromedia.com/amcleod/archives/2008/12/max_milan_-_fle.html</a></p>

<p>There are links to other various talks, etc etc,</p>]]>
    </content>
    <published>2008-12-16T02:56:15Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2008://34.33895-comment:2156913</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2008://34.33895" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html"/>
    <link rel="alternate" type="text/html" href="http://www.insideria.com/2008/12/frameworkquest-2008-part-2-get.html#comment-2156913" />
    <title>Comment from Jump Manual on 2009-10-26</title>
    <author>
        <name>Jump Manual</name>
        <uri>http://thejumpmanual.blogspot.com/2009/07/jump-manual-comprehensive-and-honest.html</uri>
    </author>
    <content type="html" xml:lang="en" xml:base="http://thejumpmanual.blogspot.com/2009/07/jump-manual-comprehensive-and-honest.html">
        <![CDATA[<p>Very great debate going here. I good post about Cairngorms, i have been there and would want to go there again.  </p>]]>
    </content>
    <published>2009-10-26T17:11:29Z</published>
  </entry>

</feed
