Getting Started with Cairngorm – Part 5

November 30th, 2007

In Part 4 you saw the full Service to Worker pattern demonstrated. However, the method discussed in the last tutorial doesn't fit every situation. In this tutorial you will learn a few "best-practices" for Cairngorm projects as well as an extension to the Service to Worker pattern for more complex cases.

Delegates, Commands, and Responders

These classes (Delegates, Commands, and Responders) have specific responsibilities. Many developers run into problems when they do not adhere to these responsibilities. The following tips are guidelines for your code.

  • Responders - Responders should deal only in strongly-typed application objects. Responders may set values on the model.
  • Commands - Commands never deal directly with server interaction. Commands may set values on the model.

  • Delegates - Delegates should pass strongly typed strongly-typed application objects to the Responder. If the Delegate doesn't receive strongly-typed application objects, it must parse and convert the data into that format.

Cairngorm Delegate Data Diagram

Figure 1 - Data Transmission in the Service to Worker Pattern

The goal of this separation of responsibility is that services should be able to be switched out with only a change in the delegate. This may sound a bit unimportant, but if you are working for a large company, the server-side implementation can change drastically from development to production. For this to work properly, the service call will need to have two responders: the Delegate, and the actual Responder. Figure 1 illustrates this separation. The data passed from the service to the delegate can be in virtually any format, but the transfer from the Delegate to the Responder needs to only be application data (VO's, model classes).

In this case, the Delegate now has an added responsibility, parsing the raw data. To accomplish this, you can create a factory class to parse the data. In the sample below the class DeliciousFactory (because it parses data from a Del.icio.us feed) has a method buildPostArrayFromJSON which handles this responsibility.

Actionscript:
  1. package net.davidtucker.deliciousbrowser.business {
  2.    
  3.     import com.adobe.cairngorm.business.ServiceLocator;
  4.    
  5.     import mx.rpc.AsyncToken;
  6.     import mx.rpc.IResponder;
  7.     import mx.rpc.events.FaultEvent;
  8.     import mx.rpc.events.ResultEvent;
  9.     import net.davidtucker.deliciousbrowser.factories.DeliciousFactory;
  10.    
  11.     public class PostsDelegate {
  12.        
  13.         private var responder:IResponder;
  14.         private var service:Object;
  15.        
  16.         public function PostsDelegate( responder:IResponder ) {
  17.             this.responder = responder;
  18.             this.service = ServiceLocator.getInstance().getHTTPService( "sampleService" );
  19.         }
  20.        
  21.         public function getRecentPosts():void {
  22.            
  23.             // Call the Service and Attach that call to an AsyncToken
  24.             var token:AsyncToken = service.send(params);
  25.                
  26.                // Create a Responder for the call
  27.                var responder:mx.rpc.Responder = new mx.rpc.Responder(onResult, onFault);
  28.  
  29.                // Add the Responder to the AsyncToken
  30.                token.addResponder(responder);
  31.            
  32.         }
  33.        
  34.         private function onResult( e:ResultEvent ):void {
  35.            
  36.             // Parse JSON into Array of VO's
  37.             var posts:Array = DeliciousFactory.buildPostArrayFromJSON( e.result as String );
  38.            
  39.             // Pass VO Array to Responder
  40.             responder.result( new ResultEvent( ResultEvent.RESULT, false, true, posts ) );
  41.            
  42.         }
  43.        
  44.         private function onFault( e:FaultEvent ):void {
  45.             ...
  46.         }
  47.        
  48.     }
  49. }

Code Example 1 - A Delegate Parsing Raw Server Data

Parsing the server data is only a part of this extended design pattern. For this to work properly with the traditional Cairngorm flow, the delegate must "intercept" the result of the service call. To accomplish this, you will attach an AsyncToken [Reference] to the service call, create a responder for the call, and then attach the responder to the AsyncToken. This is illustrated in lines 23-30 of Code Example 1.

Now that the delegate has "intercepted" the result of the service call, it need to have methods to parse the data. When you created the responder inside of the delegate (line 27 of Code Example 1), you passed in a result and fault method. In this case it was onResult and onFault. You now need to add these methods to the delegate.

To pass the parsed data to the original responder, you will need to create a new instance of the ResultEvent [Reference] with the parsed data in the result property (line 40 of Code Example 1). This event will be passed as an argument to the original responder's result method.

Setting ModelLocator Values

Within a Cairngorm application, it can be extremely tempting to set values of ModelLocator variables in your events, delegates, or views, but this should be avoided. These values should be set only in the Command Level (see Figure 1) of the application. This means that you can set these values in a Command or Responder. This keeps every class in tune with its true function.

Sequence Commands

Cairngorm also contains a class, SequenceCommand [Reference] that allows the developer to chain command/events together for sequential execution. Initially this may seems like it breaks the framework's rule oft having every command triggered by an event, but it doesn't. Inside of a SequenceCommand you define the nextEvent property (which is an instance of a CairngormEvent). This event is executed when the executeNextCommand method is called. This is the most effective way to attach multiple commands to a single user gesture.

Actionscript:
  1. public class SampleSequenceCommand extends SequenceCommand implements ICommand, IResponder {
  2.        
  3.         public function SampleSequenceCommand() {
  4.             this.nextEvent = new GetPostsEvent();
  5.         }
  6.        
  7.         override public function execute( e:CairngormEvent ):void {
  8.             ...  
  9.         }
  10.  
  11.         public function result( event:Object ):void {
  12.             this.executeNextCommand();
  13.         }
  14.  
  15.         public function fault( event:Object):void {
  16.             ...
  17.         }
  18.  
  19.     }

NOTE: The SequenceCommand class assumes that you are not separating your Command and Responder. You could easily extend the architecture and create a SequenceResponder class to achieve the same effect.

ViewHelper and ViewLocator Classes

Many people have inquired about the ViewHelper [Reference] and ViewLocator [Reference] classes. Both of these classes are now deprecated as of Cairngorm 2.1, and it is considered bad practice to use either of these classes in a new Cairngorm project. Should you be working with an existing project that still uses these classes, I would recommend refactoring your code to meet Cairngorm 2.2 standards.

Summary of Tips

  1. Don't use ViewHelpers and ViewLocators
  2. Only set ModelLocator variables in the Command Level (Command or Responder).
  3. SequenceCommand can be used to chain multiple commands to a single user gesture.
  4. Delegates deal in raw service data (which could be application data), but Responders only deal in strongly-typed application data.
  5. Commands do not directly communicate with services.

Application Code
Beginning Code Download (9 Kb)
Finished Code Download (12 Kb)

References
AS3CoreLib

Looking Ahead

In the next (and final) tutorial on Cairngorm, you will learn tips to make your Cairngorm development go faster as well as learning more "best practices" for Cairngorm development.

Cairngorm, Flex | Comments | Trackback | Del.icio.us | Digg | Technorati Jump to the top of this page

30 comments on “Getting Started with Cairngorm – Part 5”

  1. 01

    Thanks for this tutorial David!

    I’ve learned Cairngorm with this serie and I really thank you for that.

    A question though : I have a component with many states. Let’s say a contact detail with 2 buttons (edit,remove). When I click on a button, the component’s state should change. Also, the currentState property depends on the detailContactState variable in the ModelLocator.
    So, my question is: when I click on a button, may I change the currentState directly in my view or should I dispatch a new event to a command that will change the detailContactState?

    PeZ at December 1st, 2007 around 6:07 am
    Jump to the top of this page
  2. 02

    same question ,change the model from views directly is ok?

    Nshen at December 1st, 2007 around 9:03 am
    Jump to the top of this page
  3. 03

    @PeZ,@Nshen - In the last tutorial I will cover “multi-layered” views (which will partially address this issue). However, in these situations you must ask yourself - “Is the change of state in a component completely self-contained?”. If the user gesture is within the component and the change of state doesn’t affect the application model, the ModelLocator doesn’t even need to me involved in this - the component can store and change its own state.

    However, if the view component relies on other components for user gestures or relies on application model data for it’s internal state, then you need to dispatch a Cairngorm event.

    You obviously can break these rules, but you will end up with components that are not “loosely-coupled”.

    David Tucker at December 1st, 2007 around 4:22 pm
    Jump to the top of this page
  4. 04

    Great Tutorials David!

    This series has really helped me wrap my head around Cairngorm.
    Looking forward to the next part!

    Derek Santos at December 3rd, 2007 around 9:34 am
    Jump to the top of this page
  5. 05

    [...] Part 5 [...]

    Jump to the top of this page
  6. 06

    Great job David, been following and its helping me a whole lot! Its been hard understanding these concepts but everything is soo clear now. Thanks. i hope you keep this up

    K

    Kofi Addaquay at December 5th, 2007 around 2:31 pm
    Jump to the top of this page
  7. Jump to the top of this page
  8. 08

    Again, Great tutorial..

    Just one question. What is the real purpose of the AsyncToken?

    Thanks

    Joe at December 7th, 2007 around 7:29 am
    Jump to the top of this page
  9. 09

    I see the Language Reference said “The token that represents the indiviudal call to the method. Used in the asynchronous completion token pattern.”
    a design pattern?

    NShen at December 11th, 2007 around 9:22 pm
    Jump to the top of this page
  10. 10

    Well done David. I have been looking at Cairngorm for about 10 months now coming from mainly a php background. I read and googled heaps but could not find enough of the right info to have a go. Seeing your series of articles has given me the confidence to get my feet wet. Thanks mate …. look forward to the next movie.

    DG at December 13th, 2007 around 9:02 pm
    Jump to the top of this page
  11. 11

    Thx David

    This tutorial was the most useful documentation in this topic. I’ve been searching for the right description since the company here decided to move this way from classic Java MVCs. You seem to be the only one who really wants to explain instead of just talking about.

    Lovas at January 4th, 2008 around 8:15 am
    Jump to the top of this page
  12. 12

    Hey David
    Thanks a lot for this great Cairngorm tutorials serie.
    Just one question. I followed another tutorial where the author was using code-behind and separating the AS3 from the mxml. What do you think of this ?

    Rod at February 3rd, 2008 around 7:25 am
    Jump to the top of this page
  13. 13

    It is certainly a personal preference. Some people hate MXML and ActionScript in the same file. I have no problem with it - and I also think that it leads to better project organization and less files.

    David Tucker at February 3rd, 2008 around 7:33 am
    Jump to the top of this page
  14. 14

    Great tutorials. They have really helping me learn Cairngorm. I’m looking forward to reading the last tutorial in the series.

    Christopher Garvis at February 9th, 2008 around 11:22 am
    Jump to the top of this page
  15. 15

    Great tutorial!
    What do you suggest for a good structure with ServiceLocator and NetConnection?

    Gallo_Teo at February 18th, 2008 around 8:19 am
    Jump to the top of this page
  16. 16

    Hey David, great series… I love it.. I finally have an idea aout cairngorm. Adobe article got me really confused. but in this part you said that you gonna covert “next week” cairngorm code generation.. what about that? thanks in advance.. keep on this way great work thanks for all

    rafael ochoa at February 22nd, 2008 around 3:35 pm
    Jump to the top of this page
  17. 17

    Hi David, excellent tutorials that I am working through and learning a lot.
    I am facing a problem with the SequenceCommand - the executeNextCommand() is firing before the initial command has completed. I need it to fire after so it can use the data generated by the first command (loading external XML). I think I need to not use a responder and put the this.executeNextCommand(); in the result function rather than at the end of execute but I am not sure how to do it and get it called when the delegate returns. Not sure if that makes sense :)

    Bob at March 31st, 2008 around 12:02 pm
    Jump to the top of this page
  18. 18

    Solved it by passing ‘this’ to the delegate from my command instead of a responder like this: var delegate:MyDelegate = new MyDelegate( this );
    Thanks again for the tutorials.

    Bob at April 1st, 2008 around 4:18 pm
    Jump to the top of this page
  19. 19

    This is such good stuff. Question .. sticking to a standard. If the data returning from the backend is e.g. an Oracle refcursor (single array) - do you advise still building a “single var” ColdFusion VO with matching ActionScript VO to move this data into e.g. a Flex datagrid. This app is for corporate reporting and there are dozens of Oracle procs that return data as a single “report list”. Should I be consistent and match each one of these proc calls with matching VOS to hold the “single var”?
    Thanks, Mic.

    Mic Cross at April 8th, 2008 around 8:10 pm
    Jump to the top of this page
  20. 20

    David -

    This is the only place I’ve seen such a good explanation of a more complex use of the Business Delegate’s purpose. Specifically using the delegate to hide the details of turning service results into application models which are actually usable by the commands.

    This pattern is not understood by most people working with cairngorm yet… there is still much confusion so thanks for the clear explanation.

    Corbin at April 14th, 2008 around 12:36 pm
    Jump to the top of this page
  21. 21

    Hi David..
    I have seen your videos..they are amazing and helped me a lot in understanding Cairngorm framework.

    I have recently downloaded the samples from this page. I tried compiling them it is giving me error that “1045: Interface IModelLocator was not found.” I can understand that “IModelLocator” is renamed to “ModelLocator” in Cairngorm 2.2(latest). But I can not rename the interface as it will be same as the class name.

    I have tried renaming it even. But it seems not working..I am trying out that, just but thought of informing you. It would be nice if you can tell me or update the examples.

    thanks and regards

    rconceiver

    rconceiver at April 16th, 2008 around 2:05 am
    Jump to the top of this page
  22. 22

    hey david..
    it is solved..
    actually IModelLocator is deprecated from the latest release.

    thanks any ways…

    but still if you want I can send you the modified build..

    Thanks and regards,
    rconceiver

    rconceiver at April 16th, 2008 around 2:25 am
    Jump to the top of this page
  23. 23

    Actually in Cairngorm 2.2 the ModelLocator Interface was deprecated and renamed to IModelLocator. You can check out the release notes here:

    http://labs.adobe.com/wiki/index.php/Cairngorm:Cairngorm2.2:Release_Notes

    Let me know if you have any more problems.

    David Tucker at April 16th, 2008 around 2:27 am
    Jump to the top of this page
  24. 24

    Hey Davaid,

    This was AMAZING, I was wondering if I could call an XML file in Services.mxml and work with delegate file properly. Is that possible?

    I would like to see the series 5 extend version :)

    Thank You

    min at April 18th, 2008 around 11:05 am
    Jump to the top of this page
  25. 25

    @min - Do you mean a call through an HTTPService? Can you explain your situation a little more?

    Thanks

    David Tucker at April 18th, 2008 around 11:13 am
    Jump to the top of this page
  26. 26

    great stuff… thank you for such good tutorials…

    gavin payne at April 29th, 2008 around 6:13 am
    Jump to the top of this page
  27. 27

    Great Work! In your next tutorial could you cover using SetCredentials(), it seems to be an aspect of Cairngorm no-one is mentioning. I’m trying to use WebORB.NET, but it could equally be Flourine or AMFPHP, I just can’t work out when and where to make the SetCredentials call.

    Many thanks,

    Matt

    Matt Law at May 8th, 2008 around 11:14 am
    Jump to the top of this page
  28. 28

    Very interesting series of videos - thank you.

    I have a general Cairngorm question. Lets say you were building an application in Flex which was similar to the Flash CS 3 IDE or Eclipse, in that it contained multiple panels or views which could be opened and closed, and moved around to suit the person using it. Lets say one of these panels contained a Flickr image viewer, another panel contained a delicious post viewer, and a third loaded in stock prices. These three panels are all self-contained, fully functional components which do a particular job, and in an ideal world these could be reused in entirely different projects.

    Within the scope of this project, the three panels can all be controlled by some fourth panel containing just a search box, and typing in Yahoo and pressing “Go” would make the Flickr image viewer load in images tagged with “Yahoo”, would make the delicious post viewer show posts tagged with “Yahoo”, and the stock price viewer would show the latest price of the appropriate shares. Or whatever.

    I’m wondering how this would be structured in a Cairngorm project. I’m new to Flex, so my terminology is most likely completely wrong, but ideally to me I would have four different FrontControllers, one for Flickr, one for Delicious, one for Stocks, and one for the app. To accomplish this, would the Flickr viewer (for example) be a separate project entirely, and then somehow brought in to the main application as a component?

    I can’t really explain what I mean, most likely because I’m lacking a little knowledge on how things all fit together in Flex as a whole, but I’d be very interested to read your (or anyone’s opinion) on how something like this would be tackled.

    Thanks again for the videos!

    Toby Ashley at June 19th, 2008 around 6:19 am
    Jump to the top of this page
  29. 29

    Great tutorials David, I learned a lot from going through them but am stuck on one thing: howto use LocalConnection inside Cairngorm.

    I don’t mean how to make LocalConnection work because that is easy enough from the docs. I need to use an AS2 swf within a Flex app so LocalConnection is required but where should it be placed within the Cairngorm structure ?

    Drawing a blank here so any tips would be useful.

    Bob at June 29th, 2008 around 5:07 pm
    Jump to the top of this page
  30. 30

    Great series. Thanks for putting these together as they have helped me immensely. Any idea when Part 6 will be available?

    BTW, I also enjoy your tutorials on Lynda.com. Any thoughts as to making these types of tutorials (Design Patterns, etc) available on Lynda.com as well?

    Thank you!

    Scott at August 2nd, 2008 around 3:19 pm
    Jump to the top of this page

Leave a Reply

  •  
  •  
  •  

You can keep track of new comments to this post with the comments feed.

Badges

View David Tucker's profile on LinkedIn
Inside RIA Badge

Community Posts