Neste artigo, vamos falar um pouco da importância da falseabilidade na ciência e no método Test Driven Developement, ou TDD, dos quais ela faz parte integral.
O que é Falseabilidade
Falseabilidade é a propriedade de um enunciado ou teoria de poder ser determinado como falso pela observação ou algum experimento. Isso não significa que o enunciado seja falso, mas que, se ele o for, a falsidade pode ser mostrada.
O conceito de falseabilidade pode parecer algo trivial, mas é um conceito fundamental em ciência, como demonstrado por Karl Popper. Pra encurtar a história, se uma teoria não for falseável, ela não é científica.
Muitas pessoas confundem verdade com não-falseabilidade. Elas frequentemente postam suas alegações e exclamam “vocês não podem provar que isto está errado!”. Muitas vezes não podemos. Isso não torna o “isto” uma verdade.
Outras pessoas não conseguem entender como algo que é reconhecidamente verdadeiro possa ser “tornado falso”. Por exemplo, uma frase como “A Terra é redonda” não poderia ser “falseada” porque a Terra de fato é redonda na vida real. No entanto, podemos mostrar que “A Terra é redonda” é falseável porque podemos propor algum tipo de experimento ou de medição para verificar a forma de um planeta, e esse procedimento pode dar como resultado “sim” ou “não”. Que a resposta seja sempre “sim” para a Terra é mero detalhe, consequência do fato de que vivemos num planeta redondo.
Um exemplo clássico de uma teoria não falseável é a de que o universo foi criado em apenas 5 minutos, com todos os átomos, energia e tudo o mais no lugar onde estão, incluindo as nossas memórias de todos os anos anteriores. Isso pode ser até verdadeiro, mas se for falso não podemos provar. E essa “teoria” é indistiguível, para todos os efeitos práticos, da idéia de que o universo surgiu mesmo “lá atrás” e que tudo de fato aconteceu.
Muitas pessoas criam “teorias” e “ciências” sustentadas em falsidades ou em afirmações não falseáveis com o intuito de obter fama ou dinheiro. Elas conseguem seu objetivo porque o público em geral não consegue discernir se as afirmações são realmente científicas. Em outras palavras, existem incontáveis “pseudociências” por aí.
Um dos ramos onde elas mais se destacam é na medicina. As pessoas procuram os chamados “tratamentos alternativos” quando a medicina realmente científica não possui respostas ou quando elas são muito caras. Muitas pessoas defendem os tais tratamentos como sendo inofensivos em sua maior parte.
No entanto, eles se tornam um perigo mortal quando o paciente abandona um tratamento “tradicional” em prol do alternativo e suas doenças pioram. Por exemplo, alguém pode abandonar uma dolorosa quimioterapia em prol de um tratamento mais “fácil” e, com isso, piorar seu quadro e falecer.
Como isso se aplica ao TDD
Test Driven Development é uma metodologia de desenvolvimento muito similar ao método científico. Nela, são elaboradas hipóteses sobre um sistema, e hipóteses são escritas sob a forma de testes de unidade executáveis.
Esses testes são executados frequentemente. Isso corresponde, em ciência, à condução de experimentos. Quando um teste confirma aquilo que ele esperava, dizemos que o teste “passou” ou “deu verde”. Quando um teste não confirma sua expectativa, ele “falhou” ou “deu vermelho”.
Para que um teste seja útil no desenvolvimento de um software, é necessário que haja a possibilidade de que ele possa “dar vermelho”. Ele precisa poder falhar. Ele não pode ser do tipo em que, não importa o que aconteça, tudo fique verde. Em outras palavras: o teste precisa ser falseável.
Se você possui um sistema grande com milhares de testes, e se eles (ou parte deles) não são falseáveis, esse conjunto de testes é inútil. Ou talvez, como no caso das pseudociências, seja pior do que inútil: eles dão falsa confiança. Quando você faz uma mudança no código, eles parecem indicar que tudo está “ok”. No entanto, qualquer mudança que você fizer, introduzindo bugs ou não, não irá afetar o resultado em nada.
Como garantir a falseabilidade de seus testes
- Pratique Test-first
A forma mais efetiva e barata de produzir testes falseáveis é algo ensinado pela própria essência da metodologia TDD: escreva seus testes antes do código de produção. Execute esses testes. Veja esses testes falharem. Só então escreva código para fazê-los ficarem verdes. Se você escrever um teste que, na primeira vez em que ele é executado, está verde, você muito provavelmente criou um teste não-falseável.
É claro que nem sempre é assim. Você pode ter criado um teste apenas redundante. Por exemplo, escreveu três casos de teste e, então, implementou um código que funciona para um número infinito de casos. Qualquer novo caso de teste, similar aos anteriores, irá certamente dar verde. O que não pode acontecer é você escrever um teste que esperava ser vermelho e ele foi verde. Se você foi surpreendido, há algo de errado.
Você pode escrever um teste adicional que já “entre verde”, se souber o que está fazendo. Você pode estar fazendo isso para prover um exemplo a mais de uso do código, por exemplo. Ou pode haver outras razões.
O importante é que novos testes sejam, também, falseáveis. Isso pode ser garantido simplesmente pelo fato de que eles sejam idênticos aos testes anteriores, exceto pelos dados. Ou você pode também, por um momento, apagar o código de produção e executar os testes novamente para se sentir seguro de que todos serão vermelhos.
- Use ferramenta de cobertura
Existem ferramentas para, após a execução de um conjunto de testes, emitir um relatório indicando quais linhas de código foram executadas. Existe uma enorme polêmica em cima de ferramentas de cobertura. A principal crítica que recebem é a de que um código “coberto” foi executado por um teste, mas não necessariamente “bem” testado. No entanto, pode-se ver claramente que um linha de código não coberta é com certeza uma linha que jamais irá fazer um teste falhar. Eu considero as ferramentas de cobertura úteis para indicar esse trechos mais críticos.
- Use ferramenta de “Mutation Tests”
Um outro grupo de ferramentas implementa uma técnica chamada “testes de mutação”. Elas modificam o código de produção de forma aleatória (ou de acordo com padrões pré-determinados) e executam todos os testes após cada uma dessas modificações. A ideia é que qualquer mudança que não faça os testes falharem indica que eles não estão testando “bem”.
Embora a técnica em teoria vá muito além do que as ferramentas de cobertura oferecem, seu uso ainda é restrito devido a seu alto custo computacional. Existe um número astronômico de possíveis mutações a serem feitas no código. E para cada uma delas os testes seriam executados.
Além disso, uma mutação pode fazer com que um código se torne incrivelmente lento ou mesmo entre num loop infinito. Seria preciso definir um tempo máximo de execução dos testes para cada mutação. E no entanto interromper um teste não significaria que ele é infalseável.
Será interessante quando houver algum avanço relacionado a esse tipo de ferramenta, mas, por hora, acredito que não seja possível integrá-las ao dia a dia dos desenvolvedores.
- Quebre coisas de propósito de vez em quando
Se as ferramentas ideais não existem, nada impede que você modifique o código intencionalmente e de forma controlada. Isso pode ser feito periodicamente, uma vez por semana ou por mês. Embora fazer isso no código todo seja tedioso e caro (custa tempo), pode ser interessante, após a descoberta de algum bug, tentar “causá-lo” em outros trechos de código para ver se os testes deles se tornarão vermelhos.
- Invente alguma coisa nova
E mande a sua sugestão nos comentários! Eu juro que não vou roubar a sua idéia.
Conclusão
A falseabilidade é um característica fundamental em um conjunto de testes de um sistema. Embora haja ferramentas mais ou menos interessantes para dar apoio à manutenção dessa característica, a forma mais eficaz de garantir a criação de testes falseáveis ainda é: escrevê-los e executá-los antes do código de produção, verificando que eles não passam.