Quasi venti anni fa, ho avuto un sacco di informazioni sull'eccellente libro di David Thielen "No Bugs: Delivering Error-Free Code in C e C ++", che ora è disponibile come PDF gratuito .
Mi ha insegnato due grandi idee ...
I bug non vengono dal nulla. Tutti noi programmatori ci sediamo e li scriviamo nel nostro codice con le nostre dita.
"Bug" connotes that some outside agency decided to infest your program with bugs and that if you live a clean life, and sacrifice small furry animals at the foot of your computer, they will go away... This concept is important because it colors your approach to debugging your code. If you view mistakes as "bugs," you hope none are found. (You hope the good fairy came by, sprinkled pixie dust, and the bugs left.)
Bugs should not be called bugs, they should be called Massive Fuck-Ups [MFUs]... MFUs exist because programs are written by people, and people make mistakes... You will write MFUs. You will sit down and with complete malice of forethought put MFUs in your code. Think about it - you know that you are the one putting the bugs in there. So if you sit down to code, you will be inserting some bugs.
Poiché è il destino inevitabile di tutti i programmatori di scrivere bug, ho bisogno di codificare in modo difensivo, comprese le cose che salteranno su, urlano e sventolano bandiere rosse quando rilevano un bug.
Essendo stato scritto nei primi anni '90, le specifiche su questo nel libro di Thielen sono piuttosto datate. Ad esempio, su Linux e Mac OS X, non è più necessario scrivere il proprio wrapper per il nuovo operatore C ++; puoi usare valgrind per questo.
Ma ci sono alcune cose che faccio abitualmente per C / C ++ / ObjC:
- Quando posso ragionevolmente, attivare l'opzione "Warnings are errors" del compilatore e correggerli tutti. (Conservo un progetto legacy in cui sistemare tutto in una volta richiederebbe settimane, quindi aggiusto un file ogni poche settimane e, in pochi anni, posso attivare questa opzione.)
- Utilizza uno strumento di analisi del codice statico, come PC-Lint di Gimpel o quello molto elegante ora integrato nell'Xcode di Apple. La copertura è ancora migliore, ma il costo è per le grandi società, non semplici mortali.
- Utilizza strumenti di analisi dinamica, come valgrind, per verificare problemi di memoria, perdite, ecc.
- Come dice Thielen (e vale ancora la pena leggere il capitolo): Assert The World . Naturalmente, nessuno tranne un idiota chiamerà la tua funzione con un puntatore nullo - e questo significa che qualcuno, da qualche parte, è un idiota che farà proprio questo. Potresti essere anche tu tra tre anni quando quello che stavi facendo oggi è diventato nebbioso. Quindi basta aggiungere un assert all'inizio della funzione per convalidare l'argomento del puntatore - ci vogliono tre secondi per scrivere e va via nell'eseguibile della versione.
- In C ++, RTTI è tuo amico. Di nuovo, nessuno tranne un idiota chiamerà la tua funzione con un puntatore al tipo di oggetto sbagliato - il che significa che, inevitabilmente, qualche idiota lo farà - e il costo per difendersi da ciò è trascurabile. Nel codice basato su C derivato da GObject, puoi fare la stessa cosa con le macro di cast dinamiche difensive.
- I test automatici di regressione e unità sono ora una parte fondamentale del mio repertorio. Su un progetto, sono parte integrante del sistema di generazione del rilascio e la compilazione non verrà completata a meno che non tutti passino.
- Un'altra parte fondamentale è la registrazione del codice in entrambi gli eseguibili di debug e release che possono essere abilitati in fase di esecuzione da qualcosa di simile a una variabile di ambiente.
- Scrivi test difensivi in modo che i programmatori che eseguono gli eseguibili di debug non possano ignorarli se falliscono. I messaggi di runtime sulla console possono essere ignorati. Il programma in crash con un assert non può essere ignorato.
- Durante la progettazione, fornire API pubbliche e implementazioni private a cui il codice esterno non può accedere. In questo modo, se hai un refactoring, nessuno si affida a qualche variabile di stato interiore magico o qualcosa del genere. Nelle classi C ++, sono un grande fan di protetto e privato per questo. Penso anche che le classi proxy siano fantastiche, ma in realtà non le uso personalmente.
Ovviamente, ciò che farai per una nuova lingua o tecnologia cambierà nei dettagli. Ma una volta che prendi nel tuo cuore le nozioni che i bug sono Massive Fuck-Ups che hai scritto con le tue dita, e il tuo codice è sotto costante assalto da un esercito di idioti, con te come capo generale, sono sicuro che tu scoprirò tecniche difensive idonee.