Slide 1

Slide 1 text

Taking Cloud Databases to the Edge Cloud Computing Expo Wednesday, June 10, 2015 Bradley Holt, Developer Advocate @BradleyHolt

Slide 2

Slide 2 text

Image Credit: Joan Touzet (@wohali), ASF Member, CouchDB PMC Member 2

Slide 3

Slide 3 text

Image Credit: Device landscape by Jeremy Keith, on Flickr 3 Not just mobile first…!

Slide 4

Slide 4 text

Image Credit: Lynn Camp Prong (Explored) by AllieKF, on Flickr 4 Offline First! Because being offline shouldn't be an error condition.!

Slide 5

Slide 5 text

5 Doesn't ubiquitous connectivity make offline- enabled apps unnecessary?!

Slide 6

Slide 6 text

6 No.!

Slide 7

Slide 7 text

7 Quite the opposite, in fact.!

Slide 8

Slide 8 text

8 Ubiquitous connectivity is driving the demand for 
 offline capabilities.!

Slide 9

Slide 9 text

9 How?!

Slide 10

Slide 10 text

The Eight Fallacies of Distributed Computing 1.  The network is reliable 2.  Latency is zero 3.  Bandwidth is infinite 4.  The network is secure 5.  Topology doesn't change 6.  There is one administrator 7.  Transport cost is zero 8.  The network is homogeneous 10 Text Credit: The Eight Fallacies of Distributed Computing by Peter Deutsch | Image Credit: Pneumatic Central by Sleestak, on Flickr

Slide 11

Slide 11 text

11 Offline-first is the only way 
 to achieve a true, 100% 
 always-on user experience.* ! *assuming the device is reliable!

Slide 12

Slide 12 text

Benefits of Offline First 12 •  Better, faster user experience, both offline and online •  Allow your users to work offline or with limited connectivity •  Potentially saves battery life and bandwidth usage

Slide 13

Slide 13 text

Offline Patterns & Anti-Patterns •  Don't return an error for no reason •  Do let users view cached/saved data •  Do synchronize data when connected 13

Slide 14

Slide 14 text

Offline Patterns & Anti-Patterns •  Don't return an error for no reason •  Do let users view cached/saved data •  Do synchronize data when connected 13

Slide 15

Slide 15 text

Offline Patterns & Anti-Patterns •  Don't return an error for no reason •  Do let users view cached/saved data •  Do synchronize data when connected 13

Slide 16

Slide 16 text

Offline Patterns & Anti-Patterns •  Don't return an error for no reason •  Do let users view cached/saved data •  Do synchronize data when connected 13

Slide 17

Slide 17 text

Not Just Mobile Apps •  Internet of Things (Iot) •  Content delivery networks (CDNs) •  Purpose-built devices 14 Image Credit: Ethernet IoT Starter Kit

Slide 18

Slide 18 text

Apache CouchDB

Slide 19

Slide 19 text

Apache CouchDB •  JSON document database •  HTTP API •  Master-master replication 16

Slide 20

Slide 20 text

JSON Documents 17 {
 _id: "6EF9D2B0-13D3-1378-8D30-39E3CE0B36C2",
 _rev: "1-0b457efcf82fb29492ef927ba5b6ee15",
 type: "Feature",
 geometry: {
 type: "Point",
 coordinates: [
 -71.1028,
 42.3691
 ]
 },
 properties: {
 session_id: "3486b13f-7b8a-8a96-dfbf-9b82800e367f",
 timestamp: 1422928591717
 }
 }

Slide 21

Slide 21 text

CouchDB Replication 18

Slide 22

Slide 22 text

CouchDB Replication Protocol •  One-off, one way operation •  Peer-to-peer (masterless) •  Incremental •  Conflict detection 19

Slide 23

Slide 23 text

CouchDB Replication Protocol •  Synchronizes JSON documents between two peers over HTTP •  Implemented by: •  CouchDB •  Cloudant •  PouchDB •  Couchbase •  Implement your own: http://docs.couchdb.org/en/latest/replication/protocol.html 20

Slide 24

Slide 24 text

IBM Cloudant •  Globally distributed data layer for web and mobile applications •  MongoDB-style queries •  Advanced geospatial capabilities •  Full text search indexing 21

Slide 25

Slide 25 text

PouchDB

Slide 26

Slide 26 text

PouchDB •  A database in your web browser •  Also works in Node.js •  Can synchronize with any database that implements the CouchDB Replication Protocol •  Makes create, read, update and delete operations extremely fast 23

Slide 27

Slide 27 text

Hybrid Mobile Web Apps •  Native mobile web apps built with HTML5, CSS and JavaScript •  PouchDB includes an SQLite adapter for use in Cordova/PhoneGap •  Good for: •  Fully-featured, cross-platform native apps •  High-fidelity prototypes 24

Slide 28

Slide 28 text

Responsive Mobile Web Apps •  HTML5, CSS and JavaScript mobile web apps •  Responsive design •  Enhanced to enable offline usage •  PouchDB includes IndexedDB and WebSQL adapters for use in browsers 25

Slide 29

Slide 29 text

Node.js Applications •  PouchDB is installable through npm •  PouchDB includes a LevelDB adapter for use in Node.js •  In-memory and Riak-based adapters are also available •  PouchDB Server provides a Node.js server that implements the CouchDB API 26

Slide 30

Slide 30 text

PouchDB Code Examples

Slide 31

Slide 31 text

Installing PouchDB •  Download from the PouchDB website " •  CDN •  Bower $ bower install --save pouchdb" •  npm $ npm install --save pouchdb" 28

Slide 32

Slide 32 text

PouchDB Code Examples 29 •  Creating a local PouchDB database •  Creating a remote PouchDB database •  Creating a new document •  Updating a document •  Deleting a document •  Querying a database •  Replicating PouchDB •  Listening for database changes

Slide 33

Slide 33 text

Creating a Local PouchDB Database 30 var db = new PouchDB("smart-meter");" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/01-create-local-database.js

Slide 34

Slide 34 text

Creating a Remote PouchDB Database 31 var remoteDb = new PouchDB("https://bradley-holt.cloudant.com/smart-meter");" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/02-create-remote-database.js

Slide 35

Slide 35 text

Cross-Origin Resource Sharing (CORS) •  Enable Cross-Origin Resource Sharing (CORS) on remote database •  Browsers place security restrictions on cross-site HTTP requests •  If you run into a problem, remember this warning! 32 Image Credit: Grunge Warning Sign - Do Not Read This Sign by Nicolas Raymond, on Flickr

Slide 36

Slide 36 text

Creating a New Document 33 var db = new PouchDB("smart-meter");" db.post({" date: "2014-11-12T23:27:03.794Z"," kilowatt_hours: 14" }).then(function() {" console.log("Document created");" }).catch(function(error) {" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/03-create-document-post.js

Slide 37

Slide 37 text

Creating a New Document, Specifying its ID 34 var db = new PouchDB("smart-meter");" db.put({" _id: "2014-11-12T23:27:03.794Z"," kilowatt_hours: 14" }).then(function() {" console.log("Document created");" }).catch(function(error) {" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/04-create-document-put.js

Slide 38

Slide 38 text

Updating a Document 35 db.put({" _id: "2014-11-12T23:27:03.794Z"," kilowatt_hours: 14" }).then(function() {" return db.get("2014-11-12T23:27:03.794Z");" }).then(function(doc) {" // Update the value for kilowatt hours" doc.kilowatt_hours = 15;" // Put the document back to the database" return db.put(doc);" }).catch(function(error) {" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/05-update-document.js

Slide 39

Slide 39 text

Deleting a Document 36 db.put({" _id: "2014-11-12T23:27:03.794Z"," kilowatt_hours: 14" }).then(function() {" // Get the document" return db.get("2014-11-12T23:27:03.794Z");" }).then(function(doc) {" // Remove the document from the database" return db.remove(doc);" }).catch(function(error) {" console.log(error);" });" " https://github.com/bradley-holt/offline-first/blob/master/pouchdb/06-delete-document.js

Slide 40

Slide 40 text

Querying a Database with allDocs" 37 db.bulkDocs([" {_id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14}," {_id: "2014-11-13T00:52:01.471Z", kilowatt_hours: 15}," {_id: "2014-11-13T01:39:28.911Z", kilowatt_hours: 16}," {_id: "2014-11-13T02:52:01.471Z", kilowatt_hours: 17}" ]).then(function(result) {" // Get all documents" return db.allDocs({include_docs: true});" }).then(function(response) {" console.log(response);" }).catch(function(error) {" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/07-query-database-all-docs.js

Slide 41

Slide 41 text

allDocs Options •  include_docs" •  conflicts" •  attachments" •  startkey" •  endkey" •  inclusive_end (true by default) •  limit" •  skip" •  descending" •  key" •  keys" 38

Slide 42

Slide 42 text

Querying a Database with Map/Reduce 39 •  Most queries can be done with allDocs (in PouchDB) •  Map functions transform documents into indexes •  Reduce functions aggregate results of Map functions •  _sum" •  _count" •  _stats"

Slide 43

Slide 43 text

Querying a Database with PouchDB Find •  Based on Cloudant Query (Mango) •  MongoDB-style query language •  Define fields to index 40 Image Credit: Mango with section on a white background by bangdoll, on Flickr

Slide 44

Slide 44 text

Replicating a PouchDB Database 41 var db = new PouchDB("smart-meter");" var remoteDb = new PouchDB(" "https://bradley-holt.cloudant.com/smart-meter"" );" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/08-replicate-database.js

Slide 45

Slide 45 text

Replicating a PouchDB Database 42 db.bulkDocs([" {_id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14}," {_id: "2014-11-13T00:52:01.471Z", kilowatt_hours: 15}," {_id: "2014-11-13T01:39:28.911Z", kilowatt_hours: 16}," {_id: "2014-11-13T02:52:01.471Z", kilowatt_hours: 17}" ]).then(function(result) {" …" }).catch(function(error) {" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/08-replicate-database.js

Slide 46

Slide 46 text

Replicating a PouchDB Database 43 db.replicate.to(remoteDb, {" live: false," retry: false" }).on("change", function(info) {" // Replication has written a new document" console.log(info);" }).on("complete", function(info) {" // Replication has complete or been cancelled" console.log(info);" }).on("error", function(error) {" // Replication has stopped due to an unrecoverable failure" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/08-replicate-database.js

Slide 47

Slide 47 text

Bidirectionally Replicating a PouchDB Database 44 Promise.all([" db.bulkDocs([" {_id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14}," {_id: "2014-11-13T00:52:01.471Z", kilowatt_hours: 15}" ])," remoteDb.bulkDocs([" {_id: "2014-11-11T22:35:01.433Z", kilowatt_hours: 11}," {_id: "2014-11-12T00:43:01.633Z", kilowatt_hours: 13}" ])" ]).then(function() {" …" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/09-replicate-database-bidirectional.js

Slide 48

Slide 48 text

Bidirectionally Replicating a PouchDB Database 45 db.sync(remoteDb, {" live: false," retry: false" }).on("change", function(info) {" // Replication has written a new document" console.log(info);" }).on("complete", function(info) {" // Replication has complete or been cancelled" console.log(info);" }).on("error", function(error) {" // Replication has stopped due to an unrecoverable failure" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/09-replicate-database-bidirectional.js

Slide 49

Slide 49 text

Live Replication of a PouchDB Database 46 Promise.all([" db.bulkDocs([" {_id: "2014-11-12T23:27:03.794Z", kilowatt_hours: 14}," {_id: "2014-11-13T00:52:01.471Z", kilowatt_hours: 15}" ])," remoteDb.bulkDocs([" {_id: "2014-11-11T22:35:01.433Z", kilowatt_hours: 11}," {_id: "2014-11-12T00:43:01.633Z", kilowatt_hours: 13}" ])" ]).then(function() {" …" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/10-replicate-database-live.js

Slide 50

Slide 50 text

Live Replication of a PouchDB Database 47 var sync = db.sync(remoteDb, {" live: true," retry: true" }).on("change", function(info) {" // Replication has written a new document" console.log(info);" }).on("complete", function(info) {" // Replication has complete or been cancelled" console.log(info);" }).on("error", function(error) {" // Replication has stopped due to an unrecoverable failure" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/10-replicate-database-live.js

Slide 51

Slide 51 text

Listening for Database Changes 48 var changes = remoteDb.changes({" since: "now"" }).on("change", function(change) {" // A document has changed" console.log(change);" }).on("complete", function(info) {" // changes() was canceled" console.log(info);" }).on("error", function(error) {" // changes() has errored" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/11-database-changes.js

Slide 52

Slide 52 text

Listening for Database Changes 49 // Create several documents" remoteDb.bulkDocs([" {_id: "2014-11-11T22:35:01.433Z", kilowatt_hours: 11}," {_id: "2014-11-12T00:43:01.633Z", kilowatt_hours: 13}," {_id: "2014-11-12T02:42:52.284Z", kilowatt_hours: 14}," {_id: "2014-11-12T02:46:23.730Z", kilowatt_hours: 16}" }).catch(function(error) {" console.log(error);" });" https://github.com/bradley-holt/offline-first/blob/master/pouchdb/11-database-changes.js

Slide 53

Slide 53 text

Location Tracker •  Stores data locally in PouchDB •  Front end built with AngularJS •  Authentication logic built with Node.js •  User interface built with Leaflet •  Replicates location data to Cloudant •  More info: https://cloudant.com/location-tracker/ 50

Slide 54

Slide 54 text

Image Credits 51 •  Joan Touzet (@wohali), ASF Member, CouchDB PMC Member •  Device landscape by Jeremy Keith, on Flickr •  Lynn Camp Prong (Explored) by AllieKF, on Flickr •  Pneumatic Central by Sleestak, on Flickr •  Ethernet IoT Starter Kit •  Grunge Warning Sign - Do Not Read This Sign by Nicolas Raymond, on Flickr •  Mango with section on a white background by bangdoll, on Flickr

Slide 55

Slide 55 text

Bradley Holt Developer Advocate [email protected] @BradleyHolt github.com/bradley-holt