sábado, 6 de setembro de 2008

TDD na Prática - Parte III: Abstração, Simplificação e o Ciclo do TDD

Conhecer como verificar as partes do software e estabelecer o nível de abstração para obter os dados a serem verificados é um ponto vital quando se escreve código de teste.

Expor uma interface simples em uma classe e esconder seus detalhes de implementação é imprescindível para alcançar um modelo de fácil reutilização, substituição e que possa ser facilmente testado. Dependências entre classes devem ser tornadas explícitas e bem-definidas, de forma que se possa trocar a classe da qual se depende por outra, sem que haja um esforço adicional.

E, de novo, aplicando os conceitos de acoplamento e coesão e refatorando o código, podemos obter código com a qualidade desejada. A experiência conta muito a favor, é claro, mas tendo em mente a meta de sempre tentar simplificar as coisas ao máximo (KISS- Keep It Small and Simple), é possível chegar a resultados muito satisfatórios.

Só implementar o necessário

O interessante em o design seguir os testes é que você acaba percebendo a quantidade de código que deixa de escrever. Se você se concentra em escrever código que tente resolver um determinado problema da forma mais simples possível, muita coisa que talvez você fosse escrever, pensando que poderia ser útil futuramente, deixa de ser feita - justamente porque você acabou não precisando pra nada (YAGNI - You Ain't Gonna Need It).

Um teste de cada  vez

Às vezes quando estamos criando um teste, pensamos em uma outra coisa que pode ser testada, não exatamente relacionada à parte de código que está sendo testada, e que  podemos adicionar ao teste que está sendo feito agora. Resista a esta tentação. Mantenha cada funcionalidade que precisa ser testada em testes diferentes. Teste uma funcionalidade por vez. Os testes devem permanecer os menores e mais simples possíveis.

Não implemente mais do que o exigido pelo teste

Após escrever o código do teste e executá-lo, ele irá falhar. Afinal, você ainda não escreveu o código que o implementa. Então você começa escrever o código que implementa a funcionalidade e, de repente, bate aquela idéia de escrever um método ou função que você tem certeza absoluta que vai usar no próximo teste. Por que já não deixar pronto o código para o próximo teste, que você tem certeza que vai escrever ? Acontece que você está escrevendo somente o código necessário para passar no teste. Ao escrever um teste de cada vez, você deve implementar uma funcionalidade também a cada vez. Deixe a implementação sempre seguir os testes. Resista a vontade de escrever código sem que algum teste tenha sido escrito para o mesmo antes.

Refatore

Se o código que você irá escrever for muito parecido com algo que você já fez, refatore (DRY - Don't Repeat Yourself). Se você acha que determinado pedaço de código não faz parte da abstração criada (classe, método, função, etc.), refatore. Se um pedaço de código pode ser tornado mais simples e fácil de entender, refatore. Não deixe de aplicar este passo do ciclo. Ele gera um enorme impacto na qualidade e diminui muito o custo da manutenção futura do código.

E outra coisa importante: Refatore os testes também. O código de teste também pode ser simplificado e melhorado, como o código que o implementa.

Em suma, siga o ciclo do TDD

O ciclo do Test-Driven Development se baseia em 3 passos:

  1. Escreva um teste que verifique uma funcionalidade;
  2. Implemente somente o código para passar no teste;
  3. Refatore o código criado;

Respeitando o ciclo, você mantém o código sob controle, não disperdiça tempo criando algo que não vai precisar e mantém o escopo de cada teste sempre pequeno, facilitando seu desenvolvimento e manutenção.

Tente sempre seguir o ciclo. Não sucumba às tentações. ;)

Nenhum comentário: