Design patterns have always helped in building a manageable, testable, reusable and optimized software. Generally, it helps in modularizing the software such that each component is separate and handles a single responsibility. Additionally, they drastically improve the readability of the code which plays a big role in communicating the software code. Also, the software development process drastically speeds up with the already proven design paradigms. Mobile developers are no way away from educing the benefits of following the design patterns. Initially, mobile applications were too small to follow the design or architectural patterns and hence they used to strictly stick to the most basic ones. Nowadays, since the mobile applications are getting bigger and almost mirrors(functionality wise) to their desktop or web counter-parts and hence they necessitate to consider the design patterns before they actually go into the development mode.
Lately, I have been in the quirk of attending the iOS and Swift dev conferences, either in person or on the web. Every other such conference has at least two to three talks on the emerging or accepted design patterns especially considering the mobile applications. The mobile platform like iOS has already recommended developers to follow MVC (Model-View-Controller) in their apps. Apple’s MVC is the modified version of the original MVC, to go well with the mobile application, but the developer community feels otherwise. Hence, the developer community has been trying out different design patterns which are already practiced in other software development platforms. We will be seeing such design patterns which are widely accepted by the community as well as the transition is pretty successful too. Like all other design patterns, these, too, won’t fit best in all the scenarios. Each has some pros and cons and it’s totally our responsibility to choose one of them wisely for the case. If none of the available work for you, developers could help you generate a new one as per your need.
We will be covering some of the most popular ones in iOS developer community, MVC, MVP, MVVM and VIPER. This post would be a two-part series.
Let’s start with the simplest and the most used one. Apple has, through its sample codes, always recommended to follow MVC. As mentioned earlier, the Apple form of MVC is modified a bit to better adapt to the mobile applications. General form of it is represented as follows –
It basically composed of a View, a Controller and a Model. The view can be imagined as the user interface shown to the user at some particular point in time. Model is the data to be shown in the View’s components. The controller is a bridge between them. These three, always maintain a relationship. Controller owns a View and associates a Model with it.
The view has a responsibility to show its user interface to the user. Eventually, the view passes the actions originated from the user interface to the Controller. The actions are either user-initiated, for example, the user may tap on a button present on the screen to initiate an action, or sometimes automatically generated, for example, the screen may need to refresh its contents on a timely basis. Controller’s responsibility is mainly to receive these actions from the View and act on them. Controller, while processing, may update the Model. Sometimes this update process takes a while. The Model notifies the Controller when it completes its update process, upon which the View gets notified by the Controller to update its user interface with the updated data. View and Model never talk to each other directly. They communicate via Controller. This is the only difference that Apple’s MVC possesses as compared to the original MVC, shown below.
Apple might have thought to not to tightly bind the View to the Model just because of the fact that the views in the mobile applications can be highly reused. If the tight coupling had been kept, we would have need to re-implement the views every time for the different model. A model-independent view is an actual idea behind Apple’s MVC.
Simple enough, right? But this simplicity of MVC brings in some problems and difficulties. These problems were not faced until mobile applications were shorter and simpler. But now, when iOS devices are more powerful than the desktops, users expect the mobile applications to be powerful enough to fully utilize the device resources. More expectations lead to the bigger app which generally integrates multiple components which in-turn lead to the bigger codebase. Such bigger codebases with multiple components can be managed well if each component is given a limited responsibility.
Firstly, the problem that MVC causes is, it fails to follow the single responsibility paradigm and resultantly causes MVC. What? MVC causes MVC? Yes, MVC (Model-View-Controller) causes MVC (Massive View Controllers). According to MVC, Controller is the mediator between the View and the Model. This forces controller to handle numerous responsibilities. Modern user interfaces are designed in such a way that a single screen provides certain features of the application. A single screen(view) is then composed of multiple functional subviews for which the screen’s controller needs to integrate with several different complicated modules. Managing multiple functional subviews and integrating with different modules is a lot of responsibility given to the controller. The controller, in this case, will manage View’s lifecycle, handle user actions, which, in client-server based application, may need to make a server call, handle the response, handle errors, run screen refresh timers, handle multiple callbacks, listen to the notifications, handle view’s orientation and so on. This makes controller’s code bigger. Apparently, the code becomes very difficult to manage and understand. This problem is slightly solved when the concept of child controllers was introduced in iOS.
Secondly, MVC makes it difficult to test the unit test cases. Due to Controller-View direct relationship, developers need to tweak and play around in such a way that only the business logic is executed to generate a valid test case result.
MVC still works well in many cases where the user interface is simpler and controller needs to handle less responsibility but it fails miserably for complex user interfaces.
MVP is just an extension of the Apple’s MVC where the view controller’s responsibility is distributed between View and Presenter. It does treat a controller as a view. The View keeps UI handling responsibility whereas Presenter deals with the actual business logic (update model and other things). This way the unit testing is easier since all the unit test cases are written over the Presenter where the view related handling is not available. In a way, it is beneficial over Apple’s MVC, it distributes the responsibility well and testing the unit test cases is less tedious work. It reduces the speed of development though since implementing Presenter and bind it across the layers brings in some additional work.
MVVM (Model-View-View Model)
This is the latest pattern making a mark in modern applications. It was originally introduced by Microsoft in 2005 to make event-driven programming easier. Mobile developer community discovered it to be beneficial for the mobile applications too. It came out to be suited for most of the challenges that MVC could cause.
MVVM asks to distribute the responsibility to View (view/view controller), Model and the View Model. Like MVP, MVVM, too, treats a view controller as a part of the view. We already know the responsibilities of the view and the Model from the MVP pattern. ViewModel is the new component here, responsible for the non-UI related handling. It may seem like the Presenter in MVP with regard to responsibility sharing. In MVP, view specific data creation logic stays with the view. The presenter just acts as a mediator between the view and the model and shares some responsibility with the view controller. Due to improper distribution, view controller still needs to handle a lot of responsibility in MVP. In MVVM though, a view model, as its name suggests, is the view specific representation of the model. View owns a view model which in turn owns a model. Hence, a typical flow in MVVM is, the view gets a data either from the server or from the database, gives it to the view model. View model then processes it and notifies back through binding. A small example of a view model’s data processing could be, a model may have a timestamp in millis but a view would want to represent that in a user-friendly manner. In this case, the view model would be responsible to convert the timestamp(millis) to the formatted date string. This formatted date string then used by the view to show to the user. View model keeps the representational data creation complexity with itself and thus, reduces the responsibility of the view(controller).
View Model shares the updates with the view through binding. If we talk about implementing binding in iOS, there is no native approach. We could still implement a similar mechanism through KVO, delegates or notifications. This does not work as efficiently as binding works in other programming languages. To achieve binding efficiently, developers have started chaining MVVM with the reactive approach( a better way to implement binding than through KVO or notifications). MVVM helps in distributing the responsibilities and reactive approach helps in binding the view model with the view.
Although the view model is tightly coupled with the view, we have managed to keep our view and model separate, which Apple’s MVC highly mandates. Furthermore, the separation of business logic (handled by view model) from the view controller makes unit testing easy.
MVVM does come with its own challenges. It gives a very high-level explanation of the distribution of the responsibilities. Since it was not originated keeping mobile applications in mind, mobile developers confab a lot about what to whom. One such debate would discuss on where does a networking related code belong? To view or to View Model? Original MVVM says it should belong to the view. In my opinion, it makes sense because the error scenarios can directly be handled by the view which can allow the view to display errors to the user or retry the action again. If a View model wants to keep the networking code to make it abstracted from the view, it needs to respond back to the view with the errors, in which case the extra layer of abstraction is added. At last, its developers control to decide and distribute the responsibilities as per their need.
Another challenge for the developers is that the reactive approach is quite complex. It does come with a learning curve and is prone to mistakes upon which developer may find a hard time to even spot the issue.
This seems to be a very good architectural pattern in theory and works well in practical scenarios too. This would not be the best choice for the simpler user interfaces.
I hope you find this post useful. In the final part of this blog post, I will be covering VIPER design pattern.