views:

124

answers:

2

The litmus test for me for a good MVC implementation is how easy it is to swap out the view. I've always done this really badly due to being lazy but now I want to do it right. This is in C++ but it should apply equally to non-desktop applications, if I am to believe the hype.

Here is one example: the application controller has to check some URL for existence in the background. It may connect to the "URL available" event (using Boost Signals) as follows:

BackgroundUrlCheckerThread(Controller & controller)
{
   // ...
   signalUrlAvailable.connect(
      boost::bind(&Controller::urlAvailable,&controller,_1))
}

So what does Controller::urlAvailable look like?

Here is one possibility:

void
Controller::urlAvailable(Url url)
{
    if(!view->askUser("URL available, wanna download it?"))
      return;
    else
      // Download the url in a new thread, repeat
}

This, to me, seems like a gross coupling of the view and the controller. Such a coupling makes it impossible to implement the view when using the web (coroutines aside.)

Another possibility:

void
Controller::urlAvailable(Url url)
{
   urlAvailableSignal(url); // Now, any view interested can do what it wants
}

I'm partial to the latter but it appears that if I do this there will be:

  1. 40 billion such signals. The application controller can get huge for a non-trivial application
  2. A very real possibility that a given view accidentally ignores some signals (APIs can inform you at link-time, but signals/slots are run-time)

So what do you suggest to remove coupling and also keep complexity down? Thanks in advance.

A: 
NawaMan
+1  A: 

The litmus test for me for a good MVC implementation is how easy it is to swap out the view.

I'll probably draw fire for saying this, but I don't agree with this statement. This looks good on paper, but real-world examples show that a good UI is responsive and interactive, which often times necessitates intertwining the view and controller. Trying to code a completely generic controller to handle unforeseen theoretical views adds a ton of code and complexity to both the controller(s) and the views. Interlinked views/controller worked better in my experience - I think of it as "M(VC)".

I would say litmus test for a good MVC implementation is how easily you can "add" another view/controller pair to a model. Are the changes to the model from one view/controller (e.g. desktop operator) propagated out to the other view/controller (e.g. web remote user). Is the model generic enough to support different view/controller paradigms (e.g. desktop GUI, command-line, scheduled/batched input, web-based UI, web service, etc.)?

This isn't to say that controller code can't be shared (e.g. derive from a common base), but you do have to find the right line between what should be handled by the controller (external manipulation of the model) and what should be considered part of the behavior of the model (internal transitions of the model). Ditto for view code.

I think reading some of the answers under "What goes into the “Controller” in “MVC” would also help with this.

Bert F
I did read your linked post in my extensive survey of StackOverflow. I'm not saying I disagree with you. In my case, yes, the model is generic enough. It currently supports a desktop and XML-RPC view. However, there is a lot of repeated code which I am trying to avoid. I figured MVC would help significantly.How would you rewrite the examples above in your interlinked world?
cheez
I'm saying your solution ("This ... coupling of the view and the controller") is natural and to be expected. To implement another view, you may also need to create a new interlinked controller to go with it. You may need to refactor to distill out the common code (perhaps into base classes) between the 2 views and between the 2 controllers. I assume the controller code above is for the desktop app and the new view is for a non-UI XML-RPC view. You would create also create an XML-RPC Controller with urlAvailable() callback that would download the URL without user interaction.
Bert F
In such a setup, I presume the controller would have zero to no logic at all? That is, it simply connects the views and the model?
cheez
This is what I mean by "the right line between what should be handled by the controller ... and what should be considered part of the behavior of the model ...". Definitely input processing specific to this view/controller pair belongs in the controller - this code is likely affected by type of interface (e.g. desktop API calls, XML-RPC processing, web UI form handling etc). Functionality common to multiple controllers may either be in controller common/util classes (or a base class?) or should be considered for incorporation into the model.
Bert F
One last thing - "... often times necessitates intertwining the view and controller ..." - but not always. You may find a straightforward way to create a generic controller for your app - cool. However, in my experience, I wouldn't add a ton of complexity trying to create a ultra-generic controller. I've tried it and it didn't seem worth it in the end. Intertwined view/controller pairs seemed cleaner, more understandable, and more maintainable. Separating M from V and C is natural. Separating V from C (to support significantly different future Vs) is much harder and may not be worth it.
Bert F
Argh, this is hard. I'm going shopping.Thanks for your advice Bert F. I will let you know how it goes.
cheez
FYI, thanks to this advice I did not try too hard to create an ultimately generic controller. At this point, I have two controllers: one controls application logic, the other controls GUI logic. It's working out really nice and I'm very happy with it :)
cheez