Designing the mobile application architecture
Over the years, mobile application developers have experimented with various standard architecture patterns like Model View Controller (MVC), Model View Presenter (MVP), Model View ViewModel (MVVM), and clean architecture et al. These patterns need improvisations to implement it for specific requirements of the mobile app. While designing the architecture, the first step is to identify and state the objectives. Below were the objectives identified by us:
In this blog series, we will discuss the architecture of Dream11 Android app, and future improvements that we plan to undertake:
Dream11 Android Architecture
Our philosophy is to design and maintain a Clean Architecture. We have segregated it in 4 layers, View, Presenter, Model and Services. We are using RxJava for data streaming, Dependency Injection for object accessing and DataBinding library to update the view and obtain events from the view. It is important to note that we are using data binding, but not the MVVM philosophy, where View Models are the most intelligent entities. For us, View models are just POJO classes which hold data for a view and obtain events from view.
Clean Architecture has guidelines for the object dependency (producer-consumer) and the code structure
Having a clean architecture means that the producer should not be dependent on the consumer, as in below diagram, where view layer is consuming the observables from the presenter and the presenter is consuming the observables from model layer and so on. In this case, producer layer objects can be created without the dependency on the consumer layer
We have written enterprise and application specific logic in the same layer to reduce communication between layers and centralise all decision making at one place.
View Layer: It comprises of Activities and Fragments. Each flow has one Activity and multiple Fragments for respective screens. For example, LoginActivity manages different screens (fragments) of login flow. This approach provides tremendous flexibility and ease. For instance, whenever we need to discontinue the flow, we can simply close the activity. We also use flow specific activities to trigger prerequisite execution.
Presenter Layer: It is an interface/adapter between view layer and the model layer. It has below responsibilities:-
It creates ViewModels using the data received from the feature layer and exports them to view layer through observables
It delegates the events of view layer to respective feature layer class
While mapping models to view models, it also adds view specific logic, if required
This is the most intelligent layer in our architecture. It contains the enterprise logic and the app logic (deciding the flow of an application). Below are some interesting characteristics of this layer:
Feature classes are segregated on the basis of business logic types:Since data sharing across different app components needs wiring code, we minimized the number of feature classes by using logic type and not screens like LoginFeature, PaymentFeature. As a result, the logic for all login related screens are handled by Login Feature. Similarly, the logic for all payment related screens is handled by PaymentFeature class, because same business components can share the data with relative ease.
Feature classes can communicate with each other through Request Message Pool, RMP is a special kind of event bus, we will discuss it in detail in the next blog
Own/Monitor the data: We have a single source of truth for data. But, instead of the single state container, it is fragmented in respective feature classes. For instance, the PaymentFeature class takes care of the Payment state of the app, so all the feature classes are a singleton, created using the Factory-Pattern.
Model Layer should be platform independent. This allows all the platform specific functions like making HTTP calls, a message read permission, log in through Facebook and Google, saving or retrieving values from database to be written at the service layer.
Some Android SDK APIs seeks message read permissions while the others (Facebook, etc.) need an instance of the activity. Clean architecture principles do not permit access to the platform object instance in enterprise or app specific code. Additionally, we cannot put them in the view layer because a producer cannot depend on its consumer objects.
To solve this problem, we created UIListener interface. Here, the object is being passed to the service layer class, which provides current activity and application object to service classes.
Things to be improved: