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

Show Posts

* | |

  Show Posts
Pages: [1]
1  Announcements and General Discussion / General Discussion / Re: 5 reasons PureMVC kicks ass on: April 17, 2008, 11:22:39
After using PureMVC intensively for four months now, I wholeheartedly agree  :D

After twenty years in software this is the nicest framework I've used. It is simple and clean and 'flows' without the need for artifacts. Its a joy to work on a UI project where the architecture supports solving problems. Most questions I run into have an answer on the forum already. If you follow the suggestions in the 'best practices' documentation solutions fall into place.

Many Kudo's to Cliff.
2  Announcements and General Discussion / General Discussion / Re: Notification Stacking on: April 17, 2008, 11:14:34
If you're using Flex then there might be an easy solution for this using 'callLater'.

From the docs: 'The callLater() method queues an operation to be performed for the next screen refresh, rather than in the current update.'
3  Announcements and General Discussion / Architecture / Re: Asynchronous command chaining on: January 28, 2008, 10:33:13
Thanks for the link Joel,

This would indeed be a solution for the problem I raised.  Spicelib looks nicely done.

In the meantime I've come up with a similar more lightweight approach, based on the AsyncToken pattern.
A class 'SequentialCommandQueue' provides a method to add commands for execution. When a method returns an AsyncToken it is considered a asynchronous command, otherwise a synchronous command. On execute the list of commands is traversed until completion. When a command returns a AsyncToken the queue adds itself as the responder and waits until a response has been received. On success it continues with the next command. On fault it invokes the fault handler.

I'm using this in commands to update models, and in models to call services.

interface ISequentialCommandQueue
    public function addCall( func:Function, resultHandler:Function=null, faultHandler:Function=null, ... args ):void;
    public function execute():AsyncToken;
Simple example:
public class LogonCommand extends SimpleCommand
   override public function execute( note:INotification ):void
      var event:LogonEvent = note.getBody() as LogonEvent;
      var q:SequentialCommandQueue = new SequentialCommandQueue();
      var configProxy:ConfigurationProxy = facade.retrieveProxy( ConfigProxy.NAME ) as ConfigProxy;
      var userProxy:UserProxy = facade.retrieveProxy( UserProxy.NAME ) as UserProxy;
      q.addCall( configProxy.loadConfiguration );
      q.addCall( userProxy.logon, null, onLogonFailure, accountName, password );
      q.addCall( userProxy.retrieveUserData );
      q.addCall( sendNotification, null, null, ApplicationFacade.NTY_LOGON_COMPLETE );

   public function onLogonFailure( event:Event )
Sometimes it is necessary to share state between multiple methods This can be done by create a 'task' class with the methods that share state and add these methods to the queue. Each method can store the state in the task class instance.

My objective was to have something lightweight with a minimal memory footprint and the least amount of overhead. I found this to work really well.

4  Announcements and General Discussion / Architecture / Re: Asynchronous command chaining on: January 08, 2008, 04:01:06
Thanks for the quick reply and sorry for the slow follow up. I was experimenting with your suggestions and some other ideas.

In the previous example, the user account creation complete notification is wired up to the create mailbox command. The solution does work well. However, I do see some disadvantages with this approach:
1. The user account proxy didn't used to have knowledge of mailboxes. Now it needs to add a parameter to pass data around with which it has nothing to do. The more of these workflow-ish commands are added, the more unrelated data has to be passed around.
2. It puts business logic in the notification wiring, where it doesn't belong. The ability to create a mailbox after a user account now also needs to be coded into the ApplicationFacade notification wiring, and in the user account proxy (which passes the data around). For this simple example this is no problem, but for a large application the number these dependencies becomes ugly.
3. I found myself adding notifications for the sake of wiring commands together. Maybe I'm being picky but it feels like the notifications are used to fill in for a missing part.

So, how to pass data around in a manner that scales, while still honoring the stateless command principle?
I'll try by generalized your suggestion a little as follows:
Instead of passing the mailbox info to the create user account proxy, an array is passed with a set of proxy functions and parameters. The result handler of the proxy takes the next proxy function from the array and calls it, passing in the parameters and the remainder of the array. This repeats itself until all proxy functions are called.

With this approach each Command can build a set set of proxy functions that need to run sequentially. The model proxy's don't need to know any details of follow-up action, just support the ability to pass such actions through.

I'm still not completely happy with this solution because passing in the proxy function array adds an artifact to proxy functions that doesn't belong there because it isn't needed to perform its function.  The burden of serializing asynchronous commands doesn't belong in model proxy's nor does it belong in the facade wiring. Still, I take this last approach as the lesser of the two evils.  ;)

Alternatively, a proxy aggregate class can do it all. It can be used to build up multiple proxy commands, can be a responder for each proxy function, and sequentially call the proxy functions.

Thanks for the discussion Cliff and Rhysyngsun. I really appreciate your feedback and hope you can keep sharing your thoughts.
5  Announcements and General Discussion / Architecture / Re: arch_101's StartupCommand vs BestPractice's ModelPrep & ViewPrep commands on: January 08, 2008, 03:11:31
The initializeView and initializeModel methods are intended as hooks to allow you to use your own View or Model implementation. They cannot practically be used for preparation of Model and View.

Ah I understand,
Thanks Cliff
6  Announcements and General Discussion / Architecture / Re: arch_101's StartupCommand vs BestPractice's ModelPrep & ViewPrep commands on: January 04, 2008, 05:22:53
This is a question that I have as well.

I'll go a step further (risking ire and despair of the PureMVC guru's)...

The Facade class has protected methods for initializeModel and initalizeController. These are called by initializeFacade during facade instantiation.

Would there be a problem with registering proxies and commands in these methods in the concrete facade? The motivation is pure pragmatism. You don't have to look in three or more different places just to find out what is being instantiated during startup.

I can see why registering the mediators at this point is a problem since these depend on instantiation of the views.
7  Announcements and General Discussion / Architecture / Re: Asynchronous command chaining on: January 04, 2008, 05:08:54
@Cliff: thank you very much for the elaborate response and the explanation. I understand (and agree) that keeping commands stateless avoids a swat of problems and that the model should hide the backend integration. There is a lot of elegance in the simplicity of it and I'd love to keep it that way.
Unfortunately, the problem remains. I am probably making things too difficult so let me try to describe a simple use-case. Hopefully you can suggest a more PureMVC'esc approach for it.

@Rhysyngsun: thanks as well, that is something I can try, but how to solve the problem of conditional subcommands?

The use-case is: create a user account, with optionally an email mailbox. If the request to create the user account fails then no email mailbox should be created.
1: Add command 'createAccount', which has a parameter that indicates whether a mailbox should be created as well. In addition there are two model proxies, one for the user accounts, one for mailboxes.
2: When executed, the command calls the user account proxy and adds the user. The mailbox can't be created yet until we're sure the create user account request was accepted.
3. user-account-proxy sends a user-account-creation-successfull notification. So far so good.
4. The user-account-creation-successfull notification is bound to the create-mailbox command.
5. The create-mailbox command invokes the mailbox proxy to create a new mailbox.

The problem is that the state of whether the mailbox should be created, is lost along the way.

I appreciate the excellent feedback.  :D
8  Announcements and General Discussion / Architecture / Re: Asynchronous command chaining on: January 04, 2008, 12:09:10
Has there been any progress in async command chaining?

I'm facing a similar situation where a macro command needs to execute a number of simple commands sequentially. Each simple command talks to the model which in turn has one or more calls to the backend (log on, get configuration, etc), which are asynchronous.

The philosophy that backend interaction is hidden in the model is nice and simple, however, that doesn't mean we can ignore the fact that some commands  are asynchronous. When there is a sequential dependency between commands, there is a need to wait until one async command is finished before the second one is started.

In short, the current implementation of the MacroCommand needs async support.

Here is one possible approach. This is just to help the discussion.

A. Add an IAsyncCommand interface and a SimpleAsyncCommand class.

   public interface IAsyncCommand
       * Execute the <code>ICommand</code>'s logic to handle a given <code>INotification</code>.
       * @param note an <code>INotification</code> to handle.
       * @param responder an <code>IResponder</code> to report the result of the command.
      function execute( notification:INotification, responder:IResponder ) : void;

The SimpleAsyncCommand class stores its responder (the MacroCommand), and calls into the model proxy. When the model proxy replies with result or fault method, SimpleAsyncCommand passes it up to its responder (the MacroCommand). The MacroCommand implements IResponder and uses the result method to flag the command as complete and continue on to the next command.

In addition, since SimpleAsyncCommand can talk to one or more asynchronous model proxies, the model proxies will need a responder to reply to as well. This can be implemented in SimpleAsyncCommand base class with the default behavior to pass the result or fault method back to the responder (the MacroCommand).

        public class SimpleAsyncCommand extends Notifier implements ICommand, INotifier, IResponder

IResponder is defined in Flex. Since you aim for cross-platform portability a similar interface can be provided with PureMVC.

The same pattern repeats itself in the model proxy and in the model business delegates. Unfortunately, the model proxy cannot use the same implementation. Only one instance of the proxy is being cached by Model. If it would store the responder, a second call risk overwrite the responder if the first one hasn't replied yet. A Flex solution is using the Async Token as described in this thread: http://forums.puremvc.org/index.php?topic=68.0

A possible more portable implementation is to use an 'async command queue' in which stores the responder, and one or more business delegate instances with the corresponding response handlers. The async command queue can be used by the MacroCommand in calling one or more SimpleaAsyncCommand, by SimpleAsyncCommand in calling one or more model proxies, and by a model proxy in calling one or more business delegates.

I'm looking forward to hearing your thoughts on this approach and whether you think its worth developing it further.

Pages: [1]