Futurescale, Inc. PureMVC Home

The PureMVC Framework Code at the Speed of Thought


Over 10 years of community discussion and knowledge are maintained here as a read-only archive.

New discussions should be taken up in issues on the appropriate projects at https://github.com/PureMVC

Pages: [1]
Print
Author Topic: Document-Based Application: is PureMVC the way to go?  (Read 26947 times)
shauno


Email
« on: February 11, 2009, 06:37:17 »

Hello!

Lately I've been struggling a bit with PureMVC and a particular application I'm building. I've been very happy with the framework up until this point (don't get me wrong, I dig it!), but the framework seems to be adding a lot of unnecessary complexity in this particular case.

I wrote a pretty useless post about it on my blog, but Cliff suggested it would be more appropriate to open it up for discussion with the community. I agree. Please bear a couple of things in mind though: I'm not bashing PureMVC, I'm still learning the ins-and-outs of application design (who isn't!?), and I haven't made mind up on the framework quite yet. Here goes:

My project could be described as document-based: there many identical view components, each in need of mediation, but representing different models. These components can appear in many places throughout the app, nested inside of other components and containers, coming and going as the user navigates.

Perhaps, for example, we have a comment list component, but instances of that component can appear near the root of the app as well as inside Tab Navigators, Pop-up Windows, and a couple of other places simultaneously. For one thing, I found it tricky to design a mechanism for creating, registering and removing Mediators for such components as they appear and disappear.

Secondly, say the component lazily loads a list of comments from the server when it has focus: it's Mediator calls a method on a Proxy, and the Proxy sends a Notification when it's retrieved the list of comments. All Mediators of this type then receive that Notification and we have to come up with another mechanism for filtering the response - only one of them was actually interested in that particular list of comments. It's not the sort of thing that anyone else really needs to know about - the application model hasn't changed.

Maybe Proxies shouldn't be the gateway to Services, but I don't really know where else to put them in a PureMVC application.

Perhaps there are decent ways to handle the issues above, but I feel that they will probably just add code and complexity, and ultimately be fighting against how the framework was designed.

Anyhow, some other things have also started bugging me:

Boilerplate code: creating Mediators and Proxies can be quite tedious - I find my spirits drop a notch whenever I need to create one of them.. "Ok, let's do this thing! Woo! Create New Class.. Must extend some class and implement some interface.. and define my static NAME constant.. and.. ah.. create a getter to cast my view.. and.. override onRegister to hook up my view listeners.. and override listNotificationInterests.. and handleNotification.. and viola! I can start coding!" Actually, that's first time I've listed it our for myself - should keep that for next time :)

A Mediator could be this simple: A class with two typed properties - a reference to a view component and a reference to an event bus - both injected by an IOC container whenever the view is added to the stage. It needn't extend some framework class. We could even do away with the event bus and just use the view as a dispatcher if we were using regular Events instead of Notifications (and if we were so inclined.. I'm not).

A Proxy could be just as simple. And using an IOC container instead of a Model/Service locator (registry), we could easily reconfigure our application. Constructing, initialising and registering our actors in commands makes this difficult.

Casting: casting is to expected when using a registry to store objects, but it's not like it gives us any flexibility: we have to know the actors type (to get it's static NAME constant) to pull it from the registry anyway. I feel it's appropriate to hard-wire certain things: some things really should be concrete. What is the advantage of throwing things into a loosely coupled bucket but then having to cast them all over the place afterwards anyway?

Having only used PureMVC up until now, I have started looking into other frameworks. Each one has it's pros and cons (as expected), but each has something groovy to bring to the table.

PureMVC:
I like: Works with Flash and Flex
I like: Mediators - keep views entirely free of framework code
I like: Proxies - are "deaf" (don't listen, but can be called directly)
I like: Commands - are stateless, and can be easily wired to system events
I like: Documentation, utilities, community
I don't like: Boilerplate code
I don't like: Framework code in my Mediators and Proxies
I don't like: Lack of formal Services concept
I don't like: Custom event bus instead of using native Flash events

Mate:
I like: Combination of Injectors and ObjectBuilders can auto-wire mediators to views
I like: Binding fits naturally with framework
I like: Laura Arguello's accent
I don't like: Flex only
I don't like: Presenters instead of Mediators - making view components harder to re-use
I don't like: Bubbling events - essentially putting system communication responsibilities on views
I don't like: Declarative injection limits flexibility

Swiz:
I like: Works with Flash and Flex
I don't like: The word "bean"
I'm not sure about: Everything else - singleton, central event dispatcher, metadata for dependency injection, documentation

At the moment I'm feeling like PureMVC teaches the right principals (separation of concerns) but is overkill for the problems it is designed to solve. MVC is just a guide. Once you understand how the actors in PureMVC interact you should know how to treat and design components in your system without using the framework - is a generic MVC framework is even necessary? You could implement MVC without one. It might look like this:

One or more Event Busses - hold references to dispatchers and actors
Mediators - hold references to a bus and a view component
Proxies - hold references to a bus and a model
Services - hold references to a bus and a service gateway
Commands - get passed a reference to a bus when executed
IOC Container - to define rules for wiring the above components

Yes, I'm probably being very naive. I'm just battling with this stuff at the moment.. looking at my project and trying to figure out if there is a better way to build it. I'm also not sure that everything I've said makes sense - apologies if I come off sounding like a babbling lunatic! Lack of sleep and a head swimming in code :)

So, honestly, how are you guys/girls enjoying working with PureMVC?

EDIT: Links:
http://code.google.com/p/mate-examples/wiki/DocumentBased
http://en.wikipedia.org/wiki/Dependency_injection
http://mate.asfusion.com/
http://code.google.com/p/swizframework/
« Last Edit: February 13, 2009, 08:01:43 by shauno » Logged
willw
Full Member
***
Posts: 30


View Profile Email
« Reply #1 on: February 12, 2009, 05:59:55 »

> Secondly, say the component lazily loads a list of comments from the server when it has focus: it's Mediator calls a method on a Proxy, and the Proxy sends a Notification when it's retrieved the list of comments. All Mediators of this type then receive that Notification and we have to come up with another mechanism for filtering the response - only one of them was actually interested in that particular list of comments. It's not the sort of thing that anyone else really needs to know about - the application model hasn't changed. <

How about: the Mediator passes in 'this' to the call on the Proxy (natch untyped, as an Object reference, so the Proxy remains ignorant of the Mediator). The Proxy stores it in its AsyncToken, as described in Cliff's answer to me here http://forums.puremvc.org/index.php?topic=991.0 (but you store an object ref instead of a callback).

When it handles the result from the service, the Proxy includes the object reference in the Notification that it creates. Mediators look for the reference, and then only process them if they match 'this'.

Will
Logged
shauno


Email
« Reply #2 on: February 12, 2009, 06:24:50 »

How about: the Mediator passes in 'this' to the call on the Proxy

Hi Will,

Indeed, that would work. But I feel the need to "filter" is, in this case, a little unnecessary and just creates extra work - no model has changed state in the application, so there isn't any need to notify the entire application of this event.

Another option might be to return a result directly from the proxy call, say, an unpopulated DTO/VO and give it to the view immediately. The view could then bind to the DTO which gets updated by the service when the result is received. Just thinking aloud. Thanks for your response.

Cheers,
Logged
willw
Full Member
***
Posts: 30


View Profile Email
« Reply #3 on: February 12, 2009, 07:49:37 »

Yes, that's neater, and presumably you would store the VO in the same way, as part of the AsyncToken.

Do you need to handle the failure case in the Mediator/Component? (That's where my schemes tend to get sticky.) But perhaps an empty VO is good enough, and use a general failure reporter.

Will
Logged
shauno


Email
« Reply #4 on: February 12, 2009, 08:04:11 »

Perhaps a "serviceError" property on the VO - if blank then all is well, if populated then there is a problem. There could also be properties for progress etc, but wouldn't want to put too much of that in the VO.

// Shaun
Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #5 on: February 12, 2009, 09:37:49 »

Perhaps, for example, we have a comment list component, but instances of that component can appear near the root of the app as well as inside Tab Navigators, Pop-up Windows, and a couple of other places simultaneously.

Document-based applications that can have multiple instances of a 'document viewer' component bound to multiple instances of a 'document model' can be handled easily in two ways using PureMVC.

In the Standard Version of the framework where there is only one Model, View and Controller for the whole application, you generally need to create a relationship between a specific mediator and a specific proxy. However you still want this to be loosely coupled.

So when a new 'document' is created, there are 4 parts - 2 boundary objects and 2 framework objects:   
  *  a document view - the view component / display object
  *  a document model - the data carrier / value object
  *  a document mediator
  *  a document proxy

One Command instantiates and registers everything. Since there will be multiple instances of both the Mediator and the Proxy, their names must be dynamically generated, and the trick to tying them together is to simply name them the exact same thing. This can be the document name, for instance. So the View has a Mediator named "doc1" and the Model has a Proxy named "doc1".

:
var docName:String = note.getBody() as String; // document name passed to command

var docView:DocumentViewComp = new DocumentViewComp(); // the document view
var docModel:DocumentModelVO = new DocumentModelVO(); // the document model

facade.registerProxy( new DocumentProxy( docName, docModel) );
facade.registerMediator( new DocumentMediator( docName, docView) );

facade.sendNotification( ApplicationMediator.INJECT_VIEW_COMPONENT, docView ); // inject view comp

When the Mediator wishes to retrieve its document model it can do so easily by saying:

:
var docName:String = this.getMediatorName();
var docProxy:DocumentProxy = facade.retrieveProxy( docName ) as DocumentProxy;

When the Proxy sends an update notification, it should set its own name as the type parameter for the notification:

:
var docName:String = this.getProxyName();
facade.sendNotification( UPDATED, data, docName );

When the Mediator is evaluating notifications that come from that Proxy, it can simply check the type property and only act if the type property of the note is equal to the mediator name:

:
        case DocumentProxy.UPDATED:
             if ( notification.getType() == this.getMediatorName() ) {
                 docView.data = notification.getBody() as DocumentModelVO;
             }
             break;

In the MultiCore Version of the framework there can be any number of Model, View and Controllers for any number of modules. You have a whole different level of separation available that can lead to far easier reuse outside of the application you're writing.

Consider the PipeWorks demo. It has a RSS Reader module that has its own PureMVC apparatus isolated from that of the application it appears in except in that it can communicate via messages to the other modules or to the app.

Now, the view hierarchy of the demo is quite simple, you just keep adding readers to a big canvas, each tuned to a different feed. But the same approach seems applicable to your comment list component. These RSS readers could easily be placed in a more complex hierarchy. Or into another application altogether. Total separation and totally reusable. The RSS module makes it's own service connection and fetches its own data, but the model could easily be injected in a message from the main app if it needs to.

Inside the modules you don't have any of this issue of trying to bind specific Proxies to specific Mediators. From the module's perspective there's only one Document View component connected to one Document Model component. Easy to develop, easy to understand, easy to reuse.

For one thing, I found it tricky to design a mechanism for creating, registering and removing Mediators for such components as they appear and disappear.

As for registering the Mediators the command shown above should clear that part up. As for removing the Mediators, they should remove themselves by listening for the 'removed' or 'removedFromStage' events from their own view components:

:
override public function onRegister() {
    docView.addEventListener(flash.events.Event.REMOVED_FROM_STAGE, onViewCompRemoved);
}

private function onViewCompRemoved(event:Event){
    docView.removeEventListener(docView, onViewCompRemoved);
    docView == null;
    facade.removeMediator( this.getMediatorName() );
}

private function get docView():DocumentViewComp{
    return this.viewComponent as DocumentViewComp;
}
 

As for Laura's accent, I'm afraid I'll never be able to compete with that. :)

-=Cliff>
« Last Edit: February 12, 2009, 09:40:47 by puremvc » Logged
shauno


Email
« Reply #6 on: February 13, 2009, 01:18:50 »

Hi Cliff,

Thanks for the in-depth response, and code samples. As always, this forum proves to be an in-valuable resource for PureMVC application developers.

I think a better way for me to explain my dilemma is to imagine that almost the entire view object graph is outside of my control. Not a completely unreasonable workflow. Imagine I am given an entire Flex app produced by a Flex UI layout specialist, and I wish to "wrap" my application code around it. I am often not the one instantiating the view components, but I wish to wrap mediators around components reflexively as they appear.

Say that some event causes a pop up Window to appear. The Window contains a Tab Navigator that employs deferred instantiation of view components. The third Tab Item contains an Accordion. The second Pane of that Accordion contains a custom List component. As a side note, the entire Window can be closed by simply clicking a little "x" button in the top right corner of the window.

That List component can appear in any number of convoluted configurations, lazily instantiated, nested as deeply inside other components as the UI designer deemed appropriate, and disposed of by means outside of my control. But it should always do the same thing: load a list of items from the server. So, I write a Mediator for the custom List component, to bridge it back into my application. Wiring up that Mediator is what I am finding tricky. Of course, to remove the Mediator I can always listen to the view as you suggested, so that's not really a problem.

I wish I had a better way to explain it, but perhaps it's the difference between outside-in, and inside-out. If that makes any sense at all!

The reason I was hesitant to start this topic in the first place, was that in order to properly demonstrate why I don't feel PureMVC is a good fit for these types of situations, I would need to come up with a better system - a ridiculous task. So now I lie awake at night trying to invent some reflexive/automatic MVC framework, weighing the pros and cons of every approach, desperately trying to ignore the very likely possibility that eventually, having discounted all my ludicrous ideas, I will end up with a system identical to PureMVC, but with a sillier name!

Nevertheless, I feel it's a good exercise - this is how I learn: by trying things my own way and making plenty of mistakes, so that I can fully understand the complexities of the problems I am dealing with. Only then can I trust that third party code really is making my life simpler. At the end of the day, I might arrive at the conclusion that PureMVC is indeed still my framework of choice, but without the nagging feeling that "there must be a better way".

As Jeff Atwood says: "So, no, you shouldn't reinvent the wheel. Unless you plan on learning more about wheels, that is."

Have a great weekend all!

// shaun
Logged
miroslav
Newbie
*
Posts: 2


View Profile Email
« Reply #7 on: February 13, 2009, 09:29:06 »

Hi Shaun,

I know how you feel since I had similar moments in my projects and in many cases you see the solution when you look at the problem from different perspective. You just have to keep trying :)

I don't know how your project looks but I'm guessing that you have one mediator for Flex application instance and no matter how deeply your list component can be nested you always know when you need to display that data (Flex has many events for view components states) and you can always be sure that this list component is on display tree.

The way I would try to solve this problem is to dispatch custom event from the list component and let it bubble up to the application instance, in application mediator listen to this event and fire notification that will trigger command for registering mediator and proxy as in Cliff example for standard version of PureMVC. This should be very simple solution, one event and one notification.

I hope this helps you :)

Miroslav
Logged
shauno


Email
« Reply #8 on: February 14, 2009, 02:11:00 »

Hi Miroslav,

Thanks for your response. That would certainly work, and is nice and simple. But imagine that I really cannot add even a single line of code to the view component - not even one that simply dispatches an event.

I'm busy playing with an idea that uses a similar approach: building a dictionary of view component class definitions to mediator class definitions. The application mediator that you mentioned then listens to the application for ADDED_TO_STAGE events and fires off a command to wire up the mediator. It works, and feels kinda magical ;)

Cheers,
Logged
onison
Newbie
*
Posts: 1


View Profile Email
« Reply #9 on: February 24, 2009, 02:05:52 »

I have the same dilemma to choose or not to choose pureMVC. My project looks pretty much  like ScrapBlog.com. AS3 and PureMVC are both new to me, so it makes me even harder to understand how to use PureMVC to develop a ScrapBlog.com like web application. For example, for the following task:
1) view : lots of identical dynamic add/remove textboxes in one document
2) view: a text format toolbar to show the format of active textbox, like font name, font size, letter spacing, etc.. also the toolbar need to set text format to the active textbox.

So a question for every actionscript guru -  what’s the right way to implement one mediator as the bridge to those textboxes and the text format toolbar?

Details information will be very welcome and appreciated.

-Raymond


Logged
puremvc
Global Moderator
Hero Member
*****
Posts: 2871



View Profile WWW Email
« Reply #10 on: March 23, 2009, 12:02:43 »

The toolbar would have a single mediator. See the CodePeek demo which has a toolbar for search. Its just a component like any other, handled by a mediator like any other.

The dynamic textboxes would all likely have their own mediators, each an instance of the same class, so they need to be dynamically named as opposed to using a constant for the mediator name. See the HelloFlash demo for an example of this scenario. There, we have th HelloSprite which, when you drag it, emits more HelloSprites, each mediated by its own HelloSpriteMediator. Visually it may seem quite different, but conceptually it is the same.

-=Cliff>
Logged
shauno


Email
« Reply #11 on: April 18, 2009, 04:56:16 »

Just a quick follow-up for anyone who might be interested: I tried my hand at writing a PureMVC-like framework that uses Dependency Injection and features Automatic Mediator Registration. It's called RobotLegs AS3. More info here:

http://shaun.boyblack.co.za/blog/2009/04/16/robotlegs-an-as3-mvcs-framework-for-flash-and-flex-applications-inspired-by-puremvc/
Logged
Pages: [1]
Print