Há quase vinte anos, obtive muitas informações sobre o excelente livro de David Thielen "Sem erros: entrega de código sem erros em C e C ++", que agora está disponível como PDF gratuito .
Ele me ensinou duas grandes idéias ...
Os erros não vêm do nada. Todos nós, programadores, sentamos e os escrevemos em nosso código com nossos próprios dedos.
"Bug" indica que alguma agência externa decidiu infestar seu programa com bugs e que, se você vive uma vida limpa e sacrifica pequenos animais peludos ao pé do computador, eles desaparecem ... Esse conceito é importante porque é colorido sua abordagem para depurar seu código. Se você vê os erros como "bugs", espera que nenhum seja encontrado. (Você espera que a boa fada tenha aparecido, polvilhado pó de duende e os insetos deixados.)
Os bugs não devem ser chamados de bugs, eles devem ser chamados de Massive Fuck-Ups [MFUs] ... As MFUs existem porque os programas são escritos por pessoas e as pessoas cometem erros ... Você escreverá MFUs. Você se sentará e, com total malícia de premeditação, colocará MFUs em seu código. Pense nisso - você sabe que é você quem está colocando os bugs lá. Portanto, se você se sentar para codificar, estará inserindo alguns bugs.
Como é o destino inevitável de todos os programadores escrever bugs, preciso codificar defensivamente, incluindo coisas que irão pular, gritar e acenar bandeiras vermelhas quando detectarem um bug.
Tendo sido escrito no início dos anos 90, os detalhes sobre isso no livro de Thielen são bastante antigos. Por exemplo, no Linux e Mac OS X, você não precisa mais escrever seu próprio wrapper para o novo operador C ++; você pode usar o valgrind para isso.
Mas há algumas coisas que eu faço rotineiramente para C / C ++ / ObjC:
- Quando razoavelmente possível, ative a opção "Avisos são erros" do compilador e corrija todos eles. (Eu mantenho um projeto legado em que a correção de todos de uma só vez levaria semanas, então eu apenas conserto um arquivo a cada poucas semanas - e em alguns anos, posso ativar essa opção.)
- Use uma ferramenta de análise de código estática, como o PC-Lint da Gimpel ou a muito bacana agora incorporada no Xcode da Apple. A cobertura é ainda melhor, mas o custo é para grandes corporações, não meros mortais.
- Use ferramentas de análise dinâmica, como valgrind, para verificar problemas de memória, vazamentos, etc.
- Como diz Thielen (e ainda vale a pena ler o capítulo): Afirme o mundo . Obviamente, ninguém além de um idiota chamará sua função com um ponteiro nulo - e isso significa que alguém, em algum lugar, é um idiota que fará exatamente isso. Pode até ser você em três anos quando o que você estava fazendo hoje ficou nebuloso. Portanto, basta adicionar uma declaração no início da função para validar esse argumento do ponteiro - leva três segundos para digitar e desaparece no executável do release.
- Em C ++, o RTTI é seu amigo. Novamente, ninguém além de um idiota chamará sua função com um ponteiro para o tipo errado de objeto - o que significa que, inevitavelmente, algum idiota o fará - e o custo para se defender disso é insignificante. No código baseado em C derivado do GObject, você pode fazer o mesmo com as macros defensivas de conversão dinâmica.
- Os testes automatizados de unidade e regressão agora são uma parte essencial do meu repertório. Em um projeto, eles são parte integrante do sistema de compilação de lançamento, e a compilação não será concluída a menos que todos sejam aprovados.
- Outra parte importante é o código de log nos executáveis de depuração e lançamento que podem ser ativados no tempo de execução por algo como uma variável de ambiente.
- Escreva testes defensivos para que os programadores que executam executáveis de depuração não possam ignorá-los se falharem. Mensagens de tempo de execução para o console podem ser ignoradas. O programa que trava com uma declaração não pode ser ignorado.
- Ao projetar, forneça APIs públicas e implementações privadas que o código externo não pode obter. Dessa forma, se você precisar refatorar, ninguém confiará em alguma variável mágica do estado interior ou algo assim. Nas aulas de C ++, sou um grande fã de protegido e privado para isso. Eu também acho que as classes proxy são ótimas, mas não as utilizo pessoalmente.
Obviamente, o que você fará para um novo idioma ou tecnologia variará nos detalhes. Mas uma vez que você leva em consideração as noções de que os erros são importantes, você escreveu com seus próprios dedos, e seu código está sob ataque constante de um exército de idiotas, com você na cabeça como general, tenho certeza de que você descobrirá técnicas defensivas adequadas.