4

Model-View-Controler

A naive implementation of MVC leeds to infinite loops.

Example: Model is a Workbook with Worksheets, View is a Tabbar with Tabs

  1. User interakts with Tabbar to create new Tab
  2. Tabbar sends event onTabAdded to Controler
  3. Controler calls Workbook.addWorksheet()
  4. Workbook sends event onWorksheetAdded to Tabbar
  5. Tabbar adds Tab and sends onTabAdded to Controler -> 2) Infinite Loop!

Alternatively, the loop could be initiated by programmatically adding a Worksheet through a macro. Or a tab could be added programmatically by automated UI testing.

It seems that the more components you have and the looser the coupling is (considered good design), the more likely it is to have infinite loops.

Do you know about implementation patterns how to avoid such infinite loops? An evaluation of pros/cons of such patterns?

My special interest is a solution for a rich JavaScript client.

The answers to the following questions are not really on the implementation level:

Community
  • 1
  • 1
Wolfgang Kuehn
  • 12,206
  • 2
  • 33
  • 46
  • I don't understand why your 'tabbar' would raise an "onTabAdded" event when the using the updated model to refresh the page as "onTabAdded" is clearly in response to a user interaction, not a display refresh. I don't think you understand how to use the MVC pattern, I'd take some time and look at some implementations. – Lazarus Jun 09 '11 at 11:17
  • @Lazarus: Well, maybe you could explain how my example could be modified to avoid the loop, possibly by adhering to MVC. – Wolfgang Kuehn Jun 09 '11 at 11:19
  • @amadeus : The View has a button that triggers a command in the Controller to add a new tab/worksheet when clicked. That command modifies the Model accordingly and directs the Controller to present the same View but with the newly modified Model. The View renders the Model (which now includes n+1 tabs) just as it did before. No additional messages are sent from the tabbar as it's a View, it just displays what you give it. You've over complicated the model. – Lazarus Jun 09 '11 at 11:31
  • @Lazarus: So in your solution the view is not incremental, as it always does a complete rerendering of the model. In the above example (not many tabs), this is probably the best solution. – Wolfgang Kuehn Jun 09 '11 at 11:39
  • @Lazarus and first comment: onTabAdded should always fire, after UI interaction and API-calls. Tabbar does not know who is listening. – Wolfgang Kuehn Jun 09 '11 at 11:48
  • @amadeus: A simple view might not be an entire 'screen' in your app, it could be as narrow as a single control but even then I'd expect to see an overarching view that encompassed the partial views. To you last comment, I completely disagree. An event either indicates that user interaction has occurred or that the display has updated, never both. Your problem with infinite loops here is entirely due to bad design. – Lazarus Jun 10 '11 at 10:51

1 Answers1

3

You would typically code something like this (pseudo code):

boolean inEventProcessing = false;

processEvent(event){
    if inEventProcessing return
    inEventProcessing = true
    doProcessEvent(event)
    inEventProcessing = false
}

The alternative is to make sure that by construction no loops happen. This is the conceptual cleaner way, but hard to do if you don't come up with it in the very beginning. One way would be to allow Observers only arguments to the constructors of Observables. This way it would be impossible to construct loops. But it is a extremely rigid structure which probably causes all kinds of different problems.

I do suspect the solution of those problems would lead to a really nice and clean architecture or to a complete and extreme mess, depending on the team working with it.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
  • Wouldn't it be better to code to avoid the need for such methods? Unless you are multi-threaded is this strictly necessary? – Lazarus Jun 09 '11 at 11:27
  • @Jens: You would have to add a try/finally around doProcessEvent. This makes a lot of boilerplate. Best to abstract this away in a generic EventGuard. Then yours is a viable solution. – Wolfgang Kuehn Jun 09 '11 at 11:33
  • @amadeus Of course one should abstract all this away and need to take care of exceptions, but how to do that depends a lot on the language used and I don't know enough javascript to do it properly. – Jens Schauder Jun 09 '11 at 13:14
  • @Lazarus this hasn't anything to do with multi-threaded stuff. Imagine a model with a property. a textbox is bound to that property. The textbox does some formatting of its content whenever it is updated. If the model does something similar you might end in an infinite loop. As said in the answer: If you can avoid it thats great, but it is often hard to avoid it in a simple and secure way. – Jens Schauder Jun 09 '11 at 13:17
  • @Jens Schauder: You'll need to expand on that, unless you are assigning several tasks to a single event (surely not) then I can't see the purpose for your code. Under no circumstances should an event related to a user interaction also be triggered when a control updates itself, that would just be really really bad design. – Lazarus Jun 10 '11 at 10:55
  • 1
    @Lazarus No matter how bad that design is. It is a very common problem. And this is a very pragmatic solution to the problem. – Jens Schauder Jun 10 '11 at 11:23