One thing I've seen happen again and again in a lot of technologies is a "framework gravity". A lot of people see this as engineers just wanting to work on "hype" technology but I think what is actually happening is a reflection of global engineering time.
React is great for SPAs. Most large companies are working on honest-to-god SPAs. By extension most engineers are working on SPAs. So most tooling is created for SPAs. Now if you aren't building an SPA you look around and find almost every resource is around building an SPA. Even if you know you don't need an SPA, it's easier to hire, iterate, and even use other open source solutions if you are building an SPA, so you try to hamfist your project into an SPA.
It's a bit like having a bike commute in America. A bike might be the best thing for you to do - cheaper than a car, keeps you healthy and you don't need a garage. But you quickly find that everything is built for cars and it's easier to deal with the disadvantages of a car than try to commute with a bike.
I remember thinking the same thing about Hadoop 5-6 years ago. If you had "small data" you could get what you wanted with SQL and fast disks. But everything else assumed you were on Hadoop. Newgrads were trained in hadoop. New tools were Hadoop first. New research was all hadoop. If you hit a small issue with your DB, almost every solution would be "this is how it's solved in Hadoop". It was hard to even know if what you were trying to do what even possible without Hadoop.
The only optimism I have is that maybe in 5 years we will all collectively wake up and stop trying to shove React everywhere just like we stopped with Hadoop.
> Most large companies are working on honest-to-god SPAs.
Most devs don't work at large companies, at least not tech oriented large companies. I'm almost certain most projects don't come out from such companies either, statistically.
In fact, most projects are not SPA, nor using any kind of AI, Big Data, or another buzzword.
So I don't think that's it.
I think that large companies are just the loudest, also creating/promoting popular FOSS projects, and they have great engineers that are on many social networkd, including HN, or write famous blogs.
And so people have the impression that you need an SPA into a docker mix among other microservices each horizontally scaled in the cloud, monitored using an observability framework, using a big data pipeline for processing things they will store in their NoSQL sharded DB accessible through a GraphQL Api.
Because Jack working at GAFAM for $500k has the time, env and will to sing about it, but Juan working in a Madrid bank is just spending his company time fixing the Tomcat server quietly.
It's not as if all of them are working on a SPA or the backend of a SPA.
On the other side, the long tail of devs working in medium and small companies are probably working on both a frontend and a backend. This is especially true when there are one or two developers in all the company, when the company business is selling some service or physical product and software is a cost and not the source of income. And a medium company in the USA is a large one in many countries, a small one a medium one.
So the sum of devs in the long tail can be much larger than the sum of the devs in the top companies.
Fixed it with "at least not large tech oriented" because banks, supermarkets, the media industry, the entertainment industry, etc. employ a ton of devs, but they won't likely use Kubernatis for most of their stack.
Yep. We recently did an assessment of available UI libraries and pretty much concluded the best maintained libraries with a modern look and feel are all web-focused and we're likely to have to settle for building an electron app if we want to be able to take advantage of the best selection of 3rd party libraries without building as much ourselves. As much as I don't like the ecosystem or Javascript as a language, there's so much tooling around it and the libraries available seem to be miles ahead of other options. I'm hoping Redux and TypeScript can make it moderately bearable. Fingers crossed.
Seriously, what is there? Microsoft doesn't even have a clear direction for desktop apps - their most recent stuff like VS Code and Teams are built on Electron.
Hi, I'm a Redux maintainer. Note that we have considerably changed the Redux patterns that we teach over the last couple years to make it easier for folks to learn and use Redux. We now teach using our Redux Toolkit package as the default way to write Redux logic [0], and the React-Redux hooks API [1] as the standard way to work with Redux in React components.
We recently rewrote our tutorials from scratch [2], and offer an opinionated set of guidelines on how to write Redux code effectively [3], such as "put all Redux logic for one feature in a single file", "use feature folders", and "prefer putting logic in reducers".
We also now recommend some TypeScript usage patterns [4] that simplify the amount of types you have to write.
Finally, we are about to release a new "RTK Query" data fetching layer that will be in the upcoming RTK 1.6 release [5]. It's in beta now [6], and we're just polishing the docs before it goes live.
Hopefully this will help you and anyone else who's using Redux!
Just wanted to say thanks for Redux Toolkit and the hooks API - they were truly the key features in making me consider it a solid benefit with TypeScript integration in mind and getting the interest of colleagues who were less familiar with the ecosystem.
Yeah, one of the reasons we recommend the hooks API as the default _is_ because it's so much easier to use with TS. It's _possible_ to use `connect` with TS, but the typing overloads are a complete pain to work with. Fortunately, `useSelector` is just a simple function call, and `useDispatch` just gives you the `dispatch` method itself. Less abstraction, easier to type correctly, and easier to use.
Tbh if you're living in React-land and understand Redux, useReducer with useContext has subsumed the need for it in nearly all cases for myself and my team.
For the parts it doesn't match, truly global stuff or tonnes of mutation, MobX is nicer out of the box than Redux. Redux can be just as nice and in some ways more powerful, but thats only after installing and configuring X amount of middlewares, with all the type confusion that can add :(
Fortunately, you no longer need to "install a bunch of middleware" yourself - Redux Toolkit's `configureStore` gives you a good default setup out of the box [0], and we have TypeScript usage guidelines that infer all the needed state and dispatch types automatically [1]
It's also worth noting that there are some significant difference between `useReducer+useContext` and Redux. Not saying those are bad and that you should avoid them : ) just that it's important to understand the intended use cases and technical behavior differences [2].
You bet there’s a big difference! In my experience, too many teams misunderstood what Redux is excellent at, and made a mess of things due to that misunderstanding. In those teams, useReducer alone gets us 80% of the way there, useContext combined with a well constructed reducer solves another 10-15% — and for most of the projects I’ve worked on across different teams with differing skill sets, often 100%.
I’m glad to hear the Typescript inference issues I ran into a year, year and a half ago are solved. That wasn’t Redux’s fault per se, but composing middleware in such a way that the types flowed through correctly was such a hassle previously. Nice to hear it’s better now
Yep, my recurring theme is "take the time to understand the use cases and tradeoffs of the tools you're looking at, and pick whatever actually solves _your_ problems".
Btw, it is actually possible to use Redux Toolkit's `createSlice` API to create reducers just for passing to `useReducer`, even if you don't have a Redux store in your app - after all, reducers are _just_ functions. I've done this several times myself for cases where I wanted a well-TS-typed reducer with some complex logic in a plain React app.
And yeah, my co-maintainer Lenz Weber is a TS genius, and has done an amazing amount of work over the last couple years to improve our TS handling in a lot of cases.
Interesting, I did look at MobX briefly but pretty quickly concluded it seemed like overkill for our use case where Redux, Redux Toolkit and Thunk would pretty much solve everything we needed and seemed comparatively simple to follow, I'll definitely take a look into useReducer and useContext though, that looks like a potentially viable option for the majority of cases.
I've got experience with MobX (from about 3y ago) and more recent experience with RTK. I still feel that MobX is easier to reason about -- but RTK is a big improvement over vanilla Redux. /$.02
If you're building a desktop app, just plain C# in visual studio has an extremely powerful GUI (WinForms) that is fairly easy to use. Lots of widgets abs very good charts and graphs that you can zoom-in on and annotate in a million ways. It's miles ahead of Python (saying this as a Python guy). Click Once means installs are fairly simple (assuming a Windows deployment).
That's true, but it seems like WinForms is basically a dead end at this point, not much maintenance work is put into it and you have to jump through some serious hoops to make basic stuff like DPI scaling work even last I checked. Completely agree though, the 3rd party component story is very good on .NET, but the applications you're producing don't exactly have a modern look and feel unless you're investing serious UI design effort in them on top of things.
WPF (and whatever they've taken to calling the UWP version of it now) is a little more modern, and it's what I was initially leaning towards, but also doesn't seem to be moving much and it feels like the future is very unclear, while even MS themselves have started putting out Electron apps. It really doesn't breed confidence.
Coming off of an extremely disappointing Build - I don’t think any news even made it to HN this year, and not a peep about desktop - I agree that the future is unclear.
WinUI is the future, but they’ve admitted it will be years before it reaches the maturity of UWP, which is embarrassingly bad even 5 years on.
WPF, in my opinion, is the best choice for “native” windows apps. The actual best choice is Electron, as most teams doing new work at MS have noticed.
WPF, for native, hits the sweet spot of supporting newer technology (high DPI), having decent performance, and being well implemented; it has been solid for at least 10 years now. Also easy to style and theme, similar in concept to web, but just more annoying.
After being burned with their C++/WinRT reboot without tooling matching C++/CX after 4 years in the works, and the whole situation as you describe, I have decided to eat my UWP hat and just focus on WPF/Win32 in what concerns Windows desktop applications.
The migration wizard for .NET apps was a CLI script, really? In the land of "Developers, Developers,.." and GUI wizards.
Maybe if enough of us keep doubling down on Forms/WPF/Win32 and ignore the whole WinUI/Reunion reboot, they finally understand want we really want for desktop Windows.
I was too busy this week to watch any of the Build stuff, but it is surprising how it's basically just been crickets. I can't remember a year with less buzz about anything that Microsoft has queued up...
I dunno. Yeah it was declared dead, but still works great. We have an app some engineer developed to make his job easier that has probably 50 distinct charts in it. Each one is a SQL query that hits a database for a user selected time slot. It's used by over 100 staff now for analysis and building reports. Works great and is easy to support. I don't think we'd gain anything by making it an electron app. I've been pretty disappointed with those kinds of bloated apps, and I'm not sure if they'll ultimately last as long either.
Myself, I'd just build some command line script that hit up a database and pipe data to build a GNUPlot script and just generate a PDF report. That seems to be the best way to hook into a well maintained GUI project. It isn't sexy, but it's dead simple, should last forever, and be very simple to port to a different OS or language in a single afternoon.
And not being on the assumed target platform, I am grateful the web is seen as such a strong target. Either I'll get a solid in-browser experience or an Electron experience, but regardless I actually get access to the application. Android has a decent-enough story for PWAs as well.
Take a look at Sciter [1]. You build your UI using HTML/CSS/JavaScript, and your application logic in any language with a C FFI [2], and it supports Windows, Linux, Mac OS, and Android. The distribution size is tiny: only a single dynamic library of around 10 MiB. It's not open source, though.
Think of MS stuff from top to bottom as on maintenance, plus a little extra. Less investment than in the old days as foundational tech is becoming commoditized.
The focus and revenue is from cloud now, since MS has comparatively little hardware or advertising profits.
Develop desktop apps in something focused on it, such as QT. Flutter may mature.
I did look at Flutter but pretty much concluded that it was still fairly immature and didn't have great 3rd party libraries available for things like graphing and data tables (sort, filter, group, etc, with all the UI work done for you). This was a year or two ago so things may have improved since, but in React-land there's plenty of very capable and well maintained options in both the commercial and open source world.
Another big issue is the ability to seamless transition parts of your software between different programming models. We just don't have good solutions to this that I know of. The thing with SPAs is that you are probably worse off starting with a traditional server-rendered HTML web site and slowly introducing more and more interactivity, unless you know you won't eventually be better off with an SPA at the foundation (or unless you've planned and budgeted for that eventual rewrite).
React is actually great at embedding individual interactive components on a static HTML page (like an interactive chart or table component, or even a fancy button). You can go a long way just having your Rails app render a navigation menu and application shell, and each page just loads a big React component in the main content section. Great!
But then you need to update a little bit of that application shell in response to a visitor interaction or some newly-fetched data. Maybe one of your menu links needs a little red number next to it to indicate the number of unread messages. Still easy, with JQuery or whatever DOM manipulation library you're using. But then when the visitor clicks on one MessageRow component in your big MessageList React component and reads the message. The unread count didn't change! That's still easy to fix though. But pretty soon you're writing a lot of manual DOM manipulation code to sync every bit of data bidirectionally between every source of mutation and every UI element that depends on that bit of data. You'd be better off with an SPA, or at least with having React grow to own a little bit more of your application shell!
Where this line gets drawn is tricky, and I don't think the conclusion is "always use an SPA framework from the beginning of every web site project." But I do think the options to conveniently and maintainably use SPA frameworks to render traditional HTML pages on the server are improving a lot more than the options to gradually introduce whole-page-level interactivity to traditional server-rendered HTML frameworks.
This is why NextJS is so compelling; if you want to create an SPA (just like with create-react-app), it can do that. But with built-in 0-config support for SSR and SSG, you can pick and choose where and how data-fetching and rendering happen (client or server, at build-time or request time, or any hybrid combination), using one language, one paradigm, one framework. IMHO it's the obvious foundation for any greenfield (or brownfield) React project.
I've been building web-related things since 1998, and IME NextJS has the best DX and most flexibility of any framework I've encountered.
agreed. it's so in tune with the developer/web ecosystem of 2021. the fact that my React SEO landing pages are pre-cached and served by a CDN with so little config required is slightly magical.
The problem you describe is a data modeling problem, its because the same data comes from different places and is stored on multiple places, where each change triggers many changes. Its like like programming using only global variables. The solution is to have one directional data flow rather then bidirectional. UI should only listed to changes- not mutate data directly. Instead UI input should be sent to a client/server data store that in turns trigger the listeners.
React can work really nicely with different parts of the DOM via Portals however!!
Portals are awesome for use cases where you're sprinkling dynamic bits into an SSR'd shell. And for all parts of your app that don't need that level of interactivity, you've got plain old templates in your server side language of choice.
There's some limits to this but it's a neat trick.
The web components and the pending state protocol is one of the things I which more people would know about. Listen for change events bubbling up and push down changed values. This does not only apply to single data fields but the entire DOM tree.
I see a big difference between Hadoop and React though: React pushes the costs on the client. This is something that's not often mentionned, but with a traditional SPA, a good part of your code runs on the client, which is server costs you don't have to pay. I don't know if it's something that people do consciously to reduce costs and just never talk about, or if it's an unintended consequence, but it's here. If your React app is too slow/unoptimized, the client will pay the cost, not you. If your Hadoop cluster is too big/not efficient enough/not useful, you're directly paying for it.
The "server cost" of traditional SSR is heavily overrated. It can be made small enough to be basically a rounding error compared to everything else your backend is doing. Even more so since retrofitting SSR onto a JS single-page application is quite inefficient, so you end up paying for that load many times over.
This is only sometimes true. Other times, cutting the server rendering makes things a million times easier because maybe you're not contacting your database, or you're offloading large per-user objects to the client instead of keeping them in ram for thousands of uniques per minute, or, or ...
Some calculations are less heavy on the client side. It's not building the html itself once you know what you need that is heavy, it's that awful dropdown menu with dozens of nested filters that rely on user-input data which is awful to build serverside, but incredibly easy to build client side.
> because maybe you're not contacting your database
Except you will anyway, to do all those API queries you need to fill the page. That involves multiple handshakes back the server, and yet more server-side resources tied up.
> or you're offloading large per-user objects to the client
This access happens either way, and will be discarded in short order by any cache, even using the most naive LRU policy.
If the state is coming from the server-side database, and has to be persisted there, you'll still need to fetch it, and save it. If there's some transient state that belongs to the web page, vanilla JS is just as capable as a SPA at managing that - and it's just as prone to losing unsaved changes.
Not really. If you have to make database queries in order to display the page, there's no way of getting around it. Even if your webserver isn't in a cluster with your API and database, while you might be sharing the load between your servers, it's still server load that needs to be accounted for. And if it is in the same cluster, probably cheaper to make those fetches from your webserver than to have multiple connections, in addition to those database queries you're going to do anyway.
You're still making assumptions. Some stuff is harder to calculate server-side, period.
For a very simple example, I'm currently replacing a SSR feature that takes a list of items and renders a "screenshot" of them. The screenshot has to go through PDF rendering, conversion to JPG, it's insanely expensive.
I'm replacing it with a client-side generation of an SVG, and in-browser conversion to PNG. It's very clean, very fast, simple to do, cheap for the client, takes less time than it would to even download the original.
(Keyword: Currently. This isn't a hypothetical scenario, this is a real-world instance of replacing SSR with CSR)
Firstly, thanks for providing an explicit criticism to the argument. It's more helpful than a dismissal (or an inexplicable downvote), and it's appreciated.
As I see it, the subject of the OP, and this broadly this thread, is about the downsides of using SPAs (e.g., React) vs SSR for applications that require server-side persistence. Of course, pre-processing (or display post-processing) client-side makes a lot of sense. Such client-side offloading doesn't require an SPA, and also it can be part of an SSR driven application (as you are doing) using vanilla JS. So the distinction here between SPA and SSR is moot.
The cycle of data retrieval -> user transformation -> data persistence to server, is where SPAs vs SSR have actual tradeoffs. And this, I believe, is what zozbot234 was alluding to. As for Hadoop, I don't personally know how that fits into modern web apps.
React optimization problems are more than just CPU; React encourages lots of little requests in such a way that no amount of computing power can tackle. Coupled with other flawed but popular design antipatterns like skeleton screens, performances is abysmal. Not just long page loading times but browser and machine freezing slowdowns.
BitBucket and Jira have gotten so much worse since they moved to React. With all my computers resources at its disposal, it takes longer now to load a single jira ticket than it did when it was all handled server side 10 years ago. If you look at the chrome debugger, its no wonder why. React fans can stand back, cross their arms, and explain about how atlassian must be doing it the wrong way, but it seems pretty consistent behavior across many react apps.
I think this is a good assumption, but it breaks down when you look at bandwidth costs. A large reason why these apps take so long to load is because of the kb of dependencies and bundles they have to download. That adds up quickly with many visitors, and there's practically no way you would be accruing the same amount of bandwidth costs with a bland PHP or direct HTML response.
You think heavy HTML responses are cheaper than one extra-heavy initial JS request?
I'd like to see some analysis on that. I'm assuming if you're building an SPA or any kind of app, many of your visitors and clicks are repeat visitors and won't have to download that bundle... probably once a day, M-Th assuming daily release schedule w/ lets-not-break-it-before-the-weekend policy.
I think all that client-side caching would outweigh the cost of the initial bloated bundle.
> many of your visitors and clicks are repeat visitors
I think this isn't a guarantee and depends on what kind of application you're trying to build. A DMV website is (hopefully?) not going to have many users returning every day or even every week or month. If it's not social media or gaming, it's probably not going to have any sort of consistent userbase, so most visitors are not going to benefit from client side caching.
> You think heavy HTML responses are cheaper than one extra-heavy initial JS request?
If we assume "cheap" means cost-wise here, almost certainly. Consider a search engine like Google. If you are generating HTML server side (ex. PHP), the row count is limited by whatever you assume the user's screen resolution will be. That means a few hundred results returned at most, since no user is going to scroll through thousands of results on the same screen. So you perform a DB query and generate the HTML for a hundred rows or so and return it, job done.
Now consider the JS equivalent: the user downloads up to a megabyte of bundled JS. Then, the JS has to perform a fetch call to some API which probably returns the rows in JSON. At last, the client side JS iterates over the JSON and generates some new DOM elements for each row. Job done.
In the JS example, the user's browser had to download the bundle and the API response in order to render the rows, while the PHP example only queried the DB in order to render them. You might think, well the PHP way still uses up bandwidth to get results from the database right? Which is technically true, but pricing wise your database is most likely in the same data center as your web server so you're not paying anything for that bandwidth (since it's going over a physical direct connection cable instead of the Internet proper). Whereas the user is 100% not going to be in the same data center as your API server, so you're going to get whacked with bandwidth charges wherever your API is hosted on top of serving the JS bundle.
Of course, for the majority of people we're talking about pennies here. It really doesn't matter until you start getting more than 1 request per second, at which point every hour of every day of every month of every year is going to compound your bandwidth pricing problem until you figure out a way to slim down your payloads. Or, just do what most news sites do and keep adding third party advertiser JS until your ad profits outweigh your bandwidth expenses. Lots of options in this brave new frontier!
> If your React app is too slow/unoptimized, the client will pay the cost, not you
For the client the experience is worse and the cost is higher, so it's definitely a worse solution. SPAs really only make sense when you have a mostly offline application, which is just a very tiny bit of websites out there.
I don't know if it's something that people do consciously to reduce costs and just never talk about, or if it's an unintended consequence, but it's here.
It's very deliberate. It's even what is taught in colleges.
I've had debates with recent graduates who believe the proper way to build anything from a web site to an app is to offload as much of it as possible on the client. If the client doesn't have the latest gear? Too bad. They're an "edge case" and shouldn't be allowed to be on the internet. Go curl up in a corner and die, you old and poor people.
The tech world would be an entirely different world if ethics were part of the required curriculum.
I'm genuinely not quite sure what you're talking about. What remotely significant costs are being transferred from the server operators to the client? An SPA without SSR still needs to server a bunch of static data to the client (the JS app bundle). It also needs to look up and return any dynamic data the client app subsequently requests. The only actual computation being moved is the generation of HTML/DOM markup from the server data, and I can't imagine that being a remotely significant amount of computation except in some pathological examples like extremely large pages or extremely intensive computations required for rendering (like, I don't know, maybe some geometry visualization tools or something?)
You don't offload things to the client in order to save money. You offload things when it will improve performance. Most of the processing power and bandwidth will still be incurred by the server, just at a different time in the lifecycle of the app.
If your page takes 3 seconds to show anything at all, your bounce rate will be stupid high.
If your page loads nearly instantaneously with placeholders, and then the content loads in over the span of 4 seconds. Your bounce rate will be significantly better.
Even though your page loads slower, it will be perceived as faster resulting in less users navigating away before your page starts rendering.
Perceived performance is only one factor but there are many other reasons why you offload things to the client.
In my experience it is definitely talked about. Most clients are pretty powerful these days so if you can save backend compute power by e.g. returning a redis cached table and then sorting the rows on the front end without bogging it down there isn’t a good reason not to.
I think it's mostly a tradeoff for having a more developer-friendly abstraction. If React only offloaded computation and didn't make complex UIs simpler to write, it wouldn't be anywhere near as popular.
I see this a lot. Especially with languages - of course I would love to write a big app in Haskell, but the tooling for Java / JavaScript / C# is just so much better (before Swift / Kotlin it was so much worse).
And what is happening with React is just like what happened with those languages: all of the big drawbacks are getting their workarounds. Bundle splitting and server-side rendering address large bundles and long load times, as the author mentions. Of course they have their own issues, but as time goes on I'm sure more workarounds will be created.
I wouldn't be surprised if in the next 5 years, React's drawbacks don't fully go away, but they're a lot less. Although I'd rather like React gone too, personally I really don't like using it.
A more specific search, e.g., "single page", will not redirect.
In some ways, for discovery, Wikipedia's search engine is better than Google's. For one, it is non-commercial and does serve ads based on past surveillance of the user's activity. Second, the user can retrieve larger numbers of results and page through them quickly without triggering a (false positive?) defensive measure than temporarily blocks her IP address from retrieving results for a defined period. Third, it is curated to remove commercial content rather than curated to further a business purpose in online advertising.
No wonder Google steals Wikipedia content for "instant answers" or whatever they call it. Wikipedia search works quite well.
In that sense Wikipedia is a bit like Google in that they try to guess what the user is searching for, perhaps what is most popular. Thus, a search for "SPA" automatically redirects to the article on Spa as in therapeutic water treatment. A link to the Disambiguation page, if it exists, will always be provided (cf. "Did you mean ....").
However, change the search string "spa" to something more specific and then see all the search results.
There is a name for this kind of phenomenon - Inadequate Equilibria - why civilizational scale failures can still occur even if every actor is doing things as efficiently as possible.
In my opinion, it's that 'most not widely experienced but SPA focussed developers read about SPAs'. I think the issue is your search filters or other filters that have created a knowledge focus bubble in your life.
The hadoop thing is so unusual, really strange. I'm fairly certain, to very certain, that Sql is the industry standard while hadoop is a small corner of the mindshare.
Perhaps it's time to widen your sources, and e.g. cycle through different browsers to reduce search profiling.
I agree with your logic but not the premise; wrt React and SPAs in particular, thankfully NextJS has emerged as a robust React-based framework encompassing every kind of rendering mode (SSR, SSG, ISR, CSR/SPA, hybrid) and architecture.
Which is good as long as you're only building just a frontend. Or a landing page.
The moment you need to integrate it with server side validations, authentication, add a database, migrations, background jobs, etc. it becomes a mess. In fact, a custom undocumented mess.
This gravity is probably the fuel of society, it's hard to avoid its negative side effects, it's a natural positive feedback loop.
Just like finding beer money by making a youtube channel on trendy topic.. the short term effort/reward is higher than doing quality stuff (or even finding a better job, which can be hell) and this web being the trend, everybody will be nice to you if you want to make a youtube channel..
"Newgrads were trained in hadoop. New tools were Hadoop first. New research was all hadoop."
Reminds me of a job about four years ago: New hire, right out of college, "I studied Java". Surprise! Your team is PHP! Now learn that without any help from your team leader or we're gonna fire you. And they did. Poor kid.
I've been happily using MySQL for over 10 years and have never seen a reason to switch. Happy to have avoided the NoSQL craze. There's been like 1 or 2 queries where SQL has been suboptimal but nothing insurmountable :-)
The amazing part to me is that SPAs are so much harder to do right compared to old-school server-side rendered HTML. One could be forgiven if they think a "simple" SPA is a good starter project, but they'd be very wrong. Async programming (Javascript Promises and/or async/await) is difficult, error-prone, and should be avoided whenever possible. On top of this, understanding how data flows through these SPAs is no small task.
Compare this to server-side rendering where you run some DB queries, generate some HTML based on those results, and send it to the browser to be rendered.
There are some cases where you actually need a rich experience in the browser. In those cases, I would start by seeing if plain old Javascript would work.
In writing this, I definitely feel like a "get off my lawn" guy. But I've just seen too many junior and senior engineers (me included) fall flat on their face trying to use these SPA frameworks.
It's absolutely possible, dare I say easy, to do old school SSR wrong.
You start with an honest to god html file. Your IDE lints it. You are happy, life is easy.
Then you need a second page. So you copy some things over. Then you need a third page, and it becomes apparent that you need a way to share parts of your html pages across multiple files, in a generic way.
And kids, that's the story of how I met your templating system.
ALL of them suck. ALL of them are incredibly hard to lint, test, get right. They scale badly. They're all awful.
It's easy to get things wrong in that world, because nothing gets things right.
There's kludges of course, things that generate html entirely programmatically from their own language, or some weird abstraction.
These all suck too. You have to learn new languages, or weird shorthands, or at best new APIs. None of them truly took off either so the tooling is poor.
You know what's a language that already has tons of tooling? JavaScript.
You know what's a robust API for building HTML that you already know, that is already supported by virtually everything? The DOM.
And you know what's a markup language you already know and can intuitively parse without having to learn new things? HTML.
> And kids, that's the story of how I met your templating system.
> ALL of them suck. ALL of them are incredibly hard to lint, test, get right. They scale badly. They're all awful.
That's not really true. But fairly incredibly, it seems relatively little attention has been given to the design of HTML templating languages (certainly there are a lot of them, but most seem to have accreted rather than been designed).
Anyway, the least weird templating language that was designed that I am aware of is the TAL[0] syntax, which has as it's main constraint that unrendered templates must still be valid HTML. The original motivation for this was to eliminate the terrible workflow problems of round-tripping templates between a web designer and a (backend) developer, but there turned out to be other benefits, like taking care of linting difficulties. It is also rather deliberately not Turing-complete, as that has proved an 'attractive nuisance' that causes more problems than it solves.
The TAL syntax is most strongly associated with Python frameworks (I would guess that Chameleon[1] is the most popular implementation), but there are implementations for most prominent languages[2].
> You know what's a robust API for building HTML that you already know, that is already supported by virtually everything? The DOM.
How popular is SSR in JS using the DOM directly, rather than a template language of some sort (eg. Handlebars, Jade, Nunjucks)?
Thymeleaf templates are also valid HTML when not rendered. Of course you still have to put some thought into them to make them believable, by e.g. providing placeholders for elements that would be rendered in cycles.
Yeah, I find Thymeleaf to be nice, especially when coupled with Spring. I'm always happy when we decide to use it instead of bloating everything up with a separate Angular application.
If you have some other way of being able to view an unrendered template in a browser and have it display sanely, I'd be very interested to know about it.
> ALL of them suck. ALL of them are incredibly hard to lint, test, get right. They scale badly. They're all awful.
Hard disagree.
Lisp family of languages have tree templates that are easy to lint, test and get right. They also scale as well as- or better than React.
Lisp has had 50 years to catch on, and unfortunately, it has not had the uptake a lot of its proponents would like. I think part of this is the different mental model you need to build around programming when you use these family of languages.
To extend your point, I think the linked article suffers from a common trend in web dev editorialism, which is over-generalisation of problems, and reducing the domain into simple binary thinking.
A lot of these arguments talk about the dangers of SPAs, but don't talk to the reason why first class interactivity/reactivity exists on the web. It's because for average users, they want to see feedback to their actions immediately. Articles like this talk to SPAs as if they are unnecessary or overused. I disagree, I think SPAs are mostly appropriate for most SaaS, social media, or business tooling. Sure, the poorly implemented version of an SPA is harder to debug than a poorly implemented template generated site, but that's like comparing the complexity of a car built in 2021 to a car built in 1980. And cars from 2021 sell better than cars from 1980.
A lot of these articles strike me as opinion pieces decrying the direction of modern web development, and seem to point to the past as a more 'gilded age' of internet browsing. But this was back when users sat at a desk, and scrolled pages using a analog mouse, viewing it on a CRT monitor. Users today want to browse on their phones, want to share and upload, to take live videos, to see when their message was sent, delivered and read. We need SPAs and libraries like React just like we need cars that can do lane assist. It's because it's a feature users want, and on the whole, it is much easier to build using React and SPAs.
But in the wild, on end user machines, many times the SPAs perform worse/slower than SSR ¯\_(ツ)_/¯
And users don't actually want SPAs, users don't care how it's implemented. But users want performance and reliability, and want their pages to feel natural and work fully with all the features other sites have. Anecdotally SPAs often load slowly, break subtly standard web features, and often are slow to use.
Not all SPAs, but a significant amount of them.
As someone who's fluent with SSR and SPAs (react/vue), who consults in the enterprise space, I reach for SSR solutions, about 2/3+ of the time as the appropriate architecture. Of course ymmv but you need to be fluent with all the options to be in position to pick the best tool for the job!
> Async programming (Javascript Promises and/or async/await) is difficult, error-prone, and should be avoided whenever possible.
Whaaat. Async/await/promises is trivial. JS is still single-threaded so you don't have any of those annoying threading issues.
Where it gets a bit wonky is when you apply it to the UI because you have this extra state you need to worry about. After the user clicks something, but before you get the results back from your server. You have a loading or saving state to deal with. But React mostly makes that trivial too.
SPAs get hard because of all the reasons listed in that blog post. They're incredibly hard to optimize properly.
And for that reason, I don't disagree with your first sentence. If all you're doing is worrying about 1 page at a time and shipping some HTML, you're golden.
Perhaps you've been luckier than I have in your experience with Rails and Django codebases! I have seen a tremendous amount of "not doing it right" and "architecting things in such a way that it makes it nearly impossible to 'do it right' when adding or changing any behavior."
With any of the popular React server-side rendering frameworks, getting up and running with a basic web site with some pages and HTML content is not significantly harder (and in fact not that different at all) than doing the same in Django or Rails.
I have to agree. I'm a OG Rails dev looking and constantly compare the productivity of old school SSR sites compared to current complex SPA frameworks. People how tie themselves in knots, the UI interactions are tricky to get right, more places to code, then second guess the frameworks, then try it again. SSR Rails apps just had 3, maybe 4 places to write code - controllers, models, view folders - you can flip back and forth in blinding pace, and get your app up and running really, really quickly. Yes agree there's some places SPA's are really applicable. But watching an app get built that you see no distinct advantage for either end user or dev team makes you wonder.
As mostly a user that doesn't develop web apps anymore, all this feels very true to me.
I'm soooooo sick of interfaces that load an empty useless shell of UX chrome and then slowly trickle in content at some later time, and leave spinners, or even worse, gray boxes simulating text.
Send the text content in the initial reply, please! It's bad enough having to wait for webfonts, but when you wait to start doing the slow database query for content until after an html shell has been loaded, and after a huge JavaScript bundle has been parsed and executed, you're just wasting time. Reminds me of the Google Web Toolkit of yore. We really haven't progressed much in the decade for single-page apps since then, when it comes to the user. And that's a horrifying thought.
I liked the overview i remember myself having 15 years ago, today there's a new library/API/service to learn everyday to keep even the simplest things working.
Everything is sluggish, everything takes ages to load, to compile, to understand.
Also simple web apps i try to prototype takes ages to make and debug. Anyone else feel this?
It's like something always goes wrong with some dependency, some build process, some versioning error, some service, so you end up using 95% of your time setting up services, reading manuals, and debugging instead of coding which was simpler in the just-post-spaghetti days of web-dev.
I don't know if it's feasible yet but i hope switching to less technologies with more mature JS/CSS and a few minified libraries run locally will work out for me - harder with teams of course.
I don't know what's a good simple backend with the same philosophy, Laravel Lumen maybe? I feel like you need some layer above sql unless you wan't crazy complexity - or maybe a simpler database / api system.
I want the simplest system possible! (who doesn't)
What's happened is the philosophy has been that more layers allows less experienced developers to write business systems. This situation with layers on layers of cruft is the result of that.
Probably true, but for me it's sucking the fun out of developing.
I like optimisation, removing stuff, making to code shorter, clearer, faster. Small neat pieces that are fun to write, like little machines working together.
That to me is the beauty of coding, just as in music, design etc.
The meticulousness, the creativity and the dogmas you set up for yourself is what makes it exciting and fun - it doesn't have to be perfect but at least you "know the code", and can look at the little machine that you built.
In framework/service hell, you have zero idea what's going on. It's like directing an orchestra on the other side of a valley, or clicking a button to create a painting instead of painting.
This is one of the worst UI trends in the last decade. Mock content gives devs permission to ship slow APIs, and they can even look janky when your API is too fast. It feels like watching a half hour of trailers before the movie starts.
Well, they definitely don't solve the problem for the user, as the grey boxes inevitably aren't the same shape as the content that eventually appears, and the jumping around is still there. Text fields are often variable length and can reflow. Buttons are also frequently dynamic, and all sorts of widgets may not just line up. Sometimes, incomprehensive design changes cause further disalignment between the skeleton and the actual content.
It's sad and funny that the YouTube app seems to have just recently jumped on this bandwagon (either that, or the situation worsened so much that I started noticing how bad it is).
And I can't even count the number of web sites (from companies with plenty of engineering budget!) that render the gray placeholder UI, but when the real data comes in, it doesn't even remotely line up with the placeholder UI (which is the whole point). I totally get how it happens: the placeholder UI and real data UI isn't sharing code, and just relies on dumb luck that the next person who changes the real data UI also changes the placeholder UI to match it.
Easier said than done. When you have to load a number of components, each with possibly multiple rows within them, it can take awhile to pull all the data and it is better to break them into a bunch of smaller backend calls that can be cached as needed than trying to return a single json object containing all the data needed to be displayed on a user generated app.
That seems like a good excuse for when there are multiple lists of things, but when it becomes the standard behavior for pagination of a single table of 10 rows, it's ridiculous.
> can be cached as needed
For requests of < 30kb, client side caching has very few benefits. If it's a slow database query, then hopefully the server side is caching something to lessen load.
> trying to return a single JSON object
Certainly there are some cases where JSON might make sense to return to a browser, but the cases that I'm frustrated by should never be serialized as JSON when sent to the client, and should be sent as tables or other HTML. Having JSON transformed by JS as the only method is displaying data feels like the fundamental architectural error that is degrading the web for users.
All these years later, huge advances in compute and bandwidth, and in many ways that good 'ol 28.8k modem in a Penguin box was as responsive.
Both caching and json I’m referring to as coming from the backend, not going to the browser from the frontend. I’m saying you break out large data objects (from the backend) into multiple calls and then render them as they respond so you can then see which ones are slowest and should be cached (on the backend.) I get what you’re saying about loading screens for a few rows but I didn’t think that’s what we’re talking about.
It's like all of these posters have never worked on a large-scale app, acting like the decision to lazy load content is made just because we don't have anything better to do.
That's what the goal is, and that's what SPAs enable. You can't build a modern web app without it being a SPA. The two are basically synonymous, I don't understand how there is even a discussion around this. No user wants to navigate to another page and lose their context. That's why the industry moved to SPAs. If you ever tried to manage complex UI state in the jQuery/Backbone/Knockout/etc days you would see that a React SPA is a huge improvement. It actually enables devs to build complex apps without getting bogged down in bugs.
> The two are basically synonymous, I don't understand how there is even a discussion around this.
This erroneous belief is the very source of the problem. Here's a user, telling you that I'm sick of lag from weird multistage loads in apps that gain nothing from keeping local state in browser JavaScript variables.
I have never, literally never, thought that a good experience came from a SPA. Give me HN and it's 2000s dead simple tech any day. Or compare the absolute shit-show of new Reddit in an SPA to old Reddit.
As a counter point: were I to write a hacker news clone it would be an SPA. You wouldn’t know from using it, because I’d break it down into routes using e.g. react router (but that’s really just for organizational reasons) and it’s simple HTML and plain text so there’s really no need to have loading screens. An SPA doesn’t have to be bloated and show loading screens and the aforementioned grey boxes.
I’ll also add that Reddit’s problem doesn’t stem from being an SPA, it still loads state, etc from url navigation just as much as it keeps the state as you browse (depending on where you go on the site.) Reddit’s problems stem from (for some reason I can’t fathom) being the worst UI implementation I’ve had the displeasure of using recently and constantly adding features (before bugs from the last round of useless features are fixed) in an effort to converge towards some kind of weird Facebook clone.
> Here's a user, telling you that I'm sick of lag from weird multistage loads in apps that gain nothing from keeping local state in browser JavaScript variables.
You do realize the alternative is the same amount (or more) of waiting with a blank screen, right?
> Or compare the absolute shit-show of new Reddit in an SPA to old Reddit.
You are conflating bad design / UX with SPAs. You can build a SPA that is exactly the same as the old Reddit. Reddit is trying to monetize their site, many of their shitty UX decisions are done with that goal in mind.
> Managing complex UI state is the problem.
...What? Unless you are talking about stripping web apps of their functionality, you can't avoid this. You will have complex UI state. It's just a question of whether you use some shitty, convoluted approach of the olden days, or you use a modern solution that makes this faster and easier.
Anyways, you do realize you are in the minority, right? Most users have an expectation of how modern web apps should function. Redirecting a user for simple tasks doesn't cut it. If SPAs didn't provide a better experience, and in turn, better conversions, companies would not adopt them.
> Frameworks should lure people into the pit of success, where following the normal rules and using normal techniques is the winning approach.
> I don’t think that React, in this context, really is that pit of success. A naïvely implemented React SPA isn’t stable, or efficient, and it doesn’t naturally scale to significant complexity.
It is a pointless generalization. Not every React SPA is the same. Some scale, some don't. Some use server rendering, some don't. React may be a perfect fit for your app, or it may not. It's not like a "naively implemented" app using vanilla JS or server templating or any other framework will be automatically fast and scalable. Quality of input = quality of output, regardless of what abstractions you decide to use in the middle.
Every "<technology> is good/bad" article eventually reduces down to an internet flame war ignoring all nuance.
I thought the original article had a lot of nuance, actually, and did a good job describing where React reasonably fits in the scheme of things.
I would argue your statement that “every React app is different” is part of the problem. There are so many react apps that are essentially the same but each one is implemented with some bespoke cocktail of parts because React isn’t really a framework, and it doesn’t solve the “rest of the app.” This isn’t inherently a bad thing, but it contributes to the general confusion and churn that had made front-end engineering significantly harder and less fun - at least in my experience - over the last 5 years or so.
I would say the popular server-focused frameworks that came before suffered from complementing problems which also did not lead to a pit of success.
Namely view code (HTML/CSS/JS) was harder to compose in a scalable fashion, Rails'/Django's template composition feels vastly inferior to proper componentization. Namely limited type checking, globals sharing, ... These things do make it harder to refactor and get rid of unused code, which also has real impact on users.
Another biggie was that there is no great gradual path from server-code to client-code, with potentially additional data. Now React SSR does make you work more for the server use case, in that you tend to write code which should also work on the client-side (which might change with React Server Components) but at least you don't have to face lots of decisions when expanding the interactivity of your app.
All that said, I also agree with the blog that there is still lots of refinements to be done on the React side of the world, I just view the world we came from as far less rosy.
React is famously not a framework though. Next is the relevant example here, which actually does work to address a bunch of the complaint points, including doing full page reloads when you’ve deployed a new version of the app.
I would define a framework as something that offers a high level abstraction, promotes best practices and takes care of a bunch of boilerplate stuff for you.
React doesn't do that at all. Next, Blitz, Redwood etc, do.
- It "calls you" (i.e. you never explicitly call your React components, React does)
- It permeates your codebase (e.g. migration from moment to date-fns is something you can realistically do piecemeal, React to Vue or vice versa not so much)
- It enforces a specific architectural paradigm (components) to the exclusion of others (e.g. MVC, MVVM, etc)
- Its direct competitors are frameworks (Angular, Vue, Backbone, Aurelia, Mithril...)
- it is composed of multiple libraries (react, react-dom)
- Experience in it is considered a primary hiring criteria in many shops (which typically isn't the case for libraries)
Almost everything in your first few points there depends on how you choose to use React, though, rather than being inherent in the library itself.
It "calls you" (i.e. you never explicitly call your React components, React does)
The starting point for doing anything with React is where you call it to render a certain component at a certain point in your document. There are things built on top of React, such as Next.js, that add more layers and do follow more of a framework design, but even there they are still calling React when they need to rather than the other way around.
It’s true that React provides features can automatically trigger a rerender later on. You don’t have to use any of those, though.
There are also integrations with many other libraries, such as those for managing state in one way or another, where the library can trigger rerendering of specific React components when relevant state changes. In this case, it’s the library calling React rather than React calling out.
Another alternative is the original React “philosophy”, simply rerendering the entire tree whenever you need to and letting the VDOM mechanism and perhaps a few helping hands that avoid unnecessary rerenders in your components keep this reasonably efficient. When to call into React for a rerender is entirely your own choice.
I suppose you could argue that React operates somewhat like a framework because it calls the render function for each component, but to me this is more analogous to a generic sorting algorithm that calls a comparison function I pass in when it needs to. It still doesn’t do anything until I call `sort`, and the code I write is still what decides the overall control flow for the program.
It permeates your codebase (e.g. migration from moment to date-fns is something you can realistically do piecemeal, React to Vue or vice versa not so much)
It is possible to use React only as a convenient rendering library and keep other responsibilities like state management and communications separate, just like any other software.
Some people choose not to do that and instead write React components that manage state and call remote APIs and cook you breakfast in the morning. Whether this strategy is wise is a different question.
I’m working on a new front-end using React right now, and even at an early stage when presentation code is a large part of what has been written so far, maybe 1/3 of the code even knows React exists. I’ll be surprised if that figure is even 20% by the time we launch. Even now, we could drop React tomorrow in favour of any other rendering code, and nothing would need to change in the code that handles our data model, diagram layouts, communications with our back-end APIs, etc.
It enforces a specific architectural paradigm (components) to the exclusion of others (e.g. MVC, MVVM, etc)
Components are just a way to build a rendering hierarchy: data in, DOM out. Nothing about that forces you to adopt any specific architecture in the rest of your application. Again, some people do choose to put other responsibilities within their components, even using React components to model non-presentational aspects so almost their entire front-end architecture becomes one big tree of React components, but you don’t have to do this and then deal with all the problems it potentially creates that you didn’t otherwise have.
> The starting point for doing anything with React is where you call it to render a certain component at a certain point in your document
You're trying to use the literal meaning of "you call it" to make an argument but that argument doesn't support the position you think it does. Yes, React has `ReactDOM.render()`, but did you know Angular.js also has an entry point called `angular.bootstrap()`? Vue has `new Vue()` and Mithril has `m.mount()`. In all of these frameworks there are various callable APIs, but that fact doesn't oppose the fact that your React component code is called by React, not by you.
> It is possible to use React only as a convenient rendering library
This is also possible with Vue, Hyperapp, Choo, Mithril and many other frameworks.
> Nothing about that forces you to adopt any specific architecture in the rest of your application
Again, same can be said about various frameworks. You don't need to use Vuex. Lichess uses MVVM w/ Mithril. Etc. Ultimately, componentization offers a prescriptive organization pattern. Nobody complains about React code being spaghetti like they do about jQuery, and for a good reason (sagas and other auxiliary libraries aside)
I would say the traditional distinction between a library and a framework, to the extent that the industry has any settled definition for these terms at all, is about who dictates the application architecture and the control flow.
A framework typically establishes a runtime environment and then calls into your code to respond to specific events. Common examples are GUI applications that run an event loop responding to operating system events and web servers where the entry points to your own code are handlers for different requests. In the early days, JavaScript was mostly used similarly, as the entry point to your own JS code tended to be a specific event on a specific DOM node. There might be some code to set things up when your program starts, but once you hand over control to the framework, it decides what the run and when, and your code doesn’t do anything unless the framework asks it to.
A library, in the not-a-framework sense, works the other way around. Your own code ultimately has control and you call into the library when you require specific functionality. The library doesn’t do anything until you ask it to.
So to answer your question, yes, I did know those things, but I don’t think the equivalence between those calls is necessarily appropriate in this context. It’s not just about who calls the function the first time. It’s also about what happens next — whether your own code continues to call the library in a similar way later, or whether you hand over control to a framework once and that deals with everything from then on. Calling ReactDOM.render doesn’t have to be a fire-and-forget operation; it can simply perform a single render and then return having completed its task. You might then call it many further times to rerender that part of your page in response to changes in the data it depends on.
Control will often flow back and forth between your own code and library or framework code. Sometimes this happens on a small scale, like the sorting example I mentioned where you are calling a higher order function and it takes a simple callback function as a parameter. Sometimes it happens on a much larger scale, like calling React to render a component you supply, and then React calling that component’s own render logic, which in turn calls back into React to create child components, and then React calling their own render logic, and so on.
You can certainly argue that the latter starts to resemble a framework, but if you’re only talking about rendering a component tree that is triggered by a call from your own code and returns control to your code again once the rendering has finished, the difference is merely a matter of scale. Surely everyone would agree that the sorting example is a library call, so where do you draw the line? The overall architecture of your application and its control flow is still determined by your own code.
You certainly can use React more like a framework, in the sense that you call into it once to set things up and then hand over control. You can write components that have additional responsibilities like maintaining your application state and fetching data from remote APIs, and you can use hooks (or class-based component state and lifecycle methods) so that interesting events from those other sources will automatically trigger a rerender.
My point is that you don’t necessarily have to design your application in that style just because you’re using React. If you choose not to, then React doesn’t “call you”, it doesn’t permeate your codebase in the way you described before, and it certainly doesn’t exclude the use of architectural patterns like MVC or MVVM.
I don't think it makes sense to say "React is a library because you can forego using enough of its features to fall below some arbitrary line". By that logic, I can include Ember in a page and not use any of its features other than `console.log(Ember.VERSION)`, and voila, "it doesn't call you", "it doesn't permeate the codebase", "it doesn't exclude any architectural patterns", therefore it's not a framework. This line of reasoning clearly culminates in reductio ad absurdum.
IMHO, it's more fruitful to ponder the possibility that certain projects are not frameworks because they fundamentally lack something that frameworks provide. Suppose we tried to use nothing but lodash to implement a web app. It's certainly doable (given that people write vanilla apps), lodash would "permeate" the codebase and it would probably call a sizable number of your callbacks. But I think we'd both agree lodash is not a framework. But why? I'd argue it's because organizing units (in the "unit test" sense) coherently in a way that is maintainable is outside of its expressed scope. In other words, it's not suitable to that task, even if we wanted it to. React is not only suitable for it, it's specifically designed for that purpose.
Speaking of units, another way we can approach this is by looking at where unit boundaries are in comparison to user code boundaries. If you look at any usage of node's `child_process` API, the event handler functions are generally not considered units; the entire child_process instance setup might be one unit, and the event handlers may call other units that are ideally decoupled from whether callback arguments are partial Buffers or error codes and so on. Similarly, a sorting callback is not typically a unit (i.e. you never test that the callback returns 1 or -1, you test that the code sorts correctly instead). React components on the other hand are units in and of themselves. I believe it is accurate to say that frameworks provide abstractions whose purpose is to delineate where a unit boundary is. Components fit that bill perfectly, just as controllers and views and services do in other architectures.
I don't think it makes sense to say "React is a library because you can forego using enough of its features to fall below some arbitrary line".
Please note that I’m not arguing that React itself is or isn’t a framework. I’m simply saying that it can be used in multiple and qualitatively different ways, in contrast with your own position in the comment I originally replied to.
In particular, nothing stops you from using React only for what it’s really good at: providing a declarative way to specify the required rendering behaviour, with reasonable modularity due to the component system and reasonable efficiency for many practical applications due to the VDOM. This was the combination of ideas that React popularised within the front-end web development community, the innovation that moved the goalposts in that part of the software industry. You can also use other libraries for what they’re good at, whether that is state management or accessing remote APIs or doing a fuzzy string look-up to power a search box. And you can use your own code to implement your application-specific functionality, as well as delegating to and co-ordinating between these other dependencies whenever it makes sense.
None of this is a novel or React-specific idea. We’ve been building software effectively with modular architectures and separation of concerns for many decades. Isolating presentation code from other aspects is perhaps the most common example, and patterns formalising different arrangements of those responsibilities have been around since at least the 1970s.
I appreciate that this is not necessarily the most trendy or popular way to use React today. There is no shortage of libraries and blog posts and forum comments that actively encourage building your whole application as one big tree of React components, even if those components have little if anything to do with presentation and rendering. But in a discussion about whether modern practices are really a good idea, I think it’s reasonable to point out that there is also no shortage of blog posts and forum comments and Stack Overflow questions asking how to solve problems with that kind of application that wouldn’t have existed in the first place with a better architecture.
It’s very late here so this will be my last comment for tonight, but just to finish, your last paragraph provides some great examples of how different the two approaches we’ve been discussing can be. I absolutely do have unit tests for custom comparison functions in the project I’m working on right now, because there is significant decision-making logic inside them, and if that logic is correct then I can be reasonably confident that the sort using that comparison function will be correct as well. On the other hand, I typically don’t test my React components at all (with that type of unit test) because by design they contain very little logic to be verified.
> it can be used in multiple and qualitatively different ways, in contrast with your own position
I agree React can be used in different ways but as I already pointed out earlier, this is a not-particularly-notable characteristic shared by a variety of frameworks, so what you're saying is more of a tangent (i.e. that a tool within a class of flexible tools is itself flexible too) than a contrast to anything I said (i.e. that the bullet points support the idea that React is a framework). In order to contrast to my original comment, the logical thing to do would be to present arguments to support the idea that React is not a framework, since that was the point of contention upthread that I was responding to.
In order to contrast to my original comment, the logical thing to do would be to present arguments to support the idea that React is not a framework, since that was the point of contention upthread that I was responding to.
You originally wrote, in the comment that I first replied to:
- It "calls you" (i.e. you never explicitly call your React components, React does)
This is clearly true, but as we have established, merely having a library call back into your own code is not a defining characteristic of a framework, because we all agree that the sort and Lodash examples aren’t frameworks.
I don’t think you’ve ever properly addressed my point that calling ReactDOM.render may only differ from these examples in terms of scale. You gave an obviously contrived example of importing Ember and not doing anything, but you can import React and use it to render component trees usefully efficiently — its raison d’être — simply by calling render when you need to, without relying on tools like state or hooks to trigger updates.
When people talk about React not being a framework, I believe this is what they usually mean. You can use it as a library just for handling your view rendering — “the V in MVC” — and you can call that functionality on demand and handle any other responsibilities your application has somewhere else using whatever code or libraries you like.
- It permeates your codebase (e.g. migration from moment to date-fns is something you can realistically do piecemeal, React to Vue or vice versa not so much)
I have migrated more than one substantial web UI from another rendering system to React. It was just like swapping out any other library. Most of the codebase didn’t know the previous rendering system existed before and didn’t know React existed afterwards.
I would like to emphasize that this is completely normal software development. Nothing I did during those migrations was novel or specific to front-end web development.
However, you can’t swap rendering libraries like that if you choose to tangle the other responsibilities of your application with your rendering logic, for example by doing other things inside your React components. In that situation, you are no longer separating concerns cleanly, and of course you will have more difficulty if you want to change your rendering library when you have you have tied the rest of your software architecture to it as well.
- It enforces a specific architectural paradigm (components) to the exclusion of others (e.g. MVC, MVVM, etc)
I have built and maintained more than one substantial web UI that used React and yet still had a clean separation of concerns along the lines of MV*. You use React for the V. You use the other parts to handle other responsibilities and to determine what data to pass into the V for rendering using React.
Obviously the “V in MVC” approach emphasizes using React for rendering, while managing other responsibilities like state and remote API calls in other ways. That means you’re not going to be using a lot of hooks, or class component state and lifecycle methods, because you won’t much need them. I’m not arguing that this is the only way you can use React, and clearly some people prefer to use those other React features more and their software designs will differ accordingly.
But contrary to your claim that I quoted above, React does not enforce a specific architecture. It does not stop you from adopting other strategies for designing applications and managing UI code that have proven to be effective elsewhere in the software world, and those strategies can be used as effectively with React as any other rendering library.
Those are the three specific claims you made that I first responded to because I don’t fully agree with them in the context of React. If your argument is that React is a framework because those claims are defining properties of a framework and React has them then evidently we disagree about that conclusion. But IMHO terminology isn’t as interesting as exploring different ways React can usefully be employed and the guarantees it gives and restrictions it imposes in each case, whatever we choose to call them.
> ReactDOM.render is only different to these examples in terms of scale
I think you're confusing longitudinal vs latitudinal comparisons (see point about direct competitors). Sorting is not a competitor to React, or even in a similar class of tools.
I did mention equivalents to ReactDOM.render in various frameworks. Those equivalents also differ in scale in the exact same way as React does to sorting, and yet we're clearly in framework territory when we talk about them. One substantial difference I addressed is that React is inextricably integrated to its internal state and re-rendering mechanisms even if you only use ReactDOM.render; calling setState will always take over control for managing batch updates (not calling it is beside the point; it's always available). This is objectively more "frameworky" than, for example, Mithril's `m.render`, which acts like a true library in this case (and yet, it's still a framework).
> I have migrated more than one substantial web UI
I'm not sure what this has to do with the point you quoted. We've established w/ the lodash example that it is possible to "permeate" the codebase w/ a library, but that doing so is not an intended use case for a project that is a library, and conversely a project that is designed to dominate a complex control flow orchestration between user code and itself throughout a significant portion of scope for an app is a framework characteristic (and React presents that characteristic)
> had a clean separation of concerns along the lines of MV
Here, it appears you're conflating framework-ness with a specific scope size (roughly the size of MVC); this is inaccurate. Consider that Ionic is a framework despite being largely a "only V". Consider that Jest is a framework, despite having no concept of M/V/C whatsoever. Entity is only "M" but also a framework. But what they all have in common is they are organizationally opinionated within their scope of operation (this is what alluded to when I mentioned spaghetti code).
> If your argument is that React is a framework because those claims are defining properties
They are not defining properties, not exclusive to frameworks, possibly not even universal, and certainly not an exhaustive list of arguments. What I'm saying is that these are arguments used to support the idea that React shares an overall strong semblance to frameworks (even if the imprecise examples can be nitpicked to whatever extent). "If it quacks like a duck" and all that.
If we were to zoom out a bit, the entire reason why this whole framework-vs-library thing is even a thing stems from objections that the "just a library" tagline is often mindlessly parroted as a soundbite to support the idea that React is not "bloated". But ironically, if you scroll around this thread, you'll see that this correlation has lost its edge on two fronts: a) people now complain about fragmentation in the React world caused precisely by its lack of opinions in various areas of web development and b) many of the frameworks I mentioned are less "bloated" than React (because they don't support multiple ways of doing components, because they offer equivalent functionality in less bytes, or because apps written in them require less boilerplate for things like state management, for example).
This discussion is frustrating and I feel perhaps we should agree to disagree at this point. It seems we keep talking past each other and I don’t know how else to explain my position. It also seems that perhaps you have some more specific ideas in your head about what some of these terms mean and you are seeing what I’m writing through that lens, but unless you explain those ideas the rest of us can’t productively discuss them with you.
I addressed three specific claims you made in the comment I first replied to. The first was true as written and my point in that case was that it doesn’t tell the whole story about how React relates to your own application code. I have tried to be diplomatic, but the second and third were simply incorrect: you claimed that React permeates your code and makes migration between rendering libraries difficult, and that it enforces a specific architectural style to the exclusion of others, but as I have tried to explain, my own experience on multiple occasions has proven otherwise. These things are only true if you use React in a certain way, and my greater point throughout this discussion has been that you are not required to use React in that way and a different approach may be beneficial in some respects. I feel like the old saying applies here: perhaps someone who says a thing cannot be done should not interrupt someone who is doing it.
I think you’re being too pedantic. In 99% of React apps, React “establishes a runtime environment and then calls into your code to respond to specific events”, as you put it.
In 99% of React apps, React “establishes a runtime environment and then calls into your code to respond to specific events”, as you put it.
I don't know what the true proportion is, but obviously a lot of people do choose to use React that way. This has never been in dispute.
My point is that you don’t have to. You can keep things simple with React and keep responsibilities cleanly separated within your code. If you do, you will never have a lot of the problems that people who choose to tangle everything together within their React components can run into.
This whole discussion is about whether modern web development practices are good practices, so I think that’s a fair point to make regardless of how many people currently choose to do things the other way.
You’re still writing code which is based on React’s view of the world, not standard web APIs. Saying it’s not a framework just means that people are cobbling together their own frameworks using some popular libraries, which gives more flexibility at the cost of the various combinations being less tested and harder for someone else to support.
To be clear, this can be a reasonable trade off – but there’s a cost which people often discount until they realize they just spent a week wrestling with abstraction layers.
React forces you to write code a certain way. jQuery does not force you to write your code a certain way. In my experience, that’s the single biggest difference between a library and a framework.
I agree with a lot of these points, but differ slightly in two regards:
1. In my experience React DOES lure people into the "pit of success" in at least one important aspect -- modular and re-usable front-end code. React is certainly not the only way to get this, but it does help force you into some good patterns.
2. The "sweet spot" for React is pretty large. If your site is truly static (e.g. a blog, a product landing page), then yes it's overkill... but so is something like Rails/Django! Just use a static site (+ generator, if needed.) If you're building an "app"/you're interacting with a database, then you're almost certainly going to want end up wanting interactivity. And it snowballs -- a little state change here, an ajax call there, and all of a sudden your front-end is ballooning without structure or modularity.
Yes this. The article mentions the following as poor candidates for client side rendering. I can agree with blog, but suggesting a tool like React is a poor choice for a shopping cart is naive.
> Those are things like blogs, shopping-cart-websites, mostly-CRUD-and-forms-websites.
How? It's the most painful, difficult, slow, frustrating, confusing programming experience I've ever had in my 25 years.
It's made me want to leave the industry completely and I honestly think I will after this project.
It has single handedly slaughtered and destroyed my quarter century love affair with programming.
It's a wildly inflexible architecture that aggressively forces their users to conform to an orthodoxy that's fluid and always changing. So you get a pile of inherently unmaintainable, unavoidably messy code that is deprecated the day you write it.
It's sheer insanity. Trying to get horizontal communication between components.
I'm slapped and told "no don't do it that way" and then I'm given half a dozen extraordinarily convoluted ways to do it instead.
They say "you aren't thinking in react". There is no thinking in react because there's a bunch of different ways to go about it and each one fights against the limitations voluntarily imposed by the framework.
Each one is a hack to get around the needless artificial barriers that exist there for no damn reason other than to make life harder.
Pass a parameter with an onclick handler. Again, I get slapped around as no that's not how it's done.
Why isn't it easier? Why is the Framework requiring me to do more work, to set up an indirection? Why am I working more with it then without it? Why does it give me less, do less, and require more from me?
It's literally the most complicated convoluted and elaborately complex way to do what should be simple and direct things. Every task gets a layer or 4 of complexity slapped on top of it.
It's like they replaced Galileo's chart with epicycles because they have to appease some invisible theory gods.
It's theory that has literally zero hard evidence as to why doing something directly is bad but doing the same thing with a bunch of weird generators callbacks and hooks is good.
In my 5 years of working with it, it's always without failure been the worst catastrophic mistake on every project, blowing through budgets and deadlines like nothing else.
Productivity is slaughtered. Otherwise 10x engineers become 1/10x. It's remarkable how much it stagnates and destroys everything.
This is pure Jim Jones cult magic stuff. It literally only exists to make people feel special and elite while doing what should be simple stuff.
I'm quitting engineering after this thing ships. I simply do not have the words for how much I despise react. It's the most despicable creation I've ever laid eyes on.
I honestly want to have absolutely nothing to do with programming now. After React it makes me physically nauseous.
I find it slightly incredible that someone can describe React as "the most painful, difficult, slow, frustrating, confusing programming experience I've ever had in my 25 years", have a whole bunch of complaints about how bad it is, and how it makes no sense, and how it reduces their productivity by a factor of 100 ... and then also use it for 5 years.
There are for sure lots of bad ways to use React, and lots of bad React developers. I actually had a very poor experience with React my first project using it.
But that's true for any framework (or lack thereof.) It's definitely possible to find good React patterns too. My 2nd project with React was a great experience, and was infinitely more maintainable and reusable than the framework-free frontends I had worked on.
Sounds like you've worked in really bad React projects (and/or really good non-React projects). All I can say is that my experience has been different! Redux + Redux Toolkit (https://redux-toolkit.js.org/) helped me and my team establish React patterns that were organized, concise enough, and performant -- although we did still have to tinker and try some things out until we found the patterns that worked for us. Hope it helps!
Here's things that are super simple to do with Javascript but extraordinarily difficult in react:
* a function your code can access
* data your code can access
* a dom node you can access
The very core parts of basic programming have been slaughtered and perverted in some kind of repulsive overengineering porno show.
I've worked 3 months on something that should have literally taken 2 days. React is giant sack of bullshit that's made it take months.
Instead of managing say a global object there's this sheer utter insanity of redux store. Something that I could explain in 10 words now takes 9,525: https://www.valentinog.com/blog/redux/
The pythonic notion of "we're all adults here" has been replaced with "we're all completely utterly incompetent children here that need safety locks on everything". I no longer know what works.
I'm actually astounded, I'm not joking in the slightest, in any way whatsoever that
var a = 10 + 5;
still works and I'm not forced to do something like:
let a = [...new Array(10).fill(0), ...new Array(5).fill(0)].length;
as a workaround.
I am quite literally shocked by this. Just thinking that this is still possible made me actually shout in happiness at my desk. I really just did that.
I wish I was being sarcastic. I'm not. React breaks programming that much. At that fundamental of a level. It's that profoundly bad.
Coding in react is like if you wanted to get out of bed and take a shower but then find out your town has been carpet bombed and you're sitting underneath piles of collapsed concrete. So first you need to survive the day, get rescued, clear out the rubble, then rebuild everything, then you can go take the shower. Shit's so much easier this way!!!
No.
No it fucking is not.
Just no.
This vile framework is the most vulgar code in an already repugnant front-end javascript ecosystem. It's utterly shameful.
Amen! Have been waiting for a react replacement for ages. Hate using it for all these same reasons. Use preact, but mostly same issues.
The fact that they change the seemingly every few months, and have the entire framework scattered around 3-4 different libraries that are always changing is annoying enough.
Oh you want to set the class of the html element? We're gonna rename that to className cause it's easier to read and and we can.
Functional components and hooks become a ridiculous mess too, in any more than basic scenario.
Here's another example. Say in javascript I want to navigate to a page 'login', here's a way to do it.
window.location = 'login';
And there I go!
In react, well it really depends on what version. If I'm doing pre-hook (pre 16.18 or so) classes, first I need to make sure my constructor brings in props that I call a super on.
Huh?
No no stay with me. Then I have a this.props.history object and I push a new entry on to the stack like so
this.props.history.push('login');
Remember to make sure you use the fat-arrow to pass the this reference downward and that you export your class using withRouter. Effectively here's the replacement code:
import React from 'react';
import {withRouter} from 'react-router';
Class A extends React.Component {
constructor(props) {
super(props);
}
fn() {
this.props.history.push('login');
}
}
export default withRouter(A);
And even then you may still have to "debug" this because it may "break" for inexplicable reasons. Because "In order to make use of history in the App component use it with withRouter. You need to make use of withRouter only when your component is not receiving the Router props,
This may happen in cases when your component is a nested child of a component rendered by the Router or you haven't passed the Router props to it or when the component is not linked to the Router at all and is rendered as a separate component from the Routes."
Again, we are replacing:
window.location = 'login';
That is our only goal here
How is this easier then the first one? It isn't.
What problem has been solved? None.
Does it take less time? No.
Is this less typing? Less code? No.
Less complexity? No.
Are difficult things less difficult? No.
Fragile things more robust? No.
No none of this. It runs away from more reusable, self-contained, portable code as fast as possible. It gets in a rocket car and fires up the engines to go Mach 1 in the wrong direction. It's a giant tangled spaghetti dish of the worst anti-patterns in software engineering as a requirement for it to work.
For future readers, a flagged dead sibling comment said this
> Poor child. Wait until you have to build a sufficiently complex web app. Global variables are never the answer
"never the answer" is a Fundamentalist Orthodoxy.
Look at those words, "fundamentalist" and "orthodoxy".
When they are the answer and are needed then instead of a basic global thing some bizarre fundamentalist mind palaces get built. There's say "a singleton object that expose shared properties through a getter/setter pattern" or some other word salad to avoid using the word "global" and avoid making the code look like a global.
So weird rules get piled on, maybe some ornate calling convention.
These people dress up a global and disguise it in a sufficiently large enough costume so their fundamentalism doesn't get offended.
It's simply blind dogmatism and utterly indistinguishable from any other cult-driven purity test.
The ceremony is a necessary delusion so they can maintain some imaginary tribal membership to some fiction of "senior developer" they have constructed out of bad advice and empty platitudes by other misdirected self-assessed experts.
It's like the anti-climate-change or anti-vaccine people who think they are smarter than everyone; ignorance breeds a confidence that only progresses the pursuit of greater ignorance. Like astrology, these imagined worlds are far richer and more complicated because they have to construct something that follows arbitrary rules and disagrees at a fundamental level with basic realities to prop up mythical narratives holding their tribes together.
High-level, we wanted to minimize the need to "jump around" to multiple files or multiple places in a file to make a single change to an action (and also just minimizing the amount of boilerplate generally).
If I'm remembering, createSlice() got us most of the way, but async actions still needed an extra declaration (and maybe types? we were using TypeScript), which couldn't be placed next to the createSlice reducers, since they're in-lined. I can't remember if we ended up popping the reducers out into their own functions so they could be next to the createAsyncThunk call, or if that created too much of a typing headache and we just dealt with having async action creators declared at the top. (We also tried just using createReducer directly, but iirc the typing was just extra work compared with createSlice.)
**
Only partially-related to RTK, but the other thing we had to tinker with a bunch was performance. RTKs default use of immer helped a lot, and I believe we also ended up using createSelector (or perhaps the Reselect API directly) in a few places. We also had to learn to make extensive use React.memo and React.PureComponent. Redux dev tools were incredibly helpful for figuring all of this out.
*
Anyway, hope that's useful/interesting! RTK made a big impact in my day-to-day React/Redux development, from "ugh so much boilerplate I feel stuck" to "I can make changes reasonably quickly." Hope to see it continue to improve!
You should be able to write thunks in the same file as `createSlice`, usually in front of the `createSlice` call, and then use the `extraReducers` "builder callback" syntax inside the slice to handle the various actions dispatched by the thunk. See the example here:
And yeah, `createSelector` _is_ the Reselect API, just re-exported.
You might want to also take a look at our upcoming "RTK Query" API that will be in Redux Toolkit 1.6, which should be out in the next couple days. It's a data fetching and caching layer built specifically for Redux usage. The preview docs are here:
Ah yes. We did end up using extraReducers, but didn’t love that the thunks and their corresponding reducers had to live in separate parts of the file. (For me at least, mentally simpler to have an action and it’s reducer close together.)
This looks cool, thanks for passing along! I’m actually starting a new project now, and deciding what my state management / caching layer should be, so great to know this is an option.
I have a really hard time relating to the conclusion of this. In a big React codebase there are certainly a lot of indirection and "artificial" barriers. The React ecosystem is indeed turbocharged and confusing, atleast if you are trying to follow the latest trends.
However, there is atleast a method to the madness. Compared to the bowls of jQuery spaghetti that was used to bring SSR apps to life back in the days, the situation is infinitely more ordered. To say nothing of the absolute insanity that was pre-framework-driven SPAs.
Redux is a good example of this. It requires a load of boilerplate and seemingly contrived ways of reacting to interactions. What most people don't understand is that this is the primary feature of it. It is a rigid flow of data that enforces you to go through the same steps each time. As such, you can get into a Redux powered app and understand it relatively quickly.
If I may ask, what was your stack of choice before being forced to work with React?
The alternative to React is not jQuery spaghetti or full page reloads. You have solutions that cost a third or less of the effort of doing an SPA (and not as little as throwing in some jQuery) such as Unpoly, or Hotwire.
I'm only bringing up jQuery because the transition from homegrown jQuery madness to React is still a common upgrade path (even more so five years ago). I'm not claiming React is the optimal choice for anything. In many cases it is objectively the most pragmatic one, though. It has arguably the most momentum and mind share of any frontend technology ever. And it just isn't as horrible as the parent and other posts make it out to be.
> Redux is a good example of this. It requires a load of boilerplate and seemingly contrived ways of reacting to interactions. What most people don't understand is that this is the primary feature of it. It is a rigid flow of data that enforces you to go through the same steps each time. As such, you can get into a Redux powered app and understand it relatively quickly.
No this is totally completely wrong.
Tools don't make the programmer competent.
The person that created a mess of jquery will create a mess of react, ember, vue or whatever they are using. They don't become better programmers with more authoritarian tools.
This delusional attribution was supposed to happen with OOP in the 80s, RAD in the 90s, it doesn't work. You can't shove competency into people by enforcing upon them more complicated systems. In programming, bureaucracies, companies, governments, any human system.
Instead what you get is more complicated messes. Look at any Java code for a great example. Or bureaucratic institutions or anything else structured under supposedly all-encompassing ideas. All you've given is a shinier and longer rope to hang themselves with.
It's a long promulgated empirical claim with lots of empirical evidence stating it's dead wrong and does not work.
Javascript, the browser, html, and css, that is a stack. I say <button> and a button appears. I don't have to poke addresses for graphics, implement a line algorithm, a flood fill, define hit points, create the abstraction of a document that moves with a scrollbar or that flows around a page ... literally millions of things are solved.
These tools (JS, HTTP, HTML, CSS) seek to empower and enable, not constrain and dictate. That's the difference. This is why TBLs open system kicked Ted Nelson's Xanadu's ass and why 30 years later he still doesn't have shit to show.
The baseline supposedly "raw" tools are already incredibly high level and sophisticated.
What about your "MVC"? HTML is the model, CSS is the view, Javascript is the controller ... that's why there's 3, that's why they do what they do, that's why they are there.
It already exists. It's already there.
What these frameworks do is go in and break all of that. It becomes one big garbled mess again. Solved problems become unsolved and the programmer gets blocked from using any reasonable solution to get back there. All in the name of the authoritarian appeal that this will produce better code.
It's utterly absurd. It doesn't produce better systems or code, it hasn't ever, and it will continue to not.
Instead it will produce deprecated unusable messes that need full-time staff to babysit the complexities of all the parts and make sure the cathedral of interacting dependencies doesn't catastrophically collapse. That's why these projects have 6-figure salaried engineers on "maintenance". Look at the batshit insanity on the server side with k8s and tools like prometheus these days. It's trying to solve problems by tossing a bag of hurdles and complexity at it. Before that it was chef/puppet.
Sometimes these days I see both k8s and chef on systems that have become magically more broken and have more people working on them with more downtime than they were before.
It's why these things are constantly "rewritten". Because the old authoritarian complex thing is finally acknowledged to be inadequate when enough reality finally seeps in and then they run off to the next one hoping that once again, documentation that reads like a book on astrology or homeopathy will be the silver bullet to their problem.
I don't really understand what you are suggesting. If everyone would stop using mainstream frameworks, the result would be endless bespoke ones. As long as programmers want to simplify, innovate and accelerate their work, they're going to leverage and implement abstractions if there is room for it.
I have worked on plenty of projects using their own, homegrown bespoke frameworks, and it ain't pretty. On top of that it is absolutely wasted knowledge that won't translate to any other code base. If you want to argue that it's all incompetence, I guess that's fine. To me it's about familiarity.
This imagination that there needs to be a framework is nonsense. It's done by people who have drunk the koolaid and don't have a long view of programming.
The complexity implicating the overhead is an imposed illusion.
All software lays bare the organizational structure that it's created in.
The structures work within other organizations similarly structured.
It's why ruby shops look the same along with php, java, etc. Why it looks like their is a consistency of dynamics among these channels of development.
Some of these institutional structures are healthier and more productive than others.
React, as a codebase is an autocratic hierarchy ultimately run by ignorant indecisive incompetency that fosters cult adherence to achieve ultimately banal ends through a needless level of strife and overhead.
That's effectively most programming teams which is why it's ultimately so popular. It's also why there seems to be so many cocky buffoons in their early 20s doing it.
Those who see a need for frameworks are speaking more to their rigid notions of the organizational structure upon which software is built then upon the technical need at the software level.
Hey woha wow hold on a second. Quitting engineering over this? Just find a job thats pure Rails / Django / .NET. Those jobs are around, usually its smaller projects companies but they are super pragmatic. Anyway quitting is extreme, take some time off you are burned out probably.
I'm sorry you have this experience. I think the most confusing part of React for me was that even though JSX looks like HTML, you're actually not interacting with HTML at all. At its most basic you're just giving React a `[{ type: 'div' }]` and it will create and manage an actual <div /> for you.
it's not that. it's the rationalization through imagined differences. A forceful separation and grouping of equivalent things into difference categories and a dictation of their interaction by segregation in the name of more "organized code".
Things do adhere to a structure under its guise, it's an accurate statement. But it's an arbitrary one that's of dubious and most likely negative value.
The reality of maintenance, deadlines, budgets and number of engineers working on the projects seem to suggest the impact is overall negative.
There's two reasons this stuff sticks around:
1. Counterfactual testing can't ever be done to test without ... You can't rerun the project with the same initial conditions and do some kind of clean demonstration of it being a hindrance.
2. Even if #1 was achievable, there's other reasons people do not want to admit to it. And this is especially applicable to an authoritarian framework such as react that enforces doctrine by explicitly disallowing heretical code
Political scientist Adam Przeworski claims authoritarianism can reach a stable configuration "mainly on lies, fear and economic prosperity":
* There needs to be an economic value to the doctrine perceived in the mind of the prospect.
* There has to be a fear of losing out or falling behind by not adhering to the orthodoxy
* The core claims have to be fundamentally, exhaustively and obviously fraudulent.
React checks #1 and #2 and for #3 they claim simplicity, painlessness, ease of use, all of these are profoundly fraudulent claims as anyone who has extensively worked with it knows.
This is why it's become a stable authoritarian system.
The book is pretty great. I'll put it with "The soul of a new machine", Ferguson's "Computer Wars" and Lapsley's "Exploding the phone" as top narrative tech books.
> unloved, unpopular, uncool things like Django, Rails, Laravel
Oh they're loved all right, it's just that they're (all three) very mature, packed with features, easy to pick up and people who work with them don't have a reason to sit around and discuss the tools.
I work for a smaller Rails shop and the atmosphere is just so nice there. We work on small (think $20k) projects for different niche customers, we absolutely reject SPAs (for what we do), we host the apps on cheap VMs, we don't worry about scaling at all, we talk to the clients a lot, we prototype fast and it's all just so easy and even brings good money.
Rails is the no-bullshit way, and definitely the human way.
But where's the job security in doing projects quickly and cheaply? With React I can be a 10x duration and billing developer .. 5x on the write, and 5x on the maintenance/rewrite ;)
Good you have found your niche, and it's great that you haven't overextended yourself when it comes to delivering value to customers. I would say though that your work is a subset of web dev, and while totally valid in that area, I don't think it applies as concretely to other domains, particularly those with larger audiences, or those with needs for greater reactivity.
Are you disagreeing with my assertion that the above poster's view is a bit too narrow in its application? I know a lot of sites run rails/php/django, but that does not mean that they are the majority, or even part of a minority that are the 'most' succesful.
I always have cognitive dissonance about this kind of stuff. I read this article and “In defense of the modern web” and I feel like I agree with both of them.
I think new things don’t necessarily make older things obsolete. We have printers, for example, but it’s not like pens, pencils, and even chalk aren’t useful.
Whenever I start a new project (admittedly, these are personal projects so not the same kind of scale—but in my job where the where the scale is bigger I’ve noticed a similar sentiment), I like to think about everything I have available to me. I could make a Vue SPA, a generated static site with 11ty, a backend CRUD app with PHP (I like Fat-Free Framework), WordPress (haters gonna hate), a site with no JavaScript, a site with only vanilla JavaScript, or anything in between.
I at once feel like a wide-eyed optimist ready to plow into the future and a curmudgeonly get-off-my-lawn skeptic who’s been burned too many times.
It's a good thing I consider building websites/apps good fun or else I would be really stressed out. :-)
>new things don’t necessarily make older things obsolete. We have printers, for example, but it’s not like pens, pencils, and even chalk aren’t useful.
When first reading your example, I expected the printer to be the old technology. I think printers and pens have very different use cases. Using a pen establishes a creative loop with direct feedback, while printing is about making a copy of something that already exists. I think its fairer to compare a printer to digital storage/digital display of a document. The former exists due to ancient legal requirements when signing contracts.
Similarly delivering a cached SSR HTML document fast and hydrating it with JS afterwards is the way to go. TTI is only a problem if you don't use regular links as fallbacks to make requests before hydration replaces them with JS-based event Handlers.
Implement the modern web by using the established web as a fallback.
There’s a really great fix for this, which is to design JS frameworks to not take over the entire application.
I have been waiting for a long time for the framework that will let me write a web component, and then include that web component in a regular HTML page, in a way that’s supported by the idioms and best practices of that framework.
It’s also worth pointing out that all of these drawbacks to rendering web pages on the front end via JavaScript were obvious the moment these frameworks were introduced. The critics at the time were right. But we still lack for easy-to-use alternatives.
Web components have been a possible build target for Vue for a while. It seems totally possible to set up a Vue project like you’ve suggested, use all the Vue conventions & tooling, and output web components that you then use a la carte. Maybe I’m missing something about what you are looking for, but more details are here: https://vuejsdevelopers.com/2018/05/21/vue-js-web-component/
And I’m sure the same can be done in other frameworks.
Nobody does this in practice. Tooling, tutorials, frameworks, etc are all created around the idea that the entire application is an SPA with a single root element. I understand that it’s possible to do this in theory, and that’s why I said I want to see a framework where the idioms and best practices are geared for this kind of use.
I'd encourage you to give React a try for this use-case! I've done this exact thing -- slowly introducing React in certain places in a large web app -- and it's worked great.
You're right that tooling/tutorials are mostly geared towards SPA usage, but React itself is designed to work for both. You'll have to decide on a pattern for "bootstrapping" React in a given page or element, since there aren't well-established best practices, but after that it's smooth sailing.
In fact, that's one of the major contributors to React's success. It's so easy to integrate into an existing application. If you take any major tech company (that's existed before React) that has adopted React as their main framework, I will bet the majority of them are, to this day, running React in parallel with another framework (and many are running it WITHIN another framework).
I have a very good idea of how the web used to work 10 years ago.
But when I try to learn Modern Javascript frameworks, the tutorials rarely do a good job of explaining that they won't teach me how to create a normal, traditional website, or if it's even possible to create a normal website with the framework. They simply assume that the modern way is the standard way.
I want a modern alternative to PHP, but the JS community doesn't make it easy to learn JavaScript.
At least I know how things used to work. Imagine a newbie that never developed a normal website and now thinks React/client-side rendering is how the web is supposed to work. They won't even be able to understand the tradeoffs being made for them.
I want a modern language and framework that still makes sane decisions, and when it does weird things (e.g. client side rendering being the default) at least tells you upfront that it's making those decisions, and their implications.
> Imagine a newbie that never developed a normal website and now thinks React/client-side rendering is how the web is supposed to work.
I had the luck of learning the web "the old way" at the university. First HTML, then CSS, then PHP where we cobbled together a small website (our end projet was a recipe website where you could create an account and post recipes, so there was database usage too). All of this was made in WAMP/XAMP. We had a course on JavaScript the next year but I honestly didn't understand anything. Some time after though, when I started working again on the web, having an understanding of HTML, CSS and what you had to do by yourself made me understand fundamental web technologies on a deeper level than most of my peers that started with the MERN/MEAN/MEVN stack. I'm sure they'll be more attractive to employers though.
There's nothing particularly weird about client-side rendering (at least, it's no weirder than server-side rendering was in the era when most pages were static data).
It could, of course, be considered "weird" if one's mental model is that patching together document description declarations on-the-fly on a server to later be re-interpreted and rendered on the client is "normal."
Server-side Node.js still exists and, if you like, can be quite similar to good old PHP. A "Hello World" app in Express.js is pretty barebones and easy to get started with, and there are probably lots of comparable alternatives. I've always found Express.js to have a big community with lots of guides and info, although I admittedly haven't had the experience of coming to it as a newcomer to programming or the web.
This is something I'll never understand: Isn't the only selling point of JS that it runs on every web browser? Why would anyone want to use it (or, in 2021, PHP) on the server side, where you can use any language you want?
Hah, I've been saying the same thing for years. It bothered me even more so because I was a Perl programmer and everyone kept saying how messy Perl code is. But they want JS on the backend?!
Server side blazor is actually architecturally elegant, and the implementation is quite good though not perfect.
The result is about 25% of the complexity of an equivalent react for the same app in practise for 90% of systems (ie excluding monty haul what if but usually practically irrelevant edge cases).
The part about API changes being incompatible with old versions of the frontend (that are still loaded in someone's tab somewhere) is a valid problem, but honestly isn't significantly worse for SPAs than for traditional server-rendered HTML websites. Your basic HTML web form will break too, if your API has changed in an incompatible way!
It's true that traditional websites would coincidentally get a new version if the visitor happened to click a link, but relying on them to do that to avoid seeing an error isn't a better solution than an SPA notifying the visitor that they need to refresh to avoid seeing an error.
Also, I don't really agree with the author's view that needing to refresh an SPA to get a new version is "bizarre" or "something from the bad old days of desktop software." On the contrary, it's an extremely prominent UI element and a fundamental action in all web browsers!
That said, one "trick" is to have your SPA silently listen to your server for app version updates, and when there's a new version, just make your client-side Link component do a full page load (instead of a client-side route transition). Then at least you'll have the same behavior as traditional HTML websites.
> That said, one "trick" is to have your SPA silently listen to your server for app version updates, and when there's a new version, just make your client-side Link component do a full page load (instead of a client-side route transition). Then at least you'll have the same behavior as traditional HTML websites.
I think the author’s point is that it’s sort of a bummer that we have to deal with this just to get back to “normal”. I agree that it seems under-discussed, too.
But again, the "normal" isn't that great: the visitor might have just so happened to click a link before using a broken form, but that's not some architectural guarantee that you'll avoid errors. It's just a happy accident that the visitor might have unknowingly triggered an entire app update before using an outdated form.
I have to admit, I’ve been avoiding TypeScript and React for any professional projects.
TypeScript due to lack of experience, but I understand the benefits.
React due to many reasons, but most of which is that I don’t agree with the “benefits”.
I have been working with the Frontend for over a decade and have been on the forefront of its progression. KnockoutJS was a pivotal moment and cemented what followed with Backbone, Angular, Vue, and React (and several others).
It don’t think the current state of development is going in the right direction. But that’s just my opinion and a wild one at best.
I’ve been using typescript for years and I’m still constantly learning new things. Certainly has benefits, but also a large conceptual (and often syntax) hump.
On the frontend, maybe look at Svelte?
I’m not going to try and sway you from your current chosen stack, but my personal experience with it (compared to the others) is that it’s like coming home. More like the natural evolution of early web tech, imo.
There's no reasonable argument that you can make in favor of Knockout, Backbone (I hope you mean Marionette though... no one used Backbone on its own), Angular, or Vue that doesn't also apply to React.
I feel like this post just reached into my head and pulled out all my current thoughts about web development and the dominant architecture paradigm. I love it when someone articulates my thoughts better than I do.
Spot on. There are cases for SPAs but there are also a lot of bad cases.
Just the other day there was a news article (don't remember which) here on HN. The entire page "shell" loaded but the content of the article did not.
Quick inspection and it appeared that the SSR page was loading fast but some SPA call that loads the data was underperforming terribly so it was blank.
Let that sink in... we're in the web, it's 2021, everything BUT the article content loaded. Talk about optimizing the wrong thing. We've all went crazy.
I saw this referenced in the job ad for a "Software Engineer: Web" on the Oxide careers page yesterday.
More of a meta comment, but it's funny how interesting things link to more interesting things, and the "HN web crawler" inevitably finds and identifies them.
I really need to focus on this, but I believe what we are seeing is an interesting adversarial game between client and server. For instance, if you build your server with a strong API, then clients are going to build tremendous complexity.
My personal bet is that we need a streaming protocol such that applications look more like X11.
Looks like you're trying to reinvent some wheels there.
No harm in doing so but just so you know, React (or my preference, a tinier version called Preact) would let you update new chat contents without blowing away all the other InnerHTML content. The way you're doing it now will result in a flicker, and mess with things like highlighted text will unhighlighted when replaced. And that's just with the basic dumping of the chat text into a DOM innerHTML. I'm pretty sure what you're doing there would also be susceptible to XSS without additional filtering.
Nice blog post! I read the whole thing. I'm working on something with multiplayer using an unbounded queue of command events, so I learnt a few things about that situation. If you have any posts that elaborate on the typical infrastructure events from running that in production, I'd love to read it as you obviously put a lot of effort into your blog posts.
This is entirely new infrastructure, and I don't have data yet since this is a side project.
I am biasing towards relying on a connected socket for all state management which is fair for board games (and, I do believe more generally given how connected the world is becoming).
There are tremendous problems with using WebSockets in production, but they can be overcome with a decent protocol design as you have a number of failure modes to contend with. I'm in the process of publishing a paper for a conference that will share some of the architecture of my production learnings.
There is an SPA pattern (perhaps sometimes called "offline-first") where your client application code does all reads and writes data against a local database, then another bit of client code is responsible for syncing this local database with the server's database. The local database could be IndexedDB, or localStorage, or even some bespoke DBMS. In some sense the client app would be running on one node in a replica set.
Indeed, one could go even further and try streaming the UI state itself from the server, so that the client is something like an X11 client. The obvious downsides of this are 1) the server needs to store the session state and 2) it's fairly intolerant of connection interruptions, but for something like an interactive game these are probably not deal-breakers.
I'm currently designing my own deck builder similar to Dominion.
My advice would be to use first make a game without the network, and just have hotseat. Once you have a hotseat game, then the question is how to pull the state out of the client and then be shared between two computers.
The complications arise during the failure modes of the network, and how transactions play between multiple play. Chess is a fairly simple game to get started with (I'm not sure how makruk compares), but modern eurogames tend have a lot of rules that can be changed by pieces or cards. These get... very complicated.
> "There are decent patterns in the form of GraphQL, but for a React component that loads data with fetch from an API, the solutions have only gotten weirder. There’s great documentation for everything else, but old-fashioned data loading is relegated to one example of how to mock out ‘fetch’ for testing, and lots of Medium posts of varying quality."
The truly old fashioned way is to load your data and render the page with it in the server. A simplicity that was lost in the SPA, but that's what SSR gives back to you. But since this is an anti-SSR piece I'm not sure what it's getting at.
The problem with SSR, as I understand it according to this article, is that it still removed native link handling from clicks, resulting in the need to override all the basics with bulky JavaScript that doesn't load until some time after rendering.
Which, as a user, has bitten me many times. I hate hate hate when a page seems loaded, but something has stalled, and I can't interact with anything.
As much as I hate Java, I still kind of long for old fashioned Tomcat web apps that sent out fully formed and usable HTML with small bits of JavaScript enhancements.
> So, Server-Side Rendering runs your JavaScript frontend code on the backend, creating a filled-out HTML page. The user loads the page, which now has pre-rendered content, and then the JavaScript loads and makes the page interactive.
Does this mean that one could make the page interactive with server side rendering, but it's not normally done? Or did I completely misunderstand this paragraph.
If you click on an <a> tag before the JavaScript has loaded and React has hydrated, the browser will do a full page load of the URL that you clicked on. Assuming that new page is also rendered on the server, it should work fine and feel just as good as if it was a traditional server-rendered HTML web site or if you had JavaScript turned off. (Of course, things that do require JavaScript for interactivity, like custom tooltips on hover, custom form validation, etc. won't work until the JavaScript has loaded.)
Just to add to the above, this is specifically when your pages are server-side rendered. Hydration is a concept of taking a server-rendered page and making it interactive with Javascript.
You can have your NextJS/React app server-rendered, and then users visiting a page will get the page. Clicking links within the application will use Javascript routing to load the part of the application that needs to be displayed (and prevent the default navigation from clicking said links). I think in practice it's more likely for users to fall back to default navigation which then relies on full server rendering when they have Javascript disabled, than it is because they've clicked before the front-end router has started working.
Also, before this thread I didn't realize React itself could be server-rendered (I thought that was the distinguishing point of Nextjs). Is it common to use non-next React for SSR?
I believe so. I've encountered it used in several projects longer before Next.js (or at least before Next.js was so popular). The basic idea is really simple, on the server you just ReactDOMServer.renderToString(<App />) in Node and respond with the HTML string.
Of course, the devil is in the details. You probably need some conventions for statically determining what data needs to be loaded based on the URL (before you renderToString), some way of passing that global data to the client for React hydration, perhaps some API client that can handle making requests from both the client and the server, some system for handling HTML-specific concerns like meta tags and cache-control headers, etc. Frameworks like Next.js presumably make all these decisions for you!
What they mean is that, with a normal React SPA, the html content sent to the client will be little more than something like `<div id="react-app"></div>`. After the JavaScript loads, react hooks into this div and starts filling it with the html it generates for your app. With SSR, that div will be populated with html when it’s downloaded - this is the html that was rendered by the server. When the page is first rendered it will look like your app, but it’s totally static html. The JavaScript has to load and react has to take over managing the html within that div before any of the interactive content (think: button click handlers on so on) will be functional.
> Does this mean that one could make the page interactive with server side rendering, but it's not normally done?
It can be done, it is actually, how things were done a quarter of a century ago: server-side rendered content with tiny triggers for interactivity directly embedded in the code. In the next step, as complexity grew and as an attempt at separating concerns, you would send the content and along with it a bundle of code for interactivity (which may have been sent in the same request or as a separate resource). Then, we got frameworks. Technically, these could do this as well, but it doesn't match their basic pattern.
JQuery document ready handler that makes a XMLHttpRequest and then a pile of jquery DOM manipulation calls to make the DOM state reflect the data you just got back from the server. Basically just a lot of imperative DOM manipulation calls. No templating, no MVC patterns, etc. This is the kind of frontend JS that was all over the web in the early 2000's.
JSON or XML, using REST or websocket maybe? One request per "page load" is an anti-pattern in SPA's though - you should send all static data once, lazy load large assets like images, and sync only the dynamic non cacheable data.
It kind of depends on your mental model for your user. For mobile devices in many countries outside the United states, you're doing your user no favors shipping them a bunch of static data that they don't actually need yet because you've wasted their bandwidth if they never use it and bandwidth costs money.
React is very good at what it's for, and much of this article is saying that React is not good at what it isn't for. That's a fair point to raise due to the ubiquity of the library, since many will reach for it out of habit or ignorance when it isn't appropriate, but it really doesn't amount to second guessing the modern web in my opinion.
There are plenty of people still using Django and even things like Plone. They're just not in the zeitgeist, because those tools have practically congealed at this point and there isn't much reason to have a discourse about them.
Every Product Manager: “I dunno, ever since they started saying React, everything takes 3x longer to ship and we have 2 teams on very challenging technical projects to enable performance that doesn’t suck”.
What were they using before they started saying React? Backbone.js? JQuery? How big and how interactive was the website at the time they started using React?
>I don’t think that everyone’s using the SPA pattern for no reason. For large corporations, it allows teams to work independently: the “frontend engineers” can “consume” “APIs” from teams that probably work in a different language and can only communicate through the hierarchy
This is really the main reason. Ultimately just a consequence of Conway's Law [0].
Programming is always trade-offs. Having programmed interactive web UIs for over a decade now, I really enjoyed it the most when programming using BackboneJS. Enough structure to avoid the JQuery spaghetti, but the library didn’t treat you like a moron. Coffeescript was popular back then too, glad to see the better parts of it make it back into JS (and not the semantic whitespace).
I really like the way that Phoenix Liveview is trying to solve for this, trying to find the sweet spot in the middle of building multipage apps and SPAs. Great talk about it from the developer here https://youtu.be/8xJzHq8ru0M?t=409
> Sure: traditional non-SPA websites are not immune to this pitfall. Someone might load your website, have a form open for many weeks, and then submit it after their session expired or the API changed. But that’s a much more limited exposure to failure than in the SPA case.
I don't really understand why this is a much more limited exposure to failure and he doesn't really elaborate why this is the case. It seems like the cause for failure in both cases are identical and the only reason that the SPA one would be a more likely scenario is simply due to the prevalence of SPAs, rather than any technical reason.
Overall I broadly agree with the article; that React is often wasted on webpages that simply don't need it. That a lot of technology that is plenty serviceable today is overlooked because it's not 'cool.' I actually think php is great (even though writing it isn't very fun to me) and it was one of my first introductions in creating dynamic webpages when I was a kid outside of some cgi scripts like NewsPro.
Vanilla javascript today is very robust but it's not exactly someone will end up writing a lot of unless they're going out of their way to do so. Web components might very well fit the needs someone might have for their website... but that doesn't really matter if you already know how to use components in React and you have to learn web components. There's a lot of momentum towards the known, especially when that known technology is valuable to employers.
Ultimately I think that while it's generally excessive, people gravitate towards what they're comfortable with and what makes their development life easier. Sure, this website may not require a React app, but it's something that I'm very familiar with and it's easy for me to create a website with it. It's easy for me to create interactive and dynamic elements in a system that is designed for that purpose. And the reward for having this knowledge is market value. This will always be a problem, regardless of what web technology is popular at any given moment.
The spa paradigm was not invent d by react. Or any framework for that matter. Remember when asynchronous xmlhttp requests were cutting edge?. It's just one step from ajax to spa.
I have been growing increasingly dissatisfied with react but there's no clear superior alternative. Server side react is a pretty good solution for most problems and fairly scalable.
Many people compare SPAs vs "traditional" MVC with full page reloads or jQuery spaghetti, not realizing nowadays there are great intermediate solutions which don't take as much effort as SPAs by a long shot, such as Unpoly, Hotwire, etc.
It's unfair to compare a highly over engineered React application vs a lazily built jQuery mess.
Even outside of SPA apps and new magic, Rails is still faster to develop a prototype or website in than React or dare I say any modern SPA tools.
We tested this for fun with some very experienced React and Rails devs at our company, each starting from a freshly formatted laptop to include the time it takes to get an environment up. Requirement was to create a simple blogging site with comments, authors, and tags (with some upfront design). Rails hands-down took the cake, by a large margin, each time.
It was for fun obviously, not exactly scientific, but was pretty eye opening seeing how much further ahead the Rails devs were at each step.
For dynamic websites, React should always be SSR first with optional client hydration. Next.js makes React SSR easier, if you're using Next.js for non-static sites, and not doing SSR, you shouldn't be using Next.js.
Browsers have decades of optimization to show HTML to you as fast as possible. Before scripts, sometimes before stylesheets. Browsers can't optimize the extended network dance you need to do to download and parse KB of Javascript before you can _start_ fetching data.
SSR with partial client Javascript hydration. It's a solved problem, but few people do it.
For me the clear threshold for when you've gone too far with SSR is if it needs auth. Just do not go there. So this is not an SSR issue per se, it's poor SSR implementation issue IMO.
I'm not sure why that threshold needs to exist. It shouldn't be any harder for your SSR to check a cookie than it is for your REST API to check a cookie. There are some benefits of SSR that don't apply to pages with private content, namely being able to cache the HTML response in a CDN and (arguably) being treated better by search engine crawlers, but many of the benefits of SSR apply just as well to private content.
"There are decent patterns in the form of GraphQL, but for a React component that loads data with fetch from an API, the solutions have only gotten weirder."
Wonder how many people using "GraphQL" realise those decent patterns are from the 1970's, i.e., QBE.
Huh? I’m not sure how the page you linked is related to GraphQL, except maybe that they are both querying paradigms. They seem largely orthogonal. Am I missing something?
"It is the first graphical query language, using visual tables where the user would enter commands, example elements and conditions. Many graphical front-ends for databases use the ideas from QBE today."
GraphQL seems to borrow the name. Graph [ical] Q [uery] L [anguage]
It could be a pure coincidence, but then, further down:
"GraphQL a QBE for JSON front-ends."
As evidenced by the reply, the parent seems to have predicted correctly that there are people who have no idea the two are related, i.e., one is descended from the other.
Absolutely I can understand QBE being prior art for a number of querying paradigms. However, the two aren’t closely related.
As far as the name goes, the “graph” in GraphQL likely refers to the data graph (as opposed to “graphical”) as data graph traversal is one of the key selling points of the language. The other one being homoiconicity between request and response.
I made no such suggestions. I was suggesting that it’s certainly plausible that QBE influenced aspects of GraphQL. The “prior art” being QBE, not GraphQL.
I tried to go the old-school route of server rendered pages. But then I thought to myself: I would need to write an API later so that's double the amount of work. What if I'm also going to make a mobile app?
I can spin up a graphql API, use create-react-app, and react native, use apollo client to share lots of code and be done with it.
The alternative is more "pure" I guess but it's a lot of double work.
Why not just have a function that makes a db call and then send the data into the template?
If a mobile app needs to request the same data, simply make a .json version of the route and use that same little db access function, shove the return into res.json({}) and Tada.
Sharing ui code between react native and web-react is pointless so you'd be sharing what? some formatting functions? the request functions that the .json and ssr routes effectively return for you?
Care to share some of those? I am a backend developer and trying my hands in front end development; interested in knowing what's the sane way to be part of this landscape.
I choose React for personal projects because it's easy. I'm not too concerned with performance. This article doesnt spend much time on developer experience.
And to me this is the root of the problem. Developer experience is awesome so fuck the users, the usability, the performance, the scalability of the business, the time it take to build anything, the stability, the security, the robustness, and whoever will come in 2 years after we left to maintain this. I'll be gone by then.
But lots of the developer experience is actually awful. Some is good, but there's so much needless complexity that is just painful. Stockholm syndrome applies if you don't realise there's easier ways, of course.
Well there's also what might be called the "eschatological perspective on technology": time in development is spent only once, but user life time and technical resources are spent million times (at least, if it's a significant project). In this context, we may also speak of the "eschatological debt" of a project.
Personally I love SPAs and would still use them all the way instead of Django/Rails. The problem with server-side rendering is you need to start duplicating all the code the moment you need some front-end interaction. Also, I prefer when the interactions are snappy, and having to hit the server on every click to fetch some html feels so slow.
I do agree though that building SPAs is too complex and that we haven't yet found the perfect solution.
One day browsers will natively support modules and "Bundle Splitting" as the article calls it will just be the intuitive and automatic thing to do. Until then we have webpack.
Most browsers do support js modules today but it's kind of an awkward situation to say the least. And if you need to support older browsers you may as well not bother, you probably use Webpack and/or Babel (or TypeScript) anyway for other reasons. Especially if you're trying to do isomorphic stuff for an SSR app, as NodeJS then has its own pile of idiosyncrasies and baggage around module support.
This situation has been playing out for many years and it has only gotten more confusing.
I've seen the issue of new hires, time after time, getting a small ui ticket and immediately asking, "where is the client store?" or "Why aren't we using Redux, it'll clean up our code a bunch."
Of 20+ applicants I've interviewed this year, only 2 knew about element.dataset and how to create a basic state scoped to that vanilla JS "component".
The issue is groupthink and using the hammer on everything.
The point of Redux (or any state library) is to share state between components. Unless you're doing something like putting the state for a child in the data- attributes of a parent somewhere further up the tree I don't think element.dataset does the same job at all. element.dataset is much closer to something like using useState.
The point was that there are many ways to solve the problem. For say, a simple tab layout where you add click handlers to the tabs and hide/ show the contents, you would never notice any latency using the DOM apis. The DOM apis are the core of web development. You need to know them and consider them before moving into the abstraction atop.
> Most bundle splitting techniques require you to load that ‘index bundle’, and then only once that JavaScript is loaded and executed does your browser know which ‘page bundle’ it needs. So you need two round-trips to start rendering.
Hopefully you're performing some server-side rendering, which should know which page is being rendered, and save the browser a round-trip by including the page bundle in the initial response.
> So the user will be using an old version of your JavaScript frontend with a new version of your API backend
You should never couple your API backend that tightly to your frontend release version. What if you find a critical bug and have to roll back? Anyone that deals with a native app also has to deal with people not installing updates.
> (regarding SSR) The first is that the page you initially render is dead
You can always make your JS render-blocking if it's really that important. Most people would rather see the content first.
> If you do SSR on any pages that are custom to the user, then you need to forward any cookies or authentication-relevant information to your API backend and make sure that you never cache the server-rendered result.
This applies to every website.
> But no option really lets a web app be careless about its data-fetching layer.
This applies to every program that has to fetch data from somewhere.
> Speaking of data fetching. It’s really important and really bizarre in React land
This is definitely true but also something React expressly considers out of scope, for better or worse. I think the reason the GraphQL clients tend to have a better story here is that a lot of the tricky things about data fetching (data normalization, deduping queries, updating related objects, etc.) are difficult or impossible without a common query schema with standardized field types, which GraphQL provides.
All in all, I think the SPA pattern has won out because it's the one pattern that lets you treat your website like an actual long-running program, instead of a series of stateless requests. People will complain about complexity and tout the zen-like purity of their Jekyll blogs, but this complexity is what allows the web, as a platform, to thrive and compete against native apps and the walled garden of app stores.
React is great for SPAs. Most large companies are working on honest-to-god SPAs. By extension most engineers are working on SPAs. So most tooling is created for SPAs. Now if you aren't building an SPA you look around and find almost every resource is around building an SPA. Even if you know you don't need an SPA, it's easier to hire, iterate, and even use other open source solutions if you are building an SPA, so you try to hamfist your project into an SPA.
It's a bit like having a bike commute in America. A bike might be the best thing for you to do - cheaper than a car, keeps you healthy and you don't need a garage. But you quickly find that everything is built for cars and it's easier to deal with the disadvantages of a car than try to commute with a bike.
I remember thinking the same thing about Hadoop 5-6 years ago. If you had "small data" you could get what you wanted with SQL and fast disks. But everything else assumed you were on Hadoop. Newgrads were trained in hadoop. New tools were Hadoop first. New research was all hadoop. If you hit a small issue with your DB, almost every solution would be "this is how it's solved in Hadoop". It was hard to even know if what you were trying to do what even possible without Hadoop.
The only optimism I have is that maybe in 5 years we will all collectively wake up and stop trying to shove React everywhere just like we stopped with Hadoop.