| ▲ | syspec 7 hours ago |
| Whole blog post is basically: Make a mutation in the clientside, assume it worked, and save in the background. |
|
| ▲ | mohsen1 7 hours ago | parent | next [-] |
| Works for Linear because the tab stays open, and worse case if tab is closed you can recover later when the tab is opened again and deal with conflict resolution. Won't work if: 1. user clicks a button and closes the tab thinking transaction is done and it's important that transaction is done 2. conflict resolution is difficult or impossible in future client wake up |
| |
| ▲ | nine_k 6 hours ago | parent | next [-] | | The user clicks the button, the mutation is stored in local storage. The user closes the tab, but it's not a problem. A background worker picks up the mutation and sends it to the remote backend. It takes time, retries, etc. Similarly, any errors reported by the background worker go to local store, and the next time the UI tab is loaded / activated, they are shown. A service worker can show a notification outright to let the user easily load the main UI. Normally this would be a rare occasion. | | |
| ▲ | blauditore 4 hours ago | parent | next [-] | | 1. What if the browser gets closed/killed?
2. Error messages around syncing issues are notoriously worse than those of a sync request to the backend that failed. So the UX in the end is worse. More generally: You can't circument the trade-offs of a distributed database, which such products are, conceptually. | |
| ▲ | ifwinterco 6 hours ago | parent | prev [-] | | Yeah this pattern can be made to work fine. Main downside is it significantly complicates the front end code compared to just waiting for FE to sync with BE before updating | | |
| ▲ | galaxyLogic 5 hours ago | parent [-] | | What if we had a local server running on the same PC, which then relays the request to some shared server on the internet? | | |
| ▲ | cwillu 4 hours ago | parent [-] | | That's what a background worker is: a local server managed by the browser and only accessible to pages of the origin domain. |
|
|
| |
| ▲ | pyrolistical 5 hours ago | parent | prev | next [-] | | Expose the sync queue to end user and train them to understand if they attempt to close the tab with a pending queue they will get the ugly prompt warning them | |
| ▲ | dbbk 6 hours ago | parent | prev | next [-] | | Still works if you use beacon requests, they survive tab close | | |
| ▲ | anotherevan 4 hours ago | parent [-] | | Bear in mind that beacon is something of a hail Mary, though. No way to tell if it was successful or not or react if it wasn't. |
| |
| ▲ | Onavo 6 hours ago | parent | prev [-] | | Yes and for linear (if you break it down strictly in a theoretical CS sense, is roughly equivalent to TodoMVC in terms of application complexity assuming non-collaborative text editing) they have clearly defined states for most items and few if none truly destructive actions. The hardest part is anything text related. |
|
|
| ▲ | NewsaHackO 7 hours ago | parent | prev | next [-] |
| I agree. To each their own, but the UI updating automatically doesn't really add much value to me. I would prefer that the view I am seeing is a snapshot in time of what the ground truth server was, not some mixed state that forces me to consider the possibility that seeing my request go through on the screen doesn't actually mean it went through and has been sent to the server. |
| |
| ▲ | inezk 6 hours ago | parent [-] | | The goal is - and I think they have achieved it - is that you don't have to think about it. They handle sync, and they do it reliably. | | |
| ▲ | SoftTalker 5 hours ago | parent [-] | | Then they have solved one of the fundamental hard things in computer science. |
|
|
|
| ▲ | aboodman 2 hours ago | parent | prev | next [-] |
| Well that "make a mutation client-side" phrase is doing a lot of work. Make a mutation to what? The classic server rendered web-app doesn't have any data to make a mutation to. You could try to patch the UI but that would be a huge pita and not really a scalable (in effort) solution. If you have an SPA, you still don't really have data on the client-side. You have a bunch of cached query responses. You can update those, but (a) it will be a pita to do correctly, (b) you'll have to do it to every possibly affected query, and (c) you have to remember to undo it at the right time (way more subtle than it appears - think it through!). A sync engine creates the client-side normalized datastore that allows you to "do a mutation client side". In fact, you're kind of right that once you have a sync engine, just doing a mutation is really easy. The real challenge is all the infra required to enable you to do so. |
|
| ▲ | Aeolun 4 hours ago | parent | prev | next [-] |
| I think whole generations are constantly discovering that the client is really, really fast. |
|
| ▲ | willsmith72 2 hours ago | parent | prev | next [-] |
| so.. optimistic ui? like upvotes on hacker news since forever? |
|
| ▲ | prerok 7 hours ago | parent | prev | next [-] |
| Indeed. I have to say, I hate this. Suppose you are in a meeting, you update something and you see the result, but the rest of the team does not. Ok, a couple of hundred ms does not play into this but if the update does not make it through? And yes, it happens. |
| |
| ▲ | artman 7 hours ago | parent [-] | | Changes go through and synced to everyone on your team in almost realtime. If there's a conflict on the server and your change cannot be applied (almost never happens), your change is rolled back on your client, again, almost in realtime. If servers cannot be reached, we will show you a syncing badge within 4 seconds to tell you that you have made changes that haven't been sent to others yet. Strange that we can be so be polar opposites on this. You hate it, I would never write an app in any other way, ever again. | | |
| ▲ | n_e 6 hours ago | parent | next [-] | | As a user, I like when things appear to sync instantly and perfectly, such as in Google Docs. As a developer, I hated the article and many of the comments I read thus far because: - Having clients and a server properly sync and not lose data in the event of a network failure amounts to having a consistent distributed system which is not easy to do, and the commenters don't seem to have understood that - I hate having written a long document and then losing it because the sync code is buggy, so the previous point becomes even more important. So reading many of the things here has been mildly infuriating. That being said, none of these people are likely affiliated with Linear, and given the overall quality of the product I'm pretty sure it works properly. | | |
| ▲ | ifwinterco 6 hours ago | parent [-] | | In the case of a partition the client nodes get temporarily out of sync but the system will then synchronise to one state again once the partition is resolved if it’s written correctly. So no violation of CAP theorem it just prioritises liveness over consistency | | |
| |
| ▲ | porridgeraisin 6 hours ago | parent | prev [-] | | (curious) What if a user closes it before 4 seconds? Ctrl+enter, it optimistically locally updates within 1 second. I close ctrl+w. But my wifi goofed and it didn't reach the server. | | |
| ▲ | singron 6 hours ago | parent | next [-] | | I have mysteriously lost comments/descriptions I wrote on issues. I figured it was related to a failed and lost opportunistic update like this, although I suppose it could have been caused by a fixable bug. | |
| ▲ | artman 6 hours ago | parent | prev [-] | | The HTTP request is fired off instantly, so chances are that the request is already written to the socket and closing the page won't cancel the request. Should your wifi-router drop it, your client will retain the transaction on disk and retry it the next time you come online. | | |
| ▲ | porridgeraisin 5 hours ago | parent | next [-] | | > next time you come online Yeah that's the issue isn't it?
I see in the UI it's sent. But actually it's sent only the next morning. To be fair. It's fine for an issue tracker. Anything actually important i'd spend a few seconds going over what I just sent. In which case I'd see it's not synced. And what's not that important it's really fine if in some random wifi edge case it's phantom sent. So makes sense. | |
| ▲ | cwillu 4 hours ago | parent | prev [-] | | That's really gross behaviour; users like it because they don't understand it and don't know to blame it for their issues when weird things happen to them, and weird things to them all the time. ‹giant argument breaks out before people realize a bunch of messages went missing and were posted out of order› “Oh, it's just ‹app› being weird again. I really hate that.” |
|
|
|
|
|
| ▲ | girvo 4 hours ago | parent | prev | next [-] |
| AKA what Relay does out of the box haha Though its depressing how few actually use it to its full extent. My team is one of the few where I work; heavy declarative mutation directives with optimisticResponse (and optimisticUpdaters because some of our APIs are not very Relay-compatible, annoyingly) |
| |
| ▲ | cheema33 3 hours ago | parent [-] | | > AKA what Relay does out of the box haha... Relay does optimistic updates well. However, frustratingly, Relay does not do any persistent caching to disk, like Linear does. This means, first page load will always have to fetch data from the server. | | |
| ▲ | girvo 3 hours ago | parent [-] | | I think that’s an acceptable trade off, personally… but! You can implement persistent caching if you’d like :) you create the record store when you stand up the environment, so it’s possible to have that hydrated with data from somewhere else But I’ve only done that in toy examples not prod, I’m sure there’s something I’m missing haha |
|
|
|
| ▲ | pier25 7 hours ago | parent | prev | next [-] |
| For native apps this is less of an issue since they have access to persistent storage but with browsers there's no guaranteed persistence. |
| |
| ▲ | WhyNotHugo 7 hours ago | parent [-] | | There's guaranteed persistence, but there's no guarantee that the host will be up anytime soon. E.g.: I might leave a final reply with all the details on an issue before going on vacation (or maybe I don't work the next day but my colleagues abroad do!). I see that it's properly posted and close the laptop. The reply with be delayed by days or weeks, but the UI indicated that it had been properly saved. | | |
| ▲ | pier25 7 hours ago | parent [-] | | > There's guaranteed persistence There's not. Browsers can delete "persistent" storage at any time. https://developer.mozilla.org/en-US/docs/Web/API/Storage_API... | | |
| ▲ | 12_throw_away 6 hours ago | parent | next [-] | | It depends. From the link: > If, for any reason, developers need persistent storage [...] they can do so by using the navigator.storage.persist() method of the Storage API. This makes a request for guaranteed permanent storage ... which can be approved (or denied) by the user or by browser defaults. | |
| ▲ | ifwinterco 6 hours ago | parent | prev [-] | | Edge case but playing devil’s advocate: a user can also uninstall the native app at any time, and might still expect their last change before they closed the app to be reflected in the web version. You can never truly trust anything about a client because by definition you don’t control it | | |
| ▲ | killingtime74 6 hours ago | parent [-] | | But the os can't uninstall the native app at any time unprompted right | | |
| ▲ | aforwardslash 4 hours ago | parent | next [-] | | Corner case: actually, it can. Also, thats how auto-updating works ; depending on local state as a source of truth using browser apis is a terrible idea IMO. The whole concept of "assume it is committed while we sync in the background" is, in the most cases, a terrible architectural decision, unless it is coupled with explicit feedback (eg. A small visual indicator indicating if the background queue is empty or syncing). Also, it breaks temporality: last-update-wins no longer holds, because update time and sync time are decoupled. And you also create a new problem, which is local cache coherence. It may be a good fit for some systems (though I cannot think of a single one), but in general is just a horrible solution. | |
| ▲ | ifwinterco 6 hours ago | parent | prev [-] | | No, it’s definitely a lot less likely and probably an edge case you can ignore in practice |
|
|
|
|
|
|
| ▲ | sneak 6 hours ago | parent | prev [-] |
| I believe this is called “eventual consistency”. |
| |
| ▲ | amelius 6 hours ago | parent [-] | | No, because if a transaction fails it still needs to be handled by the user in many cases. E.g. if you buy a book, but it turns out the book was already sold, then you will first get a message "Your book is on its way!" and then "Oops, sorry, the book was already sold to someone else". Eventual consistency is just a property of the database. |
|