Hacker News new | comments | ask | show | jobs | submit login
A single-page app is almost always worse than a multi-page app (gregnavis.com)
289 points by 1gor 79 days ago | hide | past | web | favorite | 145 comments

So, the OP argues that SPAs introduce unnecessary frontend state:

"I think this is a very underappreciated aspect of SPAs. Stateful software is always more difficult to work with than stateless. The frontend state is added on top of the already-existing backed state. This requires more development time, increases the risk of bugs, and makes troubleshooting more difficult."

But the thing is, almost as soon as you have any kind of significant user input to handle (multipart forms, date pickers, autocomplete elements, conditional input elements) you are instantly dealing with complex frontend state. And then your choice is not "SPA vs plain HTML forms," it becomes "SPA vs (ad hoc jQuery tangle + ad hoc server side endpoints that know to speak to random jQuery UI libraries)."

I find the ad hoc jQuery+endpoint tangle much harder to reason about than something built with a front end framework and a more uniform API.

But the thing is, almost as soon as you have any kind of significant user input to handle (multipart forms, date pickers, autocomplete elements, conditional input elements) you are instantly dealing with complex frontend state. And then your choice is not "SPA vs plain HTML forms," it becomes "SPA vs (ad hoc jQuery tangle + ad hoc server side endpoints that know to speak to random jQuery UI libraries)."

In my experience, this is false.

In the last two years I've built five very complex forms for the healthcare industry that not only had crazy looking flow-charts, but had to be multi-lingual, predictive, mobile-friendly, and fully accessible.

They use all those little bits that you talk about - multi-part forms, date pickers, autocomplete, and conditional input.

The only JS is for the autocomplete. The rest is all HTML5/CSS3.

We did user testing on three of them (100 people from our target group, selected randomly at two of our facilities, with generally low levels of technology literacy), and the paginated HTML5/CSS3 versions all scored higher than the previous Javascript SPA mess the preceded them.

I can believe that in your user testing people would score a non-spa higher, but that isn't relevant to the question of whether an spa had more complex state management hidden from the user than a mpa.

What I imagine happened in your tests is, you didn't compare two different implementations of the same UI, you implemented the form via two different UI's and the users preferred the experience of new one to the old one.

I believe that you compared different UI's because otherwise you wouldn't need user testing: you could just measure the latency and code complexity.

The person you are responding to is saying, for a fixed user interface design, the necessary state management will be the same and your only choice is how to implement it. You say you believe this to be false but it doesn't seem like you are responding to the point.

Isn't it unuseful to be pedantic to the point of completely missing the point of the post you're replying to?

That person had something to contribute that was worthwhile. Sorry it wasn't a double-blind placebo controlled clinical trial, but it was still useful info and very much related to the topic replied to.

You must've missed the "vs plain HTML forms" part.

As a top level comment, it is valuable to point out that many executions of SPAs are lack lustre and will not deliver a superior user experience. If it was a top level comment and didn't lead with contradiction of the prior comment, I would have affirmed and probably not have posted anything. That is why I started by telling the commenter that I believed he actually produced better implementations, because he has a point but not a point that is meaningful to back up his disagreement.

The point of the comment chain in question is that a given UI has a need for a given amount of state. That is the point that was "[believed] false" and the point I was reiterating. User feedback is not useful at all for determining whether SPA's will require more state than multiple "plain HTML form"s. Moreover, the key assertion of the article is that this is necessarily the case, a point which is asserted without evidence and used as the foundation of the entire article. If you remove that assertion, the whole article collapses.

The comparison doesn't make sense though. There's absolutely no reason you can't build an interface using single-page that functions to the end-user identically to any multi-page form. You can't necessarily do the reverse (multi-page to emulate single page), but that is also irrelevant to the top level -- if the SPA has 10 times the complexity to build an identical UI, then it's probably going to be harder to maintain for no value to the end user (which isn't to say no value).

What I got is that they built different UIs and found one of those UIs was better than the others; that says nothing about single-page vs multi-page. Maybe it was easier for them to build the "winning" UI as a multi-page app, but I didn't see that being said.

If you didn't use JS for date pickers, you didn't have very inclusive browser support - especially for something like a healthcare website. [1]

Were the designs and layout of these SPA and HTML5/CSS3 website also identical?

[1] https://caniuse.com/#search=input%20date

It's more than a little absurd that there isn't a passable date picker implemented across the major browsers. I have wasted far, far too much of my life fighting with different half-baked JS datepicker components already in my life.

Still better than supporting IE6.

If it's public facing, that's a huge concern.

If it's intended for business users, particularly if on an intranet site, it's often very easy to limit the number of browsers and versions you need to support to just a handful.

The Web has been collecting dates from users in forms long before date-pickers existed.

The Web has been doing lots of things poorly for a long time as well. I know I've seen some implementations of date-pickers I don't like, and more old school implementations without date pickers that were just clumsy.

86% isn't bad, particularly considering you can easily polyfill a date-picker in the missing browsers and attach it to input[type=date] elements.

>In the last two years I've built five very complex forms for the healthcare industry that not only had crazy looking flow-charts...

Can you maybe elaborate a little bit more? I've had to do some pages for configuring industrial machinery, some having over 100 parameters, many of which would affect what other parameters could then be used or selected. Used Vue.js which worked pretty good, but I'm curious of other ways...

Some of our forms have 150+ fields with a rule engine that hides/shows various sections of the forms or hides items from particular drop downs, even auto populating fields with custom data via 60+ rules. All using jQuery, and it's impossible to work on.

I was wondering if I might be able to ask you some questions about those healthcare forms? (I wanted to send a private message but couldn't find any contact information.)

I'm working on a product that can fill out very complex PDF forms, as well as automatically generating web-based forms for people to fill in, so I would be very interested in hearing some more details.

Were you able to stop page refresh after form submit without JS? That's something I've been looking for, for a long time.

yeah that's also what I'm curious about, unless he adds a confirm page for some actions (which is actually more work) than just confirm('Text');

That's like saying that if you have to kill a fly, why opt for swatter when you can use a bazooka?

After spending some years building an SPA webapp, I'm really missing the simplicity of stateless HTML. The front-end framework my colleagues picked really likes to carry state around, like between pages, which has caused numerous hard-to-find bugs. These bugs are triggered when you do certain sequence of actions across multiple pages. That stuff should be impossible. We really ought clear all state between pages, but apparently it's harder to fight the framework to do this. Carrying state around is just fundamental for it.

I'm currently on hiatus from that project to work on a small one that's needed quick. So far, I haven't used a single line of javascript, and it's a multi-page form. I can add, remove, and edit rows from an HTML table without javascript or server side state. Instead of an autocomplete input, I used an input and search button and had the server return a page with search results to select from. State is maintained through inputs, hidden or not. Different submit buttons perform different actions, but they all send all fields to be re-rendered in the next page.

I gotta say, it's just refreshing to do things this way after so much time. It's super-responsive not having to load and run bunches of javascript. It's also cool to see the forward and back buttons work for free, without any special consideration on my part. I can use them to replay every action I've taken in the form, all additions, edits, and removals of rows in the aforementioned HTML table, and the different form pages.

Were I asked to do things "prettier" (to somebody else's standard of what's pretty), I would just use minimal javascript. There is no reason to go all-in with a front-end framework just for a dynamic datepicker.

> I can add, remove, and edit rows from an HTML table without javascript or server side state

I may be being dense, but can you provide me with a hint as to how? I guess the answer is "css", but it's not obvious to me how you would do this.

Not css but html5. It allows you to have multiple submit buttons, each linked to a different action through the formaction attribute. So I have an "add item" button that submits all fields (of the whole document) to a "/foo/form/add_item" route and simply adds a row of empty inputs. All other fields are filled with the same values they were submitted with. I also have a submit button per row where each has an action with a route that includes the index of the item to be deleted. Likewise, all fields are submitted, the indicated row is omitted, and all other fields are rendered with the values they were submitted with.

I got the backend prepared to facilitate this. I just call a function with another function that manipulates a datatype representing the form. It parses the submitted data into that, passes it through my function argument, renders it, and responds with it.

In the example I gave, the HTML table holds the inputs for the row data, but initially I thought the items would need more fields than would be pleasant to work with in the table. What I was doing then was displaying a subset of the data in the table, hold the raw data of all items in hidden fields, and have a subform below the table for new items and item edition. This was somewhat more complicated, specially because of the way the backend framework I was using thought of forms. I had one HTML form that I wanted to treat like multiple, validating one or the other depending on what submit button was used. Getting that to work in Yesod was a little troublesome but I imagine it would have been easier (though less safe) in e.g. Rails.

Anyway, I think continuing that way would probably have also been doable, had I not switched to having the inputs in the HTML table for simplicity.

Legitimate question: if you have multiple pages, are you still actually creating an SPA ? That may be the problem that you're encountering, and I can sympathize. Nobody wants to transfer state across page loads, it's a mess...

The reason we chose to make an SPA for the big project is that we wanted the back-end to work for multiple different types of front-ends, some potentially adding automations from the client side via the API. Who knows, were it not for that, we may have chosen a simpler HTML+jQuery design.

You know, TimJYoung, I think I may have misunderstood what you were asking. It's still one page that loads the initial HTML layout, javascript files, and HTML templates. What I meant by "page" in my original post were front-end "pages" that just modify the content of the main container tag in the actual page. I don't need to transfer state because it's already there. Clicking a link causes the framework to destroy the content in a tag, run some javascript functions that probably make some requests to the back-end and fill the tag with the "page" of the new front-end route. The problem is that because of front-end framework supposedly-helpful automagic, unexpected things happen due to keeping state from previous front-end routes.

Ahhh, yes, in that case it seems like you might possibly be better off (and happier ! :-) ) with just using a page-oriented architecture. It seems like the client-side state is just getting in your way, as opposed to being helpful in any way.

The way that I look at it is this: if you're going to do an SPA, then do it like you're writing a desktop client application: all content is manipulated on the client, the only requests to the back-end are for data (JSON/XML), and the client typically will maintain quite a bit of state. Complex applications that are ports of desktop applications and sit behind authentication dialogs are ideal candidates for SPAs. Here's an example case study of such an application from our company web site:


The one exception to this would possibly be something like an online manual/help browser application, in which you might be able to make an exception and have the content driven by an SPA, thus allowing for more control over advanced content navigation via a tree view or vertical menu.

In general, though, if you find yourself needing to do a lot of history/page management, then that is a good indication that you might be trying to shoehorn a traditional, page-oriented architecture into an SPA.

You do still have state, but with a MPA you have a cleaner break between each page and thus far less ability for state to persist and cause problems (though there are plenty of technologies to shoot yourself in the foot if you so desire). I wonder if the most optimal solution is to have a MPA but using some SPA technology. This reduces the overall state of every page, but still gives you decent technology to work with the state of the page that you just cannot do away with.


That feels like a straw man, you can obviously also use modern js and a decent framework (vue react whatever) to make the portions of the page that need state, transitions and complex interactions very user friendly and easy to reason about without pulling the entire site or section of site up into an SPA. I have seen far too many implementations pull whole sites or large sections of sites up to SPA to mitigate one complex form or stateful interaction area. There is obviously a range of implementations that can be done from SPA|--------------------------|Page-Level and none of the areas on that spectrum require you to do anything in a"jquery tangle" let alone with any jquery include at all.

The author recommends that as an option as well

> Third, if you’re implementing a very complicated component then you can use React just for that component. For instance, if you’re building a chat box then there’s really no need to implement your login page in React. The same applies to Vue.js and the rest of the pack.

I'm not sure stateful vs stateless is even the right way to frame it.

With no JavaScript at all, your application is still stateful. Even if an individual HTTP request is stateless, your app as a whole still has state. The state just lives in the database in that case, and each request you make either gives you a view of part or all of its current state or provides data to transition the application from one valid state to another valid state.

Actually, thinking of an application as a series of transitions between valid states is why I enjoy using things like Redux. Used properly, it acts as a gatekeeper that makes it hard to move the application from a valid state to an invalid one. It adds a fair amount of boilerplate, though, which I know some people find frustrating.

Maintaining state on the front end and keeping it in sync with the back end is a pain. But I don't think it has to be. it's just an artifact of us being stuck in a certain paradigm of application development that we don't seem to be able to get out of.

It wouldn't be impossible to design a system that runs over a network, but doesn't require the front-line application developer to think about the network. It sounds like something Alan Kay might have worked on at some point. :)

I envision a Smalltalk-ish environment where, in my application running in a browser, I send a message to an object telling it to save itself. And when it receives this message, it transmits itself across the network, validates its data, and persists itself into a database. Maybe an object database like Gemstone/S. But the application developer wouldn't have to worry about all the details most of the time. Just tell the object to save itself, and it'll report back whether it was able to or not, so you can update the application accordingly.

I'm sure I'm overlooking a ton of potential pitfalls, of course. I think we can do a lot better than we're doing right now, but I'm not 100% certain what better looks like, or quite how to get there. Maybe I just need to watch a few Bret Victor talks for inspiration and then get to work trying to build something. :)

> I envision a Smalltalk-ish environment where, in my application running in a browser, I send a message to an object telling it to save itself.

It sounds to me like "what if Javascript had SOAP", heh.

We can envision lots of things. The beauty of software engineering/architecture is you can envision almost anything.

The trick is that the more complex the thing is, the harder it is to pull of _well_, and the easier it is to end up with a monster.

The complicated things take more expertise/skill/experience to design, and _also_ take more development time to produce -- and on an ongoing basis to maintain. And it's not always clear where development resources come from on 'shared commons' like platforms (unless they are proprietary and only available for a fee). The current front-end JS environment is already _pretty darn complex_ of course. How well it's pulling it off, well, is a matter of debate central to the OP.

On, and then there's getting different actors to coordinate in thing that require that (like browser's supporting something).

I can envision it too. But I wouldn't wager much on it happening in a way that actually results in an improved development environment (instead of a monster).

Using SOAP from JS is doable if you really want to. :)

But if we're comparing to crufty tech, I'd say what I was talking about in that sentence was more like DCOM or CORBA. Both of which were nice in concept but a bit of a PITA in practice.

Thanks, you're right, that's what I meant. I have thankfully forgotten most of what I ever knew about these technologies.

Check out Lively4 [1] and see what you think. It's the fourth incarnation of dan ingalls' LivelyWeb concept.

[1] https://lively-kernel.org/lively4/lively4-core/start.html [2] https://github.com/LivelyKernel/lively4-core

https://pouchdb.com/ works more or less like that. You just save objects, and then it'll report back when it's synced with the server.

This is true, the author seems to imply that it's somehow possible to always avoid complex UI state. Might be true for some UIs, but definitely not for all (e.g. a calendar UI would suck big time when rendered exclusively on the server-side).

is that true? googles auto-suggestions are rendered server side, as you type in the field they update. (unless I am mistake, but I thought that was the case)

That's not really "rendered" server side; the data is fetched from the server by JavaScript in JSON form, then dynamically inserted into the DOM.

I think it's a combination of local cache immediately, followed up by a server response

Honestly no it wouldn't suck and from a end user perspective for a calendar. It is actually far superior. Granted this is only my personal opinion. There seems to be this desire to overcomplicate the front end when simple solutions work quite well. Granted they don't have all the catchy buzzwords. But they make for a better less bug filled solution.

Calendar UIs commonly demand stuff like auto-refreshing, datetime selects, drag-dropping items around, resizing those, list goes on. Please elaborate how you'd build a "simple solution" that does not resort to client-side rendering.

Yeah, even a "Select All" button that checks all checkboxes requires Javascript.

Aside: I don't understand the premise of this thread that suggests it's a "SPA" just to, say, use React on a single page of an application. The whole basis of the "SP" in "SPA" is that the Javascript (state) spans multiple pages.

I once worked with a guy who built an app with everything done server side in web forms, including a datetime picker. It stands out in my memory as one of the worst pieces of software I've ever seen produced.

> I once worked with a guy who built an app with everything done server side in web forms, including a datetime picker

ASP.NET Webforms? I have good memories of being able to do that easily, with zero (or almost zero) JavaScript.

It's not the best user experience ever (the whole page has to reload after each click, and the state is persisted by serializing structs in <input type="hidden"> fields), but I had a pleasant experience when I developed with it.

ASP.NET Webforms components were the best thing until we finally had React/Vue!

The only problem was that it was way too easy to make a mess in your backend code.

Did he ever have trouble finding employers or paying clients?

My problem with the idea that SPAs, as an idea, are inherently more difficult to develop is that this doesn't translate to desktop/mobile applications, which are, conceptually, very similar in architecture (fat UI client, app server on the back-end). What may be more true is that the way in which we develop SPAs is so flawed that it causes serious issues with quality/development effort. IOW, perhaps the issue is with JS and its limitations with large, complex client applications, not the SPA architecture.

Disclaimer: my company sells a web development product that creates SPAs that work like desktop applications.

I agree, but using a front-end framework does not mean you must build your entire app as an SPA. You can still have separate pages, and UI components on each page get handled by your framework of choice. Also, there's a big difference between the state of a single form vs. keeping the state of your whole application in the frontend!

...and this is really what it comes down to. State management should come down to what the front end has to manage in order to be well-organized and structured. By creating a multi-page app, all you are doing is forcing yourself to organize your state by page. This is something that can be done simply enough by using modules in your state manager of choice. With a SPA, you have the option, with MPA, the decision of overall organization has already been made.

With SPA you usually dont add frontend state on top of backend state, you only have the frontend part, and a stateless API.

This makes it very easy to test and reason about.

> stateless API

Does it not access any data?

It is generally accepted that when someone uses the phase "stateless API" they mean session state not data persistence.

Yes, and this does nothing to help with the problem of state coherence between the backend and frontend.

Most JSON/data APIs for SPAs are similar to SQL database servers: maintaining a persistent connection is useful for performance reasons, but there's nothing about the API that dictates that it's required. The only state that is required across API calls is an authenticated session, and that is maintained on the server side.

and even authentication can be done stateless. Makes load balancing easy since each request can go to a different server

There are some interesting implementations out there taking advantage of persistent connections to allow the server to handle the rendering while having targeted fragment updates come from the server.

Here's a thread I posted about some FOSS I've been working on that relies entirely on the server for rendering and using VDOM diff/patching on the server for updates. I'm definitely biased, but in my opinion this approach is vastly more user friendly because it enables realtime data updates as easily as request/response style updates.

here's the thread https://news.ycombinator.com/item?id=18318415

if you need some click bait, here's a gif of me in seattle over cell phone internet interacting with a SSR realtime app with the server in cali. https://imgur.com/z8pKt8t - all operations going round trip, with no application level JS written

having worked with JSF, I can safely say that me and server side rendering with peristent client connection to push updates are ... not friends.

You have multiple scopes in the same document. You have the jsp scopes which gets rendered once, when the client requests the page, and the jsf scope which lives longer. Initially when rendering these scopes seem to share variables, but after the request is rendered, the jsp scope gets removed

I promise you that your complains are with the abstractions chosen and implementation and not the concept. Texas doesn't have any of the issues you're talking about. You don't even worry about the data that populates the view. You simply write view code like any other templating engine that knows how to render itself and when data changes you send a small message to a process that handles updating the client and texas handles all the logic for efficiently updating its client.

Is this kinda how next.js works? I have not used it myself but I think it looks neat.

I believe nextjs is just taking react and rendering the initial page load on the server. So this library (texas) and nextjs don't really have much in common.

Thanks! Texas looks awesome.

From the blog post

> Third, if you’re implementing a very complicated component then you can use React just for that component.

LOL. So avoid complexity by writing in VanillaJS, but feel free to load an enormous frontend library for a single component. Makes sense.

Eh, let's avoid eye-rolling hysterics on this forum and stay practical.

There are components that are complex enough to warrant a view library, embedded in an application that's not. In fact, it doesn't take much complexity at all, in my experience. At which point loading a view library a la carte is your only real option.

What doesn't make sense about that?

There are applications that warrant a view library. There's not a single case where importing two view frameworks with one handling the "complex components" makes any sense. React can also do very simple components. Pick one and run with it. If your application is complex enough to warrant a complex UI library, use a complex UI library.

The complexity involved in using two different libraries that handle the rendering in very different ways (one doesn't even do the rendering, so now you have two rendering solutions in addition to two view libraries. Yay!) in the name of simplifying your code is an absolute joke.

I'd assume it is to have a enormous front end library to handle all your complicated components and the author would be horrified by the prospect of every component written with a different front end library. It does present an issue if you literally have a single component that needs it, but I think this advice was aimed at cases where there are many such complicated components.

You are making a false comparison. Why would an SPA not be a "ad hoc jQuery tangle + ad hoc server side endpoints that know to speak to random jQuery UI libraries" ? I think it's quite possible to design an SPA like that.

HTML has support for everything you listed without resorting to JavaScript. Maybe some sort of graphic editor for a special file type isn’t possible without JavaScript? But most things really have been thought of and incorporated into html.

HTML doesn't have support for autocomplete elements and conditional input elements. Even date pickers are spotty.

Datepickers, specifically datetime pickers, in pure html are vomit inducing.

Or just have multiple pages with the complicated ones rendered with something like React. Nothing stops you from having more than one app bundle and with proper packaging it’s not even particularly slower to download or parse.

You don't have to use jQuery... https://news.ycombinator.com/item?id=18336429

That's why I love to use Vue to handle complex frontend states without building a full SPA

Sorry, but this is just silly and looks at the problem from the wrong end.

Of course single-page apps generally require far more development than multi-page. Of course they require more state, more testing, are slower to load, etc.

But they also do a million things multipage "apps" can't and, and therefore have the potential to provide a vastly better user experience at the end of the day.

In the end it's same tradeoff as literally every other business decision: will the resulting benefits be greater than the costs they incur?

My dentist doesn't need a single-page app for their site. Anything complex enough to intuitively be called an "app"... there's a good chance it does.

It should be completely uncontroversial that "if it costs much more, it better provide a benefit that's worth the extra cost". I agree completely with the statement, "it's same tradeoff as literally every other business decision: will the resulting benefits be greater than the costs they incur?"

I will add that I think "vastly better user experience" is very situation-dependent. Many applications put on the web (be they client-side rendered, server-side rendered, or a mix) are really boring simple things: fill in a simple form and get some basic information. A lot of users and businesses really don't value that much what an SPA can do. They don't think they are "vastly better" - sorry. In many cases an SPA doesn't necessarily give you the benefits worth the cost, especially since there are many costs. In other cases an SPA is obviously the right way to do a job, and it'd be a poor decision to try to do otherwise.

I wish people would focus on understanding "there are X ways to do this, and here are the pros and cons of each approach". Trade-offs, trade-offs, trade-offs. If we focused more on understanding the alternatives and their trade-offs, the field would be a saner place.

It is not at all obvious to me that a single page application requires more state than a multiple page application.

Consider a choose your own adventure book.

Both a single page application and a multiple page application can implement this entirely through the url and I don't see how I have any state other than the url.

If that is too facile, there were choose your own adventure books where you had hit points and could fight monsters. So now I store hit points in the session or in the url or in the single page application's state.

Single page application doesn't mean single url. I don't exactly understand what additional state would be required to implement any particular user experience via a single page application or multiple page application. The only difference I see in either case is where the state gets managed and mutated.

You still have to test a non-SPA app and you still have to manage state--it's just on the other end of the wire.

TBH, given the state of modern tooling I'm not sure that SPAs really do require more development (once you have actually bought into the process of using them, which is nontrivial). I do, however, think they generally scale (developer-scale, not performance-scale) better than any multi-page system I've ever worked on.

I like your division of "site" and "app", and it's the same one I use. The boundaries are definitely fuzzy, but if you're working on it--I think you know.

> I do, however, think they generally scale (developer-scale, not performance-scale) better than any multi-page system I've ever worked on.

I've never understood this opinion. To me it seems like you're forcing such complexity that you _need_ focused developers. That by definition scales far worse than having all cross functional team of developers that can work on the view layer and the data layer (by virtue of the view layer being easy enough all developers can understand it).

It's touted quite frequently ime that it's better to have front-end engineers and back-end engineers and that to me just feels flat on its face wrong.

I'm not claiming there are no benefits to SPAs, of course. I'm just saying I don't understand the opinion that claims it scales better with development cycles.

Hear hear! I don't think the assertion that SPA's are faster to build / more scalable holds up to much scrutiny.

1. SPA's still require some back end to render the initial page / payload.

2. SPA's cannot be trusted, so you need to duplicate things like validations.

2a. "But you can just do an ajax call to validate records on the back end, and get a json response!" — how's that any more performant than just doing a traditional page load? With pjax or turbolinks, the performance difference between these options is even closer.

I remember a decade ago, when there was a management demand to get rid of the "page load", and our quick and (very) dirty solution was to simply load the next page with ajax as HTML and simply replace most of the body with the body of the loaded page. It was hardly any faster (we measured), but everyone insisted it was suddenly blazing fast. The psychological effect of avoiding the visual artefacts of a page load was large enough that it was mostly sufficient.

We eventually did some minor optimisations - returning smaller parts of the page, and replacing more precise sub-parts of the DOM. We had some other small pieces of JS on the pages too, but for the most part just having the server render everything replacing large chunks was good enough.

I'm both of these developers, and I don't think either part is complex or all that difficult. I have no problem bouncing from backend to frontend in the course of implementing a feature and I don't find my mental stack getting smashed in the process. If your developers aren't cross-functional in exactly the way you describe, I think you probably hired insufficiently skilled developers. ;)

To me, it's more that every HTML templating solution I've ever seen kinda sucks for composition beyond a very basic "insert blob here", whereas TSX--don't write plain JavaScript, kids--does a lot to address that. It's more that commingled views/controllers and the actual logic of the application causes separation-of-concerns issues (and yes, you can write better code, but people don't). And it's more that for any nontrivially successful thing I'm probably going to either need to provide an API or a mobile client--which are the same thing--and so I might as well get it out of the way to start.

In a way, it's the microservices argument. You don't make microservices because of performance, you make them because it forces less skilled developers to do (more of) the right thing and allows those less skilled developers to parallelize better. So it is with tooling like React in an SPA and an API-driven backend. But, and unlike microservice-all-the-things, I find myself able to crank out more involved features, faster, using React and talking to a backend API in something like Swagger than dealing with postbacks and string-manipulating my way to HTML output. So I think there are wins on both ends.

I don't think there's a production application out there not using an entire toolchain for their client side code. I'm not saying it's _too_ hard for people to be cross functional. I'm saying it's hard enough that companies often times make an artificial separation.

I don't agree with the microservice comparison because the separation of view/data layers could more easily exist with a back-end rendered application. It only exists more readily with front-end rendering because the complexity is so much higher that you find specialists in that field who can only work with that stack. The separation is purely artificial and driven by increased complexity.

While there are some valid concerns in the article, it mostly is just a rant against SPAs, which seem to be unfamiliar and subjectively disliked by the author.

As with stacks, this is highly team-dependent. I for one do not crave for the time of constant back and forth between backend-frontend mindsets and stack lock-in because of rigid query/rendering requirements. This may not work for the author's team of mostly "backend-mindend" devs who wish for more control over output, but is much preferred for a more diverse set of members (or especially departments).

Totally agree with you. There is a huge benefit having a clean API which works for a variety of clients (native / mobile / desktop) and a corresponding variety of team members instead of maintaining 2 different view sets on your backend, without even talking of the specific issues you can find yourself in in web development (browser specific features / inputs / styles / ...). And you still can't do any real native apps.

Over the past year we replaced an Angular front-end with the author's recommendations: Turbolinks and Stimulus.js. With the pair, our app mostly feels like an SPA, but has the developer benefit of leaning on server-side rendering.

The experience was wonderful and highly recommended. I think it's perfect for small teams who are more productive with traditional/backend tech.

> The experience was wonderful and highly recommended. I think it's perfect for small teams who are more productive with traditional/backend tech.

You presented the actual valid argument for the OP's position. If you are a small team of largely backend engineers, using tech you aren't familiar with is probably the wrong solution. Unfortunately, the blog post decided to take a more aggressive stance and made the author just look like a fool.

Unfortunately, there are too many weird corner cases with Turbolinks. And it doesn't work with certain ad scripts (which ad publishers aren't interested to support Turbolinks).

How does Stimulus compare to Angular? It seemed like a random plug in the article for a framework that appeared at first glance to basically be Angular.

I want to hug Greg for this article and especially this paragraph at the end: "Third, if you’re implementing a very complicated component then you can use React just for that component. For instance, if you’re building a chat box then there’s really no need to implement your login page in React."

You can totally do that, but I write React for the entirety of an app because it means not having two separate development flows for different features.

Making my login page driven by HTML and postbacks, rather than a straightforward REST(-ish) API talked to by an SPA, makes it nontrivially more difficult to establish the kind of separation of concerns necessary to then build a mobile application out of it (and as it happens, React is pretty useful there with React Native).

Completely Disagree. SPA's are about making your 'site' like a GUI application. If you had to use Apache to navigate pages in visual .net or QT that'd be crazy.

SPA's also benefit from static caching and serving. You do not always need to have the pages being served from your origin, but can be served from a much cheaper source like Cloudflare or even a different origin.

Could not disagree more with the article. In my experience, well designed SPAs are almost always better and lighter than multi page apps. The fact that a lot of SPAs are implemented quite poorly is a different story. In actual fact, whether a web app is single or multi page is merely an implementation detail; in both cases we're just passing information back and forth between client and server. With multi page apps, you transmit and parse full markup each time. With SPAs, you do it once and then mutate as needed. In that sense it's more efficient and I can't see why that's a bad thing.

Forcing a SPA just for the sake of SPA is overkill. But putting a group of related actions into a single page makes sense. Absolutely feel free to make a separate page for each separate group of UX actions/tasks. But let us not go back to the days of full page reloads on every mouse click.

I think that the over-applicaton of the SPA architecture is one of those things that in the future will seem obvious, and we will wonder, "what were they thinking"? But when it is what everyone does, it is hard to question. It probably still has a few years before this becomes clear to management at the typical web shop, however.

I get where the author is coming from but if your frontend team is already proficient at making SPAs then going SPA from the start actually simplifies things and buys you room to maneuver. The backend team can focus _just_ on the server side and the frontend team can just request the needed APIs. Additionally you can now reuse the API you just built with other systems. If your Widget Management Interface™ is a MPA and you your Automated Widget Building Factory™ to know when to produce more widgets then you just got a new project. If it's an SPA then you just give the Factory a user and have it use the API.

>An MPA renders a 500 page upon error and that's it. However, an SPA needs to detect errors in the client code and then update the user interface accordingly. Again, busywork required to regain what MPAs offer out of the box.

Is that supposed to be a downside? Just showing a 500 page isn't really a great UX, the SPA experience is probably a lot better (think preserving of unsaved data for example).

Then you go back to the point made in the beginning of the article:

Is the better UX during 5xx worth the extra investment?

Does it directly drive more revenue than what it costs in developer time?

I would argue that in most situations the business is better off using 10 hours of engineer time working on some source of 5xx, than 10 hours making sure the error has good UX.

Problem with SPA made here is simply that there isn't an easy "good enough" solution like you have for MPA, it is either good ux or nothing. (I don't know if that is true or if it is just that SPA devs will always insist in good ux even if it doesn't improve company's bottom line)

User Experience is not just about bottom line, and approaching it from that position is just terrible. People that have to interact with terrible UX don't like those interactions. A 500 error with a bolded text saying "an error occurred" is going to make me never return to your site, because a reasonable user experience for that page doesn't require 10 hours of work.

Users never returning has an effect on bottom line. So you can make the argument from that position.

Whether users return, and how that hurts your business, depends very much on your site and your users.

I will disagree about UX not being about bottom line though (in the usual context of a for-profit company of course). In a common setting, whoever pays developers and designers are doing so as an investment that they think will be profitable. If you can cut costs without hurting (long term) revenue by cheaping out on UX then of course you should (!). But often the idea is good UX will drive revenue...

I am not arguing against SPAs, but to prevent redownloading common page elements (menu bars, footers) you can use web components. I recently built a website using web components for this purpose (official implementation of the university's official theme) and it was a good experience. Proper CDN caching means you only have to download them once.

You can have the best of both. The simplicity of multipage apps with the feel of SPAs. Turbolinks is one example that comes to mind.

Or if you want the full power of React, Redux, AND the simplicity of Turbolinks/PJAX. You can use https://jho406.gitbook.io/breezy/ which is Turbolinks for React Redux Rails, you can build SPA without APIs, just by treating JSON as a navigational format.

Full disclosure, I'm the author and I've been trying to get some feedback on the project.

This seems really misinformed and written by somebody who has no idea how SPAs work. The SPAs approach results in much cleaner and simpler architecture in practice because you have clear separation between the client and the server. It also forces you to think about the API up front allowing you to create other clients, such as native mobile apps, later on.

The SPA approach also helps with statefulness, because it allows you to keep the UI state on the client where it belongs. The UI becomes much easier to reason about because you're not trying to keep state of the server and client in sync. Meanwhile, the server can just be a set of service calls the UI queries when it needs data, and doesn't need to store any state about it. This directly helps with horizontal scaling where you can spin up more servers and balance across them.

While SPAs can have a larger initial Js download, they can be a lot more responsive overall because you don't have page repaints, and you fetch data as you need it.

Testing actually becomes easier because your front-end is decoupled from the backend. You can test it in isolation, and the amount of statefulness is dependent on the complexity of the UI as opposed to whether its implemented SPA style or not. An equally complex UI implemented using traditional server-side rendering will likely be harder to test in practice.

Also not sure why authentication needs to be any different with SPAs. You can authenticate exactly the same way as if you did server-side rendering.

>Let's illustrate this with an example: we're building an e-commerce site that has a list of categories. We need to update the list from time to time. In an MPA, the list is updated on every page load. That's not the case in an SPA though.

Why wouldn't it be?

>In an MPA, we can simply pass models to views and render attributes we need. This isn't the case in an SPA. We need to define data formats and implement serialization.

Not really sure what that's about either. JSON exists, and I'm pretty sure nobody is inventing serialization formats in SPAs.

>Single-page apps are much more expensive to build than multi-page apps. In most cases, there is no business reason to choose this architecture.

Perhaps this is just a problem with the particular stack the author is using, and they're extrapolating this to be a general problem?

>>In an MPA, we can simply pass models to views and render attributes we need. This isn't the case in an SPA. We need to define data formats and implement serialization.

>Not really sure what that's about either. JSON exists, and I'm pretty sure nobody is inventing serialization formats in SPAs.

I think the author means serialization of models into JSON for your API, which is non-trivial in frameworks like Django - you have to pick which model fields to use, how to represent foreign keys, etc. In Django you can just pass that model object into a HTML template processor (view) in a MPA.

That's a problem with Django though, and not an inherent problem in SPAs.

At my current workplace - as a deliberate design choice - and last one - organically "discovered", but deliberately maintained - we've tended towards building user facing products as collections of smaller apps sharing a backend, rather than typical SPA (Single Page Application) architecture

What that means in practice is that:

1. Routing is always handled server side. The less frontend state (IMO/IME) the better. There will be the odd bit of pushState where appropriate, but no actual full-on routes.

2. Whether to render content server or client side is determined on a case by case basis. It's often easier to build HTML using whatever templating system your backend tooling provides than build a REST/GraphQL endpoint for a component to consume.

3. You can introduce React/React-style programming piecemeal to a team with varying levels of experience. Everyone on a team (with varying degrees of frontend skill/experience) can be productive from day one.

Does anyone else do this?

Another potential benefit is reduced toolkit lock-in. Migrating a bunch of smaller pages one at a time is pretty doable. Migrating a large SPA without disrupting business could be like trying to pass a camel through the eye of a needle.

This is where skill and experience come in.

Should huge wizards and complex forms be constantly sent back to the server and rendered as each bit is filled in? Of course not.

But if you have a basic CRUD app with a big dashboard, create route, edit route, view route, etc., it's a hell of a lot cleaner to break up each one of these main features into mini SPAs that cleanly refresh the state on the server when moving from one function to another.

Otherwise, you're constantly making duplicate calls to ensure you've got the data you want as you really can't be sure if some previous click from one of dozens of in-memory widgets has stale or incomplete data.

At least that's been my experience working on a few legacy apps written in AngularJS and, God forbid, JQuery. At that time, an Asp.Net or GWT app would have probably been easier to maintain as the duct tape increased over the years.

Maybe React and Vue allow for cleaner architectures, but older apps were a pain.

I don't really agree with the author that SPA's are almost always worse. Although sometimes they're gratuitous, as was the case with a lot of early Angular apps where it was pretty clear that the developers thought they were being cool by making way too many things behave "dynamicky" for the sake of having their work appear more like an app than a site.

On the other hand, there are plenty of times where a multi-page app is just fine. If that's the tool that works best for you, then by all means use it. The vast majority of users don't even perceive things like page reloading, etc. Build something useful, whatever the means are.

>The vast majority of users don't even perceive things like page reloading, etc. Build something useful, whatever the means are.

This is the correct response, but among developers you will have zealotry on this topic. I personally find MPAs easier, but that is based on my work experience and my perception of the learning curved involved in things like React and Angular (I found VueJS to be far easier to learn). I do like the idea of thinking about an API from the get-go with an SPA, but do all applications need an API? Nope. The amount of applications in the business world that will require both a web implementation and an iphone/android app is actually quite small, isn't it?

How would something like this work as a non-single-page-app:


Would the user have to chose "32 GB Ram", hit a submit button and wait for the page to reload with the matching laptops?

I can't decide whether you're joking or not. That's how the web has worked since its inception until just a few years ago when SPAs appeared on the scene. I don't think SPAs are always a bad idea, but they sometimes are. For instance, I've gone back to HTML Gmail and I love how fast it is compared to the JavaScript mess the main product has become.

Not joking. It was a rhetorical question.

What I mean: This is an example where a single-page approach is better.

I agree that there are many single-page sites that would be better if they were multipage. But I'm not sure the "almost always" is justified.

The title of the article is even stronger "The Architecture No One Needs". But you and I clearly can bring up examples where it's an architecture that does make sense.

Why is this product chart SPA better than a simple MPA? The zoom animations do not add any value to the user experience.

Also, with this SPA, you can't bookmark or a share a URL to a particular hardware search, so information and usability is lost. The URLs could be fixed, but the SPA has to explicitly manage the page history. An MFA gets that for free.

As a developer I appreciate it more, perhaps users might find it slicker. However, I go back to something another user posted "The vast majority of users don't even perceive things like page reloading, etc. Build something useful, whatever the means are." And that is the correct answer here. As the other poster stated, there are tons of applications that don't need to be an SPA. Think of damn near every admin section of a companies intranet or whatever. That thing just needs do the job, run fast enough, be easy to scale and develop on and hopefully not look like an eye sore.

That's basically how every other product comparison site works. And, honestly, this is one of the worst ones I've seen.

In a traditional MPA yes. The user would have to choose and hit submit and wait.

Regardless, I think this is a superior experience. It does require some getting use to because of the screen/price chart, but just because it's different than anything everybody has done in the past, doesn't mean it's worse. I think someone getting used to this reactive approach might find it a bit hard to go back to a more traditional click/wait cycle.

I was going to point out the mention of Turbolinks and other JS stuff (author isn't a fundamentalist if you read more than the headline), which would help, but in this case, to be honest, my opinion is "hopefully it wouldn't happen." It hurts my eyes.

If it stopped the developer doing some ridiculous animation and providing me with a list of products like every ecommerce website on the net, then, sure. Also, why do you need the submit button? Just let me click on a link which filters by 32 GB and be done with it.

SPA done properly is much simpler than classical, well known and established ways of making web applications. The only issue is in misleading "best practices".

What I don't get is why these conversations try to pretend that "best practice" is a single point, making huge implicit assumptions about the skill level and practices of the host organizations... Things which almost always have larger force multipliers than the wider space of "what options for this (theoretically) exist in wider industry".

If I have a team of apes slapping keyboards that know Perl and don't understand finer points of OS/servers/state-management very much and see JS as form of evil, then yeah... I'm going to have an MPA where everything complicated happens in a CGI Perl backend that gets wiped clean between every request and probably hand-roll a little bit of turbolinks for them so they don't have to in the spots that will benefit from that.

If I have a team consisting of a single perfect crystalline entity that exists out of time and can pluck the correct solution out of the set of all possible solutions and just start banging out source files in alphabetical order, but BA is staffed by two-headed barbarian ettins that change their mind mid-sentence and can't produce static documentation then we're going to have to account for that least common denominator when it comes to our project management style -- super-iterative... maybe kanban, crystal boy banging out a set of feature branches and staging environments for them with big demos meetings of "so.. kinda like this?"

SPAs: reinventing the browser in the browser, and you get the bonus of doing it all in JavaScript!

I hate SPAs, so much more complexity and work. In MPAs you can still use JS and AJAX for a better experience, but SPAs just have so much needless extra work and are harder to maintain. They are also frustrating to use. They can be better to use when done well, but you don't often see that unless it's from someone quite big.

Alternate title: the front-end sucks now because we have too many options for doing generally the same thing, and they all aren't compatible with each other, but my way, the way I first learned, is best, and something about functional programming even though UIs arbitrarily necessitate or do not necessitate state.

I, personally, place blame on WC3 for this state of affairs, as Web components should have solved the UI interoperability problem, observed objects were dropped which regardless of what one thinks of them (I think a trie is better) would have unified state management clearly (replaced by Proxy? yeah, I see everyone using that string-only thing for state), and various other specs should have solved most of these issues, but I guess they were too busy making people leave their org over DRM, rather than making a useful, consistent, easily-produced internet. Who needs standards when all of the for-profit board members have their own un-interoperable libraries?

I didn't really learn web development seriously until the age of SPAs, so I find SPAs much easier to reason about than multi-page. That said, I'm not really sure that a UI which is mostly fields and forms really warrants a front-end framework unless its an extremely complex, stateful flow.

bull crap.

The complexity of state management must exist within an app. Either it's stateful server side or stateful client side.

Going away from the SPA pattern doesn't save anything in this regard.

The only unique complexity SPA brings to the table is route management, which can get confusing, and a non-trivial learning curve.

I’m curious if anyone has done any analysis and seen any patterns emerge around days of the week >> certain popular HN topics (controversial/rants/per category)? Kind of similar to the analysis you find around best times to post etc. I feel like I see type system related posts closer to Fri/Sat.

I think we could make a nice color coded calendar or almanac to celebrate these more. Maybe even create more formal holidays. I’m inspired by the Giant Man radio interview[0] I heard on NPR this last weekend. Highly recommend it, by Hillary Frank.


> Error HandlingAn MPA renders a 500 page upon error and that's it. However, an SPA needs to detect errors in the client code and then update the user interface accordingly. Again, busywork required to regain what MPAs offer out of the box.

I'm no gilded dev, but 5 years back when PHP wasn't avoided like the black plague we would still need to update user interface handling these internal server errors. It's judt good design practice.

I more or less agreed/understood with the writer up to that point. Everything else past this just sounded like a argument for argument's sake.

The user experience is always the number one problem of any application. Implying that you don't like building great products because you are lazy says more about you than the state of the front-end world.

I will add that since the learning curve is substantially higher for SPAs, non-technically proficient front-end people (designers or folks who just do HTML/CSS) will constantly bastardize your app; creating 1000 line components, splicing in jQuery, inadvertently creating elements with duplicate IDs. It's been a headache for me at times, and I often feel like I'm the maid cleaning up after people.

It's understood that this can also happen in an MPA, but I think the blast radius is much smaller.

Oh. He's talking about websites.

I've just started implementing a website which would look like an ideal fit for a non-SPA (online library), but since I am using my own spare time on it, there's no way I will go back to the old non-SPA development.

Most of the problems are solved by using Haskell+Elm+Generating the API types (sharing the code for their encoding/decoding). Testing the backend is way easier through API, and testing UI is better done with hands/eyes.

The routing and type safety from url to database that Yesod (Haskell) offers makes it simple to make MPA than an SPA. You can still add an API to test the backend.


Yesod is great, and would cover most of my app, but then you get things like "search field which filters as you type" and other UI elements (even as small as "like" button) and you get into a territory where you stop having a good time.

JWT is encoding standard for tokens. Bearer tokens can be JWT tokens (and usually are). Has anyone idea what author had in mind with bearer tokens?

From the context, any bearer token that's tied to a session with backend state, in contrast to having no backend state, securing state through the JWT validation, with the listed downside of having no way of revoking it.

> There are cases where an SPA makes sense but this is a topic for another article.

Without that second part, this is just a trite rant against SPAs.

As much I tend to be sympathetic to the no-SPA cause, it's easy to run into requirements that exclude MPA's. Incrementally updating a page just has too many potential performance and usability advantages. (Not to mention that an SPA can potentially be given some offline capability to accommodate a marginal network connection.)

> For instance, if you’re building a chat box then there’s really no need to implement your login page in React.

Wrestling with this idea. Been using create react app for most of my projects that arguably do not need it. But the development is so much faster and easier to manage than traditonal html/css webpack

Most of the issues listed are either issues with MPA's as well or optional for SPA's.

There are plenty of MPA's with slow first time loads for instance.

I find the author forget that those problems arise with each new paradigm and each time tools evolves to resolves those problems.

This was a rant, but I did learn about turbolinks, so its a worthwhile read for me. The salt in here is strong.

If I let the browser handle internal links so everything reloads, is my SPA now an MPA?

Turbolinks have to be my favorite part of Rails, I've used them with other applications as well, the idea that you just load partials (without a huge framework such as React) is pretty nice.

I'm a long time server-side developer who've been working on the front-end for the past 6 months.

I don't agree with this article. I think its author has a significant misunderstanding of SPAs and overstates some of the potential issues. Having built both type of applications at varied level of complexity I absolutely don't agree with the notion that SPAs are necessarily more expensive than MPAs. I'll address a few of his points, but most, if not all, of his claims can similarly be refuted.

Statefulness: Few people would build an SPA on top of a stateful backend? Most SPAs query an API which nowadays will more than likely be hypertext driven (read stateless). The user authenticates, gets an access key, then serves that access key along with each subsequent request to the API that needs it. The server does not keep a session around. It receives the query, does its job in the confines of what is requested and serves back a response (likely in JSON). That's more or less it. There's very little state involved here.

Testing: Vague unsubstantiated claims. Why make backend and frontend talk to each other when mocking would do just fine.

Performance and network latency: Has anyone been using an SPA recently and had this as their main problem? If your client is incessantly polling your API, then it's a sign that either your API is not designed well enough to address the problem domain, or you need to employ a caching mechanism on the front. There's no cookie cutter way to architect an API. If your client is more likely to query and use 10 items from a collection, don't force it to make 10 requests, provide a facility to bundle them up into one. On the front-end most frameworks have satisfactory libraries to handle state and cache management.

Slow first time load, multiple times per day? Stop updating your live bundle multiple times in a single day.

Authentication with JWTs: JWTs are not an SPA requirement, they're just one of many approaches to authentication. I don't use them and don't see the point of them in most apps that I've built. If you do use them and need to keep track of them (maybe because you'd like to be able to invalidate them), store them in something fast like Redis on the server.

State updates: The JavaScript ecosystem has excellent caching facilities, that can automatically poll and update resources upon a timeout. It's indeed not rocket science.

Error Handling: You catch the error from the http response and call your handler. That's practically like muscle memory whenever one does an http request.

            // handle response

No busywork there and probably much more user-friendly than that default error message that will be served by nginx (if one truly wants to stick to such a "no busywork" philosophy).

The rest of the article can similarly be addressed.

My conclusion is simply that if you want to maximize your cost efficiency, build a team that is familiar with their tools. If all your developers have done and are familiar with are MPAs, then yes, it might be more costly to build an SPA for them at first. I should know. I went through that phase at the beginning of my recent JS foray. Doing anything was slow and would've taken me a fraction of the time by simply playing around with Jinja on the backend. But fast-forward a few months, after immersing myself a bit more with the ecosystem, I cannot imagine reverting to that approach to build anything more complex than a simple data driven app. Emphasis on the simple.

The justified text on this page makes it so hard to read on mobile.

tldr; I've invested a lot of time becoming very good at rails and I don't want to learn a new appraoch to solving a problem I am already very good at solving.

The quality of an end product doesn't have as much to do with tools as people would like to believe.

This is a load of garbage.

Hahaha. Its nice HN will give a voice to Neo-Luddism even if its content borders on trolling

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact