A Journey of Discovery: Using Server-Driven UI to Power the Wattpad Homepage
The homepage serves as Wattpad’s primary means of enabling our users to passively discover new content or information. In early 2019, we set out to completely redevelop the technology powering our home experiences across backend, mobile, and web in order to enable a system that allowed for rapid iteration and experimentation. This series of blog posts aims to describe some of the core philosophies that drove this project, with this post focusing on the concept of “Server-Driven UI”.
The homepage is one of the most viewed pages in our client-side experiences (i.e. mobile and web) and therefore must carefully balance content discovery, merchandising, and marketing objectives. Each of these areas requires us to be able to support rapidly updating the information being presented to users as our data scientists test new discovery algorithms, new marketing campaigns roll out, et cetera.
The existing APIs powering home followed a traditional setup in which they solely provided the groups of information (“modules”) that were to be presented to users. It was then up to the clients to interpret this response and determine how it was to be presented to users. Though we were not frequently changing the UIs on home, this setup meant that we were still required to individually make changes on each frontend platform in order to ship new modules. As a result, we were collectively tied to the constraints of each client, making it such that the slowest client (in terms of iteration speed) was able to determine the timelines of any new changes being rolled out on home.
Enter Server-Driven UI
Server-Driven UI is a concept in which the server API provides instructions on the UI components that should be shown on clients, along with the information needed to populate them. At its core, it is a move away from an API solely providing data while leaving all UI logic up to the interpretation of the client. This allows clients to only have to ship a set of supported UI components that the server can then use to render a page.
As an example, given the following UI:
While a traditional API response may provide data on each of the stories being shown:
A server-driven UI approach would abstract away the data in favour of only providing information on the UI-component that needs to be shown:
By introducing server-driven UI to the home experience, we solved several challenges:
- Enabling consistency of experience across clients as each would now be guaranteed to be displaying the same information.
- Reducing duplication of work as most iterations on home would only require server changes.
- Removing dependencies on App and Play Store release timelines.
In order to support server-driven UI, the home API accepts a set of client information (e.g. app version, display language, etc) and uses this to build and return a list of supported “sections”. Each section is given a different
type, which allows for the client to map it to the matching component in the UI layer:
Mapping Sections to UI Components on Android
Our Android stack uses a combination of the Paging Library, Moshi, and Epoxy to build the home experience. We currently don’t make use of React Native in our app due primarily to performance and app size considerations.
For example, given the following section:
…we would create a
SmallNavigationSection data object on the client along with an appropriate UI component:
Once a PageKeyedDataSource has fetched the API response from the server, the type to class mapping included in
HomeSection#UiType is used by our parsing code to inflate the appropriate class using Moshi:
We then make use of an Epoxy Controller to map section objects to the relevant UI views:
Putting this all together gives us a flow that takes the API response and maps it to the UI that is shown to users. Note that all information regarding the placement and inflation of UI was provided by the server, with the client serving solely as a rendering layer.
Challenges and Next Steps
The introduction of server-driven UI massively increased our team’s velocity. We are now able to deploy A/B experiments across our user base, collect results, and introduce improvements all within the timeline it would previously have taken to make changes on each client and wait for their roll out to a large number of users. As a tangible example, we were able to quickly implement and roll out the COVID-19 banner (used as an example earlier) to our global audience in a matter of minutes as that situation developed.
However, this approach is not without its own set of challenges:
- The server now has to keep track of the specific clients and app versions that support any particular UI component in order to adapt the information appropriately to any given user.
- Providing all information via the server required us to move towards a world in which our Go microservices have to start keeping track of languages and localizing responses appropriately.
We’re working on solutions to these and other challenges as we continue to build our server-driven UI approach, and hope to share them with you in the future.
Have you used server-driven UI? We’d love to hear how you approached the specific challenges that may have been brought up in your use cases!
I’d like to recognize the entire Content Discovery team at Wattpad for their work on redeveloping our home experience, as well as Laura Kelly’s talk at Droidcon for being a source of inspiration throughout our journey towards server-driven UI.