Hacker News new | past | comments | ask | show | jobs | submit login
The future of web software is HTML over WebSockets (alistapart.com)
517 points by jack_riminton 48 days ago | hide | past | favorite | 325 comments



I have thoughts, and I agree but also disagree a bit.

We are in the dark-ages with respect to streaming sockets, and I am the architect of one of the worlds largest WebSocket and streaming services.

First off, unseating the operational benefits provided by request response is a huge challenge. It's possible, and I've done it. One of these days, my co-authors and I will present an OSDI paper with the broad strokes. It's very easy to list a lot of the challenges with scaling WebSocket, but each of them can be solved.

I believe we will have a nicer world with QUIC --> Http/3 and the up and coming WebTransport discussion. SADLY, that will result in a decade long "caniuse" issue, so we should expect to see WebTransport polyfills to arrive...

Second, HTML over WebSockets is nice, but what is better is reactive data binding over the socket. Let the browser maintain a DOM tree that templates over a JSON object, then reactive-ly update and it's an amazing experience. You have minimal data transfer, and minimal rendering updates. There is a great deal of power in having your UI be a stateless function over a giant JSON object.

Finally, the big challenge is dealing with the server state in a meaningful way. The exceptionally nice property of using request response for everything is the shared-nothing stateless nature of the web server. It's exceptionally forgiving in both operational and developer issues.

It's very easy to fuck up the implicit state tied to the connection, and this requires discipline to get right. It's very easy to ship unreliable software that then has issues based on the connection.

Now, I'm a HUGE believer in that we need to use streams for everything, but it requires a mind shift. The key thing to tackle is dealing with the server side state, and this is where I have my shitty idea of a programming language for board games. In essence, I am building a DIY database such that people connect directly to the database and get that sweet giant JSON object along with a stream of updates.

The DIY part is related to the fact that I invented a programming language to transact on the JSON object such that you get all the benefits of durability with the mental model of working within a single machine.

http://www.adama-lang.org/


> The key thing to tackle is dealing with the server side state

The core problem of web UIs has always been managing state. People like statically-rendered pages because most state gets kept in a) the URL, and b) transient HTML elements, and both are highly visible and easy to deal with in robust ways. When you're forced to have server-side state it's exceptionally painful, but people usually just avoid it altogether which in most cases pushes things towards the virtue of having less state anyway.

For complex UIs with lots of little interactions the above story doesn't really work, so we've invented state management systems for the client. Managing complex state still sucks, but it sucks less with these tools.

Sounds like this approach is just moving that state store back to the server, with a greased pipeline so it isn't so horribly painful to add new pieces of state even though both sides are involved. But you'll still face all the same problems you face with a front-end store: transientness, cache-clearing, even modeling is hard when you're dealing with a big blob of mutable state. And there will be the additional challenge of associating this stuff with a user (which you get for free on the front-end, even with modern state stores).

> Let the browser maintain a DOM tree that templates over a JSON object, then reactive-ly update and it's an amazing experience. You have minimal data transfer, and minimal rendering updates. There is a great deal of power in having your UI be a stateless function over a giant JSON object.

> this is where I have my shitty idea of a programming language for board games

It's funny, I started building a web-based board game to play with family during quarantine, and I landed on this exact approach totally by coincidence :) I'm using polling requests instead of websockets because I'm lazy/it doesn't need to scale, but it's the exact same idea where the server just publishes a giant JSON object of state and the clients are pure functions of it (and send messages to the server to mutate it). I wonder if there's some aspect of board games that pushes one towards that line of thinking.


I'm working on the complex UIs now, and it is a challenge. Fortunately, I can focus on gaming designs which is less complicated.

I think the key thing here is figuring out how the UI can be made mostly declarative and a stateless function of the state. I'm drawing some inspiration from

https://flutter.dev/docs/development/data-and-backend/state-...

and the challenge is the polish to make products great. My strategy is that I'm going to make a UI editor so I can make faster progress on designing the board game UI and then build a minimal set of controls to do data binding. The key is to get into the fight about what is the polish needed, and what reasonable escape hatches are needed.

> I wonder if there's some aspect of board games that pushes one towards that line of thinking.

There is, they are exceptionally complicated!!! SO COMPLICATED! The key is the implicit state machine between all the players, and you just can't quickly model it with traditional tools and databases. All it takes is a single card or game piece (which changes rules) to invalidate EVERYTHING. Games are exceptionally messy!


It seems like you could get most, if not all the way, there with an "isomorphic" Redux store on client and server side, along with a custom Redux middleware (very easy to write and well-documented) that reads actions from and writes actions to whatever connection you have set up. That way, your initial "giant json object" on the client is just the current store state and your "streaming updates" are just redux action objects going over the wire. You'd probably want some extra metadata attached to the objects (e.g., a uuid field and an ack field containing the last action's uuid) and youd have to deal with all of the usual synchronization problems in your middleware, but you'd have a solid starting point, at least.


Yep. As an example, see this pair of posts from 2017 on a distributed VR app with Redux actions over the network:

http://jimpurbrick.com/2017/01/04/vr-redux/

http://jimpurbrick.com/2017/07/04/react-vr-redux-revisited/


If your game has limited number (say, < 10) participants per game board, then concurrent updates to shared state etc can be solved with a traditional game state hosting server model. But if that number is higher say 100+ then you need a sharded distributed setup. That's when things get really tricky if you don't keep things simple.


So, like all engineers, I imagine that my products that I ship will reach massive levels of scale. Such massive level of scale that I need to use elastic compute, so I should expect processes to come and go.

Thus, my processes clearly has to sustain 100k+ connections. And, at a moment's notice, I should expect the process to go "poof". Maybe someone is going to do a kernel upgrade or someone decided to unplug a machine, I don't know!

Having operated with the above assumptions, I found it hard to be wise to avoid that and then invented a programming language that would operate in a modern cloud environment.

I need better hobbies, or not... who knows.


the real world is messy, games are a way of identifying the messiness (and then provoking one user to be upset at how the developers chose to model the messy world)


> where the server just publishes a giant JSON object of state and the clients are pure functions of it (and send messages to the server to mutate it)

So, XSLT for JSON basically. I like it.


> I'm using polling requests instead of websockets because I'm lazy/it doesn't need to scale, but it's the exact same idea where the server just publishes a giant JSON object of state and the clients are pure functions of it (and send messages to the server to mutate it).

I like this approach as well, but I do worry that users today expect optimistic updates on the client, and the injection of a X00ms delay would make the app feel sluggish.


You are over complicating things. UI state should live in the client. Having the server maintain it is not only more complex but will also introduce a latency. Let's say I click a button to delete an item in the list. The button state goes to pressed, list loses focus, button takes focus, button unpressed, delete animation starts on deleted item, translation animations on the other items to slide into its place, new items devirtualized if the list is too long,... Now that's 1 user input. Imagine multiple consecutive input like mouse scroll. Or drag-and-drop.

Only state shared between multiple clients should go to the server.


"UI state should live in the client." this is wrong and I think you have missed the point of the article.

In server-rendered app, there's nothing like UI state.

There's a request. This request and the database is enough to build response. There is no UI state. Your app can be (and often is) absolutely stateless and restult depends only on request and a state of the storage.

While when you have SPA, API & server, you lose the application state and it's not possible to store the whole app state in the client for many reasons (security, scalability, synchronisation...). So you have to store subset of it. And you have to build a machinery that will do all this synchronization so your states stay in sync. It's double the effort to get 5% improvement.


> In server-rendered app, there's nothing like UI state.

Of course there is.

For example, any state related to interactivity like forms, client-side validation, widgets, filters, etc.


All these things can be set up declaratively on the render time and managed through Ajax/socket. Local state is voluntary here.


So when using a drag-and-drop widget you're going to be waiting for server responses at every step of the way?


The server isn't maintaining the UI state in my model. Instead, the server is maintaining a single document, and the entire UI view is then predictable based on that.

Think about the nature of a document store, you put data in and data out. You gain concurrency by using compare and set such that multiple requests can compete, but this is expensive. First, you risk conflicts which require re-execution for the losers. Second, you must download the entire object, make a change, then write the entire object back.

The key to what I am doing is that I'm having the language take a message from a durable queue, integrate that message into the document via some code, then emitting a state change out. The client then subscribes to the document's parts to updates its UI state, and as the document changes, so does the UI.

The UI can be much more complicated while the server can be beautifully simple.


The way to eliminate latency with server side state is called optimistic updates.


This is a next step for my project as I'm trying to figure out how to generalize client side predictions in a sane way.

Basically, I'm happy with my latency (for board games) which I hope to migrate closer to people as more edge compute offerings emerge. However, I'm wondering what the path is to find some of these ideas in more latency sensitive applications.

The explanation for how the net-code behind Overwatch is a good explanation: https://www.youtube.com/watch?v=W3aieHjyNvw

and I'm just trying to figure out how to build the reactive tree in a way to support it sanely.


You don't have to predict. Requests just fall into two categories:

1) Nothing bad can happen if we show some optimistic result before server returns, but server side will end up in different result.

2) Something bad can happen. Accordingly, for (1) we can do optimistic update, for (2) can't


Consider that while a videogame runs on 60fps (or more), a board game runs on frame-per-turn. You would be doing what overwatch is doing in a frame, for an entire turn. That's way easier: if a turn is out of sync, revert to the previous one!


The architecture you're describing is awesome.

It sounds like the one I was working with ~18 years ago.

Except it used HTTP (long polling or comet) instead of HTTP/3 for the transport. And more partial rendering to DOM-diffs on the server side because it was faster than doing it all on the client, but the client still applied diffs.

The issues with full DOM state synchronisation, handling network errors and recovery, transport of templates and data, minimisation of transport subject to maximising responsiveness, some amount of anticipatory prefetching, were much the same then as now.

A lovely thing about all this stateful streaming cleverness is you end up building a mostly stateless, functional-reactive model on top of it again, that ends up extremely robust.

It's just faster, and it can react immediately to server side data changes as well as client side. And that model can be declarative, it doesn't particularly need to be in JavaScript despite running on the client.


Yes, HTTP/1.1 is awesome but you need to use comet-stream, comet is the same thing as long-polling and it's terrible and was only required because IE broke the XHR standard until IE8!


IE did XHR before everyone else, and many years before there was a standard. It invented XHR; it was shipped in IE4. IE's behaviour defined the standard everyone else copied.

Then other browsers copied it, adding their own quirks. The XHR standard wasn't created until about the same time as IE8 was released. So it's not possible for IE before IE8 to break the XHR standard, as there wasn't an XHR standard before IE8.

Long-polling is still used as a fallback today. The modern alternative is WebSockets, but they do not work reliably in every network environment, either at the client or server side.

Last time I looked, Facebook and Gmail were using long-polling to good effect.

Despite the conceptual ugliness, long-polling when implemented properly works quite well and is extremely reliable. In practice, "quick and dirty" long-polling is not always implemented well, but it's not hard, just takes a little thinking about unreliable networks.

XHR has nothing to do with long-polling particularly, and it doesn't remove the need for long-polling either. Long-polling is usually done with XHR these days, but it can be done easily without XHR, using invisible iframes or dynamic script elements. The latter is called JSONP and you've probably heard of it. SSE can also be used.

All of these things have nothing to do with HTTP/1.1. They work perfectly well over HTTP/1.0, 1.1, HTTP/2 and HTTP/3.


> Let the browser maintain a DOM tree that templates over a JSON object, then reactive-ly update and it's an amazing experience

Totally agreed. I even pulled off an Elixir library as a POC to show this concept, here's an example project: https://github.com/surferseo/live_data/tree/master/examples/... (most relevant part of API is here: https://github.com/surferseo/live_data/blob/master/examples/... and here: https://github.com/surferseo/live_data/blob/master/examples/...)


Not the author, but since nobody did, I feel compelled to mention htmx:

https://htmx.org/


> HTML over WebSockets is nice, but what is better is reactive data binding over the socket. Let the browser maintain a DOM tree that templates over a JSON object, then reactive-ly update and it's an amazing experience. You have minimal data transfer, and minimal rendering updates. There is a great deal of power in having your UI be a stateless function over a giant JSON object.

Interesting that you're exploring this idea in the context of board games. I implemented[0] a similar idea while making a browser-based magic the gathering interface. Basically send commands to update the server state (a big JSON object), and the server does state diffs per client and sends lz compressed JSON patches. Worked quite well, but I haven't played with it for a couple years.

[0]: https://github.com/anderspitman/pojo_flow


>In essence, I am building a DIY database such that people connect directly to the database and get that sweet giant JSON object along with a stream of updates

Isn't that Firebase DB?


Yeah, that was my reaction to a lot of the discussion on this article. Firebase Realtime DB has been one of the most amazing pieces of software I've used. I don't have to worry about the connection details at all, I just have this data store that feels like a local DB except it's "magically" synced with the server, and any other users of the DB "magically" get updates when I change it.


How do you implement ACLs and other privacy-related transformations in that model?


You write Firebase Security Rules [1] that restrict access to paths within your database, it's quite awesome. Those rules can be used to implement ACLs and object ownership, and also role-based access according to claims that exist on the JWT of the authenticated user.

[1] https://firebase.google.com/docs/rules


It could be, but I own it and the roadmap.

The key thing that I can do is await on players decision, so I can block the entire process for multiple people to do things.


And Realm, and couch/pouch


> Second, HTML over WebSockets is nice, but what is better is reactive data binding over the socket. Let the browser maintain a DOM tree that templates over a JSON object, then reactive-ly update and it's an amazing experience. You have minimal data transfer, and minimal rendering updates. There is a great deal of power in having your UI be a stateless function over a giant JSON object.

I think a lot of the "best-practices" for SPA is trying to do this. But as streaming the data transfer is not yet common, the data is abstracted as a giant JSON object to be a parameter of the UI as a stateless function (React+Redux/MobX/etc, Vue+VueX). When enforced correctly on the project level, what's complicated _is_ syncing the data to the server. I think you'll like Supabase's subscription approach to reactively bind the JSON for the client.

I think a separation between the info-web (document-content heavy) and the app-web (needing stateful data sync) will be more clearly defined in the next few years. Nobody likes trying to sync data between the client and server over HTTP calls; we just have to wait for streaming to be the norm for the app-web (and native apps, ofcourse).


I am doing something somewhat similar - I have a Postgres database and I send all the user tables to the client on connection and then stream all the updates. I use Vue and Vuex-ORM to make the client tables reactive, and put a view on that. When something changes in the database, the client UI will also update.

It is indeed a very powerful and reliable way of ensuring synced state.


I do the same for a collaborative music app. User gets the state of a session on load as a JSON object then just received the diffs. It's pretty efficient.


Sounds like you’re describing a system similar to Meteor.


This sounds like what Microsoft were trying to do 15 years ago with webforms: the browser was treated like a dumb terminal with the UI rendered on the server and pushed to the client.

The UX back then was horrible, however technology has come a long way since.


I have a personal project based on this approach (JSON over Websockets): https://quixical.com/

It appears to work well. Security was tough work though (at least I thought it was). And scaling up, no matter what tech you have access to, can be costly.

Also, determining how to handle disconnections is quite an interesting UI problem. Auto reconnect might be an option, but then you need to think about a retry policy. And it can be harder than you think... Mobile phones drop connections with surprising frequency, so it's worth thinking about very early on.


Security is exceptionally interesting, and it is why my language handles privacy as a first class citizen.

The scaling up is a challenge due to the lack of common investments. It can be made absolutely cheap, and it is way cheaper than polling.

People that dismiss websockets have a point that it throws away decades of wisdom, but the winnings and potential are there. The challenge is curating the right ideas and educating everyone... is hard.


> It's very easy to fuck up the implicit state tied to the connection, and this requires discipline to get right. It's very easy to ship unreliable software that then has issues based on the connection.

I agree with this and it's why I believe that Phoenix LiveView is the best solution to this problem. The programming model and tooling that you get with the BEAM (along with things Phoenix provides like PubSub) are the best there is to manage this complexity.


> In essence, I am building a DIY database such that people connect directly to the database and get that sweet giant JSON object along with a stream of updates.

biff implements this as a framework, backed by the Crux bi-temporal DB. It natively uses EDN rather than JSON, but emitting JSON should be trivial if that's needed.

https://findka.com/biff/#introduction

https://opencrux.com/main/index.html


> There is a great deal of power in having your UI be a stateless function over a giant JSON object.

Something like this: http://jasonette.com


Kind of, except the JSON is pure data rather than a rendering tree. That's a very interesting project...


> Second, HTML over WebSockets is nice, but what is better is reactive data binding over the socket.

This is the approach we are building in https://braid.org. We are extending HTTP from a state transfer protocol into a state synchronization protocol, so that when you do a GET request, you can also be promised to receive all updated versions of that resource. This extends very nicely with software that binds the resource directly into a DOM element.


Your website doesn't seem to be reachable.


Sorry, there was an outage this morning for a few hours, but it's back now.


Got a question for you -

I'm making a chat bot thing (https://www.brian.bot/) and have added socket-based web chat... but I don't even know how to phrase the question of "how do I horizontally scale the socket connections".

Webchat <-> Server <-> Slack. Once I have more than one server dyno (heroku), then I can't ensure that the Slack event hits the dyno with the corresponding socket connection.

Thoughts / tips?


I'll be completely honest... you're mostly screwed. I say this with full love in my heart.

Your best bet is to use Amazon and then leverage their ELB offering with sticky routing. HOWEVER, now you have a new problem as capacity dies, gets removed, cycled, added, etc. Sticky routing was designed with the assumption that it was an efficiency play as opposed to a deterministic play.

What you will see happen is that your internal state will be split brain, and people joining the chat will not be globally consistent. Some people will be on host X while some will be on host Y. So, you have two choices. You could use a database to provide the global state, at which point now you have a whole bunch of problems. You can start with polling the database, and the key advantage of the websocket is moving the polling from client to server, so that will be a win for users. However, it will cost you. Second, you could introduce a message broker, but then you have the problem of how to initialize the state. Ultimately, everyone ends up with a hybrid database for storage and message broker for real-time.

In your model, the database becomes like Slack, and your Server becomes a proxy. This could be super neat, but what is the value-add of the Server?

The interesting thing to observe is that the solution is how to turn your front-end app into a database like thing. If the load balancer could route traffic like a database traffic controller thing, then you can put all your state in the front-end and move crazy fast. However, you will move so fast that you will fuck up your state. State is VERY HARD and exceptionally unforgiving to manage yourself.

There is great wisdom in using a database with versioning and all that. It’s a great abstraction having lasted so long. I’m working on the state bits and trying to figure out the people side of discipline with my silly language, and I have some novel contributions to provide over the coming years.

There are some linked pdfs on http://www.adama-lang.org/blog/some-thinky-thoughts-2021 which may provide some more insight.


That's super helpfully, actually - tells me about some problems that I wouldn't have anticipated, and tells me NOT to go looking for certain other solutions.

Short term, I think I can get by with switching from Slack's events API to their real-time widget - aka, the server gets a socket to both the web chat, and the slack.

Long term - probably the Redis pub/sub with the socket-receiving server split out as a microservice (which normally I'd be "eh" about, but this seems perfect).

I currently don't have to worry about multiple people on the webchat (outside of needed features) and even once that's an important thing, I doubt I'll need to worry about exactness. As long as each message get delivered reasonably quickly, and to everyone, should always be good.

hmm, hmm hmm - great stuff, thank you!


Just a random thought - wonder if anyone tried a p2p protocol instead of a database or message broker for spreading information. Wonder if it'd be any better than broadcast to every stateful instance.


Bittorrent, blockchains.


You can use a redis to distribute messages via PUB/SUB. The sockets subscribe to the events that are relevant to them. It can handle thousands of messages a second in a local environment and probably more in a dedicated hosting environment.


Seconding this approach. I've used PUB/SUB for this exact purpose.

When you need to send something through the websocket then publish a message via redis and have handlers in the code that are subscribed to that channel so every server can check if they have the websocket connection and whichever one has it will send the data through


That mostly sounds great, although TBH my first instinct would be to stick all the socket stuff in a microservice. I don't normally advocate for them, but this seems like a perfect situation: very well defined layer that contains no business logic.


Pretty sure that Erlang or Elixir would work there - you can have clusters of stateful servers.


Interesting ideas, somewhat in line with what I've been thinking about.

Perhaps you or someone in this topic might be interested in my little project[1] fit for innovative ideas like this. It is not very far from being available for experimental use in place of JSON. A future direction is experimenting with replacing HTML[2].

[1] https://www.tree-annotation.org/

[2] https://imgur.com/a/ER5qwtZ


What advantage is this providing except job security for developers that have to port working HTTP/1.1 systems to HTTP/2&3 and WebSockets?

Have you used HTTP/1.1 comet-stream? I recommend you look at this sites source before you commit further: http://fuse.rupy.se


This seems like X Windows protocol over HTTPS with JSON as the wire encoding.

It's sad to think how much effort is spent reimplementing technologies because the IPv4 address space wasn't large enough.

If IP address space were larger, we wouldn't have needed to rely on Network Address Translation (NAT). NAT became a poor-man's firewall and effectively blocked peer-to-peer connections making it difficult to host a server at home. This incentivized early ISPs to offer only asymmetric connections that pushed users towards a consumer-only service that crippled early Internet protocols. With the World Wide Web being "the" reason people got on to the Internet in the first place, early NAT-enabled routers focused only on HTTP tunneling, so completed protocols that required inbound connections were finally killed off.

Who would have thought that a small IP address space could result in a mass protocol extinction event from which only HTTP and HTML would survive....


> NAT became a poor-man's firewall and effectively blocked peer-to-peer connections making it difficult to host a server at home.

Most ISPs (with the exception of very small ones) until recently assign one public IP address per customer and NAT is done on home router. With this setup it is not hard to host a server at home - it is just one rule on router to NAT all incoming connections to that server. Many SOHO routers support such setup. Alternatively, the server can just work as a router.

> This incentivized early ISPs to offer only asymmetric connections that pushed users towards a consumer-only service that crippled early Internet protocols.

Asymmetric connections are offered because many last-mile technologies (like ADSL and cable modem) are asymmetric on link-level - they use different bandwidth allocations for upstream and downstream.


Not necessarily true for all countries and ISPs. Eg in India, you have to specifically request for and pay approx $55/mo for a connection with static IP whereas regular broadband connections (150 Mbps, 500 GB data, FTTH) start as low as $12/mo.


They are asymmetric because the are provisioned that way. IE it was done intentionally.


This. But also majority of people are (or were, before covid and the whole wfh thing) consumers of content not producers so that uplink would have terrible utilization anyway


HTTP isn't only about NAT. Lots of protocols have a clear notion of client and server, and don't require dialback.

HTTP is successful partly because it's simple and "stateless", in the sense that all protocol state is held by the client in cookies. Keeping all state in cookies+database provides some useful properties, in particular around scaling, being unfazed by IP address changes (e.g. wifi to wired), reboots of both clients and servers, version changes, hibernation/wake-from-sleep, and a variety of other things that otherwise break connection oriented protocols.

Of course sometimes people screw that up in other ways, hence the popularity of "clear your cookies" as a troubleshooting tip. But overall it works pretty well. Look at the prevalence of hacks on top of SSH to create persistent sessions, to see what has to be done when you don't have that model. SSH only survives as a protocol because remote administration doesn't need to be a particularly great user experience and it doesn't need to scale, so legacy and inertia wins out. Otherwise we'd probably see a request/response protocol take over there too.

X11 was always a PITA not only due to NAT but also due to institutional firewalls, e.g. universities often have enough IPs to give everyone a public IP but firewall traffic anyway to stop exploitation of vulnerable devices. So the whole "remote client connects to local server" model was not only confusing but also a poor fit for the real world internet in which centralised, professionally run servers are invariably more secure than scattered non-professionally run edge devices.


Couldn’t agree more


This seams really optimistic and kind of glosses over the subject of scaling out websocket connections apart from this.

Anecdotally, the typical single Rails server process seems to be perfectly happy supporting nearly 4,000 active connections. And you can easily swap in the excellent AnyCable to bump that up to around 10,000+ connections per node by not relying on the built-in Ruby WebSocket server.

That's not a lot of connections on it's own. If you are implementing a chat service you'll still need some form of pub/sub (or something) to glue all of that together when users connect to disparate nodes.

Also

How about client-side validations? Easy. On every input change, round up the form values and send ’em down the WebSocket.

That's just server side validation.

As a disclaimer, I haven't used any of the HTML over WS frameworks the author discusses, but I've spent a fair amount of time dealing with scaling socket connections. It definitely makes the question of scaling horizontally more challenging. I feel like this article really glosses over that aspect.


FWIW the article should have led with Phoenix LiveView, which really pioneered this approach, and is much better suited via its concurrency model for large scale streaming apps (like chat apps).

Where Rails with “live view” tooling would work really well is building CRUD heavy sass apps that don’t need a persistent connection, just want really fast page refreshes and/or partial updates.

The work the basecamp team did on Hey seems to be a good illustration of that.


Phoenix live view (anything on BEAM really) maps each ws to a BEAM process so scaling to 10000+ connections is both cheap and built-in


But LV is still in its infancy and there are very real implications of using websockets that are unrelated to open connections.

Just the other day someone posted on the Elixir forums about live_redirect causing 2 network round trip connections[0]. Basically there was double the latency to transition between pages due to this "bug". I air quoted "bug" because it's working as intended, it's just not optimal.

The creator of Elixir mentioned it was doable to fix the issue but when an issue was open on GitHub[1] it was shot down with a "this is a known tradeoff, you'll need the 2nd route trip for the websocket". I'm not sure what the state of the issue is but it currently stands as closed.

I've pinged 80ms to servers where LV was being used and the delay was extremely noticeable (before I even knew about this double network round trip issue). It feels much worse than a Turbo Drive / Turbolinks driven site (which uses HTTP instead of websockets like LV does). In some cases LV feels slower than a regular site even with the DOM having to re-parse all of your assets. The only time LV feels like a net win to me is when you're on a local connection with 1ms of latency.

I wanted to use LV a lot, but backed out because I kept running into bugs and missing features. Plus after feeling a LV site on a non-local connection I can't say that I would want to impose that experience on users. Especially folks who happen to connect from let's say Europe to the US, or even further away. The web is a global place.

[0]: https://elixirforum.com/t/shortcomings-in-liveview-are-there...

[1]: https://github.com/phoenixframework/phoenix_live_view/issues...


> The creator of Elixir mentioned it was doable to fix the issue but when an issue was open on GitHub[1] it was shot down with a "this is a known tradeoff, you'll need the 2nd route trip for the websocket"

Please Nick, you can literally check your links to see this is inaccurate. I mentioned a solution after the issue was closed - and not before as you describe. And I figured out the solution *with Chris*, as I clearly mention in my comment.

And then later on:

> dive into the source code that I can't read very well because there's a lot of macros

There are like 8 macros...

> since LV is a pre 1.0 release the docs aren't really written up yet since stuff is changing all the time

Seriously? No one has ever said this is the case. Just go to the [official docs](https://hexdocs.pm/phoenix_live_view). All public functions are properly documented, there are introductory guides, etc. Sure, we don't have official screencasts but that's something we rely on the community to step in: Pragmatic Studio has a fantastic course on LiveView (which I was involved as a sounding board), there is Grox.io, etc. And it hasn't stopped either, a new book was literally announced today.

There are other inaccuracies in the comments below but honestly I don't have the energy to go down this rabbit hole again.


> There are like 8 macros...

I should have used quote / unquote instead of the word macro.

When I looked into the code I started with the engine and renderer. Between both modules they had dozens of quote / unquote usages which to me was hard to follow. Not because it's written poorly or anything like that, but it's not exactly easy to trace that code to learn how something works in more detail.

> I mentioned a solution after the issue was closed - and not before as you describe.

Yes, after it's been closed. But look at it from what end users of your library see from that chain of events:

1. User asks question on forums and presents a case where something very bad happens (2x network round trips)

2. User posts issue on GitHub

3. Creator of LV says it's a known trade off and quickly closes the issue

4. You and the creator of LV talk offline and figure out a potential work around

Re-opening the issue after #4 would have done a lot of good because it shows at a glance that it's a current issue, it's being addressed and open for discussion.

With the issue being and staying closed this gives off a message that you're not actively working on fixing the bug and aren't open to any form of discussion or assistance around fixing it. Maybe that wasn't your intention but that's the message you're sending to some people.

> Seriously?

That's the answer I've always received in the past when asking questions about the state of the docs on Slack and IRC over the years. The current docs usually give you a partial understanding of how something works. It's usually enough to get a basic idea of how something might work but not enough to get the ball rolling to implement a solution in your own application. I don't think I'm the only one who feels this way either because I've seen a lot of repeated questions on IRC and the forums, especially around LV components.


When did you last use it? Javascript hook support wasn't there early on. The state of the art is the "PETAL StacK" [1] which uses client-side JS for interactions that don't require a roundtrip

[1] https://thinkingelixir.com/petal-stack-in-elixir/


> When did you last use it?

I gave it a fair shake a few times.

Once when it first came out, then again a year later and then again 6 months ago.

Lack of hooks wasn't a concern I had at the time. It was more around core behavior of the library and critical features that were missing. Some of those features have been added after I posted about them but all that did was destroy any confidence I had in using LV because these are things that would have been encountered on day 1 of deploying a single LV app to production. We're talking huge things, like how to invalidate and update assets in the <head> of your page in a user friendly way.

It left an impression on me that LV isn't really being used much in real world apps by the team developing it. I could be wrong of course but that's the impression it left. Plus it feels like it's taking a really long time for certain features to make their way into the library. For example file uploads took something like 18 months to go from being talked about publicly to getting an alpha release and now it feels like it's on the burden of the community to test this in production without really knowing much about the feature.

That and the docs still leave a lot to be desired (especially around the time I read them) and the story for the last ~18 months is that since LV is a pre 1.0 release the docs aren't really written up yet since stuff is changing all the time. I know docs take a long time to write (I've written literally over a million words of blog posts / course notes / documentation) but docs and practical examples are also the most important thing IMO to nudge folks into using something.

Personally I don't want to have to read minimal docs, API specs and dive into the source code that I can't read very well because there's a lot of macros to see how something works just to use it effectively. Especially if I'm on the front lines of having to pioneer the tech, which means I'll probably be under pressure to report and fix bugs that I don't know how to fix.

I don't know. All of this experience with LV and Elixir / Phoenix really made me understand that this tech stack is not for me. Especially not when Hotwire Turbo exists and works with any back-end language and it also has proof of it being used in a mission critical massive SAAS application (https://hey.com). That leaves me super confident that it'll work for me (and it has been), even outside of Rails.

Maybe in 5+ years I'll try Elixir again (hopefully Stripe and other payment providers have Elixir clients by then!), because the core Elixir eco-system in general has a bunch of nice things. It just doesn't feel optimized yet for building applications (IMO). At least not compared to most other web frameworks.

Also, while I don't use Laravel I also have major respect for Caleb Porzio. He created Laravel's version of Live View (LiveWire)[0] by himself. It mainly uses HTTP and he also has a ton of docs / videos on implementing practical application features with it. He shipped 2 major versions and everything about its API and docs just oozes creating something made for developers to develop applications. It's funny how a slightly different position on something can make something explode in popularity.

I haven't even written a single line of Laravel and have no intention on switching to it, but his presentation and execution of an open source library is something I admire.

[0]: https://laravel-livewire.com/


I think ultimately Phoenix and by extension LV just don't have the manpower.

LiveWire builds on Laravel which is a massively popular framework on a massively popular language, Laravel itself using components from Symfony that is basically the backend framework with the most contributors in the world.

But LiveView may hit 1.0 this year :)


> I think ultimately Phoenix and by extension LV just don't have the manpower.

For comparison's sake:

- [LivewWire] Caleb (creator of LiveWire) made 1,000+ commits and added 200k lines of code from Jan 2019 to Feb 2021

- [LiveView] Chris (creator of LV) made 700+ commits and added 80k lines of code from Oct 2018 to Feb 2021

- [LiveView] Jose (creator of Elixir) made 450+ commits and added 25k lines of code from Oct 2018 to Feb 2021

There's even more contributors to LV (207) overall than LiveWire (145) which is interesting because LiveWire is 3x more popular based on GitHub stars.

From that you could say that LiveView has more manpower than LiveWire since Caleb wrote all of that code himself in a shorter amount of time while 2 people are main contributors to LV.

Plus at the same time Caleb wrote a huge amount of practical documentation (focused on building features), created lots of screencasts where you build features you would expect to see in most apps (data tables, etc.) and started a podcast around LiveWire. And on top of all of that he created AlpineJS at the same time.

> LiveWire builds on Laravel which is a massively popular framework on a massively popular language, Laravel itself using components from Symfony that is basically the backend framework with the most contributors in the world.

At a fundamental level it feels like the creator of LiveWire is investing in creating a tool that helps developers build applications better and faster. I think that stems from Laravel giving off a sense of developer productivity for building apps, but don't forget that library creators are making these decisions.

I never really got that same impression from working with Phoenix or LiveView. I think it caters towards a completely different type of developer than myself which is why I struggle so much using it. It always felt like instead of showing you how to do something, it makes you figure it out yourself.

> But LiveView may hit 1.0 this year :)

That would be nice to see but I'm not sure how much of a difference that will make in the short term. In the short term going 1.0 is really just deciding to tag a commit. If Chris and Jose plan to write another book to use LV that could still be over a year or 2 out unless they've been writing it in private, or if they re-write the documentation that's also another long journey.

Neither of them really strike me as the screencast type either. When they do create videos they do an excellent job at explaining things tho. Really wish they did more of them to be honest. But yeah, these things take time. I don't know what their schedules are like too so maybe it's not even fair to compare LV vs LiveWire in terms of how fast the library is being built. Maybe Chris and Jose only work on Phoenix and LV for 2-3 hours a week where as Caleb is working on his stuff full time.


Comparing two projects by the number of commits and lines of code written. You must be a manager.

Maybe Chris and Jose are more efficient? Maybe the Elixir/LiveView code is just better written and doesn't need rewrites?

Why do so many people glorify quantity over quality?


> Comparing two projects by the number of commits and lines of code written. You must be a manager.

We are dealing with limited information here, and GitHub makes it easy to see at a glance what folks are doing on a project. It just so happens it focuses on presenting commits and lines of code written.

Everyone knows it's not the best metric but to get a high level overview of activity those stats work. Especially when the person I was replying to said LV is maybe moving slow due to a lack of manpower. Those numbers show the opposite (LV has more folks working on the project than LiveWire, despite it being much less popular due to Elixir being a smaller niche than PHP).

> Maybe the Elixir/LiveView code is just better written and doesn't need rewrites?

I don't think it's fair to jump to any conclusions about the quality of either code bases.


Exactly, and without equalising between languages. PHP is verbose, elixir is elegant.


This is an incredibly offensive and insulting comment about people you don’t know, regarding software you openly state you don’t use on a daily basis.

I would care a lot less if we were talking about billionaires building commercial startups, but you’re literally attacking open source contributors. Moreover, my personal experience in using LiveView and interacting with the community has been the exact opposite of yours, so I find your comments to be totally misleading for people who might think that your walls of text have any nuggets of wisdom in them.

I’ve tried a lot of open source software that left me thinking, “wow, what a waste of my time.” For some reason I never felt a need to openly attack the authors of these low-commercial-value-for-the-creator, volunteer-driven projects. You might want to consider directing your critical eye toward the actual problems in this world, rather than volunteer programmers’ projects that didn’t met your personal, highly-opinionated requirements.

The parent comment is Exhibit A for why so many people refuse to get actively involved in the open source software scene, and why so many drop out.


> Regarding software you openly state you don’t use on a daily basis

Perhaps I was too critical in some of the replies and should have phrased things in a more positive way but I did use Elixir / Phoenix / LV on a daily basis for a pretty long time.

Over the course of those 18 months I'd estimate putting in 250-300 hours of programming time in spurts while writing 3 applications totaling around 9,500 lines of assorted Phoenix / LV code. Not a lot of code by any means, but enough to put a decent dent towards developing the main app I was building which is where I encountered those issues at the time. I have no agenda or reason to make anything up. I want to see Elixir and Phoenix succeed in the end. I just decided to temporarily put it on hold until it gets over the early adopter phase.


Maybe my impression following the Phoenix and LiveView commits was wrong but it still feels it's mainly two people.

José works at the same time on Elixir, Phoenix, LiveView, Ecto, Nx, Dashboard and more, it's a lot.

To be fair there also has been integration of LV in the Phoenix mix tasks, in addition to the Dashboard (using LV, ah!), so it's not like things are stalling.


It is also important to note the latency in these connection. Generally speaking 4000 Active connection you are looking at 150ms+ for 98th percentile already. Which is bad to be frankly honest.

( Results were from 2016, so may be things has improved )


Sure, it's server-side validation – which is great, and works well. And now it works without a full page submit and reload. That's a huge benefit.


Ever since xmlhttprequest (and even before that with images) we've been able to do server-side validation without a full page reload.

This "solution" completely ignores the purpose of client-side validation which is to a) reduce load on server-side resources, b) validate faster without the network latency and c) validate more securely and privately by not sending the content to the server.


Which you can do already for over a decade with AJAX.


Yup. And DHTML over a Java applet before XMLHttpRequest. 1999 at least, iirc.


Everything about this sounds terrible for mobile, lossy or even medium latency connections. Non-blocking background updates are unnoticeable, but imagine your website being jammed like a stuck video every time you click or scroll?

He describes a "please wait buffering" future of web software. No thanks.


Also:

> Do we really believe that every one of our users is going to have a device capable of digesting 100 kB of JSON and rendering a complicated HTML table faster than a server-side app could on even a mid-grade server?

Yes. This really isn't hard. Pretty much any smartphone can do this with blissful ease. And it scales horizontally because your server can just worry about getting stuff from the database and handing it out.


Exactly. Our app renders highly detailed 3D anatomy on the canvas. The largest model is a 1mb json file with 57mb(!!!) Of assets. We've never had a problem with mobile devices, they're shockingly capable.


What countries are your users in?


San Francisco isn't a country.


Turbo[links], Stimulus, etc. ARE non-blocking background updates. It's HTML over the wire instead of JSON. [1] I don't think this is what you think it is.

[1] https://hotwire.dev/


since when is HTML lighter than JSON?! this use case was what propelled JSON into the mainstream.


The argument is that it is lighter for the device just to receive static HTML, than it is for the device to receive JSON and build HTML templates.


The idea is that HTML is just slightly heavier but the advantage is you can render it on the server and don't need all that middleware and serialization layer.


That was my first thought too, the word "latency" isn't even mentioned in the article.


With this approach you can keep all of the traffic inside a WebWorker, so nothing blocks. You also get the benefit of not having to open a new connection for every request and automatic reconnects when someting goes wrong. The connection is most likely already established before you even need it.


You just described http2


Wait, with http2 a webbrowser never closes the connection it has to a webserver?


Even HTTP/1.1 from 1999 keeps a persistent connection open, if the client and server agree.

What it doesn't do so well is lots of parallel requests and responses out of order. HTTP/2 is better for that.

Both versions will close the connection if it's been idle for a while, and automatically reconnect as needed.


Yes, it's a long-lived TCP connection. It's not mandatory but the whole point of the protocol is to make one connection and send/receive all your assets over it instead of making more connections (which take time to setup and slow down page rendering).


It keeps it open as long as it is used and usually a bit past that. So if you have any traffic or are making periodic requests then it won't close the connection. If you are using SSE that can also use the same shared connection for streaming realtime updates to the client.


At least their web page seems to work without Javascript... I hope this technology will too.


Of these things, I've only played with LiveView (I'm a web dabbler, not a pro, but an Erlang/Elixir fan so it was interesting to me). At least through the material I've worked through, it fails to a usable mode when JS/WS themselves fail on the client side. In theory, the only required JS is the JS needed to establish the WS connection and communicate with the server and issue the updates. But if the WebSocket fails, you should end up with just a full page load instead of the diff being applied. (NB: A particular site/application may have more JavaScript, but for what LiveView offers out-of-the-box there's not much JavaScript that's included or needed.)


I had this thought as well, but having used Liveview in Phoenix this really isn't the experience. Since the updates are really small and as long as you do it only when you want updates from the backend anyway the experience is just as smooth as any SPA even on a shitty mobile connection.


Isn’t this also the basis for Stadia RIP and XBox Mobile work on iPhones? That seems to deliver acceptable results for even arcade games on WiFi.

Latency seems to have been conquered.


> Latency seems to have been conquered.

I dare you to say that from Australia.


We are not close to conquering the speed of light. Ping time NY to Australia is 100-200ms regardless of software stack.

But if you have a server in Australia then I would still say that.


I used to love WebSockets a lot more. At some point I got deeper into implementing HTTP servers and proxies, and realized how much of a special case WebSockets are to implement. They're cool, but I prefer Server-Sent Events on HTTP/2 whenever I can get away with it, which is pretty much always (binary data being a big exception, and even then I consider long-polling first).

I think there's value in keeping our protocols as simple as possible to accomplish the task at hand.


I feel like websockets get waaay too much hype and attention compared to SSE, especially for use cases that are barely interactive at all.


Sadly it's not entirely unfounded. SSE on HTTP/1.1 is basically useless due to the connections-per-domain limits implemented in browsers. So WebSockets got a lot of mindshare while we waited for HTTP/2.

But today I always start with plain HTTP, then try SSE, and finally WebSockets if I have to.


Future-proofing is a good use case though. As a developer I don't want to maintain both SSE and WebSockets, since they solve similar problems and WebSockets are a superset of SSE. Even though my WebSockets implementation is currently unidirectional (server to client), I still opted for that over SSE because I'll probably need send data the other way at some point in the future. Why learn two tools when I can just learn one?


If you use nginx, you can use the excellent nchan module to push messages by having your backend make a POST request to nginx. Clients can connect to nchan via websockets, SSE, and few other things like long polling without your app having to support all of them. Been using it for a recent project and really like it.


What's wrong with normal HTTP requests for client->server streams? You get the added bonus of being able to dump them to a curl command for debugging.


More overhead, and it doesn't scale. My nodejs websockets server can handle thousands of connections without a problem, but my rails api server allocates a thread per connection so I'm limited to <16 unless I start horizontal scaling.

For infrequent requests everything goes through the api, but for stuff like chat and live-document-editing, nodejs is the better solution.


I think I missed something. Why can't you use node for SSE?


I can, but why would I limit myself to one-way communication when I can have bidirectional communication?


You didn't cite bidi as your reason for choosing WS in your last comment, you cited scaling and node vs ruby.

But to answer this new question:

* You can have bidi without WS.

* Because WS is more complicated.


> You didn't cite bidi as your reason for choosing WS in your last comment, you cited scaling and node vs ruby.

Because I was answering this question: "What's wrong with normal HTTP requests for client->server streams?"

> You can have bidi without WS.

Only by combining HTTP (which doesn't scale because my api server runs rails) and SSE (which does scale). If I want scaling bidirectional communication, I need websockets.

> Because WS is more complicated.

More complicated than SSE? I don't think so.


And using SSE with Hotwire is even easier than using WebSockets: https://mercure.rocks/docs/ecosystem/hotwire


I've used HTTP/2 SSE for TinyDev (docs.tinydevcrm.com) and I've encountered the need for a reverse proxy and the unidirectional dataflow to be kinda eh, even if it is great in theory. I haven't played around too much with WebSockets though, but IMHO money + traction carries a good deal of weight.


Why do you require a reverse proxy, and are those requirements unique to SSE for some reason?

I guess I'm not seeing what the alternative setup would be, even with WebSockets.


Isn't HTTP/2 SSE being deprecated?


I sure hope not. Are you thinking of HTTP/2 server push?


I've seen nothing to suggest SSE would be (or is even capable of being) deprecated on HTTP/2.

You may be confusing it with HTTP/2 Push, where a server can inform a client of a future resource it will need, which is _de facto_ dead, with only a few real implementations beyond the bare minimum required by the HTTP/2 specification.



I'm also sad that SEE's don't get the attention and love they deserve.


You might check out https://braid.org, which is like SSE but specifically for updating state at URLs, and works for binary data.


Thanks. Braid looks interesting, but complex and mathy. It's not clear to me what the use cases would be or why I would choose it over SSE or WebSockets for any given problem.


That's good feedback, thank you. I think we'll be able to get clearer use-cases there within the next few months.


Another "The future of <thing> is what <some person> says it is" without much more than a few paragraphs of explanation.

No diagrams. I don't see much of a comparison between costs/benefits of alternatives.

Nice hypothetical. I didn't read it, because I've seen the format before and I'm getting a bit bored of it.

Whereas if it cited some other engineers/technologists, some studies, some academics, etc., then perhaps I'd be more inclined to read this.

But one person's opinion? Nah. I need an aggregate of opinions to be persuaded to read another "The future of thing..." article.


The guy I learned about 'mis en place' from had coined a term, "retro-grouch" for people who loudly insist on a nostalgia for old technology.

When the Trough of Disillusionment hits, us old farts pop out of the woodwork to say "see, told you so" whether we were right or wrong.


Did you learn mis en place in a kitchen, or does it have a meaning in technology circles that I'm unaware of?


Turns out if you do skilled manual labor, the concepts translates. Bob was a bike mechanic. I don't know if he used the words, but he kept harping on us for not having our shit or tools together for a task ahead of time. When you're covered in grease is not a time to be digging for a wrench.


https://en.wikipedia.org/wiki/Mise_en_place

I think it also relates to operational professionalism and having your tools and toolbox in order ala Adam Savage and Jamie Hyneman from Mythbusters. They both had very interesting relationships with order, process and tooling.

I think structuring dev teams around a professional kitchen is really powerful model. All roles are critical, the sous chef, the busser, the prep cook, the dishwasher, everything.


You can't scale without delegating. And in a crunch is not the time to work out procedures. You do that between. Yeah, it's not a bad model, and you can stretch it pretty far until it breaks.


I think the closest other team arrangements to watch for modeling software around would be theatrical performance and to a lesser extent bands.

Though kitchens are especially interesting as they have pipelines, surges, lots of tasks that can be broken down into a series of steps.

Mythbusters has another interesting aspect in that they came from movie production background, so wall time was really critical, you can't hold up a shooting day to get a better glue formulation for simulated flesh falling off bone.

Part a thing is its structure, but the other part is how it evolves over time and its reaction rates to stimulus.

Agree on the beers.


I work in an org where it is used to refer to the prep for a release, but with sort of a wink and a nod.


Well, it is an opinion piece


Clearly I arrive at this piece without the expectation of it defining the future-- I know better than to expect a pop tech piece to deliver to me a view of the future.

format: blatantly unoriginal

content: not persuasive, underdeveloped

effort: very low

value: very low

"The future of" is a very bold statement. The more cliche it becomes, the more I expect an author to actually outline, in a bold, cohesive, relatively comprehensive way, their theory.

Otherwise stop trying to tell people what the future will be-- it's a waste of time & attention.

Sure, the headline is catchy. The rest seems like the author was simply trying to reach a certain word count and claim their cheque.

--> "Future of" articles should read like a graduate academic paper-- give the future of technology the proper respect it deserves.

--> Or, they should be a policy paper.

Not a pop tech piece. Pop writers-- stop with the silliness-- stop appointing yourselves as definers of the future unless you expect folks like myself to come along and bring you back to reality.

____

Take this linked citation for example:

"Fast-forward to 2020 and the web isn’t getting any faster"

It's linked to an article by an individual who has an undergrad degree in psychology, a grad degree in IT, and is a design/UX-related employee. That's not the person I would go to for a technical, knowledgeable analysis of internet speed evolution.


But he could be right

Why does it annoy you so much?


I'm just sick of low effort articles where the author appoints themselves oracle/definer of the future.

It results in devolution of knowledge and a disrespect of the attention of intelligent people.

"he could be right" -- what a waste of a statement unless it is followed up by any premise. He could right... Ok, that's a claim. But based on what?


But you’re the one whose decided to dedicate so much attention to it. If it’s a prediction you don’t agree on just ignore it

The fact that it’s touched a nerve is more interesting to me


Wait a sec-- So someone can write an opinion, and that's ok-- but hey: no one critique it, ok?

But if I write an opinion-- that's not ok. But you-- you're allowed to critique my opinion.

_______

Let's apply your logic to your replies:

Well, jack_riminton, It seems like I've touched a nerve.

Why did you feel compelled to comment on my commentary, when you could have just ignored it?

Why are you critiquing my opinion if you're making the case that opinions should not be critiqued (and should simply be ignored if a person is in disagreement)?

______

Ohh.... Now I see. You're the one who posted the article.

Well, everything is very clear now: Simple bias.

______

Note: You never followed up when I questioned the premise of your claim "he could be right." It seems you're not interested in analyzing whether or not he is right. So what's the point of even posting this article?

Yet the purpose of my entire thread is to draw attention to the fact that him being right will not result from conclusions of a poorly contrived, low effort, pop-tech article.


Seems more like your nerve was touched. If you can't handle critique and do not want attention why are you posting your article here?


Firstly it’s not my article

Secondly I don’t even agree with it

It’s an interesting (and apparently provocative) prediction. I’ve enjoyed reading the responses


In college, when you write only "2" for an answer, the teacher doesn't say "hmmmm, he might be right", instead you get an F for not showing your work.


Really? Requiring you to "show your work" was rare in college for me, though typical in K-12. But not showing your work, if you're wrong, means no potential for partial credit in college (for instance, correct process but a lost sign might get you half credit versus no credit).

Unless of course, showing the work was the task (such as writing out a proof) versus a straight computation.


It’s not college though is it?


The failure with "he could be right" is here:

He could be right because... (these are just generic examples)

- He mentions renowned research by XYZ who has through years of painstaking research concluded (as cited in XYZ peer reviewed journal) that the basis of his argument is sound

- He's an expert in XYZ field, having worked at XYZ company which clearly demonstrates proficiency in XYZ subject material

- He clearly elucidates, citing several researchers and with clear, understandable diagrams how the phenomenon XYZ works

... Yet you make no effort to construct a premise to base your claim upon. Because no real premise exists: the article's author makes no effort to support his own claim about the future.


I’m gonna be “that jerk on HN,” but this is that idea that just keeps getting rehashed every couple of years then fizzles out. The reason that it’s so attractive is because as developers we love to build and save time, and we think, “imagine what we could do if we didn’t have to ask for data from remote servers...”

The problem is that stateful connections suck and create artificial complexity when you don’t need them. Instead of managing the state of your app you’re now managing the state of your app and a connection to a remote server. HTTP is a stateless protocol on top of a stateful socket connection. It wasn’t designed this way by accident.

I’m all for new engineers building SPAs creating exciting new libraries, but HTML-over-websocket has been rehashed at least three times over my professional career so far and it’s not even that long.

Don’t get me wrong — websockets have their use cases. Multiplayer online experiences pretty much require them. It’s just that HTTP isn’t fundamentally broken, and by engineering HTML over websockets you’ll almost universally find yourself building protocols to abstract the state away... re-engineering HTTP in the process.

It’s certainly a fun project which I have personally worked on. But I’m not sure it has legs outside of that. Open to being proven wrong, the authors of HTTP aren’t infallible.


As a thought exercise;

- What happens if the client’s internet connection temporarily drops? How do you handle client reconnections and retries?

- What if the remote server crashes through no fault of your own (AWS server rack catches fire)? How do you ensure a consistent reconnection that preserves application state?

These are just two questions that HTTP + Browsers solved decades ago.

Websockets are this cool technology that seems powerful and exciting until you realize the “boring old stateless World Wide Web” was built over decades of iteration using stateful sockets as the backbone, did most of the work for you in tandem with browsers, and is ultimately a lot cooler and more sophisticated than a lot of us give it credit for.


Here's another one. How do you deploy a new version of your service?

Imagine a few customers open up your site and leave for lunch. Or maybe just a random crawler or bot sitting watching for some piece of information they are scraping.

These sorts of issues can be challenging with stateless connections. I can only imagine how daunting they are with persistent connections.


The nice thing about persistent connections is that you know when they’ve been closed so you could literally signal that the connection was going down for a deployment and close everyone’s connection. Clients can retry the connection until it comes back up or use another service to monitor the status.

Games basically do this routinely.


But you can do that sort of communication already with existing websockets, without trying to add the complexity of pushing all your regular traffic over that link.


Well, this problem exists at the moment. To be honest sockets is one approach to fix it.

What happens if a webpage is loaded over plain old HTTP and then over lunch a breaking change is deployed. The page the user loaded before lunch is now no longer compatible.


Compatible with what?

It’s stateless. If the api changes from underneath and you’re polling or something, then just show an error, have the user refresh the page and move on. Or use any of the various api version mechanisms for backward compatibility. It’s not an easy problem but it’s a fairly well understood and managed one. Solving this kind of known problem isn’t, to me, a very compelling case for HTML over sockets.


I bet your ass that at least half of the developers reading HN don’t have caching of JS fully figured out such that when the JS changes server-side and immediately needs reloading on the client side that it does then and there instead of on the next request, the next page refresh, or never because they’ve f’d it up.

With server-fed, event-driven pages, you could potentially force refresh.


I leave the browser waiting for a fetch-response from the server. The server responds only later when the page that is open in the browser was updated on server. Seems to work much of the time, but sometimes it seems Chrome closes the connection after a timeout and shows a network error in the dev-tools. FireFox not.

I assume web-sockets could make it work more robustly.


my solution to version changes in a rest api is to sent a version header with every response, the app checks it and if it does not match reloads the page, thus loading the new js.


I would not accept your wager. That being said if this was a “really big problem” I’d bet you that most developers on HN would have an idea how to address it.


it is called hot-reload.


You restore the state like you would on a SPA or regular server side rendered page.

A crash or someone hitting refresh on his browser is not that different in this respect.


I'm astonished that people are asking these questions while there's obvious answers like this.

WSs aren't a magic wand, they just allow you to do more with the same.


I don't see what's astonishing about it and I'm scratching my head asking the same question. If the answer is that you handle disconnections and reconnections the same way that the HTTP protocol does it, then what's the purpose of HTML over web sockets?

You basically end up with a half-assed, buggy, and potentially insecure reimplementation of HTTP running over web sockets running over HTTP at that point.

Are you going to do session management and identification by issuing a unique identifier as well? Is that unique identifier going to be valid in perpetuity or have a an expiry date? Is it going to be valid and secure across all sub-domains or will it be prone to cross site scripting attacks?


>I don't see what's astonishing about it and I'm scratching my head asking the same question. If the answer is that you handle disconnections and reconnections the same way that the HTTP protocol does it, then what's the purpose of HTML over web sockets?

The purpose is in the things explained well in TFA: single source of truth, no replicated state, simpler development, and so on...

Who said the purpose would/had to be in handing "the server caught fire" scenarios?


The purpose is to render your page the "old way" but having the dom updated like an SPA.

It works for certain things and not for others. So, it's not "the future of web software" like the title says, it's one additional possibility for when it makes sense.


> then what's the purpose of HTML over web sockets?

Because you can do things stateless HTML alone cannot do.

No one is trying to re-implement HTTP, or even remove it from the equation.

What people are trying to reimplement (or rather, replace) is the HTML + JSON:API + React + Redux mess. Websockets is a means to that end.


Hm... great intentions, but you don’t seem to have actually answered any of the questions from the parent comment.

Unfortunately, great intentions alone won’t make this work; someone has to actually answer the hard questions about how it’s going to work too.

All the answers I’ve seen so far trying to answer them have been vague hand waving...

That doesn’t leave me with much confidence.


>Unfortunately, great intentions alone won’t make this work; someone has to actually answer the hard questions about how it’s going to work too.

People did better than that, they already built applications with this model.


You are welcome to actually look at the code for any of these solutions.

Here is the documentation for Phoenix channel authentication (what Phoenix Live View is built upon): https://hexdocs.pm/phoenix/channels.html#using-token-authent...

Additionally, here is some documentation on the security considerations specific to Live View: https://hexdocs.pm/phoenix_live_view/security-model.html

Searching can probably find you more information.


What you mean by sockets in "exciting until you realize the “boring old stateless World Wide Web” was built over decades of iteration using stateful sockets as the backbone".

I should probably already know this.


HTTP is a stateless protocol built on top of TCP network sockets [0] intended to standardize transfer of hypertext. It's the backbone of the WWW.

HTTP is quite literally "hypertext over sockets" so "HTML over websockets" is functionally equivalent... with a layer of abstraction added on top. If you build web software by sending HTML over websockets you're just reinventing what already exists; it's probably why it's never taken off. I think most developers realize within ~weeks to months of working on a "websocket-everything" framework that they're doing more work, not less.

[0] https://en.wikipedia.org/wiki/Network_socket


>- What if the remote server crashes through no fault of your own (AWS server rack catches fire)? How do you ensure a consistent reconnection that preserves application state?

Why would you? Nobody seems to ensure that with regular SPAs anyway...


> The problem is that stateful connections suck and create artificial complexity when you don’t need them. Instead of managing the state of your app you’re now managing the state of your app and a connection to a remote server. HTTP is a stateless protocol on top of a stateful socket connection. It wasn’t designed this way by accident.

Seriously, try phoenix liveview if you haven't already. These problems of dealing with stateful connections over questionable tranport and managing them are what the Erlang vm were designed for, and phoenix was designed by rails core team members.


Isn’t the issue, though, how do you scale this out? HTTP app servers are great... you can add and remove them at will, based on load, and customers never know the difference, because it only takes a few seconds after not accepting new connections for the existing ones to drain.

If you instead have servers holding state, those servers become a lot less ephemeral.

In addition, HTTP has built in caching, which is a HUGE benefit for scale.


dnautics isn't wrong. Even the issues you bring up are addressed by Erlang/OTP. Distributed Erlang with 10K nodes, hot code reload, etc.


the only people who think distributed erlang is good are people who have never done anything nontrivial with it


Could you explain why that is to someone (me) has never done anything nontrivial with it? Thanks.


i'd encourage everyone thinking about using it to go read the code (it's fairly approachable) but in short it just connects each node in the cluster to each other node in the cluster via a tcp connection and sends packets between them. there's almost nothing as far as protocol, queue management, congestion control or traffic management. it's discovery mechanism is just shipping lists of peers around. pretty much any competent programmer with networking experience could put together something comparable

it works okay in small clusters on reliable low latency networks but it's not a replacement for an actual network mesh

there have been attempts to fix it but none have really found adoption. i think this is the most notable: https://lasp-lang.readme.io/docs


thanks for your answer so basically it relies on plain TCP and its reliability features. If you need something more sophisticated you gotta do it yourself within the application code (or using libs).


Elixir tends to have sophisticated libraries around what you really want that are plug and play with distributed erlang. (Phoenix pubsub/tracker/presence). Horde/swarm, etc.


I work on a system with an distributed erlang service mesh.


> Instead of managing the state of your app you’re now managing the state of your app and a connection to a remote server.

Wouldn't an intermediate layer such as e.g. Phoenix/LiveView (https://www.phoenixframework.org/) solve the problem?


> Wouldn't an intermediate layer such as e.g. Phoenix/LiveView (https://www.phoenixframework.org/) solve the problem?

I don't think so but if I'm wrong please correct me.

For example, imagine this simple scenario: you load the comment page for this post on HackerNews

HackerNews renders an HTTP response to your browser and your browser renders the page based on that HTTP payload.

You can be sitting here on the page for 10 minutes reading comments and even if HackerNews randomly went down 20 times for 10 seconds each time during those 10 minutes you would never know because your browser has everything it needed to render the page when it loaded. It's a done deal. The request was made and the response was served.

But now let's say you use LiveView and you made this page an actual Live View. Let's also say you load all of the comments at once to keep the example the same.

Since there's a persistent websocket connection open at all times, in all 20 cases of HackerNews going down you're going to get a visual warning that the websocket connection was dropped. You also don't want to disable this visual warning because on slower devices it might take 2 seconds to load the page which is much different than an uncontrolled disconnect.

IMO this user experience is pretty bad. Why should users be concerned with the server's state after it has everything it needed to handle the request it asked for (loading the comment page). If they try to post a comment and the server is down then the user should see that error at the time of them making the comment (such as a custom 502 error page if the back-end is down).

The grandfather's comment of "it wasn't designed this way by accident" is spot on. The stateless web is a happy web. Sure you can sprinkle in websockets for progressive enhancements like broadcasting new content somewhere (which is awesome when done well), but websockets shouldn't be the basis for everything. HTTP has decades of very careful thought and optimizations around its protocol.


The sensible response to that scenario would be: Why did you make HN a Live View? I don't think anyone is suggesting that you make anything a Live View that is more appropriate as plain HTML. If you wouldn't use React, you shouldn't use Live View.

I understand you needed an example, but a better comparison would be a heavy SPA with real-time interactivity. In that case, if your server is down your API calls will fail and you're going to have to handle the failure and let the user know something went wrong any way. If anything, Live View's built-in buffer and retry can actually provide a better user experience because the UI will automatically "catch up" when the client reconnects.

> You also don't want to disable this visual warning because on slower devices it might take 2 seconds to load the page which is much different than an uncontrolled disconnect.

Live View loads the entire initial page over HTTP, then mounts the Live View. Your slow device won't see any difference if the visual warning is disabled or not.


> The sensible response to that scenario would be: Why did you make HN a Live View? I don't think anyone is suggesting that you make anything a Live View that is more appropriate as plain HTML.

It's because the creator of Live View himself said he's not going to be using "dead views" anymore for sites that don't need offline capabilities or are clear cases where LV would fall apart. He's advocating for everyone to use LV instead of regular views even to serve HTML for most sites.

I can see the appeal too, Turbolinks did a great thing a few years ago by improving page load speeds by turning regular HTTP requests into ajax calls behind the scenes and then swapping the <body> of the page, all without having to write a single line of code beyond importing the JS library and without having to change anything on the back-end.

With LV's live_redirect you can get a similar effect. It's a much different implementation (way more changes are needed on the back-end) but the end result is similar'ish.

And if you had a site that benefits from speedy page transitions (aka pretty much every site) and you happen to have a few cases where using LV makes sense such as wanting to do real time validations or show a stream of something then it would make sense to want to go all-in and use LV to serve every page so that you don't need to bring in both Turbolinks and LV as dependencies and still benefit by having fast page transitions across your site.


> If you wouldn't use React, you shouldn't use Live View.

I have bad news for you about how often most web developers are using React.


If the connectivity state doesn't matter to the user, why would you show it?


This. No reason to say "the server's gone!" when your user's not doing anything in which that matters. Do notify them _before_ trying to execute on a task that requires the server to be up, but that's not the case that was getting described.


> If the connectivity state doesn't matter to the user, why would you show it?

It's due to Live View triggering a visual indicator that the websocket connection isn't available.

It's a combination of CSS and JS. You can turn this off but if you turn it off then you have no way to show an indicator when you do care (such as transitioning between pages or submitting a form).

I don't think LV at the client level can be coded in such a way that it can tell the difference between the server dropping and the user's connection dropping due to their internet being spotty.


So just to your last point, no one can tell the difference between "you, the client, can no longer reach this particular server" and "this server no longer is up". You might be able to tell that it's the user's connection, rather than a netsplit somewhere, with some reasonable degree of confidence (ping the ISP, ping google, etc), but that's a lot of work, still just a percentage chance of being correct, for no real benefit.

To the rest...that's the point, it's just...CSS and JS. You can change it. You can show it or not, based on what the user is doing, or what view they have. Worst case, you can just hide it completely across everything, as you say, which is then no different from an SPA, except where functionality fails when you have no connectivity. Whether that leads to a better or worse user experience is dependent on the dev's handling of those failures.


> You also don't want to disable this visual warning because on slower devices it might take 2 seconds to load the page which is much different than an uncontrolled disconnect.

You can restrict the visual warning to the first load only, it would be pretty distracting otherwise.


> You can restrict the visual warning to the first load only, it would be pretty distracting otherwise.

How would this work in practice while still showing it when you want it to be shown?


If your server is done 20 times in 10 min, replace your incompetent eng, ops, service provider.

A feature that protects from ridiculously unlikely problem is no feature. It is over engineering


> If your server is done 20 times in 10 min, replace your incompetent eng, ops, service provider.

You could have incompetent engineers or you could have bad internet. The user could be on a train that is going in and out of tunnels. Or the user could be in a house using WiFi and the microwave could be causing interference.


"Replace the user". ;)


Not only that. The basic problem is latency. We moved logic to the client to be able to update the screen without incurring the latency hit of a server roundtrip. Latency isn’t going down, thanks to physics, so it is going to keep making sense to run logic locally to improve apparent performance. Granted, you need data to render something useful and if an SPA does a data fetch on every click, it might as well be rendered server-side, but still, it is going to keep making sense to render on the device in many cases.


Note that a websocket round trip is vastly shorter than an http round trip, though. If your payloads are small, 500 consecutive websocket back and forths take orders of magnitude less time than the "traditional" high level url post/fetch becauses there's none of the overhead of an http round trip.


A round trip is a round trip. Software can’t beat physics.

If you want to do requests in parallel, http 2 and 3 can do them just fine. If it’s sequential, you won’t see a huge difference between something on websockets and http/1.1.

The only thing you can save are a few header bytes. And it’s up to you how many headers you use


I'm not going to say web sockets are the silver bullet as I don't think it is, but the "only thing you can save are a few header bytes" is a bit reductionist.

If you have authentication then cookies have to be going out also and any other information that has to be kept in order to provide state over a stateless connection. You still need to handshake on each connection (maybe http2/3 bring this down a bit), and you also don't have bidirectional flow, so if you need something resembling client side "real-time" functionality you now have to implement pooling, or server side events.

The biggest issue is basically how to load balance/scale and that becomes a problem only given a scale that 98% (scientific) of the websites online won't ever experience.


> You still need to handshake on each connection

You can just use one connection (same as websockets)

> and you also don't have bidirectional flow

Sure you have. Each request and response has a body, and HTTP bodies are indefinite streams of data. You can do everything in them you like (including running your custom protocol). That's e.g. how gRPC streaming works.


Sure, but doesn't that end up being more complex than web sockets to implement correctly?

And keeping one connection then we're in the same spot regarding the scaling issues as with web sockets right? Or does plain TCP/IP have better support for changing endpoints mid-flight, reconnections and etc?

Although if so I don't understand why there was even the need to come up with Websockets? I personally would love to see a simplification of technology all across OSes, web, etc, but probably there's too much out there to provide a reasonable migration path... It sometimes feels like those projects that you work on in the beginning and then you look at, some years down the line and say, this needs a refactoring with all I've learned in the meanwhile regarding what I'm doing and regarding my understanding of the domain space - but sometimes you can't do it, doing it might not go well or you'll end up in the same place afterwards.


Why would software have to beat physics? HTTP communication and websocket communication uses completely different models.

And note that we're not talking about parallel request, those are not relevant to the "constant stream of small updates as the backend state updates" model described in the article, so let's not get side tracked, and talk about the actual stream of small fragment data in HTTP vs websockets.

Every HTTP connection (whether it's v1.1, v2, v3, or some even newer Google-flavoured "we came up with another one!" version) requires secure connection handshaking before any actual data may be sent. And if you're using any kind of session management, which you will be, now you're also spending time on cookie transmission before you get to payload transmission. And yes, there is the "Connection: Keep-Alive" header that can be set to allow more than one request per established connection, but any sane setup has that either on a small timeout (hundreds of ms at most), or on a low number of requests. You're still going to be establishing lots of connections, over and over, during the lifetime of the content at the client.

So, for many payloads a lengthy (compared to small payload transmission) HTTP connection negotiation has to happen. This is not the case for websockets, which by design are as if the "keep-alive" was set to "forever": they get initiated through a one-time HTTP call that contains an "upgrade this connection to a websocket" instruction header, after which we're done. This is now an open, persistent, bidirectional data socket.

Connection-wise, the amount of time required for HTTP vs. websocket is immense.

Secondly, let's not try to lend credence to an argument by hand waving the number of bytes in headers: the model discussed here concerns pushing small fragment updates to the client, in which headers constitute a significant part of the transmission. You can see this is modern sites that communicate small JSON fragments today where payloads like `{"error": false, "result": 12}` get dwarfed by the modern response headers, because yes "you control yoru headers" but you're not running your first server (in fact, you're almost certainly not running your own server at all, you paid a host): a response will contain not just the HTTP version and content type and length, but also the cache control value, the CSP and CORS headers, and almost certainly some extra stuff like the datetime, cookie expiration, x-frame-options, etc.

Using websockets makes an incredible difference in the model discussed in the article.

However, if you want to discuss the merits of the two completely different models, that's fair. Why would you even use the small-payloads push model? Who cares if the client has some state that "hopefully" mirrors the server? These are good questions, and unless you're writing a multi-user application with a web front-end, I genuinely don't see why the approach outlined in this article makes much sense.

Yeah, React kind of shat all over the web (and I say that as someone who quite likes React) because it was never designed with the purpose of generating web content. It was born as an interface library and never stopped being one. Its fault is being so damn easy to pick up which means that every site on the planet now uses React to build normal web pages and even do page routing, instead of having the devs write their code in React and then hitting the "and now generate that as static site with vanilla JS for the interactive bits" button. Because that button doesn't exist, instead it's esbuild (or previously, babel+webpack but thank god esbuild now exists so we don't have to use that anymore).

But that's a completely different discussion and really not related to how websockets are incredibly much better for the stateful server, thin client, many-small-updates push model.


I see websockets as the endpoint for trying to fix two problems in HTTP 1.0 that has been simmering for over two decades.

For all of the stateless goodness that HTTP is, in order to have user-specific content, you need to know who you're talking to. The hack to fix this was cookies. Instead of using a traditional stateful protocol (which could have kept track of the logged in user), we had a stateless protocol where the user basically had to present credentials with each request (also, HTTP-AUTH).

The second issue was so problematic that it made it into HTTP 1.1 two years later. Because a stateless protocol was used, if you wanted to download say, a document and a linked image in the document, in HTTP 1.0, you needed to make two requests. Back when each web page was predominantly text with few graphics, this was okay. When we moved to more graphical (albeit table-based) layouts, this was horrible. So, HTTP 1.1 ushered in Connection: keep-alive to allow for the same connection to be used for multiple requests. You still had to make individual requests, but at least you didn't have the overhead of setting up multiple TCP connections.

HTTP isn't fundamentally broken, but it is a kludge. The most painful parts of HTTP were also the most "stateless" aspects. I agree I don't understand why HTML over Websockets is a (big) thing. It doesn't make much sense to me either. Then again, I was also doing dynamic updates (with javascript pulling in HTML, not XML) before A List Apart (hello again) coined the term AJAX.

But let's not just say that HTTP is a perfect stateless protocol. It isn't. It was never "designed this way" -- it was patched up with quick fixes during the late 90's that we've been stuck with ever since. Websockets is the latest attempt to fix this problem. HTTP/2 and /3 don't really do anything to address maintaining session state, but focus on making individual request more efficient (roughly). That still leaves us with the problem of Cookies. Websockets have their own issues (scaling for one), but adopting the approach mentioned in the article doesn't mean that you have to completely abandon the rest of HTTP. But, if I could avoid having every website yelling at me about using cookies, I'd happily adopt a Websocket architecture, if that's what it took.


Why isn't an identifier included in each request ("a cookie") not a valid way to track state across requests? It's the solution that makes sense with an otherwise stateless interaction. With a persistent connection, you don't need to send that with each interaction, but the RIP:RPORT:LIP:LPORT tuple becomes the "cookie" that identifies the client or session.

> That still leaves us with the problem of Cookies. ... But, if I could avoid having every website yelling at me about using cookies, I'd happily adopt a Websocket architecture, if that's what it took.

This is a red herring. If "the problem with cookies" is that websites yell at you about using cookies, that's a legal issue with the requirement to notify users they are being tracked. This "problem" of being yelled at didn't exist before the legal requirement.

Moving the transport to websockets (layered on top of HTTP, layered on top of TCP) doesn't get rid of the legal requirement for notification or opt-out. It just buys some time until the law catches up and says that the state management you're using with websockets is also subject to tracking notification and opt-out.


> This is a red herring. ... that's a legal issue with the requirement to notify users they are being tracked

It’s not a red herring. And it’s not the website warnings that are the issue, it’s the tracking that they have to notify you about. If we didn’t have to allow cookies for basic interactions with websites (like a session cookie), then we wouldn’t need to allow tracking cookies at all. However, because we need to allow session cookies, other sites can then track us.

With a persistent connection/session, this wouldn’t be necessary.

But clearly, there are many other ways to tackle this problem. And the persistent socket connection also has issues. But after thinking about this, I think the company behind the current dominant browser may be a little conflicted about solving this issue. I’m hopeful about Firefox’s new approach.


This is an aside, but to my mind, when necessary (when you're storing user data) devs should be transparent about how that data is stored. Websockets won't necessarily mean you avoid persisting state on the browser.

In fact, you'll probably find you'll need to store some tokens on the client, somehow, just to secure the client/server connection.


Do you have any preferences regarding a direction to simplify web development, remove some of the complexity introduced with client-server separation?


Use as little tech as you can. Write HTML, CSS and if you absolutely have to, javascript.


it's difficult to keep up with the design expectations of the modern web with just HTML and CSS.

It's possible but extremely difficult to create a "modern" experience with just html. Just like how we don't build houses with mud-bricks anymore even though it's easier than steel and wood.


On the contrary, I generally browse with JS disabled and there's a strong correlation between sites for which this is existentially problematic and sites whose content or utility are garbage.

I have a personal toolkit of components I call "you might not need Javascript". Dropdowns, slideovers, toggles, modals, tabs, accordions, autocomplete, lightboxes, all with nice transition animations, and all in pure server-rendered HTML+CSS. A lot of it is just semantic elements being used appropriately. How many developers use <datalist> or <summary>/<details>? or :target and :focus-within? In my experience, not enough. How about, using <details> in combination with a CSS [open] selector? The palette gets rich in combination.

Overall, no, it's not hard, but it does require one to study. A couple of times a year, I'll re-read through the HTML LS and CSS specifications. There's a lot in there to build from, and almost all of it has broad evergreen browser support. For the leading-edge stuff, "caniuse.com" remains an essential reference. I currently have my eye on the <dialog> element, high expectations there, works well already in Chrome; Firefox just has a couple of bugs to shake out, and it's experimental (but incomplete) in Safari.

All that said: a light dusting of JS can still provide progressive enhancement, but we can limit this to minor cosmetic improvements & optimizations, for browser compatibility, and where dynamic ARIA markup is necessary.

The motivation as to why I prefer this style is another matter, and it's do with product strategy, and in particular, not crystallizing your architecture in the front end (where it is brittle) but in the backend (where it is much faster to pivot and/or rapidly prototype/spike/redevelop, by proximity to business logic and persistence schema). These are understandings that've been long (and sometimes painful) in the learning, but they're pretty much universal.


Survey monkey is completely broken without js. I did a survey this afternoon on it. Considering it looks like a few radio buttons and simple forms.. I just don’t understand.


> A couple of times a year, I'll re-read through the HTML LS and CSS specifications.

What is HTML LS?


The HTML Living Standard https://html.spec.whatwg.org/multipage/


How so? One of the most popular (if not the most) websites for developers out there is pretty much HTML + CSS. JavaScript is used, but minimally.

"Modern" experience is not necessarily the same as "good" experience. Good old server side rendered pages are fine; SPAs are being built just because "we can", not because they are actually needed (sure, in some cases,SPAs are needed, e.g., chat sites).


Are you talking about Reddit, StackOverflow, or something else?

I have yet to see a proper web app (not a blog/collection of static pages, but something that does something complex like let you manage inventory, do payroll, do your taxes, monitor sensors in real time, interact with geographical maps, or edit documents) that is done without JavaScript and has even OK UX.

SPAs are great because of separation of concerns. Sever takes care of the data (storing it, syncing it, authenticating your access to it, serving it, sharing it). Client takes care of presentation. I build SPAs because they are better. Imagine if all the apps on your phone or computer were effectively HTML documents rendered on the server. Emacs over HTML/CSS? Minesweeper? World of Warcraft? Would that be an OK experience? Probably not because you don’t want to wait for a page load every time you do something in your Minesweeper game or check stock prices or whatever. Why should web apps be inferior?

When people complain about SPAs it’s because they don’t like web apps running in the same environment as their document-based content. I guess some people prefer the ActiveX/JavaApplet model, which to a degree I can understand. Slack is an application, not a website. But let’s not overlook the fact that implementing a Slack client with just HTML and CSS would be miserable to do and miserable to use.


> Why should web apps be inferior?

Inferior compared to what?

I'm not going to call your statement nonsense but unless you have proof that SPAs make up the majority of the websites/web apps online today, I'm afraid I must disagree.

Frontend dev is a hot mess of garbage JS cobbled together to make a psuedo native experience.

> but something that does something complex like let you manage inventory, do payroll, do your taxes, monitor sensors in real time, interact with geographical maps, or edit documents) that is done without JavaScript and has even OK UX.

This is not what the web was built for. The same things you mention dismissively (server side Static pages) are the core and norm ,by and large, the vast majority of what constitutes "the web"

Good, lightweight native apps can do all the above without breaking a sweat, and you can have multiple native clients for things you care about. I don't always have an internet connection but I still want to type my documents. I fire up word. Not google docs. I need to do some serious data wrangling - I fire up excel not google sheets. Need to do some networking for my router, wireshark. Need to read an ebook - adobe acrobat. Need to write some shader code - Sublime text.

So the way it looks to me that SPAs are trinkets - not at all mission critical beyond loading cat pictures faster or bending the web backwards to do things it wasn't supposed to. Server side static pages rule the web.

Complexity is just a good way to justify a large paycheck.


I’ll give you two counter arguments and if they don’t work I think our best bet is to agree to disagree. First, I think your premise that apps are not what the web was built for is flawed. Sure, this isn’t what the web was built for, same as the Internet wasn’t built for the web, and the phone and cable lines were built for the internet, and so on. The web had a vision that changed mid way. No we can either try to go backwards and give up a really important feature (forthcoming) or we can move forward and push past what is essentially a tooling problem. In other words, just because in the 1980s web apps could not be envisioned does not mean that they shouldn’t be envisioned today.

The second argument is that there isn’t a technology today that supersedes the web in one crucial feature: no installation required and updates are transparent. Various app stores are trying to solve this in a platform specific way but do you really want to live in a world where to publish an app you must include Apple and Google and Microsoft in your deploy path? You and I may be able to go to GitHub and download OpenStreetMaps code, then download all the data, install it all locally (most of the documentation last I checked was still in German BTW), and then use it to find directions to the nearest Starbucks. An average user will give up before spelling out “GitHub”. If you can point at any platform that lets me type in the name of an application and stat using it in under 1 second without installing anything whatsoever on my system, I will eat my hat.

That isn’t to say that we can’t have nice things. With time and effort you can create such a platform and get all OS vendors to support it and all the developers to move to it. But I will postulate that fixing the JS frontend mess will take at least an order of magnitude less effort. Therefore the web is where these types of applications will live.

Again I am not talking about things that are static. This isn’t about a blog. This is about whether a real application is better server-rendered or as an SPA and I argue that in 99% of cases an SPA will be a cleaner architecture AND provide better experience to the user. The fact that coding one up is annoying (arguable at best) is a temporary tooling problem, not a fundamental design flaw.


I'll use an analogy. We web developers are building a boat using a 1992 Toyota Hilux as the hull.

Top Gear proved it was well and truly possible. It's a popular mode of transport. It carries things. It has an engine and a mostly metal body.

It still isn't quite a boat

Web apps can walk and talk like native apps, but they aren't. Sure one off things like a Facebook or spotify or meme generators can rightfully be served from a web app - but applications for computing and getting work done?

Oh and don't forget about mobile devices - what amount of web apps do you prostulate people use there?

> SPA will be a cleaner architecture AND provide better experience to the user.

This. This is nonsense.


I won’t debate your analogy because I think it is flawed for reasons such as you can’t change the fundamental definitions of a car as easily as we can change web standards, as we have done over the past 30+ years.

I will point out that I routinely use Reddit on mobile Safari and it is most certainly a web app. Things like Twitter, Facebook, etc. are also apps, and while you can download a native version, for privacy reasons I prefer their web app counterparts as they are less able to spy on what the rest of my phone is doing.

I will also again point out that Google Maps is a better experience than downloading OpenStreetMaps and setting it up yourself. Even something like Slack and Discord and Google Docs are perfectly good experiences on desktop browsers and require no installation whatsoever. You aren’t really addressing the zero installation point at all and that’s at the crux of why web apps are a thing and their main draw. You quoted my conclusion and called it nonsense without any basis since you provided a straw man argument and didn’t address the main point at all.


When people complain about SPAs it's because they're slower or less fit for the task than a collection of mostly static pages.


You can build a poor UX with either technology. That does not to me condemn the technology itself. If a technology makes it easy to create a bad UX that may be grounds for condemning it. I have written horrible SPA code in my early career using nothing but straight up jQuery and yeah that can lead to bad UX. I like the way Vue does things and liked the way Angular 1 worked pretty OK. I don’t love React but don’t have anything against it. None of these inherently lead to a bad UX, IMO.


Not sure what is so hard about a client/server roundtrip?

The server side is being broken up into micro-services which makes all server a client/server roundtrip as well. Your DB was always running seperately making it a client/server roundtrip, etc.

Maybe I'm missing something, but what aspect of client/server is overly complex? And why is websocket (a client/server roundtrip mechanism) any easier?


>The server side is being broken up into micro-services which makes all server a client/server roundtrip as well. Your DB was always running seperately making it a client/server roundtrip, etc.

The backend is likely all in the same building with a reliable and high-bandwith link between servers.

You can't compare that to a round-trip from the client to the backend.


VueJS SPA + simple REST API will get you a really nice experience for most CRUD type apps. For the backend I like Django.


PHP has its uses. Stateless request/response model with shared nothing can act as a kind of immutability. Facebook scaled for the first couple of years with just PHP 4 functions, arrays and templated HTML. The Ajax came later.


You sound like someone that gets it and after reading further it appears you have built an app in this space, and this makes sense. I have too and your right, the coolness of the realtime web is also it's achilles heel. It's not that the web wouldn't be better off realtime, it's just that there is unlikely to be in most cases a time when more than one person if any at all will consume a shared resource. And now you have to account for the most sensible case being the static state of the app where you are over-engineering the realtime features that are not really going to be used that often. In my app I had a a channel state (realtime) and a snapshot state (static). Only thing that made sense in the end was the static snapshot state for content consumption.

Here is a short demo of the product: https://www.youtube.com/watch?v=TwkgGBrK_tA


All connections are stateful the moment any kind of volatile data is added. The question is how to manage that state.

Say you have a doctor that is associated to a group of patients and is allowed to update their patient's status. And if, while the doctor is filling something out for that patient, the patient changes doctors, then the current operation has to fail and the doctor needs to be notified of this change somehow.

So what do you do with the stale list of patients in the browser DOM?

Does the UI wait to see if the write fails, or does it increase reactivity by supporting a server push? And how do you tell the DOM to update the list of menu items so that that Patient X is removed from that list? What if half the doctor's patients have been removed? Does the UI wait for the doctor to try to make some change to all of them and one by one remove a patient or does it reload the full patient list? And if so, how often does the browser poll for the full the patient list -- during every operation involving a patient?

The server push reduces the amount of time wasted by the doctor filling out stuff for a patient that will be refused by the server anyway, and it avoids costly polling, reducing bandwidth. I get that it may not be worth it, it depends on how important reactivity and bandwidth are to the app, which is why videogame makers need to do it but people writing marketing pages don't.

Either way, you have a stateful connection as the set of patients available to that doctor is important connection state that can change at any time. So you are long past the idea of REST whenever you start building an interactive UI with data that must be synced from a remote server.

I am not a fan of the server push, but I feel that ship has sailed and people are adding in a lot more complexity for the sake of improved reactivity. My personal rule of thumb would be to always sacrifice reactivity for simplicity, but then this is why I don't build marketing pages.


> So what do you do with the stale list of patients in the browser DOM?

Write the front end in something like Vue. When you catch an error from an axios call, update your data model by calling the server for updates.

When the data model updates, Vue will automagically update the DOM used by the browser.


Right, but you can see how in some use cases it's important for the data to be relatively fresh, then you have to choose between polling and server push.


I agree that the good ole stateless HTTP protocol is great, but the thing is, as soon as your web page is simultaneously displaying content from two separate HTTP requests, your web page itself is maintaining state. That's very evident on complex single-page applications like an email, chat, or calendar app, but it's also true even if you load static HTML from a server then have a bit of client-side JavaScript that checks authentication status and shows the visitor's profile picture in the top bar if they're logged in. That's a pretty basic technique that web developers have been doing for probably 20 years, yet it already requires tooling and/or developer thought to manage what is now a stateful computing session.


>The problem is that stateful connections suck and create artificial complexity when you don’t need them. Instead of managing the state of your app you’re now managing the state of your app and a connection to a remote server. HTTP is a stateless protocol on top of a stateful socket connection. It wasn’t designed this way by accident.

Then again, it wasn't designed this way to build applications with, either. It was designed to serve documents (the HT in HTTP).


I built a localhost web app, where the app runs locally and displays its UI in one or more browser tabs. [1]

It uses websockets & JSON to connect the SPA UI (in Vue.js) to the app (in Go). That works well, and I can't imagine any advantages to generating HTML with Go, except perhaps less JS code :-)

[1] https://github.com/networkimprov/mnm-hammer


You're not being a jerk, but you are applying wisdom. The challenge is that if we don't have the courage to be foolish, then we will not make progress.

All the problems with a stateful connection are solvable, but we have yet to figure out the right way to teach the discipline of doing it right. It is an exceptionally expensive proposition to solve, so most people shouldn't solve it as they will be picking up a huge bill.

The challenge is that HTTP is fundamentally broken for stateful experiences, and people are trying to build that into everything these days. They want shit to update across machines, and polling is exceptionally easy at great cost.


Genuine question: is this what Microsoft blazor is?


Blazor has two modes, one is based on client-server round trips to talk with managed code on the server, the other runs everything on the client using WebAssembly


Anybody remember GWT? [1]

Let's not go there again. It's the definition of worse than flash. And mostly for above described reasons.

Networking, Animation, Transitions, APIs, State of Data, State of Synchronization, Unpredictability and Unreliability of UI/UX States... all mixed together in a single socket.

Have fun debugging this blob of autogenerated code and transactions.

[1] www.gwtproject.org


This seems like a more complicated SPFjs over websockets that is deeply wedded to a particular Ruby framework.

http://youtube.github.io/spfjs/


Except Phoenix LiveView has essentially removed the complexity.

Normally I’d agree with your take entirely and I don’t actually think it’s possible to avoid the complexity issues in non-BEAM languages...but Phoenix is absolutely doing it.


Also I've seen request/reponse over websockets too many times.


Just sayin' ... this time around ... a) the universe of gamers is larger and b) there's a larger base of phones which can be thought of as thin clients versus a full PC and c) node.js is widespread with Deno upcoming and d) multiplayer VR is closer to reality if it only need to compute one state at the server?

Multiplayer online experiences are also growing to include more than gaming, such as betting and gambling and zoom and trading crypto.

Are websockets and or browsers improving to handle this server centric shift?


> HTTP is a stateless protocol on top of a stateful socket connection. It wasn’t designed this way by accident.

The complexity benefit of having stateless HTTP transactions is vastly offset by the statefulness of TCP, TLS states, HTTP "sessions", cookies, browser storage & so on.

HTTP is hardly "designed" and plenty of its aspects were accidental.


the power drain alone, especially for mobile devices, makes this unrealistic


We are heavy into REST and HATEOAS. This, coupled with React SPAs has worked really well for us.

The HATEOAS client we use/build has an cache/event system that will emit to subscribers (via react hooks) when a resource is stale, and needs to be refreshed.

After putting this all in place, I realized that now I just need the server to emit those 'stale' events via Websockets, and suddenly my SPA + API is a real-time multi user system with nearly no changes required in either server or client.

This made me wonder, why aren't we just always pushing the entire resource state over websockets. Use websockets to let clients indicate which resources they are interested in, and let the server keep pushing state back to the client.

This solves a number of problems that plain HTTP has:

1. We can't really push/subscribe well. It's not very natural.

2. The HTTP cache kinda sucks, because we don't have programmatic access. Simple example: Doing a DELETE on a resource should expire the cache of the parent collection. There's a good HTTP header to indicate this, but no good way to tell the browser cache to delete the cache entry, so we end up building our own caching layer.

3. Compound requests suck because HTTP caches and clients don't understand them.

But we can still keep using REST fundamentals. Things have URIs, features are discoverable, relationships are expressed with links.

Something about this also feels terribly wrong though. Do we really want to reinvent parts of HTTP over websockets? HTTP is highly optimized, what kind of performance problems are we gonna run into?


Was your use of REST/HATEOAS mostly internal to your company or dev team?

I ask because I rolled out a REST/HATEOAS api for a multi-org project and got zero uptake on the HATEOAS aspect of responses. The devs hardcoded URL resource links and totally ignored any links in responses . . .

After that experience, I am always interested to hear about more successful REST/HATEOAS projects.


> This made me wonder, why aren't we just always pushing the entire resource state over websockets.

Because this won't respect HTTP caching and you'll end up sending way more data than you need. Best instead to just send up URI and `GET/DELETE` verbs to indicate intent. I wrote about this: https://github.com/krainboltgreene/pubway.js#pubway

Actually every HTTP benefit is a reason why you wouldn't want to send resources over websocket. What if the websocket connection is slower than changes to the resource? Instead of simply telling the client what to fetch, you just gave them stale data.


Coming from a game networking side, why wouldn't you want to embrace a WebSockets world for everything? The upsides seem so incredibly intuitive for someone looking at it from the outside of traditional web development.


Traditional SQL databases aren't very streaming-friendly, so you more or less end up building an entire secondary push system just to figure out when to send what updates to who.


Mostly just the intuitiveness of the architecture. I don't need bi-directional if I'm mostly just showing you some forms in a CRUD app, and client-initiated request/response is simpler to reason about.

Bi-directional gives you more power, but you also have to think harder about the protocol and application state once the server is also pushing events to the client unprompted.


Scaling is almost always the answer.


Scaling not just technically either, it's also the engineers. Most Web engineers have had their minds bent to the request response model with databases.

The key reason is that a game lasts... minutes to hours (ignoring most MMOs), so the state machine makes sense and the risk of failure low. Web devs have to use a database which has state for years.


Plus most games are awful at handling connection issues, you'll be dropped from the game and have to reload the entire map and assets again, often taking 30 seconds or more to rejoin.

I'm not sure we should be taking advice about how to load information on mobile devices with spotty connections from the gaming industry.


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

Search: