Home  >  

FrameworkQuest 2008: Introduction

Author photo
AddThis Social Bookmark Button

FrameworkQuest 2008


Part 1: Take a Step Back
Frameworks

Frameworks, frameworks, frameworks. We talk about them all the time. What’s the best one? Which one ticks the most boxes off the pattern checklist? What’s everyone using these days? We talk about frameworks so much that it deserves to be written like this:

ffq1.jpg
FRAMEWORKS!!!

We Work Hard, So You Don’t Have To

This series of articles is scientifically designed to help you get an understanding of the major Flex Frameworks on the market today.

  • • What are your choices?
  • • How do they work?
  • • What do they preach, and is it hard to practice what they preach?
  • • How does Brand X stack up against my brand of choice?
  • • And the most important question: Does this framework make me joyful?

I could have gone about this quest multiple ways, but the way I chose was slightly more organic than the more obvious rundown of features, and I hope you get more out of this approach.

I’ve taken a simple application and built it five ways. Once with no framework at all, and once each with these Flex Frameworks:

  • • Cairngorm
  • • PureMVC
  • • Swiz
  • • Mate

All source code is available at http://github.com/thillerson/twitteria. To get the code, either check the project out using Git, or if you just want the source as a zip file, click the "download" button. The project targets Adobe's AIR platform. I expect that you know how to work with and build AIR projects already, so I don't take any time to explain that.

In the interest of full disclosure, I should let you know that I hadn’t used any of these frameworks before except Cairngorm, which I use pretty much every day. I did research and write a chapter on Cairngorm and PureMVC for Flex on Rails (shipping Q1 2009), so I was already familiar with PureMVC, but I’m most used to building with Cairngorm, and I had never worked with Swiz or Mate at all before this article was written.

At the end, in the last article in the series, I’ll put forward a subjective rating system to give you an idea of what I thought of each framework.

What Good is a Framework?

Let's take a step back. Why do we use frameworks? Here's a graphic whose idea I stole from a slide in Cal Henderson's Djangocon Keynote thoughtfully entitled "Why I Hate

ffq2.png

Django". This graph shows, with the best science available to the author, why we use frameworks. No frameworks were harmed in the making of this graphic.

Speaking in terms of complexity, a very simple application has a small advantage in development speed over an application of similar complexity using a framework. There are rules and a little bit of red tape you have to cut through to use the framework, so for a dead-simple app skipping a framework is a win in development speed.

Frameworks start to show value when you want to do things that a lot of other people want to do, like call remote services, keep things clean and separated, and in general think about your app based on similarities to every other application out there. That's what makes a pattern - common use. Following the rules of the framework pays off in productivity. You have to think less about how you want to do what you want to do, because the framework has ready, commonly accepted answers for you.

As complexity goes up, development is still pretty speedy, especially in a team situation, because the organization the framework imposes is paying off more and more. It's probably easy to remember where functionality is because you know where it fits into the framework's notion of where things should be. Development without a framework is slower because you're either mired in disorganization or you're spending extra time building something like a framework.

Things get tricky once you get to the 80/20 rule, if your app gets more complex than most. Frameworks may even make it difficult to do some things you want because at this level of complexity you're beyond the common cases the framework solves and the rules are making it hard to do what you want. At this point it may even be easier to do things with your homegrown solution because you're building things the way you need them.

At the end of the graph I'll freely admit that I'm making things up. Let's call this end of the graph "the point where the framework catches up because the author is in favor of frameworks" or simply the Deus Ex Machina section of the graph. In any case, my gut tells me that frameworks still have something to give even when applications get really complex.

The point of this artificial graph is to show that we use frameworks because at most levels of complexity of an application, a framework makes us more productive.

TwitteRIA - Don't Worry, Anyone Can Get It

Ok, now on to the fun. The app we're going to build was suggested by Anthony Franco, President of my company, EffectiveUI. He won hands down in a battle royale on Twitter, the microblogging site, the Great Chatroom of The Internet, where I asked for ideas from anyone on what app to build for this article. Sometimes the simplest person can have a flash of brilliance, and he suggested that I build a Twitter client. The prize was a mention in this article, so here it is: Anthony, you're the best looking boss I've ever had! Great hair, nice teeth, a class act all around!

The application that I've used to build with each of these frameworks is a simple Twitter client that implements these user stories:

  • 1. Retrieve authenticated user's timeline
  • 2. Set authenticated user's status
  • 3. Be exceptionally pleasing to the authenticated user's eye
    ffq2.png

You can be your own judge on number three, but numbers one and two are simple enough to not get in the way, and complex enough to exercise the frameworks. So without further ado, I give you TwitteRIA. Some of you may have it already, so to speak. I know I do.

All five projects use a special version of Twitterscript, which you can get here: http://github.com/thillerson/twitterscript/. It's a version of Peter Armstrong's, which is here: http://github.com/peterarmstrong/twitterscript/, and in turn a version of the original, which is here: http://code.google.com/p/twitterscript/. Credit where credit is due: all I did in my version was add back in the ability to authenticate users safely. Due to Flash security limitations, this means you can only use the library in AIR projects if you need to authenticate. The swc is included in the lib directory of each project. Since the application is written for the AIR platform you'll need to have either the AIR SDK or Flex Builder installed.

Now let's go through the framework-less application one feature at a time. Try to keep a lookout for problems in the application that you think a framework may be able to help solve.

Logging In

Logging in with Twitterscript is not quite like logging in to any other services. All we need to do is call a method on an instance of the Twitter object we're going to use to interact with Twitter. Because of that, all we need to do is capture the login credentials of a user in memory, and then go on to load the user's timeline. To do this, in the root application file we have two views in a view stack, like so:

twitteria_raw/src/twitteria_raw.mxml #24-27 (formatted)
<mx:ViewStack
	bottom="0" left="0" right="0" top="30" 
	selectedIndex="{viewIndex}">

	<local:LoginView id="loginView" login="login()" />
	<local:MainView id="mainView"
		username="{loginView.username}" 
		password="{loginView.password}" />
</mx:ViewStack>

LoginView captures a username and password and exposes them as public properties that we can bind into MainView. If you said "That's not very scalable, Tony!!" well, you're right. It's one problem we can help fix with a framework, but for now it works. Inside LoginView, when enter is pressed on the password field, this method runs:

twitteria_raw/src/LoginView.mxml #12-16
public function login():void {
 	username = usernameText.text;
 	password = passwordText.text;
 	dispatchEvent(new Event('login'));
}

This sets the public properties and then dispatches an event, which is listed here:

twitteria_raw/src/LoginView.mxml #3-5
<mx:Metadata>
	[Event(name='login', type='flash.events.Event')]
</mx:Metadata>

Back in the application file, we'll catch that event and switch the index of the ViewStack to show MainView instead of LoginView with the help of a few constants:

twitteria_raw/src/twitteria_raw.mxml #7-15
private const LOGIN_VIEW:int	= 0;
private const MAIN_VIEW:int		= 1;

[Bindable]
private var viewIndex:int		= LOGIN_VIEW;

private function login():void {
 	viewIndex = MAIN_VIEW;
}

Pretty simple so far. Now, since the creation policy on the ViewStack is the default, "auto", views will be created when they are displayed. MainView will be created with the username and password from LoginView bound into its username and password fields.

Loading the Timeline

Once MainView is created, it runs the init method:

twitteria_raw/src/MainView.mxml #20-37
private var twitterService:Twitter;
private var useDummyData:Boolean = true;

private function init():void {
 	twitterService = new Twitter();
 	twitterService.setAuthenticationCredentials(username, password);
 	twitterService.addEventListener(
 		TwitterEvent.ON_FRIENDS_TIMELINE_RESULT,
 		friendsTimlineLoaded
 	);
 	twitterService.addEventListener(
 		TwitterEvent.ON_SET_STATUS,
 		statusSet
 	);
 	reload();
}

private function reload():void {
 	if (useDummyData) {
  		currentTweets = new ArrayCollection(getDummyData());
  	} else {
  		twitterService.loadFriendsTimeline(username);
  	}
}

A few things are going on here. First, notice that we have a private member variable of type twitter.api.Twitter, which is the wrapper for all calls to the Twitter API. This class is provided by the Twitterscript library.

Next we have a very simple way of deciding to use dummy data instead of making calls to Twitter. This is important for a few reasons.

Consider what happens to development when Twitter is down. I know, I know, you're probably saying "But Tony, in all my years on the web, I've never known Twitter to be down!". Well, I'm here to tell you that it may happen one day, and your development effort should be prepared.

Another reason is that Twitter limits the number of messages you can send in an hour. Might as well make sure that doesn't slow development either. A less important reason is that maybe you want to do a little development somewhere without Internet access. I want to be clear that the implementation here is a very simple, even dumb, way of doing this, but I'm going to use it later in the series to make a point, so bear with me.

The init method instantiates the Twitter object, sets the authentication credentials, and then sets up some event listeners for two types of event TwitterEvent.ON_FRIENDS_TIMELINE_RESULT and TwitterEvent.ON_SET_STATUS.

The reload method is what we call when we want to reload the timeline. Here's where we use our simple method of switching in dummy data. If we're using dummy data, we simply call the friend timeline callback method with some dummy data, but if not, we kick off a call to the actual service. When that gets back, the callback is executed:

twitteria_raw/src/MainView.mxml #47-49
private function friendsTimlineLoaded(te:TwitterEvent):void {
 	currentTweets = new ArrayCollection(te.data as Array);
}

The callback sets a private member variable, currentTweets to an ArrayCollection that wraps the array of status messages in the result object or dummy data as the case may be. On down in the view section, there's a list that shows the objects in the collection:

twitteria_raw/src/MainView.mxml #90 (formatted)
<mx:List 
	id="statusList" width="100%" height="100%"
	styleName="statusList" 
	itemRenderer="TwitterStatusRenderer"
	dataProvider="{currentTweets}" />

The item renderer, TwitterStatusRenderer, displays a single twitter.api.data.TwitterStatus. Have a look at that if you'd like, but it's pretty simple.

Not too much work for something pretty cool, eh? Of course there's a lot more to a Twitter client like Twhirl or Twitteriffic, but it's kind of neat to see status messages coming up with as little code as there is so far. But wait! There's more! We can also update the current user's status.

Setting Status

MainView has a TextInput that takes a status message, with a simple little method to tell the user how much of the 140 characters of Twitter message goodness they have left to them:

twitteria_raw/src/MainView.mxml #96 (formatted)
<mx:TextInput id="statusText" width="100%" maxChars="140"
	enter="setStatus()" keyUp="countCharactersLeft()" />

When the enter key is pressed, the setStatus method is called:

twitteria_raw/src/MainView.mxml #39-45
private function setStatus():void {
 	if (useDummyData) {
  		statusSet(null);
  	} else {
  		twitterService.setStatus(statusText.text);
  	}
}

Again, this method asks if we're using dummy data or not, and calls Twitter if we're not. When Twitter returns or the callback is force-called, the callback is executed:

twitteria_raw/src/MainView.mxml #51-55
private function statusSet(te:TwitterEvent):void {
 	statusText.text = '';
 	countCharactersLeft();
 	reload();
}

The status text and character count are cleaned up, and reload is invoked, which loads the timeline again. With any luck, Twitter will return the status message we just posted in the new timeline.

There it is, a simple, effective, Twitter client.

Next Up

So if what we have here is working, why do we need a framework? Well, the app as it stands has some problems.

  • 1. State Storage. We're passing essential data from view to view, namely the username and password. If Flex's binding didn't make it so simple to code this, the code it would take on the distinct smell of Spaghetti Code
  • 2. Bloated Views. Look at MainView. Can you describe what its responsibility is? I think it would go something like this: MainView is responsible for keeping a reference to the Twitter service, deciding when to call it or create dummy data, responding when the timeline is loaded, putting the timeline data into a dataprovider, setting status messages, reloading the timeline when a status message is set, and displaying the currently loaded timeline. That's way, way, way too much. That view is schizo, friends. It doesn't know if it's dealing with service interaction, dummy data, display, or a pleasant mix of everything all at once.

These problems are exactly the type of thing a good framework will help us address, and we're going to start addressing them next time by looking at the old standby Flex Framework, Cairngorm.

Read the rest of FrameworkQuest 2008:

Read more from Tony Hillerson. Tony Hillerson's Atom feed thillerson on Twitter

Comments

23 Comments

Matt Guest said:

Great start, can't wait for the rest of FramworkQuest.

Tom Wilcoxen said:
At the end, in the last article in the series, I’ll put forward a subjective rating system to give you an idea of what I thought of each framework.

TEASE! Give it up Tony! Tell us the answer! ;)

It was the butler. Or J.R.. I'm not sure.

Ansury said:

Hey! That picture above is me, the last time I heard someone say
FRAMEWORKS!!!

What pisses me off about Flex frameworks, maybe this is not relevant in the Flex world, but designers seem to have completely forgotten what we learned about good OO design and OOP practices in general.
This is not a cheapshot but I wonder how many Flex devs came from a Java/OO background vs a Flash/Timeline background, which could explain this. (Nothing meant against Flash devs, it was never their job to know anything about these concepts.)

ModelLocator (Cairngorm) seems just a euphemism for "globals", remember those? And how developers' ears used to bleed at the mere mention of this evil word?

It might as well be called GlobalLocator, eh?

And what about loose coupling? Putting all these references to GlobalLocator attributes in your components is tight coupling. Bad. How are we supposed to reuse this stuff without changing those references? GRRRR!!

@Ansury - re: coupling and globals. I go over both these complaints in later articles in this series. I hear you about Cairngorm's coupling and I'd like to hear your feedback on my take once it comes up in the series (can't remember offhand when I talk about it).

I take issue with the globals argument though. Here's the deal - although a singleton is available anywhere in the app, which makes it feel like a set of glorified global variables, it's not the same has simply having global variables with no protected access. Since the model is an object it has full control over its variables (object = data and methods that act on the data). You can choose to have all properties wrapped in getter/setter pairs and bindable as needed. That encapsulation nullifies the argument against Cairngorm's design as it relates to the singleton model.

In any case, I feel like I can defend most arguments against Cairngorm, but other frameworks do things a lot better, as you'll see.

Stay tuned!

Ansury said:

This is true.. with Flex, many of the big global concerns are gone.

I don't know what "the perfect solution" to this is, but I do think there are some smaller 'global like' problems remaining:

1) Variable naming - either you end up with a *very* large ModelLocator (can also make it tougher to find good variable names), or a big hierarchy of sub-models that are a pain to traverse to get to what you want. There's yet another FRAMEWORK!!! called Penne someone is trying to promote out there that avoids some of this via local models within command classes, but then there's other issues you run into.

2) It's still possible to 'forget' what/when a model variable gets modified, in a complex application. I feel like on rare occasions I've seen a variable get modified twice, and I was left wondering why the first change didn't take effect. On the plus side, at least this is mitigated by the ability to use a setter with a trace() to find out what's going on.

3) If Flex/Air ever go multithreaded (maybe never?) there'll be concurrency "problems"

Bookmarked this link and I'll be interested in hearing what the final score is, as a rather disgruntled Cairngorm user.

Ansury said:

Although, I should say that I'm mainly disgruntled not for these reasons, but from the sheer amount of boilerplate code I have to write when adding even the most basic of remote calls.

And here am I thinking the model should be global? Is it just me? But yet, not global as in street worker 'Hi, you want a good time? I'm accessible to all, any time, no question asked'. No - global as in 'Ask my pimp', the proxy (where PureMVC becomes the ÜberPimp). And in this sense it becomes clear. The pimp stands at the door of the lair, filled with a colourful assortment of states. The client does not dare talk to any of them directly, but negotiates their 'access' via the pimp. Now, maybe sadly, these ladies are also forbidden to interfere with another, because that would affect their integrity and general well-being. So, relying on their agent, you are always sure you'll find them in a 'ready state', ready for action, as it were. Hey, isn't that reassuring? Essentially, that also lays the foundation for future concurrency issues (@ansury).

What's even more reassuring, is the fact that, PureMVC also prevents the client from getting bad press the morning after. This is due to the fact that even the client has an agent - the butler (or mediator, in more familiar terms), who diligently drives off to fetch the service at her seedy lair in the red light district. That way, everybody's protected, and practising safer...um... well, you get the idea.

Ansury,

I just added this comment to Tony's second part in this interesting series, but thought i'd repeat it here.

I presented on Cairngorm in Max Milan, sharing Adobe Consulting's best practices in its use, and discussing the Presentation Model pattern which address many of the misconceptions on the use of Cairngorm, such as those you have mentioned in your comments above.

The Presentation Model is pretty analogous to the Pimp in Pieter's story above, which does reminds me of a colleague who once wrote a document with the consistent mis-pelling of warehouse as wharehouse, and was less than prudent in his attention to detail when doing an "change all" in his spellchecker prior to sending the document out for release...

Ahem, anyway, we have never advocated dumping all data in a single Cairngorm ModelLocator, and completely agree that the use of any framework does not remove the need for good OO design in your applications.

I've blogged about the presentation here, with a link to the slide deck:

http://weblogs.macromedia.com/amcleod/archives/2008/12/max_milan_-_fle.html

In response to your boilerplate code point, you may also be interested in the Cairngorm FlexBuilder plugin that has been released - it creates controllers, events and commands for you. Again, a link is in the blog post.

Ansury said:

"which does reminds me of a colleague who once wrote a document with the consistent mis-pelling of warehouse as wharehouse, and was less than prudent in his attention to detail when doing an "change all" in his spellchecker prior to sending the document out for release..."

This is great...haha.

It is about time somebody created a FB plugin - I'd looked for one in the past but no luck!

MK said:

Hi, I'm not able to download the source code from the URL mentioned. When I click on download, nothing happens

Any idea, what needs to be done in order to get the code?

Thanks in advance

@MK, Maybe there was some trouble on github? Try again and let me know...

HO said:

Confirming MK's troubles: unable to download the zip file. It would be a great help if you could point out what we can do. Note: The Download button is associated with "http://github.com/thillerson/twitteria/tree/master#"

Thank you.

JJ said:

Anybody able to use the "Download" option for retrieving the source code?

Hey anyone having trouble downloading from Github, it seems to be an issue with IE. Here's the zip file for your download.

http://github.com/thillerson/twitteria/tree/0f9c072346f1f708acd1445c95ff81877bbf6436/download

adrian said:

I can download the .zip file.
But the file has been damaged....

Mike said:

Thanks for letting us know about this framework. Jacob Hiller

Vince said:

One framework is missing here: http://www.spicefactory.org/parsley/

I think it would be a worthily additions to this comparison.

@Vince - I'm probably not going to amend the article, but if you want to show how it's done, go to github (http://github.com/thillerson/twitteria) and fork the sample code project. Then add an example with spicefactory and we can look at what it's like.

JAMES said:

I go over both these complaints in later articles in this series. I hear you about Cairngorm's coupling and I'd like to hear your feedback on my take once it comes up in the series ...

A great job i have never seen before!

David Rios said:

Hi Tony,
I really enjoyed your series and learned a lot. I'm concerned with Presentation Models and real world Flex Rich Internet Applications. I agree with Alistair's comment about PM being easier to unit test, but I agree with you in the sense I don't like the idea of relying in Data Binding as the unique way of notify the view about changes in the model. I did a mention to your presentation in my post, I hope you could contribute with your knowledge:
http://toasted-minds.blogspot.com/2009/10/about-cairngorm-mediators-and.html

Thanks!

Leave a comment


Tag Cloud

Question of the Week: Dream App

If you had an unlimited budget and unlimited resources what application would you build and why would you build it?

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.