Testes: pragmatismo ou ideologia?

January 31st, 2009 § 6 comments

Eu gosto bastante do que Joel Spolsky e Jeff Atwood escrevem, mas a última conversa entre os dois no postcast regular que eles mantém realmente releva uma boa falta de conhecimento sobre o que testes e TDD realmente representam.

No núcleo do argumento dos dois está a idéia de que alta cobertura por meio de testes–Jeff Atwood menciona a falta de 95% ou mais–torna a manutenção dos próprios testes problemática considerando a proporção de testes que precisa ser mudada quando o código em si também é modificado. Um argumento secundário é que testes são mais indicados para código legado do que código que está sendo desenvolvido, a menos que o mesmo tenha rigidez natural como a especificação de um compilador.

A solução para o segundo argumento é simples: todo código é legado. Simples assim. Código que entrou em produção é legado por definição e o argumento de que há uma diferença entre código com “mais idade” e “menos idade” é dúbio no pior dos casos.

Lendo o diálogo entre os dois, é possível perceber que há uma confusão sobre o que testes realmente representam–especialmente quando os dois falam sobre a relação entre testes e arquitetura, algo que em um contexto ágil é normalmente referenciado por TDD e BDD.

Essa confusão–de que testes são feitos para cobrir a interface de uma classe ou método–é extremamente comum mesmo entre os próprios proponentes de testes, seja entre aqueles que propõem testes como ferramenta de design como é o caso de TDD e BDD, seja entre os que simplesmente os usam para validar o funcionamento posterior do código.

Eu posso concordar parcialmente com o argumento de que 100% de cobertura geralmente é desnecessária. De fato, 100% de cobertura nunca representa uma garantia absoluta de que seu código, e por extensão sua arquitetura, não possuem problemas.

Primeiro porque 100% de cobertura real é algo virtualmente impossível de ser conseguido para um corpo mais complexo de código (e realmente impossível se o mesmo tem dependências externas). Segundo, por que não importa a quantidade de testes que você tiver, a complexidade ciclomática sempre vai acabar com seu dia nas horas mais inapropriadas. Não importa o quantidade de white-box ou black-box testing que você possuir, cobertura é alvo exponencialmente proporcional à evolução do seu código.

Existe também um outro fator representado por uma variação casual da regra 80/20. Os maiores ganhos de testes estão nas partes mais complexas do seu código, é claro, mas os ganhos reais geralmente aparecem nos desvios pequenos que pegam você de surpresa. Nesse ponto, quando maior a cobertura, maior facilidade de introduzir novos testes.

E aqui está o verdadeiro ponto em que o argumento de Spolsky e Attwood falha: testes não são sobre interfaces, APIs ou contratos. Antes, eles são sobre o relacionamento entre as partes distintas de seu código. Nessa diferença essencial está um dos grandes debates recentes da comunidade ágil: qual é a diferença real entre TDD e BDD?

A minha resposta está centrada em uma pequena reinterpretação de TDD. Ao invés de usar o termo como Test-Driven Development, eu prefiro ver a questão toda como Test-Driven Design.

Se você está usando testes como uma ferramenta para guiar o design de sua aplicação, isso significa que você estará preocupado mais em saber com as peças se encaixam do que como elas funcionam individualmente, como mencionado acima.

Joel diz:

But the real problem with unit tests as I’ve discovered is that the type of changes that you tend to make as code evolves tend to break a constant percentage of your unit tests. Sometimes you will make a change to your code that, somehow, breaks 10% of your unit tests.

Você realmente pode fazer uma mudança que quebra 10% de seus testes, mas para que isso aconteça, o design do sistema precisa estar tão falho e seus testes tão quebradiços que os mesmos podem ser jogados fora sem remorso.

Há pouco mais do que duas semanas, eu fiz uma modificação considerável em uma biblioteca que escrevi. Em linhas gerais, significa trocar o motor de um middleware de DRb (Ruby distribuído) para JSON over HTTP. Esse código em particular está 100% coberto.

Por causa das diferenças entre os protocolos, uma quantidade de código significativa teve que ser modificada. Mas apenas três ou quatro novos testes foram escritos e nenhum dos outros foi modificado. Código foi movido, reorganizado em classes diferentes e mesmo assim, os testes resistiram bravamente.

A explicação é simples: enquanto existem testes que realmente testam como funções específicas funcionam, a vasta maioria destes testes é focado em como as várias partes da aplicação trocam informações: se os dados que saíram daqui nesse formato chegaram do outro lado do formato necessário, se essa AST foi reorganizada apropriadamente de modo que o gerador do outro lado da equação possa produzir a linguagem apropriada e assim por diante.

Jeff continua com outra asserção:

Yeah, it’s a balancing act. And I don’t want to come out and say I’m against [unit] testing, because I’m really not. Anything that improves quality is good. But there’s multiple axes you’re working on here; quality is just one axis. And I find, sadly, to be completely honest with everybody listening, quality really doesn’t matter that much, in the big scheme of things…

Isso é algo que me fez repensar todo o contexto da discussão. Eu realmente fico espantado de ver alguém que considera Peopleware e The Mythical-Man Month como referências básicas dizer isso. Ambos os livros focam em arquitetura dirigida por qualidade como um foco para produzir código mais robusto, entregue em menor tempo e que traz mais valor para o negócio e para o usuário. Os parágrafos finais da transcrição são realmente decepcionante nesse aspecto.

Para finalizar, TDD realmente não é um fim em si próprio. Mas o argumento de que usar testes é um desperdício de tempo–seja para quem está cobrindo 100% do seu código de forma viável ou para quem usa testes como validação de funcionalidade–é simplesmente falho.

Joel é conhecido bastante por seu pragmatismo em relação à correção de bugs. Testes são uma maneira bastante pragmática de garantir que aquele conjunto particular de situações de falha não vá se repetir por engano em alguma codificação posterior. Isso é business value, algo que tanto Joel como Jeff valorizam.

No final das contas, pragmatismo é o que realmente conta. E testes, quanto feitos da maneira certa, são algumas das mais pragmáticas ferramentas que um programador tem à sua disposição.

Tagged

§ 6 Responses to Testes: pragmatismo ou ideologia?"

  • Sobre este assunto, foi publicado recentemente um vídeo de uma apresentação na InfoQ: Testing is Overrated. Discute sobre como testes são frequentemente considerados soluções para todo tipo de problema.

    Testes definitivamente são uma Boa Coisa™ (e eu, particularmente, não sei mais programar sem eles), mas é preciso lembrar que só são capazes de demonstrar a presença de defeitos, não a ausência deles.

  • Ronaldo says:

    Eu concordo plenamente que testes não são uma silver-bullet. A questão de presença versus ausência, inclusive, é freqüentemente demonstrada quando você tem que escrever um teste novo para uma situação que não quebra nenhum dos demais testes.

    Isso dito, eu ainda discordo do argumento de Spolsky e Atwood. Continua me parecendo mais uma desculpa do que uma proposição coerente. Obviamente, ninguém é obrigado a fazer testes e existem mais programas escritos sem testes do que o contrário que funcionam perfeitamente bem. Por outro lado, o retorno de linguagens dinâmicas ao front implica soluções diferentes. Como você disse, prefiro os testes. :)

  • O fato de não ser possível garantir completamente a ausência de defeitos com testes não é uma justificativa nem de longe razoável para não usá-los, claro. Desenvolver software de qualidade usando testes é difícil, mas é ainda pior sem eles.

  • Ronaldo says:

    Hehehe. Com certeza. :)

  • Roger Leite says:

    Ótimo post!
    Depois que passei a usar TDD, realmente fica muito claro sua tendência a ser “Test-Driven Design”.

    Esta discussão do Joel e Jeff, foi decepcionante mesmo.
    Sucesso!

  • Ronaldo says:

    Sim, exato. Acho que muita gente não percebe essa faceta. O povo acha que é uma substituição à depuração ou mesmo uma forma de encontrar bugs. Olhar do ponto de vista de design é o momento em que se percebe o maior valor.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

What's this?

You are currently reading Testes: pragmatismo ou ideologia? at Superfície Reflexiva.

meta