I suspect that perhaps you've learned primarily front-end frameworks for the majority of your career (an assumption, sorry if that's not right), which will make it seem as though frontend is easy compared to all this mystery stuff you're not used to working with.
It's the same for me, but the other direction. I've always worked with server-rendered applications, so to me all that stuff is super simple and working with frontend technologies involved learning a swath of new paradigms and tooling, so it seems like the more complicated one.
I think the learning point for me is simply that you're probably not going to care about what my arguments for server-side languages are, because it's never going to map to your experience of them. Just like I don't agree with any of your general points in the second paragraph.
React isn’t too bad, as such things go, but compared to server rendering SPAs are such a slog.
There are good reasons to build them sometimes, but “fast and easy” is not one of them IME.
I was halfway through building a site when I switched to Vue. It ended up reducing the number of lines of code by 30-40%, and made the interactions much simpler to reason about.
Now that I know Vue, I think it's a vastly better way to develop than without it.
That's because understanding rendering speed is your job, not the client's job. What the client will be saying is things like "Why are my conversions so low?", "My site doesn't appear in search results." and "My friend's neighbour's dog-sitter told me my website sucks because it takes ages to load." It's your job to translate those comments in to meaningful actions, like optimizing rendering speed.
Which is sort of a weird point. So much of the web development blogosphere assumes that the reader is working on a site that sells some product direct to the public, who are very fickle, and will abandon your site quickly. Undoubtedly that industry does exist, but I've just never been anywhere near it.
If I'm able to render things from the backend, I just have to query the data and slot it into the page. No need to design an API that's flexible enough for application use but still inflexible enough to prevent security holes.
Also, if I decide later to update how the data is represented (a common activity in early-stage projects), I only have to edit only one thing instead of two things.
On the code level, it's really not all that different - the operations you perform 'directly' through function calls in a pure server render model you simply put behind another HTTP interface.
I get that this mapping work might be a bit cumbersome and take some extra work, but I'm unconvinced that it introduces some kind of security tradeoff - the client ultimately has the ability to call through to exactly the same operations, just getting the data back in a different format, right?
Instead I have to figure out what data access patterns my frontend will need and implement those, along with whatever visibility restrictions are required. I'm forced to do the former in the backend (as well as the frontend) because the latter can only be done in the backend.
(Aside: I realize that back in the day people did indeed use database mechanisms like DB users and stored procedures to do what I describe, and then client apps connected directly to the database. But this practice seems to have faxed and isn't readily doable on the web anyway).
> (Aside: I realize that back in the day people did indeed
> use database mechanisms like DB users and stored
> procedures to do what I describe, and then client apps
> connected directly to the database. But this practice
> seems to have faxed and isn't readily doable on the web
> anyway).
This is actually exactly what postgREST does for you. So in that case, you actually can eliminate the backend entirely and run the entire application in the frontend, with the security provided by stored procedures and row-level security. I think Firebase, which is somewhat more widely used, also enables a similar architecture.That said, I actually agree with your preference for server-side rendered applications. The problem is that from the browser, you can't really do anything that is not SQL -- you can't, for example, call into a C library, query a legacy API, and so on. Of course, all of that can be solved by deploying more microservices, but that not only means you have to think about API design again, it also increases operational costs. Unless you need lots of fancy live-updating things, server-side rendering is still fine, and even when you do need to update dynamically, there's Blazor Server now.
> "client should only be able to perform certain kinds of transactions and mutations"
The solution to these is equal for server rendered HTML containing {data} or an API just getting {data} in raw form - the request contains an access token which identifies and authorises the user - same goes for mutations on {data}.
The answer to the question 'how do you know who the user is when they request a server rendered page containing some sensitive data?' is literally the copy/paste solution to how to do authentication on your API - as in, it's basically the same code that must be implemented on the backend in either case :-)
The point is it's the same data and mutations, just a different interface over them. There is no security tradeoff of using one over the other.
No, it's not. If I expose an API e.g GET /widgets,I need to ensure that there is no combination of parameters that will ever return a widget that the user should not see (e.g because it belongs to some other department).
Whereas when I render a web page server side, I just need to write a single, correct, SQL statement that pulls in the widgets that this specific web page requires.
It's the same data, with the same auth needed. If it's accessible to anyone over the network you need auth for everyone in either model. The auth code is the same code in either model, only the interface changes.
Looking at your example to illustrate: you have user A and user B, who have permission to see different types of widgets depending on what department they belong to.
--
Scenario 1: filtering per-resource
There is a server-rendered /widgets page that lists all widgets, filtering based on what types of widgets the requesting user can see.
API implementation: /widgets endpoint that returns a list of all widgets for the client to render. It must filter based on what type of widgets the requesting user can see, so that only widgets they can see are included in the list. Same logic as above.
--
Scenario 2: grouping resources and authenticating at entry
There are different server rendered pages for each department, listing all widgets for that department: /widgets/foo-dept, /widgets/bar-dept. You must check the permissions on the requesting user before rendering the page, to see if they have access. If user A can't see foo widgets, you give them some kind of permissions error when they request the /widgets/foo-dept page.
API implementation: Add a dept param to the /widgets endpoint that lists only widgets in the specified department. If dept param is populated, check that the requesting user has permissions to see widgets in that department. If they do, proceed, if not, throw a permissions error and deal with it on the client to produce the exact same UI as in the server rendered example. Same logic as above.
--
If you have resources accessible over the network, and you do auth on them based on user attributes, you have to do that auth either way, regardless of if you're server rendering the data into HTML pages or returning it as JSON or whatever else and rendering the HTML on the client.
The goal of both applications is to display HTML. The duplicated work in an SPA is in the DB API -> JSON API and JSON API -> page steps. These steps involve telling my backend server about how my data are structured and how to interpret them, translating them to JSON (or something else), then telling my frontend the same things. Every SPA I have seen involves doing this work, although some (like Meteor) are designed to reduce it as much as possible. That's the standard work involved in an SPA.
The second half of my point is that you could remove this duplicate work but doing that gets rid of any security. Why is this? Let's look at my SQL API example again. In this example, I have effectively eliminated the duplicate work of making my app server aware of the data's schema. It just runs a query, serializes the blob that comes back, and returns it. So why not do that? Obviously because now I'm trusting the client too much. In a non-SPA world it's fine to trust the entity making queries (for the most part...let's not get derailed). In the SPA world it's not, so we inject the app server in between to do mediation, and we pay the cost.
In my experience, it hasn't been the case: designing a REST API (I know REST complexifies the API compared to tailored RCP) that behaves properly for the client is magnitude more work than rendering HTML with data server-side.
The main difference is switching the question from "what does this page needs to render for this user", to "what are all the things the front-end might want to access through this API for this user, and how do the front-end plan on filtering". The former is obviously easier to answer, and as the result easier to code.
Honestly most of the time you can even just cut out the REST layer except where it overlaps with views by coincidence. For instance in practice there are quite a lot of views which simply get a single resource, or list a single type of resource with paging.
For mutations I am a big fan of just doing it RPC-style. I know it's not to everyone's taste but I feel like abstracting mutations out behind a model of RESTful resources and verbs is, 99% of the time, a waste of time, the notable edge case being where you truly need a flexible API for 3rd parties (both apps with UIs and scripts) where organising functionality in this completely generic flexible way - with the considerable extra effort that you mention being the price to pay - has huge payoff.
100% agree. But that (authentication) is not what this thread is about.
> The point is it's the same data and mutations, just a different interface over them. There is no security tradeoff of using one over the other.
100% agree again. A properly written application makes no security trade-off here by using an API. But that's because a properly written SPA stack does the work of interpreting the data and it's relationships twice on both the frontend and backend.
This section also frequently applies to security.
> but still inflexible enough to prevent security holes.
Unless it involves a transaction or government secrets, security is usually way down the list of priorities.
Tell me that React websites today will still be around in 10 years time. With constant upkeep and maintenance, maybe. If a website is just a static website, not making it plain HTML is a disservice. The layers of abstraction will take its toll.
On my website I have pages which date back to 1993-94. Still readable just fine. I used to post those links to mailing lists back then and they still get regular hits from people in that community because I've also maintained the URLs constant.
In my professional life though, I realised that 95% of the things I build will be changed in the next year or so. We often inherit projects that were only just finished, and our first task is to start changing it entirely.
So I aim for robustness of maintenance rather than robustness of the finished product. It's inevitable that it will change, but I can anticipate that in the same way a well engineered car can anticipate it's maintenance cycles.
My agency regularly take over older JavaScript projects - built in whatever JS-stack was trending at the moment. There are always big parts of the stack that are no longer available or in active development. Not to mention the enormous hassle it is to bring dependencies up to date for a JS-project that hasn't been updated in three years.
Depending on the circumstances we usually recommend moving it to a boring CMS like WordPress unless there are compelling reasons to double down on the JavaScript stack (if it really is more of a web application for example.)
As an industry, this is called job security. It is fascinating to be in an industry where systems requiring high levels of maintenance are preferred by the client.
Large entities have need and budget for their applications to evolve. The delta for websites is less intensive. For the latter, reliability and longevity is important.
[1]: https://developers.google.com/web/updates/2019/12/chrome-80-...
[2]: https://stackoverflow.com/questions/30876093/will-chrome-and...
I can explicitly tie together components/html client side via JS (annoying). Or I can simply render the correct html (no need for json routes) while I have access to all of the data on the server. Rendering speed as you mentioned (client or sever), is basically never a consideration.
So why bother explicitly writing javascript to bind html components together when I could just simply render the correct server side HTML?
Ajax is fantastic, but you don't really need an SPA.
If you want to be wildly productive, minimize the javascript you write.
I'm a big fan of intercooler.js btw.
the differences are rather in the architecture.
you can win or loose a lot there, by choosing the right or wrong one.
by creating an SPA you win a much simpler backend, you separate data storage and processing from data presentation.
you win the ability to have multiple different frontends against the same backend, or run multiple backends against the same frontend.
you win the ability to upgrade/replace backend or frontend independently.
you win the ability to develop with multiple independent teams because the connection between frontend and backend is smaller and easier to define.
you win the ability to reuse generic backends over multiple projects...
these are a lot of advantages, if you need them.
but there are downsides.
you no longer have a single codebase.
you need to maintain an API
rendering is slower in the browser.
depending on what kind of application you create, you may need to be careful to not put any business logic into the frontend. (anything with business logic goes into the backend with an api to access it)
it should be clear by now that i am a strong supporter of this architecture.
i may miss some downsides of an SPA and i'd love to get more input on other potential downsides, however, loss of productivity from writing javascript is not one.
You are obviously writing more code for client side HTML generation based on JSON than regular server side rendering... I am saving effort if I need to write fewer files...
Your feature requires a JSON route, html rendering, and javascript that pulls everything together. Mine is just a route that returns HTML. Why is there absolutely no difference in effort? You have 3 files, I have one.
separating data from presentation is not new. It has nothing to do with SPAs
i have used different backend and frontend frameworks, and i found that backend frameworks do not make things simpler in the sense that you are talking about, if you want to create clean and maintainable code.
sure you can put everything in one file, but the number of files is a meaningless metric. more useful is the number of functions and abstractions. an API is an abstraction. you can do away with that if you generate html in the backend, but the price you pay is with a much closer coupling of interface and business logic that will make future changes harder. in any sufficiently large site you can't afford that and you end up rewriting your site to create the same architectural complexity simply because you need it.
SPA frameworks query the server for JSON and then render HTML right?
Simpler in the sense of what? You prefer to not have all of the variables available when you render HTML? It's simpler to only render client side HTML and to query 4 different AJAX endpoints for resources?
Why are you trying to separate business and interface logic? Why are you displaying anything that the business logic doesn't understand?
The entire point of good code is that I can edit 1 file instead of editing 3.
Back end frameworks don't help you organize code? That's kind of their point?
The end result looks very similar to the server side frameworks of old, so it's a bit of a circular evolution. I think only using one programming language (the one that is part of the web platform) and a solid, template free component framework make it incrementally better though.
You can still and should have an API but it will be an internal one(in-process, not at the network boundary).
The code inside the API is an abstraction.
> you win the ability to upgrade/replace backend or frontend independently.
> you win the ability to develop with multiple independent teams because the connection between frontend and backend is smaller and easier to define.
> you win the ability to reuse generic backends over multiple projects...
None of these are really specific to SPAs, they apply to any architecture with a separation of concerns.
It's simpler if you only write the front-end, because it de-couples the work with the back-end.
If you are in charge of both front-end and back-end, server-side rendering is easier.
It's a case of Conway's Law. Knowing that, you may choose to have a back-end team and a front-end team or a team of full stack developers depending on the end result you want.
Personally I think it depends on whether the Web is just another client for you, which consumes APIs like native applications, or if your product is entirely web-based.
This is nonsense.
Both the frontend and the backend influence the design of each other(and for good reason). The notion that you can build one without the other and be done with it is just wishful thinking.
There are very few upsides if you already serve pages server side and look at current client side js development.
Because they rarely know about it. And why would they? It's a very technical choice. Factoring in things like render speed is your job when picking the most appropriate solution for the problem at hand. When you're doing this you are placing your own comfort and ease above that of anyone using the site. Google already factors site speed into rankings and with all the Web Core Vitals stuff they've been pushing lately it's only going to be more important. You're failing your clients.
"Haha react goes brrrr"
If your clients are like mine, there are likely a lot of things your clients don't ask for. For instance, accessibility. Do we ignore that as well?
You're also not factoring in ongoing maintenance. What's easy for you to build and deploy might be less so for someone else. React, Vue, etc. are great tools - when they are the correct tool for the job - but they are still relatively niche. If you're not taking a "what if I get hit by a bus approach" then you're doing your clients a disservice.
You might want to try being a typical user for a month or so. Use a smaller monitor, an older mobile device, a slower internet connection, etc. Then take that lens and apply it to your SPA genius.
Well, some of my clients are government, so they do care about accessibility. For the rest, I put in some effort, because it's the right thing to do. (As opposed to rendering speed, which I really don't think matters, within reason.)
Just to be sure: These two are not the same and server-side rendering does not necessitate writing raw HTML. In fact, I think that most advanced languages used on the server-side have means of not writing raw HTML. There are template engines and some languages offer SXML, which already provides you with a kind of template engine.
Personal opinion: I really don't like having to write raw HTML in form of it being just a string, allowing for all kinds of markup issues, formatting issues etc. A programming language or used framework/library should have awareness of the HTML tags and prevent mistakes. SXML prevents mistakes in nesting for example. In Racket and I think in Scheme dialects as well, SXML prevents cross-site scripting by design as well. What many many people get wrong is how they split up their documents. They forget about composability and use only concatenation (looking at you, wordpress themes ...). This severely limits reuse of code. Good templating languages try to nudge you into the direction of making things composable.
I get that most of the web and most of what web developers do these days are just regurgitations of the same basic website designs. But man there is some really powerful tech in JS and WASM just waiting for someone to make brilliant stuff from.
Never trust the state of the client... Never trust client's input...
No idea what JSF is. Sorry it didn't give you access to the data you needed when you rendered files.
So yeah it happens.
Their old server side solution was near instant.
Definitely the design flaw was to index it in the frontend in the first place instead of preparing that data somewhere in between to easily be consumed by the client but still draws the picture of how many people approach SPAs these days.
Amazon, Google, Walmart, Mozilla, and Yahoo all have numbers that say otherwise.
"Amazon and others found that removing 100 milliseconds of latency improves sales by 1%."
I'm 100% sure there are people who care about 1% differences in sales, and the fact that has been rediscovered independently by different organisations shows that "people" at least "aren't happy" with very small increases in page load times, at least when making purchase decisions. (Whether that extends to people reading your latest blog post or endless scrolling your social media site's newfeed is a reasonable question, which I'm not sure 've got a good enough handle on to have an opinion worth sharing.)
(From an earlier HN submission today: https://instant.page/ - click the [1] link n that page after that "Amazon and others found that removing 100 milliseconds of latency improves sales by 1%." sentence for sources.)
There might be people that misuse SPAs when server side rendering is the better choice but SPAs clearly have use cases that are not possible with just HTML.
Sure, but that's pretty much cherry picked whataboutism when the parent comment we're talking about said: "Most people are happy if the page loads in reasonable amount of time".
So apart from people writing chat messaging widgets for websites, do you have data to contradict the conclusions about webpage load times and rates of change of user behaviour that can be obviously drawn from the Google/Amazon/Walmart/Mozilla/Yahoo data?
That said I am definitely one of the people for whom it does matter.
- 10ms response time for interactions (scroll, click, entering text)
- 100ms for in-page context switch (changing tabs in a dashboard, loading the next picture, etc.)
- 1000ms for page load
these are obviously rough guidelines — page load in particular is obviously gonna depend on your user’s internet speed if you have any kind of media — but they’re helpful when thinking about “reasonable”
Modern web is serving people mostly with nice looking shit sandwiches.
It has nothing to do with standards, businesses don't care about standards in the long run, they care about making money.
If I write something in Django, I can let the forms be auto-generated to whatever degree I like. If I do it as a SPA, I essentially need to twice as much work, as I have to write a backend to serve and consume JSON and a frontend to display and interact with it. Then you have got the nightmare of debugging the mess.
To sum it up, i was programming before the web existed, I hated the old page-post model, I don't build web pages, I build large apps. I am happy that I can deliver them via the web and I am happy about the state of the art. I think it can be improved on quite a bit, but not by going backwards.
But they all miss the point: writing with client-side JS based frameworks (React, Vue, whatever) is easier, faster, more versatile. If you have the option of writing an SPA, it's simpler quicker to build this way, and so easy to deploy.
Sure, it renders slower. I've just signed my 25th professional client, and I have never yet had a client who even mentioned rendering speed, let alone was willing to make any trade-off for it.
Server-side rendering or writing raw HTML are over-rated.