Guidelines for Event / Commands - granularity and ratio

rob's Avatar

rob

26 Aug, 2010 01:05 PM

Hi,

I started using RobotLegs for a couple of days, but I find some parts of it difficult to swallow - for the extra effort you get great architecture, it slows development of the initial version significantly (at least whilst I'm working through the learning curve).

So if I think about a simple use-case, lets say that I have one main form and one login form. This login form I'm going to display a grid of the latest announcements, before the user even attempts to login - after all it might be letting you know that the system is in maintenance mode, etc.

So logically I think I need the following classes:

MainView (MXML)
MainViewMediator
LoginView (MXML)
LoginViewMediator

LoginRequestEvent (display login form, attempt login, login success, login failure)
LoginCommand (execute the LoginRequestEvent)

NewsEvent (display news form, request news, news response, clear news)
NewsCommand

I would add the view->mediator mappings in the context file, then create a NewsEvent.RequestNews event, then dispatch it, which would cause the NewsCommand to kick into action.

The news command would then be able to interrogate the associated event, calling a private method that's sensitive to the event type - or should I have a command for each type of news event. i.e. DisplayNewsCommand, RequestNewsCommand, HandleNewsResponseCommand, ClearNewsCommand?

The comand will have the responsibility of invoking the service and then injecting the results in to the model. The model will then create a NewsEvent.NewsResponse populating the payload and then dispatching it.

The mediator then receives this and marshalls it to the view...

I might as well just make the news-grid bind directly to the models data - is this good practice (and how? - I'm used to doing everything in MXML, I guess something like loginView.grid.provider=newsModel.newsList() ?

It would seem that I'm re-using my news event for requests and responses, is this good practice?

I then question my Event object - it feels like that too should be separate, i.e. NewsCollectionEvent, NewsClearEvent, NewsDisplayEvent... but then I get concerned that I have an event and command that seem to have 1..1 mapping and add little value.

What granularity should I be aiming for? Are there any guidelines for naming conventions, granularity and the ratio of view -> commands?

Your help is appreciated,
Rob.

  1. 1 Posted by Aaron Hardy on 26 Aug, 2010 03:17 PM

    Aaron Hardy's Avatar

    Here's how I would do it. I'm not advocating that I'm a best
    practices master or anything.

    I'd have a single command, RequestNewsCommand. I'd execute that by
    dispatching an event, like you said. Alternatively, you could cut out
    the event and command by having the mediator call the service
    directly. On small projects I'd do that, but in larger projects I'd
    probably stick to the event+command+service. See Shaun's comment
    about when this may or may not be appropriate
    (http://knowledge.robotlegs.org/discussions/questions/258-best-practice-value-lists).

    When the service receives a response, I'd probably just have the
    service parse the response and drop it on the model on a property like
    "news". I usually don't feel it's necessary to have a
    response-handling command unless some non-parsing logic needs to take
    place and even then I don't use a separate command most of the
    time...I just have handlers in the the requesting command.

    When the news is set on the model, I generally dispatch events
    notifying that the model has changed. For example, I might dispatch a
    AccountsModelEvent.NEWS_CHANGED event. "AccountsModel" would be
    whatever the model was named. Usually I don't have it carry any
    payload but it could. If I wanted to get more granular I could make
    it a NewsEvent like you mentioned that carries a specific payload, but
    usually I find that to be more than necessary. The mediator watches
    for the event and, when heard, picks the news off the model and sets
    it into the view. Be careful what you name your events. You
    mentioned "NewsEvent.NewsResponse" but in my perspective the model
    shouldn't know/care than it's due to any type of response--it just
    knows it's news value is changing. Even so, I'm sure there are those
    who disagree with how I name my events.

    So, in general I would be using one command and two events (one for
    initiating the request and one for notifying of a model change). If I
    was feeling really lazy or knew my app wasn't going to be large or
    complex or that nobody was going to work on it (famous last words) I'd
    cut out the request event and command and head straight to the
    service. Adding to what Shaun said in the post I mentioned above,
    there are other good reasons to go the event+command route. For
    example, let's say you had two views that needed to show the same
    news. Which one initiates the request for the news? I'd say both
    since they should be independent of each others' actions. However,
    you probably only want the news to be loaded once. If you went
    straight from both mediators to a service, somewhere you're going to
    want some logic that makes sure the news only gets requested once. On
    the other hand, if you went with an event+command+service then you
    could have Robotlegs take care of that for you using the oneshot
    parameter when mapping an event to a command. There are things like
    this where I'll start out having the mediator calling a service
    directly and then later find it's actually simpler using an
    event+command+service.

    Regarding the various commands you mentioned:
    DisplayNewsCommand - I can't see much use for this.
    RequestNewsCommand - I'd use this as described above.
    HandleNewsResponseCommand - I normally wouldn't use this but know
    several people who would.
    ClearNewsCommand - I would use this if I needed the functionality.

    Hope that helps. I'm interested to see what others say. If anyone
    thinks my practices suck I'd be happy to hear about it.

    Aaron

  2. 2 Posted by rob on 26 Aug, 2010 03:52 PM

    rob's Avatar

    Hi Aaron,

    Thank you for taking time to reply to all of my questions!

    When you mention the advantages of using event -> command to filter out two news requests, I'm not sure I fully agree that the 'one-shot' parameter is the best way to go - although it does achieve what you say it does.

    My understanding is that it will register the event with a command, then once that event is fired, the mapping is dropped, so you'll only ever get one lot of news (which is what I think you're suggesting), but I would probably want to restrict it to one request at a time and not to be repeated with 30 seconds of the last request, so not one-shot, but perhaps some sort of data in the model that records when it was last requested and then the command could query this and decide to exit the command early, i.e. if

    I agree that the model should fire a change event, granularity I think would be refined subject to how much data we are talking about. For example, if news was no more than 10 lines ever, then replacing the entire table every 30 seconds is no problem, but if it's 1,000 rows and we are updating record 99, then it makes sense to update a row instead.

    Presumably, it's possible for the mediator to associate a models collection to a binding in code? This way, the first time the update is fired we bind, then subsequently the grid updates automatically - or is this bad practice as we would be short-circuiting the models event and relying on the binding events.

    So, if I have my main view with toolbars, should the toolbars click events directly fire events (from the view), or should the mediator register as click listeners and then translate to our events there?

    Likewise, when deciding to create a new view (window) from a toolbar button being clicked, should the mediator fire an event to create the view, or should the mediator of the view containing the buttons directly create the new view? (I don't want to over cook the use of events for the sake of it!).

    I am looking forward to pushing forward with this framework and will try not to drain too much time from you + others in this community, I do however plan to invest time back in ;-)

    Cheers,
    Rob.

  3. 3 Posted by Aaron Hardy on 26 Aug, 2010 04:16 PM

    Aaron Hardy's Avatar

    Yeah, the whole one-shot thing really just depends on what you're
    wanting to do. I wasn't advocating that that's what you should do, I
    was just trying to illustrate how events+commands can help take
    advantage of Robotlegs features if you have a need for them.

    You could have your news property be a collection. When it's first
    set, the mediator would push the collection into the view. If you're
    using a datagrid or something like that, it should already watch for
    when there are items added/removed from the collection so your
    mediator wouldn't watch for collection_change events and your model
    wouldn't dispatch any particular event unless the collection was
    swapped out completely. From your description it sounds like you
    understand how that would work and I think that practice is just fine.

    Regarding event mapping, I would do something like:

    eventMap.mapListener(
    view.loginButton,
    MouseEvent.CLICK,
    loginButton_clickHandler);

    protected function loginButton_clickHandler(event:Event):void
    {
    eventDispatcher.dispatchEvent(new LoginEvent(
    LoginEvent.LOG_IN,
    view.username,
    view.password));
    }

    In response to who should make the new views I would say it depends on
    who will be the parent of the new view. The new parent should
    probably be the one to make the new view (although popups/windows are
    a strange beast). In your case, if the new view will be a child of
    the toolbar, then I'd just have the toolbar create the view directly.
    However, if the new view is going to be a child of another view I'd
    have the mediator dispatch an event. In the case of a popup or window
    I'd probably have a command do the popping up or window creation but I
    suspect there are a lot of ways this is being done. In the case of
    the view being added to some ordinary view elsewhere, the new parent
    will watch for the event and create the new child view. You probably
    don't want the toolbar or its mediator knowing who the parent is going
    to be or caring--I would say it's not it's job.

    Aaron

  4. Stray closed this discussion on 12 Feb, 2011 10:48 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