Since 2010, I've been developing Mobile Apps, for both Android and iOS platforms. For most of these six years I've been essentially struggling to find the best approach when starting to each project I'm in. It's been a hard and rocky road, each time trying to take my past experiences and turn them into lessons learned on how to make things better.
There are some highly discussed and robust architectural design patterns available for developers to take into account when building applications. I'll just refer to the most common (MVC, MVP and MVVM), because these are pretty much the most used and they tend to be coupled to the technologies/frameworks you use and the platforms you target. I don't want to get into details about them, because that is not the focus of this article, you can get more information on them in Albert Zuurbier's MVC vs MVP vs MVVM.
MVC, MVP, MVVM
For the purpose of keeping this clean, let's just take this into account:
MVC - The most commonly used and most basic mobile app development design pattern (android and iOS). It's actually more M-VC as you tend to have a lot of coupled code that does pretty much everything on the app all in a few layers.
I'm thinking about Android's old Activities
and Async-tasks way of coding, and the iOS Data layers and massive ViewController
s that did all the work of business and user interface logic.
MVP - The commonly used pattern for web applications that some developers tried hard (and with some degree of success) to bring the mobile platforms that work on layering the code in order to achieve some separation of duty and create cleaner code. Though it does offer some more layering abstraction, it still lacks in keeping each layer more focused on a single task. I wasn't able to decide precisely where to keep the business logic.
MVVM - Microsoft's Presentation Foundation made this way of structuring code famous, and was brought to the mobile platforms layering the code even more, introducing the ViewModel
, which is essentially transfer data, thus removing some dependencies between layers. Yet it presents the same problem as the MVP, lacking focus on separation of concerns and clean data transfer modeling.
A side note to the emerging Functional Reactive Programming, I really don't know a lot about it yet, but it's next in my "Study and Fooling around experiments" bucket list.
Searching for inspiration
For my last project started from scratch, I wanted straight upfront to structure things well. I was about to go on with a 6+ months project, and I didn't want to have my shortcomings of the past to come back and haunt me. After a lot of digging, I came up to an article about Clean Application development and eventually went about digging even more to learn all I could about this interesting point of view. After reading these two posts I was sold, I wanted to work with this.
My trip for knowledge started with Raymond Law's article and setup tools for a clean architecture for Swift and led me to the core of the idea from Robert Martin (Uncle Bob). Bob extensively explains in an abstract way his approach to solving the code hell that sometimes haunts us when developing through ad-hoc methodologies, introducing simple layered software as the answer. Each layer is separated using well-defined models for data transfer and interfaces to communicate, while containing and separating functionality.
A new architecture
Eventually and through a lot of idea sharing and discussing with my team mates we came up with a nice clean structure for our code that could be applied for both the Android and iOS versions of the app. This was the resulting abstract architecture.
I omit the worker classes that actually call managers and services and manage all the background/main thread switching. This will be the subject to another article if people find it interesting enough to do so and request for more information about it.
We did stray away from the architecture's principles by applying the common business layer and data layer as separate classes storing the entire core. We later found out this was not a wise choice, but we were young and wild, and didn't know the problems we would eventually have by not keeping the modular approach. Having multiple developers working in related screens in parallel potentiated this... Fortunately we practice Code Review and were able to mitigate some of the consequences, but we did spend a lot of time merging code that was duplicated by wrongfully dividing tasks and not going with the modular approach.
We have implemented the apps so that each of the Screens implements the VIP cycle (View, Interactor, Presenter) as a scene, keeping it as logic free as possible. We avoided circular dependencies to keep memory leaks to the minimum (this was specially important to the Android platform), so View, Interactor and Presenter only had forward references to the next step in the cycle. Let's take a closer look at how we implemented this.
- So the View is actually really dumb. All it does is display information for a specific view model and react to user's input forwarding it to the Interactor as actions wrapping the data in requests passed as parameters.
- The Interactor is the tough guy in charge of dispatching work to the Processes. Also, he is actually the orchestrator of the work being processed. The Processes keep state and take care of all the logic, but the Interactor has enough knowledge of the business to know which processes to use and how to manage the flow of information and actions between them. Let's take for example a case where we have to fire calls to webservices in parallel or even use the result from one call in the other as input, the Interactor is the one who manages this kind of workflow.
- The Presenter is kind of a translation layer, where the Interactor sends some information he got from the workflow result and asks the Presenter to display it to the user. For this, the Presenter remodels the information to the essential in order to display in the View., The Presenter then instructs the View to update as a whole (or as AJAX style, updating just small portions of the view).
I know it was a really long post to get to some really small conclusions, but I wanted to give a little background as for why I thought sharing this was important. We have already iterated over this architecture a couple of times (started 2 or 3 smaller projects since then), and although we did make a few changes (as I mentioned before, we brought back the modularity, making the business processes smaller and more contained to fewer functionalities), we are keeping this as our cheat sheet on how to properly structure the apps. Or at least until we come up with a better way... The next best architecture.