The future of apps:
Declarative UIs with Kotlin MultiPlatform (D-KMP) — Part 1/3
A 3-part article explaining the new D-KMP architecture, based on DeclarativeUIs, Kotlin MultiPlatform and MVI pattern.
Latest Update: May 18, 2021
Year 2020 has not only been the year of the pandemic, but also the year which set the division between The Past and The Future in apps development.
The Future will already start in 2021 and it will be about DeclarativeUIs and MultiPlatform, changing forever the way apps are architected and implemented. It will become normal to build apps for all platforms, which share 85% of the code and have the latest native UI/UX. Development productivity will massively improve, and apps quality too!
In this article we’ll go through the main concepts, also how everything is coming together nicely.
The “past” is what app development has been until now, where most companies have built separate apps for each platform (Android, iOS, Web), with no shared code on the client-side.
In order to limit the amount of code being replicated for each platform, most apps tend to be “thin client”, delegating most business logic and data processing to the only part that is really shared: the webservices.
In this way, webservices tend to be “UI-oriented”. Architectures are designed in a way that most clicks trigger an API call, which provides the exact information to be displayed on the next view, with very limited client-side logic.
Any extra client-side logic requires a replication of the same code on each platform, so this is something that is typically avoided, unless it brings a meaningful benefit for the user experience.
In terms of client-side shared code, there have been several companies that attempted some strategies in these years, but for the most part it’s a history of failures, with many reverting back to native-only/platform-specific development. There are famous examples such as DropBox (moving away from shared C++ code) or AirBnB (moving away from ReactNative). In other words, there haven’t been suitable technologies to allow companies to make a safe long-term investment in shared code.
In this 2020, we are experiencing the rise of two important paradigms, which are happening in parallel: Declarative UIs and Kotlin MultiPlatform. This will bring opportunities never seen before, and it will make “Multi-Platform” and client-side shared code the preferred choice for apps development.
DeclarativeUIs fit perfectly in a multi-platform architecture, because they are stateless and can be fully decoupled from the business logic. By combining Declarative UIs with Kotlin MultiPlatform, we can safely architect apps with a huge amount of client-side shared code (up to 85%), performing as perfectly-native on each platform. At the same time we can have the latest native UI/UX on each platform.
Webservices can now be fully “UI-agnostic” and focus on providing the data in the most normalized way, removing any redundancy, as all data processing and formatting can be done at client level. This can also greatly improve data consumption.
But let’s go on with order. Let’s start by defining what are the pillars for the upcoming era of apps development.
The 3 pillars for the future of apps
- Declarative UIs (JetpackCompose on Android, SwiftUI on iOS)
- KMP (Kotlin MultiPlatform)
- MVI pattern (Model-View-Intent)
We call this architecture D-KMP, standing for DeclarativeUIs with Kotlin MultiPlatform. The MVI pattern is what makes the two work best together.
The D-KMP architecture
It’s important to clarify that the D-KMP architecture we are presenting is aimed at greenfield projects.
We are not talking about how to gradually introduce Declarative UIs and Kotlin MultiPlatform to an existing project.
Our goal is a clean, solid, and future-proof architecture, which doesn’t make compromises with the past, and it builds on the most innovative technologies and paradigms.
It’s also important to highlight that D-KMP is not a library, but an architecture, fully relying on the official frameworks.
Let’s now go in more detail about each of the 3 pillars of the architecture, starting with the DeclarativeUIs.
Declarative UIs have landed on Android and iOS!
After over a decade, we are experiencing the most important revolution for the mobile frameworks. Both Android and iOS have started to ship their new UI toolkits, which are both declarative, taking inspiration from the paradigms of React and Flutter. They are going to fully replace the current way of defining views in both operating systems.
Google announced JetpackCompose at Google I/O 2019. It entered Alpha stage in August 2020. It is expected to reach Beta in spring 2021, and version 1.0 by the end of 2021.
JetpackCompose is supported by any device with Android 5 and later (target API 21). This means that any new JetpackCompose API will be backward compatible, and won’t require the new Android version. This is because JetpackCompose operates low level, by drawing directly on the Android view canvas.
Apple announced SwiftUI at WWDC 2019, which was already shipped in 2019 with iOS13. There were further improvements this year with the iOS14 release.
Unlike JetpackCompose, SwiftUI is tied to the iOS framework for updates. New SwiftUI APIs will not be backward compatible. However, considering that all devices supporting iOS13 are also supporting iOS14 (unusually, Apple didn’t deprecate any device this year), we can safely target iOS14 for apps using SwiftUI.
Why declarative UIs?
JetpackCompose and SwiftUI are both Declarative UI frameworks, which means they are just describing how the UI should look like for the different states, without managing the state directly. The Declarative UI paradigm have become popular thanks to frameworks like React.js and Flutter, which have shown how simpler it is to interact with stateless components. Their success has eventually pushed both Android and iOS to join the Declarative UI world!
With JetpackCompose, you can forget about the cumbersome Android view-based system with the dreadful Fragments. And with SwiftUI, you can forget about the UIKit ViewControllers and the inflexible Storyboard. It’s a clean start. It’s the Future!
The nature of Declarative UIs allows a very neat separation between the UI Layout and the ViewModel, as no extra layer of code (using findViewById and @IBOutlet) is needed to connect the two. On this topic, Leland Richardson by Google wrote an interesting article, explaining the importance of maximum cohesion and minimum coupling.
JetpackCompose and SwiftUI are very much alike. There are trivial differences about the syntax (JetpackCompose uses Kotlin, SwiftUI uses Swift) and the navigation patterns, but the concept behind is exactly the same. And above all, the data to be fed into these two stateless UI frameworks is exactly the same. Because of this, it makes a lot of sense for a ViewModel to be platform-independent! We’ll talk more in detail about this further on.
DeclarativeUI for Web
JetBrains and Google are now working on a Compose version for the Web. Recently a technology preview of Compose for Web has been made publicly available. It is based on the DOM, and it is expected to grow very quickly in the next months.
DeclarativeUI for Desktop
In the meantime, JetBrains has already released Compose for Desktop, which is now in Alpha. It allows the development of desktop apps for Windows, macOs and Linux.
In terms of desktop, SwiftUI already supports macOS out of the box. Any UI you write with SwiftUI adapts (with minor changes) to iOS, macOS, tvOS, watchOS.
It’s easy to envision a near future where Compose and SwiftUI will be the only 2 UI frameworks you need to be able to write first-class apps on any platform.
Will Compose eventually support iOS too?
This is a very popular question. I believe it will eventually, mainly thanks to the big community behind Compose. However SwiftUI will easily remain the preferred way to write the UI of an iOS app.
But it’s a good thing. Having two strong and independent toolkits (Compose and SwiftUI), competing for innovation, is very healthy for the future of UI/UX.
Let’s now focus more on Kotlin MultiPlatform:
go to the Part 2 of this article!