Por: , novembro 11, 2013
Este texto é sobre Dependency Injection (DI) e Interfaces e foi motivado pela minha experiência com Spring durante +-3 anos. As observações abaixo se aplicam também à outros mecanismos de DI e IoC como Guice e Dagger.
Sempre trabalhei com Spring da forma "padrão". Resumindo: quando você quer injetar uma classe o senso comum diz para você fazer o seguinte:
O padrão é criar uma interface para todos os Spring beans. Não por acaso uma aplicação Spring típica possui um zilhão de interfaces e cada uma com apenas uma implementação.
Pouca gente percebe que as interfaces não são obrigatórias e nesses casos nem mesmo são necessárias para atingir dois dos princiais objetivos de DI:
Desacoplamento. O uso da interface neste exemplo não é o que garante desacoplamento, garante é que você consegue trocar as implementações com pouco impacto. Reitero que na maioria dos casos essas interfaces possuem somente uma implementação. Em relação à dependência o que temos é que a classe CaixaServicesImpl precisa de uma Classe/Implementação/Estrutura/Whatever que forneça um método público findEnderecoEntrega com determinada assinatura.
Testabilidade. Você não precisa de interfaces para criar Mocks, os frameworks de Mock atuais já conseguem mockar classes concretas e se você precisar escrever o Mock na mão basta fazer override dos métodos da superclasse antes da injeção (inclusive métodos protected).
E se tentássemos suprimir as interfaces e ao mesmo tempo usar um vocabulário mais DDD? Ficaria assim:
O código fica mais limpo e o grau de acoplamento é o mesmo (lembre-se que a relação Interface <=> Impl aqui é 1 <=> 1).
Minha conclusão é que precisamos de uma interface quando… precisamos de uma interface (!): minha classe "usuária" (no exemplo FrenteDeCaixa/CaixaServicesImpl) pode trabalhar com implementações diferentes de uma interface de acordo com determinada regra (aqui entraria a Factory e/ou uma injeção mais sofisticada). Para a imensa maioria dos casos (Services, Facades, DAOs, etc..) não é disso que precisamos.
E se depois de um tempo eu descobrir que terei duas implementações possíveis do Cadastro de Clientes? Aí você extrai uma interface e cria as duas implementações, é um refactoring bem simples de fazer !!
O super uso de interfaces em frameworks de DI é mais um vício de implementação do que algo que traz ganho real (até mesmo o EJB na sua versão 3.1 tornou as interfaces opcionais). Portanto antes de criar uma Interface faça a boa e velha pergunta: isso é realmente necessário?