fbpx
Porque Injeção de Dependência importa?
Publicado em: terça-feira, 21 de set de 2021
Categorias: Arquitetura

Algumas coisas são feitas no automático, e se você não entendeu porque o ASP .NET usa Injeção de Dependência by default, você deveria ler esse post. O que vamos entender hoje é porque Injeção de Dependência é importante, e as implicações em não usá-la.

Engraçado que esse assunto deveria ser óbvio para os mais velhos na plataforma, mas na verdade não é.

A realidade é que uma fração de nós está de fato se perguntando se o que fazemos é o que deveríamos fazer e se há ou não formas mais eficientes ou até inteligentes de fazer o básico.

Injeção de Dependência foi um dos assuntos que mais abordei no fim da versão anterior do site e foi o assunto com que comecei esse aqui. É uma paixão.

O primeiro contato

A primeira vez que injeção de dependência fez sentido para mim foi quando vi o Spring .NET fazendo sua mágica. Isso foi entre 2006 e 2007 com o icônico exemplos do Spring.Calculator (link).

Alguns anos mais tarde, nasceu o exemplo de WCF com o Spring.WcfQuickStart (link).

Aquele primeiro exemplo mostrava uma calculadora simples onde:

  • implementava as 4 operações básicas
  • Um só serviço de cálculo Calculator e AdvancedCalculator
  • Uma só interface
  • O cliente dependia da interface ICalculator
  • O serviço implementava essa interface
  • E isso era o necessário para que o spring fosse capaz de oferecer 4 formas de deployment/consumo.
    • Dynamic ASMX
    • Remoting
    • EnterpriseServices (COM+)

E se você não sabe do que eu estou falando. Eu estou dizendo que você conseguiria desenvolver local, com tudo embarcado na memória, e a escolha sob o desenho de implantação e distribuição de sua aplicação poderia ser feito via troca de configuração. Sem sequer demandar um rebuild.

Vamos supor que eu tenha um serviços de profile. O ProfileService. Se esse serviço tivesse uma interface IProfileService, bastava eu garantir que o Spring era o factory do cliente e do server para que a estratégia de deployment pudesse ser decidida no futuro, ou nunca.

Isso é de explodir a cabeça. Mas porque?

Construir objetos é uma responsabilidade

Uma das responsabilidades mais negligenciadas que conheço é a de construção de instâncias de objetos. Construir instâncias de outras coisas é por si só uma responsabilidade, e por sinal merece cuidado para não complicar as coisas.

É comum criarmos interfaces para determinar o contrato de algum objeto que precisamos. Isolamos o contrato em uma interface para permitir extensibilidade. Ou seja, possibilitar outras implementações para um mesmo comportamento. Assim desacoplarmos um pedaço do software, para isolarmos e nos preocuparmos somente com a responsabilidade de cada pedaço de forma independente.

Dessa forma, o coração do nosso software não está nem aí para qual tecnologia de banco de dados um repositório precisa lidar. Nosso core está preocupado com as operações que um repositório pode oferecer ao core, e para isso temos um contrato tangibilizado em uma Interface.

Mas se seu core tem a responsabilidade de construir esse objeto, temos um paradoxo:

Qual é a instancia certa?

Quais parâmetros, ou melhor instancias essa classe precisa?

Como construir essa dependência?

E a dependência da dependência?

E a dependência da dependência da dependência?

E a dependência da dependência da dependência da dependência?

É aí que temos de criar um grafo complexo e contextual, e naturalmente fazemos isso diversas vezes em diversos contextos, repetidamente.

– Você pode dizer: – (DRY) Don’t Repeat Yourself! e (KISS) keep it simple, stupid.

Sim, usando factory e abstract factory podemos realizar esse tipo de dependência terceirizando a complexidade, no entanto lembre-se. Patterns resolvem problemas, e aqui temos um problema que é o aumento acidental da complexidade de construção de uma dependência.

Factory e Abstract Factory ainda são super válidos, inclusive no contexto de injeção de dependência, principalmente se a dependência for contextual, ou seja, ela não é a mesma sempre, dependendo do contexto hora usamos uma dependência, hora usamos outra.

Injeção de Dependência prevê que um ator externo faça esse trabalho de popular as dependências dos objetos criados por ele, viabilizando a criação de um grafo complexo de dependências completo em memória.

A infraestrutura do asp.net usa Register/Resolver, um pattern de resolução de dependências conhecido e disseminado aqui na plataforma .NET com o Castle Project.

Eu particularmente prefiro um modelo mais declarativo e puro, pois acredito que a modelagem pura deve ser mapeada em um framework ao invés de forçar regras de modelagem de acordo com a ferramenta. Eu defendo a configuração declarativa de 100% do grafo de dependências, mas isso é assunto para um outro post.

Conclusão

A construção não coordenada de objetos é uma fonte infinita de bugs. Quanto maior o projeto, maiores são as chances de uma classe construir uma dependência errada. Esse tipo de erro tem um custo maior para o desenvolvimento, pois ao olhar para a implementação vemos um comportamento adequado, mas o resultado de negócio não é o esperado.

A dificuldade da construção errada de objetos está exatamente no comportamento certo, com parâmetros errados. Debugging ajuda muito nessas horas, mas uma infra de IoC/DI ajudaria ainda mais evitando esse tipo de cenário.

Construções contextuais, com base em factories parametrizadas e múltiplas configurações possíveis para um mesmo tipo, é um cenário que deveria ser mais comum do que de fato é, por conta da adoção do Register/Resolver pela equipe do ASP.NET, acabamos perdendo muito em reaproveitamento.

Mas faz parte, o bonus dessa estratégia é a simplicidade e redução de código, enquanto o onus é a perda na modelagem e no reaproveitamento.

Se a intenção é deixar seu código KISS e DRY, injeção de dependência te ajudará muito na hora de construir o mesmo objeto diversas vezes, evitando a proliferando de duplicidades, da mesma forma como melhorará a escrita de suas classes, fazendo com que elas sejam mais simples do que a versão em que as dependências seriam construídas manualmente via código, e mais simples do que as versões em que a própria instância obtém suas dependências.

O Cloud Native .NET é meu principal projeto.

Onde empenho energia para ajudar, acompanhar, direcionar Desenvolvedores, Líderes Técnicos e jovens Arquitetos na jornada Cloud Native.

Conduzo entregando a maior e mais completa stack de tecnologias do mercado.

Ao trabalhar com desenvolvedores experientes, eu consigo usar seu aprendizado com .NET, banco de dados, e arquitetura para encurtar a jornada.

Ao restringir à desenvolvedores .NET eu consigo usar do contexto de tecnologias e problemas do seu dia-a-dia, coisas que você conhece hoje, como WCF, WebForms, IIS e MVC, por exemplo, para mostrar a comparação entre o que você conhece e o que está sendo apresentado.

É assim que construímos fundamentos sólidos, digerindo a complexidade com didática, tornando o complexo, simples.

É assim que conseguimos tornar uma jornada densa, em um pacote de ~4 meses.

Eu não acredito que um desenvolvedor possa entender uma tecnologia sem compreender seus fundamentos. Ele no máximo consegue ser produtivo, mas isso não faz desse desenvolvedor um bom tomador de decisões técnicas.

É preciso entender os fundamentos para conseguir tomar boas decisões.

0 comentários

Enviar um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

Luiz Carlos Faria

Mensagem do Autor

Espero que goste desse post. Não deixe de comentar e falar o que achou.

Se acha que esse post pode ajudar alguém que você conheça, compartilhe!

 

Lives

Fique de olho nas lives

Fique de olho nas lives no meu canal do Youtube, no Canal .NET e nos Grupos do Facebook e Instagram.

Aceleradores

Existem diversas formas de viabilizar o suporte ao teu projeto. Seja com os treinamentos, consultoria, mentorias em grupo.