Skip to content

Instantly share code, notes, and snippets.

@Cananito

Cananito/CanonicalMVVM.md

Last active Sep 3, 2016
Embed
What would you like to do?

Canonical MVVM

Backstory

For a while now, I’ve seen the term MVVM being used in the iOS world. At first I dismissed it since it wasn’t really popular and it reminded me of C# world, which I tend to dislike. But then it started to get a bit more popular so I took a very brief glance at it and didn’t quite get the point.

What I saw was that people were combining it with ReactiveCocoa and/or treating ViewModels as dumb objects holding transformed data from a Model, for a View to consume. I ignored the ReactiveCocoa part since I wasn’t familiar with it (still know just a bit about it).

So based on my observation, it lead me to think: “Why are people bragging about it? They’re just adding a new layer to further separate concerns. Big deal.”.

However, a few days ago I was listening to Build Phase and MVVM was brought up again. I can’t remember what exactly was said, but it triggered the need to reasearch this again and see what was the big deal about it. And so I did.

Warnings

Before proceding, here’s a few warnings:

  • I am not in favor or against MVVM. I really have no opinion on the pattern itself.
  • I have no experience using MVVM.
  • I have close to no experince with .NET platforms.
  • I only spent a couple of days researching this.

The Investigation

With that said, I think we need to start with listing how develpers pitch a given pattern on a given platform/context.

iOS dev on MVC: reusability and separation of concerns.
.NET dev on MVVM: reusability and separation of concerns.
iOS dev on MMVM: avoidance of MassiveViewController through further separation of concerns.

This is not completely scientific, just my general perception, so I won’t go into detail about it. But keep these in mind throughout this article. The reason this is important is because I think it explains the motivation behind the definition and implementation of each pattern in each context.

So I started by going to Wikipedia to look up the definition of MVVM. I noticed 2 things right away. First one was that MVVM was developed by Microsoft. Second one was that MVVM is a variation of MVP, which better decribes Apple’s take on MVC.

So I read all of the wiki and things started to look fishy. I proceeded then to find Microsoft’s definition of MVVM.

Unlike the diagram in Wikipedia, the diagram in MSDN caught my eye right away for some reason. It might’ve been that I now knew that MVVM was a variation of MVP. So I read all of that page to start making parallels between what I’ve seen in the iOS space, but also with Apple’s MVC itself.

Here’s the most important paragraph:

The view model acts as an intermediary between the view and the model, and is responsible for handling the view logic. Typically, the view model interacts with the model by invoking methods in the model classes. The view model then provides data from the model in a form that the view can easily use. The view model retrieves data from the model and then makes the data available to the view, and may reformat the data in some way that makes it simpler for the view to handle. The view model also provides implementations of commands that a user of the application initiates in the view. For example, when a user clicks a button in the UI, that action can trigger a command in the view model. The view model may also be responsible for defining logical state changes that affect some aspect of the display in the view, such as an indication that some operation is pending.

If you substitute the term “view model” with “ViewController”, you will notice right away that they’re describing Apple’s MVC, with 2 exceptions: the View owns the ViewModel (ViewController), and that UI modifications and model updates are done through bindings.

So I was very astonished that developers in iOS land were buying and selling a false definition of MVVM. And it took me just like 10 minutes to research this. How can everyone get this so wrong? So I emailed the Build Phase hosts to tell them about this.

This topic kept bugging me throughout the day. So I thought “Maybe only a subset of iOS developers have the wrong definition of it, I’ll look for MVVM resources in the iOS context.”.

The first resource I stumbled uppon was Ash Furrow’s article in objc.io. Here’s were my perception of an iOS dev’s take on MVVM (listed at the beginning) was further reinforced. What Ash proposes is:

  • The View and Controller are essentially the same thing (hard to argue when they’re explicitly called “ViewController”).
  • Add a new layer between the Model and the ViewController: a ViewModel.
  • The ViewController owns the ViewModel.
  • The ViewController sets the Model on the ViewModel.
  • This new layer generates data out of the Model, for the ViewController to easily consume.

The advantages of this being that you took a good chunk of code out of the ViewController and that you can unit test ViewModels.

Ok Rogelio, so what’s your issue then? My issue is that that is not that canonical definition of MVVM. Let’s go back to it:

  • The View is represented by a markup language (XAML).
  • The View may be represented in code (“code behind”) through a subclass of the platform’s View baseclass, but you are encouraged to stay in markup land.
  • The View creates a ViewModel and holds a reference to it.
  • The ViewModel has a list of properties that the View gets binded to (two way binding).
  • The ViewModel has methods that handle UI events (forwarded from the View through XAML commands or in the code behind through a direct method call).
  • The ViewModel takes care of fetching the Model.
  • The ViewModel manipulates the Model.
  • The ViewModel is binded to the Model.
  • The ViewModel takes care of creating new Views (navigation, essentially).

(To see all this in action, here’s a video that goes through a WPF app, 1 hour long: https://www.youtube.com/watch?v=q-yho2LfQ0Q).

Again, the ViewModel is not a dumb object in the canonical definition. It does quite a lot. Just like your good freind MassiveViewController. In fact, I saw around that .NET people had the exact same issue sometimes: their ViewModels got out of hand. However, they have 2 less issues to deal with:

  1. All UI manipulation is eliminated because of bindings.
  2. All UI layout and styling is eliminated because XAML is capable of doing so 100% without code. IB is pretty close, but I can’t remember the last time I was able to pull this off 100% in a project.

So maybe just 1 article on MVVM in iOS wasn’t enough. I went searching for more. They all said pretty much the same thing. Except this Ray Wenderlich one that includes ReactiveCocoa in the mix (which Ash did mention at the end of his post).

This described the pattern two steps closer and one step farther to the canonical one. Bindings with the UI (through ReactiveCocoa), and commands in the ViewModel (event handling, also binded through ReactiveCocoa). But the ViewModels were being externally set on the ViewControllers, as opposed to the ViewModels being created by the Views themselves (I may be wrong on this detail).

My Real Issue

Ok, again Rogelio, what’s the your issue with all of this? My issue is that it makes it harder to learn more about it when big parts of the implementation are very different between platforms/contexts. And it also makes for an awkward conversation with Silverlight and WPF developers.

Solution?

Let’s say you agree with me that the iOS implementations are not MVVM. This takes us to 2 options:

  1. Call it something else. Maybe MVVCVM (Model-View-ViewController-ViewModel).
  2. Implement it correctly (if for some reason you 100% agree with the canonical definition of MVVM).

I would honestly settle for number 1. In fact, I think 2 is near impossible in iOS. Let’s take a look at why.

The first step would be to sort out the whole View and ViewController thing. Mathematically, the best thing to do would be to drop the ViewController. We already have a View, it’s called UIView. You can do most of it in IB: layout, IBOutlets to controls/subviews, and event handling with IBActions to methods. This makes IB be the XAML and the UIView subclass be the code behind (which is a View subclass itself).

The next step is when you bump into a huge brick wall: UIKit. Navigation is deeply tied to the ViewController philosophy: UINavigationController, UITabBarController, UINavigationBar, push, pop, present, etc. They all expect the existance of a ViewController with a reference to a View. Getting around this might be a real pain.

Plot Twist

With all this said, I was talking today with a co-worker that comes from the ASP.NET world and he said that they used MVVM. When he started talking about how they implemented it, he described the ViewModel like I’ve seen it described in the iOS world: as a dumb object holding transformed data from a Model for a View to consume.

This made things very interesting. I went to search for APS.NET examples that used MVVM and could not find anything helpful. All I could find is exactly what you find in iOS land: everyone has their take on it. Some just passed a dumb ViewModel to the View. Some used Knockout.js to do it on the client-side. So many variations. And it makes sense: the web stack, like UIKit, isn’t very flexible for completely different patterns.

I guess the conclusion afterall, is that this whole rant is pointless.

Update 1

Justin Spahr-Summers responded with a link to a waaaaay more accurate description of MVVM in the context of iOS. So I still don’t know at what point the definition got distorted, since people are using it way differently, like it is explained in a thoughtbot GitHub issue.

@cxa

This comment has been minimized.

Copy link

@cxa cxa commented Dec 18, 2015

A typo in “First one was that MVVM was developed my Microsoft.”, should be “...developed by Microsoft.”

@Cananito

This comment has been minimized.

Copy link
Owner Author

@Cananito Cananito commented Aug 26, 2016

@cxa Just saw the comment. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.