Unterbrechung von Änderungen – MRTK2

Die Verbraucher von MRTK hängen davon ab, dass sie eine stabile Version-to-Release-API-Oberfläche haben, sodass sie Updates für MRTK durchführen können, ohne bei jedem Zeitpunkt große Änderungen zu haben.

Auf dieser Seite wird unsere aktuelle Richtlinie zum Unterbrechen von Änderungen im MRTK beschrieben, zusammen mit einigen langfristigen Zielen, wie wir den Handel zwischen der Erhaltung von Änderungen niedrig halten und die richtigen technischen Änderungen am Code vornehmen können.

Was ist eine unterbrechungsende Änderung?

Eine Änderung ist eine unterbrechungsende Änderung, wenn sie eine der Bedingungen in der Liste A erfüllt UND alle Bedingungen in Liste B erfüllt.

Liste A

  • Das Hinzufügen, Entfernen oder Aktualisieren eines Elements oder einer Beliebigen Funktion einer Schnittstelle (oder Entfernen/Umbenennen der gesamten Schnittstelle).
  • Das Entfernen, Aktualisieren (Ändern von Typ/Definition, private oder interne) von geschützten oder öffentlichen Membern oder Funktionen der Klasse. (oder Entfernen/Umbenennen der gesamten Klasse).
  • Die Änderung der Reihenfolge von Ereignissen, die von einer Klasse ausgelöst werden.
  • Die Umbenennen aller privaten SerializedField (ohne entsprechendes NerializedAs-Tag) oder öffentliche Eigenschaft auf einem ScriptableObject (insbesondere Änderungen an Profilen).
  • Ändern des Typs eines Felds auf einem SkriptableObject (insbesondere Änderungen an Profilen).
  • Aktualisierungen zum Namespace oder Asmdefs einer beliebigen Klasse oder Schnittstelle.
  • Entfernen von Prefab- oder Entfernung eines Skripts auf oberster Ebene eines Prefab-Objekts.

Liste B

  • Das betreffende Objekt befindet sich im Foundation-Paket (z. B. in einem der folgenden Ordner):

    • MRTK/Core
    • MRTK/Provider/
    • MRTK/Services/
    • MRTK/SDK/
    • MRTK/Erweiterungen
  • Das betreffende Objekt gehört nicht zum experimentellen Namespace.

Wichtig

Jedes Objekt, das im Beispielpaket (d. h. Teil des MRTK/Examples/Examples/Folder) liegt, wird jederzeit geändert, da ressourcenweise kopiert und von Verbrauchern als "Referenzimplementierungen" angezeigt werden sollen, aber nicht teil des Kernsatzes von APIs und Ressourcen sind. Ressourcen im experimentellen Namespace (oder allgemein als experimentell gekennzeichnete Features) sind solche, die veröffentlicht werden, bevor alle Due Diligence durchgeführt wurden (d. h. Tests, UX-Iteration, Dokumentation) und wird früh veröffentlicht, um Feedback schneller zu erhalten. Da sie jedoch keine Tests und Dokumentationen haben, und weil wir wahrscheinlich nicht alle Interaktionen und Designs heruntergeheftet haben, veröffentlichen wir sie in einem Zustand, in dem die Öffentlichkeit davon ausgehen sollte, dass sie können und ändern werden (z. B. geändert, vollständig entfernt usw.).

Weitere Informationen finden Sie unter Experimentelle Features .

Da der Oberflächenbereich für die Unterbrechung von Änderungen sehr groß ist, ist es wichtig zu beachten, dass es eine absolute Regel gibt, die sagt, dass "keine unterbrechungsfreien Änderungen" nicht möglich wäre - es kann Probleme geben, die nur auf eine sane Weise behoben werden können, indem sie eine unterbrechungsfreie Änderung haben. Um eine andere Art und Weise zu setzen, ist die einzige Möglichkeit, wie wir wirklich "keine bruchweisen Änderungen" haben könnten, keine Änderungen zu haben.

Unsere ständige Richtlinie besteht darin, änderungen nach Möglichkeit zu vermeiden und nur dann zu tun, wenn die Änderung einen erheblichen Kunden- oder Rahmenwert langfristig entstehen würde.

Vorgehensweise beim Unterbrechen von Änderungen

Wenn es möglich ist, etwas ohne unterbrechungslose Änderung zu erreichen, und ohne die langfristige Struktur und Die Rentabilität des Features zu beeinträchtigen, führen Sie die bruchende Änderung nicht aus. Wenn es keine andere Möglichkeit gibt, ist die aktuelle Richtlinie, jede einzelne Änderung zu bewerten, um zu verstehen, ob der Vorteil der Übernahme der Änderung die Kosten für den Verbraucher übersteigt. Debatte über das, was zu tun ist und was nicht im Allgemeinen auf der PR stattfinden wird, oder die Diskussion selbst.

Was hier geschehen kann, fällt in mehrere Buckets:

Der durchbruchende Änderung fügt Wert hinzu, könnte jedoch auf eine Weise geschrieben werden, die nicht durchbrechen kann.

Diese PR hat beispielsweise ein neues Feature hinzugefügt, das zunächst in einer Weise geschrieben wurde, die unterbrochen wurde - es hat eine vorhandene Schnittstelle geändert - aber dann neu geschrieben, wo das Feature als eigene Schnittstelle ausgebrochen wurde. Dies ist im Allgemeinen das beste Ergebnis. Versuchen Sie nicht, eine Änderung in eine nicht durchbrechende Form zu erzwingen, wenn dies die langfristige Lebensdauer oder Struktur des Features kompromittiert.

Die unterbrechungsende Änderung fügt dem Kunden genügend Wert hinzu, dass es sich lohnt, zu tun.

Dokumentieren Sie, was die unterbrechungspflichtigen Änderungen sind, und stellen Sie die bestmögliche Entschärfung bereit (d. h. präskriptive Schritte zum Migrieren oder noch besser, die automatisch für den Kunden migriert werden). Jede Version kann eine kleine Menge von Änderungen enthalten, die brechen – dies sollte immer in Dokumenten dokumentiert werden, wie in dieser PR getan. Wenn bereits ein 2.x.x→2.x+1.x+1 Migrationshandbuch vorhanden ist, fügen Sie anweisungen oder Tools zu diesem Dokument hinzu. Wenn es nicht vorhanden ist, erstellen Sie es.

Der durchbrechende Änderung fügt Wert hinzu, aber der Kundenschmerzen wäre zu hoch.

Nicht alle Arten von unterbrechungsfreien Änderungen werden gleich erstellt - einige sind deutlich schmerzhafter, dass andere, basierend auf unserer Erfahrung und auf Kundenerfahrungen basieren. Beispielsweise können Änderungen an Schnittstellen schmerzhaft sein, aber wenn es sich bei der Unterbrechung um eine Änderung handelt, in der ein Kunde in der Vergangenheit nicht erweitert/implementiert wurde (z. B. das Diagnosevisualisierungssystem), ist die tatsächliche Kosten wahrscheinlich auf nichts niedrig. Wenn die Änderung jedoch der Typ eines Felds auf einem ScriptableObject (z. B. auf einem der Kernprofile des MRTK) ist, wird dies wahrscheinlich zu massiven Kundenschmerzen führen. Kunden haben bereits das Standardprofil geklont, das Zusammenführen/Aktualisieren von Profilen kann sehr schwer sein, manuell zu erledigen (d. h. über einen Text-Editor während der Zusammenführungszeit), und das Erneute Kopieren des Standardprofils und die Neukonfiguration aller Elemente durch die Hand ist äußerst wahrscheinlich, dass schwer zu debuggende Regressionen auftreten.

Diese Änderungen müssen wir wieder auf das Regal setzen, bis eine Zweigstelle vorhanden ist, die erhebliche Änderungen ermöglichen (zusammen mit einem signifikanten Wert, der Kunden einen Grund zum Upgrade bietet). Ein solcher Zweig ist derzeit nicht vorhanden. In unseren zukünftigen Iterationsplanungssitzungen werden wir die Reihe von Änderungen/Problemen überprüfen, die "zu brechen" waren, um festzustellen, ob wir eine kritische Masse erreicht haben, um eine Reihe von Änderungen gleichzeitig zu verfolgen. Beachten Sie, dass es gefährlich ist, einen Zweig "alles ist zulässig" zu drehen, ohne dass aufgrund der begrenzten Technischen Ressourcen, die wir haben, durchgeführt werden, und die Tatsache, dass wir Tests und Überprüfungen in diesen beiden teilen müssen. Es muss ein klares Ziel und ein gut kommuniziertes Anfangs- und Enddatum eines solchen Zweigs sein, wenn es vorhanden ist.

Langfristiges Management von Brüchen

Langfristig sollten wir versuchen, den Umfang der Änderung zu verringern, indem die Reihe der Bedingungen in List B erhöht wird. Die Reihe von Dingen in List A wird immer technisch für die Gruppe von Dateien und Ressourcen, die wir als "öffentliche API-Oberfläche" bezeichnet haben, brechen. Die Art und Weise, wie wir etwas mehr Freiheit für Iterationen erhalten können (d. h. das Ändern der internen Implementierungsdetails, die einfachere Umgestaltung und Freigabe von Code zwischen mehreren Klassen usw.) ermöglichen, ist es, expliziter zu sein, welche Teile des Codes offizielle Oberfläche sind, anstatt die Implementierungsdetails.

Eine Sache, die wir bereits getan haben, ist das Konzept eines "experimentellen" Features (es gehört im experimentellen Namespace, es kann keine Tests/Dokumentation haben und öffentlich erklärt werden, aber ohne Warnung entfernt und aktualisiert werden). Dies hat die Möglichkeit, neue Features schneller hinzuzufügen, um früheres Feedback zu erhalten, aber nicht sofort an die API-Oberfläche gebunden (da wir möglicherweise nicht vollständig die API-Oberfläche gedacht haben).

Weitere Beispiele für Dinge, die in Zukunft helfen könnten

  • Verwendung des internen Schlüsselworts. Dies würde es uns ermöglichen, code in unseren eigenen Assemblys (zum Reduzieren der Codeduplizierung) zu haben, ohne dinge öffentlich für externe Verbraucher zu machen.
  • Erstellen eines "internen" Namespaces (d. h. Microsoft.MixedReality.Toolkit.Internal.Utilities), wo wir öffentlich dokumentieren, dass alles, das innerhalb dieses internen Namespace enthalten ist, jederzeit geändert werden kann und entfernt werden kann usw. Dies ähnelt der Verwendung von C++-Headerbibliotheken von ::internen Namespaces, um ihre Implementierungsdetails auszublenden.