DEV Community

Igor Rudel
Igor Rudel

Posted on

2

Dica Java: Evite trafegar objetos de DTO's #002

Uma das práticas que venho adotando (ás vezes tentando adotar) nos serviços que tenho construído é de: cuidar e evitar que objetos de classes DTO's trafeguem fora da camada a que ela pertence.

Vejo em muitos desenvolvimentos as classes DTO's de Request e Response sendo usadas na camada de service, de requests por argumentos de métodos e responses em retornos de métodos.

public class PersonService {

    public PersonResponse create(final PersonBody body) {
        //implementação das regras

        return new PersonResponse();
    }
}
Enter fullscreen mode Exit fullscreen mode

As classes de Request e Response são basicamente a definição dos contratos (geralmente REST) de entrada e saída do serviço e deveriam ficar apenas na camada WEB, ou seja, nas Controller's. Existem também as DTO's que são payload's de recursos de mensageria (Kafka ou RabbitMQ), que, por sua vez, também deveriam ficar apenas na camada dos listener's.

Por essa abordagem, tenho aplicado o uso de classes que chamo de domínio em ambos os locais dos métodos das services: argumentos e retornos.

public class PersonService {

    public PersonDomain create(final PersonDomain person) {
        //implementação das regras

        return new PersonDomain();
    }
}
Enter fullscreen mode Exit fullscreen mode

A nomenclatura das classes podem variar um pouco, por exemplo: PersonCreationDomain ou PersonCreation.

Os de->para sempre utilizando MapStruct caso a estrutura das classes sejam muito parecidas ou construções mais manuais separadas em Bean's que concentram as construções/mapeamentos (costumo chamar de Mapper quando utilizo MapStruct ou Factory quando a construção é manual).

public class PersonController {

    private final PersonService service;
    private final DomainMapper domainMapper;
    private final ResponseMapper responseMapper;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public PersonResponse create(@RequestBody final PersonBody body) {
        final var domain = domainMapper.map(body);

        return responseMapper.map(
            service.create(domain)
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Dessa maneira, ambos os DTO's ficam apenas no controller e no máximo são repassados para uma camada de mapeamento (DomainMapper e ResponseMapper).

Dos pontos mais importantes dessa abordagem: manter responsabilidades nas camadas e reaproveitamento de código.

Até o momento eu mostrei apenas responsabilidade.

E o reaproveitamento?

Imagina agora que a necessidade de criação de pessoa será por mensageria e o payload muda um pouco, mas todas as regras e a lógica se aplicam.

Pode ser criada uma classe apenas para o contrato da mensageria (ex: PersonPayload), ter apenas um mapeamento da nova classe para PersonDomain (MapStruct ou manual), e é reaproveitado a service sem alterar contrato do método ou necessitar definir outro método na PersonService que manipule o objeto da PersonPayload.

O mais legal: a PersonService nem sabe se é REST, Mensageria, SOAP, etc... desacoplamento da camada de serviço da aplicação!

Existem alguns conceitos como SOLID, Clean Code, responsabilidade, organização, padronização, etc, aplicados nessa abordagem.

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (2)

Collapse
 
diegobrandao profile image
Diego de Sousa Brandão

Muito boa essa abordagem! Basicamente, você está separando bem as responsabilidades e evitando que DTOs "contaminem" camadas que não deveriam conhecê-los. Isso lembra bastante a arquitetura hexagonal, onde a camada de serviço trabalha apenas com objetos de domínio e as interfaces externas (REST, Kafka, etc.) lidam com a conversão dos dados.

Collapse
 
oigorrudel profile image
Igor Rudel

Não gosto muito de dar nomes como "hexagonal", porque daqui 2 meses há uma nova arq com outro nome e aplicando o mesmo conceito de forma diferente kkk mas sim, tem um pouco do conceito aplicado :D

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay