MVC Communication

mbarjawi's Avatar

mbarjawi

11 Oct, 2012 08:24 PM

I need help in figuring how to setup communication between different parts of my application. When a view requires some data to be loaded, I am not sure where to make the request, who makes the request, or who sends the data back.

For example, lets say we have a users view that should view the list of users in a system. When the view is loaded, this is what I currently do in the mediator:

// INSIDE MEDIATOR:
override public function initialize():void
{
    // listen for a signal from the model indicating user list updated
    usersModel.usersListUpdatedSignal.add( usersListUpdateHandler );

    // After that, I check the usersModel if it already has the users list or not.
    if( usersModel.usersList != null )
    {
        // If it has, I pass it right away to the view
        view.usersList = usersList;
    }
    else
    {
        // If not, I dispatch the injected trigger
        loadUsersList.dispatch();
    }
}

private function usersListUpdateHandler( usersList:ArrayCollection ):void
{
    view.usersList = usersList;
}

// The trigger in turn runs a command that loads the required data.
// INSIDE COMMAND:
// Once the command loads the data, it updates the UsersModel.
[Inject]
public var usersModel:UsersModel;

[Inject]
public var usersServices:IUsersServices;

[Inject]
public var context:IContext;

public function execute():void
{
    usersServices.loadUsersList()
        .addOnce( usersListLoadedHandler );
    context.detain( this );
}

private function usersListLoadedHandler( usersList:Array ):void
{
    usersModel.usersList = new ArrayCollection( usersList );
    context.release();
}

// The UsersModel in turn uses a signal to dispatch 
// the data to who ever is listening for user updates.
// INSIDE UsersModel
public function set usersList( value:ArrayCollection ):void
{
    _usersList = value;
    usersListUpdatedSignal.dispatch( _usersList );
}

So my questions:

  • I feel it is better to move the code that checks if the data already exists or not into the Command itself. This way, anybody calling the command wouldn't have to repeat the same IF statement to check if the data already exists. The command will take care of that checking, and so no repeated data will be loaded from the database. However, if I do so, and if the data was already loaded into the model, then the model will not get updated... resulting in the signal inside the model not getting dispatched. The mediator will not get the data it needs. So what should I do?

  • I think that maybe to fix the problem in the point above, I would move the signal from inside the model to just a signal that is injected into the context. The command will dispatch this signal loaded with the data whether it loads the data from the server or whether it finds this data inside the model itself. This way, the Model will become silent.

  • The other question I had in mind... why do we have to have signals inside models... I saw this in RL2 example where they call them as Notifications. I mean what happened with just binding? Why not inject the model inside the mediator and pass it to the view. The view binds its data to that model. This way, whether the model already has data, or it will be loaded later on with data, the view will be updated.

Thanks,

  1. Support Staff 1 Posted by Ondina D.F. on 12 Oct, 2012 12:46 PM

    Ondina D.F.'s Avatar

    Hi Mutasem,

    I would change the logic inside your mediator like this:

    [Inject]
    public var usersListUpdatedSignal: UsersListUpdatedSignal;
    
    [Inject]
    public var loadUsersListSignal: LoadUsersListSignal;
    
        override public function initialize():void
        {
               usersListUpdatedSignal.add( usersListUpdateHandler );
               loadUsersListSignal.dispatch(); //triggers the command       
        }
        
        private function usersListUpdateHandler( usersList:ArrayCollection ):void
        {
               if(usersList)
                   view.usersList = usersList;
        }
    

    Yes, you can dispatch the signal from the command.

    The other question I had in mind... why do we have to have signals inside models... I saw this in RL2 example where they call them as Notifications. I mean what happened with just binding? Why not inject the model inside the mediator and pass it to the view. The view binds its data to that model. This way, whether the model already has data, or it will be loaded later on with data, the view will be updated.

    Of course you can use bindings, and/or inject the model into your mediator, if you want to.
    Robotlegs, as a framework, allows you to do just about everything with your classes, and lets you design your application as it fits you. If you look at examples from different users, there is a large variety of MVCS implementations. Some developers do inject models into mediators, some others don’t. The Best Practices and most of the discussions on this forum are about MVCS, but there are other design patterns that can be used in conjunction with robotlegs as well.

    The pros and cons of injecting a model into a mediator are the subject of many threads on this forum. Stray’s responses should give you a pretty good idea about the cons. I can’t find all the relevant discussions on this huge topic right now. One of them:

    http://knowledge.robotlegs.org/discussions/questions/309-inject-mod...

    I made my point (or so I think) about Best Practices here:
    http://knowledge.robotlegs.org/discussions/questions/1072-models-an...

    Ondina

  2. 2 Posted by mbarjawi on 12 Oct, 2012 05:57 PM

    mbarjawi's Avatar

    Thanks Ondina for your explanation. I know that Robotlegs allows me to use any design pattern I need... thats why I love it.. its flexible!

    I have been trying to learn MVC and use design patterns in my code for long long time. I have to admit that I was never able to grasp the concepts and feel that I am really applying them correctly until I met Robotlegs. So, because of my inexperience in this field, I always keep falling into these little confusions.

    Back to the topic,

    • I already thought about an implementation like yours, but I wasn't sure if that is one of the good practices. Actually thats how I used to do it in RL1. Now in RL2, using Signals, I would start the command, check for data being loaded or not, if loaded, I would send back the already loaded data, if not, then I would load it and then send it back once I have it.

      In RL1, I even used to have to layers of commands. GetUsersListCommand that will check for data already there or not... if not, then I would dispatch another command LoadUsersListCommand that would load the data from the server. Not sure if this is the right way or not... but now I am moving towards having it all in single command using RL2.

    • Which do you think is a better practice than the other. In the case when the data is already loaded, the Command itself will be the one dispatching the signal back UsersListLoadedSignal... In the other case, when the data is not loaded, the Command will load the data and update the Model. Now, should the Command itself send the UsersListLoadedSignal loaded with the new data, since the views are already listening for this signal? or should the Model dispatch the UsersListUpdatedSignal ? or should the Model even dispatch the same signal UsersListLoadedSignal as the Command does?

    Thanks,

  3. Support Staff 3 Posted by Ondina D.F. on 15 Oct, 2012 08:51 AM

    Ondina D.F.'s Avatar

    Hi Mutasem,

    I have been trying to learn MVC and use design patterns in my code for long long time. I have to admit that I was never able to grasp the concepts and feel that I am really applying them correctly until I met Robotlegs. So, because of my inexperience in this field, I always keep falling into these little confusions.

    I can see where the confusion comes from. Robotlegs’ MVCS is not the same as the traditional MVC. For someone like you, used to the classic MVC, the big questions are: What code goes where? ; How to define the roles, responsibilities and collaborations of the new MVCS-actors? The terminology is not always clear, there are lots of overlapping concepts, but also different meanings for the same term.

    In RL1, I even used to have to layers of commands. GetUsersListCommand that will check for data already there or not... if not, then I would dispatch another command LoadUsersListCommand that would load the data from the server. Not sure if this is the right way or not... but now I am moving towards having it all in single command using RL2.

    The question to be asked is: Should Models and Services be portable/re-usable or not?

    If the answer is yes, then the Model should encapsulate all the logic responsible for maintaining the integrity of the data, for manipulating the data, and for informing other actors of changes to the data (through events or signals).

    Same for Service classes. They should encapsulate logic for storing, retrieving data from data sources (Server, File system…), and informing other actors about the results. They shouldn’t be dependent on Models either (meaning no Models injected into Services), just in the case when extreme decoupling was needed.

    Say, you wanted to repackage your Models and Services into a library shared by 2 different applications or you wanted to use Model’s data in 2 or more different Views inside one application.

    If parts of the Model’s duties would be performed in a Command, or the Command would act as a responder to a server call, or, the Command would do both, Model’s and Service’s jobs, then one of the 2 applications would need to implement a similar Command just to be able to interact with the Model and/or the Service, or maybe just with the Model. Or, you’d have the Command in your library as well, and that might not be ideal. Or, if you wanted to call the Service from another Command triggered by another event, dispatched by another actor in your app, you’d have to repeat the code, for example, make the Command act as a responder, because the Service would be useless without the Command.

    • If the goal is portability, encapsulation, and loose coupling letting a Command call the Service, which would dispatch an event/signal with the server response, triggering another Command that would access the Model to update its data, which would dispatch an event/signal when its data changes (null or otherwise), for a Mediator to hear it, would be the safest approach.

    • Alternatively, if there is no need for a Service reuse, the Service can update the injected Model(against an interface) itself, with the server’s results, and the Model can dispatch an event/signal ->Mediator->View.

    In these scenarios the Model is checking and updating the data, and is deciding what event/signal to dispatch and when.

    You said: “I would start the command, check for data being loaded or not, if loaded, I would send back the already loaded data, if not, then I would load it and then send it back once I have it.”
    I’m asking: the already loaded data? Loaded by whom? By another Command?
    If you mean the same Command, as in your example in a previous post, isn’t its role to call the Service first and then update the Model? Calling the Command means that the View (in your case) needs data, right? So, if there was no Service call previous to the creation of the Mediator, the Model’s data should be null anyway. I guess you ran into some kind of race conditions?
    Meaning the data has been loaded before the Mediator could listen for an event/signal carrying the data.

    Probably you need the same Model in different parts of your application that are loaded at different points in time (deferred instantiation). In this case, as I mentioned in other posts/discussions, the options are:

    • after the mappings in your context have finished, call the Service from a Command, wait for the results to come back(either in the same command or dispatch an event from the Service to trigger another Command), update the Model, and then dispatch an event to let your application know that it can add your View(s). Each Mediator can ask for data in its initialize() by dispatching an event/signal triggering a Command that accesses the Model’s method, say getData(), which will dispatch an event/signal with the already loaded data as a payload.

    • Alternatively, in case there is just one Mediator needing the Model, and its View is the first one to be added to the display list, you can make the service call after FlexEvent:APPLICATION_COMPLETE has fired(for Flex apps). This makes sure the Mediator in question has been created already and it’s able to hear events from the updated Model.

    • like the previous option, call the Service once, but instead of using a Command, inject the Model into each Mediator. The Model doesn’t need to dispatch events/signals in this case. I’m mentioning this option, because you asked about it, and in your use case your Model seems to get updated only once with data from a server and its role is the one of a data provider, meaning no other actors will modify the Model later, and the application’s state won’t be affected. It’s good to inject the Model against an interface and expose only the getters in your Mediator (even if the Model doesn’t have mutable states).

    • each Mediator needing the Model’s data dispatches an event/signal. The Command calls Model’s method modelHasData(), which checks if data is null. If data is null the Service has to retrieve it, else it will be sent to mediators via event/signal. Now, it’s your choice whether you trigger another Command to call the Service or do it in the same Command.

    • call the Service after bootstrapping your app + RelaxedEventMap

    If there were more Mediators needing data from the same Model, my choice would be to call the Service once on APPLICATION_COMPLETE and then just trigger a command from each Mediator onRegister() to access the Model. I would let the Model dispatch an event/signal with the data as a payload.

    or should the Model even dispatch the same signal UsersListLoadedSignal as the Command does?

    If you dispatch an event/signal from a Command, you don’t need to dispatch it from the Model too, or vice versa. Can you explain why would you dispatch it from both, Model and Command?

    Cheers,
    Ondina

  4. 4 Posted by mbarjawi on 15 Oct, 2012 05:37 PM

    mbarjawi's Avatar

    Hi Ondina,

    Thank you again for your reply.

    I’m asking: the already loaded data? Loaded by whom? By another Command?

    The data might be already loaded by any other part of the software. For example, the logged in user have multiple schools under him. Each school has multiple students under them. The logged in user can load a school's students when working with that school... but then can also switch to a different school and then come back to the first school. I don't want to load a school's student's from the server every time the logged in user goes back to that first school. Instead, I want to load it once, keep it in the memory in case the user asks for it again. So if the user asks for it again, that's when the data is "already loaded".

    The data might also be already loaded by the same mediator. The loadUsersList function is called in the initialize() method. This method is called whenever the UI is added to stage. So first time the user navigates to the UI, the data will be loaded from the server. Then the user navigates to a different screen, then comes back to the same first screen which will attempt to load the same user list... but this time it should just get it from the memory instead from the server.

    In addition, I cannot load the data at the context initialization or CREATION_COMPLETE because the user needs to select which school he wants to load. In addition, its not feasible to load all the school's data/student lists before context initialization or even after creation complete... why load all this data while the user might need only a single school's student list.

    The question to be asked is: Should Models and Services be portable/re-usable or not?

    That is exactly what I am trying to achieve. I have a backend database and php services. They are currently being called from the application I am building. However, this is not the only application that needs to access this same database. This is why I created a library in which I am planning to keep all the Models and Services so that they get used by different application in my company.

    Same for Service classes. They should encapsulate logic for storing, retrieving data from data sources (Server, File system…), and informing other actors about the results.

    Should we actually store the data in the service?? I thought services just retrieve data from the server and pass them on to the models (after parsing).

    Say, you wanted to repackage your Models and Services into a library shared by 2 different applications or you wanted to use Model’s data in 2 or more different Views inside one application.

    That's exactly what I want. Both cases exist in my application.

    If the goal is portability, encapsulation, and loose coupling letting a Command call the Service, which would dispatch an event/signal with the server response, triggering another Command that would access the Model to update its data, which would dispatch an event/signal when its data changes (null or otherwise), for a Mediator to hear it, would be the safest approach.

    Lets say I want to follow this approach, I wasn't able to see the difference between this approach and my approach.

    So, in my approach this is what I do:

    • Once the view is on stage, and the mediator is configured, the initialize() method is called. In it, I listen for usersListLoaded signal, and then I dispatch loadUsersList signal.
    • The loadUsersList signal triggers the loadUsersListCommand
    • The loadUsersListCommand checks if the requested usersList has already been loaded or not by asking the Model model.containsUsersList( schoolId )
    • If the usersList is already loaded, then the Command dispatches the usersListLoaded with the usersList as the payload.
    • Otherwise, the command calls the service.loadUsersList( schoold ) and listens for the result
    • The resultHandler inside the loadUsersListCommand updates the model and then dispatches the usersListLoaded.

    In this scenario, I have 1 model, 1 service, 1 command, and 2 signals.

    Currently, the Model and the Service are in a library. The command and signals are in the application. If I am to use the same Model and Service in a different application, then I need to implement a similar command. Since the service function names and the models properties are the same in both applications (because we are dealing with the same model and the same service), then the second command in the second application will be exactly the same as the first application. I don't feel its right to place the command in the library... but in this case, wouldn't it seem more logical to have the command in the library?

    Now, I will try to break up the approach that you mentioned just to create a comparison between both and see if I understand your approach correctly. In the approach that you mentioned:

    If the goal is portability, encapsulation, and loose coupling letting a Command call the Service, which would dispatch an event/signal with the server response, triggering another Command that would access the Model to update its data, which would dispatch an event/signal when its data changes (null or otherwise), for a Mediator to hear it, would be the safest approach.

    • Once the view is on stage, and the mediator is configured, the initialize() method is called. In it, I would listen for usersListUpdated signal and the usersListFound signal, and then I dispatch getUsersList signal.
    • The getUsersList signal triggers the getUsersListCommand
    • The getUsersListCommand checks if the requested usersList has already been loaded or not by asking the Model model.containsUsersList( schoolId )
    • If the usersList is already loaded, then the Command dispatches the usersListFound with the usersList as the payload.
    • Otherwise, the command dispatches the loadUsersList signal
    • The loadUsersList signal triggers the loadUsersListCommand
    • The loadUsersListCommand calls the service.loadUsersList( schoold )
    • Once the data arrives at the service, it dispatches the usersListLoaded signal
    • The usersListLoaded signal triggers the usersListLoadedCommand
    • The usersListLoadedCommand updates the model by calling model.usersList = newUsersList; or maybe model.setUsersList( newUsersList )
    • The model dispatches the usersListUpdated signal which gets caught by the mediator

    This approach used 1 model, 1 service, 3 commands, and 5 signals.
    This approach seems most loose coupled and each command does only a single job. But I am not sure how this is more portable than the first approach. In this approach, the model, service, the usersListLoaded signal, and the usersListUpdated signal all need to be in the library.

    Maybe its my little experience that is preventing me from seeing the high benefits of the second approach... but I see more work to be done for not much benefit gained.

    Sorry for the loooong reply, and thanks for putting the effort and time to help me figure this out.

    Regards,
    Mutasem

  5. Support Staff 5 Posted by Ondina D.F. on 15 Oct, 2012 06:04 PM

    Ondina D.F.'s Avatar

    Hi Mutasem,

    Just letting you know that I’ll read your post later and answer tomorrow. I’m about to shut down the computer and have dinner and so on…..

    Ondina

  6. Support Staff 6 Posted by Ondina D.F. on 16 Oct, 2012 02:29 PM

    Ondina D.F.'s Avatar

    Hello Mutasem,

    Should we actually store the data in the service?? I thought services just retrieve data from the server and pass them on to the models (after parsing).

    No, that’s not what I meant! You’ve identified a poorly formulated sentence.
    But, since I’ve described the role of a Model in a sentence above the one about Services, it should have been clear that it wouldn’t make sense to store the data in a Service class and at the same time to pass it on to a Model. Also, none of the use cases I presented throughout my posts is using the Service as a data store.

    Anyway, I will edit my post to prevent further misunderstandings :)
    I should have said:
    „Services should encapsulate logic for storing data to data storage and/or retrieving data from data sources (persistent data storage: Server, File system…).”

    But, that’s probably not good enough either. Maybe this is better: A Service class provides access to external data sources of many kinds. A Service provides a means of communication between an application and external systems or environments (other applications, persistent data storage, devices..). A Service is like a half-duplex – data flows in both directions.

    Of course, a User, an Agent interacting with an application, is also an external system. The half-duplex in this case is the user interface, the View, accepting input from User, and presenting the data, processed by the application, in a meaningful way (information) back to the User.

    The application is the link between 2 external worlds, transforming raw data into information.
    Of course, the data entering the application via a Service is not always ‘raw’ data, so the application is just transporting it to the consumer.
    Through Views and Services, the application is interfacing the external world (systems).

    Another edit:
    „Services should encapsulate logic for storing data to external data storage and/or retrieving data from external data sources (persistent data storage: Server, File system…).”

    Now, I’m sure, your observant eyes will be able to find many flaws in my explanations, and we could go on and on, deliberating about the different meanings given to the terms used in conjunction with MVCS.
    So, since my wording is not the best, please see other discussions, the articles under “Knowledge Base”, the Best Practices document on github, the robotlegs book for more and better presented details on the roles of each MVCS actor.

    Hopefully, at least the role of a Service, even if described in my own, imperfect words, is clearer now.
    Back to your question: the Service class shouldn’t store data. Usually, the Models and VOs are used as a sort of data object cache.
    The distinction between Models and Services is just a conceptual one, though. It helps identifying their roles and purposes. Other MVC-frameworks don’t make this distinction. As with everything else in robotlegs, you’re free to do whatever suits you best.

    Now, addressing the rest of your post:

    This approach used 1 model, 1 service, 3 commands, and 5 signals.

    That’s your scenario, not mine :)

    First of all, I presented generic scenarios. The details you provided in your last post weren’t present by the time I responded, so I gave you more options to choose from: in the first part of my post for a 1Service+1Model+1View, as your posted example seemed to be, and then for a Model used by other views as well, but not knowing that you’d need to add/remove/reattach your views. There are many possible permutations and combinations when designing an application, and, of course, I couldn’t address them all.
    In my simple scenario (1Service+1Model+1Mediator), there were just 2 commands: one for accessing the service and the other for accessing the model.

    I’ll exemplify this by using events.
    - A UserEvent, with 3 constants USER_DATA_REQUESTED, USER_DATA_LOADED, USER_DATA_UPDATED, that would correspond to 3 signals, if you chose to use signals

    • UserMediator registers a listener for UserEvent.USER_DATA_UPDATED and right after that it dispatches USER_DATA_REQUESTED, triggering

    • UserDataRequestedCommand accesses UserService.accessUserData()

    • UserService.onServerResponse() dispatches USER_DATA_LOADED with the results as a payload (of course you can parse them, and so on)

    • UserDataLoadedCommand() accesses the UserModel.updateUserData() passing the payload of the event

    • UserModel.updateUserData() does what it has to do with the data, and dispatches USER_DATA_UPDATED with the data as a payload

    • UserMediator reacts to the event and passes the payload to the UserView, view.setUserDataProvider(payload)

    If you need to check if the Model has data, you can do it in UserDataRequestedCommand, and either the Model (OR the Command ) dispatches USER_DATA_UPDATED with the data as a payload, or the command accesses the service if model’s data is null.
    Actually, I’ve already said that you can do that in my first answer to you, and then, again, in the second part of my last post. You have compared an approach used for 1Service+1Model+1Mediator with the one used for 1 Service+1 Model+1..n Mediators. I never said you’d need a 3rd Command, but you can use as many or as few commands as you wish.
    I can only repeat myself: how granular, encapsulated, loosely coupled a class is, or how many responsibilities a class has, is your decision to make. If one approach doesn’t fit your needs, use another. Even with the details provided in your last post it’s hard to give you a recipe for a part of your app and a guarantee that it will play well with your app as a whole.
    In the example you posted at the beginning, the mediator had a model injected into it, a signal like this: usersModel.usersListUpdatedSignal.add, and the mediator was accessing a model and was listening for a signal from the model at the same time, and you made the decision to call a service inside your mediator’s initialize(). So, yes, the approach from your last post is a better one :)

    Sorry for the loooong reply, and thanks for putting the effort and time to help me figure this out.

    No problem! As you can see, my answer is quite long as well :) Complex topic=many words. Many questions=many answers.

    Ondina

  7. Support Staff 7 Posted by Ondina D.F. on 16 Oct, 2012 05:15 PM

    Ondina D.F.'s Avatar

    Forgot to answer this:

    I don't feel its right to place the command in the library... but in this case, wouldn't it seem more logical to have the command in the library?

    A library may contain whatever you need to share between applications or within one application. (view components, assets, styles , models, services, config files…) If you need commands too, so be it. I just meant that if the applications sharing a library are designed differently, it would be ideal to have just the common resources or classes, shared by both apps in this library.
    But, in your case it seems not to be a problem.
    For big projects (with more related apps) it could make sense to have more than one library, one for assets, one for models, one for mobile view components, one for desktop components, one for whatever else, so you can load just the ones needed in a certain app.

  8. 8 Posted by mbarjawi on 16 Oct, 2012 05:35 PM

    mbarjawi's Avatar

    Hello Ondina,

    Thank you for your kind response. I really appreciate all the efforts.

    Since you have more experience than I have, a sentence like the one you mentioned that talks about services storing data would make me wonder if that is a practice that I don't know about because of my lack of knowledge on the topic. However, I already feel and believe that services shouldn't store data... and thats how I have been doing it for a long time... but again, my comment was only to make sure that I am not missing an important practice that I haven't been using. In the end it appeared that I wasn't.

    Your explanations has been very insightful to me. As you said, there are many scenarios in an application and they are too many to be covered in a small thread. However, I think right now I understand how communications should be established in my application.

    Mutasem

  9. Support Staff 9 Posted by Ondina D.F. on 17 Oct, 2012 12:24 PM

    Ondina D.F.'s Avatar

    You’re welcome, Mutasem! Good luck with your project:)

  10. Ondina D.F. closed this discussion on 17 Oct, 2012 12:24 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