DEV Community

Cover image for PRINCÍPIO DA INVERSÃO DE DEPENDÊNCIA
Victor Lis Bronzo
Victor Lis Bronzo

Posted on

PRINCÍPIO DA INVERSÃO DE DEPENDÊNCIA

Módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações (interfaces).

Na prática, a sua regra de negócio não deve saber se você usa MySQL, Stripe ou AWS. Ela deve depender apenas de um contrato (Interface) que diz O QUE precisa ser feito, e não COMO será feito.


IMPLEMENTAÇÃO ENGESSADA

O erro mais comum no dia a dia é dar um new FerramentaExterna() direto dentro do seu caso de uso.

Quando você faz isso, seu código depende da ferramenta.

Se a ferramenta for descontinuada ou a API mudar, você terá que abrir o "coração" do seu sistema para consertar.


UM MAU EXEMPLO

A classe de negócio fortemente acoplada ao provedor de e-mail SendGrid. Isso é uma má prática.

Exemplo de Código:

import { SendGridProvider } from 'sendgrid-sdk';

// RUIM: O serviço instancia a ferramenta diretamente.
class RegisterUserUseCase {
  private mailProvider: SendGridProvider;

  constructor() {
    // Forte acoplamento!
    this.mailProvider = new SendGridProvider('API_KEY');
  }

  public async execute(email: string): Promise<void> {
    // ...lógica complexa de negócio...

    // Se o SendGrid mudar ou cair, essa classe quebra.
    await this.mailProvider.sendEmail(email, "Bem-vindo!");
  }
}
Enter fullscreen mode Exit fullscreen mode

INVERTENDO O JOGO

A solução é não depender da classe concreta SendGridProvider, mas sim criar uma interface genérica dentro do nosso próprio domínio.

O nosso serviço passa a receber essa dependência pronta pelo construtor (Injeção de Dependência).

A parte mais interessante é que nossa aplicação não precisa saber exatamente quem está por baixo dos panos, seja Resend, EmailJS ou outro, ela apenas segue o molde.


UM BOM EXEMPLO

O serviço agora depende apenas do contrato. A infraestrutura que obedeça.

Exemplo de Código:

// BOM: O contrato pertence à NOSSA aplicação.
interface IMailProvider {
  send(to: string, message: string): Promise<void>;
}

class RegisterUserUseCase {
  // Recebemos a abstração de fora (Injeção de Dependência)
  constructor(private mailProvider: IMailProvider) {}

  public async execute(email: string): Promise<void> {
    // ...lógica complexa de negócio...

    // O serviço não faz ideia de qual ferramenta está enviando
    await this.mailProvider.send(email, "Bem-vindo!");
  }
}
Enter fullscreen mode Exit fullscreen mode

O PODER DA INVERSÃO

A maior vantagem do DIP é a Modularidade.

Se amanhã o seu cliente pedir para trocar o SendGrid pela AWS SES, você só cria uma nova implementação da interface. A classe RegisterUserUseCase não sofre nenhuma alteração.

Além disso, os Testes Unitários ficam absurdamente mais fáceis, pois você pode injetar um Mock de e-mail falso sem precisar fazer disparos reais.


Meus Links
Github: victor-lis-bronzo
Linkedin: victor-lis-bronzo
Portfólio: portfolio.victorlisbronzo.me
Portfólio mais legal: victorlisbronzo.me


Deixe sua reação ❤️
Você já aplicava Injeção de Dependência antes de saber que isso era a base do DIP?

Top comments (0)