FlowingDev

Les UUID, expliqués : l'ID unique qui ne marchera sur les pieds de personne

Un UUID est un nombre de 128 bits utilisé pour identifier de l'information de manière unique dans les systèmes informatiques, garantissant quasi-certainement que deux UUID ne seront jamais identiques.

Essayer l'outil: Générateur d'UUID

En une phrase

Un UUID est un nombre de 128 bits qui sert de numéro de série unique pour littéralement tout ce qui vous passe par la tête en informatique, avec une chance ridiculement faible d'être créé deux fois.

Le problème que ça résout

Aux débuts de l'informatique, garder une trace des choses était simple. Votre premier utilisateur avait l'ID 1, le second l'ID 2, et ainsi de suite. Cet « entier auto-incrémenté » fonctionnait super bien... tant que vous n'aviez qu'une seule base de données et un seul serveur pour créer tous les enregistrements.

Puis l'Internet est arrivé. Et les systèmes distribués. Et les microservices. Et les applications offline-first.

Soudain, plusieurs ordinateurs se sont mis à créer de nouvelles choses (utilisateurs, articles, produits, entrées de log) en même temps, sans se parler. Si un serveur à Dublin et un serveur à Tokyo essayaient tous les deux de créer le « prochain » enregistrement, ils créeraient tous les deux l'enregistrement #5830. Lors de la synchronisation ultérieure de leurs bases de données, paf : collision. Quel est le vrai enregistrement #5830 ? Et là, c'est le chaos.

C'est le problème fondamental que les UUID (Universally Unique Identifiers) résolvent : la génération d'ID uniques, de manière décentralisée et non coordonnée. Un développeur sur son portable dans un café peut créer un ID pour un nouvel élément de sa to-do list, et être statistiquement certain que personne d'autre, sur aucun autre ordinateur, dans toute l'histoire passée et future de l'univers, ne générera jamais exactement le même ID. Cela permet aux systèmes de créer des identifiants uniques de manière indépendante, ouvrant la voie aux logiciels robustes et distribués sur lesquels nous comptons aujourd'hui.

Comment ça marche sous le capot

Au fond, un UUID n'est rien d'autre qu'un grand nombre : 128 bits. Ça représente 2¹²⁸ combinaisons possibles, soit environ 340 undécillions (un 3 suivi de 37 zéros). Pour vous donner une idée, si vous génériez un milliard d'UUID par seconde, il vous faudrait environ 10 milliards d'années pour épuiser toutes les possibilités. La chance que deux UUID générés aléatoirement entrent en collision est astronomiquement faible.

Anatomie d'un UUID

Bien qu'il s'agisse d'un entier de 128 bits, on ne le voit jamais sous cette forme. Il est presque toujours représenté comme une chaîne hexadécimale de 32 caractères, découpée en cinq groupes par des tirets.

Un UUID typique (Version 4) ressemble à ça : 123e4567-e89b-42d3-a456-426614174000

Décortiquons ce format :

  • Structure : 8-4-4-4-12 (représentant 32 caractères hexadécimaux, pour un total de 36 caractères avec les tirets).
  • Données : Chaque caractère hexa représente 4 bits (un « quartet »). 32 caractères * 4 bits/caractère = 128 bits.
  • Les nombres magiques : Vous voyez le 4 au début du troisième groupe (42d3) ? Ce 4 n'est pas aléatoire. Il spécifie la version de l'UUID (dans ce cas, la Version 4). Le premier caractère du quatrième groupe (a456) a aussi une signification spéciale ; il identifie la variante, assurant la conformité avec la disposition standard. Pour la plupart des UUID que vous rencontrerez, ce sera 8, 9, A, ou B.

Un petit tour des versions

L'invite de cet outil spécifie la Version 4 (v4), qui est le type le plus courant. Mais il existe plusieurs versions, chacune avec une stratégie de génération différente.

Version Méthode de génération Cas d'usage
v1 Timestamp + adresse MAC de l'ordinateur générateur. Quand un tri basé sur le temps est nécessaire. (Rarement utilisé aujourd'hui à cause des risques pour la vie privée liés à l'exposition de l'adresse MAC).
v2 Comme la v1, mais avec des infos POSIX UID/GID en plus. Extrêmement rare. Une formalisation de la v1.
v3 Hash MD5 d'un « namespace » et d'un « nom ». Déterministe. Avec le même namespace et le même nom, on obtient toujours le même UUID. (Moins courant, MD5 a des faiblesses).
v4 Pur aléatoire. Le choix par défaut. Quand on a juste besoin d'un ID unique sans se soucier du reste.
v5 Hash SHA-1 d'un « namespace » et d'un « nom ». Le choix déterministe moderne. Même idée que la v3, mais avec une fonction de hash plus robuste.

Générer un UUID Version 4

Générer un UUID v4 est conceptuellement simple :

  1. Générer 128 bits de données aléatoires cryptographiquement sûres.
  2. Bricoler quelques bits spécifiques pour définir les champs « version » et « variante », comme l'exige le standard.
  3. Formater les 128 bits résultants en une chaîne hexadécimale avec des tirets.

Voici le pseudo-code pour l'étape de « bricolage » :

// Assuming `bits` is an array of 128 random bits (0s and 1s)

// Set the version to 4 (0100)
bits[48] = 0;
bits[49] = 1;
bits[50] = 0;
bits[51] = 0;

// Set the variant to '10x'
bits[64] = 1;
bits[65] = 0;

En réalité, la plupart des langages de programmation fournissent une fonction sur une seule ligne comme crypto.randomUUID() qui fait tout ça pour vous, en s'assurant que c'est fait correctement et de manière sécurisée. Ce qu'il faut retenir, c'est qu'un UUID v4 n'est rien de plus que 122 bits de pur hasard, enrobés dans 6 bits de métadonnées.

Histoires vécues

Le cauchemar de la fusion de bases de données

Deux startups, « Acme » et « WidgetCorp », décident de fusionner. Toutes deux ont des produits à succès, chacune avec sa propre base de données d'utilisateurs, de produits et de commandes. Lors de la première réunion d'intégration, un développeur junior demande : « Comment on va fusionner les tables d'utilisateurs ? Mon utilisateur avec l'ID 101 c'est 'Alice', mais leur utilisateur avec l'ID 101 c'est 'Bob'. » Un silence de mort s'installe dans la pièce. Absolument toutes les tables des deux bases de données utilisaient de simples ID entiers auto-incrémentés. Les fusionner serait une tâche monumentale, impliquant de réécrire les clés étrangères, de faire des références croisées pour chaque enregistrement, et de prier pour n'avoir rien oublié. Leur fusion a pris des mois de retard.

Leçon : S'ils avaient utilisé des UUID dès le départ, la fusion aurait été triviale. L'utilisateur f47ac10b-58cc-4372-a567-0e02b2c3d479 d'Acme aurait pu coexister parfaitement avec l'utilisateur 9c68a520-2a83-43a3-b45d-4c86518a28cc de WidgetCorp. Pas de collisions, pas de cauchemars. Les UUID sont essentiels pour les systèmes qui pourraient un jour avoir besoin d'interagir ou de fusionner.

Le panier d'achat ultra-réactif

Une développeuse créait une nouvelle fonctionnalité d'« ajout rapide » pour un site e-commerce. Quand un utilisateur cliquait sur « Ajouter au panier » sur une liste de produits, un spinner apparaissait pendant 1 à 2 secondes le temps que l'application attende que le serveur crée l'article dans le panier et retourne son nouvel ID. L'expérience était lente. La développeuse a eu un éclair de génie : et si l'application n'attendait pas ? Elle a modifié le code pour que, lors du clic, le navigateur génère immédiatement un UUID v4 pour le nouvel article, l'ajoute à l'état local et mette à jour l'interface instantanément. L'application semblait ultra-rapide. En arrière-plan, elle envoyait la requête au serveur en lui disant : « S'il te plaît, crée un article de panier avec cet UUID spécifique. » Si le réseau plantait, l'application pouvait simplement réessayer plus tard, en utilisant le même UUID pour éviter de créer des doublons.

Leçon : La génération d'UUID côté client permet de créer des « UI optimistes » (Optimistic UI), où l'interface se met à jour immédiatement, en supposant que l'opération réussira. Cela crée une expérience utilisateur beaucoup plus rapide et réactive, et simplifie grandement la gestion des scénarios hors ligne.

L'enquête au pays des microservices

Un client signale une erreur : sa commande a échoué, mais sa carte a quand même été débitée. Le système était un enchevêtrement complexe de microservices : Auth, Gateway, Orders, Payments, Shipping. Une seule requête pouvait rebondir entre cinq ou six de ces services. Trouver le point exact de la défaillance, c'était comme chercher une aiguille dans une botte de foin d'un million d'entrées de log par minute. L'architecte principal a imposé un changement : chaque requête entrante sur la Gateway se verrait attribuer un UUID, appelé « ID de corrélation ». Cet ID serait transmis à chaque microservice qui traitait la requête, et chaque message de log devait l'inclure. La fois suivante où une erreur s'est produite, l'équipe de support a simplement cherché cet unique UUID dans le système de logging. Instantanément, ils ont eu l'histoire complète et chronologique du parcours de la requête à travers tout le système, identifiant le service exact qui avait échoué.

Leçon : Les UUID sont inestimables en tant qu'ID de corrélation pour tracer les requêtes et déboguer dans les architectures distribuées et basées sur des microservices.

Erreurs et pièges courants

  • Utiliser les UUID comme clés primaires de base de données... à la légère. Bien que parfaits pour l'unicité, les UUID sont volumineux (16 octets contre 4 ou 8 pour un entier) et aléatoires. Le caractère aléatoire peut être désastreux pour les performances des index de la base de données, entraînant une fragmentation et des écritures plus lentes, car la base de données peine à insérer de nouvelles lignes au milieu d'un index en arbre B. Les bases de données modernes et les nouvelles versions d'UUID (comme la v7 proposée, qui est ordonnée par le temps) peuvent atténuer ce problème, mais c'est un compromis essentiel à connaître.
  • Supposer que tous les UUID sont aléatoires. Un développeur pourrait voir un UUID dans un système hérité (legacy) et construire une logique en supposant qu'il est imprévisible. Il pourrait ne pas réaliser qu'il s'agit d'un UUID v1, qui contient un timestamp et l'adresse MAC de la machine qui l'a généré, ce qui pourrait potentiellement fuiter des informations sensibles.
  • Le traiter comme une simple chaîne de caractères. Certains développeurs pourraient penser que n'importe quelle chaîne unique est un « UUID ». Ils pourraient utiliser "produit-123" ou générer un ID avec un générateur de nombres aléatoires faible. Les vrais UUID respectent un format strict et, pour la v4, doivent être générés avec une source d'aléa cryptographiquement sûre pour garantir l'unicité.
  • Utiliser la mauvaise version pour le travail à faire. Une erreur courante est d'utiliser un UUID v4 (aléatoire) quand on a besoin d'un UUID déterministe. Par exemple, si vous devez générer un ID unique pour un fichier en fonction de son contenu, vous devriez utiliser un UUID v5 avec le hash du fichier comme « nom ». Cela garantit que si vous rencontrez à nouveau le même fichier, vous générerez exactement le même UUID, ce qui facilite la déduplication.

Pourquoi vous devriez garder ça dans un coin de votre tête

Vous devriez penser à utiliser un générateur d'UUID chaque fois que vous vous trouvez dans une situation où :

  • Vous devez créer un identifiant unique, mais vous ne pouvez pas compter sur une autorité centrale (comme une séquence unique de base de données).
  • Vous construisez un système distribué, un microservice, ou toute application où plusieurs instances doivent créer des données indépendamment.
  • Vous voulez générer des ID uniques côté client (dans un navigateur ou une application mobile) pour des mises à jour d'UI optimistes ou des capacités hors ligne.
  • Vous avez besoin de créer des ID de corrélation pour tracer des requêtes à travers plusieurs systèmes.
  • Vous choisissez une clé primaire pour une table de base de données et vous privilégiez l'unicité globale par rapport aux performances brutes d'insertion (et que vous avez pesé le pour et le contre).

Dans le développement logiciel moderne, ces scénarios sont la règle, et non l'exception. Savoir quand et comment utiliser les UUID est une compétence fondamentale.

Pour aller plus loin

Théorie bouclée. Place à la pratique — 100 % dans ton navigateur.

Essayer l'outil: Générateur d'UUID