MVVM Benchmark in an MVC World — Part 1
The iOS SDK has been ever changing since its original release, but one thing that has endured the trials of time was the design pattern — MVC A.K.A. Model-View-Controller.
Apple’s usage of the MVC pattern in iOS can be traced back to OSX’s APIs — Cocoa, APIs from which the iOS SDK takes shape.
While I’m sure most of you tech savvy readers are familiar with how MVC works, I’ll be doing a brief overview.
What is MVC?
The Model-View-Controller (MVC) design pattern assigns objects in an application one of three roles: model, view, or controller.
Apple’s MVC Reference page
MVC defines both the role for a given object within an application but also how it should communicate with other types of objects.
Apple heavily encourages to use the MVC pattern when developing applications for the iOS platform as it complies with their own frameworks and coding standards.
Model Objects
Model objects are used to encapsulate the data and the manipulation over such data. (e.g. an Animal class)
The model objects are created or updated by the controller objects, while at the same time, notifying the controller if it gets updated by some other controller object.
View Objects
A view is an object which usually represents a model object in the user interface. (e.g. an image of a cat)
View objects are updated according to the controller’s instructions and can delegate user interaction back to the controller as well. (e.g. the image is tapped)
Controller Objects
The controller is the intermediary between model and view objects, manipulating both as the the UI is interacted with and when the model changes as well.
A controller maps user input into model objects, is notified of changes and updates the UI accordingly.
Why would you even want another design pattern?
Even though Apple recommends using MVC for anything and everything iOS related, is has some huge caveats when it comes to code structure and logic separation.
MVC is sometimes unabbreviated as Massive View Controller due to the fact that controller objects contain most of the logic in an application. From delegation, to data sourcing, view manipulation, model manipulation, dispatching network requests; the controller does it all. You can easily browse through GitHub and see it for yourselves.
Because of this issue, there’s always a compromise between staying true to the MVC pattern and refactoring code to other view and model objects. (e.g. animalTableViewCell.setupWithAnimal(animal), which breaks the MVC pattern as the view actually has a pointer to the model object)
Another issue with MVC is Unit Testing. Since controllers and views are so tightly coupled, it becomes really hard to mock all the views and their life cycle, while at the same time separating the business logic from the view logic.
Although issues can be found on the MVC pattern, it is highlighy regarded as the best architectural pattern when it comes to development speed.
…MVC is the pattern of your choice if you are not ready to invest more time in your architecture, and you feel that something with higher maintenance cost is an overkill for your tiny pet project. — Bohdan Orlov
A challenger approaches — MVVM
MVVM A.K.A. Model-View-ViewModel is a design pattern that has been growing in popularity among iOS developers.
This pattern still maintains the view and the model objects from MVC but introduces the view model concept.
The view model is basically a refactor of the old controller logic of mapping model representation to the views and the interaction between the UI to the actual model changes.
MVVM in iOS relies heavily on libraries such as RxSwift (or ReactiveCocoa) and RxCocoa. These libraries allow the developers to work in a functional reactive programming paradigm, allowing both data binding and observable streams.
The motivation behind MVVM is to reduce the complexity of the view controller classes and make the presentation logic easier to test.
— MVVM is compatible with your existing MVC architecture.
— MVVM makes your apps more testable.
— MVVM works best with a binding mechanism. — Ash Furrow
In case you want to learn more about MVVM, I suggest reading the following articles: Introduction to MVVM, iOS Architecture Patterns and MVVM in Swift. As for reactive functional programming, ReactiveX, Functional Reactive Awesomeness with Swift and Reactive Swift.
Why benchmark MVVM vs. MVC?
As with every software architecture, it is generally a good idea to understand their advantages and disadvantages within a given context.
Although some benefits like code refactoring and testability are clearly favouring MVVM, we want to measure it in a real use case, where the same application is developed twice, one in MVVM design pattern and another in MVC.
We also have to take into account that MVC and MVVM have different requirements in terms of frameworks (and their performance impact), as MVC relies only on Apple’s frameworks, while MVVM might (and will on our specific use case) rely on RxSwift and RxCocoa.
With this, we’ll be able to understand how much better one is over the other in the defined contexts.
Benchmark Swift App — Yet another Reddit App
To successfully cover all our basis when it comes to iOS development, we wanted to create an application which deals with asynchronous network calls, JSON parsing, image loading, collection and table views, storyboarding and user authentication (among others).
This is the reasoning behind our choice of creating a Reddit iOS app, as it certainly fits the above requirements while at the same time providing a RESTful API with OAuth authentication.
The ongoing project can already be found on GitHub and will be in active development in the coming months.
The app is expected to take advantage of Apple’s default UIKit classes in order to keep development time to a minimum. As such, the UI/UX customisation will not be a focus, although proper navigation and responsiveness will still be a priority.
Benchmark metrics
We will be splitting the metrics into two categories — binary and code, where runtime focuses on actual application usage metrics; and code on the developer’s quality of life.
Binary
In this category we want to understand how much of an impact the code architecture actually has on the application’s usage of the device’s resources.
The following metrics will be measured:
- Binary size
- Bootup time
- CPU usage (average and peaks)
- Memory usage (average and peaks)
- Main thread locks
Code
Even though development time would be a great metric to measure, due to the fact that I am currently only one developing both applications, it would make the first architecture take longer due to the problem solving part of developing the applications.
So to actually measure the developer’s QoL, we will be looking into the following metrics:
- Lines of code (total and average per file)
- Number of files (classes, structs, enums, views, etc)
- Function (and calculated variables) complexity
- Mutability and Immutability
- Testability
- Compile time
Code of conduct
This architecture benchmark is open to adding other relevant iOS design patterns to test, as well as other metrics to be measured (and how to measure them).
The project is open source at GitHub and we’re actually open to contributions from the iOS community as hopefully this will benefit iOS developers when choosing the architecture for the next application they develop (or refactor)!