This book is a work in progress, comments are welcome to: johno(at)johno(dot)se

Back to MVC...

NOTE: chopped up and take from various rounds in an email discussion, needs to be organized...

Samuel,

Thanks for the feedback! Such comments aid me in figuring out exactly what it is I want to convery in my writing, and also in realizing when I haven't been clear enough or possibly even ambigious.

One of the first things that comes to mind is that you assume that views are inherently stateful. This is false, at least in the sense that you're using the phrase; the *original* Smalltalk MVC framework worked, to the best of my recollection, almost identically to an IMGUI -- the only state a View maintained is a link to its model, plus configuration parameters like on-screen coordinates and dimensions, color choices, and the like.

First of all, my whole journey in discovering MVC and thinking about it is from the point of view of me a game developer, and especially one who has worked on real time networked games using the client-server model.

I regards to me knowing (or indeed caring) about how the original Smalltalk MVC framework worked in detail; I met with Trygve Reenskaug himself in late 2008 to discuss what I had been working on in relation to his work in the 1970s. What I found interesting was that he was extremely reluctant to talk about his original thoughts on the subject. It also seemed to me that he viewed the Smalltalk MVC framework as a perversion of his original ideas. His gist was this; use whatever works for your application domain, and call it whatever you want!

My somewhat unclear point is this; there are elements of the various incarnations of "MVC-ish" architectures out there that I think are important in the context of real time applications.

I will try to clarify my mindset step by step.

Controllers, likewise, don't boss views around like they do models (two sole exceptions: (1) refresh your display, (2) change controller). Again, I'm talking about the original Smalltalk-80 MVC here. Instead, controllers served to parse in-bound user events and dispatched updates to models as appropriate.

My approach to "user events" is to not have them as events, at least not to drive Controllers. I explicitly sample and cache all keystates and mouse state (cursor position, button states) per frame and have all subsequent code query this cache. I also keep the last frame's cache around to support queries like "was button clicked" (i.e. down before but not down now).

My typical "main loop":

I have a call to "doInput()" once per frame (the Controller), which samples input and reads from / writes to the Model. Any IMGUI stuff goes here (I view IMGUI calls as "reacting to input"). Often, due to the nature of the APIs I use, this results to writes to a cache of vertex buffers and other junk, in order to create the "widgets".

Next I "update()" the Model, which is often active / runs some kind of real-time logic.

Finally I "doOutput()" (again the Controller), where the and "programs the output" using the View object. Usually lastly there is a call to "imgui::draw()" which simply flushes the caches of drawing data and draws the implicit widgets to the screen.

Some coders I know disagree with this approach due to the IMGUI caching, and instead have no "doInput()" stage and just do input sampling and output rendering in the "doOutput()" stage. Indeed this simplifies the implementation if the IMGUI.

The models, then, would notify all views that its state has changed, causing all interested views to update their representation in real-time.

This is hugely significant and of my main points; if the Model notifies a View that Model state has changed in order for the View to update their representations, be it real-time or not, then that View is stateful.

This does not hold logically; for what both you and I say to be true, you must concede that the IMGUI concept of a view is also stateful; the only "state" an MVC view _should have_ is that which exists in the framebuffer. Obviously, regardless of what the model state is, if the framebuffer does not get redrawn, the user will receive obsolete information about the state of the model. The view should NOT copy the state of the model. That's the whole point of having a model in the first place.

To be perfectly clear; the View retains state that is NOT the same state (i.e. the same bytes) that the Model contains, but the intent is for this View state to constantly be in sync with the corresponding Model state.

It is here that I feel you are mistaken. I've never seen a single View class which cached the state of its corresponding model. Even those that rely on GDI or NS-widgets. The caching is done by the lowest-level widget toolkit. (One possible exception I'm willing to concede are the cross-platform toolkits like wxWidgets, but that's due to necessity more than anything else.)

I'm not saying "ANY FORM of state in the View is evil", I'm specifically saying that any View resident cache (transformed or not) of information that exists in the Model is something to avoid. I'm not talking about the framebuffer, I'm talking about data structures in the View that mirror concepts in the Model. Think parallell class heirarchies etc.

It happens, at least in game architectures, much more than you'd think; my previous example of "ServerTank", "ClientTank", "SceneGraphTank".

I absolutely did not intend to get into a religious discussion about what MVC IS; I realize more than ever that I don't know enough about the original intentions to have an opinion. I should really call my stuff something else. What I do know however, is that programs all over the place are duplicating state that doesn't need to be duplicated, and I want to write something cohesive about how to avoid THAT.

I think this is BAD.

I concur -- I'm just trying to correct the record about Smalltalk's original MVC concept. It is my interpretation that MVC was distorted throughout history, for _no_ other GUI toolkit has replicated Smalltalk's immediacy in GUI implementation, before or since.

Just so I understand you; you think that I should be calling it MVC, but focus instead on saying that many IMPLEMENTATIONs be unnecessarily retained / state-duplicated due to the fact that the underlying APIs are retained?

I would certainly mention this at least in the introduction or first chapter to the book. I don't think it needs to be repeated throughout, though.

Controllers were nested, like views are nested. An input driver would notify the root controller (the entire screen) of something (like, a mouse moved). This controller would then decide how best to deal with the event (pass it to children, perhaps). Each child controller, should it receive control, basically repeats the steps. Each controller is responsible for deciding hot-vs-active states (as appropriate for the GUI; I don't think the original Smalltalk GUI distinguished between these two things, but later implementations did), and if active, dispatching events to models as appropriate. This is one of the reasons people thought Smalltalk was so slow, in fact -- it executed a massive tree of decision-making code every input event, which is a behavioral characteristic very much in common with IMGUIs! The responsiveness of IMGUIs today come from high-speed CPUs, not code efficiency.

I definitely have nested objects I call "Controllers" that process (poll) user input. Which one that is "active" at any given time can be quite complex but depends on both Model state as well as internal state in the Controllers. In this way I'm not being "pure" about where "the state of the application goes", but that isn't my intent.

Any state that isn't in Model is related to things like "what screen does the user want to see right now?", if such things are part of the application design. These are inherently things that the Model doesn't care about, especially in cases where the Model represents a server with multiple clients. However, if the activeness of any given Controller inherently (by design) depens on some part of the Model state, this will of course always supersede any user preference, always within the constraints of the logical design.

In my applications I hence have a single Model, many Controllers (often heirarchical), and a single View. This is a point where I know people might disagree, but my approach for real-time apps / games is that the View, conceptually, is just a toolkit for putting stuff on the screen (and / or rendering sounds). The Controller(s) are the ones who actively "program" the screen output using the functionality supplied by a shared View.

*** I admit that this is one of the main reasons why I might be better off calling this whole architecture something else to avoid confusion! ***

I feel that there should be a single View object / "rendering tool and visual asset repository" and that it should be as stateless as possible. State that it does tend to contain are things like in-memory representations of 3d models, HLSL effect handles, texture handles, etc, but these are just parts of an essentially procedural interface for the Controllers to play around with on a frame by frame basis.

I do NOT 3d scene-graphs that are based on frame coherency. There are no objectified "instances" of 3d models. Such things are simply another variant of a visualisation caching state that belongs in the Model that is being visualized. The trend for game "engines" to build a Retained-Mode system on top of (for example) DirectX's Immediate-Mode interfaces is something I don't understand.

A great litmus test; What if you want to have several independent "visualisations" of the same Model, and be able to switch freely between them? A 2d view, a 3d view, a console-style log view? And you don't want tedious / expensive set-ups and tear-downs when you switch between them? These are the kinds of requirements that were really instrumental in leading me to believe in this very strict reduction of state duplication.

Also, my personal discovery of IMGUI really meshed well with this philosophy in my opinion, as there was now a way to do mouse driven guis (with all the classic widgets) without being force to user objects for the widgets. A gui toolkit with a procedural interface!

The other thing of interest is that a true MVC architecture will have two separate object hierarchies: you have the visual hierarchy which establishes what the user sees, and you have a controller hierarchy, which should be a proper subset of the former, establishing which chunks of screen real-estate respond to mouse and/or keyboard input.

Again I disagree, as noted above.

I hope this provides some greater insight on MVC, and helps dispel the myth that views and/or controllers are inherently stateful.

I meant that they TEND to be stateful, based on what I have seen, in the ways that I (and you) have described. My agenda is to describe an implementation where they are NOT so, thereby agreeing with you that they needn't be.

However, the examples you have given include some of the kinds of "statefulness" that I aim to avoid.

The pattern describes a decomposition of responsibility, without implying a specific implementation method.

Agreed. Not to get too far into a tangential discussion, but I suspect that the "mish-mash" of responsibilities often seen in various architectures is a result of Object Oriented Programming principles, i.e. "an object should encapsulate state and behaviour". This tends to produce code where objects are responsible for doing "everything that can possibly be done" with the state they encapsulate, be it visualisation, persistence, or whatever.

My code is looking more and more "procedural" these days, not least because Controllers and View have public access to Model member variables (albeit often as constant reference, i.e. read-only). These feels like "functions operating on structures".

Contemporary implementations are stateful precisely _because_ the underlying GUI implementations merge model, view, and controller responsibilities on a per-widget basis (while we have MacOS System I to blame for setting this trend, a good technical reason exists for not using proper MVC in contemporary OS designs). You can only go so far in attempting to untangle these roles in MVC frameworks designed to sit on top of monolithic granite.

I agree to this as well. I have only briefly seen this kind of code (MacOS), and it looks terrible to me.

My main experience with graphical user interface toolkits is Microsoft Foundation Classes. They had an architecture called Document/View, where the Document was basically the Model, and the View was what I would call the Controller. In that architecture, there are lots of "standard" widget classes (I suppose this would be called the View once instatiated), but my main beef with all of this was precisely the REQUIREMENT of data synchronization between the Document and the View-widget objects.

Again, I suggest that the very existence of such state caches is the main problem, and with out them the need for synchronization no longer exists. IMGUI, for example, is an expression of this principle, but it really goes much deeper than just IMGUI.

That technical reasons I alluded to above include:

This is sort of beyond the scope of what I'm getting at, but I'm sure you're right. I do have an extension to my take on MVC that involves a formalisation of writes to the Model and is designed to operate across networks links (i.e. the local Model mirrors a remote Model, which resides on the server).

So, for IMGUI/MVC to be truly useful, you need a single-address-space operating system to eliminate the messaging overhead between models, views, and controllers. (Multitasking is not a relevant concern.)

I disagree, and have implemented a few different variations on the idea. I think that MVC works very well across a network using a client-server style architecture.

Indeed, this was how I "stumbled upon" MVC in the first place. My main beef with the architectures I had been using was the trend of having a server-side and a client-side representation of each concept within the application (for our strategy games we would have a ServerTank and a ClientTank, and often also a "SceneGraphTank"). These kinds of parallell object heirarchies, as well as the redundant copying of information they implied, is something that is undesirable to me.

My approach when running MVC across a network is to have the network aspects by completely transparent by the introduction of a write-proxy interface. The Controllers will talk to this write proxy instead of to the Model directly, and hence substitution of a network links is possible. All access to the Model from without is constant.

Each client will have local space MVC components, and the networking aspects will transparently update the local Model with data from the server, which natrually holds the "real" Model.

The idea (and one of the goals) is that this will work the same way, at least from the MVC components view, in the local case as in the remote case. The differences are all isolated to external systems that either forward method calls on the write proxy to the server or operate on the local Model from without.

In a way I guess I am agreeing with you; there needs to be local adress space MVC components. However, one of my main goals when moving to MVC was to ensure that any networking or adress space issues were transparent.

As in many real-time games that run across a network, doing something like this can require a fair bit of local "prediction". Sometimes running the local Model (on clients) as if it were "in-charge" helps, with incoming network data simply superseding / overwriting calculated state.

However, I'm sure you can see that one of the major wins is that every part of the system sees the state that makes up the Model in the same way; simply the public interface of the Model. There is no other representation of the "state of the application", and few or no intermediate "caches" of such state.

Anyway, hopefully you'll find this feedback/mental ramble useful or insightful. I look forward to your finished book.

Indeed I have, and thank you again for taking the time to write to me. I haven't been actively working on this stuff for a while, but hopefully I will be able to find the time in the near future to get it all done.

regards,
/johno

Back to MVC...