Blog ·
Dokumentation vor dem Merge geschrieben
Zwei Sätze einer Dokumentationsseite waren am Tag der Auslieferung falsch, weil ein anderer Zweig zuerst landete. Was eine Wache fängt und was nur ein grep.
Von Provibr
Eine Dokumentationsseite ist eine Menge von Behauptungen über Code. Das klingt selbstverständlich, bis man bemerkt, dass nichts im Build eine davon prüft. Tests behaupten etwas über Code. Typprüfungen behaupten etwas über Code. Prosa über Code behauptet etwas über Code und wird dadurch geprüft, dass ein Mensch sie einmal liest, an dem Tag, an dem sie geschrieben wurde.
Wir haben in einer Runde zwei neue Dokumentationsseiten geschrieben: eine für den Automatisierungseditor, rund 2930 englische Wörter über acht Abschnitte, und eine für das Dashboard, rund 909. Dazu ein Abschnitt, der zwei bereits bestehenden Seiten hinzugefügt wurde. Zwei Sätze auf der Automatisierungsseite waren schon falsch, als sie ausgeliefert wurde.
Niemand hatte eine Unwahrheit geschrieben. Beide Sätze stimmten gegenüber dem Zweig, auf dem sie geschrieben wurden.
Der Satz, der beim Schreiben wahr war
Dokumentation zu einer Funktion entsteht meist nach der Funktion, das heißt, sie entsteht, während andere Zweige noch offen sind. Unsere auch. Die Seite beschrieb einen Benachrichtigungsknoten und sagte sinngemäß, dass er keine E-Mail verschickt. Auf dem Zweig, gegen den sie geschrieben wurde, stimmte das genau: der Knoten schrieb eine Benachrichtigung im Panel, und nichts verließ das Haus.
Eine parallele Runde wurde zuerst zusammengeführt und gab dem Knoten ein E-Mail-Kästchen, standardmäßig aus, eine eigene Abmeldekategorie und die Regel, dass ein Testlauf nie etwas verschickt. Jede dieser Tatsachen ist für eine Leserin interessant. Keine davon stand auf der Seite, und was auf der Seite stand, sagte ihr jetzt das Gegenteil.
Der zweite Satz beschrieb, wie ein Tarif mit einem Flow verbunden ist. Er sagte, der Tarif führe den Flow dahinter aus, aus einer Zeit, in der diese Beziehung eins zu eins war. Derselbe Merge ersetzte sie durch einen Join: ein Tarif darf je Zeitpunkt höchstens einen Flow hängen haben, von drei Zeitpunkten, und ein manuell oder per Webhook ausgelöster Flow darf dort gar nicht hängen. „Kann nicht angehängt werden“ ist eine bessere Antwort als „angehängt und tut still nichts“, aber es ist eine andere Antwort, und die Seite gab weiterhin die alte.
Die Reparatur war klein. Interessant ist, wie es gefunden wurde: jemand hat absichtlich nachgesehen, denn eine Runde, die ein Thema berührt, ist der einzige Moment, in dem überhaupt jemand einen Grund hat, die Prosa zu diesem Thema noch einmal zu lesen.
Was eine Wache fangen kann
Auf denselben Seiten gibt es eine zweite Fehlerart, und anders als die erste lässt sie sich maschinell fassen.
Die Dashboardseite hat eine Tabelle, die die Karten aufzählt, die eine Benutzerin hinzufügen kann. Diese Karten haben Namen, in neun Sprachen, und diese Namen gibt es bereits: es sind die Beschriftungen in der Auswahl, die die Benutzerin tatsächlich anklickt. Eine Dokumentationstabelle zu schreiben heißt, sie ein zweites Mal zu schreiben.
Es ging sofort schief, im ersten Entwurf, im Englischen:
| In der Auswahl | Auf der Dokumentationsseite |
|---|---|
| Integration list | Connections |
| Open tickets | Tickets |
| Credit balance | Credit |
Keines davon ist als Englisch falsch. Alle drei sind als Dokumentation falsch, denn wer die Anweisung liest, „Connections“ hinzuzufügen, sucht eine Karte namens Connections und findet eine Karte namens Integration list. Das Auseinanderlaufen ist bauartbedingt still: beide Texte sind für sich in Ordnung, und niemand legt ein Handbuch neben eine Auswahl.
Die Tabelle nimmt jetzt dieselben Katalogschlüssel wie die Auswahl, und ein Test verlangt, dass sie in allen neun Sprachen Wort für Wort gleich sind. Der Dokumentationsschlüssel wird aus der Kartenkennung abgeleitet statt von Hand aufgeführt, damit die siebte optionale Karte, die jemand nächstes Jahr hinzufügt, gemessen wird, ohne dass sich jemand daran erinnern muss, sie hier einzutragen. Das ist dieselbe Form wie die Wache, die wir zwischen den beiden Kopien der englischen Servertexte laufen lassen, und sie besteht aus demselben Grund: zwei Orte, die eine Wahrheit halten, brauchen einen Test, der das sagt, und keine Gepflogenheit.
Die Schaltflächennamen auf derselben Seite waren in fünf der neun Sprachen geraten. Auch sie kommen jetzt aus dem Katalog. Und drei Sprachen hatten das Wort Scripts übersetzt, den Namen eines Menüpunkts, der im Produkt nicht übersetzt wird, sodass die Seite einer spanischen, portugiesischen und ukrainischen Leserin sagte, sie solle etwas anklicken, das unter diesem Namen nicht existiert.
Ein technisches Token ist kein Wort
Produktnamen, Ports, Pfade, Modulnamen und Statuscodes stehen in einem dicktengleichen Token und bleiben englisch, wo immer sie auftauchen, in jeder Sprache. Diese Regel ist nicht neu. Neu war, dass ihre Umsetzung auf diesen Seiten gleich mit zwei anderen Wachen zusammenstieß.
Ein <code>-Element wörtlich in ein Array von Tabellenzeilen zu setzen löst die Lint-Regel aus, die auf jedem JSX-Element in einem Array einen Schlüssel verlangt, auch hier, wo die Tabellenkomponente jede Zelle in ein eigenes Element mit Schlüssel packt und der Schlüssel nie gelesen wird. Einen Schlüssel daranzuschreiben löst eine andere Wache aus, die ein Kind mit Schlüssel neben Übersetzungsaufrufen sieht, deren Schlüssel sie in dieser Datei nicht auflösen kann.
Der Ausweg war eine einzeilige Funktion, die das Element zurückgibt. Für die Lint-Regel ist es ein Funktionsaufruf statt eines Array-Elements, für die andere Wache ist es kein Schlüssel. Die gezeichnete Ausgabe ist byteweise gleich. Es ist eine Kleinigkeit, und es ist die Art Kleinigkeit, die mit einem Abschaltkommentar gelöst wird, wenn niemand aufschreibt, warum die beiden Regeln uneins waren.
Bildschirmfotos, die erfolgreich aussahen
Zur Messung dieser Seiten gehörten Bildschirmfotos an Ankern: zu jedem Abschnitt scrollen, ihn fotografieren, ihn ansehen.
Neun davon zeigten den Seitenkopf.
Der Browserbefehl, der einen Bereich jenseits des Sichtfensters aufnimmt, rechnet seinen Ausschnitt vom oberen Rand des Dokuments aus, nicht von der aktuellen Scrollposition. Scrollen Sie zu einem Anker acht Bildschirme weiter unten, fragen Sie einen Bereich an den Koordinaten ab, die das Element meldet, und Sie fotografieren stattdessen den Seitenkopf, in genau der richtigen Größe, in einer Datei mit dem richtigen Namen. Jedes dieser Bildschirmfotos war ein plausibel aussehendes Bild der falschen Sache.
Den aktuellen Scrollversatz zu addieren behob es. Die allgemeine Form begegnet uns immer wieder: eine Messung, die scheitert, indem sie normal aussehende Ausgabe erzeugt, ist schlimmer als eine, die abstürzt, denn der Absturz wird noch am selben Tag untersucht.
Der Teil, den keine Wache erreicht
Die Kartennamen ließen sich maschinell fassen, weil beide Seiten Zeichenketten in einem Repository sind. Die beiden veralteten Sätze nicht, und es lohnt sich, genau zu sagen warum, denn es ist verlockend zu glauben, für jedes Dokumentationsproblem warte irgendwo ein Test darauf, geschrieben zu werden.
Ein Satz, der sagt, ein Knoten verschicke keine E-Mail, ist eine Behauptung über Verhalten, das über vier Dateien, einen Vorgabewert, ein Kästchen und eine Kategorienliste verteilt ist. Es gibt keinen Ausdruck, mit dem man ihn vergleichen könnte. Der einzige Mechanismus, der ihn fangen würde, ist ein Test, der das Verhalten zeichnet und den Satz liest, und das ist ein Test, der je Satz geschrieben werden muss, von jemandem, der schon weiß, dass der Satz falsch ist.
Was wir stattdessen taten, war billiger und verdient es, als Vorgehen benannt zu werden: als die Korrektur gemacht wurde, wurde der ganze Dokumentationsbaum nach jeder weiteren Behauptung über E-Mail und jeder weiteren Behauptung über einen Flow je Tarif durchsucht. Es gab keine dritte Stelle. Das ist ein Ergebnis und keine Formalie. Ohne sie hätte die Runde zwei Sätze repariert und die Leserin mit der vernünftigen Annahme zurückgelassen, die Seite sei geprüft worden.
Dieselbe Disziplin gibt es in diesem Projekt schon an anderer Stelle für ein anderes Paar: unsere langen Artikel können gegenüber der Liste der live geschalteten Integrationen veralten, und nichts wird dabei rot. Zwei Artikel sagten einmal sechs Wochen lang, zwei Hypervisoren stünden auf der Roadmap, während beide längst ausgeliefert wurden. Die Regel, die daraus entstand, ist dieselbe: ändert eine Runde den Status einer Sache, dann durchsuchen Sie die Prosa nach ihrem Namen.
Was wir aufschreiben würden
- Prosa über Code ist eine ungeprüfte Behauptung. Nichts im Build liest sie. Das ist in Ordnung, solange alle das wissen und niemand annimmt, ein grüner Lauf sage etwas über den Absatz.
- Dokumentation wird gegen einen Zweig geschrieben, nicht gegen main. Sind andere Runden offen, ist die Seite eine Momentaufnahme eines Zustands, der vielleicht nie ausgeliefert wird. Lesen Sie sie nach dem Merge noch einmal, nicht davor.
- Ein Name, den es im Produkt gibt, gehört gelesen und nicht abgetippt. Drei von sechs Kartennamen liefen im ersten Entwurf auseinander. In neun Sprachen ist das eine Fehlerklasse und kein Versehen.
- Leiten Sie den Dokumentationsschlüssel aus der Kennung ab. Dann ist die nächste Karte abgedeckt, ohne dass sich jemand an diese Regel erinnern muss.
- Ein geratenes Wort in einer Sprache, die Sie nicht lesen, ist unsichtbar. Fünf Sprachen hatten Schaltflächennamen geraten, und nichts war rot.
- Einen Produktnamen zu übersetzen ist eine kaputte Anweisung. Wenn das Menü in jeder Sprache Scripts sagt, sagt das Handbuch in jeder Sprache Scripts.
- Wenn zwei Lint-Regeln uneins sind, schreiben Sie auf, welcher Sie gefolgt sind und warum. Die Alternative ist ein Abschaltkommentar, den später niemand beurteilen kann.
- Eine Messung, die beim Scheitern plausible Ausgabe erzeugt, wird nicht hinterfragt. Fotografieren Sie etwas, das Sie wiedererkennen, und sehen Sie sich die Bilder an.
Zur Klarheit: beide Seiten sind in neun Sprachen live, die beiden veralteten Sätze wurden in allen neun korrigiert, und die Wache über die Kartennamen liegt in der Suite und wurde rot bewiesen, bevor sie grün bewiesen wurde. Die Behauptungen auf den Seiten stammen aus dem Lesen des Codes und nicht aus dem Ausführen; das curl-Beispiel auf der Automatisierungsseite wurde nicht gegen einen echten Endpunkt abgefeuert; und jede Übersetzung hatte eine Leserin, nicht zwei.
Aus der Plattformarbeit an Provibr. Die Karten, auf die sich diese Namen beziehen, stehen in eine Verknüpfung ist ein Verweis, kein Recht, und was neun Kataloge kosten, um ehrlich zu bleiben, steht in sechzehntausend Schlüssel, neun Sprachen.