Yes, I admit it. Initially I thought MVC (Model-View-Controller) was the «perfect» way to architecture your Apps, but lately, I have opted for another type of architecture. Why? it is a good point to start, as a tricycle is for bike riding. But it is not a good bike.
MVC: The modern way
After reading this article about MVC, I realized that I do not understand MVC as Rui Peres does on that article. Rui states that UIViewControllers are part of the View objects. I agree with that, but then, Rui creates a controller object to embed the business logic into it, to avoid including all the business logic into the ViewController and getting to a Massive View Controller problem. Then, Rui ends up with Model-View-ViewController-Controller, which is pretty close to a MVVM architecture. Rui responds at the comments that MVC «as-is» is not a good way to go:
Well, I am against what Apple said on that regard, otherwise you end up with a huge UIViewController. Hence the use of a proper controller, that is easily testable and has no dependency with the UI. (Rui)
So maybe there are other ways to code…
Other models
I have written about other models, like MVVM, VIPER and MOVVER on this post, but to sum up:
- MVVM does exactly what Rui tried on the article, put away all business logic from the UIViewController itself and avoid a massive view controller. You put this on the ViewModel.
- VIPER is even more fragmented, and all presentation goes to Presentation objects, Interactors include business logic and Routers perform navigation.
- MOVVER, which is my current choice, is a an intermediate solution. You create view models that behave like a Presenter-Interactor pair and use routers to help you with navigation.
So, why should you use them?
Benefits of clean architecture vs MVC
Changing requisites (a.k.a. the client wants changes)
MVC: If you have built your UI within a ViewController which is tied to it’s business logic, this can be a mess…
Clean architecture: You just have to change the part the client wants to change. No need to rebuild other parts of your architecture.
e.g.: Imagine a UI that shows a collectionView with custom cells, with a button inside and a background image. When you tap on an cell, you show a full screen modal view. If you tap the button, you have to show a popupController.
Then the client changes his mind and tells you to build the same UI but using a tableview and a push animation for the detail, and substitute the button with a disclosure indicator which will show a detail view controller. The data is the same, the business logic is the same…
Using a clean architecture, you just have to:
- Create the new UI and uiviewcontroller.
- Wire up your ViewModels, Routers, etc… This is a couple of lines of code for each property/method. Promised.
- Modify the way the viewControllers are presented (modally, popup, etc.) and
…you are done. Barely UI and wiring code.
If you are in MVC, you will have to:
- Create the new UI and uiviewcontroller.
- Create -again, as you cannot copy it directly – the business logic for the label and image of the new UITableViewCell, as it was INSIDE the collectionViewCell.
- Create -again, as you cannot copy it directly – the business logic for the view controller.
- Rewrite your code for the transitions, as they are completely new, and are located in different places (detail disclosure does not work as a button inside a cell).
UI code, business logic, etc. More work for sure…
Multiple Devices: UI is different, Business Logic does not
MVC: If all your business logic is in the UIViewController, then you will have to deal with different devices in the same subclass, or create subclasses for each device/configuration and copy business logic code. This is, copy&paste the same code for each subclass. Both alternatives are really bad…
Clean architecture: If you have MVVM/VIPER/MOVVER architecture, you can create ONE business logic object, and use it wherever you want. On an iPad Pro or on an iPhone 4s.
Colaboration
MVC: Having few files implies you will run into conflicts if two or more people work on the same file.
Clean Architecture: having different files implies a developer can be building ui and the other one can be writing the viewModel. No worries about conflicts
Easy routing
MVC: You have to build routing inside a Storyboard or manually in the view Controller.
Clean Architecture (not MVVM, as it has no routers): You create a router for a ViewController and you can use it wherever you want in your App. Plain and simple.
e.g.: At the last example, we had a button inside a collectionViewCell.
MVC: If you do not have routers, you have to tell your view controller to PUSH a view. You do it using delegates or, using segues. Then, you cannot reuse your code for the tableView version.
Clean Architecture: You write the presentation code inside a router and you pass the router to the cell. At the tableView version, you assign the routing behavior by passing the router to the tableView. Plain and simple.
Fully testable
MVC: At last but not least, your business logic code, which is the «what does this app» is inside the UIViewController. That is, you have to do UI Testing on it.
Clean architecture: it is fully testable without any UI interaction. It works with delegation or other binding system, and does not need to know if a UI is behind the scenes. So, you can build Unit Tests. No need for UI Testing at ViewModels.
Clean Architecture, less pain, less time
I have read tons and tons of articles telling you to follow MVC «if you do not need to test» or «do not need for maintenance»… In RealLife™, you will always maintain your code, change it, debug it, refactor, etc. even before version 1.0.0. So it is cristal clear for me that a clean architecture is worth a shot, as it will save you tons of hours, not next month, but tomorrow when the client changes its mind, you need to refactor, and so on.
Just a final note I want to share with you. Apple says about MVC:
The Model-View-Controller design pattern (MVC) is quite old. Variations of it have been around at least since the early days of Smalltalk. It is a high-level pattern in that it concerns itself with the global architecture of an application and classifies objects according to the general roles they play in an application. It is also a compound pattern in that it comprises several, more elemental patterns.
[…]
One can merge the MVC roles played by an object, making an object, for example, fulfill both the controller and view roles—in which case, it would be called a view controller. In the same way, you can also have model-controller objects. For some applications, combining roles like this is an acceptable design.
That is, Apple never said that breaking MVC into MVVM, VIPER or MOVVER is a bad idea or water mixing roles is bad. In fact, Apple mixes roles in ViewControllers.