layout: true --- class: center, bkg-gradient-rock,bkg-bottom # Développer des applications résistantes
à des conditions dégradées --- class: middle
Aleth Gueguen conseil IT
Consultante indépendante depuis 2006
Je développe des logiciels sur mesure pour les PME
??? Quand je parle de logiciels, c'est essentiellement basé sur la techno WEB donc c'est de ça qu'on va parler aujourd'hui même si ce que je raconte ça peut s'appliquer à d'autre technos --- class: bkg-vertical-right background-image: url(../_images_bateau/rochers_remous_cropped.jpg) # Conditions dégradées .absolute.arrowcond[] .mt12[ ## .tag1[Pas de réseau] ] ## .tag1[Réseau intermittent / Latence] ## .tag1[Batterie faible] ## .tag1[Appareil entrée de gamme / ancien] --- class: bkgx156-y0, no-margin-h background-image: url(image/chantier.jpg) # Équipes sur le terrain - Chantiers en zone blanche ou grise - Usine - Extérieur > Pas de prise de courant pas de recharge pendant la journée de travail -- .mt3-5[ ## .tag1[Mais aussi] ] .small[ - Ado en galère, accède à un site d’aide sociale avec une PS2 de seconde main - En zone de montagne pendant et après une tempête ] ??? Quelques cas impressionnant où un ensemble de [struggle] se combinent - Hivernant au Pôle Sud, Internet dispo pendant quelques heures quand le satellite passe au zenit de la station --- name: qualites # Les deux faces opposées du Web ##  Navigateurs présents partout ##  On ne maitrise pas l’environnement d’éxécution - Ressources disponibles : RAM / CPU / vitesse - Version du navigateur - Taille d’écran - État de la batterie ??? le + : distribution universelle, tout (ou presque) embarque un navigateur le - : on ne maitrise pas du tout les appareils sur lesquels notre code tourne. Et c'est pas forcément des foudres de guerre --- class: bkg-vertical-right, cores background-image: url(../_images_bateau/lac-volcan.jpg) ## Aggravé dans le cas des appareils mobiles .tag2[L’accès au réseau n’est jamais certain ] .tag2[CPU peu puissants sur la majorité des appareils]  ??? 5G ou pas / Intermittence / Latence La majorité des smartphone, c'est de l'android milieu ou entrée de gamme on peut considérer que le web c'est un environnement hostile --- class: bkg-vertical-r102, nav-bat background-image: url(../_images_bateau/bateau-en-marche.jpg) # Navigation en bateau à voile .tag2[Environnement réaliste
pour les conditions dégradées]
Pas toujours
Contrainte
??? Il se trouve que j'ai un mode de vie où je passe plusieurs mois par an sur mon bateau. J'y vis et j'y travaille Et ça m'a permis de d'expérimenter en conditions réelles ces fameuses conditions dégradées --- class: center, middle,bkg-vertical-left background-image: url(../_images_bateau/panneau_solaire.jpeg) .mon-lab.absolute[ # Mon lab R&D ] .absolute.pv100w[Paneau solaire 100W
priorité aux instruments
nav / pilote / météo / AIS] .absolute.pv-arrow[ ] .absolute.pas-partout[Réseau = pas partout] .absolute.carte-manche[ ] ??? La question du réseau, oui il y a la solution d’internet par satellite Est-ce que c’est ça qu'on veut ? Plusieurs milliers de satellites / plusieurs constellations / des réentrées [x par jour] avec la pollution que ça entraine --- class: center, bkg-vertical-0 background-image: url(../_images_bateau/scilly-2023-2.jpg) name: expe .ml50[ # Comment faire ## pour fournir une expérience positive malgré tout ? .w-max-content.mauto.left[ ### .tag1[Limiter la taille du code à éxécuter] Enlever la dépendance au manque de ressource ### .tag1[Éxécuter les tâches en local] Enlever la dépendance au réseau ] ] --- name: fondamentaux class: middle, bkg-vertical-right background-image: url(../_images_bateau/cygne_cropped_vertical.jpg) # Revenir aux fondamentaux .tag2[Les vertus cachées du “plateforme native”] ??? Le web a tellement évolué depuis ces 10 dernières années qu'on peut utiliser les API natives pour obtenir les mêmes fonctionalités qui autrefois étaient fourni par des librairies externes --- name: ux-html # HTML, le langage du WEB .retro[Rétrocompatible] .list-img[ - UX de HTML ] --- name: html-moderne # HTML, le langage du WEB .retro[Rétrocompatible] .list-img[ - UX de HTML - HTML moderne ] --- name: css-moderne # HTML, le langage du WEB .retro[Rétrocompatible] .list-img[ - UX de HTML - HTML moderne - CSS moderne  grid, animation, scroll ] --- class: img72  .absolute.nav.dejavu[⬅️ Navigateur optimisé pour parser et afficher du HTML] .absolute.arrow.resized[] .absolute.mille.dejavu[1000 × < tr >] --- class: limites,bkg-vertical-right, relative background-image:url(../_images_bateau/falaise_noire.jpeg) # HTML/CSS.limites-h1[a aussi besoin de JS] .list-img[.absolute.acc[] - Persistence des données - Gestion du cache de l’application (hors-ligne) - Accessibilité (en partie) ].resist[C’est ce qui fait la résistence aux conditions dégradées ] ??? Même si on va déjà très loin avec HTML/CSS y a certaines choses que ça gère pas : enregistrer son travail, ce qu'on a écrit, ses notes sur sa machine (dans le navigateur) Afficher les pages depuis le navigateur sans faire une requête à travers le réseau --- class: center, middle,js-natif
??? Et ça, Js natif/vanilla/ sait le faire. Depuis 10 ans --- class: no-build, middle .dflex[
.list-img.flex-2[ - Code rétrocompatible, pas de “breaking change” - Pas de dépendance aux spécificités d’un framework .tag2.bugue[si ça bugue, c’est ton code] - Pas de code supplémentaire à télécharger, parser, éxécuter - Pas de chaine de build ] ] ??? Pas de code supplémentaire(celui du framework) à télécharger, parser, éxécuter Pour quoi j'insiste tellement sur l'inutilité d'un framework pour s'adapter ? Parce que ça nous permet de s'affranchir du manque de ressources sur la majorité des appareils mobiles --- class: sync, bkg-multi background-image: url(image/multi_screens_app_ates.png) # Méthode de construction pour des web apps professionnelles - Travail réalisé en local - Données persistées dans indexedDB - Synchronisation avec serveur/back-office distant quand les conditions le permettent ??? Ce que je vous raconte, c'est tiré de ce que développe pour des applis pro tout le process se passe en local / tire parti du cache d’application iDB embarquée nativement dans navigateur on peut voir ça comme un mini back-office pour 1 et qui synchro le travail avec le serveur distant quand les conditions le permettent --- class: bkg-action-pg, relative background-image: url(image/action_page.png) .absolute.tag2.cache[cache] .ml47[ # Principes généraux .no-ul[ 1. Une action = Une page 2. Pas d’état : données enregistrées dans indexedDB, paramètres propagés dans l’URL si besoin 3. Modifier le DOM, pas de repaint / re-render 4. “Event delegation” : écouter sur l’élément de niveau supérieur ] ] --- class: no-margin-h, cache # Servir une page en local avec un service Worker .dflex.cache-wrapper[.absolute.legend.tag2[cache].flex-1.list-doc[ - style.css - lib1.js - lib2.js - font.ttf - image.png ].list-doc.second[ - home.html .absolute.file[.cached-response.tag2[].response[/home]] - homeController.js - report-form.html .absolute.file[.cached-response.tag2[].response[/new-report]] - newReportController.js - list.html .absolute.file[.cached-response.tag2[].response[/list]] - listController.js ]] .smaller[Librairie WorkBox pour abstraire la gestion du cache https://developer.chrome.com/docs/workbox/modules/workbox-cli#injectmanifest ] ??? Les SW servent entre autre à gérer le cache d’application Un SW a un cycle de vie : install, activate, ... L’API SW est assez bas niveau => bcp de boilerplate --- class: bkg-top background-image: url(image/page-controller.png)
--- name: controller .tag3[/public/js/pages/newReportController.js ]
.dflex.noshow[ ```js //public/js/pages/newReportController.js // 1. imports import * as iDBStorage from './libs/iDBStorage.js' import importPhoto from './components/importPhoto.js' // 2. cache DOM refs const elts = { myEl: document.querySelector('[data-someting]'), // ... } // 3. const, let + ‘theThing’ // ... // 4. Initialize web components customElements.define('import-photo', importPhoto) // 5. Templates function function entryRowTmpl(row) { return `
${row.col1}
${row.col2}
${row.col3}
Menu
` } // 6. eventHandlers // 7. eventListener // 8. init() // 9. local utility functions // 6. eventHandlers const changeHandler = { changeThing: (event) => { // do Stuff // persist the thing in indexedDB }, handleEvent: (event) => { let handler = event.target.dataset[event.type] if (!handler || !this[handler]) { return } this[handler](event) } } // 7. eventListener formElement.addEventListener('change', changeHandler) // 8. init() function init() { // get theThing from iDBStorage // doStuff } // 9. local utility functions // Call init init() ``` ] --- name: custom-elt background-image: url(../_images_bateau/combo-mini-phare-ilot.jpg) # Web component .struct.tag1[pour modulariser] .dflex.code[ .ldom.absolute.tag2[light DOM] .absolute.arrow-y[] []  ] .dflex.noshow[ .text-left[ ```html
``` ] .text-left[ ```js export default class importPhoto extends HTMLElement { connectedCallback() { this.displayElt = document.getElementById( this.getAttribute('display-elt')) this.fileInput = document.querySelector( 'input[name=photos']) this.addEventListener('change', this) } handleEvent(event) { // do stuff } } ``` ] ] ??? si beaucoup de fonctionnalités différentes dans la page .small[meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the-light-dom] --- class: bkg-left, bkg-bottom, relative background-image: url(image/persist_iDB.png) # Persister les données dans indexedDB
indexedDB permet de
stocker des objets JS
Création d’un object store et de l’index
.dflex.noshow[.flex-1[ ```js const db = await openDB('myAppDb', DB_VERSION, { async upgrade(db, oldVersion, newVersion, transaction) { const reports = v1Db.createObjectStore('reports', { keyPath: 'name', unique: true, }) reports.createIndex('reportStatus', 'status') } }) ``` ].flex-1[ ```js let report = { timestamp: Math.ceil(today.getTime() / 1000), categorie: null, lat: null, lon: null, content: '', photoFileNames: [], status: 'transmission_pending' } ``` ]] ??? iDB présent dans tous les navigateurs BDD par défaut object store API ancienne à base de callback --- class: bkg-vertical-left, results background-image: url(../_images_bateau/regate-deriveurs.jpg) .ml60[ # Résultats - Performance ressenti «instantané» pour une page de formulaire +250 input - Données persistées en local pendant plusieur mois - Synchronisation en tâche de fond ] ??? ça marche. ça marche même très bien Livrer uniquement le code dont on a besoin, ça fait une grosse différence en terme de performance Anecdote s/ demande ressenti instantané > “je détruis l'écran si ça réagit pas immédiatement au tap” Dans Android au moins j'ai testé les données persistées dans iDB et dans le cache ça tient plusieurs mois > pas loin d'un an --- class: center, bkg-cover background-image: url(image/grenouille.jpeg) .bkg-gradient-green[ # Quelques observations ] ??? Alors, est-ce que j'ai trouvé la martingale parfaite ? Certainement, non ! Il ya pas mal d’inconnues encore et de freins --- class: bkg-vertical-right, ref-ux background-image: url(../_images_bateau/shipping_kiel_canal_cropped.jpg) .center.fit-content[ # 1. Comprendre où sont
mes données]  .tag2.absolute[Refléxion sur l’UX] ??? Cloud vs local Concept du stockage ça n'a rien d’évident pour une personne utilisatrice de comprendre où est stocké ce qu'elle produit Photos, textes, ... Là on est vraiment dans le dématérialisé Ne sais pas discriminer entre ce qui est remonté vers un serveur distant “le cloud” et ce qui est présent en local dans son appareil. Ne sais pas faire la différence entre ce qui est "public/publié" et ce qui est non-accessible au regard extérieur --- class: coutures # Rendre les «coutures» visible .list-img[ - .tag1[Montrer les opérations de synchronisation] .after[Ce qui est “chez moi” vs ce que je veux “remonter” dans un serveur distant] - .tag1[Rendre visible l’intermittence du réseau] .after[Est-ce que j’ai assez de bande passante ? C’est quoi le débit là où je suis ?] - .tag1[Rendre la main] .after[Laisser la décision SI ET QUAND je déclenche une opération de synchro] ] ??? Je vous livre des premières pistes sur lesquelles je me suis penchée mais c'est loin d'être très avancé opé de synchro, souvent c'est complètement transparent. La machine gère ça dans son coin et on ne sait pas ce qu'elle fait. --- class: bkg-vertical-right, sync-actions background-image: url(../_images_bateau/oiseau_rocher.jpg) # «Matérialiser» les actions de synchronisation Différencier les données texte.absolute.legere[] et les photos/fichiers.absolute.lours[] - Donner le choix - Aider à décider (poids / état du réseau / ...)
??? Un autre option, que j'ai développé pour une app de navigateurs l'équivalent de polarstep, pour les gens qui naviguent --- class: bkg-vertical-0 background-image: url(../_images_bateau/baleiniere.jpg) .ml47[ # 2. Justifier ses choix techniques Ce que le client veut en priorité : C’est que **ça marche** Dans un futur à peu près connu Que ça tombe pas en panne .tag1.smaller[Le choix technique n'est pas le problème du client] ] --- name: objections class: bkg-vertical-right-narrow background-image: url(../_images_bateau/falaise.jpg) # Répondre aux objections ## Développement moins risqué, plus rapide, moins cher .relative.aligne[Aligné avec le .rgen.tag1[Référentiel général d’écoconception de services numériques]] ## Maintenabilité .tag2.small.absolute[«Sans framework
on a du code “code spagetti”»] Structurer le code Former au web natif.absolute.dble[] ## Frein au recrutement ??? Méthodes de structuration du code > connues et appliquées Poule et œuf Offre de formation / Offre sur marché de l’emploi Les entreprises recrutent des dev React parce qu'ils sont nombreux ## C’est le rôle des organisations de prendre leurs décisions tech en fonction de leur produit et des besoins clients Fenêtre d’Overton pour passer au web natif Les écoles / bootcamp forment à React parce que c'est demandé sur le marché de l’emploi On voit apparaitre de + en + de critique sur les framework D’autres apparaissent, mais ça reste encore assez lourd comparé au natif --- class: bkg-cover, conclusion, middle, center background-image: url(../_images_bateau/scilly-2023.jpg) .ml50[ # Conclusion Web ⇨ plateforme universelle mais attention aux mobiles Rendre visible les coutures On a besoin de concepteur / designer pour proposer des solutions ] ??? environnement hostile (surtout dans le mobile) Le natif : réponse au bloatware ? Rendre visible les coutures, laisser les décisions aux gens (synchro / local // local vs cloud) On a besoin (terriblement) de concepteur / designer qui s'emparent de ces questions et proposent des réponses --- class: center, middle, bkg-cover, color-white background-image: url(../_images_bateau/rubber-duck.jpg) .mtvb[ #Questions ?]