Une version de SDK conserve son identité de la bêta à la version stable

Lorsque l’on développe un SDK, son numéro de version ressemble d’abord à une simple information technique. On modifie du code, on publie un package, on incrémente un nombre et on passe à la suite.

Puis le SDK commence à être utilisé.

Une équipe attend une nouvelle API. Une autre doit planifier son intégration. Le support veut savoir à partir de quelle version un comportement est disponible. Des partenaires externes préparent leur propre calendrier de mise à jour. À ce moment-là, le numéro de version ne décrit plus seulement un artefact : il devient un outil de coordination.

Et un numéro sur lequel plusieurs équipes se sont alignées est beaucoup plus difficile à changer qu’on ne l’imagine.

MayoSDK, le SDK qui ne manquait pas de sauce

Lorsque j’étais chez Ketchapp, je gérais un SDK appelé MayoSDK.

Oui, le nom était volontaire : Ketchapp, mayo… Nous avions choisi d’assumer la blague jusqu’au bout. Merci à Jonathan d’avoir créé cette blague.

MayoSDK était distribué sous la forme d’un package Unity Package Manager, ou UPM. D’abord déployé en interne, il a ensuite été utilisé par les nombreux studios externes avec lesquels nous travaillions. Sa version devait donc utiliser la forme major.minor.patch, par exemple 1.9.10, avec la possibilité d’ajouter un suffixe de préversion. Unity s’appuie sur les règles de Semantic Versioning pour comparer les versions et résoudre les dépendances.

Sur le papier, tout paraît simple :

  • la version majeure signale une incompatibilité ;
  • la version mineure apporte des fonctionnalités compatibles avec l’existant ;
  • le patch contient des corrections sans changement d’API.

Dans la réalité d’un SDK utilisé par plusieurs centaines de jeux, il fallait également représenter le niveau de maturité d’une même livraison.

Avant qu’une fonctionnalité ne soit considérée comme stable, nous la publiions dans quelques jeux afin de la valider en conditions réelles. Une première bêta pouvait révéler un problème, puis une deuxième en corriger un autre. Lorsque le résultat semblait suffisamment solide, nous passions en release candidate, puis en version stable. Et même après cette publication, un correctif urgent pouvait encore être nécessaire.

Le code évoluait donc plusieurs fois alors que, du point de vue des équipes qui l’attendaient, il s’agissait toujours de la même fonctionnalité et de la même livraison.

Quand un numéro de version devient une marque

Imaginons que l’on annonce à tous les services :

La fonctionnalité A sera disponible dans MayoSDK 1.9.10.

À partir de cet instant, 1.9.10 devient le nom de cette livraison. Il apparaît dans les tickets, les feuilles de route, les messages Slack, les documents d’intégration et parfois les engagements pris avec un partenaire.

Si chaque bêta consomme ensuite un nouveau numéro — 1.9.10, puis 1.9.11, puis 1.9.12 — la version stable peut finir par sortir en 1.9.15. Techniquement, rien n’empêche de le faire. Humainement, le message est devenu beaucoup moins clair.

Certains retiendront le numéro annoncé au départ. D’autres utiliseront celui de la bêta qu’ils ont testée. Les derniers parleront de la version finalement publiée. Tout le monde évoquera la même fonctionnalité avec un identifiant différent.

Le problème n’est donc pas seulement de numéroter des packages. Il consiste à préserver un vocabulaire commun pendant tout le cycle de livraison.

Figer le numéro cible dès la première bêta

Après plusieurs essais, je suis arrivé à une convention simple : le numéro de la future version stable était choisi avant de publier la première bêta, puis il ne changeait plus pendant sa validation.

Dans notre convention pour MayoSDK :

  • le premier nombre représentait la génération majeure du SDK ; dans les faits, il est toujours resté à 1 ;
  • le deuxième nombre n’était incrémenté que pour une évolution structurante, comme de nouvelles API importantes ou un changement incompatible ;
  • le troisième nombre identifiait une livraison fonctionnelle précise ;
  • le suffixe indiquait son niveau de maturité et l’itération publiée.

Le cycle d’une livraison 1.9.10 ressemblait alors à ceci :

  1. 1.9.10-beta0001 : première publication dans un nombre limité de jeux ;
  2. 1.9.10-beta0002 : nouvelle bêta intégrant les premiers correctifs ;
  3. 1.9.10-rc0001 : release candidate que nous estimions prête à devenir stable ;
  4. 1.9.10 : publication stable ;
  5. 1.9.10-hotfix1 : dans notre convention historique, correctif urgent explicitement rattaché à cette livraison.

Cycle de publication d’une version de MayoSDK, de la bêta au correctif

Le nombre 1.9.10 portait la promesse fonctionnelle. Les suffixes racontaient uniquement où nous en étions dans sa validation.

Le compteur sur quatre chiffres n’avait rien de magique. Il rendait simplement l’ordre des publications immédiatement visible, y compris dans des outils effectuant un tri lexical. Une autre équipe pourrait tout à fait préférer beta.1, beta.2 et rc.1, qui correspondent à l’écriture habituelle de SemVer. L’essentiel est que la convention soit documentée, monotone et appliquée automatiquement par la chaîne de publication.

Un langage commun pour tous les acteurs

Grâce à ce système de nommage, nous pouvions conserver une communication fluide pendant toute la durée de la livraison.

Dans la plupart des échanges, les différents acteurs parlaient simplement de la version 1.9.10. Les équipes de développement savaient quelle fonctionnalité elles devaient intégrer. La QA savait quel périmètre elle devait valider. Le produit, le support et les partenaires pouvaient organiser leur travail autour du même repère. Ils n’avaient pas besoin de connaître le détail de chaque bêta, de chaque release candidate ou de chaque nouvelle publication du package.

Lorsque davantage de précision était nécessaire, l’équipe SDK utilisait le nom complet : 1.9.10-beta0002 ou 1.9.10-rc0001. Mais cette complexité restait limitée aux personnes qui en avaient réellement besoin.

Nous avions donc deux niveaux de conversation :

  • 1.9.10 désignait la livraison fonctionnelle dans les échanges entre les équipes ;
  • le suffixe désignait l’artefact précis dans les échanges liés au développement, au déploiement ou à la validation.

Cette séparation évitait d’imposer le cycle de vie interne du SDK à toute l’entreprise. Une personne pouvait demander « Quand la 1.9.10 sera-t-elle disponible ? » ou annoncer « Ce jeu passera sur la 1.9.10 » sans devoir préciser si la version actuellement testée était la deuxième bêta ou la première RC. Le contexte fonctionnel restait stable, même lorsque les packages continuaient d’évoluer.

Les équipes peuvent commencer leur intégration sur une bêta sans apprendre un nouveau nom lorsque la release candidate arrive. Les tickets et la documentation restent rattachés au même objectif. Le changelog peut être préparé sous un seul en-tête. Enfin, le passage en stable devient très lisible : on ne change pas la promesse, on retire simplement le suffixe.

Cela améliore aussi la communication externe. On peut annoncer que la fonctionnalité sera disponible en 1.9.10, donner accès à 1.9.10-rc0001 aux partenaires qui souhaitent l’intégrer en avance, puis publier 1.9.10 sans avoir à corriger tout le discours entre-temps. Dans les faits, les bêtas restaient réservées à nos validations internes : seul le stade release candidate était proposé en accès anticipé.

Cela peut sembler être un simple confort de vocabulaire. En réalité, la communication autour d’un SDK est un véritable défi à part entière. Plus le SDK possède de consommateurs, plus les interlocuteurs ont des rôles, des contraintes et des niveaux de connaissance différents. Le numéro de version doit relier ces personnes sans leur demander de comprendre toute la mécanique de publication.

Une bonne convention de nommage rend cette complexité presque invisible. Mais cette simplicité n’arrive pas toute seule : elle doit être pensée, documentée et partagée avec autant de soin que le cycle de livraison lui-même.

Le cas particulier du hotfix

Il existe toutefois une subtilité importante. Pour Semantic Versioning, tout ce qui suit un tiret est une préversion. Par conséquent, 1.9.10-hotfix1 est considéré comme antérieur à 1.9.10, et non comme une mise à jour plus récente.

Notre suffixe hotfix1 était utile comme convention opérationnelle dans un écosystème contrôlé, où les versions étaient sélectionnées explicitement. Mais il ne faut pas compter sur un gestionnaire de packages compatible SemVer pour proposer automatiquement 1.9.10-hotfix1 à un projet qui utilise déjà 1.9.10.

Pour un SDK publié largement ou consommé avec une résolution automatique des dépendances, la solution correcte est de publier le correctif sous un nouveau patch stable :

1.9.10              version qui introduit la fonctionnalité
1.9.11              version stable corrigée et désormais recommandée

La communication ne perd pas pour autant son repère. Il suffit d’employer une formulation plus précise :

La fonctionnalité A est disponible à partir de la version 1.9.10. La version stable recommandée est la 1.9.11.

La version d’introduction et la version recommandée ne répondent pas à la même question. Les distinguer permet de rester exact sans renoncer au numéro devenu familier pour les équipes.

Interne ou externe, la règle doit être explicite

Un SDK interne autorise davantage de conventions maison, car son équipe connaît les consommateurs, maîtrise souvent le registre et peut accompagner chaque mise à jour. Cette proximité ne rend pas le versionnage moins important. Au contraire : un SDK partagé par de nombreux projets internes peut créer autant de dépendances et de coordination qu’un produit public.

Pour un SDK externe, les outils et les utilisateurs ne connaissent pas les habitudes de l’équipe. Ils interprètent les versions selon les standards. Il faut donc être beaucoup plus strict : une rupture d’API incrémente la version majeure, une fonctionnalité compatible incrémente la mineure et une correction incrémente le patch. Les suffixes restent réservés aux versions qui précèdent la stable.

Dans les deux cas, quelques règles évitent beaucoup de confusion :

  • choisir le numéro cible avant la première préversion ;
  • conserver ce numéro pendant les phases bêta et RC ;
  • ne jamais remplacer le contenu d’une version déjà publiée ;
  • documenter précisément la signification de chaque segment et de chaque suffixe ;
  • publier les notes de version avec le package ;
  • automatiser la génération et la validation des numéros ;
  • communiquer avec « disponible à partir de » lorsqu’on parle de la version d’introduction d’une fonctionnalité.

Le versionnage fait partie du produit

Une bonne stratégie de versionnage ne sert pas uniquement au gestionnaire de packages. Elle aide le développement, la QA, le support, les équipes produit, les partenaires et les utilisateurs à parler de la même chose.

C’est particulièrement visible pour un SDK : sa version se retrouve dans le code de ses consommateurs, mais aussi dans leurs plannings et leurs décisions. Elle devient un contrat technique autant qu’un repère humain.

Avec MayoSDK, figer le numéro cible dès la première bêta nous a permis de faire évoluer une livraison sans diluer son identité. Les suffixes indiquaient sa maturité ; le numéro principal conservait la promesse.

Finalement, versionner correctement un SDK ne consiste pas seulement à savoir quel nombre incrémenter. Il s’agit de faire en sorte que, lorsqu’une équipe prononce le nom d’une version, tout le monde sache exactement de quoi elle parle.