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!");
}
}
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!");
}
}
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)