Adapting MVP for Mobile Platforms
Vectorform moved to integrate a universal architecture for our mobile team across both the iOS and Android platforms. It has changed how the entire team builds apps, estimates new work, and cross-trains across platforms. So, what did we do and why did we do it?
As the title gives away, we went with a modified Model-View-Presenter (MVP) architecture. MVP is a mature design pattern, and there are a ton of articles and information about what MVP is, so we’ll keep this discussion of its application to software architecture at a high level. The V stands for View, the part of the app that displays content to the user and sends events from user interactions up to the Presenter. The View is dumb and doesn’t know how to do anything unless it involves drawing or animating. Within that display realm, the view can be as smart as it needs to be. The P stands for Presenter. The Presenter receives events from the View and issues orders to the View as it interacts with the application’s data layer. The M stands for Model. It houses all the data and network connections. In addition to these core components, we’ve adopted the concept of UseCases from Clean architecture, which allows our data layer calls and other logic to be reusable and bite-sized.
This architecture allows our Views to be devoid of business logic, our Presenters to contain (almost) all of the data and user event routing to be testable. Our data layer can exclusively focus on the fetching and modeling of data. It’s clean and straightforward. Many architectures exist that can do the same, so why did we go with this version of MVP? When we picked an architecture, we wanted to have something that worked well on both platforms. While Android pushes MVVM, and Apple has a long history with MVC, we didn’t feel that either approach would work that well on both platforms. Because MVP is close to MVC, we were able to adapt it rather quickly on iOS as well as Android. We have implemented a similar set of base classes and interfaces in Swift and Kotlin that allowed our mobile team to unify our approach to building native applications on both platforms.
Since Swift and Kotlin are similar languages, our engineers can rapidly learn how to work on Android and iOS. The fact that our in-house approach both share the same architecture and MVP design ideology makes it easy for our lead engineers to architect the protocols or interfaces for the more significant parts of a project across both platforms. One team can also reference implementation details from work that may already be done on the other platform. Our engineers can open a project across both platforms and easily find where a piece of functionality is implemented. As our developers gain facility across Android and iOS, when they need to add a feature, they are already thinking about how to do it on either platform. Engineers who previously only knew Android or iOS could quickly ramp up on the other. This is especially true for new hires. A vital part of our onboarding is teaching new developers how to work with our MVP architecture. Since almost all of our projects become examples of that architecture on both platforms, institutional knowledge is easily accessible.
Nothing is perfect, and there are still some bumps in the road, but having the team shift to where a project need exists is invaluable. Instead of hiring another Android dev, we can have our iOS devs become fully capable of writing on Android (and vice versa). Or, if we do need to hire the new Android dev, they can more easily shift to iOS in a few months when the Android project they were initially hired on for is completed.
By managing our own shared architecture, we can also make changes rapidly when either platform changes. A prominent example of this we recently completed was for the support of the ViewBinding changes in Kotlin that replaced the synthetic view capabilities that were initially supported. Since our View classes contained only view code, the transition was smooth and didn’t slow down other areas of application development.
The clean architecture features that we added after our initial switch to a common architecture to both platforms have also been a welcome addition that took care of a problem with our Presenters often having duplicated code logic across multiple screens. And since this is our internal work, we gain high-level flexibility that lets us add features and fix bugs in our base classes as soon as we need them. We aren’t stuck in a cycle waiting for a third-party fix or building in workarounds that may again break later. By continuing to invest in our own internal libraries, we’re able to evolve them at the pace we need, and we continue to explore adding new functionality to further make our codebase clearer for developers who will take on a project at a later date.
Our internal library will continue to evolve and take shape in whatever way best suits the team. We are exploring how changes to UI tool kits may impact our MVP library in the near future. As SwiftUI and Compose are coming out of their infancy, we can investigate new efficiencies to be gained. At the same time, we as a team now have the experience that helps bring native performance to separate code bases that are closely aligned.
Up next we’ll discuss the possibility of using Kotlin to drive parts of cross-platform mobile development. We’ll explore what new capabilities these and other platform changes may provide to help us streamline our work even more, and also whether or not these changes can be incorporated in a way that lets new developers quickly adapt to how we work as a unified mobile team.
In the meantime, contact us if you have questions or are interested in learning how we can help you integrate Kotlin into your projects!
Interested in learning more? Let’s start a conversation.