Blog ·
Uno script di conversione dal raggio troppo ampio
Uno script di tipografia ha arricciato un apostrofo in una citazione di uscita di un programma, in un articolo che non doveva toccare. E tutto restava verde.
Di Provibr
Il francese e l’italiano richiedono un apostrofo tipografico e non uno dritto, e c’è una prova che lo impone. Scrivere quel carattere direttamente in un file sorgente è inaffidabile: a seconda di come il file viene prodotto, una shell, un heredoc o uno strumento di modifica possono riappiattirlo. Scriviamo dunque il carattere dritto e in seguito eseguiamo un piccolo script che lo converte.
Quello script maschera il codice. Tutto ciò che sta fra backtick e tutto ciò che sta dentro un blocco delimitato viene lasciato in pace, perché un apostrofo dentro un frammento di codice cambierebbe il frammento, e il confronto dei fatti andrebbe giustamente in rosso.
È stato eseguito come glob su un’intera cartella di lingua. Ha convertito un apostrofo dentro una citazione di uscita di un programma, in un articolo scritto da un altro turno, che si trovava per caso nella stessa cartella.
Il mascheramento era corretto e il bersaglio sbagliato
La riga danneggiata era una citazione di ciò che un comando aveva stampato, messa dentro le virgolette basse come prosa corrente invece che marcata come codice. Qualcosa della forma Locking administration user's password. Quell’apostrofo appartiene alla macchina che l’ha emesso, e arricciarlo fa affermare all’articolo che la macchina ha detto qualcosa che non ha detto.
La regola di mascheramento è giusta. I backtick e i blocchi delimitati sono codice. Una citazione di uscita di un programma composta come prosa non è marcata come codice e non si può distinguere dalla prosa guardando i caratteri, perché è precisamente quello che è: prosa che cita una macchina.
Il difetto non sta dunque nel mascheramento. Sta nella selezione. Tre articoli di altri turni sono stati modificati da uno script scritto per toccarne quattro.
Perché il controllo della build non se n’è accorto
Questa è la parte che si generalizza oltre un singolo script.
I nostri articoli sono generati. La fonte è markdown, l’uscita sono file generati e committati, e c’è un controllo che ricostruisce dalla fonte e pretende che il risultato sia identico byte per byte a quanto è committato. Se i due divergono, va in rosso.
Non divergevano. Lo script ha cambiato la fonte, la build è stata eseguita, l’uscita è stata rigenerata dalla fonte cambiata, e le due coincidevano alla perfezione. Il controllo risponde a «l’uscita è coerente con la fonte», che è una domanda vera ma non questa. Nulla nella catena risponde a «questo turno ha cambiato solo ciò che doveva cambiare».
Nemmeno la prova di tipografia se n’è accorta, per la stessa ragione al contrario: in francese un apostrofo arricciato è il carattere corretto. Il cambiamento ha reso il file più conforme, non meno.
L’unica cosa che l’ha mostrato è stato git status su percorsi fuori dai file propri del turno. Ora la regola è questa: dopo aver eseguito una qualsiasi trasformazione, elenchi i file cambiati e confermi che ognuno di essi è suo.
La regola che ne segue
Esegua uno script di trasformazione sui nomi dei file del proprio turno. Mai su un glob sopra una cartella.
Scritto così sembra ovvio, e non era ovvio mentre lo si scriveva, perché un glob su una cartella di lingua è il modo naturale di esprimere «converti gli articoli francesi» e lo script aveva una corretta proprietà di sicurezza che lo faceva sembrare sicuro: pretende almeno una sostituzione per file, così che una corsa che in silenzio non fa nulla non possa riportare successo. Quel controllo riguarda il successo vacuo. Non dice nulla sull’ambito.
Un controllo di sicurezza che protegge dal fare troppo poco non è un controllo di sicurezza contro il fare troppo. Sono proprietà distinte e hanno bisogno di meccanismi distinti.
Due versioni più piccole dello stesso problema
Il turno che ci è incappato ha incontrato anche due difetti di traduzione della stessa famiglia: qualcosa che avrebbe dovuto essere immune alle modifiche non era marcato come tale.
Una direttiva di caching compariva nella fonte come prosa nuda invece che fra backtick. Due lingue l’hanno tradotta, il che trasforma una parola chiave in una locuzione, e una delle due ha per giunta reso plurale una durata di un anno. Nessuno dei due casi viene intercettato dal confronto dei fatti, perché quel confronto copre ciò che sta fra backtick e ciò che è una cifra, e una parola chiave nuda non è né l’uno né l’altro. La riparazione è marcarla come termine in tutte e nove le lingue, dopo di che il confronto la copre in modo permanente.
Il secondo era una tabella di etichette dell’interfaccia. L’articolo inglese la usava per mostrare che due elenchi di nomi si erano allontanati, e dichiarava esplicitamente che lo scostamento era stato misurato in inglese. Sei delle otto traduzioni hanno tradotto la tabella. Una coppia di nomi tradotta non è una versione più blanda della misura; è una misura diversa, che non è mai stata presa. Disfarlo ha richiesto 26 sostituzioni.
Entrambi i difetti hanno la stessa forma dell’apostrofo: un pezzo di testo che è dato e non lingua, in una posizione in cui nulla lo marca come dato.
Ciò a cui un controllo risponde è più stretto di ciò a cui sembra rispondere
I tre meccanismi in gioco qui sono ciascuno corretto e ciascuno ha risposto a una domanda adiacente a quella che contava.
| Controllo | La domanda a cui risponde | La domanda a cui non risponde |
|---|---|---|
| Il controllo della build dei contenuti | l’uscita generata è coerente con la fonte | questo cambiamento ha toccato soltanto i file voluti |
| La prova di tipografia | questo file usa i caratteri giusti per la propria lingua | quei caratteri sono nei posti giusti |
| La protezione interna dello script | questo file ha ricevuto almeno una sostituzione | qualche file ha ricevuto una sostituzione che non doveva ricevere |
Nessuno di questi è progettato male. L’errore è il presupposto che un muro di controlli verdi costituisca copertura, mentre ciò che costituisce davvero è la copertura delle cose a cui qualcuno ha pensato.
La contromisura più economica non è un altro controllo. È guardare il diff, al livello dei nomi dei file, prima di committare qualsiasi cosa prodotta da uno script.
Che cosa annoteremmo
- Delimiti una trasformazione ai file del proprio turno. Un glob su una cartella non è un ambito, è una categoria.
- Una protezione contro il fare troppo poco non dice nulla sul fare troppo. Sono proprietà diverse.
- Una citazione di uscita di un programma è un dato. La marchi come codice, oppure una trasformazione del testo la tratterà come lingua.
- Un controllo di coerenza fra fonte e uscita è cieco a un cambiamento in entrambe. Risponde sull’accordo, non sull’intenzione.
- Un cambiamento che rende un file più corretto è il più difficile da notare, perché ogni segnale di qualità va nella direzione giusta.
- Legga l’elenco dei file del proprio diff. È l’unico controllo che risponde alla domanda sull’ambito.
- Tutto ciò che è una parola chiave va fra backtick nella fonte, in ogni lingua, oppure qualcuno la tradurrà e nessuna prova se ne curerà.
- Una misura tradotta è una misura inventata. Se il senso di una tabella è che due cose differiscono, la tabella è una prova e non prosa.
Per chiarezza su che cosa sia: il danno è stato annullato, il turno si è concluso con il controllo dei contenuti a 815 file generati su 815 identici byte per byte, la suite web a 4546 verdi, le suite dei pacchetti, del gateway e degli strumenti a 7236 verdi, il confronto dei fatti su 1240 paragrafi senza rilevamenti, i collegamenti a 81 su 81, le tabelle a 99 su 99 e la scansione dell’impaginazione a 108 su 108 a 390 pixel contro una build di produzione. La prova di tipografia è stata dimostrata rossa con due difetti piantati e verde in seguito. Non dimostrato: c’è un lettore per traduzione, tre lingue sono state controllate soltanto su impaginazione, tipografia e stato HTTP, e le cifre citate da turni precedenti non sono state rimisurate qui.
Dal lavoro di piattaforma su Provibr. Che cosa ha trovato un secondo lettore negli stessi otto articoli si trova in tre difetti che nessuno script poteva vedere, e che cosa fanno nove cataloghi a un insieme fisso di controlli si trova in sedicimila chiavi, nove lingue.