Skip to content(if available)orjump to list(if available)

Moving on from React, a year later

Moving on from React, a year later

258 comments

·January 20, 2025

sc68cal

I was worried that an application I was building in Django, with a frontend built with Bootstrap and some LIGHT jquery was making me look like an old curmudgeon but the part about testability of the frontend really resonated with me. It was MUCH easier to structure everything as pytest unit tests and completely rely on Django for all the business logic rather than trying to put state in the frontend and deal with synchronizing states between FIVE distinct systems (remote devices, the Django application, the database, an event stream, AND the front end).

I recognize that I'm not hip or with it, because I really fell out of front end development at the peak of jQuery where it was mostly about fixing browser incompatibilities, but it's nice to see that maybe it went too far in the other direction and we're overdue for a bit of a swing back towards server side.

DanielHB

Just because you have an SPA doesn't mean you need any state in the frontend. Main problem with react devs is just overcomplicating and over-abstracting stuff. The best way to explain it to a backend person is like the same interpersonal problems with overengineered microservices architectures.

tiew9Vii

redux-query seems a popular library for dealing with API calls in react.

I’ve landed on a project using it.

By default it seems to maintain its own cache in the frontend of all api requests unless you use a non ergonomic feature “useLazy*” where you can give it hint if to use the local cache or not.

It’s completely terrible in a web app! Web is distributed and multi user by default.

End result with the app I’m working on if user a adds an item in one browser session, user b goes to a list view they don’t see the update, they see the redux-query cache.

It’s an over complicated mess for an already solved problem. Have the server send proper cache-control headers and let the browser deal with the caching instead of trying to build fat clients on a web app that should be thin clients.

You are right you don’t need to maintain state on the client but all these fashionable JavaScript frameworks promote doing just that.

kilburn

redux-query is not popular by any means. [1]

Both react-query (that is tanstack query now) [2] and rtk-query [3] include extensive configurability regarding their caching behaviors. This includes the ability to turn off caching entirely. [4,5]

Your story sounds like a usage error, not a library issue.

[1] https://www.npmjs.com/package/redux-query

[2] https://tanstack.com/query/latest/

[3] https://redux-toolkit.js.org/rtk-query/overview

[4] https://tanstack.com/query/latest/docs/framework/react/guide...

[5] https://redux-toolkit.js.org/rtk-query/usage/cache-behavior

the_other

That sounds like an application architecture problem, not problem with react or redux-query.

pinoy420

Serverside rendering is apparently a new technology now. And this brand new thing called islands which someone reinvented recently.

emptiestplace

It's back, but the nice thing is it's 10x more complicated now!

khana

[dead]

mattmanser

And in slow javashit!

belter

Oh no. So Java JSF was right after all? :-)

imtringued

No, the only project I've worked on that was a massive failure was built with Java JSF.

pjmlp

Yep, time to dust off PrimeFaces.

spockz

What are islands? The new servlets?

shreddit

Smallish parts of JS (React, Vue, ...) sprinkled into your website for interactivity. I use it with AstroJS: https://docs.astro.build/en/concepts/islands/

null

[deleted]

null

[deleted]

aryonoco

Using a SPA doesn't mean ignoring software engineering principles.

At my work we develop web applications for a mission critical sector (emergency services). We use .net for the backend (we have also used golang in some projects) and Typescript and Angular for the frontend. We follow MVVP patterns, SOLID principles, etc. There are multiple layers, each layer has a well defined single responsibility. Our applications have been quite successful with happy users and great maintainability if I may say so.

There is nothing special about our setup. We could have used Vue.js or react for the frontend. We could have used any platform to build REST endpoints (though personally I like strongly typed languages for implementing business logic and think .net is underrated).

Software engineering might not be as old as say civil engineering, but we've been doing it for decades now and have a rich library of patterns and architecture types to draw from. I've been building software for over 25 years; the technology stack might have changed in that time but the principles are still very much the same or are extensions of the previous ones.

Using a SPA doesn't change the fact that if you want to build good applications, you first have to design them.

tyre

> Let’s assume that making a JS change costs twice as much time a Ruby change, which I think is being generous to JS.

Everyone's mileage varies, of course, but this is quite the assumption. It feels like a lack of familiarity/comfort with the frontend or poor tooling.

With typescript and a basic UI library like MUI, this really shouldn't be the case for UI changes. If you're using raw JS and manipulating the DOM, maybe?

kellysutton

The original post could have been a bit more precise on this point. Basically, this math assumes something where the server-provided data changes in concert with the frontend.

If we're using jsonapi, GraphQL, Thrift, or any other protocol that's not HTML, we need to do the following:

- Make the change on the server to support the new functionality. Deploy.

- Make the change on the client to adopt the new functionality. Deploy.

- Remove the old functionality from the server (optional)

Because the client is a separate application, it becomes riskier to deploy those changes together. I need to think about it more as a developer.

With server-authored HTML, this separate client + server deploy is not required.

Lutger

There are a couple of reasons this is not convincing either:

- Other factors can often dwarf the separate deployment overhead, especially given that the deployment steps are done so often it will force the team to make it efficient and get used to it.

- There is no hard requirement for separate deployment in the first place, if we are just talking about react / spa you can deploy it in a single step. (Not saying you should)

The point is: yes there is quite a lot of overhead. From separate deployments, from separate state management and I think the big ones are often having two different programming languages and having to align schema on frontend and backend. It is hard to deny this. But then saying that because of this overhead, these kinds of apps take 2x time to code implies denying there are benefits as well, that under given circumstances can outweigh the overhead.

I think it is more interesting to assume that in some cases the benefits outweigh the cost of the overhead, and in others they do not.

leptons

>With server-authored HTML, this separate client + server deploy is not required.

SSR has been a thing in react for a long time.

runako

If the app has a backend, aren't we still talking about modifying two distinct apps (React + backend app) vs a single one?

Obviously unless the team has committed to React SSR + React backend (is this common?)

bryanrasmussen

yeah and it sort of sucks in comparison to most other server-authored HTML solutions, in this statement I am of course thinking of Next but I suppose various forms of suckage will be found in other solutions.

Lutger

Absolutely, this is one of the main assumptions where the blog falls apart. What takes more time and carries more risk, really depends on context. Boring, but unavoidable. This is another one:

> when compared to a world where that change isn’t risky (server-rendered ERB)

Server rendered html templates a la PHP - which is what ERB is, may be not risky in this smallish project with likely a fairly straightforward UX and seasoned rails devs, but it can be risky in others for sure. I think a lot of the motivation to embrace what react began was a desire to move out of a tangled mess of spaghetti templates, to be able to use means of abstraction and modularity as powerful as regular backend code. Frontend devs want to create and use components. You cannot create a component with html templates, not really. It will be a mess.

Moving from server rendered html to an api + spa architecture has quite an overhead of course. Just like adding a separate backend service. That price should be worth it. And a good developer can judge whether in which context that is the case. But pretending the benefits that motivate such a change just never justify the costs doesn't make sense to me.

The cost of a change is a very, very complex measure. Anyone who has a simple answer to it that is universal, true and useful will win a Nobel Prize. This is because the cost depends on the person who is making it and his peers, on its effects in the future, on the project of which it is a part, on luck and on the larger ecosystem in which it is done. There are just way too many parameters.

mvdtnz

My experience with very highly paid frontend developers is they like to spend hours and hours (and thousands and thousands of dollars) building out little libraries and components and frameworks that will enable other teams to be faster. Except this never eventuates because things rarely turn out to be reusable along the right axis so a new component or library or framework is developed to solve the problem.

On top of this UI developer propellor-heads love to spend time (and money) pontificating on abstract theories about functional programming and homomorphisms and endofunctors so they can render some text inside a <b> tag. It's how we wound up with utterly ridiculous pieces of code like the "hooks" API in React.

JOnAgain

Can’t get promoted pumping out 10 great pages. But a library that you can claim will enhance the productivity of 100 other engineers? Now that’s IMPACT!!

Except you’re at a company where everyone has figured this out so now you have 4 competing libraries with their own teams which are all 1/2 done making every engineer less productive cause they all have bugs and slightly different priorities.

ctkhn

this is exactly the frontend team from a previous role. we were losing millions a month and had 2 major cuts within 4 months - and instead of cleaning up or simplifying our bloated frontend, the teams responsible for it started building new component libraries for the rest of the org to use on future pages

veidelis

4 competing in-house libs? How can that ever happen? Is middle management non-existant? That is anarchy, hehe

goosejuice

I also get the feeling that modern frontend is a massive money pit but this seems to be a leadership problem. I wouldn't go so far as to blame the IC. There are developers over-engineering in every ecosystem.

Earw0rm

Something about the psychology of front-end - not quite as hardcore technical, a little more humanities-aligned - perhaps makes them even more susceptible.

The self-consciously cool kids are always going to be more easily swayed by fashion than cave hermits.

tannhaeuser

You forgot the part where everything has to be redone every 5-10 years despite grand allusions of reusability because of the cyclic nature of the frontend market. The JS framework proliferation is largely driven by skills becoming obsolete (or needing to become obsolete for economic reasons) as younger frontend devs move in who want to carve their niche and distance themselves from "horrible" previous-gen unmaintainable and wayyy overengineered stuff. Which was objectively unmaintainable either from the start as a work of love of a developer who put all his thoughts into it so it became incomprehensible ;) or became unmaintainable when later developers (who couldn't care less) had to violate the original grand vision of state encapsulation or hypermedia architecture or whatever for a trivial business form app.

I guess the good thing is that comprehending our absurd web frontend creations is beyond current LLM's capabilities.

chefandy

I've done a lot of back-end and a bit of front end development. You're correctly identifying a crappy outcome, but incorrectly attributing the effect of shitty developers and project management with whole disciplines and common practices within them.

zsoltkacsandi

I've had exactly the same experience.

null

[deleted]

marcus_holmes

I think the author was talking about React specifically.

I've worked in JS, TS, React, and RoR, and yeah I'd say making a change is probably twice as quick in RoR as in React.

The thing is that Rails is an opinionated framework. If you do things that the framework is designed to do, then it's very very easy. If you go off-piste and have to fight the framework to do the thing you want it to do, it gets very hard very quickly.

React is less opinionated (about most things) so the converse is true; it is slower to write stuff in, but there's less constraint.

ajmurmann

I feel the comparison is really hard. Rails really is a framework that solves anything but the business logic for 80% of your app. React is really a library for rendering components and everything else is your decision to pick or build from scratch. E.g. Rails has opinions on how to build forms while React, a supposed frontend framework, doesn't have anything baked in specific to that. Sure the community has opinions about it but React doesn't like Rails does.

psychoslave

There is no free lunch though. Typescript and whatever frontend stack we might go with will come with their own drawback. It doesn't mean the trade-off is never worth it, but we better keep in mind that adding transpilers and a truckload of external libraries does have a maintenance cost.

bvrmn

Typescript has so vast productivity benefits there is no any second though to use or not to use it.

Zanfa

I wouldn't touch a React project without Typescript. But if you use something like Web Components (or Stimulus etc) where you compartmentalize small bits of UI into distinct reusable components, JSDoc gets you 90% of the benefit of Typescript without the baggage.

bvrmn

Also it depends from API response. It could vary from FE dictating schema or backend making hard orthogonal domain modeling API.

In first case FE is productive there is no need to transform data but makes BE a hot mess. Otherwise FE have to maintain layer of code to convert BE data to presentable UI data. It's harder but allows to decouple UI reqs from changes along all stack.

null

[deleted]

htmxsucks

HN is not real world, just like how Reddit is not real world.

I am a FE with 10 years of experience, and has tried, and tried really really hard and multiple attempts to make HTMX works well.

Doesn’t work. UX is much worse, code discoverability is much worse, slower to code in, everything is messier than just plain React SPA with JSON data. Terrible, terrible DX and UX.

Seriously, there is a reason why despite all the rage in going back to multi page Django/Rails app, very very few people actually take it seriously. You just don’t hear the negativity because most folks just tried it, saw that it is worse, and moved on without writing a blog post.

tobyhinloopen

I've contributed to all kinds of frontend setups; Elixir LiveView, React, Vue, Angular, HTMX and many more.

I've yet to find a frontend scripting solution that works well. My current stance is to have the frontend as thin as possible, no matter how it is written. Have your domain logic on the server output Plain-Old Data structures (JSON or similar) and render them with stateless, dumb views, be it a template, Vue, React or whatever.

A clear boundary between the domain logic and view is important. Rails templates that can basically access anything is a terrible idea.

cybrox

I have similar kind of experience and made similar conclusions for myself.

In addition to the points you have made already, I would like to add that almost every larger project needs a lot of business logic on the backend side anyways. There is no possibility to have this logic in the frontend and there never will be (for security reasons at least). So given these circumstances, we usually already have quite a few people experienced with - and very efficient in - these backend technologies.

So why would I spend a lot of time re-creating all kinds of routing, models, properties, etc. in an SPA? We currently run an Ember SPA for our largest project and 1/3+ of the time spent on it is pure waste because it is simply additional work to facilitate the use of this SPA at all.

In every project I've worked on, the interactive and dynamic elements actually used that are written in JS end up being a lot fewer than originally anticipated. Unless you're building a product where the majority of the functionality relies on instant, realtime updates such as maybe a streaming site with chat, etc., building, maintaining and extending an SPA is a huge overhead that offers little benefit over "dumb", static views with small, isolated interactive components.

diggan

> Unless you're building a product where the majority of the functionality relies on

This is a huge problem in the ecosystem. People want a landing page, so they reach for some full-stack SPA backend+frontend framework that is hip today, which is absolutely bananas.

Sure, if you're building web app with lots of dynamic and interactive elements, go crazy, because you'll probably need it, lord knows you'll get tangled up in state management no matter how clever you think you are.

But for websites that aren't trying to became the new Google Maps/Figma/Whatever, simple and basic templating patterns won't just be faster to develop, but easier to maintain and a better experience for your visitors to use.

zelphirkalt

My experience exactly. Why one would do that anyway? Not listening to experienced engineers and being blinded by modern FE hype. Thinking just because many other businesses do it, one has to do it too. Then decision made by non-technical or not too technical management people.

And sure enough, then came the self inflicted workload. "Oh we need to change the router.". A problem you do not have with any popular mature web framework on the backend. "We need to upgrade to NextJS version 149, for feature blablub." Which would come naturally with something like Django or other traditional web framework. "We need to upgrade NodeJS!" ... and so on and on.

While all of what the FE actually did could have been just render static templates and a few lines of script.

Companies choose their own downfall by following the FE hype trains. The result are the shitty web apps, that don't need to be "apps" in the first place, but could simply have been static pages. It is quite a comedy show and I would laugh, if it did not affect me negatively.

egeozcan

I also have a lot of experience with various setups and front-end technologies, and I couldn't agree more!

Furthermore, I'd say this: if you can't simply serialize your view-model and send it to the client because something might get exposed or because it's a complex object with embedded logic, your first priority should be fixing that. Only after achieving this should you even think about changing how you handle the front-end.

jeppester

We use inertia.js to do exactly this.

It's a really strong selling point that you can use a popular FE framework for all the templates, but at the same time almost completely avoid state management.

diggan

> but at the same time almost completely avoid state management

Unless you're just building simple landing pages (I think the context is "web apps" here) or something, you might not have removed any state management, you've just moved it elsewhere.

So the question is, where did you move it instead? The backend?

pandatigox

Out of curiosity, what difficulties have you faced with Elixir LiveView? I am developing in it right now, and am enjoying managing state and interactivity in one codebase (I like how everything is channeled through the socket).

Has your experience been more negative?

oefrha

If you handle all interactivity server side so that the user can’t do anything at all without a round trip, sure. It’s just a terrible app for users with latency/patchy connectivity. As soon as you try to mix in slightly nontrivial client local state and transforms it becomes the most retarded JS imaginable.

tobyhinloopen

My primary complaint is that it is hard to test (compared to "stateless" pages) and that the whole thing feels complicated.

I also feel like the learning curve is pretty steep and you can't just have a random, experienced non-Elixir dev join the project and have them fix something. They must be comfortable with Elixir & Phoenix before they get productive. I feel like it is multiple layers of complexity and uncommon patterns.

Other than that, I think it is very cool. I have very strong mixed feelings about the feature hah.

plantwallshoe

Can you offer some examples of issues that have arisen from using the rails-style template with access approach?

tobyhinloopen

It is very easy to have very important choices made inside a rails template, like permissions (can X access Y?) and it is similarly easy to ignore permission checks and just query anything you like.

This makes it also very easy to end up with N+1 issues that are not caught in tests (because the tests don't render views), "forgetting" to scope the data (rendering more records than the user should be able to access) or rendering sensitive attributes the user should not have access to.

Even with tests that do include rendering the views, it is very easy to have a test like:

    it "renders my posts" do
      post0 = create(:post, user: current_user, title: "Foo")
      post1 = create(:post, user: current_user, title: "Bar")
    
      response = get "/my-posts"
      document = parse_html response.body
    
      expect(document.css("tr td.title").map(&:text))
        .to match(["Foo", "Bar"])
    end
Now there's so much wrong with this test, but the primary issue is when the view does something like this:

    <%= render "posts", posts: Post.all %>
The test implies the document should only render the current user's posts, but the view / template actually renders all posts. You don't want to test this kind of logic by inspecting HTML, because it is error-prone and expensive to test this way.

What if you want to change the HTML structure? You'll end up rewriting all these tests, and it is VERY EASY to make subtle mistakes when rewriting the tests, resulting in false positives in the future.

Instead, I think you should separate this logic to a model, not to be confused with "activerecord classes" - I'm thinking of a `UserPosts` model, like this:

    module UserPosts
      extends self
    
      def get_user_posts(user, opts)
        user.posts.with_opts_or_something(opts)
      end
    end
Then you also disable automatic loading of relations (forgot the config name) and, by convention (or enforced in some way), never refer to any model modules or classes in a view (or any method called by the view, like the helpers).

Your controller will likely look like this:

    class UserPostsController < Whatever::Base
      include UserPosts

      def index
        @posts = get_user_posts(current_user, page: params[:page])
      end
    end
By keeping the domain logic inside specialized modules per access scope (i'd have separate `Posts`, `PublicPosts`, `AdminPosts`, `ModeratorPosts` modules), you can test the logic in tests per module (including tests what the module SHOULD NOT access). Then, when writing the views and controllers, you don't need to re-test or re-remember to test the "should not" cases - the test cases you're easy to forget.

You can also design the modules in a way that they only load (select) the properties that context would be allowed to access. If you have sensitive data (like a user's real name or email), you don't even want to load that property when loading the users from a `PublicPosts` context, since public posts should only render the user's id and public nickname for example. You can also wrap the posts/users in presenters using whatever fancy gems you fancy, as long as it gets the job done.

In an ideal world, I'd lock down Ruby templates to only have access to previously loaded data via instance variables and helpers, nothing else.

It is a bit hard to explain, since I have limited time to address it properly, but I hope I get the point across.

Epskampie

I'm a freelance webdev with 15 years of experience, and recently I've made some new projects with Symfony Stimulus & Turbo to great success.

A few thoughts:

I tried just htmx too, too limiting. Stimulus/Turbo combination is much better.

Use the right tool for the job. Highly interactive app, like an editor? Use react or similar js framework. Mostly page/document website? A backend framework is much faster and easier to develop, and much simpler to test.

Use what you know yada yada.

fullstackchris

A blend of both? Drop in a React component where needed on a given page! People forget (me included) that even React can be mounted into a single DOM element.

With all this framework nonsense its hard to forget at the end of the days its all just javascript.

mst

If you're doing something something reasonably small, using preact rather than react and then wrapping it into a web component so you can just ... put it in there ... is a really nice option to have.

(it may not be the right option in any given case, but it's worth knowing it's there even so)

null

[deleted]

timabdulla

I'm not too sure about HTMX in particular, but my Rails app's FE is just HTML and Stimulus/Turbo. I'm not sure why you think it simply "doesn't work".

To me, it's a lot simpler. I use forms and links and render HTML templates. That's it.

I don't need to worry about building and maintaining a JSON API just to serve the front-end. I don't need to worry about distinct sets of routes and models. There's just one repo with one build pipeline and test setup. There's no need to worry about front-end state at all, since I'm just using plain-old links and forms.

I'm not claiming that there is never a use for React or its ilk, but I am genuinely finding it hard to understand how one can assert that this simple HTML-based approach is categorically worse in all circumstances.

In my context, the simple approach works. If I were working on something that had a high degree of inherent complexity on the front-end -- maybe a web-based video editor or some kind of WSIWYG productivity tool -- this approach would almost surely fall apart, but that's the point of engineering: Choosing the right tool for the job at hand.

davnicwil

The truth is in a similar vein but more general - most just pick the stack they are most productive in, whatever that may be, and move on without writing a blog post.

For less frustration when reading such posts that are written, read the author as writing for themselves, reporting the pros and cons for their very particular situation, and see if there's some nuggets to be found in that context.

Don't read them as telling you those same pros and cons apply to your situation -- even if they veer into implying they may :-)

zsoltkacsandi

> Doesn’t work.

It worked for us, one of the most visited websites in my country, migrating away from a Vue.js based “modern” frontend stack.

It was a huge success in terms of productivity, developer experience, and cost.

kopirgan

If I understood correctly the author of original post is also talking from real world experience, not running university research lab.

drdaeman

This may depend on a type of website/webapp one is working on? I have a suspicion that sometimes HTMX may actually fit nicely (e.g., for an online survey), sometimes React-like framework is the probable way to go (e.g. a marketplace app), and sometimes it could be that neither is a good option (e.g. games).

DanielHB

The main problem is that it is not really viable to start with HTMX and add react (or another frontend framework) later because you end up having two completely separate stacks that are very incompatible with each other.

The worst sin a large codebase can do is being inconsistent.

recursivedoubts

Ah yes. The You Are Maybe Gonna Need It (YAMGNI) principle, a classic.

pjmlp

The Web development projects I work on, are still mostly server side rendering for the last two decades, using Java and .NET frameworks.

And when not, it is due to CMS products available as SaaS like contentful.

In such cases we go for Next.js due to it providing a similar experience with server side rendering and controllers.

In one thing you are right, we don't take seriously development stacks that don't offer either JIT or AOT compilation.

RangerScience

FYI - There's some neat ways you can embed React components inside Rails templates. Basically - embed the props in a template-managed `script` tag, and use Stimulus to mount the react code, passing in the props read from the DOM. Now your React is pure state-to-view, no need to synchronize anything, - it's really just a handful of React components instead of a full React app.

That said, AFAICT, there's just two advantages:

1. Those annoying little UX doohickeys that actually DO want that level of interactivity

2. You can use any of the vast library of existing React components (for me, that's been react_big_calendar)

As a bonus (and, why I rolled my own, since `react_on_rails` doesn't support these), and with a bit of tweaking:

1. It plays nicely with Turbo. I can use Turbo to update my React props and it just... works.

2. You can embed a template as a child of the React component.

2a. This also plays nice with Turbo.

It sounds a little screwy, but so far it's working well, and it feels like it lets me use the right tool for the right job - aka, Rails for everything except the stuff with extremely high interactivity.

jnathsf

Amazing! I would love to see a blog post or a gem that unlocks React components with a Rails + Stimulus/Turbo app.

RangerScience

I intend to! And to wrap it in a gem; I’ve got it partly there, but it’s a currently a mess as I ran into a bunch of “oh that didn’t actually work” problems at various points. I’ll post a link later…

Edit: Ach, sorry - it's going to be awhile, when I went to roll my own I did it inside my project, so it's not even close to being available as a gem :/

fareesh

I do this too, it works well

austin-cheney

People in the comments talk all about their favorite pet tech stacks with only a single purpose: how long it takes them to write code. In front end logic that typically means putting text on screen or interactions.

Years ago I decided to not worry about those concerns and it turns out those concerns are irrelevant. Writing content, really all front end logic, is as fast as you can type on a keyboard irrespective of your tech stack. Just about everything else is over engineered insanity. That was even true back in the IE7/8 days.

It became apparent to me the only thing that mattered is time to refactor. The larger the application is the more true that becomes. The things that help with that the most are type annotations on everything, high execution performance, and fast test automation. Everything else became a distraction or noise that got in the way. The application does what it promises or its defective. It can be modified quickly or good ideas are abandoned for risks or costs.

So I don’t worry about tech stacks and spend too much energy on execution speed.

ec109685

Server rendered HTML is all well and good until you want to add native apps or a first class API layer. At that point, it makes more sense to have the web be just another client and move as much business logic into the API layer as possible.

timr

There's absolutely nothing preventing you from emitting JSON (or whatever) API responses from the same controller logic that renders HTML.

Rails makes it easy.

ec109685

A native app is more than just translating each html page into a screen. You’ll likely want to build a data model that you use throughout the app, instantly load as much of the next screen from data already fetched as you can, etc.

Having a flexible API tier makes that more ergonomic.

timr

Nobody said anything about translating pages into screens.

The point is that the data model (and hence, the API design) applies equally to a web UI or a native application. The issues you're raising also matter for making webpages fast. When you think about the data model design before you make the presentation layer, in almost all cases, the choice of what you render is basically a straightforward transformation.

neeleshs

Even with react, we have found that having a separate API layer was more ergonomic.

Maybe with graphql it is different

renegade-otter

First class API layers and native apps require such a massive amount of work (and money) that your app emitting HTML is the least of your problems.

This is not 2011 when every website was building an "app" for native experience. If you are not building an Uber or an AirBB, you will probably manage.

pjmlp

Those that want to make it right deliver JSON as well.

Those that want it easy, use Electron.

kellysutton

A friend mentioned this made the front page. I'll try to answer any questions on our approach at Scholarly. Thanks for reading!

Swizec

> Let’s assume that making a JS change costs twice as much time a Ruby change, which I think is being generous to JS

I don’t grok this part. Based on my experience with RoR and JS/TS, making changes in TS-land is much easier and quicker than dealing with Ruby.

Is this just a preference/experience thing in the end? For you and your team RoR is faster/easier, so that makes it the better choice. For a different team JS/TS may be faster/easier, so that makes it the better choice?

kellysutton

Haven't written much TS, so can't speak to that.

I should have made the distinction between client-side and server-side JS/TS. Familiarity and expertise will be a main driver of productivity for a team, regardless of language/framework. For us, that's RoR.

Client-side JS however has a multiplying property, where we often need to write more server-side code to accommodate the growth in client-side code. If the client-side code is providing undifferentiated value (e.g. authoring HTML), we now have more pieces in our system to accomplish our goal (author HTML). What's been surprising to me is that you don't need to author HTML client-side to have a reactive experience. With Turbo, Stimulus, and server-rendered HTML, a great experience is possible with fewer layers.

Swizec

Great answer. Thanks!

I think the power of fat clients comes when you have different consumers of the same APIs/logic. Like a browser app or two, maybe backend services, a few task queues, etc. Then having a clean separation between client code and business logic becomes super valuable.

In my experience with SPA we got to a point where my team could go weeks, even months, without having to make changes in server code. Whole new features that were fully supported by our existing APIs because they were written as reusable APIs. If you’re having to write a bunch of Rails to support the growing client code, you probably didn’t need a separate client yet.

But when your codebase gets to that point even Rails is just a frontend really. So it’s mostly about which tradeoffs you prefer. Unfortunately I left Rails right around the time Turbo was becoming a proper thing you could use so I don’t have the best feel for what it’s like.

evanmoran

Thank you for writing this all up. Just curious if you ever considered switching away from Ruby? I think many people are living in parallel stacks (TS, Go, Python, Rust) and it would be interesting to hear how it’s been going more recently in that ecosystem from your perspective.

As to rendering, I’ll be honest and say that my code has moved more towards client-side (using ConnectRPC and my framework ojjs.org—-shameless plug :), but I love that you have had success with a different path. Super interesting, and thanks again!

kellysutton

I don't have a reason for switching away from Ruby at this point in my career. Things can always change down the line. Maintaining multiple languages at the same layer sounds like a personal nightmare to me. I'd rather learn to write PHP and have that be the only language, than to write Ruby+another language on the server-side.

We're building our company on Rails because we think it's the best choice for a young company, since it allows us to respond to customer feedback more quickly. That's what we're optimizing for right now!

fareesh

Did you give inertia a try?

phaedryx

I think the idea of "sprinkling" JavaScript into your server-rendered HTML is a good one. However, I think that Stimulus is terrible.

1. There isn't a good way to test it. There is nothing in the docs about how to test it.

2. Keeping state in the DOM is dangerous

3. Messaging between Stimulus controllers is painful

4. They disconnect parameters from functions. The functions have to scan through the DOM to find what they need which I think is fundamentally weird

5. Reusability is rare

6. It doesn't try to play nice with the larger JavaScript ecosystem.

I personally prefer Vue.

abhgh

Reg. #2 - I returned to frontend dev. after years for a hobby project (and even earlier, my frontends weren't very complex, I could get by with jQuery in the pre-React days), and I am surprised to see this is popular (or at least a supported feature everywhere). I would also think #2 is dangerous, but I am wondering if its just me being simplistic. Aside from a thin layer of reactive controls, when do people need #2?

nchmy

Care to elaborate on #2?

phaedryx

I remember when Backbone first came on the scene and “get your truth out of the DOM” was the rallying cry.

I'm going to cheat and get a list from AI:

1. Difficulty in maintaining and debugging: When state is scattered throughout the DOM, it becomes challenging to track and manage, leading to code that is hard to maintain and debug.

2. Performance issues: Frequently querying the DOM for state information can be more expensive and slower compared to accessing data stored in JavaScript objects or dedicated state management solutions.

3. Lack of a single source of truth: Storing state in the DOM makes it difficult to establish a centralized, authoritative source for application data, which can lead to inconsistencies and errors.

4. Synchronization problems: Keeping DOM elements in sync with a mutable list of data can quickly become complex, especially when dealing with dynamic lists or elements without unique identifiers.

5. State persistence issues: DOM-based state is vulnerable to loss during page refreshes or navigation, which can lead to poor user experiences, especially in single-page applications.

6. Scalability challenges: As applications grow, managing state in the DOM becomes increasingly cumbersome and can result in performance bottlenecks.

7. Difficulty in implementing advanced features: Techniques like time-travel debugging, state snapshots, and easy hydration become more challenging or impossible when state is primarily stored in the DOM.

8. Increased complexity in component communication: Relying on DOM for state can complicate the process of sharing data between components, potentially leading to prop drilling or other anti-patterns.

tomnipotent

In the "old days" I'd colocate data as HTML attributes:

    <div data-parent-id="1234" data-category="Article">
We'd use this data for any number of purposes to build out other little features that'd rely on the attributes.

est

I think the key takeaway of the article is:

> Code is not an asset, it’s a liability.

> What is the least amount of code we can write and maintain to deliver value to customers?

regardless of HTMX/Bootstrap/react, the simpler the better.

overstay8930

Watching Meta rewrite Messenger twice without success was enough for me to never touch React for any large project, especially after that botched e2ee chat rollout.

cwalv

You think the major complicating factor of rolling out e2ee was that they used react?

overstay8930

Given I was able to see the errors directly in the js console, yes. You used to be able to break everyone's state by putting an emoji in a URL.

fsociety

I was hoping for stronger rationale than this. This is not a React-specific problem.

gejose

You really think Messenger isn't successful? You think any issues Messenger had was because of react?

Do you have sources on this?

overstay8930

I didn't say Messenger wasn't successful. I said that Meta rewrote Messenger twice and did not meet their internal goals both times.

Even today you can see Messenger completely break down if you have to sync for more than ~30 seconds. JS console fills up with errors about your broken state as you start to lose messages. Local storage is out of sync, session state breaks, and it's all right there in the console. It's been like this for years on WebKit. React just has too many bugs for a complex behemoth like Messenger.

React Native is just as bad and basically everyone I know in real life can corroborate lost messages, broken group chats, horrible photo experiences, and memory leaks!

You can just look at Messenger vs WhatsApp and the difference is just night and day in the user experience. The e2ee backends are the same (according to my pcaps, I could be lying), it's purely the front end that changes - and you won't find anyone that says Messenger is better than WhatsApp.

forrestthewoods

The only UI framework I’ve ever used that I didn’t absolute hate is DearImGui. I realize it doesn’t produce polished, professional looking UIs. But my god is it the only thing that doesn’t suck.

JavaScript and ReactJS are at least 10 times less efficient to write than C++ Dear ImGui. That’s so crazy.

elcritch

I feel the same about DearImGui. Want a list of sliders, bam, it’s done.

So I started working to create my own UI framework with some of the DearImGui feel but being a bit more scalable.

Recently I just added basic CSS [1]. Super fun to get it working but it’s been a lot of work combining UI styles. But it’s cool getting 60fps live animations in a 4mb binary. Hopefully CSS can help get it looking good.

1: https://blog.elcritch.net/why-i-settled-on-css-for-theming-i...

andrewmcwatters

Dear ImGui isn't for end-user facing UI.

forrestthewoods

Did you read my whole comment? It feels like you didn’t read my whole comment. Because I said “I realize it doesn’t produce polished, professional looking UIs”.

I don’t think that’s an intrinsic quality of a DearImGui type API design. I’m reasonably confident it could produce a professional end-user facing UI. And that it would be perfectly performant and battery efficient.

hombre_fatal

Yeah, drawing everything to the screen every frame makes a lot of things easy. You can just update state and it will get drawn on the next frame.

DOM UI libraries like React have the harder problem of surgical tree updates since they can't just redraw from scratch.

It's where all of their complexity comes from. Not even React's basic primitives like useState would be necessary if you were just going to redraw the whole UI on the next frame.

lmz

Good luck making that immediate UI accessible.

girvo

> but I think the “fat client” era JS-heavy frontends is on its way out

Look, you might be right! I still think it’s not the right tool for all situations. But this has been said over and over for at least ~7 maybe 8 years for what I can remember and it’s yet to be true, for better or worse. We’ll see though!