Responders inside Commands is this OK?

Enrique's Avatar

Enrique

04 Jun, 2011 09:07 PM

Hi ! I found a tutorial about robotlegs where they are calling a service with a command in this way:

public class LoadCountryData extends Command
{
   [Inject]
    public var applicationModel:CountryListModel;

    [Inject]
    public var service:CountryDataService;

    public function LoadCountryData()
    {
       super();
    }

   private var responder:CallResponder = new CallResponder();

    override public function execute():void
   {

        responder.addEventListener(ResultEvent.RESULT, resultHandler);

        responder.token = service.getCountryData();
   }

    private function resultHandler(event:ResultEvent):void
    {
        applicationModel.countryList = (responder.lastResult as Country_list).country;
     }
  }
}

How you can see the command is listening for the service responde directly, is this OK? I thought commands was destroyed after the execute, and we need to catch the result inside our service, and dispatch a new event (probably with the result) that creates a new command and assign it to the model for example.

  1. 2 Posted by seantheflashguy on 04 Jun, 2011 09:12 PM

    seantheflashguy's Avatar

    Hi Enrique,

    This should be fine. Updating the model from the command is correct.

    You can also just create your responder class and update the model there.

    HTH,

    Sean

  2. 3 Posted by Stray on 04 Jun, 2011 09:15 PM

    Stray's Avatar

    Hi Enrique,

    I wouldn't take this approach unless you also detain and then release the command using the command map - your listener here won't be cleaned up automatically, and the command will be held in memory by that and so it won't be disposed of and then the handler could potentially fire again the future.

    Unless there's something magical about Responder that is causing it to be cleaned up automatically?

    Stray

  3. 4 Posted by Michal Wroblewski on 04 Jun, 2011 09:17 PM

    Michal Wroblewski's Avatar

    It's almost fine. Commands can be GC'ed.

    To prevent it from being GC'ed use:
    in execute method:

    commandMap.detain(this);
    

    when you're done with that command (complete or error)

    commandMap.release(this);
    

    But it's always better to let model control service calls so I'd recommend that approach.

    Cheers

  4. 5 Posted by Weyert on 04 Jun, 2011 09:22 PM

    Weyert's Avatar

    Also clean up the event listener in the success event handler or does a responder clear this up? Because now it won't be garbage collected.

  5. 6 Posted by seantheflashguy on 04 Jun, 2011 09:25 PM

    seantheflashguy's Avatar

    Hey Enrique,

    Yeah definitely listen to Stray and Michal on this one and disregard my input. They are super knowledgeable about RobotLegs :)

    Sean

  6. 7 Posted by Enrique on 04 Jun, 2011 09:34 PM

    Enrique's Avatar

    Wow, 3 replies in less than 10 minutes, that's awesome, but now I'm more confused because the 3 replies are different :)
    [ EDIT, 5 replieeees !!!! please let me write :) ] I didn't know about commandMap.detain and release, and I thought the same as @stray.
    I know updating the model from the command is ok, but is OK to have a listener in the command? I thought commands was only "execute".
    I see this approach in Cairngorm (commands implements IResponder and they have a result and fault listener).
    @Michal how can be our command released if they have a listener? this case in particular is a bit confusing to me because the listener is added to "responder" which is part of the command, but the results come from the service, so I think there must be another listener in another place... maybe it doesn't matter because the service cleans everything for us. I can see and advantage in this design, each command that uses the service can use it's own result. Probably this is cleaner and faster (we don't need to map another command for the result, destroy this command, dispatch a new event in our service, create the new command).

    Is this a best practice in Robotlegs? are you listening the results of your services inside your commands?
    if not, what is the best practice for this?

  7. 8 Posted by Michal Wroblewski on 04 Jun, 2011 09:37 PM

    Michal Wroblewski's Avatar

    As I can see you have to manually remove listeners from responder because Responder class can handle multiple results.

  8. 9 Posted by Enrique on 04 Jun, 2011 10:02 PM

    Enrique's Avatar

    I want to recall that this is not my code, I found it in a tutorial.
    And after seeing your replies I see it's OK, but it's not so common, I mean, you are not using this pattern in your projects am I right?
    I can think only in another alternative:
    1) Command executes the service
    2) The service listen the result
    3a) The service dispatch an event mapped to another command
    3b) The service updates the model
    4a) The new command updates the model

    What is the pattern your are following?
    Do you see any pros and cons of listening the result inside our command?

  9. 10 Posted by Michal Wroblewski on 04 Jun, 2011 10:03 PM

    Michal Wroblewski's Avatar

    I use a model to call service. Service returns Promise (Responder-like). Command calls model method to call. In other approach you can call service from the command and when service get a result it (service) dispatches command with the result, which can be saved in a model. So there are 2 approaches I'd recommend.

  10. 11 Posted by Michal Wroblewski on 04 Jun, 2011 10:10 PM

    Michal Wroblewski's Avatar

    There's no problem to use AsyncCommand if you don't have to manage that responder during the call e.g. cancel it or else but remember about using detain and release.

    BTW. Check out that discussion

  11. 12 Posted by Enrique on 05 Jun, 2011 05:23 AM

    Enrique's Avatar

    OK, I've read those discussion, Promises, AsyncTokens, etc. Thanks Michal !

    Now this is my conclusion for the Best Practice:

    Service must be a singleton

    Service returns Promises (AsyncToken if you are using Flex and RemoteObject for example) so you can differentiate every response even when you have one Service.

    Commands call services, receive the Pomise, and listen for the result in the Promise (assign a Responder to the AsyncToken).

    The command updates the model, dispatch an event, or anything you want with the result.

    we don't need to use "detain" and "release" in our command because our command add a listener to the Promise (AsyncToken), so Promise has a reference to command, and Promise is saved from GC because has a reference on the Service which is never GC because is a Singleton.

    In the worst case, (if the service never release the Promise reference) we need to remove the listener to the Promise in our command (so at least our command is GC)

    I see that approach very similar to how commands works in Cairngorm. I'm a bit confused for that, I thought Cairngorm was the worst framework :(

    I can't see the advantage of executing a service from a command, releasing the command, and creating a new command from the service when the result is ready.
    Can you explain why or when that approach is better?

    Respec to to calling service from your model, are you listening the service from your model too? isn't that a "bad" thing?

  12. 13 Posted by Stray on 05 Jun, 2011 08:48 AM

    Stray's Avatar

    Hi Enrique,

    detain and release are relatively late additions to the CommandMap, so it's likely that early demos won't refer to them.

    Even if you are using a listener which should prevent GC, I would still use detain and release because these communicate your intent. They make it immediately obvious to the next developer (or yourself in six months time) that you intended this Command to not be short-lived.

    I would also clean up listeners explicitly, rather than hope for GC, again because it communicates your intent.

    We spend nearly all our time reading and thinking about code, and very little time writing it, so the code that *reads* the clearest is a good goal I think.

    Regarding the 'why bother with 2 commands' side - the answer is simply that you should split up responsibilities appropriately. It's very possible (I have this in my code) to have single command that calls a service, and then a series of different possible results, which then mean that you need variation in how you respond to those results.

    Personally my own set up is that a Command calls a service, the service is injected with a factory that handles any results, the factory then updates models and so on and the models release update events which the view uses (via mediators) to update itself.

    But it all depends on the details of your application.

    Whatever you do, do it mindfully and express your intention clearly in your code, and you'll be winning :)

    Stray

  13. 14 Posted by Enrique on 05 Jun, 2011 02:08 PM

    Enrique's Avatar

    You are right @stray about writing clean and clear code, I do that at really, but is good to know what is necessary and what not too.

    About the pattern, it's true that exists a lot of way for doing the same thing, this happens all the time, but I'm always paranoid about performance, and even more in Flas/Flex which is full of memory leaks taht we can't control (more in old players).
    That's why I'm always trying to code with the "best practices".

    Do you have a sample of the code, or an open source project to see it better @stray? I'm not catching your factory idea.

    // Maybe that could be a good idea, to have a repository with projects/apps written in Robotlegs.

  14. 15 Posted by Enrique on 06 Jun, 2011 06:24 PM

    Enrique's Avatar

    @stray: OK, I found your explanation about factory and services and so on here: http://knowledge.robotlegs.org/discussions/questions/451-does-model...
    If we are using the caller command for receiving the results too (an async command) then we need to inject the factory (parser) inside our command not the service, but the idea is the same. Thanks!

    About your comment:

    The only part that I'm not happy with is the use of the check against 'null' to decide whether the builder hit an error. I'm sure there is a better way to do this, but I haven't worked out what that is yet! Any input there gratefully received...

    why you are unhappy with that?
    if you want an onResult and onFault but synchoronous maybe you can throw an error in your Builder (in the Factory, the try is onResult, the catch is onFault)

  15. Support Staff 16 Posted by Stray on 07 Jun, 2011 10:46 AM

    Stray's Avatar

    Yes, I think you're right Enrique. I had an unspecified aversion to that approach, but I don't know why that felt just as wrong.

    I think I was trying to keep my many-many builders dry, and not sure whether to do the error handling via inheritance or composition.

    Stray

  16. 17 Posted by Michal Wroblewski on 07 Jun, 2011 10:50 AM

    Michal Wroblewski's Avatar

    [off topic]

    Stray, it's just your Programmer sense you talked about in one of your posts. It won't let you stop drilling ;)

  17. Support Staff 18 Posted by Stray on 07 Jun, 2011 01:15 PM

    Stray's Avatar

    :)

  18. Ondina D.F. closed this discussion on 02 Nov, 2011 12:47 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac