Pinakes 0.7.85 è online. Tre delle quattro cose che contiene nascono da qualcuno che stava usando il programma e si è fermato davanti a un ostacolo: due richieste arrivate da un utente su GitHub e una segnalazione da una biblioteca vera, che mi ha mostrato una schermata in cui il salvataggio annullava ciò che l’utente aveva appena fatto. La quarta l’ho trovata io, ed è la più imbarazzante: un test che si spegneva da solo.
Correggere trecento libri senza aprirne trecento
Dopo un’importazione capita spesso che un intero scaffale abbia bisogno della stessa correzione: l’illustratore che nessuno ha compilato, un editore scritto in modo diverso, un genere che vale per tutti. Fino a ieri l’unico modo era aprire i libri uno per uno, ed è esattamente il punto in cui si smette di correggere il catalogo.
Nella lista dei libri ora c’è «Modifica campo», accanto alle azioni di massa che c’erano già. Si sceglie il campo — autori, illustratori, traduttori, curatori, coloristi, editore o genere — e come applicarlo. «Aggiungi» somma il valore a quelli già presenti senza duplicarlo; per il genere, che è un valore solo, riempie soltanto i libri che non ne hanno, così un riempimento di massa non può sovrascrivere una classificazione scelta a mano. «Sostituisci» lo rende l’unico valore, dopo una conferma che dice quale campo e quanti libri.
La parte che non si vede è quella a cui ho dedicato più tempo. Tutta la selezione viene applicata in una transazione sola: o si scrive tutto, o non si scrive niente. Il nome digitato viene risolto una volta per l’intero lotto, quindi un autore battuto per trecento libri crea un autore, non trecento. E le scritture relazionali passano per lo stesso codice che usa il modulo del singolo libro, non per una copia: reimplementarle avrebbe silenziosamente perso tre cose che quel codice fa e che nessuno nota finché non si rompono — il rilascio della provenienza di importazione, senza il quale la prossima reimportazione cancella la scelta manuale scambiandola per un residuo; l’aggiornamento delle colonne denormalizzate che l’esportazione CSV e l’API pubblica leggono ancora; e la gestione dei punti di salvataggio dentro la transazione.
Un universo che si vede
La lista delle collane ordinava già le righe come un albero — prima l’universo, poi i suoi cicli — ma tutte le righe erano identiche: per capire che un ciclo apparteneva a un universo bisognava leggere la colonna del genitore e ricostruirsi la gerarchia in testa.
Adesso il blocco è disegnato. L’intestazione porta l’icona dell’universo, uno sfondo appena diverso e il numero di serie che raccoglie; i figli sono rientrati e uniti da una linea che scende finché il blocco continua e si chiude ad angolo sull’ultimo. Alla fine del blocco c’è una riga più scura, ed è il dettaglio che conta di più: quando dopo un universo arriva una serie ordinaria senza gerarchia, senza quel segno non c’era nulla che dicesse che l’universo era finito.
Il salvataggio che annullava sé stesso
Questa è arrivata da una biblioteca: «ho disattivato la sezione caratteristiche, ma quando salvo ritorna». E in più le caratteristiche continuavano a vedersi sul sito pubblico.
La visibilità di una sezione stava su quella pagina due volte. C’è un interruttore nell’elenco di ordinamento in cima, che scrive nel database appena lo tocchi, e c’è una spunta «Visibile» dentro la scheda della sezione, che viene scritta quando premi Salva. I due non si parlavano. Quindi la sequenza più naturale del mondo — spengo in cima, salvo — rimandava al server il valore che la pagina aveva al caricamento, e riaccendeva la sezione. L’interruttore aveva funzionato: era il salvataggio ad annullarlo.
La seconda metà del problema era più sottile e si vedeva sul sito pubblico. Quella biblioteca aveva disattivato le quattro schede delle caratteristiche, e ci era riuscita; ma il contenitore era rimasto acceso, e il modello, non trovando le schede spente, le disegnava comunque riempiendo i buchi con i propri valori di ripiego. Il risultato era un sito pubblico con quattro riquadri intitolati «Feature 1», «Feature 2», «Feature 3», «Feature 4», una stella ciascuno e nessun testo. Ora vengono disegnate solo le schede davvero attive, e se non ne resta nessuna la griglia non compare affatto.
Guardando il resto del pannello contenuti sono saltate fuori altre due cose. Un campo non valido faceva scartare tutte le modifiche della pagina, mentre il messaggio nominava solo il campo colpevole: si legge come «quel campo è stato ignorato» mentre in realtà non era stato salvato niente. Adesso lo dice. E l’indirizzo /admin/cms, quello a cui chiunque accorcia gli altri, rispondeva 404: le tre voci esistevano solo come pulsanti dentro le impostazioni, e una pagina che le impostazioni non collegano si poteva raggiungere solo digitandone lo slug. Ora c’è un indice, costruito leggendo il database e non un menu fisso.
Un test che si spegneva da solo
L’ultima non è una funzione, ma è la cosa che mi ha insegnato di più. C’è una suite che verifica la migrazione dello schema dell’emeroteca, e il suo valore sta tutto in un punto: smonta lo schema fino alla versione precedente e poi esegue l’aggiornamento vero, perché è l’unico modo per accorgersi di una colonna dimenticata o di una normalizzazione dei dati che fa la cosa sbagliata.
Quella parte era protetta da una variabile d’ambiente, per non smontare per sbaglio lo schema del database di sviluppo. Senza quella variabile la suite stampava SKIP e proseguiva dicendo «tutto a posto». In locale nessuno la impostava mai. Risultato: i centoquarantacinque controlli che provano davvero l’aggiornamento non erano mai stati eseguiti fuori dall’integrazione continua, e il controllo di qualità locale risultava rosso per un test che si dichiarava verde.
Adesso il lavoro avviene in un database tutto suo, creato al momento, e la scorciatoia non esiste più: la suite passa da 215 a 360 controlli. Ma il numero da solo non dimostra niente, quindi ho rotto la migrazione di proposito due volte per vedere se se ne accorgeva — togliendo la protezione che impedisce di sovrascrivere una condizione già registrata, e togliendo la guardia su una collisione di chiavi uniche. Entrambe le volte è caduta, e sono due errori sui dati che nessuna verifica di schema avrebbe visto.
Una postilla che mi sono guadagnato da solo: la prima versione della protezione controllava di stare lavorando sul database giusto confrontandolo con il nome configurato. Solo che se qualcuno configura come «database usa e getta» il database vero, quel confronto è soddisfatto e il test cancella le tabelle dell’installazione. Una guardia che verifica la propria coerenza interna non protegge da un valore sbagliato in ingresso. Ora quel nome viene rifiutato prima di qualsiasi scrittura.
Come si aggiorna
Dal pannello di amministrazione, sezione Aggiornamenti: Pinakes scarica il pacchetto, fa il backup e applica la migrazione da sé. Chi usa l’immagine Docker prende fabiodalez/pinakes:0.7.85 oppure latest. Il pacchetto e il suo checksum sono nella pagina della release.