Estou eu esperando uma s boas duas horas para embarcar no Santos Dummont para palestrar no Falando em Java amanhã quando me passa pela cabeça algo que acho que pode ser bem útil para levar à uma empresa burocrática um mínimo de agilidade.
Existem muitos lugares, especialmente lugares de três letrinhas com certificações de 3(+1) letrinhas, onde revisão por par é algo obrigatório. Note que revisão por par não é algo ruim, pelo contrário. Revisão assim é tão boa que XP prega que ela seja feita o tempo todo. O ponto é que existe uma diferença entre a aplicação útil desta técnica e o que geralmente é feito nestes lugares, de maneira extremamente burrocrática (conheço lugares onde a revisão resulta em uma declaração que é impressa e assinada pelas partes).
Fazer um desenvolvedor revisar linha por linha do que o outro fez é besteira. Quer saber se ele seguiu as regras de nomenclatura e os seus padrões? Quer saber se ele não introduziu nenhum bug óbvio? Se seguiu boas práticas? Não quebrou Camadas? Existem ferramentas que fazem isso automaticamente e o fazem enquanto a pessoa trabalha, não depois. Fazer a pessoa explicar ao revisor em linhas gerais é a técnica que eu havia julgado ser mais interessante até então, mas acho que além disso pode haver algo melhor.
E minha proposta é que o revisor revise apenas os testes unitários do desenvolvedor. Ele vai poder criar novos testes e questionar os que não julgar adequados, mas o código em si é irrelevante. Por quê? Porque não é eficiente. Não adianta, a pessoa não vai conseguir revisar cada linha, pensar em cada problema, lendo um grupo de blocos de código.
Em compensação, se a classe possuir uma interface bem construída, típica de Test-Driven Development, o código em si não é o foco. Claro que haver um código de qualidade e bem construído é fundamental, mas essa revisão tem foco no comportamento dos componentes (provavelmente classes)afetados.
Imagine que nós temos uma classe Pedido, imagine que o teste unitário dela é o abaixo:
class PedidoTest extends testCase{
public void testFechaPedido(){
Pedido pedido = new Pedido();
assertEquals("Pedido esta aberto", Pedido.Status.ABERTO, pedido.getStatus());
pedido.adiciona(produto1, 2);
pedido.adiciona(produto2, 1);
pedido.fechar();
assertEquals("Pedido esta fechado", Pedido.Status.FECHADO, pedido.getStatus());
assertEquals("Pedido calculou preco correto", ((produto1.getPreco() * 2) + produto2.getPreco()), pedido.getTotal());
}
}
Agora imaginemos que existe uma requisição para mudar esta classe. O governo acabou de decidir morder mais algum % do capital gerado no país, então existe uma nova regra de negócios que diz que toda compra vai ter 10% de imposto. O desenvolvedor cria a classe e cria seus testes, o que o revisor vai fazer? Reler todo o código? Não, ele revisa os testes e vê que o desenvolvedor não fez o suficiente. Na verdade o desenvolvedor deixou o código acima exatamente como ele está (ok, esse é um exemplo bobo). O que o revisor faz? Modifica o caso de teste:
class PedidoTest extends testCase{
public void testFechaPedido(){
Pedido pedido = new Pedido();
assertEquals("Pedido esta aberto", Pedido.Status.ABERTO, pedido.getStatus());
pedido.adiciona(produto1, 2);
pedido.adiciona(produto2, 1);
pedido.fechar();
assertEquals("Pedido esta fechado", Pedido.Status.FECHADO, pedido.getStatus());
long valorTotal = ((produto1.getPreco() * 2) + produto2.getPreco());
valorTotal = valorTotal+ (valorTotal * 0.1);//+10%
assertEquals("Pedido calculou preco correto", valorTotal, pedido.getTotal());
}
}
E pronto. Ao invés de tediosamente ler centena de linhas de código e tentar fazer de cabeça a execução do programa o revisor se concentra no que importa: o funcionamento.
Claro que num ambiente TDD este tipo de teste provavelmente já estaria escrito, mas dificilmente um ambiente TDD utilizaria revisões formais como técnica habitual do processo de desenvolvimento, esta prática tem mais a ver com processos extremamente burocráticos, geralmente certificados por algum órgão de três letrinhas.
Mas e a qualidade do código escrito? Primeiro estes são verificados com as ferramentas acima, que são mais eficientes que qualquer desenvolvedor (o cara não consegue fazer um parsing linha-a-linha como a ferramenta faz), mas ainda é preciso falar em evolução constante.
Um dos princípios básicos de qualquer metodologia iterativa (isso inclui XP e RUP, por exemplo) é de que você não vai acertar da primeira vez. Esquece.Então o que fazemos? Crie o código que cumpra o seu papel e o evolua aos poucos, com refactoring. Bons programadores tendem a gerar código de qualidade nas primeiras iterações, mas programadores mais medianos geralmente vão ter que refatorar bastante. Quando você possui testes unitários refatorar é algo seguro, se você mudar a implementação de Pedido e não mudar o comportamento seu sistema vai funcionar, e para verificar se o sistema funciona você não precisa mais de um time com 3543 pessoas dedicadas a apertar todos os botões existentes, apenas rode o teste de regressão unitário dentro da sua própria IDE.
A idéia deste post é dar uma ferramenta para os pobres desenvolvedores presos em processos burocráticos e inflexíveis sobre como dar ao seu dia-a-dia características ágeis. Agilidade não precisa ser aprovada pela diretoria, agilidade pode ser feita na sua baia.
Epílogo: Meu vôo foi cancelado e eu cheguei no evento de ônibus. :P
Ei cara, muito bom este artigo, valeu ai! Fazia tempo que procurava por algo do genero…
[...] testes unitários e pratique Test Driven Development [...]