Flex Pasta » Cairngorm

Cairngorm users know a chain event:  a way to execute, in order, multiple remote requests such as http, remote object, or web service calls.

 The Good

  • Executes multiple requests in order
  • Ability to use data returned from an earlier event on the chain to make a request for a subsequent event on the chain

The Bad

  • When events are chained that do not need to be in sequential order
  • When events are chained that do not need a previous result’s data

The Ugly

  • A chain event is a performance hit!  It makes one request, waits for the result, then makes the next, waits for the result, and so on.  It’s bad for the end user to have to wait for all these events to fire in order.  The problem is compounded when chain events are over used.
  • The code.  Using chain events with Cairngorm involves ugly code that makes bugs more likely.
  • Business logic use cases are needed in more numbers and are more difficult to design, implement, and maintain.  For example, what happens when a 5 chain event incurs a fault abnormally during event 3?  What happens when event 2 comes back with a result, but it is not in the format expected?  How does a support team troubleshoot a user’s problem when they’re failing on one part of a chained event?

One alternative option to a chain event is the Transfer Object Pattern.  Here are the goals of the Transfer Object Pattern:

  • Reduce high method invokations by encapsulating the calls in a generic object.
  • Reduce the chatiness of the application by eliminating requests across the network

Example:  From Chain Event to Transfer Object Pattern

The Chained Event:

Event 1: Call a remote Java method: public Customer doLogin(String username, String password) - It takes a user name and password and returns me a Customer object.

Event 2: Given the Customer object from event 1, I now use it to call public List<Accounts> getCustomerAccounts(Customer customer) -  This method takes the customer object I got from Event 1, and then retrieves the customer’s list of Account objects.

The Transfer Object Event:

The transfer object pattern has only one event.  It will call a remote Java method called public LoginResult doLogin(LoginRequest loginRequest)

LoginRequest would look something like this:
public class LoginRequest
{
private String username;
private String password;
}
…getters and setters….

The LoginResult would look something like this:
public class LoginResult
{
private Customer customer;
private List<Account> accountList;
}
…getters and setters…

The workload is now away from the Flex chained event and put on Java.  In this case, I only have one request/response at login, rather than two.  This improves performance and wait time for the end user.  It also makes my Flex code less cluttered(without all those “what ifs” for the chained event).  The Java code needs some modifications but is still simple and easy to maintain.  Adding on is also very easy.  Say I also want to return a list of statement objects at login.  I simply add the new list object to the LoginResult class without having to add the plumbing for more remote calls.  There is minimal work in Flex to get the data I need and without the clutter of adding on to a chain event.

The Transfer Object pattern is an example of another approach to a chain event.  It may not work in all cases, but is worth considering!

I ponder a simple Cairngorm vs. Penne example. I want to add on to the Italian Store(find the code under Introducing The Penne Framework). I want to add a feature to the application to allow the user to delete a pasta type.

Using Cairngorm:

  1. Add a trash can to the datagrid.
  2. Add a new class DeletePastaTypeEvent.
  3. Implement the clone method with the deleted pasta type as payload. Create a static variable for the event type making sure the “type string” hasn’t been used anywhere else.
  4. Invoke the event from the trash can click handler.
  5. Add a new DeletePastaTypeCommand.
  6. Add a new method “deletePastaType()” in the PastaTypeDelegate Class.
  7. Add a line in FrontController mapping the DeletePastaTypeEvent to the DeletePastaTypeCommand.
  8. Fill in all the execute, result, fault methods in DeletePastaTypeCommand with the cookie cutter code.

Eight steps, which doesn’t even include having to add or change a model locator.

Using Penne:

  1. Add a trash can to the datagrid.
  2. Add a new method “deletePastaType()” in the IPastaRemoteRq, implementing it in PastaRemoteRq.
  3. Add a new method “deletePastaType(pastaTypes:ArrayCollection)” in the IPastaRemoteRs, implementing it in PastaRemoteRs.
  4. Invoke the request method from the trash can click handler.

Twice as many steps in Cairngorm vs Penne. Penne also required no class creation, vs two with Cairngorm. When looking at my datagrid in Penne, I can click right through to the deletePastaType and see what is happening. With Cairngorm, I have to dig up another file, DeletePastaTypeCommand.

I welcome your comments and feedback.

As first discussed in a previous post, “The Pros and Cons of Cairngorm“, I noted the need for a more lightweight framework for developing in Flex and Air. I am releasing version 1.0 of The Penne Framework, a simplified Flex and Air framework, as a second option to the popular Cairngorm Framework. This page has the Penne base code, and a java/flex example application using Penne(called the Italian Store) with remote objects. I have created a diagram which summarizes how Penne differs from Cairngorm.

The Penne Framework Diagram

About the Diagram

Let’s discuss the command class in Cairngorm, because this is the meat of the difference between Cairngorm and Penne. In Cairngorm, I will have one command class for a type of event. For example, I might have a remote service that returns a list of customers. This would have one command class. Then I could have another command class for getting all of the customer orders. In Penne, there is one request and result class for both of these remote calls. The request would have 2 methods in this case:

1: getAllCustomers(),

2: getAllCustomerOrders().

The result class would have

1: getAllCustomers(custList:ArrayCollection),

2: getAllCustomerOrders(orderList:ArrayCollection).

In a large project, the number of classes to create in Cairngorm would be drastically higher than Penne. There is a ton of overhead work to create in even a simple remote call in Cairngorm. With Penne, it is easy to grow your project without as much busy work.

Penne still keeps a strong structure for code layout. It is easier for a developer to see what is happening. Instead of looking at an event that is mapped to a command, which is mapped to a delegate, which calls an external service, in Penne I just call the method directly from a view class. It is very clear the remote service I am calling and from where. If I use BlazeDS and remote objects, my java remote methods can directly matchup to my flex request/response classes. There is a huge reduction in steps to figure out a path to a bug with Penne.

Hang on a Minute, How can Penne just delete all those event classes?? How will Penne ever have code reuse??

Penne is not getting rid of event classes. They are just not part of the framework. I am no longer required to create one for every type of remote service call. If creating a component such as a date chooser, or datagrid, then standard events are used to allow parent components to interact with them. Depending on the task, this kind of flexibility in a component is usually NOT needed. With Penne, call the request method directly from within a view component, and the result will cause bindings to fire changes back to the view components. Only use events for remote service calls when it is required for code reuse or the parent component needs to be aware, not for any other reason. I don’t create events because I have to anymore, I create them because they are NEEDED for something more than just kicking off a remote service call.

What about the model? Certainly Penne can’t get rid of that too?!?!

The model isn’t gone in Penne.  Model variables still exist in the application.  ModelLocators still exist just like in Cairngorm.  Penne, however, offers a secondary option for remote services.  Penne allows the developer to place “model” variables inside the response classes if desired.  By placing the result directly in a variable in the same class, tt becomes much easier to see what binded variable goes with which remote service call.  In my view layer I can just say PastaRemoteResult.getInstance.pastaTypes. In Cairngorm, if you opened up a model class and I said to someone, “Where does this model variable customerList get set?” They would probably start sweating and begin opening up all of the command classes trying to remember which one(s) it is. Then after it’s found a text search will be done to find the corresponding view where the CairngormEvent that goes with that command gets invoked. It is tough enough for the person who wrote the code to know where everything lives. Just wait until a new hire comes to code on the application has no idea what is going where. With Penne it is simple and structured. Everything is easy to find. If for some reason I need to control things like viewstacks and state management, I can still create a separate “model” class just for this, but all remote service calls’ model variables live in the response class.

Conclusion

The Penne Framework improves upon Cairngorm by simplifying it without sacrificing separation of duties. Penne drastically reduces the number of classes created in a large enterprise project. This reduces code complexity and readability. As an added benefit, Penne will reduce my pesky Flex Builder compile times!

Take a look at Penne, I welcome feedback and suggestions. The Design approach to flex can be improved. I hope Penne can start to accomplish this goal!

The Code

Here are the three zip files to download. One is the Penne.zip which includes the Penne source and Penne.swc. The other two are the Italian store. There are 3 projects in all which can be imported right into eclipse. I am using flex 3, java 1.5, with eclipse europa. The example Italian Store application is extremely simple. It shows how Penne can be used and offers comments as to how Penne works.

Penne Framework

Italian Store Flex

Italian Store Java

Cairngorm seems to be the architecture pattern of choice for flex. If you’re new to flex it certainly is a good way to keep you organized in your code layout. As you grow your code base flex can turn into spaghetti quickly if you don’t start out with a solid framework.

Here is what your typical Cairngorm structure might look like:

  • Business - Contains the various services for Remote Object calls, Web Service calls, etc
  • Command - Handles the formation of the Request/Response of these service calls.
  • Control - Here lives the one and only Cairngorm controller class. Home of headaches and heartbreaks, this is where you map your events to command classes. The headaches and heartbreaks come into play when you forget to add your new event and commands to this class. When you finally figure it out, your mind repeats idiot idiot idiot idiot over and over again for a few minutes. But this goes to the root of the main con I see with Cairngorm…..keep reading.
  • Domain - If you are using Remote Objects, you probably want to keep the matching actionscript classes in one place.
  • Event - When a user interacts with your super cool app, events are fired off that cause other layout changes based on the user request. Biggest problem with Cairngorm is that you have to implement a clone method for each event, another piece of painful overhead.
  • Model - Holds the data and states for the app.
  • View - All datagrids, etc, that make up the user interface.
  • Vo - Stores other objects similar to domain that organize data for easy use in the view.

So this all looks like good fun right???? Well yes, until your tasked with writing an app to takeover the world!! Well ok, maybe not take over the world but the app is going to be BIG! Lets just say your going to have 100 remote methods divided into 10 different parts of your app. Which since I made the math simple means you will have 100 event classes, 100 command classes, 10 model classes, 10 business classes, and a long control class, not to mention probably hundreds more view classes.

What does this mean for me?

  1. Order more ram for your pc. Java can compile one class and keep trucking, but actionscript into a swf requires more chips than a game of poker. 2GB minimum RAM if you are setting out on a big project.
  2. Start looking at a lot of busy work, creating the 200 event/command classes needed. Some people have even created Cairngen, a code generator for all those classes. This is my main issue with the framework. If your have to write a code generator for the framework, then the framework needs to be simplified!!

How to simplify Cairngorm?

Get rid of all the command classes, and almost all of the event classes. Continuing from the theme above: 100 remote methods in 10 remote classes(10 methods per class). Here are the steps to simplify:

  1. Create 10 interfaces in actionscript that will match your methods in your 10 remote classes. Put these in the “business” folder.
  2. Create a new folder called “request”. Create 10 classes called ‘RemoteServiceRequest’, each of which implement your 10 interfaces. This replaces what would be the “execute” method of a command class.
  3. Create a new folder called “response”. Create 10 classes called ‘RemoteServiceResponse’, each of which implement your 10 interfaces. This replaces what would be the “result” method of a command class.
  4. Create a new folder called “fault”. Create 10 classes called ‘RemoteServiceFault’, each of which implement your 10 interfaces. This replaces what would be the “fault” method of a command class.

So we are now looking at 40 classes in all and far less overhead to create them, add to them, and edit them because they all implement the interface classes you created. It is also more clear what remote methods you are calling, no guessing as to what command class goes with which remote method. More importantly, your code is still clear and has and organized framework. You still use the model in this framework, storing state and data objects. When you call a remote service, and you need other view functionality changes, you can still dispatch a normal flash event for this. This approach outlined is a significant departure from Cairngorm. In fact, it deserves its own name. Let’s call it the Penne Framework. Look for more about the Penne Framework on my blog in the future(and maybe even some real live code!).

Conclusion

The Cairngorm framework is a well thought out architecture for flex applications. It provides good separation of responsibilities for your code. For larger projects, it can create a lot of overhead in the number of classes needed to support this approach. The Penne Framework provides a simplified alternative for large scale flex projects. Look for more on the Penne Framework in the future!!