Salta al contenuto principale

Come il delta debugging trasforma un salvataggio difettoso in un caso minimo di regressione

Originale Persistium diagramma di riduzione controcampione che mostra un grande stato rotto ristretto in un piccolo dispositivo di regressione riproducibile.

Un metodo pratico per ridurre una sequenza riproducibile di salvataggio o azione rotta in un piccolo dispositivo di regressione verificabile senza perdere l'invariante violato.

Un grande salvataggio rotto è la prova, non una spiegazione

Quando un salvataggio non riesce a caricare, una ricerca scompare, o una migrazione viola una regola di gioco, il primo artefatto può essere enorme: centinaia di campi, raccolte nidificate, una lunga storia d'azione, un'istantanea di contenuti e un ambiente che non esiste più. Questo artefatto è prezioso perché riproduce il problema. È difficile perché dà uno sviluppatore molto più informazioni di quanto possano ragionare subito.

Invece di chiedere a una persona di individuare l'unico valore rilevante, chiedere a un predicato deterministico se un candidato dimostra ancora il fallimento. Quindi rimuovere o semplificare le parti dello stato mentre il predicato rimane vero. Il risultato finale è un caso di regressione minima: abbastanza piccolo da rivedere, abbastanza stabile da rigiocare, ed esplicita circa l'invariante che rimane rotto.

Il Minimal non significa visivamente piccolo o universalmente più piccolo. L'obiettivo utile è un controcampione materialmente ridotto sotto un costo limitato. Un riduttore può fermarsi quando nessun intero gruppo può essere rimosso, quando un bilancio di esecuzione è esaurito, o quando l'apparecchio è abbastanza comprensibile per diventare un test di regressione. La proprietà conservata conta più di un ottimale astratto.

Stabilire la riproducibilità prima della riduzione

La riduzione funziona solo quando il fallimento è ripetibile. Prima cattura il predicato preciso: l'attuale caricatore getta un errore classificato, fa un falso ritorno invariante, uno stato risultante differisce semanticamente dal risultato previsto, o una sequenza di azione produce una sovvenzione non valida? Evitare di usare un predicato vago come “il gioco sembra sbagliato.” Il predicato deve restituire la stessa risposta per gli stessi input, o il riduttore inseguirà il rumore.

Registrare l'ambiente accanto al candidato: l'applicazione costruire o commettere, la versione di migrazione, la versione di adattatore, il contenuto e la configurazione snapshot, il seme deterministico, le assunzioni di piattaforma e l'hash di avviamento. Se un orologio live, una sorgente casuale, un fetch di configurazione remoto, o un lavoratore di sfondo possono cambiare il risultato, sostituirlo con un limite di prova deterministico o registrarlo come una limitazione esplicita.

Per i guasti di sequenza d'azione, conservare lo stato iniziale e le azioni ordinate separatamente. Uno stato finale può nascondere l'operazione che l'ha prodotta. Un dispositivo di sequenza può esprimere "avviare da questo profilo, eseguire queste sette richieste, poi l'invariante fallisce".

Ridurre campi e collezioni in partizioni

Dividere il livello superiore salvare in gruppi di campo, rimuovere un gruppo da una copia di lavoro e eseguire il predicato. Se il fallimento persiste, mantenere la rimozione; se scompare, ripristinare il gruppo e suddividerlo. Questo è più efficiente che eliminare un campo alla volta da un grande oggetto. Continua a nidificare record e collezioni una volta che una regione rilevante è identificato.

La rimozione di una voce può cambiare indici di elenco, regole di capacità, o bilanciamenti aggregati. Normalizzare l'ordine in cui l'ordine non è significativo, preservare identificatori stabili in cui i riferimenti richiedono loro, e dichiarare se un elemento mancante dovrebbe essere assente, nullo, o rappresentato da un fallback legacy esplicito.

Spostare interi verso zero o un limite importante, accorciare le stringhe, sostituire un identificatore lungo con un identificatore di prova sicuro, e ridurre i timestamp ad un'epoca stabile solo quando il loro valore esatto non è la condizione sotto test. Ogni semplificazione deve mantenere il predicato vero. Questo spesso rivela che un apparente bug del profilo complesso è davvero "un ID dell'elemento in pensione più un inventario completo" o "una versione negativa saltata un contro

Originale restringimento-stato visivo che mostra un salvato rotto diviso, semplificato, riprodotto, e conservato come un dispositivo di regressione minimo.
La riduzione si alterna tra rimozione controllata e ripetizione deterministica fino a quando l'importante fallimento rimane in uno stato più piccolo.

Ridurre le sequenze di azione senza cambiare il loro significato

Alcuni fallimenti emergono solo dopo il tempo: una riprovazione di acquisto dopo una riconnessione, un salvataggio dopo un aggiornamento di configurazione, o una migrazione dopo un tutorial interrotto. Applicare la stessa idea di partizionamento alle azioni. Rimuovere una metà contigua della sequenza, riprodurre, e mantenere la rimozione se l'invariante ancora fallisce. Quindi subdividere.

Le azioni devono avere parametri stabili e risultati attesi definiti. Un riduttore che sostituisce ogni richiesta con un nuovo ID di transazione casuale non verifica più la semantica originale dei tentativi ripetuti. Un riduttore che elimina il caricamento iniziale dei flag di funzionalità può alterare il contesto di configurazione. Registrare l’identità dell’azione, gli input rilevanti, se la fonte è attendibile o non attendibile e il punto in cui viene verificata l’invariante. In questo modo la sequenza finale è utile sia agli sviluppatori sia al controllo qualità.

Quando una sequenza dipende dalla convalutazione, scegliere un calendario deterministico. Registrare l'ordine in cui i lavoratori o i clienti simulati raggiungono i confini critici. Se il fallimento si verifica solo sotto una gara, un test potrebbe avere bisogno di una barriera controllata piuttosto che di chiamate a sonno dipendente dal tempo. L'obiettivo non è quello di fingere la convalutazione è semplice; è quello di rendere l'interleaving osservato riproducibile abbastanza per ragionare.

Conservare l'invariante violato nel manufatto finale

Un piccolo apparecchio senza un'affermazione diventa un altro file misterioso. Conservare l'invariante violato accanto all'apparecchio in termini chiari: il diritto duplicato per un'identità di transazione, il riferimento di catalogo sconosciuto dopo la migrazione, la valuta negativa, la ricerca completa inaccessibile, o l'errore semantico dopo un giro.

Confronta prima e dopo lo stato semanticamente. Un diff raw può contenere timestamp riscritti, array riordinati, ID generati, o formattazione di serializzazione. Un diff semantico evidenzia i valori che interessano l'invariante. Può segnalare che un elemento modificato da un fallback legacy valido a un ID sconosciuto, o che un saldo è stato incrementato due volte per la stessa chiave di registro.

Scrivere un manifesto di ripetizione con il percorso di fissazione, hash sorgente, hash ridotto, impronta ambientale, seme deterministico, sequenza d'azione se, nome predicato e risultato atteso. Questo manifesto permette ad un'altra persona di eseguire il caso senza accesso allo stato sovradimensionato originale.

Sapere quando la riduzione dovrebbe smettere

Alcune migrazioni sono lente; alcuni scenari hanno bisogno di adattatori di servizio; alcune condizioni di guasto sono inquietanti fino a quando un ambiente è fisso. Impostare i budget per tentativi, il tempo di parete e il conteggio di artefatti. Fermare quando l'apparecchio è abbastanza piccolo per spiegare il problema, quando nessuna partizione può essere rimosso senza perdere il fallimento, o quando il lavoro rimanente richiede giudizio di dominio piuttosto che restringimento meccanico.

La riduzione ha dei limiti. Non può decidere se un vecchio oggetto debba corrispondere a un sostituto, se una missione ritirata richieda una compensazione o se un valore salvato sia valido in un’economia riprogettata. Queste sono decisioni di prodotto. Inoltre, non può ridurre in sicurezza dati cifrati o sensibili copiandoli in strumenti ad accesso esteso. In questi casi, creare un equivalente sintetico che preservi la condizione strutturale oppure mantenere l’indagine riservata entro il perimetro di accesso appropriato.

I nomi delle strisce, le informazioni di contatto, i dati di ricezione, gli identificatori dei dispositivi, i gettoni di accesso e qualsiasi campo non necessario per il predicato. Un apparecchio minimo è l'opportunità di migliorare la privacy e la diagnosi. L'artefatto finale dovrebbe essere sicuro di includere nel corpo di prova del progetto e abbastanza utile per prevenire la ricorrenza.

Controllo pratico

  • Definire un predicato di fallimento deterministico prima di rimuovere qualsiasi stato.
  • Registra l'applicazione, l'adattatore, il contenuto, la configurazione, il seme e l'ambiente di fissaggio.
  • Mantenere la sequenza iniziale di stato e azione separata quando il comportamento si svolge nel tempo.
  • Riduci prima i gruppi di alto livello, poi i campi, le collezioni e i valori nidificati.
  • Conservare i riferimenti e la validità strutturale durante la sfida della rilevanza semantica.
  • Utilizzare un programma di concordanza controllato invece di tempistiche-dipendenti.
  • Conservare l'invariante violato, la classificazione prevista, diff semantico, e rigiocare manifesta con il risultato.
  • Fermarsi a un utile controesempio legato; non ottimizzare indefinitamente per la minimalità teorica.
  • Ridurre o sintetizzare i dati sensibili prima che un apparecchio entri nei test di routine.

Domande frequenti

Il delta è debug solo per gli incidenti?

No. Il predicato può essere un crash, ma può anche essere un invariante di gioco violato, un conteggio di diritto sbagliato, un viaggio di salvataggio fallito, una classificazione di migrazione rifiutata, o un errore tra stato atteso e osservato.

E se il fallimento fosse intermittente?

Ridurre in primo luogo il nondeterminismo. Fissare i semi, catturare la configurazione, isolare i confini del tempo e della rete, e controllare la convalutazione. Se il risultato rimane probabilità, utilizzare un predicato basato sulla soglia solo con la cura e registrare che la limitazione.

Può un riduttore correre contro i dati di produzione?

La riduzione della routine non dovrebbe. Utilizzare i dispositivi sintetici o recisi e un ambiente controllato. Un'indagine sugli incidenti ristretti può avere bisogno di prove protette, ma che è un processo operativo separato con controlli di accesso, regole di conservazione e revisione.

Cosa afferma Persistium qui?

Persistium è in sviluppo come una famiglia di prodotti di affidabilità locale. Questa nota presenta un flusso di lavoro di riduzione generalmente utile e non sostiene che un prodotto pubblico diagnostica automaticamente i risparmi arbitrari, ha osservato i guasti del cliente, o gestisce un servizio di analisi ospitato.

Sistema correlatoEsplorare Persistium