Architectural Pattern Landscape

Great article here (h/t: ManiacDev) on selecting an architectural pattern for your apps:

iOS Architecture Patterns: Demystifying MVC, MVP, MVVM and VIPER

Let’s define features of a good architecture:

  1. Balanced distribution of responsibilities among entities with strict roles.
  2. Testability usually comes from the first feature.
  3. Ease of use and a low maintenance cost.

Starts out going through the Massive View Controller we’re all familiar with,

…it might seem that Cocoa MVC is a pretty bad pattern to choose. But let’s assess it in terms of features defined in the beginning of the article:

  • Distribution — the View and the Model in fact separated, but the View and the Controller are tightly coupled.
  • Testability — due to the bad distribution you’ll probably only test your Model.
  • Ease of use — the least amount of code among others patterns. In addition everyone is familiar with it, thus, it’s easily maintained even by the unexperienced developers.

Cocoa 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.

Next, the MVP option is “Cocoa MVC’s promises delivered” by redefining the UIViewController as the View,

… Does this mean that Apple’s MVC is in fact a MVP? No, its not, because if you recall, there, the View is tightly coupled with the Controller, while the MVP’s mediator, Presenter, has nothing to do with the life cycle of the view controller, and the View can be mocked easily, so there is no layout code in the Presenter at all, but it is responsible for updating the View with data and state.

In terms of the MVP, the UIViewController subclasses are in fact the Views and not the Presenters. This distinction provides superb testability, which comes at cost of the development speed, because you have to make manual data and event binding…

  • Distribution —we have the most of responsibilities divided between the Presenter and the Model, with the pretty dumb View…
  • Testability — is excellent, we can test most of the business logic due to the dumb View.
  • Ease of use —… the amount of code is doubled compared to the MVC, but at the same time, idea of the MVP is very clear.

Thirdly, No doubt you’ve heard at least in passing of MVVM and its enablers of the Reactive Cocoa ilk, which decouple similarly to MVP,

  • the MVVM treats the view controller as the View
  • There is no tight coupling between the View and the Model

In addition, it does binding like the Supervising version of the MVP; however, this time not between the View and the Model, but between the View and the View Model.

So what is the View Model in the iOS reality? It is basically UIKit independent representation of your View and its state. The View Model invokes changes in the Model and updates itself with the updated Model, and since we have a binding between the View and the View Model, the first is updated accordingly…

There is one bitter truth about reactive frameworks: the great power comes with the great responsibility. It’s really easy to mess up things when you go reactive. In other words, if do something wrong, you might spend a lot of time debugging the app… Yes. Yes, you might. If you mix your FRP with Core Data, you will, we confidently predict.

  • Distribution —…the MVVM’s View has more responsibilities than the MVP’s View. Because the first one updates it’s state from the View Model by setting up bindings, when the second one just forwards all events to the Presenter and doesn’t update itself.
  • Testability —the View Model knows nothing about the View, this allows us to test it easily. The View might be also tested, but since it is UIKit dependant you might want to skip it.
  • Ease of use —…in the real app where you’d have to forward all events from the View to the Presenter and to update the View manually, MVVM would be much skinnier if you used bindings.

Some other worth reading discussions on architecting with MVVM:

And lastly, we’d skipped past this VIPER thing up to now, but anything described as “LEGO building experience transferred into the iOS app design” must be fun, yes?

VIPER makes another iteration on the idea of separating responsibilities, and this time we have

five

layers. Topping the View,

  • Interactor — contains business logic related to the data (Entities) or networking, like creating new instances of entities or fetching them from the server. For those purposes you’ll use some Services and Managers which are not considered as a part of VIPER module but rather an external dependency.
  • Presenter — contains the UI related (but UIKit independent) business logic, invokes methods on the Interactor.
  • Entities — your plain data objects, not the data access layer, because that is a responsibility of the Interactor.
  • Router — responsible for the segues between the VIPER modules.

Basically, VIPER module can be a one

screen

or the whole

user story

of your application — think of authentication, which can be one screen or several related ones. How small are your “LEGO” blocks supposed to be? — It’s up to you…

  • Distribution —undoubtedly, VIPER is a champion in distribution of responsibilities.
  • Testability —no surprises here, better distribution — better testability.
  • Ease of use —finally, two above come in cost of maintainability as you already guessed. You have to write huge amount of interface for classes with very small responsibilities.

To help with that “huge amount”, check out Generamba, introduced here :

… An average iOS developer creates only one class per screen. But for the one who uses VIPER that’s a moment of suffering. To be true – it’s a little longer than just a moment. Usually he has to create and fill with boilerplate code for around five classes, six protocols and five test-cases … That were the reasons to create our own code generator called

Generamba

. We got a highly extensible tool for a wide range of different code generation tasks though originally it was developed with just VIPER modules in mind.

Another application of the VIPER principles to simplifying view controllers is

Humble Object Pattern in Swift

For a side assist to the model view whatever patterns when networking is involved — and when isn’t it these days? — check out

Exploring MVC-N in Swift

… So, you cache the data, change the layer, and each one of the ViewControllers will stick it in the cache as they get data. When any other ViewController comes up, they can get the data out of the cache.

No. This is bad.

This is what I refer to as the “anti-pattern”. I cannot count the number of times I have seen this, or done it myself. This is the pattern I am attacking. I am openly saying: please stop doing this. We want to write code, we want to see results right away, and we end up doing this. This is a problem…

That is what we should be doing at design time, not at the 11th hour when we are shipping tomorrow morning, and saying “I need to refactor all this”. When we have the UI/UX, we understand how the app needs to come together, and that is when we should be looking at it.

“I need data from the network. Where do I put that code to get the data out of the network?” This is where the MVC-N comes in…

For a completely different option, check out ReSwift (née ReduxKit/SwiftFlow), a Swift version of Redux:

Unidirectional Data Flow in Swift: An Alternative to Massive View Controllers

Redux

is an alternative or a variation of the

Flux

framework that was developed at Facebook, and that Facebook now uses for most of their web applications. The main idea is that information always only flows in one single direction. We don’t have communication between individual view controllers, we don’t have individual delegator callback blocks. Information flow is structured and set in one very specific way…

Along the same Flux-inspired lines is Ziggurat iOS App Architecture.

Of course, if you have seriously simple needs, having a controller at all might be overkill:

Design Patterns in Swift: Document-View

The document-view pattern was once the preferred pattern used in Visual C++ development. Microsoft built the original Microsoft Foundation Classes around this pattern, in fact, back in the dark ages. It’s not used much today, but it’s useful when you have simple data management needs…

And finally, here’s a resource for even more deep diving into architectural patterns:

fantastic-ios-architecture

UPDATES:

A Declarative Architecture for Swift Apps Improve your iOS Architecture with FlowControllers

boilerplate: “Select the right architecture and functional reactive programming framework.”

Functional Core Reactive Shell

A Different Take on MVVM with Swift: “this is just my way of doing MVVM … I call it Scene-Stage-Director.”

NonReactiveMVVM: MVVM: A non-reactive introduction

iOS-Awesome-Starter-Kit: “The perfect combination: Clean Swift + ReSwift + PromiseKit.”

Getting Started with PromiseKit Faster Together: Uber Engineering’s iOS Monorepo VIPER architecture: Our best practices to build an app like a boss iOS Project Architecture: Using VIPER

Viperit: “Write an iOS app following VIPER architecture. But in an easy way.”

Swift with a hundred engineers

Good iOS Application Architecture: MVVM, MVC, VIPER Which Architecture is the Best?

VIPER-S: Writing Your Own Architecture to Understand Its Importance (Part 1) + Part 2 + Part 3

Struggling with iOS Design Patterns? Embrace Modlizer

Taming Great Complexity: MVVM, Coordinators and RxSwift

Architecting iOS Apps with “Core”

Good iOS Application Architecture: MVVM vs. MVC vs. VIPER

Unidirectional Data Flow: Shrinking Massive View Controllers

New iOS Software Architecture: 4V Engine

MVVM at Scale: Not so Simple…

Driving View-State through Data for Fun and/or Debugging

iOS Architecture: A State Container based approach

Avoiding singletons in Swift

Much ado about iOS app architecture

MVVM — MVC done right.

View-state driven applications

Model-View-Controller without the Controller

A Flexible Routing Approach in an iOS App

Pragmatic iOS Development: In defence of MVC

iOS-VIPER-Xcode-Templates

Protocol Oriented Tips For MVVM in Swift

Navigation in Swift

Coordinator Tutorial for iOS: Getting Started

How to use the coordinator pattern in iOS apps

The C in MVVM-C

Protocol-Oriented Routing in Swift

Dependency Injection with the Cake Pattern

Swifty Protocol-Oriented Dependency Injection

Tempura: “A holistic approach to iOS development, inspired by Redux and MVVM”

A Better MVC, Part 1: The ProblemsPart 2: Fixing EncapsulationPart 3: Fixing Massive View ControllerPart 4: Future DirectionsPart 5: An Evolution

Blurring the Lines Between MVVM and VIPER

Hosting Viewcontrollers In Cells

So Swift, So Clean Architecture for iOS

Advanced iOS Architecture: Solving the 5 Issues of the MVC, MVVM and VIPER patterns

Model controllers in Swift

Handling mutable models in Swift

Swift Tip: Bindings with KVO and Key Paths

How to implement singletons in Swift the smart way

Value-Oriented Programming

Evolving mobile architecture at Reddit

Different flavors of view models in Swift

How to dismantle a Massive Singleton iOS App

XCoordinator — Introducing an iOS navigation library based on the coordinator pattern

Controller Hierarchies

Avoiding Massive View Controller using Containment & Child View Controller — Alfian Losari

Alex | April 15, 2016

Leave a Reply