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 tipico blocco o metodo ha questo aspetto:
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 rifiutarsi di continuare il calcolo. Ovviamente può notificare il problema con un messaggio di errore nel registro o qualche altro meccanismo.
Per dirla in un 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. Assumono che un pezzo di codice debba ricevere un input corretto e non dovrebbe essere responsabile di ciò che accade se l'input è sbagliato. Inoltre, se un'eccezione del puntatore NULL si arresta in modo anomalo nel programma, un bug verrà trovato più facilmente durante il test e avrà più possibilità di essere corretto.
La mia risposta a questo è 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 per manifestare il bug? Dovrebbe essere un programma che non esegue una determinata azione, ma può ancora continuare a funzionare, o un programma che si blocca e deve essere riavviato?
Riassumendo
Quale dei due approcci per gestire input errati consiglierebbe?
Inconsistent input --> no action + notification
o
Inconsistent input --> undefined behaviour or crash
Modifica
Grazie per le risposte e i suggerimenti. Sono un fan del design per contratto. Ma anche se mi fido della persona che ha scritto il codice chiamando i miei metodi (forse è me stesso), possono ancora esserci dei bug, che portano a input sbagliati. Quindi il mio approccio è di non assumere mai che un metodo sia passato all'input corretto.
Inoltre, vorrei utilizzare un meccanismo per rilevare il problema e notificarlo. Su un sistema di sviluppo, sarebbe ad es. aprire una finestra di dialogo per informare l'utente. In un sistema di produzione scriverebbe solo alcune informazioni nel registro. Non penso che i controlli extra possano portare a problemi di prestazioni. Non sono sicuro che le asserzioni siano sufficienti, se vengono disattivate in un sistema di produzione: potrebbe verificarsi qualche situazione nella produzione che non si è verificata durante il test.
Ad ogni modo, sono stato davvero sorpreso dal fatto che molte persone seguano l'approccio opposto: lasciano che l'applicazione si arresti "a scopo" perché ritengono che questo renderà più facile trovare bug durante i test.