Reacting badly

There's a strange moment that occurs during passionate arguments between close friends, romantic partners, or coworkers when two sides with deeply dug opposing trenches suddenly realize that they agree - almost - about everything at issue. When the key realization is that the two sides differ not so much about the facts, as the paradigm by which they approach those facts.

I am reminded of this feeling when reading Alex Russel's passionate essay The Market for Lemons and its response from Laurie Voss The Case for Frameworks. Russel set the web development community on fire uproar with his critique of the current state of frontend development, the fact that he blames this state on JavaScript-heavy sites in general and on React in particular, and that he believes that the team behind React has specifically peddled it to the broader web community, despite being aware that it does not "scale down" particularly well.

First, some disclaimers about where I come at this from. In the last six years, nearly every application I've worked on has involved some sort of rich-text editor, interactive data-vis, or map. The ability to update the user interface without consulting a server was not a nice-to-have, it was part and parcel of what we were making. I have never found creating complex interactions with jQuery or vanilla JS to be approachable, and this is a view which seems to be shared by Russel and his allies.

The only mental model which has ever made sense to me in this space is one where application states are modeled as simple data structures, and transitions between those states are triggered by pre-defined edges. Each state maps in a one-to-one manner with a state of the DOM. Such a mental model can be tested exhaustively without looping in a browser, or - indeed - React. I have found that combining extensive unit testing and TypeScript closes off the vast majority of bugs from reaching production because most possible application states can be anticipated in advance.

If this sounds like a React + Redux app, that's because it is, and (the React part of it) was copied by all the other frontend DOM management frameworks over the years between 2014 and now. The community seems to have moved past Redux, but I still find the basic model works no matter how it is implemented. Mapping between a raw data structure and the DOM is what frontend frameworks now do, in the same way that backend frameworks implement some variation of MVC, and have since Rails was first released in 2005.

Now, I have no love for Facebook (the company that released and maintains React), and don't use it or anything they own. I'm confused by enthusiasm for CSS-in-JS. I hate configuring webpack to the point that the release of Parcel and later Vite was like a weight being lifted from my chest. There's also no question that the total weight of React is large enough that Preact is probably a better choice from an a priori perspective (but one also has to consider the value of walking a well-trodden path).

I have argued that putting a lot of business logic right in React is a bad idea. When data is fetched in effects, and when state gets updated in response to props, we're quickly shedding the benefits of having a well-defined state we can make sense of (this is what Eric Elliot calls time-travelling spaghetti). Of course React is bad if you abuse it.

And yet I don't think that my preference for declarative, pure-function-like components has anything to do with "developer experience". I don't think I am selfishly choosing React and leaving our users out to dry. Partially, Russel and I may simply be coming at this from different directions. He writes "Vanishingly few scaled sites feature long sessions and login-gated content." Perhaps that's true in raw numbers of websites: but those are not the sites where users spend the most time and where developers therefore spend the most time working. Many of them are built with WYSIWYG tools instead of code (and many of the WYSIWYG tools are themselves created with frameworks like React). If you're using React to make normal websites (not apps), you might want to give server-side frameworks a closer look. But the more interaction there is with a page, post-render, the less the old imperative style of creating interactivity works. This is not a "DX" issue: it's a UX issue where bugs become unanticipated and un-anticipatable.

Russel's ultimate claim is that these were intentional decisions and that those of us working day-to-day have had the wool pulled over our eyes. Again, I'm not so sure. React is popular because it does something valuable. Yet I'm in agreement that there is room for improvement.

The current state of web development is, in short, a mess. There are frontend and backend frameworks with different benefits and drawbacks that play together to varying degrees. There is REST and GraphQL. There are cookies and JWTs. There are testing frameworks and build pipelines and CSS preprocessors and linters and formatters. And most of these things are still issues, most of the time, whether your HTML is rendered on a server or in a browser.

Basically, I resist the prescriptive idea that there is One True Stack and we've lost our way. If anything, what we need is a smaller React and a better build system that emphasizes convention over configuration. We need mature, batteries-included Node.js frameworks so that HTML can be rendered either server- or client-side depending on circumstances. We should have single solutions for building, linting, formatting and testing to end the ceaseless bikeshedding that front-loads every product. We should probably just admit that CSS-in-JS was a bad idea from the start.

So, let's maybe not throw the baby out with the bathwater. There may be a time in the not-too-distant future when this seems like a bad dream, as the browser wars and jQuery spaghetti do now. Or maybe not. Maybe complexity is the price we pay to play outside the walled garden. Either way, we won't get there from here without acknowledging that most of the territory is common ground.

Like this post? Start a conversation, browse my other writing, or view my portfolio.