Ho pensato a questo problema per un po 'e sarei curioso di avere opinioni da altri sviluppatori.
Tendo ad avere uno stile di programmazione molto difensivo. Il mio blocco o metodo tipico è simile al seguente:
T foo(par1, par2, par3, ...)
{
// Check that all parameters are correct, return undefined (null)
// or throw exception if this is not the case.
// Compute and (possibly) return result.
}
Inoltre, durante il calcolo, controllo tutti i puntatori prima di dereferenziarli. La mia idea è che, se c'è qualche bug e qualche puntatore NULL dovrebbe apparire da qualche parte, il mio programma dovrebbe gestirlo bene e semplicemente rifiutare di continuare il calcolo. Naturalmente può notificare il problema con un messaggio di errore nel registro o qualche altro meccanismo.
Per dirla in modo più astratto, il mio approccio è
if all input is OK --> compute result
else --> do not compute result, notify problem
Altri sviluppatori, tra cui alcuni miei colleghi, usano un'altra strategia. Ad esempio, non controllano i puntatori. Presumono che un pezzo di codice debba ricevere un input corretto e non dovrebbe essere responsabile di ciò che accade se l'input è errato. Inoltre, se un'eccezione del puntatore NULL arresta in modo anomalo il programma, verrà trovato più facilmente un bug durante il test e avrai maggiori possibilità di essere risolto.
La mia risposta è normalmente: ma cosa succede se il bug non viene rilevato durante il test e appare quando il prodotto è già utilizzato dal cliente? Qual è il modo preferito in cui il bug si manifesta? Dovrebbe essere un programma che non esegue una determinata azione, ma può comunque continuare a funzionare o un programma che si arresta in modo anomalo e deve essere riavviato?
Riassumendo
Quale dei due approcci alla gestione di input errati consiglieresti?
Inconsistent input --> no action + notification
o
Inconsistent input --> undefined behaviour or crash
modificare
Grazie per le risposte e i suggerimenti. Sono un fan del design anche per contratto. Ma anche se mi fido della persona che ha scritto il codice chiamando i miei metodi (forse sono io), ci possono essere ancora dei bug, che portano a input sbagliati. Quindi il mio approccio è quello di non dare per scontato che un metodo abbia passato l'input corretto.
Inoltre, utilizzerei un meccanismo per rilevare il problema e informarlo. Su un sistema di sviluppo, ad esempio, si aprirà una finestra di dialogo per avvisare l'utente. In un sistema di produzione scriverebbe solo alcune informazioni nel registro. Non credo che controlli extra possano portare a problemi di prestazioni. Non sono sicuro che le affermazioni siano sufficienti, se sono disattivate in un sistema di produzione: forse si verificherà una situazione nella produzione che non si era verificata durante i test.
Ad ogni modo, sono rimasto davvero sorpreso dal fatto che molte persone seguano l'approccio opposto: hanno lasciato che l'applicazione si arrestasse in modo "intenzionale" perché sostengono che ciò faciliterà la ricerca di bug durante i test.