0

The basic idea of the application I've been working on is to allow groups of users to collaborate on "Stacks" of flash cards. Eventually, the app will function as a client-server system (with an iOS app as the client, and a Rails app as the server)

The requirements of this design, as I see them, are like this:

  1. It needs to handle merging of edits smoothly. Because many users will be editing each Stack, and because every client may not be able to upload their changes as soon as they are done, the design needs to be able to elegantly reconcile discordant changes to the shared data.
  2. It needs to be efficient. Because many users will be accessing the app over their celular connection, I need to minimize the amount of data uploaded and downloaded from the server, to make sure the app runs speedily over these connections, and to reduce data use for the already limited clients.

Originally I was just going to go the simple route and have the client send along to the server a "bulk" report at every sync, meaning that the entire local copy of each Stack would be uploaded, and then the server would process all this, merging it into its own master copy with previous clients' edits, before sending down the entire new data set to the client, who would save this accurate copy for offline viewing and editing.

The problem that I saw with this, keeping in mind my design requirements, chiefly is that it is horribly inefficient. Not only would the client app have to waste time uploading and downloading all this data, it would have to write all the new information to its local data store, even though most of it would be the same as the previous copy. I also could not fathom how the server would make sense of conflicting edits in an efficient, logical way.

So here's what I came up with:

Whenever a client makes a change to a shared Stack, in addition to altering its own copy of the database, it will make a note of the change in a log, including what was altered, how, when, and by whom. The next time the client syncs with the server, be it in a second or a few days, this "receipt" of actions is sent to the server, instead of the entire local data copy.

There, the server first stores these actions for posterity, before executing all the changes on the server copy of the data. It then uses this database of receipts to grab all of the relevant changes to the Stack since the last time the client synced with the database. Only these are then sent back to the client, which runs the changes on its own local copy.

Using this log of all the changes clients have made, the server can decide which changes invalidate which other changes (for instance if a user deletes a card, and then before syncing with this change, another user edits the sane card, then the deletion would be invalidated). Although complicated to implement, this would theoretically be an ideal solution to my merging problem.

So what do you think?

Is this a feasible solution? Do you see any glaring holes in my master plan?

Thanks!

maxluzuriaga
  • 1,327
  • 9
  • 16

1 Answers1

1

One thing to watch out for is not trusting the time from a device as part of the algorithm:

Can I Rely on the iOS Device Clock Being Correct?

My answer on that thread talks about that and also merging/interleaving operations.

You might need to consider if two users edit the same conflicting piece of data on the same card. Since you can't trust the time, the client does know the last "server time marker" as of it's last sync so you could credit all changes as of that last sync server marker. What that does is reward the client that syncs more often as it interleaves the changes by the only thing you can be sure of (the server's time).

Hope that helps. Definitely a complex topic to do correctly (and generically).

Community
  • 1
  • 1
bryanmac
  • 38,941
  • 11
  • 91
  • 99