DEV Community

Patrick Augusto
Patrick Augusto

Posted on

DDD, Dependency Injection e Facade com NestJS!

Bom dia, boa tarde, boa noite!

Hoje vou falar um pouco sobre a aplicação desses conceitos em NestJS!

O problema

Recentemente no trabalho vivi um processo interessante de desenvolvimento de uma POC (Proof of concept).

Uma POC é uma prova de conceito de algo, onde precisamos entender como vai ser o produto final, encontrando problemas que vamos ter, desafios, entre outros pontos.

Uma POC não precisa ser algo complexo ou idêntico ao produto final. Mas, um dos principais requisitos eram testes!

A questão é que se o código está ruim, os testes irão ficar horríveis e principalmente ruim de manutenção. O projeto de uma POC não é necessariamente um produto jogado fora, provavelmente será reutilizado para o produto final. Então, querendo ou não precisamos pensar no futuro.

Decisões

Eu não usei TDD, pois o problema a ser resolvido ainda estava muito nebuloso para nós, então usar TDD só poderia nos atrasar (talvez no produto final faça mais sentido).

Então eu fui codando e descobrindo as regras de negócio enquanto sujava a mão.

Chegou um momento em que o código estava uma bagunça.

Apliquei um primeiro refactor, e conforme o código foi crescendo aquilo ficou uma bagunça também.

Até que chegou um momento em que vi a necessidade de parar, refletir, e refatorar de uma forma que o código ficasse mais manutenível.

DDD

Não sou detentor de conhecimentos profundos de DDD, porém tentei aplicar ao menos o que entendo dele.

Refatorei o código utilizando alguns conceitos de DDD, principalmente o uso de Application, Domain e Infrastructure.

Cada camada ficou com responsabilidades diferentes:

Application

Aqui ficaram algumas controllers, services e validadores. Como alguns algoritmos e DTO's.

Domain

Na camada de domínio ficaram entidades do banco de dados e interfaces

Infrastructure

Nessa camada ficaram as comunicações com banco de dados e módulos de mensageria, como RabbitMq e Redis.

Dividindo o projeto dessa maneira, ficou muito mais fácil de entender onde estava cada responsabilidade, e consequentemente dividir os testes mais detalhadamente.

Depencency Injection e Facade

Injeção de dependência é um padrão de desenvolvimento de programas de computadores utilizado quando é necessário manter baixo o nível de acoplamento entre diferentes módulos de um sistema.

O Facade é um padrão de projeto estrutural que fornece uma interface simplificada para uma biblioteca, um framework, ou qualquer conjunto complexo de classes.

O uso de DI é quase obrigatório no NestJS, pois a essência dele é basicamente essa.

Agora, como foi a aplicação do pattern Facade e DI? Quase simples:

Há um injectable chamado UserEventBus que está na camada de domínio:

Image description

Obs: Um dos princípios do DDD é a separação de responsabilidades, e uma camada não precisa saber o que a outra camada está fazendo. Cada uma dessas camadas tem suas responsabilidades bem definidas e não precisa saber os detalhes de implementação das outras camadas.

Sabendo disso, veja que o UserEventBus, utiliza uma abstração do serviço de mensageria, que é basicamente uma interface:

Image description

E a forma que o Nest entende qual classe realmente vai implementar, é na configuração do provider:

Image description

Aqui eu informo pro Nest que quem usar a interface IMessageService, por baixo dos panos estará usando a classe RabbitMqService =)

Acima, implementamos o uso do pattern Facade no NestJS.

O que foi feito?

  1. Injeção de Dependência: Para a services RabbitMqService, não está sendo usado diretamente as classes, mas sim fornecendo uma string como token ('IMessageService') e especificando a classe que deve ser usada para criar a instância quando essa dependência é solicitada. Isso é uma forma de injeção de dependência, onde o contêiner de injeção de dependência é responsável por criar as instâncias das classes baseadas nos tokens fornecidos.

  2. Uso de Interfaces como Tokens: Ao usar strings como tokens para injeção de dependência, estamos efetivamente usando uma forma de Injeção de Dependência por Contrato. Isso significa que, em vez de depender diretamente de uma classe específica, você depende de uma interface (ou, neste caso, uma string que representa uma interface). Isso permite que você altere a implementação subjacente sem alterar o código que depende dessa interface, aumentando a flexibilidade e a manutenibilidade do seu código.

  3. Exportação de Dependências: Por fim, foi exportado o token 'IMessageService', o que significa que essa dependência pode ser injetada em outros módulos que importam MessagingModule. Isso é uma prática comum para compartilhar serviços e repositórios entre diferentes partes da aplicação.

Aprendizados

Ao aplicar o DDD, ficou (um pouco) mais claro o uso dele e a importância. Obviamente há um mundo enorme sobre isso, mas nada que uma boa prática não ajude.

Em um projeto, é importante ter em mente que o código irá mudar. Eu mudei toda a estrutura umas 3 vezes até ficar o ideal no momento, e provavelmente pode mudar ainda mais. Não fique triste por isso, aprenda no processo.

Escrever testes te dá segurança! Tenho garantia que posso alterar qualquer camada da minha aplicação sem ter problemas, apenas deixo o teste rodando em modo watch e se eu quebrar outra camada da aplicação, saberei imediatamente!

Fim =)

Para o próximo, tentarei falar mais sobre os testes feitos.

Obrigado se você leu até aqui, se conseguiu aprender algo, deixa um emoji aí =)

Top comments (0)