Why Architecture is important in iOS Development
A couple of years ago, all of the iOS apps were small containing less than 10 screens. The codebase was small, storyboards were working excellent, and it was easy to maintain your project. From an architectural point of view, MVC was doing a great job.
How about today?
Today, we are facing big technological advancements and an insane app market growth. In other words, apps are becoming big and complex. We are working on projects that contain 20, 30 or even 40 screens making it impossible to be maintained with MVC.
Feeling weird while doing MVC in iOS? Have doubts about switching to MVVM? Heard about VIPER, but not sure if it worth it?
As technology moves forward, so should we (developers).
Why care about choosing the architecture?
Because if you don’t, one day, debugging a huge class with dozens different things, you’ll find yourself being unable to find and fix any bugs in your class.”. Naturally, it is hard to keep this class in mind as whole entity, thus, you’ll always be missing some important details. If you are already in this situation with your application, it is very likely that:
- This class is the UIViewController subclass.
- Your data stored directly in the UIViewController
- Your UIViews do almost nothing
- The Model is a dumb data structure
- Your Unit Tests cover nothing
And this can happen, even despite the fact that you are following Apple’s guidelines and implementing Apple’s MVC pattern, so don’t feel bad. There is something wrong with the Apple’s MVC, but we’ll get back to it later.
Let’s define features of a good architecture:
- Balanced distribution of responsibilities among entities with strict roles.
- Testability usually comes from the first feature (and don’t worry: it is easy with appropriate architecture).
- Ease of use and a low maintenance cost.
Distribution keeps a fair load on our brain while we trying to figure out how things work. If you think the more you develop the better your brain will adapt to understanding complexity, then you are right. But this ability doesn’t scale linearly and reaches the cap very quickly. So the easiest way to defeat complexity is to divide responsibilities among multiple entities following the single responsibility principle.
This is usually not a question for those who already felt gratitude to unit tests, which failed after adding new features or due to refactoring some intricacies of the class. This means the tests saved those developers from finding issues in runtime, which might happen when an app is on a user’s device and the fix takes a week to reach the user.
Why Ease of use?
This does not require an answer but it is worth mentioning that the best code is the code that has never been written. Therefore the less code you have, the less bugs you have. This means that desire to write less code should never be explained solely by laziness of a developer, and you should not favour a smarter solution closing your eyes to its maintenance cost.
We at iLeaf Solutions use i)MVVM based on clean architecture in our projects and also ii)VIPER architecture for much bigger project.
What is Clean Swift Architecture ?
Clean Swift is Uncle Bob’s Clean Architecture applied to iOS and Mac projects. The Clean Swift Architecture is not a framework. It is a set of Xcode templates to generate the Clean Architecture components for you. That means you have the freedom to modify the templates to suit your needs.
In an MVC project, your code is organized around and grouped by models, views, and controllers. In Clean Swift, your project structure is built around scenes (or screens). Here is an example how does one scene looks like. In other words, we will have a set of components for each scene that will “work” for our controller. These are the components:
The latest and the greatest of the MV(X) kind
The MVVM is the newest of MV(X) kind thus, let’s hope it emerged taking into account problems MV(X) was facing previously.
In theory the Model-View-ViewModel looks very good. The View and the Model are already familiar to us, but also the Mediator, represented as the View Model.
- 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.
What is View Model responsible for?
- View Model stands between the Model and the View Controller, and provide the data that a view controller needs to display in it’s views.
- View Controller NO longer access the model directly.
- If the model has a NSDate, then the VM will have the NSDateFormatter that knows how to display the date as a string for the view.
- A View Model does not know about the view.
- It does not know stuff about presentation, but it does provide the data for presenting.
- Note that is “data” for presenting is not the actual model, but a intermediary object.
What is grey?
- Networking call is a grey area. Neither VM nor VC defines where the network logic should go.
- But it is safer to be in VM. Or use another composition pattern with a network object.
How different is MVVM and MVC
- It is actually not much different.
- The introduction of a View Model simply extract the business/app logics out of a View Controller.
- It uses a composition pattern, so a VC now will have a VM. In doing so, you can now write tests for the VM (which has the important business logics).
- How View Model (VM) communicates with View Controller (VC)?
- Remember, VM does not know anything about the VC.
- Just like VC does not know anything about the model.
- VM and VC can communicate via delegates or Functional Reactive Programming (FRP).
- You would have have know delegate pattern, which is widely used in Apple’s frameworks.
Login View Model (View Model)
The MVVM is very attractive, since it combines benefits of the aforementioned approaches, and, in addition, it doesn’t require extra code for the View updates due to the bindings on the View side. Nevertheless, testability is still on a good level.
ii)VIPER(View Interactor Presenter Entity Router)
VIPER is our last candidate, which is particularly interesting because it doesn’t come from the MV(X) category.
By now, you must agree that the granularity in responsibilities is very good. VIPER makes another iteration on the idea of separating responsibilities, and this time we have five layers.
- 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 code blocks supposed to be? — It’s up to you.
If we compare it with the MV(X) kind, we’ll see a few differences of the distribution of responsibilities:
- Model (data interaction) logic shifted into the Interactor with the Entities as dumb data structures.
- Only the UI representation duties of the Controller/Presenter/ViewModel moved into the Presenter, but not the data altering capabilities.
- VIPER is the first pattern which explicitly addresses navigation responsibility, which is supposed to be resolved by the
Yet again, back to the features:
- Distribution — undoubtedly, VIPER is a champion in distribution of responsibilities.
- Testability —no surprises here, better distribution — better testability.
- Easy 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.
Coding Structure of VIPER
How Router work with Appdelegate
Maybe, it’s too early to adopt VIPER for your application and you should consider something simpler. Some people ignore this and continue shooting out of cannon into sparrows. I assume they believe that their apps will benefit from VIPER at least in the future, even if now the maintenance cost is unreasonably high.
I know that for most people MVC is the comfort zone, but once you get out of it and try something new you will be amazed by the results. Clean Swift based architectures contains a bit more coding and few more files than MVC, but that makes it super easy for maintenance and writing test cases.