Hacker News new | ask | show | jobs
by RHSeeger 1137 days ago
> We moved away for MPAs because they were bloated, slow and difficult to work with. SPAs have definitely become what they sought to replace.

Plus we now get the benefit of people trying to "replace" built in browser functionality with custom code, either

The SPA broke it... Back button broken and a buggy custom implementation is there instead? Check.

or

They're changing things because they're already so far from default browser behavior, why not? ... Scrolling broken or janky because the developer decided it would be cool to replace it? Check.

There is a time and place for SPA (mail is a great example). But using them in places where the page reload would load in completely new content for most of the page anyways? That's paying a large cost for no practical benefit; and your users are paying some of that cost.

8 comments

> There is a time and place for SPA (mail is a great example). But using them in places where the page reload would load in completely new content for most of the page anyways? That's paying a large cost for no practical benefit; and your users are paying some of that cost.

Yep. It's bonkers to me that a page consisting mostly of text (say, a Twitter feed or a news article) takes even so much as a second (let alone multiple!) to load on any PC/tablet/smartphone manufactured within the last decade. That latency is squarely the fault of heavyweight SPA-enabling frameworks and their encouragement of replacing the browser's features with custom JS-driven versions.

On the other hand, having to navigate a needlessly-elongated history due to every little action producing a page load (and a new entry in my browser's history, meaning one more thing to click "Back" to skip over) is no less frustrating. Neither is wanting to reload a page only for the browser to throw up scary warnings about resending information simply because that page happened to result from some POST'd form submission.

Everything I've seen of HTMX makes it seem to be a nice middle-ground between full-MPA v. full-SPA: each "screen" is its own page (like an MPA), but said page is rich enough to avoid full-blown reloads (with all the history-mangling that entails) for every little action within that page (like an SPA). That it's able to gracefully downgrade back to an ordinary MPA should the backend support it and the client require it is icing on the cake.

I'm pretty averse to frontend development, especially when it involves anything beyond HTML and CSS, but HTMX makes it very tempting to shift that stance from absolute to conditional.

I remember writing high complexity rich internet applications (knowledge graph editors, tools to align sales territories for companies with 1000+ salespeople, etc.) circa 2005. It was challenging to do because I had to figure out how to update the whole UI when data came in from asynchronous requests, I had to write frameworks a bit like MobX or redux to handle the situation.

Even before that I was making Java applets to do things you couldn't do with HTML, like draw a finite element model and send it to a FORTRAN back end to see what it does under stress, or replace Apple's Quicktime VR plugin, or simulate the Ising model with the Monte Carlo methods.)

What happened around 2015 is that people gave up writing HTML forms and felt that they had to use React to make very simple things like newsletter signups so now you see many SPAs that don't need to be SPAs.

Today we have things like Figma that approach the complex UI you'd expect from a high-end desktop app, but in many ways our horizons have shrunk thanks to "phoneishness" and the idea that everything should be done with a very "simple" (in terms of what the user sees) mobile app that is actually very hard to develop -- who cares about how fast your build cycle is if the app store can hang up your releases as long they like?

> The SPA broke it... Back button broken and a buggy custom implementation is there instead? Check.

MPAs break back buttons all the damn time, I'd say more often than SPAs do.

Remember the bad old days when websites would have giant text "DO NOT USE YOUR BROWSER BACK BUTTON"? That is because the server had lots of session state on it, and hitting the browser back button would make the browser and server be out of sync.

Or the old online purchase flows where going back to change the order details would completely break the world and you'd have to re-enter all your shipping info. SPAs solve that problem very well.

Let's think about it a different way.

If you are making a phone app, would you EVER design it so that the app downloads UI screens on demand as the user explores the app? That'd be insane.

> "DO NOT USE YOUR BROWSER BACK BUTTON"?

Yeah, state mutation triggered by GET requests is going to make for a bad time, SPA or MPA. Fortunately enough of the web application world picked up enough of the concepts behind REST (which is at the heart of all web interaction, not just APIs) by the mid/late 00s that this already-rare problem became vanishingly rare well before SPAs became cancerous.

> going back to change the order details would completely break the world and you'd have to re-enter all your shipping info. SPAs solve that problem very well.

The problem is entirely orthogonal to SPA vs MPA.

> If you are making a phone app, would you EVER design it so that the app downloads UI screens on demand as the user explores the app?

It's not only EVER done, it's regularly done. Perhaps you should interrogate some of the reasons why.

But more to the point, if it's bad, SPAs seem to frequently manage to bring the worst of both worlds, a giant payload of application shell and THEN also screen-specific application/UI/data payload, all for reasons like developer's unfortunately common inability to understand that both JSON and HTML are perfectly serviceable data exchange formats (let alone that the latter sometimes has advantages).

> It's not only EVER done, it's regularly done. Perhaps you should interrogate some of the reasons why.

Content in the app is reloaded, sure, but the actual layout and business logic? Code that generally changes almost never, regenerated on every page load?

I know of technologies that are basically web wrappers that allow for doing that to bypass app store review processes, but I'd be pissed if an alarm clock app decided to reload its layout from a server every time I loaded it up!

The SPA model of "here is an HTML skeleton, fill in the content spaces with stuff fetched from an API" makes a ton more sense.

The application model, that has been in use for even longer, of "here is an application, fetch whatever data you need from whatever sources you need" is, well, a fair bit simpler.

Everyone is stuck with this web mindset for dealing with applications and I get the feeling that a lot of developers now days have never written an actual phone or desktop application.

> But more to the point, if it's bad, SPAs seem to frequently manage to bring the worst of both worlds, a giant payload of application shell and THEN also screen-specific info, all for reasons like developer's unfortunately common inability to understand that both JSON and HTML are perfectly serviceable data exchange formats (let alone that the latter sometimes has advantages).

I've seen plenty of MPAs that consist of multiple large giant mini-apps duct taped together.

Shitty code is shitty code!

> here is an application (your browser), fetch whatever data you need (html) from whatever sources you need (my web server)

Parentheticals added.

It wasn't GET mutation... it was POSTs with multi-page forms that was the problem. It was such a pain to subdivide a form and create server and session state and intuit the return state. And what happens if you needed a modal with dynamic data? Did you pop open a new window and create a javascript call for the result? There was no great progressive answer to them.

Oh, and then request scope wasn't good enough because you needed to do a post-redirect-get? I will say that I do not think MPAs for web applications were the good old days.

Yeah. As someone that’s quite bearish on JS altogether, and as someone that’s worked on a few old-school multi-step forms recently, we can’t pretend that this was and still is anything other than a code and UX disaster. And…I’m not an idiot, I understand different HTTP request types and how browsers handle going back through history. I know that there’s not something obvious I’m missing. I’ve put the work in. The reality is that non-JS web technologies aren’t very good at some things that are quite common and that many people expect in anything more than a brochure site.

I’m just so miffed that it can end up necessitating roping in so much BS. Mind you, not necessarily in this example. Things like HTMX excite me. And, on the other side, things like Next.js and Remix that IMO are a breath of fresh air, even if they might not ultimately be heading in the right direction (I genuinely have no idea).

It is totally possible to make MPAs where reloads are never a problem.

As for phone apps these are undeniably a step backwards from desktop apps, web apps and every other kind of app. On the web you can deploy 100 times a day, waiting for the app store to approve changes to your app is like building a nuclear reactor in comparison.

All the time you get harassed in a physical store or a web site to "download our mobile app" and you know there ought to be a steaming pile of poop emoji because the mobile app almost always sucks.

One of the great answers to the app store problem is to move functionality away from the front end into the back, for instance people were looking to do this with chat bots and super apps back in 2017 and now that chatbots are the rage again people will see them as a way to get mobile apps back on internet time.

Sure. You maintain the entire application state in session scope or some sort of internal state. It was possible, but it was hell.
Or the other way around, you keep as much as you can on the client but use nonces in critical requests to prevent (accidental) replays.
> Remember the bad old days when websites would have giant text "DO NOT USE YOUR BROWSER BACK BUTTON"?

It was even worse when the page didn't warn you, but would lose state all the same!

> If you are making a phone app, would you EVER design it so that the app downloads UI screens on demand as the user explores the app? That'd be insane.

Good luck forcing users to download 50MB before they can use your web app.

The web and mobile/desktop apps are two totally different paradigms with different constraints.

Neither broken back buttons nor messy scrolling are unique to SPAs. You're just talking about bad websites.
I mean, there's nothing about an SPA that forces you to break the back button, to the contrary, it's possible to have a very good navigation experience and working bookmarks. But it takes some thinking to get it right.
I don’t think “forces” is the right way to think about it. By default a SPA breaks navigation history etc (it’s right in the name). It’s not onerous to reimplement it correctly but reimplement you must.
And it's very common for it to be re-implemented incorrectly.
No it doesn't and no you don't. Every modern SPA framework has solved that problem long ago.
Right, so you agree: you have to reimplement it. You can just use a framework to do so.

It might be news to folks to learn that every single SPA framework has solved the problem entirely because it's really not an uncommon experience to have your browser history broken by a SPA. I believe that most frameworks implement the API correctly. I also believe a good number of developers use the framework incorrectly.

Or simply unaware about the whole "back button" debacle. Which is yet another stone to throw at the SPA camp: if using technology A requires a programmer to learn about more stuff (and do more work) than technology B for achieving pretty much the same end results, then technology A is inferior to B (for achieving those particular end results, of course).
That's like saying you have to reimplement assembly arithmetic, you can just use the Calculator app to do so.

Bad websites are the results of bad developers, not the tool. You can have your history messed up by any kind of website.

No, it’s like saying you’ve been provided with a calculator but may, if you wish, create your own calculator with some parts provided. No guarantee it adds numbers together correctly.
Mail is not a good example. Why would you like to read a collection of documents through A Single Page interface? Gmail was a fantastic improvement over Hotmail and Yahoo, and it provided UX innovations we still haven't caught up with, yes, but MPAs are naturally more suited for reading and composing them. Overriding perfectly clear HTML structure with javascript should be reserved for web experiences that are not documents: that is, videogames, editors, etc (Google *Maps* is a good example). The quality of the product usually depends on how it was implemented more than the underlying technology, but as I see it is: if it's a Document, if the solution has a clear paper-like analogue, HTML is usually the best way to code it, structure it, express it. Let a web page be a web page and let the user browse through it with a web browser. If it's not, well, alright, let's import OpenGL.
Mail is good for a SPA because the main central view which shows the different items (emails) to view or take an action on is based on a resource intensive back-end request, so keeping that state present and not having to refresh it on many of the different navigation actions yields a tremendous benefit.

You could do some client side caching with local page data, but just keeping it present and requesting updates to it only is vastly superior.

Thats honestly one place SPAs shine, where there's a relatively expensive request that provides data and then a lot of actions that function on some or all of that data transiently.

I'm willing to wager that I get far more data loading Gmail than just an email or list of titles/senders.

That is, it may seem a fine optimization, but has led to a fairly bloated experience.

You're thinking just of the amount of data sent, not the amount of work that's done on the back end. Just because it's only showing you the most recent 40 messages or something doesn't mean it isn't doing a significant amount of work on the back end to determine what those messages are. Not having to scan through all your email and sort by date nearly as often is a significant win.
That is an at rest choice that should be identical in both.

I presume you are thinking of rendering? But, again, that is largely done client side in both cases.

No, I'm talking about back end processing cost. If the main page of the app has a significant server cost in the determining what data is being sent, being able to just redisplay the data you have when you browse back to the main page instead of request it again, which could incur that large processing fee, is a large gain.

As a simplisit ecanple, imagine an app which on login has to do an expensive query which takes five seconds to return because of how intensive it is on the back end. If you can just redisplay the data that's already in memory on the client, optionally updating it with a much less expensive query for what's changed recently, then you're saving about five seconds of processing time (and client wait time) by doing so.

Yiu could use localStorage to do something similar without it being a SPA, but that's essentially opting into a feature that serves a similar need.

Client side caching is a strong point of SPAs, so it makes sense that a use case that can leverage that heavily will have benefits.

What exactly is the resource-intensive request here? Loading an E-mail, or list of E-mails? I don't see why that should be any more resource-intensive than any other CRUD app.
A list of emails. That's essentialls a database query that is taking X items and sorting by the date field, most commonly, except that the average user can have thousands, or even tens or hundreds of thousands of items that are unique to them in that dataset that need to be sorted and returned.

Sure, gmail optimizes for this heavily so it's fast, but it's still one of the most intensive things you can do for an app like that, so reducing the amount of times you need to do that is a huge win for any webmail. If you've ever used a webmail client that's essentially just an IMAP client for a regular IMAP account, you'll note that if you open a large inbox or folder it's WAY slower than trying to view an individual message, most times, for what are obvious reasons of you just think of a mailbox as a database of email and the operations that need to happen on that database (which it is).

If clicking on an individual message is a new page, that's fine, but if going back to the main view is another full IMAP inbox query, that's incredibly resource intensive compared to having it cached in the client already (even if the second request is cached in the server, it's still far more wasteful than not having to request it again).

JavaScript doesn't override perfectly clear HTML structure, it generates it.
There's been a fair amount of discussion on this thread, which left me wanting to clarify my comments...

It is entirely possible to have a MPA application that makes calls to the back end to retrieve more data. Especially for things like a static page (cached) with some dynamic content on it. My problem is when people convert an entire site to a Single Page (SPA). When I click to go from the "home page" to a "subsection page", it makes sense to load the entire page. When I click to "see more results" for the list of items on a page, it seems reasonable to load them onto the page.

Side note: If I scroll down the page a few times and suddenly there's 8 items in the back queue, you're doing it wrong. That drives me bonkers.

my favorite example is dev.to. A (web-)developer-centric site, open-source nowadays. In a similar discussion years ago it was praised as well-done SPA. Everytime the topic comes back up again I spend 5 minutes clicking around, it every time I find some breakage of a page being critically broken during a transition, not being the page the URL-bar says it is, ... because having a blogging site just be pages navigated by the browser was too easy.
I fail to see how HTMX could be the "future". It could have been something useful in the 2000s, back when browsers had trouble processing the many MBs of JS of a SPA. Nowadays SPA's run just fine, the average network bandwidth of a user is full-HD video tier, and even mobile microprocessors can crunch JS decently fast. There is no use case for HTMX. Fragmented state floating around in requests is also a big big problem.

The return of the "backend frontender" is also a non happening. The bar is now much higher in terms of UX and design, and for that you really need frontend specialists. Gone are the days when the backend guys could craft a few html templates and call it a day, knowing the design won't change much, and so they would be able to go back to DB work.

> Nowadays SPA's run just fine, the average network bandwidth of a user is full-HD video tier, and even mobile microprocessors can crunch JS decently fast.

ie. "I don't live in a rural area, but that's fine, nobody who matters lives there."

Really sounds to me like you’re speaking from your own professional context and are talking to consider the huge spectrum of circumstances in which web code is written.