Thoughts on Rich Harrisâ âMetaphysics and JavaScriptâ
Rich Harris, creator of Svelte, shared his slides from a recent talk titled âMetaphysics and JavaScriptâ where he critiques aspects of the React programming model. I found the talk extremely cogent and applicable to my experience using React.
I want to regurgitate some of his points in this post in order to help further elucidate and articulate my own feelings around programming in React, which as of late have mapped quite directly to Richâs points.
A note before we begin: I love React and use it everyday. The following changes none of that.
UI is a Function of State...?
Rich starts off his talk by clearing stating that he plans to critique the âmost sacred of sacred cowsâ: that your UI is a function of your applicationâs state.
UI = F(STATE)
This formulation is the very heart of the React programming model...Iâm not going to claim that itâs wrong. Iâm going to claim that itâs incomplete â that itâs more of an ideological statement than a description of what is actually happening when you build a React app. And Iâm going to claim that it represents a mode of thinking that obscures a deeper truth about how we think about our code.
Gut punch.
Ok, so how is the formulation UI=F(STATE)
wrong? Ah, but he didnât say it was âwrongâ he said it was âincompleteâ. He says âUI is a function of stateâ is not an accurate description of precisely what is happening when you build a React app.
Iâm putting words in Richâs mouth, but what I heard him saying is that the belief that your UI is a function of your applicationâs state is an abstraction thatâwhile it works well and can make you very efficientâis still just that: an abstraction. And while abstractions are useful, theyâre still a layer on top of your raw materialsâa layer that can become quite troublesome when you discover where it fails to pave cleanly over the underlying materials. If you canât find a coherent tactic for navigating flaws in the abstraction, you end up with continual friction until a fire starts and you burn up in frustration.
It reminds me of something Julio Biason said in his post âThings I learnt the Hard Way (in 30 Years of Software Development)â. He states that design patterns should be used to describe solutions, not find them.
(Again, personal opinion) Most of the time I saw design patterns being applied, they were applied as a way to find a solution, so you end up twisting a solution -- and, sometimes, the problem itself -- to fit the pattern...I saw this happens a lot: We have this problem; a design pattern gets close to the proper solution; let's use the design pattern; now we need to add a lot of things around the proper solution to make it fit the pattern.
While heâs talking specifically about âdesign patternsâ it does seem to apply quite aptly to Richâs points around the ideology of UI being a function of state. In other words, we find the idea of UI being a function of state extremely useful. It helps us move fast through complexity. However, it is nonetheless an ideological abstraction on top of the raw materials of how we have to actually build web applications in the real world: in the DOM. Rich takes time to elaborate on this:
I think [UI = F(STATE)] is an ideological statement, and what I mean by that is that like any other ideology, like capitalist ideology or communist ideology, it is a collection of normative beliefs and values that an individual or group holds for other than purely epistemic reasons, which roughly translates as âit describes the world people want to imagine, rather than the world people actually inhabit.â
Iâm using the word âideologyâ as a descriptive label, not a dismissive one.
But ideologies can be dangerous because when they start to chafe against reality, which they always do, the ideologueâs impulse is always to reshape reality rather than modify the theory.
So what we end up with when we say âUI is a function of stateâ is an ideology that approximates a proper solution to building complex web applications, and we leverage that ideology through the React programming model. But now we have to add a lot of things around the ideological solution to make it fit the raw materials with which weâre actually building (DOM) and it inevitably has flawsâor rather, perhaps I should say it inevitably makes tradeoffsâthat create friction when we rub against mismatches in the ideology and the reality in which we live.
What I really appreciate are Richâs attempts at addressing the ideology behind the framework and its mismatches with the reality of building web applications. Itâs great stuff. This is the kind of stuff Iâd like to hear when we talk about things like React vs. Vue (instead of merely âwell React uses JSX while Vue has HTML templatesâ).
I digress. Letâs continue where Rich left off.
So what would happen if we took a very naive approach to functional UI? Maybe it would look something like this: we create a function that generates some UI from some state, including an event listener that calls the function again when that state changes.
Do you see whatâs happening here? Weâre trying to create a very simple interactive experience illustrating the idea of âUI as a function of stateâ. We have some text that says âHello _blank_â where blank gets filled in by whatever value is in the <input>
. The JavaScript code is merely listening for a change on the input, and anytime it changes, it reaches into the DOM, erases everything in <body>
, and re-renders the UI based on the new stateful value of the input.
This is a great illustration of the belief that your UI is a function of your application state. So whatâs the problem here? Why does this not work? Well, thereâs more state in the UI than just the application state of name
. Rich:
We can see it doesnât work, because the old input has the focus, and the new one doesnât.
Every time that code runs, itâs reaching into the DOM, and replacing everything in <body>
with some new HTML. But what we perhaps didnât realize is that the DOM already has some state within it: the focus of the input. When we delete everything in <body>
to re-render with our new state, we loose the implicit state already contained in the DOM that a particular input has focus. React takes care of this for you with controlled inputs, but perhaps you didnât even know that? I didnât fully grasp it until I tried building a simple example along the lines of what Rich showed and realized âcrap, thereâs some state I hadnât accounted for which the browser handles for me by defaultâ. So it seems UI is not always a function of your application state.
Rich goes on to show that you could try to fix this by lifting the implicit DOM state into your application code. What happens? You end up running into another problem of the same type, and then another, and another, especially as your app and its interactions increase in complexity.
So it turns out that the DOM is stateful. But I thought thatâs what we were trying to get away from with frameworks like React? And thereâs the mismatch Rich is pointing out: the framework has an ideological bent that doesnât always match up to reality. Thatâs how we often end up trying to re-shape reality to match our ideology, rather than re-shaping our ideology to match reality.
As Rich goes on to point out, implicit DOM stateâthings like the focus of an input, the time an element has been mountedâ is a critical factor in determining what the user will see on screen at any point in time. And a lot of this implicit state canât be easily moved into our application.
our desire to express UI using pure functions is in direct conflict with the very nature of the DOM. Itâs a great way to describe a state => pixels transformation â perfect for game rendering or generative art â but when weâre building apps on the web, the idea chafes against the reality of a stateful medium.
At some level, you probably knew React was taking care of a lot of this for you. I know I did. But when I tried to build an app that took the foundational idea of âUI=F(STATE)â and build it in JavaScript (like the example Rich gave), only then did I begin to see how much React is doing for me.
And that leads us to what I saw as the apex of Richâs argument (emphasis mine):
Now of course we know how React handles [the conflict of implicit state in the DOM]: it takes the new nodes in your virtual DOM tree...and maps them onto existing nodes in the DOM. In other words React is a functional abstraction over a decidedly non-functional substrate.
To me this is a warning sign, because in my experience, the bigger the gap between an abstraction and the thing it abstracts, the more likely you are to suffer what programmers like to call âimpedance mismatchesâ, and I think we do experience that in React.
In other words, at the most fundamental level, what we have is a mismatch between the React programming model and the imperative APIs of the web. The web has a grain and I think Rich does a good job of illustrating how the idea of âUI is a function of stateâ goes against it.
So where do we go from here? I donât know. But writing this out has helped me better understand the friction I quite often feel. And itâs the perfect tee-up for a talk that says âHereâs Why Svelte Existsâ.