MVVM is lipstick on a pig

MVVM is not a step in the right direction. It’s an additional layer of confusion.

A bit of background

Once a fading pattern used in .NET client development, Model View ViewModel (MVVM) has gained popularity in the iOS community in the past few years. It is presented as a superior alternative to traditional Model View Controller (MVC) development but doesn’t provide a solution to the underlying problems in MVC.

This post will address the real problems in iOS development and show my approach for keeping a codebase in a workable state.

Soroush Khanlou has done a good job of highlighting the problems with MVVM.

My experience with MVVM

I’d done enough .NET client development in WPF and Silverlight to realize MVVM isn’t a magic bullet for good architecture. Massive View Models are real (although we didn’t have a name for them yet).

To be fair, MVVM doesn’t prevent good design. I’ve worked with well designed MVVM iOS projects and much of the advocacy for this approach to iOS development is done by people I respect. A typical MVVM app may often be better designed than a typical MVC app. However, It is a mistake to think this is a causal relationship. This effect is because their creators are among few who care enough about the state of iOS architecture to try to improve things.

While MVVM doesn’t prevent an app from being well designed, the problem is that

MVVM is a distraction

This is the template used for many justifications of MVVM.

  • Extract ViewModel
  • ????
  • Good code

MVVM gives the illusion of improving your architecture without actually improving anything.

The real problem

The real problem is Poorly Defined Classes. Poorly Defined Classes are the enemy of good software. They become dumping grounds for any piece of functionality that comes anywhere near the designated area. Until recently, most mobile projects were small self contained applications. Mobile devs didn’t really need to think about long term design implications that more mature development fields had to deal with. But those days have passed.

The prime example in iOS development is

Controllers

Soroush Khanlou does a good writeup of why they are bad here.

Not far behind Controllers are:

  • Managers
  • Helpers
  • Utilities (classes or folders)
  • Class Extensions
  • ViewControllers

And now we’re adding a new one, ViewModels

This is not a new or particularly novel concept (see this post from 10 years ago). Still, these are ubiquitous in iOS development. If you take one thing away from this post it’s that you should avoid naming classes like these whenever possible. Jr (and even most Sr) developers will not be vigilant in keeping the classes focused.

By advocating MVVM we’re advocating adding a new Poorly Defined Class to the mix. Each Poorly Defined Class invites chaos into your architecture.

In this sense, MVVM makes things worse.

Frameworks require poorly defined classes

Unfortunately, we’re stuck with some PDC’s. Frameworks require them to handle the wide array of tasks that make frameworks useful. Rails and its influenced stacks have Controllers.

In .NET, ViewModels were needed to bind to the XAML UI layout. UIKit requires ViewControllers. These types of Poorly Defined Classes are unavoidable since they are baked into the framework.

We’re stuck with one Poorly Defined class type. Automatically throwing MVVM into the mix creates two Poorly Defined Classes.

A better way

I advocate MVC by default since the ViewController is an inevitable part of developing with UIKit. Avoid Massive ViewControllers by breaking out clearly defined classes as the code evolves.

If you’ve built more than a few apps, you realize many apps end up recreating the same types of functionality. Learn to recognize these patterns and use them to clean up your design. Here is a writeup to get you started. Some other types of classes that exist in many apps are

  • Validator
  • StringFormatter
  • NetworkClient
  • Repository

These are common operations. But don’t let that limit you if you need a DogGroomerRatingInterpreter or UpUpDownDownSwipeGestureReconizer.

Pick clearly defined class names. If you’re adding functionality that doesn’t fit the class name, rename the class or break out the functionality into something else. Do this sooner rather than later. This vigilance will pay off when you have to extract parts of your app to an external library or the growing array of extensions being released.

Let the business needs drive your architecture

While most apps reuse many common components, each app IS a special snowflake. Apps and the business needs they support all evolve in different ways. Business priorities can change on a dime and your code needs to be similarly flexible.

Don’t guess

The right Patterns to extract will reveal themselves as the code evolves. Don’t force them. The biggest mistakes I’ve made when designing software have been to enforce my preconceived notions of good design on a problem I didn’t understand yet.

The catch is, until you’re deep in the weeds with actual user and business problems, you don’t understand the problems you’re facing. You can’t predict what users will do with your app. How can you predict what the right design to solve their problems is?

Attempting to apply your pet software design before the code has emerged is the cause of many headaches. Sometimes a ViewModel (assuming we can define what exactly a ViewModel is) is the right fit for a particular ViewController. But let that decision be driven by the needs at hand, not a preconceived notion of what the design should be.

Conclusion

For most teams, MVVM will only create confusion without adding any benefit. Use only the Poorly Defined Classes required by the framework. Use the actual requirements of your app to guide the overarching development patterns, not the blog musings of developers who don’t know the first thing about your apps requirements.


Also published on Medium.

Join the conversation!

  • A downside of MVVM is that you can see a Massive View Controller become a Massive View Model which only transfers the same problem somewhere else with added complexity.

    I agree with your premise that the real problem is with class design. In both cases, what should be abstracted out, becomes code in a class that is bigger then it should be.

    However if Unit Testing is a concern, MVVM can be a good pattern where these better designed classes (dependencies) are passed in (injected) to a ViewModel where they can be tested.

    With ViewControllers this becomes harder, but not impossible.

    This also makes in clearer to see that this view is dependent on these nicely designed classes with clearly defined responsibilities, more so than a ViewController instantiating dependencies in a say an action handler.

    With a ViewModel I could test.
    1. Button tap
    2. Service call
    3. Update label with some formatted text, is the text in the view the required format.

    Doing that with a ViewModel, the interactions between all of those parts becomes natural, but in a ViewController not so much.

    You could argue that unit testing is of little value and let’s use UI testing for these types of test, but I think that really the value of unit testing is better code, with better separation, which should be the end result here.

  • Loved the article, especialy the parts about having clearly defined classes. It’s right to the point as what direction one should take when developing an app. At the end of the day, it’s really about the business needs, as that’s the driving force for the creation of the app.

  • Totally agree. The business logic and associate wonkiness needs to go somewhere. Once the PDC manifests itself, factor it, refactor it, and organize it, then. I like modeling and encapsulating functionality behind services (managers) that are semantically cohesive.