>> Front end frameworks are usually pushed by developers, not management.
The last ten years I spent as a front-end "full stack" dev and every time there was some new shiny JS framework, all the devs would get out their tiki torches and pitchforks, go to management and tell them they should really really move to this new framework because blah blah blah.
In less than five years our department did this:
backbone -> angular -> react -> ember -> next -> vue -> svelte -> and finally back to angular/react which is what a majority of what we build with now.
Doing this insanity also created a way for mangers to make sure their year-end reviews looked good and polished. Every time an app that was built on a framework a few years old, suddenly a manager would declare it "dead" and needed to be re-built in record time (because the new framework allows devs to build Rome in a few days time). We would bust ass, usually hitting the deadline with something put together with duct tape and code no dev would willingly sign off on. Manager gets their raise and bonus at the expense of a host of devs running for the door.
Rinse, repeat. But 100% of the framework changes were always pushed the hardest by the devs.
> If it were I suppose we would be seeing way less react and more vanilla with jquery on forms and normal website stuff.
The reason we moved away from this and into functional/reactive programming with things like React is that it eventually creates a mess too big to untangle. We made this experience with human developers and I made exactly the same experience with LLMs, trying to go "vanilla". It works for a while but the defect rate rises quickly und the LLM spends a large amount of time navigating the mess it created. I ended up with React again because it lets you express a lot of stuff as pure transforms, which are easy to reason about for human and LLM alike, and the LLM knows it very well out of the gate.
And by "React" I don't mean "react router" and all the other unstable crap in the ecosystem. React itself is stable and that is extremely important for LLMs, otherwise it will constantly conflate what the API actually looks like now. Breaking API changes are poison, worse than going with an in-house library that the LLM doesn't know how to use, because at least then it will look it up straight away, rather than messing it up (because it _thought_ it knew how it is supposed to work) and _then_ looking it up..
A lot of times, most web app would be way better with purely server rendered pages. SPAs usually introduce a needless artificial separation. Too many times, I’ve seen an API that is tightly coupled with the web frontend instead of being agnostic and then starts being a maintenance nightmare because you have to coordinate across whole codebase because any Change Request updates the interface.
If you want an nice interactive interface SSR just won't do, it will inevitably leak. The separation between pure data and how that translates into UI through a wire interface is both natural and arguably desirable for many reasons. Typescript is a good language for UI. Java is a good language for backend. I disagree that evolving the API necessitates UI changes, or vice versa. You do need some amount of coordination of course, but if you can have developers do SSR, you can also have them do both SPA frontend and REST backend work - now more than ever.
Unless the interactivity would have span page reload, there’s no need for SPA. Figma, Spotify and Google Docs are food candidates for SPA as they have state that need to survive page navigation.
But in most web apps, interactive widgets are just little islands in the page. The higher concerns are routing, authorization,… which are already handled by the browser/server interaction.
I maintain a large reservations platform that I built as a SPA. Reservation systems are something that definitely needs to maintain state across pages, and where for instance the status of a customer's upcoming or cancelled reservations aren't simply walled off in a widget, but have effects across what actions are available to the customer. So it's surprising that so many of them are these terrible, slow and disjointed frankenstein SSR sites. (Think e.g. British Airways).
As with any SPA it should also be considered a problem if widgets updated themselves out of sync. My bank's reactive has this problem, and it's maddening. So my approach is to have all widgets and UI refresh upon central events from a single source of truth that's progressively updated as a data bundle from the server. Long poll the whole set of customer data, refresh it immediately after actions, and have those both trigger events that are recognized by all my vanilla widgets. What are we talking about? 15k over the wire every 30 seconds or on demand? Widgets that know how to adjust if something relevant to them changes? No big deal.
It's a different paradigm from either reactive or server side rendering, and the main advantage to me is the data consistency, as well as the development ergonomics of essentially having every UX element be just a view of the same data.
SSR on reservation systems looks incredibly cumbersome to me. Especially all those that still use crazy GET strings to hold state. "Pages" and user state are a front end concept.
“Pages” is indeed a presentation concern, but state isn’t. Often in SSR, user state is stored server side and identified by a cookie. You only need this cookie on the presentation side and not have to store a copy of the whole state like you usually do in a SPA.
In most SPA, state is distributed with two copies floating around. Even if you do restrict the update flow, it’s still a lot of works to keep it consistent. That’s good enough when it’s partitioned and each side take care of its own state, but in most cases, the intersection is very large.
With SSR, the “page” is a dead copy. The only source of truth is the backend.
> In most SPA, state is distributed with two copies floating around.
In all client-server systems, state is distributed with "two copies floating around". The difference between SSR and REST+SPA is that in the SSR, your server code is creating the markup to make it presentable to an end-user, but it's still fundamentally a copy of the state that exists on the server, and it's not obvious why the transformation to markup rather than structured data (like JSON) is desirable on the server. If anything, with SSR you need to copy more state from the client to the server, where it doesn't really belong.
Either one can show a user stale data. Both need backend checks on user actions to make sure the user's view is current.
In my SPAs, server calls and the state copies they return to the client are numbered sequentially from the start of each session. A server response with a number earlier than the last client call is ignored. That mostly takes care of race conditions that arise from latency. Fundamentally this is similar to SSR in that the client will not update until the server sends new data... there is no client-side modification of the client data copy, ever, so it can never diverge from the last known server state. That would of course be a disaster. The difference is that the page can change progressively without reload, and the state is available between "pages" without more calls to the server.
This is exactly the approach I advocate for, always rerendering whole app on any data update. The components are very simple, basically just views parameterized by passed in props. The data fetch is in one place. Components notify top level on data change which necessitates a fetch/rerender
Unfortunately I get shouted down by those who think we must be maximally efficient even though in makes little difference in render time, and hate “prop drilling”
>there’s no need for SPA
Many people phrase it like this, insisting that server-rendered HTML is simpler. To me, SPA's are the simpler approach. They remind me more of the .EXE's I used to ship.
The complexity is in the host of tools, libraries, and processes to build and deploy the SPA.
As long as you stick close to first-party defaults, you can circumvent almost all of that. I've had far less trouble with build steps in SPAs that follow this philosophy, than with most native environments. It only becomes an issue if you need to layer tons of individual dependencies for things to work.
I also stay away from dynamic prerendering and/or hydrating. If an SPA can't be hosted statically, it should have a very good reason.
IMO building around Vue has really paid off over the last decade. They fixed the frequent Webpack config issues with Vite, they fixed the frequent Jest issues with Vitest, they improved build times a lot with Rolldown and oxc, they fixed all the annoying linter/formatter config stuff with oxfmt & oxlint, and Vue itself prevents tons of issues that plague React projects.
From my own experience, I suspect you are conflating correlation and causation.
I have seen countless "founding engineer" job ads with every little detail of the desired stack/architecture spelled out: Java/Spring/MySQL/Linux/Log4J, C#/RabbitMQ/MSSQL/SSIS/Windows, etc. Non-technical founders/recruiters/etc don't want to "leave things to chance", and will happily overly specify the constraints, mostly informed by popularity ("Nobody Gets Fired For Buying IBM"), rather than leave the solution space unconstrained for some "generalist" to choose. I mean, how do you even know someone is competent if you can't grill them on a concrete set of buzzwords?! The horrors! So of course the recruiters gotta make up constraints to find someone "qualified".
Heck, I've personally seen this pattern at every step of company growth, from 5 employees to hundreds. I've watched as my employer's recruiters would explicitly seek tons of things we weren't yet using. Why? Because when performance isn't as desired, the first thought is not "hey, maybe our approach to managing people and projects is dysfunctional", but rather "maybe we just haven't found the silver bullet yet; let's go shopping". In my experience over 20 years, that represents 99% of the cases where new crap gets introduced: Scrum, Jira, SQL Server Integration Services (SSIS), front/back end frameworks, consultants ("our developers must be idiots, so let's get outside experts"), etc.
I think it is true that there are cases where developers will push for things like particular front end frameworks, but that's almost always the exceptionally rare case where there's any resistance to push against: few companies aren't already using the stack du jour, so most developers (especially greenhorns) will have bought into that stack ('cause "gotta pay the bills"), so a new developer brought into a nonconforming engineering org will quite likely want to use the tools they know and thus push for it. The real culprits, though, are usually the non-engineers: founders/recruiters/etc who create a financial imperative to adopt whatever is trending, which results in developers who spread that popular mediocrity elsewhere.
> If it were I suppose we would be seeing way less react and more vanilla with jquery on forms and normal website stuff.
This is backwards. The pressure from the business/product side is to create more and more interactive applications. Jquery hit its limits supporting that reasonably, sometime around the early 2010s.
The frameworks are almost always listed in the job requirements.
Why wouldn't they be?? That says nothing about who's pushing it. Companies ask for it because developers use it. That's what makes hiring easier.
But developers tell the company to use it because they need it on their resume for the next gig.
I've seen sssoooo many startups use tech stacks that are completely unsuitable for their use case, but the developers are keen to use that stack because it's the latest hotness and it looks good on their resume.
Individual contributors are almost never writing job postings or performing hiring.
I didn't say they did. I said companies writing those job descriptions does not establish causality. You've got it reversed.