These slides are from a presentation at 360Flex DC on 21 September 2010.
Most application development follows a pattern where the designers design it then the developers build it. Any change in the design requires more work from the developers, who have to implement each change request.
It doesn’t have to be this way. By modifying the application architecture, we can enable the developer to do their work before the designer, leaving the designer free to alter the design as frequently as they wish without recourse to developer time.
This frees designers to respond to client requests in a timely manner and frees developers to work on a more strategic level, adding functionality to the tools the designers use without being bogged down in day-to-day client projects.
In this session I’ll describe this new architecture, how and why I developed it, the benefits and pitfalls of its use, and how to implement it using any of the current dependency injection frameworks.
29. The approach
• Flex 3
• Dependency injection (with SmartyPants-IOC)
• Simple event bus
• Test driven development
• Lots of refactoring
• MVC is NOT a requirement
35. SearchButton
public class SearchButton extends Button {
[Inject]
public var manager : SearchManager;
[Inspectable]
public var searchTerm : String;
public function SearchButton() {
addEventListener( MouseEvent.CLICK, performSearch );
}
public function performSearch( event : MouseEvent ) : void {
manager.search( searchTerm );
}
}
36. SearchButton calls a method on the SearchManager
SearchButton
calls method
SearchManager
37. SearchManager
public class SearchManager {
[Inject]
public var service : SearchService;
[Inject]
public var tweetCollection : TweetCollection;
[PostConstruct]
public function setUpListeners( injector : Injector ) : void {
service.addEventListener( TweetEvent.TWEETS_LOADED, updateTweets );
}
public function search( searchTerm : String ) : void {
service.send( searchTerm );
}
private function updateTweets( event:TweetEvent ):void {
tweetCollection.assign( event.tweets );
}
}
38. SearchManager calls a method on the SearchService
SearchService
SearchButton
calls method
calls method
SearchManager
39. SearchService
public class SearchService extends EventDispatcher {
[Inject]
public var request : TwitterRequest;
[PostConstruct]
public function setUpListeners( injector : Injector ) : void {
request.addEventListener( ServiceEvent.COMPLETE, parseResults );
}
public function send( searchTerm : String ) : void {
request.url = "http://search.twitter.com/search.atom";
request.sendData = new URLVariables();
request.sendData.q = searchTerm;
request.sendAndLoad();
}
private function parseResults( event : ServiceEvent ) : void {
var tweets : TweetCollection = parseFeed( event.data as XML );
dispatchEvent( new TweetEvent( TweetEvent.TWEETS_LOADED, tweets ));
}
}
40. SearchService dispatches an event when complete
SearchService
SearchButton
calls method
dispatches event
calls method
SearchManager
41. SearchManager
public class SearchManager {
[Inject]
public var service : SearchService;
[Inject]
public var tweetCollection : TweetCollection;
[PostConstruct]
public function setUpListeners( injector : Injector ) : void {
service.addEventListener( TweetEvent.TWEETS_LOADED, updateTweets );
}
public function search( searchTerm : String ) : void {
service.send( searchTerm );
}
private function updateTweets( event:TweetEvent ):void {
tweetCollection.assign( event.tweets );
}
}
42. SearchManager updates the TweetCollection
SearchService
SearchButton
calls method
dispatches event
calls method
SearchManager
updates data
TweetCollection
43. Tweet Collection
public class TweetCollection extends EventDispatcher {
private var _tweets : Array;
[Bindable( event="tweetsChanged" )]
public function get tweets() : Array {
return _tweets;
}
public function set tweets( value : Array ) : void {
if ( value != _tweets ) {
_tweets = value;
dispatchEvent( new Event( "tweetsChanged" ) );
}
}
public function assign( other : TweetCollection ) : void {
tweets = other.tweets;
}
}
44. TweetCollection is bound to the TweetList
SearchService
SearchButton
calls method
dispatches event
calls method
SearchManager
updates data
is bound to
TweetCollection
45. Tweets List
public class TweetsList extends List {
[Inject]
public var tweetCollection : TweetCollection;
private var tweetsWatcher : ChangeWatcher;
[PostConstruct]
public function setUp( injector : Injector ) : void {
tweetsWatcher = BindingUtils.bindProperty(
this, "dataProvider", tweetCollection, "tweets" );
}
}
46. TweetCollection is bound to the TweetList
SearchService
SearchButton
calls method
dispatches event
calls method
SearchManager
TweetList updates data
is bound to
TweetCollection
47. At the component level, it is MVC(S)
SearchService
SearchButton
SERVICE
CONTROLLER
SearchManager
TweetList
MODEL
VIEW TweetCollection
49. Smart Components MVC
M M M M M M M M M M
V V V V V V V V V V
C C C C C C C C C C
S S S S S S S S S S
Each component is a slice of functionality
implemented using MVCS architecture
50. A component set is
• A collection of smart components that work
together.
• Each component set has a context component for
its dependency-injection configuration.
• Each component set has an event bus for
components to talk to each other.
52. Is it new?
• The architecture feels new.
• Although I gained a lot of ideas from other
peoples work.
53. Is it new?
• On reflection, it has a strong similarity to MVC in
Smalltalk-80, which is 30 years old!
• Although our components are smarter than those in
Smalltalk-80.
54. BrightTALK component Library
The BrightTALK component library is
• 158 components
• 547 classes
• 31,500 lines of code
Working very well so far.
We now build all our projects this way.
56. New technologies we could use
Since we started, new technologies have emerged.
• This architecture would work with Flex 4
components
• This architecture can be implemented using Swiz,
Robotlegs, or Parsley
• Some details in the code differ, but the principles
remain the same.
• At BrightTALK we use Signals instead of Events
57. The basic principles are
• Doesn't matter whether you use Flex3, Flex4, or
something else?
• Doesn't matter whether you use Smartypants,
Robotlegs, Swiz, Parsley or do it yourself.
• Make your components smart.