Mobile App Architecture in Simple Terms
Choosing a proper mobile application architecture has always been a subject of long discussions and many presentations given on developers’ conferences around the world. If I were to indicate one topic that for the past seven years appeared on pretty much every event I attended, that would be it—endless discussions about the pros and cons of certain approaches to design app structure.
So what is all the fuss about? Why can’t we agree on a single, right solution? The simple answer is, as you may expect, it all depends on the app itself and the team building it. All of the most popular mobile app architectures have something different to offer. The choice between them should be made before the development process begins. Take your time to think through the whole process carefully. It will result in an easier and faster development and maintenance of your application.
The most significant factor affecting the choice of mobile app architecture is the technology used to create your app. Some frameworks or programming languages strongly imply using a particular architecture model.
Another important factor is the business domain of the app. You need to consider if the app is heavily data-driven, requires a lot of user input, or if it is fairly simple and only presents some predefined content in a nice way.
Lastly, you need to consider the size of the app and the scalability that might be needed in the future.
The MVC architectural pattern is well known to everyone who ever tried to write an app for iOS. It is still recommended and used in code samples by Apple. Also, most Android sample codes were written according to the MVC pattern, but recent trends move to different mobile application architectures. Although it is still popular, it is often misused, which leads to some structural problems. Let’s have a closer look at this concept. There are three main parts of this architecture: model, view, and controller.
- Model - contains all data structures, objects representing data, persistent layers, data managing classes, networking code, any kind of helpers, etc.
- View - represents everything visible as user interface, usually view objects do not contain any complicated logic.
- Controller - these objects manage views using data from the model using a delegation pattern. It means that the controller implements a view’s methods through which data is passed to particular view objects. On the other hand, it lets the view to manipulate the data in the model indirectly.
All three components should be independent and focus on their designated tasks. Typical mistakes made here are:
- putting business logic into views (for example, view configures itself based on an object from the model)—views should be independent of business logic and reusable, they should only do things related to UI and be configured by the controller;
- big controllers responsible for too many tasks—more efficient solution is usually to embed one controller into another and split the tasks between them;
- controllers doing data manipulation or network requests—this should be a model’s job.
So what are the pros of MVC architecture? The most important one is its simplicity. Clear division of our app into three separate components makes everything straight forward and easy to design if the application is relatively small or midsize. The model is easy to test since it is usually well separated from the UI part. There is not much left to test in views in terms of unit testing.
The disadvantage of this architecture is the relatively tight coupling between controllers and views. If views change, controllers need to adjust. In complex applications, controllers tend to get big and complicated, so it may pose a challenge.
To sum up, the MVC is suitable for both iOS and Android applications. It is not commonly used in React Native or Flutter. It works best for smaller apps, and it is quite easy to learn and apply properly because of its simplicity. Some call MVC architecture dead, but I think it is still a great approach in many cases.
The MVP architecture can solve some problems encountered in the MVC. It is an acronym for Model, View, Presenter. The model has the same role and is almost identical to the one in MVC. The biggest difference is the views—they are more complex than in MVC. They are capable of knowing something about business logic and specific model data structures. A bit more complicated view is the cost of a simplified presenter that exchanges the controller. The presenter is not as strictly coupled with the view as before. This approach increases the testability and flexibility of a presenter. In the ideal world, it should be almost platform-independent and do not use a specific platform’s APIs.
Usually, the presenter asks the view to configure itself based on data from the model. So instead of telling it how to display data, it only says what to display. Views should implement some common interfaces so that a single controller can work with many views.
The common mistake is to put too much business logic into presenters. Using base presenters and inheriting from them can partially solve this problem and increase reusability.
The MVP approach is considered to be much cleaner than MVC, mainly because of the testability and reusability of presenters. Similarly to MVC, it is widely used in iOS and Android apps. It seems to work well with bigger and more complex apps and has better maintainability.
The second variation of MVC architecture is MVVM—Model, View, ViewModel. It offers even better testability and modularity than previously presented mobile application architectures. Again, the model stays the same as in MVC and MVP. ViewModel takes the role of a controller or presenter. As in the previous examples, ViewModel is responsible for binding a view to a model. The difference is that it lets the model and view to communicate directly with each other. It does not control the view. Its role is to prepare or transform the data from the model into something that can be displayed by the view.
It looks similar to MVC, but we have to remember that technically, the controllers are still present. View models are an addition that simplifies standard controllers and minimizes their role. Most of the heavy lifting is taken out of controllers, which makes them easy to test.
Another advantage of the MVVM pattern is that View models are not tied to a specific view. Usually, views bind to observable variables and actions exposed by ViewModels. ViewModels should also provide some interface for the views to pass events to the model. Again, this is perfect for testing because there is no need to mock out the view.
This architectural pattern works great in iOS and Android. The only disadvantage that I can think of is its more significant complexity, which makes it an overkill for simpler apps. I am not a fan of reactive programming on iOS and Android, which is partially implied in MVVM, because of the difficulties in debugging it. Sometimes, depending on used technology and third-party libraries, it introduces some performance drops and higher memory usage.
At the beginning of this article, I mentioned React Native and Flutter as popular platforms, but I have not indicated any good mobile app architecture used in these technologies yet. Although it is technically possible to use MVC and its derivatives in RN or Flutter, it seems to be neither a popular nor optimal solution.
React Native has been around since 2013, so various architectures have been used in apps created using this technology. However, most of them are based on the same principle. Data flow in these apps is unidirectional and performed using actions or events. Multiple elements of the app can emit them. Then there are components looking for those actions and modifying the application’s state. Other bits, like UI components, register on-state changes and adjust themselves accordingly.
The two most popular mobile app architectures based on this principle are Flux and Redux. Flux was first introduced by Facebook. Later the library implementing the idea of Flux, but slightly changed, was developed and called Redux. It became widespread, and currently, in my opinion, it’s the most popular one when it comes to designing React Native apps. Let’s have a look at some of its key elements.
Redux architecture in RN consists of Views, Actions, Reducers, and Store. As stated before, there is a single Store for the whole app. Multiple views displaying the user interface should be able to react to events like button touches and emit actions. Functions, called reducers, get all emitted actions but usually react only to some of them and modify the state. Views react to the state changes and adjust to them. The advantage of this approach is that we do not have to manually pass actions between objects and having a single state, assuring that all views get properly updated at the same time.
Redux library is available in Dart language as well, so it can be used in Flutter. However, recently the BLoC architecture, presented in 2018, has become more popular and is slowly taking over the “architecture market” amongst Flutter developers, so I decided to have a more in-depth look at it.
Another characteristic of BLoC is that most UI components are directly accessible. This works the other way as well—BloC components can be provided to any UI Component which wants to send some data or event. This, in my opinion, is somewhat similar to Redux and really convenient. Moreover, it is also possible to use this architecture with ReactNative.
So what are the pros and cons of Redux and BLoC architectures? Redux, with its single store and reducers, makes the transitions from one state to another predictable and easily testable. This can be a disadvantage in bigger applications where our store becomes simply huge. It sometimes results in many switch statements in reducers. But my experience shows that it can be overcome with clever implementation and division of the whole redux structure into multiple files.
BLoC architecture also lets us easily test and debug business logic as it is completely enclosed in BLoC components. Additionally, those components are reusable and can sometimes be directly transferred to another app or platform which uses the same programming language. One of the cons of BLoC is that it is not always easy to follow the right path and understand the whole idea of BLoC. As it is still a fairly new concept, the documentation could still be improved, but I believe that in the hands of an experienced developer, this is a pretty powerful pattern.
The conclusion that can be drawn from this short analysis is that there is no perfect solution that would work for all cases. When I choose the architecture for applications I build, I look at the technology that was selected (not necessarily by me) and take into account my personal preference. The latter is especially important as it makes working on the app more convenient and usually faster than in the situation when we are forced to follow a pattern that we do not like or fully understand.
If you have a mobile project in mind, don’t hesitate to contact us!
Senior Software Engineer