sexta-feira, 27 de novembro de 2009

Guicifique seus Testes - Parte 6

Esta é sexta parte da tradução para português do interessante artigo Guicing Up Your Testing, June 21, 2007, por Dick Wall. Trata-se de uma leitura interessante, que junta dois tópicos que estou estudando atualmente: Teste Unitário e Google Guice, além de falar um pouco sobre Injeção de Dependências e os Padrões de Projeto Singleton e Factory.

Índice

Uma rápida reflexão sobre Design Patterns

A afirmação sobre a bala de prata se aplica, em minha opinião, tanto para o uso de bibliotecas como o Guice quanto para Design Patterns. Padrões de Projeto podem encapsular conceitos importantes, mas usá-los indiscriminadamente pode levar a problemas similares aos que tivemos ao jogar todas as responsabilidades para cima do Guice.

Lembremos que a modelagem inicial do teste estava particularmente difícil de testar justamente devido a uma aplicação pouco flexível do padrão Singleton, que era difícil de ser substituída por outra mais adequada. Uando o Guice, acabamos por aplicar o mesmo padrão Singleton, mas de forma diferente, deixando claro que a culpa não era propriamente do padrão Singleton, mas sim da forma como ele havia sido implementado.

Ainda assim, não se pode tentar pensar sempre em termos de padrões de projeto, na medida que agindo dessa forma pode-se limitar bastante as possíveis abordagens de desenvolvimento. Padrões de Projeto possuem seu valor, assim como os Anti-Patterns, e ainda mais importante, a Criatividade e o Pensamento Original e Independente.

Modelagem usando Guice e o Padrão Factory

Neste exemplo, encontrei um forte exemplar de como combinar a Injeção de Dependências oferecida pelo Guice e o Padrão de Projeto Factory. Iremos usar o Guice para criar objetos FabricaPedidos, que serão injetadas como o objeto GerenciadorTaxaJuros cofigurado nos bindings do Guice. Iremos então usar esta Fábrica para criar os objetos Pedido. Ao tirar do Guice a responsabilidade de criar os objetos da classe Pedido, ela pode voltar a ter ambos os atributos Cliente e GerenciadorTaxaJuros populados via construtor, com ambos os atributos podendo ser marcados como imutáveis.

Desta forma, corrigimos os problemas que introduzimos no código ao adaptá-lo para fazer uso da Injeção de Dependências. Vamos ao código. Na classe Pedido, reescrevemos o construtor, e retiramos a anotação @Inject (já que ela não vai mais ser diretamente gerenciada pelo Guice!).

Note que restauramos a palavra reservada final ao atributo cliente, e que o construtor recebe como argumentos tanto o GerenciadorTaxaJuros como o cliente. Como o Guice não fará mais a injeção através desta classe, criamos uma FabricaPedidos, que irá fazer este trabalho:

Não devem haver surpresas até aqui: o Guice irá injetar um GerenciadorTaxaJuros via construtor da classe FabricaPedidos. Agora, para criar um pedido, iremos chamar o método criaPedidoParaCliente, passando como parâmetro o cliente deste pedido. O método criará o Pedido, usando o GerenciadorTaxaJuros injetado pelo Guice, e o Cliente informado através da chamada da API FabricaPedidos. Vejamos o que ocorre com os testes:

Ao invés de criar um Pedido no construtor, agora criamos uma Fábrica de Pedidos. No teste, esta fábrica é usada para criar objetos Pedido, para os clientes aplicáveis. Esta implementação é muito mais limpa do que a anterior, e recuperamos a imutabilidade dos atributos da classe Pedido.

Melhorias Adicionais

Outra coisa a ser notada é que, ao invés de a busca em `GerenciadorTaxaJuros` receber como parâmetro um ID de um `Cliente`, faz mais sentido receber um objeto `Cliente`, fazendo a busca baseada neste objeto. Isto torna a API mais limpa e flexível, uma vez que permitiria que a busca possa ser parametrizada também por outros atributos da classe `Cliente`, caso conveniente. Desta forma, atualizamos a interface `GerenciadorTaxaJuros`:

E sua implementação fake:

O método `calculaTotalComTaxas` da classe `Pedido` também precisa ser refatorado para receber um objeto `Cliente` ao invés de seu ID:

A Biblioteca AssistedInject

Utilizar o padrão Factory em conjunto com Injeção de Dependências solucionou as deficiências introduzidas no final do primeiro artigo, então podemos nos perguntar se o próprio Guice não poderia oferecer alguma forma de contornar estas limitações, uma vez que elas parecem ser bem comuns.

Talvez o Guice possa, em breve. Jesse Wilson e Jerome Mourits, engenheiros da Google, criaram uma extensão do Guice chamada AssistedInject, que formaliza o uso do padrão `Factory` para ser mais facilmente utilizado com o Guice. Uma descrição do que ela faz pode ser encontrada em:

  • http://groups.google.com/group/google-guice/browse_thread/thread/9a7e2c57583d21d6
  • http://code.google.com/p/google-guice/wiki/AssistedInject

Conclusão

Vimos, portanto, que a Injeção de Dependências, por mais útil que seja, é apenas mais uma ferramenta na caixa de ferramentas. Ela pode ser utilizada com outras boas práticas e padrões de projeto quando apropriado, e quando fizer sentido. Usado corretamente, ele pode tornar mais bonitas a arquitetura e a implementação de uma aplicação.

Nenhum comentário:

Postar um comentário