Why Phoenix.LiveView is a big deal
Last week at ElixirConf, Chris McCord announced a new project called Phoenix.LiveView. I believe this library has the potential to reshape the way many developers build reactive user interfaces on the web.
Today, Phoenix provides a mechanism for defining Elixir modules that represent different views in your application. View modules contain a special
render function that returns the rendered output for the particular route (typically HTML) and any other helper functions you need for rendering.
LiveView is an extension of standard Phoenix views that will automatically propagate updates to the browser anytime state changes that would impact that view (using the existing Phoenix channels infrastructure).
To make my case, it helps to have a bit more context.
I’ve spent the last six months building my first production-scale single page web application (SPA) with Phoenix and Elm. Don’t get me wrong, I’m still a huge proponent of Elm and will be sticking with it for Level for the foreseeable future. LiveView is still early (not yet released yet to the public) and it remains to be seen what its trajectory will look like to achieving maturity.
But the process of building a large SPA has given me a new way of looking at web applications.
Taking a page from the event sourcing book, applications are effectively streams of events that may or may not correspond to changes in stateful data (or other external side effects). For example, when a user submits a form to update their password, this can be represented as a “password updated” event that may correspond to a change in the
password_hash column on the
users table (internal stateful data) and notification email to the user letting them know their password was changed (an external side effect).
For a traditional non-reactive interface, it’s often unnecessary to capture or process these kinds of events; instead, it’s sufficient just to update the column in the database and expect the user will see the changes reflected the next time they refresh the page. A reactive interface, on the other hand, needs to know any time a mutation has occurred to ensure that changes in state are reflected in the interface without a hard refresh.
Succinctly put, a web interface is a transformation of state (which is subject to change any time) into a human-parsable format (HTML) that is capable of triggering side-effects (state changes and external effects).
It’s no coincidence that this effectively summarizes the Elm Architecture: the model holds state, the view transforms the state into HTML, and the update function takes in messages that may mutate state or trigger other messages.
Much of the difficulty with client-side applications arises from the fact that it’s not feasible to have all the application state readily available on the client-side whenever we need it. So, we are left to figure out to most efficiently get the subset of state we need at any given moment transformed into HTML and kept up-to-date.
For some, the solution is React + GraphQL. For others, it’s Ember + JSON API. For others still, it’s jQuery + REST + Mustache. The list goes on.
- Storing raw application state
- Consuming and applying mutation events to keep that state up-to-date
- Transforming the state into HTML
These are all things that server-side frameworks are very good at.
The industry has already embraced the declarative paradigm: define the how data maps to HTML and let the runtime take care of mutating the DOM. LiveView applies this same paradigm to server-rendered HTML and (appears to) eliminate a significant amount of complexity to achieve the same end result.
There are definitely some inherent limitations with this approach, the biggest one being that the client must be internet-connected to work. And, it remains to be seen how the library deals with the myriad complexities of the DOM.
But for now, I’m optimistic about the prospect of building reactive interfaces without taking on the complexity of full-blown single-page application.