Quanto dovremmo essere difensivi?

11

Abbiamo eseguito Pex su un po 'di codice, e ha mostrato alcune buone cose (cose brutte, ma mostrandole prima che arrivi alla produzione!).

Tuttavia, una delle cose belle di Pex è che non smette necessariamente di cercare problemi.

Un'area che abbiamo trovato è che quando passavamo in una stringa, non stavamo controllando le stringhe vuote.

Quindi abbiamo cambiato:

if (inputString == null)

a

if (string.IsNullOrEmpty(inputString)) // ***

Questo ha risolto i problemi iniziali. Ma poi, quando abbiamo eseguito di nuovo Pex, abbiamo deciso che:

inputString = "inputString = "\u0001"; ";

stava causando problemi. E poi

if (inputString == null)

Quello che abbiamo deciso è che i valori di default possono essere usati se incontriamo // *** e che siamo felici di vedere l'eccezione causata da qualsiasi altro input dispari (e che ci occupiamo di esso).

Basta così?

    
posta Peter K. 17.06.2011 - 16:51
fonte

4 risposte

9

Tre domande dovrebbero aiutarti a determinare quanto difensivo essere nella tua codifica.

Primo: quali sono le conseguenze del cattivo input? Se si tratta di un messaggio di errore su uno dei PC del tuo sviluppatore, forse non è così critico da essere sulla difensiva. Potrebbe causare interruzioni finanziarie ai clienti, interruzione delle informazioni contabili di IE? È un sistema in tempo reale in cui le vite sono a rischio? Nello scenario vita / morte, probabilmente ci dovrebbe essere più codice di validazione e gestione degli errori rispetto al codice di funzione effettivo.

In secondo luogo, quante persone riutilizzeranno questa funzione o parte di codice? Solo tu? Il tuo dipartimento? La tua azienda? I tuoi clienti? Più ampio è l'uso del codice, più difensivo.

Terzo - qual è la fonte dell'input che sto convalidando? Se viene inserito dall'utente o da un sito Web pubblico, sarei estremamente difensivo. Se l'input proviene sempre dal tuo codice, sii un po 'difensivo, ma non spendere troppo tempo a mettere gli assegni.

Sarà sempre possibile aggiungere più controllo degli errori e convalida in un sistema. Il punto è che il costo di scrittura e manutenzione di questo codice supererà il costo dei problemi causati da errori nel codice.

    
risposta data 17.06.2011 - 17:04
fonte
6

Gli utenti sono malvagi e tutto ciò che inseriscono dovrebbe essere controllato con il massimo rigore.

Qualsiasi cosa generata senza il beneficio dell'input dell'utente, o dai dati pre-disinfettati, non dovrebbe essere controllata allo stesso livello. Il problema qui è quando dimentichi e usi questi metodi su dati errati, perché hai dimenticato che il codice non è stato rafforzato.

L'unica cosa che dovresti controllare è tutto ciò che potrebbe causare un overflow o un crash. Non importa quanto profondamente sia sepolto quel metodo, e quanto sia sicuro che quella condizione non possa mai accadere. Devi comunque programmarlo, solo per placare Murphy.

    
risposta data 17.06.2011 - 17:00
fonte
2

Sarei tanto difensivo quanto devi essere. Un po 'ambiguo, immagino di sì, ma proverò a spiegare.

Quando hai ragione su un metodo, se quel metodo ha parametri di input devi prendere la decisione su cosa ti aspetti da quei parametri. In situazioni e luoghi all'interno di un'applicazione questo sarà diverso. Ad esempio, se un metodo o parte di codice accetta dati da un input dell'utente, vorresti coprire tutto il codice base e gestire qualsiasi input di conseguenza, sia tramite un messaggio di errore che con un buon modo di visualizzare dati inaccettabili.

Se il metodo è un idem esposto API. Non puoi controllare ciò che sta arrivando, quindi dovresti provare a coprire tutti gli aspetti e programmare di conseguenza.

Per i metodi che sono prodotti all'interno del core engine del tuo progetto, qui hai una decisione da prendere. Presumo che i dati in arrivo siano stati pre-selezionati e convalidati prima di arrivare o se dovessi effettuare i controlli necessari. Immagino che questo dipenda dal livello concettuale del metodo e se questo è un posto accettabile da verificare. Quindi le cose che potrei considerare sono:

1) È questo l'unico posto dove ho bisogno di fare questo controllo? Questa variabile dovrà essere controllata in molti posti diversi per questa condizione. Se è così posso fare il controllo una volta più in alto sulla catena e poi assumere la validità in seguito

2) Ci si aspetta che altri componenti del sistema lavorino con i metodi e le interfacce che scrivo. In tal caso, è possibile controllare le istruzioni di debug assert, eseguire il debug delle eccezioni, commentare i metodi e l'architettura generale del sistema, il risultato desiderato oppure i dati necessitano di verifiche.

3) Quali sono i risultati di fallimento a questo punto nel codice. Farà fallire l'intera cosa? Qualsiasi errore verrà rilevato altrove e verrà rilevato almeno quell'errore.

4) Ha senso mettere un assegno qui? A volte mettendo un controllo su una parte dei possibili dati corrotti, sebbene contribuisca a risolvere il problema a quel punto e non l'errore, potrebbe aiutare a coprirlo. A quel punto potresti passare ore a cercare un altro problema solo per scoprire che il problema reale è stato a causa di un controllo valido dei dati nella catena di eventi che si sono sovrapposti a quello che è stato segnalato all'utente / sviluppatore.

In generale, sono un programmatore difensivo, ma credo anche che con un TDD approfondito e un test di unità appropriato sia possibile inserire gli assegni in codice ai livelli richiesti ed essere sicuri che funzioni come dovrebbe una volta arrivati a qualsiasi sezioni di livello inferiore.

    
risposta data 17.06.2011 - 17:39
fonte
1

Ho passato settimane prima su bug che avrebbero potuto essere rilevati con 5 minuti di lavoro extra come questo in prima pagina. Nella mia mente questo lavoro in prima fila vale sempre la pena. Alla fine sistemerai il bug. L'unica domanda è quanto ci vorrà.

Una cosa che questi strumenti di analisi spesso rivelano sono cose che non sono necessariamente bug, ma sono cattive abitudini di programmazione che rendono più probabile che si verifichino errori. Una tale abitudine comune è l'inizializzazione variabile. A volte una stringa vuota è un valore perfettamente valido per una variabile. In tal caso, si desidera configurare lo strumento in modo che non consideri un errore in quella particolare istanza. Tuttavia, spesso una stringa vuota è non un valore valido per una variabile, ma le persone lo impostano comunque, perché il compilatore si lamenta se non c'è qualcosa lì, o la tua lingua si inizializza automaticamente alla stringa vuota, indipendentemente dal fatto che sia valida o meno.

Questo frustra le persone perché sembra una presa 22 senza una soluzione valida, ma la soluzione è quella di rifattorizzare il codice in modo che non sia necessario inizializzare la variabile finché non ci sarà un valore valido da inserire. Ciò richiede un po 'di riflessione in più, ma rende il tuo codice molto più robusto, ed è in realtà più facile da scrivere e mantenere a lungo termine.

    
risposta data 17.06.2011 - 18:21
fonte

Leggi altre domande sui tag