The Web App Trilemma

2023-10-05

The Web App Trilemma

Web application state is tricky. On the one hand, we want one big centralized state. A centralized state is easy to persist and reason about. On the other hand, we want actions to be immediately reflected in a local state, to give the user a snappy experience.

Adjecent to these, the user-interface (UI) is always either in agreement with the true state, or it is somehow conflicted with reality. Sometimes we'll choose the latter deliberately by presenting a predicted state in form of optimistic UI updates. More often than not, however, we end up with incorrect UI through bugs and race conditions.

The trilemma states that we rarely reach both a fast and correct UI, in conjunction with a simple centralized state in a web application.

Why? - Pick any two

Perfection is complex. And state management is where the bulk of complexity lies. The true origins of this discussion are philosophical, and beyond the level of this essay.

Let's start by approaching the edge of Completeness and Correctness. This is the edge your trusty static websites and server side rendering sit on. The state is on the server or in a database, and the UI is the static or dynamic page that is provided based on that state. Request-response like the web was originally meant to be.

The "traditional" way of the web obtained straight-forward state management and user interfaces that can be deemed to be, in today's standards, reliable. Add reactivity, and you'll get what made early uses of Javascript frustrating. Adding a spinner, validation or animations promote the DOM to an intermediary local state.

Getting applications right suddenly got a lot more difficult.

The reality of the web due to the Web App Trilemma

Enter front-end frameworks like React, which transition us to the edge of Completeness and Reactivity. By turning DOM manipulation from imperative operations to declarative code, some of the difficulties were solved. In the progress we got rid of Ajax and felt comfortable introducing a lot more requests from Javascript, giving us the present day single-page app (SPA).

Customers lauded the new, fast, reactive web apps, and we got obsessed with providing them with even more speed. Optimistic state and UI approaches were introduced: We swapped spinners to guessing what would happen, and then reverted if something unexpected happened.

But as we crammed in more and more features, our apps started to approach desktop-level complexity. Suddenly our inbox was flooded by users who reported conspicuous bugs in the user-interface. Actions sometimes did not result in what was shown on UI, and we kept asking customers to "refresh their browsers".

Somewhere along the way, correctness was no longer a requirement. Worse, it was not even expected at all times.

What could go wrong, if most state is centralized to the server, and fragments of it distributed locally in everyone's browser? There was a central source of truth, with local overridden chaos. So impossible is the dichotomy, that one is to question what the nature of reality is.

Then, there's the third edge. Along Correctness and Reactivity lie applications, that have many small states, distributed, to form a global state.

This rare breed of apps contains some video conferencing apps and browser games, but it seems so difficul to get right that most teams don't go this way. Partially, due to the obscure technologies needed. But this hints that the edges each have their set of interesting technologies. The "how" to reach that edge.

How? - Interesting Technologies

There are some great web applications that have shown that the browser is worthy of our attention. Among these we find Figma and the Google suite of apps. Perhaps Wikipedia and your bank's website sit somewhere along an edge, too.

Let's look at some of the technilogies that could be used to land on an edge.

Some of the Technologies related to the Web App Trilemma

Start with the obvious. The databases of Wikipedia and your bank require a centralized state. We have REST, CORBA, HATEOAS and others. In these approaches, the state sits on the server.

Then there's Operational transforms (OT) which is a way distribute mutations on a state, while maintaining a single centralized state. It requires a server to manage the state.

On the other hand Figma's pseudo-CRDT approach and Google Meets are based on many distributed states, that are merged. At least in theory. I would pile up P2P approaches like WebRTC in this edge too.

Then there's approaches on REST. Javascript frontends calling RESTful or RESTlike API's. Sure, there are a lot of solid applications here, but they either take short-cuts in UI correctness, or are exceptional pieces of engineering. For the vast majority, bugs and race-conditions will make them occasionally display an incorrect UI.

Can you think of an app, or category of apps, that would deliberately sit on this third edge? One that would have state in many places, and deliberately present a "misguided" state to the end-user.

There is one. It's called multiplayer games.

Multiplayer games sit on the right edge of the Web App Trilemma

An exceptional amount of work goes into managing multiple states in multiplayer games. Each client has its own "reality", and it is often more desirable to "fake" the effect of a player's actions locally, and then wait for the server to either confirm or correct that effect.

An approach, ill-fitted for submitting forms, but none the less prevalent in some SPA's.

Is the trilemma true?

Well, there are approaches and applications which try to work out a mix of all three. These technologies sit somewhere in the middle of the triangle. So far, few have achieved trinity.

I'd say Google Docs, which is based on operational transform's comes close to the middle. If anything, this is a glimmer of hope to break the web app trilemma.