Implementing Server Side Data Synchronization for Mobile Apps

75
Implementing Server Side Data Synchronization for Mobile Apps

description

Today mobile apps are everywhere. These apps cannot count on a reliable and constant internet connection: working in offline mode is becoming a common pattern. This is quite easy for read-only apps but it becomes rapidly tricky for apps that create data in offline mode. This talk is a case study about a possible architecture for enabling data synchronization in these situations

Transcript of Implementing Server Side Data Synchronization for Mobile Apps

Page 1: Implementing Server Side Data Synchronization for Mobile Apps

Implementing Server Side Data Synchronization for

Mobile Apps

Page 2: Implementing Server Side Data Synchronization for Mobile Apps

Michele Orselli CTO@Ideato ! _orso_ ! micheleorselli ! [email protected]

Page 3: Implementing Server Side Data Synchronization for Mobile Apps

Agenda

scenario design choices

implementation alternative approaches

Page 4: Implementing Server Side Data Synchronization for Mobile Apps
Page 5: Implementing Server Side Data Synchronization for Mobile Apps
Page 6: Implementing Server Side Data Synchronization for Mobile Apps

Sync scenario

A

B

C

Page 7: Implementing Server Side Data Synchronization for Mobile Apps

Sync scenario

A B C

A B C

A B C

Page 8: Implementing Server Side Data Synchronization for Mobile Apps

Dealing with conflicts

A1

A2

?

Page 9: Implementing Server Side Data Synchronization for Mobile Apps

Brownfield project !several mobile apps for tracking user generated data (calendar, notes, bio data) !iOS & Android !~10 K users steadily growing at 1.2 K/month

Scenario

Page 10: Implementing Server Side Data Synchronization for Mobile Apps

MongoDB !Legacy App based on codeigniter !Existing RPC-wannabe-REST API for data sync

Scenario

Page 11: Implementing Server Side Data Synchronization for Mobile Apps

get updates: !POST /m/<app>/get/<user_id>/<res>/<updated_from> !!!send updates: !POST /m/<app>/update/<user_id>/<res_id>/<dev_id>/<res> !!

Scenario

Page 12: Implementing Server Side Data Synchronization for Mobile Apps

api

Page 13: Implementing Server Side Data Synchronization for Mobile Apps

!!6 different resources, 12 calls per sync !apps sync by polling every 30 sec !every call sync little data !!

Scenario

Page 14: Implementing Server Side Data Synchronization for Mobile Apps

!!rebuild sync API for old apps + 2 incoming !allow image synchronization !more efficient than previous API !!

Challenge

Page 15: Implementing Server Side Data Synchronization for Mobile Apps
Page 16: Implementing Server Side Data Synchronization for Mobile Apps

Existing Solutions

Tstamps, Vector clocks,

CRDTs

syncML, syncano

Azure Data sync

Algorithms Protocols/API

Platform

couchDB, riak

Storage

Page 17: Implementing Server Side Data Synchronization for Mobile Apps

Not Invented Here?

Don't Reinvent The Wheel, Unless You Plan on Learning More About Wheels

!J. Atwood

Page 18: Implementing Server Side Data Synchronization for Mobile Apps

!!2 different mobile platforms several teams with different skill level !changing storage wasn’t an option forcing a particular technology client side wasn’t an option

Architecture

Page 19: Implementing Server Side Data Synchronization for Mobile Apps

Architecture

c1

server

c2

c3

sync logic conflicts resolution

thin clients

Page 20: Implementing Server Side Data Synchronization for Mobile Apps

!!In the sync domain all resources are the same !For every app one endpoint for getting new data one endpoint for pushing changes one endpoint for uploading images

Implementation

Page 21: Implementing Server Side Data Synchronization for Mobile Apps

!Get all changes (1st sync): !GET /apps/{app}/users/{user_id}/changes !Get latest changes: !GET /apps/{app}/users/{user_id}/changes?from={from}

Get changes

Page 22: Implementing Server Side Data Synchronization for Mobile Apps

!Get all changes (1st sync): !GET /apps/{app}/users/{user_id}/changes !Get latest changes: !GET /apps/{app}/users/{user_id}/changes?from={from}

Get changes

timestamp?

Page 23: Implementing Server Side Data Synchronization for Mobile Apps

timestamp are inaccurate (skew and developer errors) !server suggests the “from” parameter to be used in the next request

Server suggest the sync time

c1 server

GET /changes

{ ‘next’ : 123456, ‘data’: […] }

Page 24: Implementing Server Side Data Synchronization for Mobile Apps

Server suggest the sync time

c1 server

GET /changes

{ ‘next’ : 12345, ‘data’: […] }

Page 25: Implementing Server Side Data Synchronization for Mobile Apps

Server suggest the sync time

c1 server

GET /changes

{ ‘next’ : 12345, ‘data’: […] }

GET /changes?from=12345

{ ‘next’ : 45678, ‘data’: […] }

Page 26: Implementing Server Side Data Synchronization for Mobile Apps

operations: {‘op’: ’add’, id: ‘1’, ’data’:[…]} {‘op’: ’update’, id: ‘1’, ’data’:[…]} {‘op’: ’delete’, id: ‘1’} {‘op’: ’add’, id: ‘2’, ’data’:[…]} !!states: {id: ‘1’, ’data’:[…]} {id: 2’, ’data’:[…]} {id: ‘3’, ’data’:[…]}

what to transfer

Page 27: Implementing Server Side Data Synchronization for Mobile Apps

!we chosen to transfer states {id: ‘1’, ’type’: ‘measure’, ‘_deleted’: true} {id: 2’, ‘type’: ‘note’} {id: ‘3’, ‘type’: ‘note’} !!ps: soft delete all the things!

what to transfer

Page 28: Implementing Server Side Data Synchronization for Mobile Apps

How do we generate an unique id in a distributed system? !UUID: several implementations (RFC 4122) !Local Ids/Global Id: server generates GUIDs clients use local ids to manage their records

unique identifiers

c1 server

GET /changes

{‘data’:{’guid’: ‘58f0bdd7-1481’}}

Page 29: Implementing Server Side Data Synchronization for Mobile Apps

unique identifiers

c1 server

POST /merge{ ‘data’: [ {’lid’: ‘1’, …}, {‘lid’: ‘2’, …} ] }

{ ‘data’: [ {‘guid’: ‘58f0bdd7-1400’, ’lid’: ‘1’, …}, {‘guid’: ‘6f9f3ec9-1400’, ‘lid’: ‘2’, …} ] }

Page 30: Implementing Server Side Data Synchronization for Mobile Apps

!server handles conflicts resolution mobile generated data are “temporary” until sync to server !conflict resolution: domain indipendent: last-write wins domain dipendent: use domain knowledge to resolve

conflict resolution algorithm (plain data)

Page 31: Implementing Server Side Data Synchronization for Mobile Apps

function sync($data) {!!! foreach ($data as $newRecord) {!!! ! $s = findByGuid($newRecord->getGuid());!! !! ! if (!$s) {!! ! ! add($newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }! !! ! !! ! if ($newRecord->updated > $s->updated) {!! ! ! update($s, $newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }!! ! !! ! updateRemote($newRecord, $s);!}

conflict resolution algorithm (plain data)

Page 32: Implementing Server Side Data Synchronization for Mobile Apps

function sync($data) {!!! foreach ($data as $newRecord) {!!! ! $s = findByGuid($newRecord->getGuid());!! !! ! if (!$s) {!! ! ! add($newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }! !! ! !! ! if ($newRecord->updated > $s->updated) {!! ! ! update($s, $newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }!! ! !! ! updateRemote($newRecord, $s);!}

conflict resolution algorithm (plain data)

Page 33: Implementing Server Side Data Synchronization for Mobile Apps

function sync($data) {!!! foreach ($data as $newRecord) {!!! ! $s = findByGuid($newRecord->getGuid());!! !! ! if (!$s) {!! ! ! add($newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }! !! ! !! ! if ($newRecord->updated > $s->updated) {!! ! ! update($s, $newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }!! ! !! ! updateRemote($newRecord, $s);!}

conflict resolution algorithm (plain data)

no conflict

Page 34: Implementing Server Side Data Synchronization for Mobile Apps

function sync($data) {!!! foreach ($data as $newRecord) {!!! ! $s = findByGuid($newRecord->getGuid());!! !! ! if (!$s) {!! ! ! add($newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }! !! ! !! ! if ($newRecord->updated > $s->updated) {!! ! ! update($s, $newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }!! ! !! ! updateRemote($newRecord, $s);!}

conflict resolution algorithm (plain data)

remote wins

Page 35: Implementing Server Side Data Synchronization for Mobile Apps

function sync($data) {!!! foreach ($data as $newRecord) {!!! ! $s = findByGuid($newRecord->getGuid());!! !! ! if (!$s) {!! ! ! add($newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }! !! ! !! ! if ($newRecord->updated > $s->updated) {!! ! ! update($s, $newRecord);!! ! ! send($newRecord);!! ! ! continue;!! ! }!! ! !! ! updateRemote($newRecord, $s);!}

conflict resolution algorithm (plain data)

server wins

Page 36: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (plain data)

c1

{ ‘lid’: ‘1’, ‘guid’: ‘af54d’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

server

{ ’guid’: ‘af54d’, ‘data’: ‘BBB’, ‘updated’ : ’20’ }

Page 37: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (plain data)

c1 server

{ ‘lid’: ‘1’, ‘guid’: ‘af54d’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘data’ : ‘hello!’, ‘updated’: ’15’ } POST /merge

{ ’guid’: ‘af54d’, ‘data’: ‘BBB’, ‘updated’ : ’20’ }

Page 38: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (plain data)

c1 server

{ ‘lid’: ‘1’, ‘guid’: ‘af54d’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘data’ : ‘hello!’, ‘updated’: ’15’ } POST /merge

{ ‘guid’: ‘e324f’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

{ ’guid’: ‘af54d’, ‘data’: ‘BBB’, ‘updated’ : ’20’ }

Page 39: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (plain data)

c1 server

{ ‘lid’: ‘1’, ‘guid’: ‘af54d’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘data’ : ‘hello!’, ‘updated’: ’15’ } POST /merge

{ ‘guid’: ‘e324f’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

{ ’guid’: ‘af54d’, ‘data’: ‘BBB’, ‘updated’ : ’20’ }

Page 40: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (plain data)

c1 server

{ ‘lid’: ‘1’, ‘guid’: ‘af54d’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘data’ : ‘hello!’, ‘updated’: ’15’ } POST /merge

{ ‘guid’: ‘e324f’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

{ ’guid’: ‘af54d’, ‘data’: ‘AAA’, ‘updated’ : ’100’ }

Page 41: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (plain data)

c1 server

{ ‘lid’: ‘1’, ‘guid’: ‘af54d’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ’guid’: ‘af54d’, ‘data’: ‘AAA’, ‘updated’ : ’100’ }

{ ‘lid’: ‘2’, ‘data’ : ‘hello!’, ‘updated’: ’15’ } POST /merge

{ ‘guid’: ‘e324f’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

{‘ok’ : { ’guid’: ‘af54d’ }}

{‘update’ : { lid: ‘2’, ’guid’: ‘e324f’ }}

Page 42: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (hierarchical data)

!How to manage hierarchical data? !!

{ ‘lid’ : ‘123456’, ‘type’ : ‘baby’, … }

{ ‘lid’ : ‘123456’, ‘type’ : ‘temperature’, ‘baby_id : ‘123456’ }

Page 43: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (hierarchical data)

!How to manage hierarchical data? 1) sync root record 2) update ids 3) sync child records !!

{ ‘lid’ : ‘123456’, ‘type’ : ‘baby’, … }

{ ‘lid’ : ‘123456’, ‘type’ : ‘temperature’, ‘baby_id : ‘123456’ }

Page 44: Implementing Server Side Data Synchronization for Mobile Apps

function syncHierarchical($data) {!!! sortByHierarchy($data);!!! foreach ($data as $newRootRecord) {!! ! !! ! $s = findByGuid($newRootRecord->getGuid());!! ! !! ! if($newRecord->isRoot()) {!!! ! ! if (!$s) {!! ! ! ! add($newRootRecord);!! ! ! ! updateRecordIds($newRootRecord, $data);!! ! ! ! send($newRootRecord);!! ! ! ! continue;!! ! ! }! !! ! !! ! ! …

conflict resolution algorithm (hierarchical data)

Page 45: Implementing Server Side Data Synchronization for Mobile Apps

function syncHierarchical($data) {!!! sortByHierarchy($data);!!! foreach ($data as $newRootRecord) {!! ! !! ! $s = findByGuid($newRootRecord->getGuid());!! ! !! ! if($newRecord->isRoot()) {!!! ! ! if (!$s) {!! ! ! ! add($newRootRecord);!! ! ! ! updateRecordIds($newRootRecord, $data);!! ! ! ! send($newRootRecord);!! ! ! ! continue;!! ! ! }! !! ! !! ! ! …

conflict resolution algorithm (hierarchical data)

parent records first

Page 46: Implementing Server Side Data Synchronization for Mobile Apps

function syncHierarchical($data) {!!! sortByHierarchy($data);!!! foreach ($data as $newRootRecord) {!! ! !! ! $s = findByGuid($newRootRecord->getGuid());!! ! !! ! if($newRecord->isRoot()) {!!! ! ! if (!$s) {!! ! ! ! add($newRootRecord);!! ! ! ! updateRecordIds($newRootRecord, $data);!! ! ! ! send($newRootRecord);!! ! ! ! continue;!! ! ! }! !! ! !! ! ! …

conflict resolution algorithm (hierarchical data)

Page 47: Implementing Server Side Data Synchronization for Mobile Apps

function syncHierarchical($data) {!!! sortByHierarchy($data);!!! foreach ($data as $newRootRecord) {!! ! !! ! $s = findByGuid($newRootRecord->getGuid());!! ! !! ! if($newRecord->isRoot()) {!!! ! ! if (!$s) {!! ! ! ! add($newRootRecord);!! ! ! ! updateRecordIds($newRootRecord, $data);!! ! ! ! send($newRootRecord);!! ! ! ! continue;!! ! ! }! !! ! !! ! ! …

conflict resolution algorithm (hierarchical data)

no conflict

Page 48: Implementing Server Side Data Synchronization for Mobile Apps

!! ! …! ! !!! ! if ($newRootRecord->updated > $s->updated) {! ! ! !! ! ! update($s, $newRecord);!! ! ! updateRecordIds($newRootRecord, $data);! ! !! ! ! send($newRootRecord);!! ! ! continue;!! ! } else {!! ! ! updateRecordIds($s, $data);!! ! ! updateRemote($newRecord, $s);!! ! }! !! } else {!! ! sync($data);!! }! !}!

conflict resolution algorithm (hierarchical data)

remote wins

Page 49: Implementing Server Side Data Synchronization for Mobile Apps

!! ! …! ! !!! ! if ($newRootRecord->updated > $s->updated) {! ! ! !! ! ! update($s, $newRecord);!! ! ! updateRecordIds($newRootRecord, $data);! ! !! ! ! send($newRootRecord);!! ! ! continue;!! ! } else {!! ! ! updateRecordIds($s, $data);!! ! ! updateRemote($newRecord, $s);!! ! }! !! } else {!! ! sync($data);!! }! !}!

conflict resolution algorithm (hierarchical data)

server wins

Page 50: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (hierarchical data)

{ ‘lid’: ‘1’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘parent’: ‘1’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

c1 serverPOST /merge

Page 51: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (hierarchical data)

c1

{ ‘lid’: ‘1’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘parent’: ‘1’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

serverPOST /merge

{ ‘lid’: ‘1’, ‘guid’ : ‘32ead’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

Page 52: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (hierarchical data)

c1

{ ‘lid’: ‘1’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘parent’: ‘32ead’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

serverPOST /merge

{ ‘lid’: ‘1’, ‘guid’ : ‘32ead’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

Page 53: Implementing Server Side Data Synchronization for Mobile Apps

conflict resolution algorithm (hierarchical data)

c1

{ ‘lid’: ‘1’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘parent’: ‘32ead’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

serverPOST /merge

{ ‘lid’: ‘1’, ‘guid’ : ‘32ead’, ‘data’ : ‘AAA’ ‘updated’: ’100’ }

{ ‘lid’: ‘2’, ‘parent’: ‘32ead’, ‘data’ : ‘hello!’, ‘updated’: ’15’ }

{‘update’ : { ‘lid’: ‘1’, ’guid’: ‘af54d’ }}

{‘update’ : { lid: ‘2’, ’guid’: ‘e324f’ }}

Page 54: Implementing Server Side Data Synchronization for Mobile Apps

!!e.g. “only one temperature can be registered in a given day” !how to we enforce domain constraints on data?

enforcing domain constraints

Page 55: Implementing Server Side Data Synchronization for Mobile Apps

!!e.g. “only one temperature can be registered in a given day” !how to we enforce domain constraints on data? 1) relax constraints

enforcing domain constraints

Page 56: Implementing Server Side Data Synchronization for Mobile Apps

!!e.g. “only one temperature can be registered in a given day” !how to we enforce domain constraints on data? 1) relax constraints 2) integrate constraints in sync algorithm

enforcing domain constraints

Page 57: Implementing Server Side Data Synchronization for Mobile Apps

!!from findByGuid to findSimilar !first lookup by GUID then by domain rules !“two measures are similar if are referred to the same date” !!! !

enforcing domain constraints

Page 58: Implementing Server Side Data Synchronization for Mobile Apps

enforcing domain constraints

c1 server

Page 59: Implementing Server Side Data Synchronization for Mobile Apps

enforcing domain constraints

c1 server

{ ’guid’: ‘af54d’, ‘when’: ‘20141005’ }

Page 60: Implementing Server Side Data Synchronization for Mobile Apps

enforcing domain constraints

c1 server

{ ‘lid’: ‘1’, ‘when’: ‘20141005’ }

{ ’guid’: ‘af54d’, ‘when’: ‘20141005’ }

Page 61: Implementing Server Side Data Synchronization for Mobile Apps

enforcing domain constraints

c1 server

{ ‘lid’: ‘1’, ‘when’: ‘20141005’ }

{ ’guid’: ‘af54d’, ‘when’: ‘20141005’ }

POST /merge

Page 62: Implementing Server Side Data Synchronization for Mobile Apps

enforcing domain constraints

c1 server

{ ‘lid’: ‘1’, ‘when’: ‘20141005’ }

{ ’guid’: ‘af54d’, ‘when’: ‘20141005’ }

POST /merge

Page 63: Implementing Server Side Data Synchronization for Mobile Apps

enforcing domain constraints

c1 server

{ ‘lid’: ‘1’, ‘when’: ‘20141005’ }

{ ’guid’: ‘af54d’, ‘when’: ‘20141005’ }

POST /merge

{ ’guid’: ‘af54d’, ‘when’: ‘20141005’ }

Page 64: Implementing Server Side Data Synchronization for Mobile Apps

!Binary data uploaded via custom endpoint !Sync data remain small !Uploads can be resumed

dealing with binary data

Page 65: Implementing Server Side Data Synchronization for Mobile Apps

!Two steps* 1) data are synched to server 2) related images are uploaded !* this means record without file for a given time

dealing with binary data

Page 66: Implementing Server Side Data Synchronization for Mobile Apps

dealing with binary data

c1 server

POST /merge

POST /upload/ac435-f8345/image

{ ‘lid’ : 1, ‘type’ : ‘baby’, ‘image’ : ‘myimage.jpg’ }

{ ‘lid’ : 1, ‘guid’ : ‘ac435-f8345’ }

Page 67: Implementing Server Side Data Synchronization for Mobile Apps

!Implementing this stuff is tricky !Explore existing solution if you can !Understanding the domain is important

What we learned

Page 68: Implementing Server Side Data Synchronization for Mobile Apps

vector clocks

Page 69: Implementing Server Side Data Synchronization for Mobile Apps

!

Conflict-free Replicated Data Types (CRDTs)

!

Constraining the types of operations in order to:

- ensure convergence of changes to shared data by uncoordinated, concurrent actors

- eliminate network failure modes as a source of error

CRDT

Page 70: Implementing Server Side Data Synchronization for Mobile Apps

Math!!!

!

Bounded-join semilattices

- join operation defining a least upper bound

- partially order set

- always increasing

CRDT

Page 71: Implementing Server Side Data Synchronization for Mobile Apps

Gateways handles sync

Data flows through channels

- partition data set

- authorization

- limit the data

!

Use revision trees

Couchbase Mobile

Page 72: Implementing Server Side Data Synchronization for Mobile Apps

Distributed DB Eventually/Strong Consistency !Data Types !Configurable conflic resolution - db level for built-in data types - application level for custom data

Riak

Page 73: Implementing Server Side Data Synchronization for Mobile Apps

!

Questions? !

Please leave feedback! https://joind.in/11797 !

That’s all folks!

Page 74: Implementing Server Side Data Synchronization for Mobile Apps

Vector Clocks http://basho.com/why-vector-clocks-are-easy/ http://www.datastax.com/dev/blog/why-cassandra-doesnt-need-vector-clocks http://basho.com/why-vector-clocks-are-hard/ !CRDTs http://christophermeiklejohn.com/distributed/systems/2013/07/12/readings-in-distributed-systems.html http://www.infoq.com/presentations/problems-distributed-systems https://www.youtube.com/watch?v=qyVNG7fnubQ !Riak http://docs.basho.com/riak/latest/dev/using/conflict-resolution/ !Couchbase Sync Gateway http://docs.couchbase.com/sync-gateway/ http://www.infoq.com/presentations/sync-mobile-data !API http://developers.amiando.com/index.php/REST_API_DataSync https://login.syncano.com/docs/rest/index.html

Links

Page 75: Implementing Server Side Data Synchronization for Mobile Apps

phones https://www.flickr.com/photos/15216811@N06/14504964841 wat http://uturncrossfit.com/wp-content/uploads/2014/04/wait-what.jpg darth http://www.listal.com/viewimage/3825918h blueprint: http://upload.wikimedia.org/wikipedia/commons/5/5e/Joy_Oil_gas_station_blueprints.jpg!building: http://s0.geograph.org.uk/geophotos/02/42/74/2427436_96c4cd84.jpg!brownfield: http://s0.geograph.org.uk/geophotos/02/04/54/2045448_03a2fb36.jpg!no connection: https://www.flickr.com/photos/77018488@N03/9004800239!no internet con https://www.flickr.com/photos/roland/9681237793!vector clocks: http://en.wikipedia.org/wiki/Vector_clock!crdts: http://www.infoq.com/presentations/problems-distributed-systems

Credits