Friday, April 3, 2015

Model Widget Controller (MWC) aka: Apple "MVC" is not MVC

I probably should have taken more notice that time that after my question about why a specific piece of the UI code had been structured in a particular way, one of my colleagues at 6wunderkinder informed me that Model View Controller meant the View must not talk to the model, and instead the Controller is responsible for mediating all interaction between the View and the Model. It certainly didn't match the definition of MVC that I knew, so I checked the Wikipedia page on MVC just in case I had gone completely senile, but it checked out with that I remembered:
  1. the controller updates the model,
  2. the model notifies the view that it has changed, and finally
  3. the view updates itself by talking to the model
(The labeling on the graphic on the Wikipedia is a bit misleading, as it suggests that the model updates the view, but the text is correct).

What I should have done, of course, is keep asking "Why?", but I didn't, my excuse being that we were under pressure to get the Wunderlist 3.0 release out the door. Anyway, I later followed up some of my confusion about both React.native and ReactiveCocoa (more on those in a later post) and found the following incorrect diagram in a Ray Wenderlich tutorial on ReactiveCocooa and MVVC.

Hmm...that's the same confusion that my colleague had. The plot thickens as I re-check Wikipedia just to be sure. Then I had a look at the original MVC papers by Trygve Reenskaug, and yes:

A view is a (visual) representation of its model. It would ordinarily highlight certain attributes of the model and suppress others. It is thus acting as a presentation filter. A view is attached to its model (or model part) and gets the data necessary for the presentation from the model by asking questions.

The 1988 JOOP article "MVC Cookbook" also confirms:

MVC Interaction Krasner 88

So where is this incorrect version of MVC coming from? It turns out, it's in the Apple documentation, in the overview section!

Model view controller

I have to admit that I hadn't looked at this at least in a while, maybe ever, so you can imagine my surprise and shock when I stumbled upon it. As far as I can tell, this architectural style comes from having self-contained widgets that encapsulate very small pieces of information such as simple strings, booleans or numbers. The MVC architecture was not intended for these kinds of small widgets:

MVC was conceived as a general solution to the problem of users controlling a large and complex data set.
If you look at the examples, the views are large both in size and in scope, and they talk to a complex model. With a widget, there is no complex model, not filtering being done by the view. The widget contains its own data, for example a string or a number. An advantage of widgets is that you can meaningfully assemble them in a tool like Interface Builder, with a more MVC-like large view, all you have in IB is a large blank space labeled 'Custom View'. On the other hand, I've had very good experiences with "real" (large view) MVC in creating high performance, highly responsive user interfaces.

Model Widget Controller (MWC) as I like to call it, is more tuned for forms and database programming, and has problems with more reactive scenarios. As Josh Abernathy wrote:

Right now we write UIs by poking at them, manually mutating their properties when something changes, adding and removing views, etc. This is fragile and error-prone. Some tools exist to lessen the pain, but they can only go so far. UIs are big, messy, mutable, stateful bags of sadness.

To me, this sadness is almost entirely a result of using MWC rather than MVC. In MVC, the "V" is essentially a function of the model, you don't push or poke at it, you just tell it "something changed" and it redraws itself.

And so the question looms: is react.native just a result of (Apple's) misunderstanding (of) MVC?

As always, your comments are welcome here or on HN.


Adam R. Maxwell said...

This is news to me, since I learned Apple's notion of MVC from the Cocoa documentation. In an NSDocument-based application I've worked on (BibDesk), our model communicates only with the document (except for a few NSNotifications). This has worked out fairly well, insofar as we have changed the views out with little difficulty. The document (controller) is a nightmare, though.

Anonymous said...

What Apple uses as MVC is often called the Model–View–Adapter variant. The Controller mediates between the View and the Model and adapts model data to view representations and view interaction to model changes.

John Daniel said...

I don't think I ever really understood MVC until I worked with the PHP Zend framework (version 1, not 2). I think my problem was that Apple kept confusing me. However, I don't have a problem with this particular Apple diagram. This is the way I envision MVC to be. I don't really care who had the original diagram. I am comfortable with the idea of having the MVC concept evolve to match expectations and usability. From that perspective, Apple's diagram where the model and view are decoupled is what I expect. I want to be able to swap out the UI view for a command-line test rig, for example. I want to swap out the local model for a cloud model. I don't fault Apple on its diagrams, but its implementations. To say you implement MVC and then have a whole suite of classes named "ViewController" is just ridiculous. Which is it? A view or a controller? Apple's approach leads to an API soup and a bunch of code that gets in the way of application logic. But the diagram itself - I like that. I just wish Apple's code and architecture followed its diagrams.

Marcel Weiher said...

Thanks for your comments!

@Anonymous: first guess was Model View Presenter (Taligent, Dolphin Smalltalk), though MVA sounds very similar.

@Adam: Yes, nightmarish controllers are the common problem with MVP, which is why Apple's version has been called "Massive View Controller". Actual MVC can have very slim controllers.

@John: Pardon my bluntness, but if you envision MVC to be this, you envision wrong. It may very well be that the pattern you prefer (MVP/MVA) is better than MVC, but it's a different thing and has a different name. And yes, you can swap out the View for a command-line test rig in classic MVC, because the Model does not know about the View.

MVP/Massive View Controller tends to end up with much of the code in the "ViewController" (whatever that is supposed to be), which then happens to be coupled to both the views and the model.

Anonymous said...

Marcel, how do you solve the Massive View Controller problem with the pure or original MVC? Is a ViewController part of the View in that thinking? Maybe I should look at the source material. Anyhow, coupling view and model seems bad. Maybe MVVM to the rescue? Any thoughts on that?

Anonymous said...

MVP and MVA are kind-of the same. The Controller mediates between the model and the view, instead of the classic Smalltalk triangle, where the view knows about the model.

The advantage of MVA/MVP is mainly the highly decoupled state and reusable components: models and views are all reusable independently. In classical MVC, the view most often cannot be reused for completely different models.

The disadvantage of MVA/MVP is that you need more glue to glue all those reusable components together. That glue tends to end up in the Controller. Whenever you implement a UITableViewDataSource in a ViewController, you are glueing together your model and and the re-usable view.
Classical MVC doesn't really have that disadvantage at all: since the view gets data from the model directly, the controller doesn't need to glue those two together.

The problem with Apple's MVC in UIKit is that more and more of that glue is needed with every major iOS release, and thus ViewControllers become bigger and bigger. Things such as viewDidLayoutSubviews, updateConstraints, top/bottomLayoutGuide should all be done by the view. When is the last time you implemented -loadView, instead of creating a bunch of subviews in -viewDidLoad? Creating subviews should be part of the View logic, but often ends up in the ViewController.

Norberto Ortigoza said...

Check this article from Matin Fowler:

Daniel said...

What I've always liked about Apple's version of MVC is that I seldom subclass View objects as they don't need to know anything about the M or, for the most part, the C.

I also never restricted Controllers to only being view controllers. You can split logic up amongst many controller objects (data controllers, network request controllers, ...) and I don't find my controllers getting unnecessarily large and complicated.

Remember that with Smalltalk, we programmed by changing the environment - the patterns we use will change depending on the language and the framework we are coding for.

The patterns I use in Swift are very different than the patterns I use in Obj-C even though I'm working with Cocoa and Cocoa Touch in both.

John Daniel said...

Good luck wresting the power to name from the world's most powerful corporation. Smalltalk is dead. Get used to it.

As for the "Massive View Controller", I was on a plane this weekend and watched a couple of WWDC videos on architecture. It turns out that Apple doesn't promote that idea at all. See "Core OS iOS Application Architectural Patterns", session 224.

Obviously most developers just copy and paste from sample code and StackOverflow instead of watching WWDC videos. They rarely consider things from an architectural standpoint and that is what leads to API soup and "Massive View Controller".

But on second thought, you would probably have better luck reforming Apple's nomenclature than you would improving the architectural practices of the app developer community. People are confused and Apple doesn't really help with that. Arguing over names doesn't help either.

Anonymous said...

@John Daniel

regarding this:

"But on second thought, you would probably have better luck reforming Apple's nomenclature than you would improving the architectural practices of the app developer community. People are confused and Apple doesn't really help with that. Arguing over names doesn't help either."

I'd strongly argue that this kind of writing about these issues really does help others coming at these things from a more theoretical and stunted point of view. It certainly helps me.

Anonymous said...

Just wanted to say apple actually acknowledges the existence of the "traditional" version (complete with references to the design patterns!) in their docs and provides a justification for their Cocoa version.

Steven Mathers said...

I recommend watching an 'uncle bob clean architecture' video

To summarise the parts relevant to your post:
1) MVC and the like are GUI patterns not application architectures, and as such are a minor architectural concern
2) The MVC pattern was originally intended to be implemented many times for each tiny GUI component - button, field or label, where the 'model' is the model of that button, field or label.

The conclusion is that there shouldnt be any huge concern about a particular flavour of MVC/MVP or whatever that you use for you GUI pattern, but because people are confusing it with the architecture for their entire application - banging square pegs into round holes - they are magnifying the minor differences into undeserved and undesirable importance.