This is something that I see espoused by "web traditionalists" for lack of a better term. Sure, there are a lot of web developers who are not optimising for performance but I think the difference is that it has simply shifted to the frontend where it's more noticeable.
The kinds of people who care about performance in the backend are exactly like the kinds of people who care about performance in the frontend. There's a variety of techniques that make sense in both areas to create a snappy, seamless experience. You need experienced engineers to create performance no matter what your domain is.
We've gone down the route of creating SPAs to largely replace experiences that would require desktop applications (it was only 5 years ago that I had to download an executable to do my tax return, now I do it with an SPA). Rather than create an SPA for a blog or a simple marketing site, we've largely replaced traditional "heavy"[0] infrastructure (PHP, Apache, MySQL just to display static content) with static JavaScript-generated sites. Many of these can simply be hosted on a CDN because they have no database and often no need for complex routing.
Pretending that SPAs were part of some dark ages is just silly. Horses for courses. If your application requires what I've dubbed "heavy" architecture (above) then by all means! Such infrastructure allows a high traffic service to be highly available, but is not required to serve a single .html file.
[0] When I say "heavy" I'm mainly talking about the attack surface and maintenance required. WordPress is great for serving a blog but has been the target of many hackers due to the amount of security vulnerabilities it has had over time.
>You need experienced engineers to create performance no >matter what your domain is.
Actually the funny thing with HTML is that the simplest things are fast. If you just write a old school HTML web page without a bazillion frame works and not going too heavy on graphics things are usually fast.
And doing that is literally so much simpler and easier than learning all the super complicated frameworks of the day.
So it's a progression from initially fast for simple, to slower and slower as people learn the complicated (and slow) frameworks, and then eventually maybe fast again if you have an expert who can make all this mess fast again.
Most people never reach that expert stage of course, but sadly still leave the "easy and fast" stage.
This perspective is reasonable, until you start applying it to highly interactive / dynamic GUIs.
Real-time chat is the most obvious case where the html purist won’t offer an acceptable experience.
Another example: any page that displays a row/table of data that the user wants to sort (frontend libraries make sorting instantaneous, compared to full page refreshes with html-only).
There are lots of people using complicated frontend frameworks in cases where pure html from the server would obviously be better. But it’s difficult to argue all libraries are bad and slow for every application.
> Real-time chat is the most obvious case where the html purist won’t offer an acceptable experience.
The retro approach is to have two frames. One to submit, one to slow-stream a bunch of html elements which we can thankfully now lay out via flexboxes which are highly efficient when it comes to relayout, i.e. only the appended elements would incur some runtime costs, the already rendered ones don't get recomputed.
I have seen chan-style imageboards that update posts as people type (every dozen milliseconds) with 10k posts in a thread. The layout recomputation overhead is really low.
> Real-time chat is the most obvious case where the html purist won’t offer an acceptable experience.
I can’t recall the last time any website offered me an acceptable embedded chat experience (not counting dedicated clients like Discord) so that’s all for the better.
Yeah if you actually want to sort datasets of any meaningful size, you’ll be making requests to return database results anyway since a database is going to be infinitely faster and more comprehensive than any client side solution.
Server side rendering is not really that slow, and SPA is not really that fast if your bundle size is huge.
More important is that most users will not able to distinguish the difference. I have asked my friends how they feel to compare Facebook to a traditional MVC web site in term of speed difference, none of them can feel the difference.
However, the transition from page to page do affect the user experience. As a user, when I want to do a task that involve many UIs and I need to click multiple pages, I will think it is a bad experience, but I do accept to switch to another page for another task. Therefore, It makes sense to have a SPA for some rich UI feature so that user can remain in the same page
SPAs being the darks ages is over-the-top, but being an SPA when other web architectures could better serve the user is a dark pattern. That tax app doesn't need to be an SPA. JavaScript powered interactions make the experience nicer for the user, but that doesn't mean it needs or is improved by being a single page.
I feel like Gmail has lost that edge. Email being a text medium should be fast, but Gmail using up many hundreds of megabytes of RAM and taking many seconds to load really feels like they've lost sight of what reading an email is about.
I too despise the "kitchen sink" approach seen in Gmail's UI where they are trying to cram every unwanted and unnecessary feature into your view and RAM at once.
If you used "Inbox for Gmail" before Google abandoned it and miss the much cleaner and focused UI, this Chrome extension upgrades Gmail to have the same styles:
No, it doesn't need to be, but it is nicer. There's quite a lot of complexities to my country's tax law (as with any country's tax law, really) and it's heavily simplified by giving you highly dynamic choices. Trying to use my country's immigration site, which has some JavaScript sprinkled on but is largely static, is a largely inferior experience.
There's no reason you can't query a backend for the complexities and present those dynamically to the user. For instance, quite often an SPA might ping the backend for a list of states or provinces once you've selected a country.
Sure. It's up to the engineer implementing said app to determine the best fit for the project.
At the end of the day, you have to choose what's right for your users; whether that's a seamless experience with no full page reloads, or the occasional full page reload.
If it's a web-based user interface as this tax app sounds to be, it is arguably improved purely by being an SPA. Requiring full page reloads just to submit or change some tiny bit of data in a page is objectively bad UX.
A problem is, that I need to fiddle around with JS blocking, even on official websites from city, state or gov, because they hired inresponsible web devs or made inresponsible decisions to let Google and others track me on their website. So initially they will be blocked. As far as "experts" for SPA are concerned, they often do not even include a noscript tag, which means I see a white page. Now it cannot become less user friendly than that. I've yet to see a SPA, which offers a working alternative via noscript tag, when I blocked all their tracking.
The thing is that SPA all too often serves as a way to force tracking onto the unsuspecting user. "You need to allow our JS! Your browser is outdated! Use Chrome!" and the unsophisticated person will think: "Oh well, lets just whitelist this page dammit!"
Mostly I want my forms to be reliable, that doesn't seem to be the case for many SPA's. Getting a blank page is a very common experience and much worse than a barely discernible delay submitting a form.
"Single page" isn't the why it's the how. It enables you to take a JavaScript-first approach which in turn makes building complicated applications easier.
SPA gives you all the state stored client side, backend can be reduced to simple stateless functions. Anything persisted longer goes in the DB, and plenty of solutions exist that automatically keep the client side view of the DB and the backend in sync automatically, even across temporary loss of connectivity.
Compared to the bad days of server side session management, SPAs are far simpler to code and to reason about.
The elimination of the back and forth between client and backend means far less testing, and far simpler testing.
It is also arguably more efficient. Yes it uses more resources on the client compared to doing everything server side, but cpu and memory needs to be used no matter what. Treating web browsers as dumb terminals when the cheapest smartphone is at least quad core is a bit silly.
That said, there isn't any excuse for bad client side code that murders CPUs, but not using the client for anything but JPEG decoding doesn't make much sense!
To word it more technically, building an SPA allows you to build applications as declarative composable functions which are deterministic, as opposed to the spaghetti code commonly seen in the days of jQuery and PHP which is harder to read, reason about, debug and maintain due to their imperative and nondeterministic nature.
> building an SPA allows you to build applications as declarative composable functions which are deterministic
How is that not the definition of a function or a method?
Deterministic in what sense? It’s output? It’s input?
Bad code exists on any language. Looks like you’re comparing bad code/coding practices to good ones, that’s another thing and completely irrelevant of the language.
> How is that not the definition of a function or a method?
It basically is and that's the point. With SPA's you generally structure it so your entire app is just a function. The same cannot be said of traditional server/client apps which consist of multiple moving parts (PHP backend / jQuery frontend) which do not have an explicit contract with each other, you're just taking shots in the dark hoping your jQuery selectors match up with what the PHP backend spits out.
> Deterministic in what sense? It’s output? It’s input?
What? There is only one sense in which something can be deterministic, which is given the same input you always receive the same output. PWAs are generally deterministic because they're just functions that take an input and give you back a DOM. Non-PWAs are non-deterministic because what you ultimately see can change depending on what generated HTML the server gives back, despite being given the same user-input, it can also change based on unrelated side-effects, for example, imagine you have some jQuery feature that resizes an element, and another one that changes it's background-color. The behaviour of both features are non-deterministic because the outcome of each depends on implicit state accumulated externally by the other one.
> Bad code exists on any language. Looks like you’re comparing bad code/coding practices to good ones, that’s another thing and completely irrelevant of the language.
This has nothing to do with languages, it's about project architecture and programming paradigms. The classic webserver+jQuery type architecture is inherently imperative. Of course it can have little islands of functionally pure, declarative code, but the overall software architecture is still imperative.
In a nutshell, traditional non-PWA software cannot be written in a fully declarative paradigm due to their nature, every non-PWA app on the web is intrinsically a jungle of imperative code, making assumptions about accumulated state. PWA's are generally written declaratively, where all state and dataflow is explicitly managed, and output is deterministic based on a given input.
> The same cannot be said of traditional server/client apps which consist of multiple moving parts (PHP backend / jQuery frontend) which do not have an explicit contract with each other, you're just taking shots in the dark hoping your jQuery selectors match up with what the PHP backend spits out.
If you don’t know how your code will work, that’s an issue with the quality of the code.
> What? There is only one sense in which something can be deterministic, which is given the same input you always receive the same output.
Agreed.
> Non-PWAs are non-deterministic because what you ultimately see can change depending on what generated HTML the server gives back, despite being given the same user-input,
With a language like PHP, if you call a function twice with the same input, why would the function return 2 different outputs?
> it can also change based on unrelated side-effects, for example, imagine you have some jQuery feature that resizes an element, and another one that changes it's background-color. The behaviour of both features are non-deterministic because the outcome of each depends on implicit state accumulated externally by the other one.
If your application also does this, the only difference is that you’re not using jQuery for it.
The output of this is deterministic. Given jQuery works, the element will resize and change color.
> In a nutshell, traditional non-PWA software cannot be written in a fully declarative paradigm due to their nature, every non-PWA app on the web is intrinsically a jungle of imperative code, making assumptions about accumulated state. PWA's are generally written declaratively, where all state and dataflow is explicitly managed, and output is deterministic based on a given input.
The assumption here is that declarative is deterministic and anything else isn’t and that’s just not true.
Determinism isn’t a function of the language, structure or paradigm.
If something is deterministic is dependent on the algorithm it has.
> If you don’t know how your code will work, that’s an issue with the quality of the code.
No, it's a fundamental difference between declarative and imperative programming. With imperative programming (e.g. PHP + jQuery) you cannot know what's in the DOM resulting from PHP-generated HTML you are working with, you need to either make naive assumptions about the DOM or litter your code with conditions checking the state of the DOM before operating on it. With declarative programming you declare the structure you want, so you know exactly what you have, because it's what you've declared. There's no need to check that the PHP backend rendered some element to the DOM to enhance with JS functionality, because I already declared that element is in the DOM in my JS directly.
> With a language like PHP, if you call a function twice with the same input, why would the function return 2 different outputs?
Again, this has nothing to do with languages and is purely about programming paradigms. What you're referring to is one of the possible "islands of functionally pure, declarative code" I previously mentioned. Pure functions in PHP can be deterministic, and pure functions in JS can be deterministic, but the overall application behaviour of how your front-end (jQuery) handles the output of your back-end (PHP) results in the application being non-deterministic. For example, say you have some form that submits data and on the posted page, displays a green thankyou message in a div. Say you want to animate this div message with jQuery. You cannot safely make any assumptions about the presence or prior presentation of the div, because from the context of jQuery you don't even know if the form has been submitted and the div rendered by PHP. You need to either:
- Imperatively check the current state of anything you wish to change prior to changing it.
- Naively make assumptions about prior state resulting in non-deterministic behaviour.
jQuery makes this easier by solving that problem on node "existence" with their selector-based API which simply doesn't run your function if the targeted nodes aren't found, but the problem still remains for general state, any jQuery code needs to either explicitly check the state of everything it touches (brittle code, hard to reason about and maintain) or make naive assumptions and be non-deterministic (which seems to have been the norm).
> The output of this is deterministic. Given jQuery works, the element will resize and change color.
False, it is non-deterministic because the ultimate outcome (what you see) depends on implicit state from side effects. For example if you toggle the resize control, the resulting display is based not only on your action (input) but also whether the colour change button was already pressed (an unrelated side-effect not a concern of the logic for resizing), or if PHP initially rendered it in a different size/colour, or maybe PHP decided to not render it at all because the user's session ended? From the context of jQuery you can't determine any of this, the only way you could come close to deterministic behaviour is by explicitly checking every single bit of stateful DOM before working on them, which I've never seen done in a large project (and would be hell to maintain).
> If something is deterministic is dependent on the algorithm it has.
Yes and any algorithm which has its outcome impacted by side-effects or unmanaged state (i.e. pre-rendered HTML/DOM from PHP, changes to DOM from other side-effect causing callbacks) is inherently non-deterministic. For an algorithm to be deterministic it needs to take every single thing that could affect it's outcome into consideration as input, and I have yet to see any jQuery apps which parse the entire DOM and use it as input to achieve deterministic behaviour
> The assumption here is that declarative is deterministic and anything else isn’t and that’s just not true.
No my point isn't declarative being inherently deterministic, rather that imperative is almost always inherently non-deterministic. By the nature of imperative programming you are making assumptions about your environment (i.e. there's DOM nodes to work with) which makes it intrinsically non-deterministic (those DOM nodes could not even be there)
Well, I'd argue that old fashioned PHP sites are structurally really similar to modern declarative client-side UIs, in that in both cases your're basically just constructing a series of functions that (deterministically) convert the current state to HTML.
Client-side rendering without declarative framework (say jQuery or vanilla) is different, in that you also need to consider state transition. This gets complicated fast.
And of course, the trade-off between the old fashioned approach and modern declarative revolves around how much interactivity is required.
If you can get away with it, I'd say the old fashioned approach takes less development time because you don't need to handle asynchronous (and possibly failing) state syncs. The database containing any state you might want to access is available synchronously!
Yeah fair call and it's more the combination of PHP + jQuery I'm referring to as being non-deterministic rather than either on their own - you can definitely write deterministic PHP and jQuery code, but the implicit integration between them (PHP rendering HTML which becomes a DOM which jQuery imperatively operates on) is what I'm saying makes it non-deterministic. I'm mostly talking about the part you mentioned in managing client-side state using a non-declarative paradigm, where you either end up with a stupid amount of unnecessary complexity (conditions checking the prior state of literally any and everything you touch, I've never really seen this in a production project) or making naive assumptions about the DOM which means non-deterministic and potentially unexpected behaviour.
> If you can get away with it, I'd say the old fashioned approach takes less development time because you don't need to handle asynchronous (and possibly failing) state syncs. The database containing any state you might want to access is available synchronously!
Fair point but there's also a flip-side to this though. You can write a client-side PWA with all your async state and data persistence magically handled by a service like Firebase Cloud Firestore, so just writing the UI declaratively and not having to worry at all about servers or databases, which generally requires a lot more upfront planning (figuring out models/schemas to represent your data, service architecture etc) than just slapping a UI together and wiring inputs up to a production-ready persistence layer API in front of a schemaless NoSQL DB like Firebase.
I mean... not really. I wouldn't invest in building client-side applications unless they bought me something. My customers don't really care, the majority don't even know what an SPA is. They do care that our application is faster and has more features than our competitors.
What in JavaScript are you using to take the place of a server side database?
Your comment seems to imply that the only options are SPA or WordPress..
If you are building something that would normally need to be a desktop app, sure, an SPA might be a good idea. But this is still rarely the case, most web pages are just are just presenting data, and in those cases, the less JavaScript the better.
Yup, exactly that. WordPress editors (WYSIWYG and Gutenberg) are still far more user-friendly and mature than a Netlify CMS that still is buggy like hell and where many little details and YAML formattings need to be fixed in code editor. You really cannot expect such a thing to be done by a non-coding person.
Are you aware of any open source applications as a CMC for static generators like Jekyll? Would be very convenient to have one with a a simple github login/auth settings page and then add/edit page/post options and the ability to select or upload a theme would be great.
A huge variety of plugins, and a large pool of cheap developers with plenty of experience in the stack. I personally like Jenkins, but if I’m handing the site over to a low-tech client, I’d use WordPress hosted on managed WordPress.
The kinds of people who care about performance in the backend are exactly like the kinds of people who care about performance in the frontend. There's a variety of techniques that make sense in both areas to create a snappy, seamless experience. You need experienced engineers to create performance no matter what your domain is.
We've gone down the route of creating SPAs to largely replace experiences that would require desktop applications (it was only 5 years ago that I had to download an executable to do my tax return, now I do it with an SPA). Rather than create an SPA for a blog or a simple marketing site, we've largely replaced traditional "heavy"[0] infrastructure (PHP, Apache, MySQL just to display static content) with static JavaScript-generated sites. Many of these can simply be hosted on a CDN because they have no database and often no need for complex routing.
Pretending that SPAs were part of some dark ages is just silly. Horses for courses. If your application requires what I've dubbed "heavy" architecture (above) then by all means! Such infrastructure allows a high traffic service to be highly available, but is not required to serve a single .html file.
[0] When I say "heavy" I'm mainly talking about the attack surface and maintenance required. WordPress is great for serving a blog but has been the target of many hackers due to the amount of security vulnerabilities it has had over time.