← Back to context

Comment by wg0

6 days ago

Can someone remind me how we ended up in the SPA era and why exactly? Was it about not seeing the loading spinner? Or there were more reasons to it?

No one has mentioned it: mobile! Mobile apps became a thing, and there was a strong argument to have one common backend for your web app and your iOS app and your Android app. Plus the mobile UX (especially with iOS apps at the time) was such a gamechanger that there was a natural shift to replicate it in the browser.

That said, even though I still build SPAs at work, but I can't wait for the day that I get to build something big with Django & htmx.

  • This. An SPA has some chance of being repackaged as an app without major surgery, a Django app really doesn’t. So you have to maintain it separately.

    PWAs/Webviews/etc are not really practical options.

I'm not in web anymore but, to me, it seemed easier to visualize richly linked data in Angular than having a Django template render it. Once you have the mindset of making your website into an app, you are tempted to move navigation to the app too. That way your app can keep delivering its core user function without the interruption of a page load.

In retrospect it was slightly hubristic, as in reality you sometimes have to force reload SPA's, and if you're integrating on top of legacy systems that you just link to, you're not really avoiding the bad UX of a jarring page load. But I do find it elegant to separate presentation from data.

Because the web was made to render documents, but users want apps. CSS in part is so confusing because its original incarnations pulled heavily from traditional print media layout terms.

Everything since then was an attempt to leverage JS to turn documents into applications. Why? Ask any user.

Aside from the usual separation of tech stacks for different teams, the big thing for me is lack of any sort of type hinting or safety in templates at least in the big frameworks such as Django, Rails etc. I would much rather work with a separate build process that utilizes typescript than deal with the errors that come out of incorrectly reading formless data and making typos within templates.

  • Is that really such a big problem? These days you can type annotate what you pass to the rendering function for templates and then you know what type you have in the template. If you have a minimum of testing, heck even manual testing will do, I don't think too many mistakes make it to staging, let alone production. I would think it well worth to be able to opt out of the JS ecosystem.

>Or there were more reasons to it?

Internet was slower in both latency and throughput is one reason. The other is general tendency to separate things into smaller pieces. Faster feedback to user is the third.

Consider a typical form with 10 fields in django. You define the schema on a backend, some validation here and there, a db lookup and form-level rules (if this field is entered, make the other field optional).

This works very welly in django, but you only get the result once you fill all the fields and press enter, at which point the whole thing gets sent through model-tempalte-controller thing and the resulting page is returned over a faulty slow connection. It also hits the database which is not great because SSD is not invented yet and you can't keep the whole thing in RAM or overprovision everything 100x. Containers, docker and devops are not invented yet as well.

So you try to add some javascript into the template and now you have two sets of validators written in two different languages (transpilers are not invented yet) and the frontend part is the ugly one because declarative frameworks like react dont exist, so you add ad-hoc stuff into the template. Eventually everyone gets annoyed by this and invents nice things, so you move the part that was template rendering+form completely to the FE and let two different teams maintain it and communicate through the corporate bureaucracy that tracks the source of truth for validation rules outside of the code.

At some point you notice that people name fields in the json schema in a way that is not consistent and forget the names, so you put even bigger boundary between them with a formal API contract and independent party to approve it (I kid you not, there are places where the API between FE and BE teams is reviewed by a fancy titled person that doesn't deal with either team outside of this occasion).

Eventually you figure out that running the frontend logic on the backend is easier (it's doing the same model-view-whatever patter anyway) than other way around and remove the fence making all the bureaucratic overhead disappear in one clap.

Then somebody finds an RCE in server components.

You are here.

Add: if you want to feel the WEB before SPA, here is a nice example: https://formulieren.amsterdam.nl/TriplEforms/DirectRegelen/f... (bonus points for opening two different forms from site:formulieren.amsterdam.nl in different tabs and clicking through them in parallel)

  • You still end up separating frontend and backend in full js codebases, but it's not as explicit and can lead to wacky/confusing/unpredictable behavior if you get it wrong. I've never found a perfect solution to the frontend/backend boundary but I've found a mix of declarative container type libraries (pydantic on backend, TypeBox on frontend) with some code generation is a good solution.

    • I work in a place where it's proper to wait for a month, get the openapi spec thrown over the fence from the backend team and generate my typescript RPC out of it. The upside is I don't get paged at 4 in the morning if the thing gets into a bad mood and starts doing increased 5xx at increased rate.

  • > Then somebody funds an RCE in server components.

    I'd say they found it, but I love the conspiracy theory :D :D :D

Because JS is bad, and JS have a MASSIVE user base, so whatever they do is the web.

And because JS is on the frontend, solutions are front end, even the ones that eventually run on the (js) back-end.

Is like how people use a RDBMS but never do foreign keys, views, etc and re-invent all, poorly.

  • I had similar thoughts, but how does one use an RDBMS without making use of FKs? Do they put all in one huuuge table, that has all the columns and is super sparse? Or some other fever dream of bad design?

    • And is even worse, this is stuff that I have seen in ERPs (I integrate with several).

      One of them, not even use "date"/"decimal" types and all is mostly strings, there is not views or anything else, and the tables AND fields are called "F0001..".

    • You can have a field with some value that just happens to match the id in a different table. That something could be a foreign key or just a number.

    • As long as you don't give a shit about data integrity, you don't need foreign keys.

In my experience it's boiled down to the type of data you're working with. Building nested, tree-like structures and then submitting that structure to the back-end as one request is more easily done via the front-end than a bunch of back-and-forth requests followed up by a "commit" request.

edit: I suppose this is different concern than a true SPA, but as another sibling comment points out, its just a matter of time before routing makes its way into the front-end as well.

- Strict team separation (frontend versus backend)

- Moving all state-managament out of the backend and onto the frontend, in a supposedly easier to manage system

- Page refreshes are indeed jarring to users and more prone to leading to sudden context losses

- Desktop applications did not behave like web apps: they are "SPA"s in their own sense, without jarring refreshes or code that gets "yanked" out of execution. Since the OS has been increasingly abstracted under the browser, and the average computer user has moved more and more towards web apps[1], it stands to reason that the behavior of web apps should become more like that of desktop apps (i.e. "SPA"s)[2]

(Not saying I agree with these, merely pointing them out)

[1] These things are not entirely independent. It can be argued that the same powers that be (big corps) that pushed SPAs onto users are also pushing the "browser as OS" concept.

[2] I know you can get desktop-like behavior from non-SPAs, but it is definitely not as easy to do it or at least to _learn it_ now.

My actual opinion: I think it's a little bit of everything, with a big part of it coming from the fact that the web was the easiest way to build something that you could share with people effortlessly. Sharing desktop apps wasn't particularly easy (different targets, java was never truly run everywhere, etc.), but to share a webapp app you just put it online very quickly and have someone else point their browser to a URL -- often all they'll do is click a link! And in general it is definitely easier to build an SPA (from the frontender's perspective) than something else.

This creates a chain:

If I can create and share easily

-> I am motivated to do things easily

-> I learn the specific technology that is easiest

-> the market is flooded with people who know this technology better than everything else

-> the market must now hire from this pool to get the cheapest workers (or those who cost less to acquire due to quicker hiring processes)

-> new devs know that they need to learn this technology to get hired

-> the cycle continues

So, TL;DR: Much lower barrier to entry + quick feedback loops

P.S (and on topic): I am an extremely satisfied django developer, and very very very rarely touch frontend. Django is A-M-A-Z-I-N-G.

  • These days with 90% of SPAs being broken piles of browser standard breaking stuff, I find a page refresh or page load to be a soothing experience. They are like checkpoints in the process of using a website. Points to which I can go back using my browser's back button, and I can trust, that my browser keeps track of them.

    In contrast, when I see an SPA, I need to worry about the whole site going to shit, because I blocked some third-party unwanted script, and then I need to fear not being able to go back properly, and having to re-do everything. Now that is a jarring experience.

    • I feel you. It's definitely a tradeoff. SPAs do tend to be buggier but I can't deny that, when done right, they also tend to be better.

      Unfortunately, there's _more_ people, building _more_ stuff, so there's _more_ terrible stuff out there. The amount of new apps (and new developers, especially ones with quite limited skills) is immense compared to something like ten years ago. This means that there's just more room for things to be poorly-built.

    • Not being able to new tab to a new instance of the app is terrible. Even super complex SPAs like Facebook let me for the most part right click new tab to create a new instance while preserving the old one.

For me, yes, it is. I make an app for myself, and I thought about making it a server-rendered app like you suggested. But it's just so much better in my opinion to do everything on the client side because it means that every interaction has zero latency, regardless of the quality of my internet (which is often bad).

I’d say that we are slaves to Conway’s Law.

Adding people to dev teams looks like an obvious way to scale productivity.

Then of course you need to organise them as the numbers grow and the frontend/backend split is the first, naive, place to start.

I sometimes think that the direction web development took is like some kind of bad dream that we will wake up from. It's unbelievable to me. The problems we faced before SPAs were things like "great we've got two forms on the same page and this widget on the top right needs to update when a message comes in from the back end… How will we ever solve this", and before anybody could come up with any good patterns google came on the scene with Angular, and ruined the entire direction of the Internet, forever.

TBH I also think that Alpine and HTMX are just as dastardly and disgusting, maybe even worse. I don't know why nobody can figure out a good way to just put in reactive components where you need them. All of the frameworks support that, Svelte seems to be the one that is the least against that, but I still don't see anybody using it that way. Front end developers, which tend to have the least business logic experience, somehow captured the entire SDLC. This is why literally all software is just completely riddled with insufferable bugs, beyond anything anyone in the 90s could have imagined.

Google Maps. Gmail. OWA. There were suddenly pages that let you do things without a white flash between clicks.

It's ALL about the refreshes. Everything else came after.