La plupart des applications traitent le manque de connexion comme un accident. Vous ouvrez un écran, le réseau disparaît et cet avertissement décourageant apparaît : pas d'Internet, réessayez. L’application abandonne, tout comme l’utilisateur.
Offline-first inverse cette logique à partir de zéro. Le principe est que l’absence de connexion est l’état normal et que sa présence est le bonus. Ce n'est pas du pessimisme, c'est du réalisme. Quiconque crée des applications hybrides sur le terrain, mobiles ou Web sait que le réseau échoue plus que nous ne voudrions l'admettre.
Traitez le mode hors ligne comme une règle et non comme une erreur
La différence commence dans l'esprit du designer. Dans le modèle commun, le chemin heureux consiste à être en ligne, et le hors-ligne est une mauvaise déviation à traiter plus tard, généralement de manière mauvaise. En mode hors ligne, la voie heureuse suppose déjà qu’il n’y a peut-être pas de réseau.
Ce changement de principe modifie les décisions à tous les niveaux. L'écran ne peut pas dépendre d'un appel à distance pour afficher le contenu. L'action de l'utilisateur ne peut pas être suspendue en attendant la confirmation du serveur. Le flux doit être conçu pour être exécuté localement et réconcilié ultérieurement.
Lorsque vous concevez ainsi, quelque chose d’intéressant arrive également à l’utilisateur en ligne. Puisque tout répond d’abord localement, l’expérience est plus rapide même avec un excellent réseau. En pratique, la priorité hors ligne est un sur-ensemble de la philosophie de la priorité locale, appliquée au cas le plus hostile.
Enregistrez d'abord le local, toujours
Le cœur de l’approche repose sur une règle simple : toute écriture se produit d’abord sur l’appareil. L'interface lit à partir de ce stockage local et reflète le changement à la volée. L'utilisateur n'attend jamais que le serveur voie le résultat de sa propre action.
Dans le navigateur, le stockage de choix pour cela est généralement IndexedDB. Il s'agit d'une base de données intégrée dans la page elle-même, capable de stocker des volumes considérables de données structurées, avec prise en charge des index et des requêtes. Contrairement aux solutions plus simples, elle gère le poids d’une véritable application, et pas seulement quelques préférences vagues.
La couche d'interface traite désormais IndexedDB comme source de lecture. Le serveur devient une deuxième couche, alimentée par la synchronisation. Cette conception nécessite de la discipline, car il y a désormais deux endroits où réside la matrice, et ils doivent converger sans que l'utilisateur ne remarque la couture.
Dans les applications mobiles natives, le principe est identique, seule la technologie de stockage change. Ce qui compte, c'est la règle : le local d'abord, le distant ensuite.
La file d'attente de synchronisation et ses détails
Si l'écriture a lieu hors ligne, elle doit être transmise au serveur ultérieurement. C'est là qu'intervient la file d'attente de synchronisation. Chaque action qui modifie les données est enregistrée comme une intention en attente, stockée localement, en attendant que la fenêtre de connexion se lève.
Cela semble simple, mais le diable se cache dans les détails. La file d'attente doit survivre à la fermeture de l'application. Vous devez réessayer lorsque la livraison échoue, sans dupliquer ce qui a déjà été envoyé. Il faut respecter l'ordre des opérations, car créer un enregistrement puis le modifier sont des choses qui ne s'échangent pas sur le serveur.
Je recommande de considérer chaque opération en file d'attente comme idempotente autant que possible. L'idempotence signifie que soumettre à nouveau la même opération ne cause pas de dommages. Cela fait de la synchronisation une source de bugs subtils et un processus prévisible car vous pouvez réessayer sans crainte.
Il existe également une rétrosynchronisation. Pendant que l'appareil était hors ligne, le monde continuait : d'autres utilisateurs modifiaient, le serveur changeait. Lorsque la connexion revient, vous devez apporter ces changements et fusionner avec l'État local. Et c’est dans la fusion que se pose le problème le plus épineux.
Lorsque deux appareils modifient les mêmes données
Imaginez deux agents de terrain ouvrant la même inscription hors ligne. L'un corrige l'adresse, l'autre corrige le numéro de téléphone. Les deux ont à nouveau le signal et se synchronisent. Quelle version gagne ? La réponse naïve, la dernière arrivée écrase tout, fait perdre silencieusement son travail à l'un d'entre eux. Inacceptable.
La résolution des conflits est le thème central de quiconque prend au sérieux le hors ligne. La stratégie la plus simple, gagnante au fil du temps, fonctionne pour des données peu contestées, mais échoue gravement lorsque des vérifications concurrentes touchent différents champs du même enregistrement.
De meilleures stratégies fusionnent par domaine, préservant le changement d'adresse pour l'un et le numéro de téléphone pour l'autre. Pour les structures plus complexes, les CRDT entrent en jeu, des types de données conçus pour converger automatiquement lors de la fusion, sans avoir besoin d'un arbitre central. Cela vaut la peine d'étudier le fonctionnement pratique des CRDT avant d'inventer votre propre logique de fusion, car c'est un domaine semé d'embûches.
Ma recommandation honnête : ne traitez pas les conflits comme un cas rare et improvisez à la fin du projet. Définir précocement, pour chaque type de données, la règle de convergence. Cette décision est autant une décision de produit qu’une décision d’ingénierie, car elle définit ce qui arrive au travail de deux personnes réelles.
L'impact sur l'expérience de ceux qui l'utilisent
Tout cela existe pour servir une expérience, et l’effet sur celle-ci est grand. Une application hors ligne répond à la vitesse du toucher, et non du réseau. Pour ceux qui travaillent sur le terrain, c’est la différence entre un outil fiable et une nuisance qui tombe en panne au pire moment.
Mais il faut être honnête avec l’utilisateur. Étant donné que la synchronisation s'effectue en arrière-plan, vous avez besoin de signaux d'état clairs : ce qui s'est passé, ce qui est en attente, si quelque chose s'est mal passé. Cacher cela crée un faux sentiment de sécurité, et une fausse sécurité est pire qu’une insécurité ouverte.
Les bonnes applications hors ligne communiquent sans faire peur. Un indicateur discret des problèmes en suspens, un avertissement lorsqu'un conflit nécessite une décision, une confirmation sereine lorsque tout est synchronisé. L'utilisateur n'a pas besoin de comprendre l'ingénierie, mais il doit être sûr que son travail ne s'évaporera pas.
Par où doit commencer une équipe
Si vous dirigez une équipe sur le point d’adopter d’abord le mode hors ligne, évitez l’erreur de tout essayer en même temps. Commencez par le stockage local et lisez-le. Introduisez ensuite la file d'attente de synchronisation pour les écritures. Alors seulement, affrontez le conflit et affrontez-le par type de données, et non de manière générique.
Résistez également à la tentation de créer votre propre moteur de synchronisation à partir de zéro. C'est un problème séduisant et profond, mais résolu par des outils matures. Comprendre les options des moteurs de synchronisation prêts pour le local-first](/post/sync-engines-local-first) peut faire gagner des mois à votre équipe.
Le hors-ligne n'est pas un luxe technique, c'est une manière de respecter la réalité de ceux qui utilisent le logiciel loin du confort d'un réseau parfait. Ceux qui conçoivent avec ce principe proposent des produits qui continuent de résister exactement quand cela compte le plus.
A lire aussi
- Lieu réel d'abord : gouvernement, soins de santé et logistique
- Local-First : logiciel qui fonctionne en premier sur votre appareil
- Moteurs de synchronisation : les outils qui rendent le local first viable
- CRDT : comment synchroniser les données sans serveur pour arbitrer les conflits
- Quand utiliser PWA
- [Application hybride Qu'est-ce que 9
