Hacker News new | ask | show | jobs
by epoch_100 2181 days ago
What I think is even more significant than Hey’s backend stack is its _frontend_ stack. There’s no complex JavaScript framework; it’s all server side rendered HTML with a few touches of lightweight JS (mostly Turbolinks and StimulusJS, afaik) on the client to add basic interactivity. And it feels just as fast—if not faster—than any other modern, well-built web app.

It goes to show that libraries like React and Vue are _not_ necessary to build smooth, modern, and fully-featured web interfaces.

Edit: removed mention of Angular because, yes, it’s a framework, not a view library.

11 comments

It depends on how much data is centralized. If creating a new email round trips to the server to render in the next email list page, it may feel instant on a fast connection. With a SPA framework, it could add it to the local list of emails and push to the server in the background, so it would transition instantly regardless of connectivity. It would also work offline. If you are doing all business logic on the server side anyway, then yeah SPAs vs a server is not much different. But there is a whole class of problem that the server rendering cannot solve. Most email clients work offline and have an outbox. With a SPA you could have the web and mobile apps have the same exact code and support offline. With their setup, you have to build a native (or at least separate) app from the web app. This decision matters a lot when you’re making an app that should work everywhere, online and offline, with the exact same code.
> With a SPA framework, it could add it to the local list of emails and push to the server in the background, so it would transition instantly regardless of connectivity.

With an SPA, it could be built to do this. But most SPAs aren't developed this way.

Take a look at the "RealWorld" example SPA showcase (it's like a TodoMVC for SPAs), which has 43k stars on GitHub: https://github.com/gothinkster/realworld

And go ahead and click on the demo site: https://demo.realworld.io/

In virtually every implementation, every time you change pages, the app re-downloads everything it needs for that route. Click on an article and then go back to the feed? Every time you will see a blank feed for about 500ms and only then do the articles stream in.

You can say "well it doesn't have to be this way" or "this is just an example". But the reality is that it usually is this way. This real world example is a good representation of how most SPAs are built, and they lack the type of functionality you're describing. They instead end up creating an experience that poorly emulates server side rendering, since now many page changes end up with a blank page or a loading indicator before the data arrives in a subsequent request.

I don't know about you, but I'd rather wait 250ms once and then have the page arrive fully rendered over a transition that takes 2ms and then 200-400ms of multiple requests finishing and the page popping into place. The latter is really annoying, yet it's the experience most SPAs give you.

My post was not about what is probable but what is possible. Hey is an app, not a website, that has been built by an entire team of developers over 2+ years, with multiple millions of dollars, not a gatsby app on Netlify made in 30 minutes. They could have made this work fully offline in React in this time, if they wanted to.
Ummm, anyone claiming offline support is trivial has clearly never written offline support. I'll give you a clue: cache invalidation (and data reconciliation) is hard.
In your post you made it sound like most SPA frameworks will take care of this for you.

> With a SPA framework, it could add it to the local list of emails and push to the server in the background, so it would transition instantly regardless of connectivity. It would also work offline.

None of this happens automatically with SPA frameworks, and it requires a custom implementation of offline functionality in the context of the business domain (what to store, what to send to the server when connection is reestablished, which data to re-synchronize). It's hard to do, which I think is why most SPAs don't do it.

Moreover, it's clear that DHH is not interested in even something like basic PWA support, and will instead spend his time attacking Apple for not approving their app on the app store.

> Moreover, it's clear that DHH is not interested in even something like basic PWA support, and will instead spend his time attacking Apple for not approving their app on the app store.

Let me paint a somewhat less strawman-y picture of DHH for the benefit of those who doesn't know him:

- He is the guy who built Rails and inspired a huge number of other frameworks from Symfony and Laravel to parts of modern JavaEE.

- "His" apps (obviously built together with others) were early examples of actually working Ajax.

- He has been preaching against the hunt for unicorns for a decade or so I think, talking about sanity and sustainability.

- I think the thing about PWA is less that he isn't interested in it and more that he wants things to just work across all browsers.

- The thing about Apple is less about attacking Apple and more about defending himself - and in the process a number of smaller devs - against abuse from Apple.

I have a lot of nice things to say about Apple, but for cases like this where you wonder if it was Apple or Oracle who called you to extort money then Apple deserves all the criticism rhey get (and then some more if you ask me). Just because one is mostly nice doesn't make it OK to run an extortion racket on the side.

(Apples platform, Apples riles one might say but as far as I have seen so far they didn't break any of the rules, so even by that rule Apple is in the wrong here until they change their rules to add something tvat allows them to do this.)

I think that's holding SPAs to a higher standard than server side rendering. To compare apples to apples, you'd have to compare to the real world SSR app - think the average corporate intranet django monolith. Sure it's easier on client side network and CPU resources but the same engineers that create SPA monstrosities are the ones that create SSR monstrosities.
I don't think it's holding SPAs to a higher standard. It's holding SPAs to a reasonable expectation for SPAs. An SPA is significantly more complicated on the client side in exchange for some purported benefits, especially to the user (such as only downloading what you need). If everything is discarded on each "page" transition and re-downloaded again upon a return, and has the page-popping-into-place effect, that eliminates one of the foremost benefits of an SPA and diminishes the UX.

I encourage anyone developing an SPA to go talk to actual end users about this. Most will report that they don't like the experience, often citing a variety of issues, but one of the biggest ones is related to the immediate page transitions followed by blank boxes or loading spinners for a perceptible amount of time. You'll hear comments like "it feels too fast" or "it feels like nothing is happening". These are not good things, and developers shouldn't be clutching their React/Angular/Vue/whatever framework just because it's what they know how to develop in, at the cost of producing products that users don't like as much as normal server side rendered applications.

> such as only downloading what you need

I think SPAs provide great benefits, but most users only visit a single page. So I would add that SPAs also tend to download more than you need (in JS) if it's something like a blog

You’re also still paying a performance penalty for interacting with the virtual DOM in react. It’s not like react is just more complex to develop on, it’s also a noticeably slower experience in some cases (looking at you, Reddit.)

I’m also not completely convinced that the one-codebase ethos actually results in that much more efficiency, particularly given that one codebase is JavaScript. I’m sure there is a gain, but I don’t know that it completely offsets the costs of being so tightly bound to the JS community, but that could just be my experience

Vdom is a common point of premature optimization. React is very fast if you are rerendering components correctly. Turbo links is still having to diff just like react/vdom.
Turbolinks merges the contents of <head>, but replaces the contents of <body> outright. No diffing on the body.

"During rendering, Turbolinks replaces the current <body> element outright and merges the contents of the <head> element. The JavaScript window and document objects, and the HTML <html> element, persist from one rendering to the next."

https://github.com/turbolinks/turbolinks#navigating-with-tur...

Not to be pedantic, but there is manual "diffing":

https://github.com/turbolinks/turbolinks#persisting-elements...

Hey! I just saw this and thought I'd follow up for posterity's sake in case anyone else came across this.

This gets into how we want to define "diffing", but I would say no, no there's not any diffing on the body, manual or otherwise. Per the linked section:

"Before each render, Turbolinks matches all permanent elements by id and transfers them from the original page to the new page, preserving their data and event listeners."

So, at no point is it attempting to determine a difference between two pages. Instead, it simply queries for appropriately tagged elements (from the source code, 'this.bodyElement.querySelectorAll("[id][data-turbolinks-permanent]') and copies those over to the next page.

Thus, it's declarative rather than algorithmic and not what I would consider "diffing" at all. In this context, the parent to my comment stated it's "still having to diff just like react/vdom", which certainly isn't the case.

Cheers!

Matouš Borák published a few interesting write-ups about the front-end: https://dev.to/borama/a-few-sneak-peeks-into-hey-com-technol...

Basically it's a new, unreleased version of Turbolinks[1] + StimulusJS[2]

The "native" apps are wrappers [3] for the webapp, but with some native integrations for navigation, etc.

[1] https://github.com/turbolinks/turbolinks

[2] https://stimulusjs.org

[3] https://github.com/turbolinks/turbolinks-ios

Turbolinks is a full front-end framework. It just makes you manage the DOM diffing yourself by annotating nodes with various data attributes so that they are replaced, persisted and cached properly as navigation occurs.

It might be smaller or faster than other frameworks, but it definitely has much of the complexity and pitfalls of its brethren.

Hrmmm... we have very different experiences with Turbolinks. Maybe older versions were more like that, but v5 is definitely not. Turbolinks doesn't look at the page at a node level, it replaces the <body> tag outright for each visit. You may want to turn Turbolinks off for a specific link, or make a DOM element that holds some sort of JS-driven state permanent across page loads, but there's really not much you _can_ do on a node level and the times you do use those things are certainly the exception, not the rule.
I would call the Hey UI and UX straight out of 2007. Opening an email requires a page reload.
It seems to work quite well for me, so from my perspective, it's fine.Opening an email and fully loading that whole page takes less than 400ms for me, with he first meaningful pain around 200ms.Even on slow 3g throttling its faster than loading gmail.
Are you sure? Turbolinks and stimulus should handle that.

https://stimulusjs.org/handbook/origin

And yet it actually works right? In many parts of the world I was not able to load GMail, because the first load is just too much. I take Hey approach any day as a user.
Yep, and those parts of the world will happily pay $99/yr for email.
Hey uses turbolinks, so opening an email is an XHR call not a full page reload.
Why is either of these a bad thing?
I’m not complaining about it. I paid the $99. I’m pushing back that it’s a modern UI and modern UX. It works, but from my perspective it’s pretty ugly and dated.

It’s opinionated nitpicking, not scientific analysis.

Totally this. Maybe a great email client doesn't need to be a SPA. I love a lot of the decisions HEY made, and think the onboarding was lovely. But I think people are over hyping the core UI/UX. Is it fast? Yes. But what data are they really loading? It is also clunky and has obvious design decisions that seem made to get around needing to use more JavaScript.

I will be very interested to see it after a year of polish however.

because it's not react/vue /s
Amusingly, the comment right about yours contradicts this: saying HEY does not feel fast, and a tuned React SPA would be faster.

I would say that there's been a pendulum swing back towards no frameworks, no bloat. But the corollary (important to note) is: this assumes competence & knowledge of performance tuning - in React, VUE, or no framework. Significantly, it means you have to a little more than the defaults.

Because if you don't do any performance tuning, it's possible that a tuned React SPA could beat it. It seems possible that a HEY app written by someone who did that with React could be even faster than what we see on HEY right now, in this particular case.

> It goes to show that libraries like React, Vue, and Angular are _not_ necessary to build smooth, modern, and fully-featured web interfaces.

The main selling point of these libraries is the clear separation of concerns - frontend code is clearly isolated from the backend code. Previously it was common for backends to return dynamically generated javascript and to use the DOM as a frontend data storage layer. These weren't pitfalls if you had a solid foundation but if you were inexperienced these conventions gave you a lot of rope to hang yourself with.

> The main selling point of these libraries is the clear separation of concerns.

I've rarely heard this as a selling point, and it doesn't seem like a very good one to me.

Even when frontend code is clearly isolated from the backend code, it's quite easy to create a mess of it all.

Except now you're also dealing with 1) multiple separate tech stacks, 2) synchronizing state in at least two places, 3) duplication of code (validation being a common one), 4) payload size and possibly lazy-loading the front-end of your codebase, 5) and so on.

There might be /something/ to this selling point in a sufficiently large project or one where multiple client apps interact with a single backend, of course, but in and of itself I don't see the benefit of such 'forced' separation of concerns.

> These weren't pitfalls if you had a solid foundation but if you were inexperienced these conventions gave you a lot of rope to hang yourself with.

And by "you", you mean "you or anyone on your team"

Are the apps then just web view with a wrapper? Or its using react-native for apps?
Sounds like it for the view side, maybe they are doing a local proxy with some offline caching with native libs, does the app work offline?
I agree that react/vue/etc. aren't necessary, however this approach is not diametrically opposed to using a JS framework.

For example, if you use a framework like Stencil or Next.js w/ React, you will be able to pre-render your page into static HTML to serve to clients, but you also get the benefit of having rich JS components and code sharing. And then you avoid a lot of the issues they seem to have around lack of DOM diffing and the like.

> It goes to show that libraries like React, Vue, and Angular are _not_ necessary to build smooth, modern, and fully-featured web interfaces.

I understand what you're saying but want to clarify: Angular is a full blown opinionated framework.

And from my experience in the enterprise which library or framework to use are decided by how productive the dev team can be. Not sure newbs would hit the ground running with the HEY stack.

It is using some custom elements, though. :D
> It goes to show that libraries like React and Vue are _not_ necessary to build smooth, modern, and fully-featured web interfaces.

Ugh, I hate this trend of hating on the front end frameworks “trend”.

You can build some things without a framework (some things you simply cannot). Sure, a basic email client can be done without much JS. I’m not convinced it’s better for having gone that route.