Hacker News new | ask | show | jobs
by arrowsmith 1213 days ago
This article is great, and it reminds me of a rant I've been wanting to make for a long time: why the hell does everyone these days insist on building every web app as an SPA?

I started my career in Rails. I'm sick of Rails these days as I've worked with it for long enough to become intimately familiar with its flaws; these days I'd pick Phoenix over Rails any day of the week. But still, I'd rather spend a million years with Rails than five minutes with most of the React SPA monstrosities I've had to work with recently.

I get it: if you want to build a super-complicated, dynamic front-end, there's only so much you can do with the classic Rails-style approach (server-side rendering of HTML templates with some vanilla Javascript, or perhaps jQuery, sprinkled on top). Once you get past a certain level of complexity I can understand the argument for having totally separate "frontend" and "backend" applications where the frontend is built with something like React and the latter renders nothing more than a JSON API.

But why, why, why has the entire industry seemingly decided that the latter, complex approach is the default, perhaps even the only, way to build a web application? The last four companies I've worked for all used the "separate FE/BE" approach for every app, and at all four companies it was a terrible, unnecessary choice that added exponential amounts of complexity and slowed development to a crawl for no discernible benefit. Time and time again I'd get frustrated because the most simple, basic features would take ridiculously long to finish, be a nightmare to test, and be full of infuriating little subtleties and footguns that made the implementation fragile as an eggshell. Even something as simple as adding a <form> would take ten times longer than I knew it would have taken me in Phoenix or Rails.

And yet when I try to explain that I don't think we need the "separate FE/BE" approach for the task at hand, people look at me like I've suggested we don't need electricity. It's all they've ever known and they can't imagine there might be a better way, or at least one that isn't so agonisingly, pointlessly complex. What's happened to the industry? Why has web development become like this?

10 comments

Companies are already used to hiring frontend and backend separately, it is much easier to find an expert in either than an expert in both. It is also one of the few opportunities where you can meaningfully split up work. How much of an upside that really brings, is secondary. It already happened.

I do not buy into the YAGNI or in-most-cases arguments. Most cases are interactive applications, not the overengineered listicle websites that would be crap, even if they were not SPAs. If you write an interactive application, SSR will soon make your life miserable. The scrolling document approach to application UI sucks, especially on mobile.

I personally think full stack is more popular than separated roles. They want to hire full stack because you don't really need an expert most of the time, and full stack smashes the two jobs together while paying less. This makes management easier on the surface because you can swing the entire team towards back end or front end work. And of the more capable full stack devs, you can get them to dive into expert topics as needed (JIT expertise).
You do not need an expert most of the time, except when you do, at which point you better have one on board. You can mix and match, but keep in mind that context switches are expensive too.
These are all true, however businesses continue to work against their own interests.
That is debatable. In the grand scheme of things, politics included, it probably does not really matter. Otherwise, companies not employing this pattern should be at a competitive advantage.
> Companies are already used to hiring frontend and backend separately, it is much easier to find an expert in either than an expert in both.

I think this gets cause and effect the wrong way around. If companies stopped unnecessarily dividing their stack in two, we wouldn't have so many FE developers who don't know how to do anything on the BE and visa versa. I've worked with frontend "experts" who barely know how to query a database. Specialisation is unavoidable, but it makes no sense to me why we need to be that specialised.

Yes, frontend developers often barely know how to query a database, whereas backend developers often create terrible user interfaces, whereas fullstack developers are not particularly good at either. It is a tradeoff.
Aren't you selling Rails a bit short on its front-end capabilities considering Rails 7's embrace of Hotwire and its reworking of the asset pipeline.
I've noticed this trend with folks who move from Rails to Phoenix. At some point they switch and then never look at Rails again even if it's been years since they stopped using it. It's not like Rails was frozen in time at 2017 when they stopped using it. There's been 5+ years of progress since then.

Hotwire is one of the best things I've encountered. DHH and gang did a great job coming up with this abstraction and using HTTP for most of its communication. I'm using it today in a fairly big app and it was a breeze implementing it.

Complexity wise I'd put Phoenix Live View at like an 8.5/10 where as Hotwire feels more like a 3/10 since it builds on everything you already know. For creating just about any app I'd choose Hotwire all the time and it's also especially interesting in that you can use something other than Rails as a back-end with it if you want. I used it with Flask in a few small apps. The only server side component is for when you want to broadcast changes to more than the person who made the request but that's optional.

Modelling your frontend as a bunch of reusable components is a big benefit of frameworks. I think it's hard to go half and half with frontend component and backend templating though.

Managing any (Literally any) client-side state is also easier with a framework. I'd rather use Preact than write vanilla JS for basic state management.

> Modelling your frontend as a bunch of reusable components is a big benefit of frameworks. I think it's hard to go half and half with frontend component and backend templating though.

I've heard this before, and just don't get it. I have, can, and do create view "components" in both Django and Jinja2. They're just templates. Templates that get included in other templates. I've never (never) got to a point where I thought "darn, I want to abstract out this foo thing as a component, but can't". When I really want front end interactivity - like charts - then I'll use a JS library or a web component. With htmx, I can even do partial page updates.

None of that requires the very significant overhead that React/Angular/whatever bring.

>I'd rather use Preact than write vanilla JS for basic state management.

I'd rather use the backend. Because it owns the state, and cache invalidation is one of the two hard things [0].

[0]: https://www.martinfowler.com/bliki/TwoHardThings.html

If you think templates are a substitute for components there is very little to discuss. Templates hide hierarchy, are not easily composable, are not easily shareable (Can you publish a set of templates on NPM?) and cannot easily have complex self-contained logic.

Another big upside of JS components which does not exist in templates is typechecking.

Templates are good if you don't have complex hierarchies and have relatively simple layouts that aren't very dynamic, but they're not the same as components.

JS frameworks have relatively low overhead compared to the total size of most sites. React is ~50kb gzipped. There are also of plenty lightweight options.

> I'd rather use the backend. Because it owns the state, and cache invalidation is one of the two hard things

The backend does not own UI state. If I need to filter or sort a collection I don't want to make a request to the backend. If I need to make a selection I don't want to wait for the backend to respond before the UI updates. And so on.

> The backend does not own UI state.

It does with Phoenix LiveView. And for stuff that shouldn't need to talk to the backend I find Alpine.JS to be a comfortable option that's very lightweight and several orders of magnitude less complex than React.

How have you found the latency to be? Are you shipping in multiple regions? Is this something you think about actively? I know there are ways to optimistically update if you want, but that sort of defeats the purpose imo. (I say this as someone extremely interested in Elixir/Phoenix)
I tried something like liveview way back in the day (10 or 15 years ago) and latency was the killer. It’s probably much better these days with 5G and more efficient refreshing (we did full page refreshes, IIRC). But this is still the reason I won’t use liveview or an equivalent. If you do run into latency issues, you’re in for a world of pain if your entire application is architected incorrectly.
I get that those are the benefits. All I'm saying is that, in my opinion, the benefits you get from building a SPA are not worth the increased complexity it adds, at least for most of the projects I've encountered in the real world.
I can believe that. For a lot of projects the complexity probably causes more issues than it solves.
As someone that's new in the industry: nobody taught any other way. All during college it was Node/React/Mongo, or Node/Angular/Mongo. If I didn't spent some time on HN and learning about the rest of the tech I wouldn't know any better too.

I'll add to that that it's a bit intimidating to jump into Rails/Django/Spring/whatever today, they seem to have been getting more complex with time, and now when learning material is scattered between different versions. Also, having no occasion to do any of them professionally, it's a bit hard to know which one to pick, and take the time to learn them when I'm paid to know TypeScript and its last features.

How do you implement editable list of items where requirements are that:

- editing/creating new has to be in a popup - people don't want full page reload because they lose context (and have "feel" it beeing slow even if it is not) - edit-table is not a solution because amount of settings will fit popup - some things like item name in a list has to be updated in the list after saving in popip which requires two way data binding, because cannot do page reload - pagination and filtering is required and for same reason as above cannot be full page reload

I don't see how you implement that in a way that is maintainable with "sprinkling jQuery" on it. I would like to build it with full page reloads which would be fast and would take away complexity but every business analyst or product owner I saw was saying that "users feel" it is slow and they lose context even if list has stable sort and filtering was kept between reloads.

As someone that's basically been forced to build SPAs their whole career, these kinds of comments are always the one I hunt down with hunger in these threads, because the "complaint posts" about SPAs always sound really nice: wait, there's "actual" frameworks (SSR platforms) that take care of all the things I hate implementing for me? Awesome! But then I come to the threads and there's comments like, "cool, but how do you implement {this thing that is one of the ten variations of things I implement in SPAs for my career}," and the answers are always varied but often boil down to "oh, yeah, actually, you should build an SPA for that."

Probably the majority of the internet doesn't need to be implemented as an SPA but I guess I just keep getting gigs for apps that do need an SPA implementation? Maybe I'm self selected for it by working so much in this "niche" of the industry? I have recently been tasked with building out an ecommerce thing and it's finally a time where I'm like wait why would I build this as an SPA, and I've heard that most of the internet is basically just ecommerce sites lol.

Anyway, I would love to see some of the common things I implement in SPAs, and how I'd implement them instead in Django or whatever, cause I'd love to stop having to reimplement cookie and auth management and whatever else these things supposedly give away for free

1. Highly dynamic tables of data with filtering, sorting, pagination, etc

2. Inline editing of a Resource (Widget of some kind) without needing to refresh the entire page

3. Inline progressive forms with lots of logic (one time I had to implement an SQL query generator game)

Or whatever else I'm not thinking of right now

I am mostly annoyed with people jumping out with absolutes which are fake.

Yes you don't need to make everything SPA - but yes SPA has its legitimate use cases. There will be always bunch of people overusing stuff or using it in wrong contexts but yeah complaint posts are usually written with narration of "all or nothing".

> complaint posts are usually written with narration of "all or nothing".

Mine wasn't, I specifically said that some UIs are complex enough to justify an SPA.

I do this in Preact and it is a breeze.

But I also did it in an old Rails app with a bit of jQuery and partials. The modal loaded its markup from an endpoint. Saving was an http post that returned html which I injected into the DOM using some basic sorting / filtering logic. It was… ok, but there was duplicated logic on the front and back ends. I think if I had to abandon SPAs again, I’d probably have the “save” endpoint return the full page and just replace the html each time so that all logic lived in one place. To hell with efficiency— it’d probably be just fine and quite simple.

With Angular it is not even a breeze it is something you have out of the box no questions asked. Save endpoint returns data only for single item on the list and it is updated in place in the list with two-way-binding on return of request.
This would be trivial in Hotwire with Rails
You can build certain sections of your UI in React (or whatever) without needing to rewrite your entire app as an SPA.
Phoenix liveview.
Side note, but just wondering what you think Rails's flaws are? What did you got sick of?
Great question! I'm actually writing a lengthy blog post on this topic, but it's not published yet. Until then, I think Piotr Solnica has written some really good takes:

https://solnic.codes/2016/05/22/my-time-with-rails-is-up/

https://solnic.codes/2016/05/30/abstractions-and-the-role-of...

https://solnic.codes/2015/06/06/cutting-corners-or-why-rails...

(See also this old HN discussion about the first link: https://news.ycombinator.com/item?id=11749203)

And please pardon the self-promotion, but if you're a Rails guy and I can convince you to give Phoenix a try, I hope I can also convince you to try my course on the topic: https://phoenixonrails.com/

There's a lot of programming propaganda that floats around and gets amplified that talk up the advantages of some approach. Often the advantages being discussed aren't even the outcome of the technology, they're just the goals of the technology. Said propaganda will also completely fail to include the disadvantages of the approach. The result is a whole bunch of people who will flock to the new tech, and only 2 or 3 years later will the real story start to come out. The tech usually does have legitimate uses, it's just those uses were niche rather than "everyone should do it this way".

A big recent non-web example of this is NoSQL databases. Endless hype about their advantages. Virtually no discussion about their disadvatages. (In relative terms. It was actually there in absolute terms, I know because I picked up on it. But it was buried for a couple of years in the hype.) Endless hordes of developers switching to them, and confirmation-biasing their way past the first few red flags. Do they have a niche? Yes. Were they massively, massively overused? Absolutely. I've seen projects killed by the choice to use them, and many others switch away from them in a tearing hurry because their systems were coming down around their ears. Would a lot more discussion of their disadvantages been helpful? Who knows. In the midst of a hype cycle sober engineering discussions become a form of betrayal or personal attack for a whole bunch of engineers who too-quickly incorporate the new tech into their personal engineering identity.

SPAs are the same way, and more generally, heavily REST-based backends. Is there a time and a place for them? Absolutely! Are they always the best default organization? Heck no. Do they come with a lot of costs that need to be accounted for with the benefits? Yes.

Stepping up to a stratospheric level of abstraction, outright philosophical astronautics here, I think one of the biggest mistake programmers make is to sit down at some technology decision in which one must weight the costs or the benefits, and implicitly without thinking about it, assign a flat ZERO to some tech's costs or benefits. Most often costs, though the latter can happen. Especially in their earlier years, though even older programmers can get caught up in a hype cycle if they're not careful. Costs are never zero. Benefits are effectively never zero because nobody talks about techs with no benefits at all.

I believe this is best explained with the saying “if all you have is a hammer, everything looks like a nail”. Say you came into tech after jQuery and the like. You know your SPA frameworks/libraries. Maybe you are somewhat lazy at sniffing around for new trends/tech.

You are presented with a new challenge. What will you chose? The stuff you know you can do it with or something else entirely?

I'm working on a web framework in Ruby that works kinda like React/Preact but it's 100% server side, so you can write components declaratively as in React, but you don't need to have separate apps for your frontend and backend. I think it's can be a good approach for many types of apps.
follow the money to understand the decision making; it’s almost always locally rational for some situation that is non-local to you and typically is a higher dimensional problem than you assume.

a good place to start is to ask how the boss became the boss, given that the boss quality inevitably degrades to Dilbert