Slide 1

Slide 1 text

Christian Weyer | Thinktecture AG Auch ohne Netz Offline-First Architekturen für HTML5 Apps

Slide 2

Slide 2 text

Christian Weyer • Co-founder, co-owner and principal consultant at Thinktecture AG • Focus on – Mobile & web-based application architectures – Interoperability, cross-device – Pragmatic end-to-end solutions • Microsoft MVP for ASP.NET (Architecture) ASP.NET Web API / vNext Advisory Board Member ASPInsider, AzureInsider • Google GDE for AngularJS • http://blogs.thinktecture.com/cweyer christian.weyer@thinktecture.com @christianweyer 2

Slide 3

Slide 3 text

Talking Points • Offline-First as a Must • Users Matter • When is “Offline”? • Caching • Data Storage • Synchronization 3

Slide 4

Slide 4 text

Offline-First • Mobile-First is hip – … but it is not enough • Few web sites are designed to work offline • Few web apps are designed to work offline • Few mobile apps are designed to work offline • Offline-First == User-First 4

Slide 5

Slide 5 text

Offline is not an error! 5

Slide 6

Slide 6 text

Given Facts – Offline is everwhere • Countryside • Flight • Train • Costs • Roaming • Decide what „offline“ means to you/your apps 6

Slide 7

Slide 7 text

7

Slide 8

Slide 8 text

8

Slide 9

Slide 9 text

9

Slide 10

Slide 10 text

10

Slide 11

Slide 11 text

User Experience • Let people interact with their content • Aggressive caching is a better user experience • Make error messages informative and consistent • Don’t show contradictory information • Don’t let people start something they can’t finish 11

Slide 12

Slide 12 text

User Experience • When caching, choose breadth over depth • Design your empty states well • Never show the raw error message • Remember what your users were doing last • Never purge the cache while offline 12

Slide 13

Slide 13 text

When is „offline“, anyway? 13

Slide 14

Slide 14 text

Detect Status: Browser Events • Status properties & events • May be unreliable with different results on various platforms • Need to write algorithm to ping well-known endpoint 14 window.addEventListener('load', function() { var status = document.getElementById("status"); function updateOnlineStatus(event) { var condition = navigator.onLine ? "online" : "offline"; status.className = condition; status.innerHTML = condition.toUpperCase(); } window.addEventListener('online', updateOnlineStatus); window.addEventListener('offline', updateOnlineStatus); });

Slide 15

Slide 15 text

Browser Events - Platforms 15

Slide 16

Slide 16 text

Caching • Static vs. Dynamic caching 16

Slide 17

Slide 17 text

HTML5 AppCache • Adding static data/files to dedicated browser cache area – Based on root web page • Manifest describes what to cache • API to detect updates and act accordingly • Can be tough to test and debug • Usage information in browsers – chrome://appcache-internals/ in Chrome – help appcache in Firefox Developer Toolbar 17

Slide 18

Slide 18 text

AppCache Manifest & API 18 ... CACHE MANIFEST # v1 2015-09-14 # This is another comment index.html cache.html style.css image1.png # Use from network if available NETWORK: network.html /api # Fallback content FALLBACK: / fallback.html if (window.applicationCache) { window.applicationCache.addEventListener( 'updateready', function() { if (confirm('An update is available. Reload now?')) { window.location.reload(); } }); }

Slide 19

Slide 19 text

HTML AppCache - Platforms 19

Slide 20

Slide 20 text

Service Workers • Browser-based applications need to perform work “outside the browser” • Rich offline experiences • Periodic background sync • Push notifications • … and more native-like functionality 20

Slide 21

Slide 21 text

Service Workers • JavaScript Workers • Implement Lifecycle with events • Browser support to question – Especially on mobile platforms 21

Slide 22

Slide 22 text

Service Workers - Platforms 22

Slide 23

Slide 23 text

Data Storage 23

Slide 24

Slide 24 text

Web Storage • Two types of storage: Session and Local • Stores key/value pairs – Simple types & JSON • Properties – Storage.length • Methods – Storage.key() – Storage.getItem() – Storage.setItem() – Storage.removeItem() – Storage.clear() 24

Slide 25

Slide 25 text

25

Slide 26

Slide 26 text

Session & Local Storage • sessionStorage and localStorage properties on window object • Difference – data stored in localStorage has no expiration time – data stored in sessionStorage gets cleared when the browsing session ends 26

Slide 27

Slide 27 text

Web Storage - Platforms 27

Slide 28

Slide 28 text

Web SQL 28

Slide 29

Slide 29 text

Web SQL - Platforms 29

Slide 30

Slide 30 text

IndexedDB • NoSql database in the browser • Store and retrieve objects that are indexed with a key – rich query abilities • Changes to the database happen within transactions • Useful for applications that store large amount of data – Also for blobs • API can be challenging to use 30

Slide 31

Slide 31 text

Dexie.js – IndexedDB Wrapper 31 var db = new Dexie('MyDatabase'); // Define a schema db.version(1) .stores({ friends: 'name, age' }); // Open the database db.open() .catch(function(error){ alert('Uh oh : ' + error); }); // Find some old friends db.friends .where('age') .above(75) .each(function(friend){ console.log(friend.name); }); // or make a new one db.friends .add({ name: 'Camilla', age: 25 });

Slide 32

Slide 32 text

IndexedDB - Platforms 32

Slide 33

Slide 33 text

Storage Abstractions • Sometimes you need an abstraction over the different stores • Mozilla‘s localForage is one of them 33 // In localStorage, we would do: localStorage.setItem('key', JSON.stringify('value')); doSomethingElse(); // With localForage, we use callbacks: localforage.setItem('key', 'value', doSomethingElse); // Or we can use Promises localforage.setItem('key', 'value').then(doSomethingElse);<

Slide 34

Slide 34 text

Synchronization • „Offline“ heavily depends on use cases • Sometimes data needs to be synchronized – From server to device – From device to server • Conflicts will happen, for sure – Conflict resolution is king, but tough – Solutions based on functional requirements & logic • Certain architecture types can help – Like CQRS 34

Slide 35

Slide 35 text

Conflicts “Conflicts are not an error condition, they are the result of your infrastructure allowing the same dataset to be modified across disconnected systems. The introduction of such conflicts in such a topology is the expected behavior and their programmatic resolution is a core piece of application logic.” 35 https://cloudant.com/blog/introduction-to-document-conflicts-part-two

Slide 36

Slide 36 text

CQRS Command Query Responsibility Segregation 36

Slide 37

Slide 37 text

CouchDB & PouchDB • Apache CouchDB – Database that uses JSON for documents – JavaScript for MapReduce indexes – Regular HTTP for its API • PouchDB – Open-source JavaScript database – Inspired by CouchDB – Designed to run well within the browser • PouchDB can sync with CouchDB – Consider checking the inner workings of the sync protocol 37

Slide 38

Slide 38 text

Summary • Offline should not be an exception • Prepare your architecture and your applications for being offline • Think about your users first! • Browsers have simple storages and powerful databases available • Synchronization can be complex and tedious – It all depends on the use cases 38

Slide 39

Slide 39 text

Resources • Offline: When Your Apps Can’t Connect to the Internet – https://medium.com/user-experience-design-1/offline-93c2f8396124 • Mobile Apps Offline Support – http://www.infoq.com/articles/mobile-apps-offline-support • Introduction to CQRS – http://www.codeproject.com/Articles/555855/Introduction-to-CQRS • Working with quota on mobile browsers – http://www.html5rocks.com/en/tutorials/offline/quota-research/ • AppCache Nanny – https://github.com/gr2m/appcache-nanny • Gulp-manifest – https://github.com/hillmanov/gulp-manifest 39

Slide 40

Slide 40 text

Resources • WebStorage API – https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API • IndexedDb API – http://w3c.github.io/IndexedDB/ • Storing images and files in IndexedDB – https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/ • Dexie.js – https://github.com/dfahlander/Dexie.js/wiki/Samples • LocalForage – http://mozilla.github.io/localForage/ • Apache CouchDB – http://couchdb.apache.org/ • PouchDB – http://pouchdb.com/ 40

Slide 41

Slide 41 text

Resources • christian.weyer@thinktecture.com • http://www.thinktecture.com • Thinktecture’s GitHub Repositories – https://github.com/thinktecture • Christian Weyer’s GitHub Repositories – https://github.com/ChristianWeyer 41