O Use Case: Modelando as Interações do Seu Domínio

Guilherme Biff Zarelli
Inside PicPay
Published in
5 min readJun 6, 2024

Os casos de uso desempenham um papel crucial na definição das interações entre usuários e sistemas, atuando como uma ponte entre os requisitos de negócio e a implementação técnica.

Neste artigo, vamos entender os use cases e suas interações. Veremos como modelar casos de uso que não apenas documentam requisitos, mas também orientam o desenvolvimento de sistemas robustos e centrados no domínio.

O Use Case

Alistair Cockburn, em Writing Effective Use Cases”, define um caso de uso como “uma descrição de um conjunto de interações entre um sistema e um ou mais atores, onde um ator é uma entidade externa ao sistema”. Isso enfatiza a importância de capturar as interações do sistema de forma detalhada e clara. Essa narrativa detalha o comportamento do sistema em resposta a uma solicitação, documentando as ações necessárias para completar um objetivo.

Alistair também explora diversas formas de escrever casos de uso, o que pode ser extremamente útil para orientar uma implementação de código eficaz. Embora neste artigo o foco seja no fluxo de código dos casos de uso, e não na sua escrita detalhada, recomendo a leitura do livro para uma compreensão completa do processo.

Integração com o Core Domain

Em arquiteturas como a Clean Architecture de Robert C. Martin e a Hexagonal Architecture de Alistair Cockburn, os casos de uso são pontos de entrada para o core domain, camada que aplica as regras de negócio.

Eles residem na camada de aplicação, traduzindo os requisitos de negócio em ações concretas por meio da orquestração da interação entre dados de entrada, saída e o core domain.

A typical scenario for a web-based Java system utilizing a database — Martin, R.C. Clean Architecture; p196 (Imagem reproduzida por Sergio Rodríguez em: Github)

Na imagem acima, baseada na figura 22.2 do livro Clean Architecture, Robert C. Martin descreve um cenário típico de implementação de um caso de uso da seguinte maneira: “O UseCaseInteractor interpreta esses dados e os utiliza para controlar a dança das Entidades.”

Isso destaca como o caso de uso processa os dados e orquestra a interação das entidades dentro do sistema.

Fluxo vs. Regras de Negócio

Um equívoco frequente é tratar os casos de uso como “classes de serviço”. Casos de uso devem orquestrar as interações entre componentes do sistema, enquanto as regras de negócio pertencem ao domínio, geridos por suas Entities, Domain Services e/ou Aggregates.

Manter a lógica de negócio no domínio e usar casos de uso apenas para coordenação garante um design mais limpo e modular. Isso impede que um caso de uso dependa de outro para atender um requisito de negócio ou para tentar reaproveitar alguma regra.

Veja mais sobre domínios nesse artigo: O Core Domain: Modelando Domínios Ricos

E também essa playlist do Elemar Jr sobre Domain Driven Design: DDD do Jeito Certo

Exemplos e implementação de Casos de Uso

Agora, vamos exemplificar a utilização de casos de uso considerando a implementação de duas regras diferentes, porém muito similares: o envio e o reenvio de pedidos.

Primeiramente, abordaremos um cenário no qual as regras de negócio estão dispersas nos casos de uso, induzindo a interação entre eles. Em seguida, mostraremos como poderíamos separar melhor suas responsabilidades.

Use Cases como Serviços de Domínio (Não faça assim)

Nos exemplos a seguir, o ReshippingOrderUseCase reutiliza as regras de envio definidas no ShippingOrderUseCase. Observe como o modelo “ruim” resulta em um forte acoplamento entre esses dois casos de uso:

Veja como o ShippingOrderUseCase mantém as regras de negócios acopladas aos fluxos, expondo-as para reutilização.

A partir desses exemplos, trabalharemos em uma solução adequada. Vamos separar as regras de negócio em um serviço de domínio, deixando os casos de uso responsáveis apenas pelo controle de fluxo.

Use Cases como deveriam ser: Shipping Order

O ShippingOrderUseCase representa o processo padrão de envio de pedidos. Para melhorar a modularidade e a reutilização do código, transferimos as regras de negócio do método de envio para uma classe de serviço de domínio chamada ShipmentSenderService. Esse serviço agora trata exclusivamente do envio, lidando apenas com objetos de domínio, o que resulta em um código mais limpo e desacoplado.

Use Cases como deveriam ser: Reshipping Order

O ReshippingOrderUseCase trata de pedidos que precisam ser reenviados por algum motivo específico. Como ajuste, eliminamos a dependência do ShippingOrderUseCase e adotamos o ShipmentSenderService. Com essa transição, transferimos as demais regras de negócio exclusivas de reenvio para o ShipmentSenderService.

O Serviço de domínio: Shipment Sender Service

O ShipmentSenderService passa a centralizar as ações específicas que lidam com as regras de negócio. Por meio desse serviço de domínio, podemos reutilizar suas ações em diversos cenários que envolvem o envio de pedidos.

Com isso, finalizamos a refatoração na qual, inicialmente, observamos um cenário onde as regras de negócio estavam dispersas e acopladas aos casos de uso. Em contraste, apresentamos uma solução mais adequada, onde as regras de negócio são centralizadas na camada de domínio, permitindo que os casos de uso se concentrem no controle de fluxo.

Conclusão

Neste artigo, exploramos a importância dos casos de uso na modelagem das interações entre usuários e sistemas, destacando sua função como pontos de entrada para definir o fluxo do core domain.

Ao manter a lógica de negócio no domínio e utilizar os casos de uso para coordená-la, fortalecemos a arquitetura do sistema. Essa prática também evita dependências cruzadas entre os casos de uso, tornando a manutenção e a evolução do sistema mais simples.

Com casos de uso bem definidos em conjunto com domínios ricos, é possível obter um sistema mais coeso e adaptável.

Referências

--

--