Flex Best Practices – Models, Views, and Controllers
If you read through this entire post and don’t see anything for you, congrats and ignore this next comment.
No one seems to know how to actually implement MVC and I can’t stand it!
Too many programs out there set up like a procedural php page (front top to bottom): imports, sql statements, data, methods, and a ton of html. This is not how to set up a page, and even more so this isn’t how you set up an entire application! But people do it, don’t ask me how or why, but it’s a mess.
I want to let everyone know that the following “worst practice” example is actual code shown to me very recently. I simplified it a bit but ultimately the Flex application was one large mxml file.
You may try to argue that MVC takes more time to setup, more coding, “harder to read”, or whatever other arguments I have heard, but in the end it is easier to program, loosely coupled, simplistic, dry, object oriented, and finally best practice.
If your code looks like this, you are doing it wrong! (Worst Practice)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" creationComplete="application1_creationCompleteHandler(event)"> <fx:Script> <![CDATA[ import mx.controls.Alert; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.collections.ArrayCollection; import mx.events.FlexEvent; [Bindable] private var searchList:ArrayCollection = new ArrayCollection(); protected function application1_creationCompleteHandler(event:FlexEvent):void { runSearch(); } private function runSearch(event:MouseEvent=null):void { httpService.send({searchTerm:searchInput.text}); } protected function httpService_resultHandler(event:ResultEvent):void { searchList = new ArrayCollection( event.result as Array); } protected function httpService_faultHandler(event:FaultEvent):void { searchList = new ArrayCollection(); Alert.show("fault"); } ]]> </fx:Script> <fx:Declarations> <mx:HTTPService id="httpService" result="httpService_resultHandler(event)" fault="httpService_faultHandler(event)" resultFormat="e4x" url="http://www.someUrl.com/yourMethod"/> </fx:Declarations> <s:layout> <s:VerticalLayout gap="20" paddingBottom="20" paddingLeft="20" paddingRight="20" paddingTop="20"/> </s:layout> <s:HGroup width="100%"> <mx:Label text="Search Term"/> <s:TextInput width="100%" id="searchInput"/> <s:Button label="Do It!" click="runSearch(event)"/> </s:HGroup> <s:List width="100%" height="100%"/> </s:Application> |
This is an extremely simple example and honestly if this is all that your application needed to do then you are done. If your application is more complicated – or will get more complicated than this example – then this will fall apart real fast. On top of that good luck being able to unit test this code, reuse any of this code, using object oriented designs such as factories or even just interfaces, or even using the outliner view to find specific methods. Our final MVC application will be able to do all these things.
Quick Look At MVC
MVC is a simple concept that is immensely helpful at simplifying application development. The concept is just to split up your application by it’s model (the data), the view (what is seen), and the controller (the methods and functions that move the data from the view to the model and back).
Wikipedia – MVC
Understanding The Model
The models are your data centers for the application and extremely simple. In actionscript when you create models, this is the exact time you will want to use getters and setters for your properties. Why? Because the model just holds data and when the model has changed, it releases events to alert anything listening that the model has changed.
Best Practices: All of the properties in your model should have setters and extend the EventDispatcher to be able to send out events when the model has changed. You can see what I mean in my model code below. You could always use custom events to send let your application know of property changes, but for my example I will just use the basic Event class. It is also Best Practice to check that the property has actually changed before sending out events and updating the value. Double check that the variable has actually changed first. Very easy with strings and numbers and such, a bit more effort for larger complex objects.
Refactoring Your Code To The Model
For our example the model is EXTREMELY simple due to only one property, but you can see how simple the model is and how well it separates and simplifies the application layout. Finally you can now reuse this model in multiple controllers.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package com.unitedmindset.models { import flash.events.Event; import flash.events.EventDispatcher; import flash.events.IEventDispatcher; [Event(name="searchListChanged",type="flash.events.Event")] public class SampleModel extends EventDispatcher { public static const SEARCH_LIST_CHANGED:String = "searchListChanged"; public function SampleModel(target:IEventDispatcher=null) { super(target); } private var _searchList:Array; public function get searchList():Array { return _searchList; } public function set searchList(v:Array):void { _searchList = v; dispatchEvent(new Event(SEARCH_LIST_CHANGED)); } } } |
Understanding The Controller
Controllers are nothing more than a class that contains methods to move data back and forth from the data, update and handle responses from the view. I touched on this earlier but by separating this code into it’s own class you can have interfaces, subclasses, use unit testing on individual methods, and finally use the outline to jump to specific methods. Basically, everything that will help you grow as a developer as you make bullet proof applications.
Best Practices: The controller includes whatever methods are necessary and a reference to the view. The methods/handlers that are required by the view will always be public, everything else is private or protected. All events handlers should be in the controller and then the controller modifies the model and/or changes the view. However the view NEVER directly accesses the model. Again, my events from the model are just straight Event classes, though you could always make custom events from your model, though it is probably a bit overkill. Notice especially that the model is set to private to protect it from the view and other components. If you wanted to allow accessors to specific data within the model you may want to add getters in the controller, though again this is highly discouraged.
Refactoring Your Code To The Controller
Setting up your controller is simple, let’s start with a blank class.
1 2 3 4 5 6 7 8 9 | package com.unitedmindset.controllers { public class SampleController { public function SampleController() { } } } |
Now we just have to move the methods and change the functions that need to be available to the view to be public. Notice that the controller includes a model reference and listens for changes to the model and then updates the view as necessary.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | package com.unitedmindset.controllers { import com.unitedmindset.models.SampleModel; import flash.events.Event; import flash.events.MouseEvent; import mx.collections.ArrayCollection; import mx.controls.Alert; import mx.events.FlexEvent; import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; import mx.rpc.http.HTTPService; public class SampleController { [Bindable] public var view:UMBlogMVC; private var _model:SampleModel; public function SampleController() { _model = new SampleModel(); _model.addEventListener(SampleModel.SEARCH_LIST_CHANGED,_onSearchListChanged); } public function application1_creationCompleteHandler(event:FlexEvent):void { runSearch(); } private function _onSearchListChanged(event:Event):void { view.searchList.dataProvider = new ArrayCollection( _model.searchList ); } public function runSearch(event:MouseEvent=null):void { var service:HTTPService = new HTTPService(); service.addEventListener(ResultEvent.RESULT,_httpService_resultHandler); service.addEventListener(FaultEvent.FAULT,_httpService_faultHandler); service.resultFormat = "e4x"; service.url = "http://www.someUrl.com/yourMethod"; service.send({searchTerm:view.searchInput.text}); } private function _httpService_resultHandler(event:ResultEvent):void { var service:HTTPService = event.target as HTTPService; service.removeEventListener(ResultEvent.RESULT,_httpService_resultHandler); service.removeEventListener(FaultEvent.FAULT,_httpService_faultHandler); _model.searchList = event.result as Array; } private function _httpService_faultHandler(event:FaultEvent):void { var service:HTTPService = event.target as HTTPService; service.removeEventListener(ResultEvent.RESULT,_httpService_resultHandler); service.removeEventListener(FaultEvent.FAULT,_httpService_faultHandler); _model.searchList = new Array(); Alert.show("fault"); } } } |
Some people will argue that the httpservice should be in the model rather than in the controller. This is a point of contention among some developers. I believe it should be in the controller (or in a simple command) because it is a piece of logic that requests the data from the server, not the data itself.
Your Simplified View
Finally we will refactor our view to just the view elements and making a reference to the controller instance in your declarations section (for Fx4).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo" xmlns:controllers="com.unitedmindset.controllers.*" creationComplete="controller.application1_creationCompleteHandler(event)"> <fx:Declarations> <controllers:SampleController id="controller" view="{this}"/> </fx:Declarations> <s:layout> <s:VerticalLayout gap="20" paddingBottom="20" paddingLeft="20" paddingRight="20" paddingTop="20"/> </s:layout> <s:HGroup width="100%"> <mx:Label text="Search Term"/> <s:TextInput width="100%" id="searchInput"/> <s:Button label="Do It!" click="controller.runSearch(event)"/> </s:HGroup> <s:List width="100%" height="100%" id="searchList"/> </s:Application> |
Looking over this code you will notice that there is absolutely no logic in your view, keeping you view to only doing one thing, looking good. It is the controller instance that receives events from the view and the controller that houses all of your application’s logic.
Wrapping It All Up
Hopefully this is illuminating and pushes you to do some code refactoring. What is also great about this style of programming is that it works right in with any of your favorite frameworks. If you are making an application and are wondering “Where does this code go?”, you just have to ask yourself “is this part of what is seen, the data, or logic within the application?”. This separation will also make it easier for when you are working with junior developers and they don’t know where to put code. I am sure you can already see the benefits to not having services in your view and being able to reuse controllers over multiple views, and the ability to continue abstracting your code to new levels.
Good luck, and happy coding!





“Some people will argue that the httpservice should be in the model rather than in the controller. ”
I’d argue for MVCS. http://joeberkovitz.com/blog/reviewtube/
Very cool, will check it out!
nice write up!
oh, and please never look at my code!
I think it is time with a random code review… starting with…. wouldn’t you know. M. Bugbee!
Thanks for the simple overview for creating a MVC application. I plan on making my first attempt at MVC here in the first few weeks. Thanks again.
If you haven’t looked, also check out my Events Best Practices: http://unitedmindset.com/jonbcampos/2009/08/12/flex-best-practices-events/
I know this is going to come off like a “that guy” comment, so let me first say that I’m not trying to personally criticize you or your writings, I always dig people sharing their ideas, so thank you. The challenge with MVC is everyone has a different definition of an MVC implementation. I can guarantee you that the implementation in Smalltalk (where it originated as you probably know) is a heck of a lot different than what you described, or what other people call MVC. I think the need for separation of concerns and encapsulation through a clear API is really the issue, not necessary a strict pattern and rules based on purist statements that aren’t always true. I’m bitter because all the micro-architectures I see out there for flex claim to “be MVC”, that’s their claim to fame, yet all they’re doing is bringing J2EE problems and patterns to the world of Flex when the world of Flex doesn’t need it. You end up having to constantly work around the framework in the name of purism. Personally, I’ve had the most success establishing conventions and separation of concerns. My models actually have behavior on them, because otherwise, all you’re dealing with is a named hash (isn’t MVC supposed to be an OO concept). I’m going on a tangent here, so I’ll stop. I’ve been doing Flex and AS3 for quite a long time with great success. I started a new job about 4 months ago, and had Cairngorm forced upon me in the name of MVC, and I can say all it has done is clutter up our code. The concepts and benefits of MVC can be implemented using less rigid conventions.
Hank, I’m not going to disagree and I love your addition. It is true that no micro-architecture is perfect. I wasn’t a huge fan of them in the past, but I have warmed up to them and recently like it when I work with multiple programmers and can just say “it’s cairngorm/puremvc/mate” and they understand how the app is supposed to work. As opposed to “well I stuck my events here, and this class gets the services, and this one here…”. You get the point.
I understand that as people develop their application will grow and once in a while strict best practices falter and little patches start to pop up. But I believe that if people stick to best practices their applications will be much better off. I am sure you would agree that all to often developers stray the course and things get messy.
I will admit that my description of MVC is like an “MVC Light” version, but definitely enough for people to understand the concepts of separation of duties, which I believe is important to application development.
Thanks for the comments though! Always open for review!
Great post. I’ve read a few of your articles now and I get the feeling that you know your shit
I would say that what you are demonstrating in this article is closer to the presentation model pattern than traditional MVC. An interesting article on this debate can be found at http://www.componenthouse.com/article-5
In any case I’m currently trying to put together a small best practice example for unit testing flex code. I think that the Flex community is lacking a good reference point to consult when trying to adopt not only unit testing but best practices in general. I’ve love to get others involved in the process. If it sounds like your cup of tea, shoot me an email and we can have a chat about it.
I will openly say that I am a fan of the presentation model and also code behind. Guess I hide it enough with this post. I agree that best practices aren’t well put together in the community and as I continue to see others code I agree some reference is highly needed. I would be happy to talk to you about this shortly, just give me a few weeks to put some other projects behind me. You know the way it goes
You really should take a look at Cairngorm or Mate. Those frameworks make building your app in a MVC way a lot easier
.
[...] Source: http://unitedmindset.com/jonbcampos/2009/08/18/flex-best-practices-models-views-and-controllers/ [...]
It’s funny you say that because I am a pretty big proponent for using standardized frameworks including Cairngorm, Mate, and PureMVC. I agree they make things easier though then you do have to learn “how they do things”. Yet when I make examples I usually try to keep them framework agnostic. Thanks though!
Thanks for the clarity.
I like the way you identify what kind of code goes where.
And the “Events” article was equally enlightening.
Now can you do something on Command patterns?
I still got a big gaping undo, redo, ASync Command Chain hole in my head.
Sounds like a great topic, will do!
Flex Best Practices – Models, Views, and Controllers | The World In A State of Flex…
Thank you for submitting this cool story – Trackback from ADDBeats…
[...] ????: http://unitedmindset.com/jonbcampos/2009/08/18/flex-best-practices-models-views-and-controllers/ [...]
[...] things is from the internet.If you want to know the more information pleas visit the source:http://unitedmindset.com/jonbcampos/2009/08/18/flex-best-practices-models-views-and-controllers/: If you read through this entire post and don’t see anything for you, congrats and ignore this [...]
Hey man this was great example, but i have problem with the code. I am using flex 3.4 and this is my problem:
Inside _httpService_resultHandler function
line var service:HTTPService = event.target as HTTPService;
when i trace event.target it says that event.target is instance of object HTTPOperation not HTTPService so var service cannot be typed to HTTPService and is therefore null and thats why i can’t remove event listeners. But i don’t know why event.target is instance of HTTPObject when target is actually HTTPService. Any ideas?
Odd. I just reran the project to see if there was something I missed and while watching in the debugger I see event.target and event.currentTarget as both being a reference to the HTTPService.
This test was done with 3.4. Was there anything else changed that caused this trouble? Have you watched this in debugger and seen the output?
It’s really strange man. Maybe is mistake in my code and i don’t see where. Here take a look:
private function icon_mouseDoubleClickHandler(event:MouseEvent):void
{
var service:HTTPService = new HTTPService();
service.url = _deskConfig.SCRIPT_ROOT;
service.addEventListener(ResultEvent.RESULT, requestModuleResultHandler);
service.addEventListener(FaultEvent.FAULT, requestModuleFaultHandler);
service.send( {‘__PXDS_MODULE__’ : ‘system’, ‘__PXDS_ACTION__’ : ‘requestModule’, ‘module’:event.currentTarget.id} );
}
private function requestModuleResultHandler(event:ResultEvent):void
{
trace(event.target) // says [object HTTPOperation]
trace(event.currentTarget) // says [object HTTPOperation]
}
Very sorry, you’re right. The project was built back on 3.2 and I forgot to update the compiler options and just assumed it was built on the default (newest) like my other projects. When I run it I get a the target/currentTarget to be an AbstractOperation. The quick fix I would do is have a reference to the HTTPService in the controller and add remove as necessary. This might not be possible if you were intending to have multiple calls all running at the same time.
In this case you can still get a reference to the service (in the event.target) and just type it as an EventDispatcher (the lowest level that includes the removeEventListener) and just remove the link. Easy (slightly dirty) fix if you don’t want to type the event.target to AbstractOperation which also builts off of the EventDispatcher. All will achieve the desired result.
Thanks man. Cool. This needs me because i am trying to unload module in flex and i must get rid of all t event listeners. And i watched your post for tackling memory in flex and it was great that you share such information for free, although i was said because now i know what has to be done to unload module properly i don’t know how to do it. Simple example is text area in module when i click text area module won’t unloads. Only solution that i found on internet is to remove focus from text area. So before module unload i run this.stage.focus = null but without success. If you would share skype, gmail or im i would love to be in contact with you if you have time or will
Make sure to check this post out, when researching for my MAX presentation, he was one of the people I made sure to interview. http://blogs.adobe.com/aharui/2009/08/what_we_know_about_unloading_m.html
Usually I set up a “unloadModule” function that runs through many checks, including the focus issues. I’d definitely work to set up a good process for the actual unloading – more than the Flex unload method. Feel free to hit me up at jonbcampos [at] gmail and we can see what we can do time allowing.
Great. I read that post and there are good explanations what has to be done but i don’t know how. I also think of that only solution would be to create separate function to check what has to be done before unloading module, but i am stuck at simple text field and its focus. Thanks for support. I have already asked this question on actionscript.org so you can check it there instead of me bug you on mail http://www.actionscript.org/forums/showthread.php3?t=222889
[...] Flex Best Practices – Models, Views, and Controllers [...]
Thanks for your great article.
By using this architecture , I see I lose the code hinting and the auto complete provided by Flash Builder , for example , in the Controller , if I type :
view.searchList.dataProvider = new ArrayCollection( _model.searchList );
I don’t get any code hinting or auto complete list after typing “view.” .
it may be not important for professionals because they don’t need any help while coding, but for new comers to Flex like me it is vital …
correct me please if I miss something.