Aller au contenu

Local-first : architecture de données locale et durable

Ce contenu est une ébauche et ne sera pas inclus dans la version de production.

Local-first : architecture de données locale et durable

Section intitulée « Local-first : architecture de données locale et durable »

Le local-first désigne une approche d’architecture logicielle où les données sont stockées et traitées prioritairement sur l’appareil de l’utilisateur, la connexion réseau et les services distants n’intervenant qu’en complément. Contrairement aux applications entièrement dépendantes du cloud, une application local-first reste pleinement fonctionnelle hors ligne, conserve la propriété des données côté client et considère la synchronisation vers un serveur comme une opération optionnelle plutôt que comme un prérequis. Cette orientation répond à des enjeux de souveraineté numérique, de résilience et de latence, en s’inscrivant dans une infrastructure personnelle, locale et durable (IPL).

Le coin de la marmotte La marmotte, elle, fait du local-first depuis toujours : ses provisions sont dans son terrier, pas dans le terrier d’un voisin qui facture l’accès au mètre cube. Quand l’hiver coupe tout, elle mange quand même. C’est exactement l’idée : votre application doit continuer à fonctionner même quand le réseau hiberne.

Le modèle repose sur plusieurs propriétés attendues :

  • Disponibilité hors ligne : l’application lit et écrit sans dépendre d’une connexion active.
  • Propriété des données : les fichiers et la base de données résident sur le poste, non sur un serveur tiers.
  • Latence minimale : les opérations de lecture et d’écriture s’exécutent localement, sans aller-retour réseau.
  • Longévité : les données restent lisibles même si le service distant disparaît, à condition d’utiliser des formats ouverts.
  • Synchronisation convergente : lorsque plusieurs appareils modifient les mêmes données, un mécanisme de fusion garantit un état cohérent.

Ces propriétés distinguent le local-first du simple cache hors ligne, où les données appartiennent toujours au serveur et où le poste ne détient qu’une copie temporaire.

Le coin de la marmotte Attention au faux ami : une réserve de noisettes empruntée n’est pas une réserve de noisettes. Un cache hors ligne, c’est une copie que le serveur peut révoquer, invalider ou vider au prochain démarrage. Le local-first, c’est le titre de propriété du terrier.

Une application local-first s’appuie sur un moteur de stockage embarqué. Selon le contexte, il s’agit d’un fichier structuré (JSON, SQLite), d’une base relationnelle légère ou d’un magasin clé-valeur. Le principe directeur consiste à faire du poste la source de vérité pour l’écriture.

Un exemple minimal avec SQLite illustre la persistance locale sans serveur distant :

CREATE TABLE note (
id TEXT PRIMARY KEY,
titre TEXT NOT NULL,
corps TEXT,
maj_le INTEGER NOT NULL -- horodatage epoch pour la synchronisation
);
INSERT INTO note (id, titre, corps, maj_le)
VALUES ('a1b2', 'Brouillon', 'Contenu local', 1717000000);

Pour des besoins relationnels plus riches, un moteur comme PostgreSQL (PostgreSQL est un système de gestion de base de données relationnelle) peut être déployé sur une machine du foyer (un NUC (Next Unit of Computing) ou un NAS (Network Attached Storage)) afin de conserver la logique local-first à l’échelle d’un réseau domestique.

Le coin de la marmotte La marmotte creuse plusieurs galeries, mais une seule chambre de réserve. Traduction : multipliez les copies de sauvegarde, jamais les sources de vérité. Deux écritures qui se croient toutes les deux légitimes, c’est le début d’un long après-midi de réconciliation manuelle.

Dès que plusieurs appareils modifient les mêmes données, la question du conflit d’écriture se pose. Trois familles de stratégies existent :

  1. Last-Write-Wins (dernier écrit gagnant) : l’enregistrement portant l’horodatage le plus récent l’emporte. Simple, mais susceptible d’effacer des modifications concurrentes.
  2. Journaux d’opérations : chaque appareil enregistre une suite de changements que le serveur rejoue dans l’ordre.
  3. Conflict-free Replicated Data Types (CRDT, types de données répliquées sans conflit) : structures de données conçues pour fusionner automatiquement des répliques divergentes sans coordination centralisée.

Les CRDT constituent la brique la plus aboutie pour le local-first collaboratif. Formellement, une réplique converge lorsque la fusion est commutative, associative et idempotente : l’ordre d’application des opérations n’influence pas l’état final. Cette propriété de convergence peut s’exprimer, pour deux états aa et bb et une fonction de fusion \sqcup, par :

ab=baet(ab)c=a(bc)a \sqcup b = b \sqcup a \quad\text{et}\quad (a \sqcup b) \sqcup c = a \sqcup (b \sqcup c)

Le coin de la marmotte Last-Write-Wins, c’est la marmotte qui range sa noisette par-dessus celle de sa cousine : ça tient, mais quelqu’un a perdu son goûter sans être prévenu. Les CRDT, c’est le compartiment où les deux noisettes rentrent, dans n’importe quel ordre, sans se disputer. Plus de travail à creuser, beaucoup moins de regrets au printemps.

La synchronisation optionnelle passe par un canal réseau. Un serveur de relais peut être publié via un reverse proxy (proxy inverse) et sécurisé par TLS (Transport Layer Security). Pour éviter toute exposition publique, un VPN (réseau privé virtuel) restreint l’accès aux seuls appareils autorisés. Lorsqu’un point de présence en périphérie est souhaité, des services comme Cloudflare fournissent un chiffrement du transport et une protection contre les abus, sans remettre en cause la primauté locale des données.

Exemple d’utilisation de TLS avec OpenSSL pour générer un certificat auto-signé

Section intitulée « Exemple d’utilisation de TLS avec OpenSSL pour générer un certificat auto-signé »
Fenêtre de terminal
# Générer une clé privée RSA 2048 bits
openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048
# Générer un certificat auto-signé valide 365 jours
openssl req -new -x509 -key key.pem -out cert.pem -days 365 -subj "/CN=localhost"

Ce certificat peut ensuite être utilisé pour sécuriser un serveur local via TLS.

Le coin de la marmotte Un terrier a peu d’entrées, et chacune est surveillée. Faites pareil : un seul point d’entrée, chiffré, et de préférence accessible uniquement depuis le VPN. Ouvrir un port « juste pour tester » se termine rarement par un test.

Conteneurisation et déploiement du composant de synchronisation

Section intitulée « Conteneurisation et déploiement du composant de synchronisation »

Le serveur de synchronisation, lorsqu’il existe, gagne à être isolé dans un conteneur pour la reproductibilité. Un service exécuté avec Docker (plateforme de conteneurisation) ou Podman démarre une base et un point de synchronisation :

services:
sync:
image: postgres:16
environment:
POSTGRES_DB: notes
POSTGRES_PASSWORD: motdepasse
volumes:
- ./data:/var/lib/postgresql/data
ports:
- "127.0.0.1:5432:5432" # exposition limitée à la boucle locale

L’écoute restreinte à 127.0.0.1 illustre un point de vigilance : le composant distant ne doit jamais être ouvert sans contrôle d’accès explicite.

  • Chiffrement au repos : les données locales exposées sur un poste volé doivent être protégées ; le chiffrement du disque et le chiffrement des données au repos réduisent ce risque.
  • Sauvegardes : la primauté locale n’exclut pas la perte matérielle ; une stratégie de sauvegardes régulière et testée reste indispensable.
  • Formats ouverts : privilégier des formats documentés garantit la longévité et évite l’enfermement propriétaire.
  • Cohérence multi-appareils : un modèle de fusion mal choisi entraîne des pertes silencieuses de données ; le choix Last-Write-Wins doit être conscient de ses limites.
  • Migration de schéma : faire évoluer la structure locale sur des appareils déconnectés impose des migrations idempotentes et rétrocompatibles.

Le coin de la marmotte La marmotte vérifie ses réserves avant l’hiver, pas pendant. Une sauvegarde jamais restaurée n’est pas une sauvegarde, c’est une intention. Programmez une restauration de test dans un répertoire temporaire, une fois par saison : c’est le seul moment où découvrir un problème coûte encore peu.

Quelle différence entre local-first et offline-first ?

Section intitulée « Quelle différence entre local-first et offline-first ? »

L’offline-first garantit le fonctionnement sans connexion, mais considère souvent le serveur comme la source de vérité. Le local-first va plus loin : il place la propriété et l’autorité des données sur l’appareil de l’utilisateur, la synchronisation restant secondaire.

Le local-first empêche-t-il la collaboration multi-utilisateurs ?

Section intitulée « Le local-first empêche-t-il la collaboration multi-utilisateurs ? »

Non. La collaboration reste possible grâce à des mécanismes de synchronisation convergents, notamment les Conflict-free Replicated Data Types (CRDT), qui fusionnent automatiquement les modifications concurrentes sans serveur d’arbitrage central.

SQLite (moteur de base de données relationnelle embarqué) convient à une application mono-poste grâce à sa persistance en fichier unique et sa lecture-écriture locale. Pour un usage réparti sur plusieurs machines d’un même réseau, un moteur relationnel serveur comme PostgreSQL offre davantage de contrôle sur la concurrence et les transactions.

Le local-first supprime-t-il tout besoin de serveur ?

Section intitulée « Le local-first supprime-t-il tout besoin de serveur ? »

Pas nécessairement. Un serveur peut subsister pour la synchronisation, la sauvegarde ou le partage, mais son indisponibilité ne bloque jamais l’usage local de l’application.