[HN Gopher] The building blocks of offline support
___________________________________________________________________
The building blocks of offline support
Author : pketh
Score : 68 points
Date : 2024-01-22 18:00 UTC (1 days ago)
(HTM) web link (pketh.org)
(TXT) w3m dump (pketh.org)
| tmikaeld wrote:
| This is really impressive and I like the app, it's fast and
| powerful.
|
| However, I wouldn't consider using it without better undo, if i
| merge a set of cards by mistake it cannot be undone. Maybe store
| a larger undo history in IndexedDB?
| pketh wrote:
| While there is undo, you're right, it's pretty rough right now.
| That might be a good way for me to dip my toes into indexedDB
| tussa wrote:
| It conveniently doesn't mention the hardest part: conflicts.
|
| If you just drop a conflicting edit then it's a stretch to call
| your app "offline". Yes, it "works" but who wants to use an
| application to at drops you edits?
| halfcat wrote:
| Conflicts themselves are not hard: Keep a directed acyclic
| graph of immutable records. Changes to a record point to the
| parent/prior record. Two users update the same record, now you
| have a tree.
|
| The challenge is interpreting what that tree structure should
| mean.
|
| If you can, let a user decide how to resolve the conflict.
|
| - User logs in, they have a "conflict inbox" of things that
| need to be resolved.
|
| - Two coworkers make conflicting edits, maybe the manager gets
| a notification in their conflict inbox and they decide
| tussa wrote:
| If we want to discuss terminology, I agree I should have said
| "handling conflicts" instead of just "conflicts".
|
| What you are describing is just the beginning of conflict
| handling. The consequences for bad handling are dire: data
| loss. If conflict handling and resolving was easy (hint: it's
| not), the article would have mentioned it.
| halfcat wrote:
| Thank you. Do you see the difficulty in implementing the
| data structure to handle this? Or in the decision about
| what to do about it? Or about how to automate resolution?
|
| Let's take git as an example. If we both push changes to
| our branch, there's no problem. We have a git repo with
| different branches. For a single record, this is even
| simpler, just an append-only table with a foreign key to
| the prior state.
|
| If someone reviews a PR and finds a merge conflict, it gets
| handled. Maybe one wins, both get rejected, or both get
| accepted (a fork). But there's no requirement that data be
| discarded.
|
| But automating it seems impossible in all circumstances
| since it depends on the human intent.
| matharmin wrote:
| Conceptually that's not hard, but in practice an approach
| like that can significantly increase the complexity of the
| app:
|
| 1. Do you store the tree structure for every table in your
| app? If you have 20 tables that could be edited offline, do
| you re-implement it for each table, or try to have a generic
| implementation? 2. Do you design all your tables around the
| tree structure, or do you just store it in addition to your
| "normal" tables? 3. Every piece of code that modifies one of
| these tables need to do it via the tree structure - if you
| update your tables directly from any place it could
| effectively cause conflicts. 4. Do you build separate UI to
| resolve conflicts for every table? 5. Do you query and cache
| the tree structure on the device, or does it have to be
| online to resolve conflicts? 6. Do you expose the tree
| structure via external APIs, or keep it internal?
|
| I find that "last-write-wins" is sufficient for a large
| percentage of cases, and much simpler to implement. Or in
| some cases, just doing conflict detection is sufficient
| (notify the user that the data has changed between loading
| and saving, and they need to re-apply their edits).
|
| If you do need conflict resolution on a large scale (many
| different tables), I'd recommend using data structures
| designed for that. CRDTs is one example - while it is
| typically used for automatic conflict resolution, it often
| stores enough data to allow manual resolution if desired.
| pketh wrote:
| The scenarios where people are simultaneously editing the same
| space online and offline are very rare. When both users are
| online, I use the UI to communicate who's editing what to avoid
| conflicts. I would like to improve this in the future, but for
| now it's a utilitarian scope/resource issue
| JamesSwift wrote:
| Conflict resolution and the inability to come to a business
| decision on what to do has stopped offline-first support in a
| couple apps I've done. Its a really messy conversation to have,
| especially with people that aren't used to sweating the
| details. You can't just handwave away the complexity!
| tussa wrote:
| I've seen business software, where money can be lost, just
| handwave and silently dropping conflicts (because "it doesn't
| really happen that often!")
| Joeri wrote:
| It doesn't happen often, until you make e.g. a ticketing
| system with a pool of ticket handlers that claim a ticket
| to work on it, instead of a sole ticket handling
| responsible, and now it happens dozens of times a day and
| the customer is irate at such incompetent software.
|
| I may at an earlier part of my career, when I knew far less
| about building robust software, have stumbled into such an
| experience.
| JamesSwift wrote:
| "We dont need to worry about that because it like a 1 in
| 100000 chance of occurring"
|
| Proceeds to do millions of transactions a day.
| pketh wrote:
| perfect is the enemy of the good, and perfect can be iterated
| towards as demand scenarios increase
| emacsen wrote:
| I used to think this a lot, but then I find products that do
| exactly this and work reliably most of the time by simply
| asking you "Local Version" or "Server Version". This is what
| Steam does, what Nextcloud does, what PS5 does, and probably
| others. It's a naive approach but it seems to work well enough.
|
| Beyond that, you get into complex territory but maybe we've all
| been overthinking the problem space.
| woodrowbarlow wrote:
| if you can encode your state in CRDTs, there are no conflicts
| to resolve.
| JamesSwift wrote:
| Thats only solving the conflicts at a technical level. The
| hard problem to solve is what conflict-resolution means at a
| business level. The even harder problem to solve is auditing
| and coming up with an appropriate answer for _every single
| entity in the system_.
|
| For most products, there isnt a one-size-fits-all answer to
| how to handle conflicts.
| jiehong wrote:
| That first load time was pretty long, though (like 4 seconds).
|
| Felt as if it checked online or loaded too many things.
| pketh wrote:
| that's def not ideal and not normal, loading up the page in
| incognito takes me less than a second. It does make a lot of
| requests for assets and to the API but those are mostly async.
| Can you repro the long load time everytime? Do you still see a
| long load time for a space url like
| https://kinopio.club/fonts-6n5memHYV0K1qmeUcX2Fs ? If the issue
| persists? What browser/OS are you using? Where in the world are
| you? (the client should be serving over a CDN)
|
| EDIT: in case you were referring to the loading state in the
| vid in the post, I suspect that's a bug with the iOS loading
| screen that I didn't have time to fix before this post (it's
| just idling for most of that). will update later
| JamesSwift wrote:
| As someone who has built offline-first, I noticed that as well
| : D
|
| All the offline-first apps I've built have felt magically fast
| to load. It really is an incredible experience. I think its
| likely something to do with parsing/loading the initial view
| state that is taking a bit. Thats a pretty complicated widget
| so likely has to load libraries to handle it.
| pketh wrote:
| it's an issue with the ios app only that i'll be
| investigating (the loading screen is mostly idling during
| that time). If you load the kinopio website in safari while
| offline (the app is just a thin wrapper over the site), then
| it is indeed magically fast
| jamestanderson wrote:
| It's really cool to see offline support done well. It can be very
| frustrating when it's done poorly, or not offered at all.
|
| One of my biggest gripes with the Spotify app is the poor offline
| support, at least in my experience on Android. I have the bulk of
| my library downloaded for offline listening, so when I have a
| spotty network connection like when I'm on the Subway, I'd expect
| that I can still easily access at least my downloaded songs. Not
| the case. Spotify, it seems, won't use its local cache until it's
| thoroughly convinced you're offline, which may take several
| minutes of waiting for requests to time out. Once Spotify is
| convinced I'm offline, my downloaded songs will then finally load
| normally.
|
| My guess is that instead of doing it the way the Kinopio does -
| by reading from the local cache before fetching the remote data -
| Spotify does it the other way around.
|
| Anyway, nicely done!
| paxys wrote:
| Yeah, the only way to get Spotify to work well offline is to
| manually set your phone to airplane mode. Otherwise it will
| endlessly try and fetch everything over the internet despite it
| being fully cached.
| JamesSwift wrote:
| I ran into this all the time when trying to listen while
| mowing my lawn and going into/out-of wifi range. Very
| frustrating UX.
| pketh wrote:
| lately, I've been using zotify to download album mp3s from
| spotify and listen to them in doppler for mac/ios. It's
| been amazing to not have to use spotify to use spotify
___________________________________________________________________
(page generated 2024-01-23 23:02 UTC)