Kotlin Multiplatform MVI

Petru Alexandru Mocanu
Norigin Media Tech Blog
4 min readSep 10, 2019

another way of building a product based on a common code base

Photo by Sean Stratton on Unsplash

Overview

Let’s consider making a product for the main platforms like Web, Android and iOS, how could we do it?

  • implement it native on each platform, Web (JS — React), Android (Kotlin — native UI) and iOS(Swift — native UI)
  • use some cross-platform development, the most popular being React Native (JS), the newly Flutter (Dart) and Xamarin (C#)
  • use Kotlin multi-platform development for the common code and leave the UI related implementation to be done natively on each platform

Without getting into details and debates, in my opinion, the best quality is given by the native implementation on each platform, however there is more development needed. And for cross-platform there is a development saving at the beginning, while at the end the product will have less performance and be more limited in terms of the UI.

Kotlin Multiplatform

How about Kotlin multiplatform? It saves time by using some common code base and by doing the UI natively it keeps the performance and flexibility. From this perspective it looks quite tempting to check it out.

MVI

Next to consider is the architectural choice, the main goal is to have most of the code common and also the flexibility to make it work on all the platforms. The unidirectional data flow, separation of concerns and pure functions of MVI principles made the choice. Going forward with Model-View-Intent, I set a goal to have the models and intents fully multiplatform and the views natively.

Kotlin multiplatform MVI

How about implementing Kotlin multiplatform with a MVI architecture? The implementation is split into 3 modules Data Layer and UDF as a Kotlin shared code and the Application as a Kotlin Android code.

Data Layer

Having the models in Kotlin is extremely simple, with data classes and serialization being added in Kotlin 1.3

How to get data from the server? I am a fan of Retrofit with RxJava, however this doesn’t fit in the multiplatform shared code, so the obvious choice is rather the common of Ktor and Coroutines.

For caching the result I spent some time trying to find a library doing the job for all the platforms but unfortunately I wasn’t able to find any. Eventually I picked a library for Android (layercache) to be more flexible in order to provide a native implementation for each platform (one of the cool flexible feature of Kotlin multiplatform)

And for testing it I added some functional tests.

All this, being put together into the nice Repository pattern, I got the Data Layer having the common code in place, with network api, models, a caching interface and functional tests.

UDF

In this component I added the actual implementation of the MVI. I was checking some existing libraries, however they were not made for multiplatform development, so I ended up implementing my own.

The MVI implementation is based on the Redux principles:

  • single source of truth, one store and one state tree object
  • immutability, read only state
  • separation of concerns, view is not relevant for the the udf
  • pure functions, making unit testing easy

I have implemented:

  • State, a single tree state of the entire app
  • Actions, doing a single operation on the state
  • Reducers, applying the action on the state
  • Store, linking the state, action and reducer
  • Middleware, linking the repository functions from the data layer with the MVI

Application

The application ended up being very simple, handling just the UI part, having mainly:

  • Viewmodels, linking the UDF with the app via Livedata
  • Koin for the data injection
  • data binding
  • the actual implementation of the cache using the layercache at the base

The next steps when the application grows would be extract and reuse the UI components.

What have we got

  • Data Layer — based on repository pattern, having network api, models, a caching interface and functional tests. Done in Kotlin Multiplatform
  • UDF — based on MVI, having state, actions, reducers, store, middleware. Done in Kotlin Multiplatform
  • Application — using livedata to link the udf with the views. Done in Kotlin for Android

The Data Layer and UDF are Kotlin multiplatform, they can be used as well in Web and iOS after re-writing the application on each platform natively.

Where is the code?

https://github.com/petrumo/KotlinMultiplatformMVI

Main takeaways

First and the most important thing to keep in mind is that Kotlin Multiplatform is an experimental feature meaning

  • there are still some environment bugs, and plenty which were fixed in the last months
  • Android Studio is not fully there with the multiplatform projects setup
  • I would like to use a dedicated multiplatform caching library
  • I had to go the extra mile to put the things together

And looking into the bright side :)

  • going with Kotlin Android application forward it can be a good setup to already make it in multiplatform MVI and with the next future Kotlin releases to start using it for the iOS and Web
  • the multiplatform feature will get better integrated in the next Kotlin versions
  • there are plenty of libraries that are being developed in Kotlin with the multiplatform idea in mind

References

--

--