Dado um construtor que nunca terá que usar implementações diferentes de vários objetos que ele inicializa, ainda é prático usar o DI? Afinal, ainda podemos querer testar a unidade.
A classe em questão inicializa algumas outras classes em seu construtor e as classes que ele usa são bastante específicas. Ele nunca usará outra implementação. Estamos justificados em evitar tentar programar para uma interface?
Respostas:
Depende de como você está certo de que "nunca, nunca" está correto (durante o tempo em que seu aplicativo será usado).
Em geral:
fonte
Embora a vantagem de codificar contra uma interface seja bastante evidente, você deve se perguntar o que exatamente é ganho por não fazer isso.
A próxima pergunta é: faz parte da responsabilidade da classe em questão escolher as implementações ou não? Esse pode ou não ser o caso e você deve agir em conformidade.
Por fim, sempre existe o potencial de surgir alguma restrição pateta do nada. Você pode executar o mesmo trecho de código simultaneamente, e a possibilidade de injetar a implementação pode ajudar na sincronização. Ou depois de criar um perfil do seu aplicativo, você pode descobrir que deseja uma estratégia de alocação diferente da instanciação simples. Ou surgem preocupações transversais e você não tem suporte à AOP em mãos. Quem sabe?
YAGNI sugere que, ao escrever código, é importante não adicionar nada supérfluo. Uma das coisas que os programadores tendem a adicionar ao seu código sem nem mesmo estar cientes disso são suposições supérfluas. Como "esse método pode ser útil" ou "isso nunca vai mudar". Ambos adicionam confusão ao seu design.
fonte
Depende de vários parâmetros, mas aqui estão algumas razões pelas quais você ainda pode querer usar o DI:
Conclusão: você provavelmente pode viver sem o DI nesse caso, mas há chances de que o uso do DI termine em um código mais limpo.
fonte
Ao projetar um programa ou recurso, parte do processo de pensamento deve ser como você o testará. A injeção de dependência é uma das ferramentas de teste e deve ser considerada como parte do mix.
Os benefícios adicionais da Injeção de Dependências e do uso de interfaces em vez de classes também são benéficos quando um aplicativo é estendido, mas também podem ser adaptados ao código-fonte posteriormente com bastante facilidade e segurança usando a pesquisa e substituição. - mesmo em projetos muito grandes.
fonte
Muitas respostas a esta pergunta podem ser debatidas como "você pode precisar porque ..." como YAGNI se você não quiser fazer uma desavença.
Se você está perguntando por que motivos, além dos unittests, é necessário programar para uma interface
Sim , a injeção de dependência vale a pena fora do UnitTesting se você precisar de inversão de controle . Por exemplo, se uma implementação de módulo precisar de outro módulo que não possa ser acessado em sua camada.
Exemplo: se você possui os módulos
gui
=>businesslayer
=>driver
=>common
.Neste cenário
businesslayer
pode usar,driver
masdriver
não pode usarbusinesslayer
.Se
driver
precisar de alguma funcionalidade de nível superior, você pode implementar essa funcionalidade nabusinesslayer
qual implementa uma interface nacommon
camada.driver
só precisa conhecer a interface nacommon
camada.fonte
Sim, você é: primeiro, esqueça o teste de unidade como uma razão para projetar seu código com base nas ferramentas de teste de unidade; nunca é uma boa idéia dobrar seu design de código para se ajustar a uma restrição artificial. Se suas ferramentas forçarem você a fazer isso, obtenha ferramentas melhores (por exemplo, Microsoft Fakes / Moles que permitem muito mais opções para criar objetos simulados).
Por exemplo, você dividiria suas aulas em métodos apenas públicos apenas porque as ferramentas de teste não funcionam com métodos particulares? (Eu sei que a sabedoria predominante é fingir que você não precisa testar métodos particulares, mas acho que isso é uma reação à dificuldade de fazê-lo com as ferramentas atuais, e não uma reação genuína à falta de testes particulares).,
Em suma, tudo se resume a que tipo de TDDer você é - o "zombador" como Fowler os descreve , precisa alterar o código para se adequar às ferramentas que eles usam, enquanto os testadores "clássicos" criam testes que são mais integrados à natureza (ou seja, teste a classe como uma unidade, não cada método), para que haja menos necessidade de interfaces, especialmente se você usar as ferramentas que podem simular classes concretas.
fonte
A injeção de dependência também deixa mais claro que o seu objeto possui dependências.
Quando outra pessoa usa seu objeto ingenuamente (sem olhar para o construtor), eles descobrirão que precisarão configurar serviços, conexões etc. Isso não era óbvio, porque eles não precisavam repassá-los ao construtor. . Passar nas dependências torna mais claro o que é necessário.
Você também está ocultando o fato de que sua classe pode estar violando o SRP. Se você está passando em muitas dependências (mais de 3), sua classe pode estar fazendo muito e deve ser refatorada. Mas se você os estiver criando no construtor, esse cheiro de código será oculto.
fonte
Concordo com os dois campos aqui e, na minha opinião, o assunto ainda está aberto para debate. YAGNI exige que eu não tente mudar meu código para se ajustar à suposição. O teste de unidade não é um problema aqui, porque acredito firmemente que a dependência nunca mudará. Mas, se eu estivesse testando a unidade como pretendia, nunca teria chegado a esse ponto. Como eu acabaria entrando no DI eventualmente.
Deixe-me oferecer outra alternativa para o meu cenário especificamente
Com um padrão de fábrica, posso localizar dependências em um só lugar. Ao testar, posso alterar a implementação com base no contexto, e isso é bom o suficiente. Isso não vai contra o YAGNI por causa dos benefícios de abstrair várias construções de classe.
fonte