Comment by jacobgold
17 hours ago
These kinds of local-first syncing web apps are really interesting and can be really useful, but I think the premise is somewhat wrong.
"A few milliseconds is all it takes to update an issue in Linear. A traditional CRUD app doing the same thing takes about 300ms."
"Any data sent between the client and server costs hundreds of milliseconds."
There’s no solving the problem of a large RTT between an HTTP client and server when it’s due to the speed of light.
But what you can do is locate the backend near users and make sure it’s fast.
For example, it’s very possible to run a web app backend within ~10ms RTT of most users and have the backend render responses within ~10ms too.
In other words, you can absolutely create a traditional CRUD app where doing the same thing takes more like 30ms, not 300ms.
Thank you. Was beginning to feel like I was taking crazy pills seeing people claim that 300ms is fast when 30ms has been the target TTFB for as long as I can remember. Maybe Linear takes more time on the backend for totally valid reasons and it needs some help from the frontend, but that's not generalizable, and every bit of JS comes with its own costs.
When I started in this business, "sub-second" responses were the goal.
> it’s very possible to run a web app backend within ~10ms RTT of most users
Only if your users are all located quite close to each other, or (sadly very common) you only care about making it fast for US users and screw everyone else.
(Of course you can have "intermediary backends" around the world on a CDN's edge network or similar, but at that point you're paying the same complexity cost as this style of putting the "intermediary backend" on the client)
10 years ago, I was headlining a project where we had strict performance requirements (ssr, php mind you) - the target for any operation except login was 30ms, and any endpoint taking more than 60ms in one of the devs server would have to have explicit approval. Add the nework RTT if you dont want to have a local backend, and for most geographies is still well under 300ms. Fun fact, we actually designed a system that could be easily replicated between regions and/or perform internal routing, leveraging the operator network. 3 AWS regions would make the RTT of a request well within <100ms on average for >80% of the world population. Requests were mostly "instant" - the big trick that did it (at the time) as to avoid reflow in the browser. Funny how the spotlight is now on doing stuff that "solves" that problem with the technology that was designed to solve that problem.
> Only if your users are all located quite close to each other, or (sadly very common) you only care about making it fast for US users and screw everyone else.
Very true, mostly because it's pricey to do so--or more specifically, putting a server in DCA is $.005/user, putting a server in JNB is like $.50/user sooooo....
Sometimes this is a "so what", other times it has huge implications for app architecture.
You don't even need your backend that close if your server is fast enough. Streaming HTML immediate mode is pretty good. See this demo (server is in Germany and runs on a potato uses no optimistic updates, eveb scroll round trips) [1]
Honestly client side animations go a long way to masking latency too.
- [1] https://checkboxes.andersmurphy.com/
> it’s very possible to run a web app backend within ~10ms RTT of most users and have the backend render responses within ~10ms too.
What are you talking about? The only AWS region < 10ms away from us-east-1 is, err, us-east-2:
https://www.cloudping.co/
us-west-1 is 60ms away. eu-centra-1 is 100ms away. asia is 200ms away.
and this is datacenter-to-datacenter traffic. Actual latency over the public internet to residential providers is far worse.
Your database needs to be in exactly one region. So no matter where you put it, the majority of uses on earth are going to be > 100ms away from it.
It doesn't matter where the endpoints are, because the endpoints need to talk to the database to read and write data. Thinking you can replicate some data closer to the users? Congrats you are now the proud owner of a "local-first syncing" database. This replicated database you use (either of your own design or off the shelf) will have all the same problems of client-side syncing. Except you'll still have significant network latency.
There is no getting around physics. You either have quarter-second commits for most users or eventual consistency (aka syncing). Those are the options.
you can home tenants in a data center close to them, run a copy of your app in each region including the datastore. keep a central db for accounts, billing, etc but user content is easy enough to shard regionally.
taken to extreme, cloudflare durable objects & workers let you place data very close to a tenant automatically; but you lose total write throughput on top of sqlite.
This breaks down when someone goes on holiday to Greece for a week, and the RTT over the airbnb wifi is 5 seconds.
Optimistic updates on the frontend are probably simpler too.
But this is kind of meaningless unless the tenants themselves are in one geo. Take linear as an example, this strategy works as long as your company that uses linear is all colocated in one area. As soon as you have remote people it falls apart.
2 replies →
You can locate an "intermediary backend" on the client, write outstanding mutations into local storage, have a background worker send it to the backend, with necessary retries, etc. At worst, the background worker would put out a message about a failed update which the UI tread would receive and show.
But the happy path stays lightning-fast.
Sure but there's a ton of complexity in any kind of local-first syncing solution. Often the solution is CRDTs.
My point above is that the simple solution ("traditional CRUD app") is actually viable even when the goal is very low latency.
100% agree. A traditional CRUD app (like Linear) can be made pretty low latency without local-first. The complexity is not worth it.
2 replies →
Can you do this where you need to have a database shared between all these edge backends?
If your service shares state globally across all users (like a social network) not really. If individual customers are mostly centered around one geographic location and their data isn't shared with other customers, yes.
Even social networks tend to shard their DBs geographically. It's obviously not 100% effective (I can always add a friend on the other side of the world), but it significantly improves the average case (the majority of my friends will have gone to school/university/worked in the same geographical locations I did)