Nuvalence October 13, 2021
Written by: Brian Gardner & David Gethers
We recently worked with a client, tasked with investigating ways to develop and deliver new features to a mobile application platform with greater speed and stability. Based on the research of the team, we settled on building a Server Driven User Interface (SDUI) – based platform. The SDUI approach has been pioneered by Airbnb, Lyft, and Primephonic and seemed like a very good candidate to explore. (1)
What is Server Driven UI?
Traditional APIs serialize data in some format (typically JSON). These APIs provide data to a client, which then consumes and renders that data in whatever way it sees fit. An example of this might be a list of cities, like shown below;
Any client given this data needs to know what to do with it. For instance, the client must be aware of each field name it wants to render. It also needs to know what to do with the id provided, if it needs to interact with that individual record. This increases the coupling between the client and the server. In a mobile application, this can mean more frequent releases to an app store. This can be troublesome for several reasons.
It increases the burden on your customers to update frequently
It increases the number of concurrent versions of applications you need to support
There are no guarantees that the app store testing and release process will happen in the timeframe that your business needs it.
SDUI still relies on standard serialized formats (such as JSON). However, instead of just rendering the data, SDUI provides directives on how the data should be presented as well as the data. This is done through a shared language of layout components, similar to declarative UI frameworks provided by Jetpack Compose or Flutter, such as the example below:
For this project, we chose to use Kotlin with Spring Boot to build our API, and Flutter to build the UI. Kotlin’s syntax allowed us to quickly and easily build a Domain Specific Language (DSL) to describe our components in the API. Flutter also gave us a number of benefits. In addition to being able to build both iOS and Android naitive applications, it also gave us hot reloads, a rich environment of declarative UI components, and an easy language (Dart) to work in.
After building and working with SDUI for several weeks, the team is far from knowing all the advantages and drawbacks of the approach. But we do think that it shows a lot of promise, in certain situations.
An SDUI-based approach does keep the client side code simpler. Instead of building an application, the client becomes more of a generic rendering engine. Over time, this should mean fewer app store releases to fix bugs, etc.
It is also a more difficult way (at least initially) to build an application. Components have to be thought of in very generic, flexible ways. This can lead to a lot of refactoring, breaking API contract changes, and a few false starts. However, once past those hurdles, and the team starts getting the hang of some of the patterns, development time starts to accelerate. It’s definitely a flywheel effect.
SDUI works really well for imposing restrictions that allow for building consistent user experiences across different platforms (iOS, Android, web, etc). This seems to have served SDUI consumers like Airbnb and others well. It creates somewhat of a walled garden as far as their APIs are concerned. However, this opinionated approach also does not lend itself as well to 3rd party usage or integration. In those cases, a more traditional RESTful api may be more appropriate.
Key Learnings (so far…)
Versioning is important
We really didn’t dig into versioning the component schema. But we made a number of changes, additions, and deletions to our component schema. Versioning both that, and the API itself clearly would be beneficial for any production level application.
Along with versioning it is important to think about backward compatibility as you enrich the functionality of existing components. While trying to prove out SDUI, a mobile developer on the client Android team started integrating our changes to be rendered on the existing mobile architecture. As the SDUI team modified components being used by the Android team, we had to keep in the back of our heads to avoid breaking the previously consumed component implementation. Ensuring new fields were not mandatory and providing sensible defaults helped with this.
Don’t pass IDs
IDs are pretty useless by themselves to a front end application using SDUI. An ID by itself implies the client knows what to do with it, which is a form of coupling. It’s best to use URIs instead.
Easy things are hard at the start
Simple stateless components (text, icons, hero images, lists of things, etc) are quite easy in SDUI. However, more stateful interactions can be quite difficult. A simple button push described very generically from the server side, in a language independent way is non-trivial. Form entry with validation is even harder. Even more complex interactions (like text entry with typeahead) will probably involve building specialized components that are a superset of more basic building blocks. All of these interactions require careful planning. However, once those things are built in a generic way, it becomes very easy to re-use them.
Further Reading / Viewing
This is a collection of articles and videos that we’ve found helpful in our journey towards building an SDUI platform
KotlinConf 2019: Lona: Scaling Server-driven UI by Laura Kelly & Nathanael Silverman
Rapidly Iterating Across Platforms Using Server-Driven UI – Laura Kelly