Changements cassants — MRTK2

Les consommateurs de MRTK dépendent d’une surface d’API de mise en production stable, afin qu’ils puissent prendre des mises à jour vers MRTK sans avoir de changements cassants importants chaque fois.

Cette page décrit notre politique actuelle concernant les changements cassants dans le MRTK, ainsi que certains objectifs à plus long terme concernant la façon dont nous pouvons mieux gérer le compromis entre maintenir les changements cassants faibles et être en mesure d’apporter les modifications techniques à long terme appropriées au code.

Qu’est-ce qu’un changement cassant ?

Une modification est une modification cassante si elle satisfait à l’une des conditions de la liste A ET remplit toutes les conditions de la liste B

Liste A

  • Ajout, suppression ou mise à jour d’un membre ou d’une fonction de n’importe quelle interface (ou suppression/renommage de l’interface entière).
  • Suppression, mise à jour (modification du type/définition, création d’un élément privé ou interne) d’un membre ou d’une fonction protégé ou public de classe. (ou suppression/renommage de la classe entière).
  • Modification de l’ordre des événements déclenchés par une classe.
  • Renommage de n’importe quel SerializedField privé (sans balise FormerlySerializedAs correspondante) ou propriété publique sur un ScriptableObject (en particulier les modifications apportées aux profils).
  • Modification du type d’un champ sur un ScriptableObject (en particulier les modifications apportées aux profils).
  • Mises à jour à l’espace de noms ou aux asmdefs d’une classe ou d’une interface.
  • Suppression de tout préfabriqué ou suppression d’un script sur l’objet de niveau supérieur d’un préfabriqué.

Liste B

  • La ressource en question se trouve dans le package de base (c’est-à-dire dans l’un des dossiers suivants) :

    • MRTK/Core
    • MRTK/Providers/
    • MRTK/Services/
    • MRTK/SDK/
    • MRTK/Extensions
  • La ressource en question n’appartient pas à l’espace de noms expérimental.

Important

Toute ressource qui se trouve dans le package d’exemples (c’est-à-dire une partie du dossier MRTK/Examples/ ) est susceptible de changer à tout moment, car les ressources qu’il est conçue pour être copiées et vues par les consommateurs comme des « implémentations de référence », mais ne font pas partie de l’ensemble principal d’API et de ressources. Les ressources de l’espace de noms expérimental (ou plus généralement, les caractéristiques étiquetées comme expérimentales) sont celles qui sont publiées avant que toutes les diligences raisonnables ne soient effectuées (c’est-à-dire des tests, une itération d’expérience utilisateur, une documentation) et qui sont publiées tôt pour obtenir des commentaires plus tôt. Toutefois, parce qu’ils n’ont pas de tests et de documentation, et parce que nous n’avons probablement pas cloué toutes les interactions et conceptions, nous les publions dans un état où le public doit supposer qu’ils peuvent et vont changer (c’est-à-dire être modifiés, complètement supprimés, etc.).

Pour plus d’informations, consultez fonctionnalités expérimentales .

Étant donné que la surface d’exposition pour les changements cassants est très importante, il est important de noter que l’absence de règle absolue indiquant « aucun changement cassant » serait impossible . Il peut y avoir des problèmes qui peuvent être résolus d’une manière saine en ayant un changement cassant. Pour mettre une autre façon, la seule façon dont nous pourrions vraiment avoir « aucun changement cassant » est d’avoir aucun changement du tout.

Notre politique permanente est d’éviter d’apporter des changements cassants si possible, et de ne le faire que si le changement accumulerait une valeur importante de client ou de cadre à long terme.

Que faire des changements cassants

S’il est possible d’accomplir quelque chose sans changement cassant et sans compromettre la structure à long terme et la viabilité de la fonctionnalité, ne faites pas le changement cassant. S’il n’existe aucun autre moyen, la politique actuelle consiste à évaluer chaque changement cassant individuel, à comprendre si l’avantage de prendre le changement l’emporte sur le coût pour le consommateur d’absorber le changement. Débat sur ce qui vaut la peine de faire et ce qui n’est généralement pas pris en compte sur la demande de tirage ou la discussion sur la question elle-même.

Ce qui peut se passer ici se trouve dans plusieurs compartiments :

Le changement cassant ajoute de la valeur, mais peut être écrit d’une manière qui n’est pas cassant

Par exemple, cette demande de tirage a ajouté une nouvelle fonctionnalité qui a été initialement écrite d’une manière qui était cassant - elle a modifié une interface existante - mais a ensuite été réécrite là où la fonctionnalité a été décomposée en tant que son propre interface. Il s’agit généralement du meilleur résultat possible. N’essayez pas de forcer une modification dans une forme non cassant si cela compromettrait la viabilité à long terme ou la structure de la fonctionnalité.

Le changement cassant ajoute une valeur suffisante au client qu’il vaut la peine de faire

Documentez ce que sont les changements cassants et fournissez la meilleure atténuation possible (c’est-à-dire des étapes prescriptives sur la migration, ou mieux encore des outils qui migreront automatiquement pour le client). Chaque version peut contenir une petite quantité de modifications qui sont cassants . Elles doivent toujours être documentées dans la documentation telle qu’elle a été effectuée dans cette demande de tirage. S’il existe déjà un guide de migration 2.x.x→2.x+1.x+1, ajoutez des instructions ou des outils à ce document. S’il n’existe pas, créez-le.

Le changement cassant ajoute de la valeur, mais la douleur du client serait trop élevée

Tous les types de changements cassants ne sont pas tous créés égaux - certains sont beaucoup plus douloureux que d’autres, en fonction de notre expérience et en fonction des expériences client. Par exemple, les modifications apportées aux interfaces peuvent être douloureuses, mais si le changement cassant est celui dans lequel un client est peu susceptible d’avoir étendu/implémenté dans le passé (le système de visualisation de diagnostic, par exemple), le coût réel est probablement faible à rien. Toutefois, si la modification est le type d’un champ sur un ScriptableObject (par exemple, sur l’un des profils principaux du MRTK), cela risque de provoquer des douleurs massives chez les clients. Les clients ont déjà cloné le profil par défaut, la fusion/mise à jour des profils peut être extrêmement difficile à effectuer manuellement (c’est-à-dire via un éditeur de texte pendant le temps de fusion), et recopier le profil par défaut et reconfigurer tout à la main est extrêmement susceptible d’entraîner des régressions difficiles à déboguer.

Ces modifications doivent être remises sur le plateau jusqu’à ce qu’une branche existe, ce qui permettra de briser considérablement les modifications (avec une valeur significative qui donnera aux clients une raison de mettre à niveau). Une telle branche n’existe pas actuellement. Dans nos futures réunions de planification des itérations, nous examinerons l’ensemble des modifications/problèmes qui étaient « trop cassants » pour voir si nous avons atteint une masse critique pour qu’il soit raisonnable de poursuivre un ensemble de modifications en même temps. Notez qu’il est dangereux de faire tourner une branche « tout est autorisé » sans diligence raisonnable en raison des ressources d’ingénierie limitées que nous avons, et le fait que nous aurions à diviser les tests et la validation entre ces deux. Il doit y avoir un objectif clair et une date de début et de fin bien communiquées d’une telle branche lorsqu’elle existe.

Gestion à long terme des changements cassants

À long terme, nous devrions chercher à réduire l’étendue de ce qui est un changement cassant en augmentant l’ensemble des conditions de la liste B. À l’avenir, l’ensemble des éléments de la liste A sera toujours cassant techniquement pour l’ensemble de fichiers et de ressources que nous considérons être dans la « surface de l’API publique ». La façon dont nous pouvons obtenir un peu plus de liberté pour l’itération (c’est-à-dire modifier les détails d’implémentation interne, ce qui permet de refactoriser et de partager plus facilement du code entre plusieurs classes, etc.) est d’être plus explicite sur les parties du code qui sont une surface officielle, plutôt que les détails de l’implémentation.

Une chose que nous avons déjà faite est d’introduire le concept d’une fonctionnalité « expérimentale » (elle appartient à l’espace de noms expérimental, il n’a peut-être pas de tests/documentation, et est publiquement proclamée, mais peut être supprimée et mise à jour sans avertissement). Cela a donné la liberté d’ajouter de nouvelles fonctionnalités plus tôt pour obtenir des commentaires antérieurs, mais pas immédiatement liés à sa surface d’API (car nous n’avons peut-être pas entièrement pensé à la surface de l’API).

Autres exemples de choses qui pourraient aider à l’avenir

  • Utilisation du mot clé interne. Cela nous permettrait d’avoir du code partagé au sein de nos propres assemblys (pour réduire la duplication de code) sans rendre les choses publiques aux consommateurs externes.
  • Création d’un espace de noms « interne » (par exemple, Microsoft.MixedReality.Toolkit.Internal.Utilities), où nous documentons publiquement que tout ce qui se trouve dans cet espace de noms interne est susceptible de changer à tout moment et peut être supprimé, etc. Cela est similaire à la façon dont les bibliothèques d’en-tête C++ utilisent les espaces de noms ::internal pour masquer leurs détails d’implémentation.