Pular para o conteúdo

Service Layer

“Defines an application’s boundary with a layer of services that establishes a set of available operations and coordinates the application’s response in each operation.”

O Service Layer é a fachada dos casos de uso. Ele coordena colaboradores (entidades, Repositórios, gateways), gerencia a fronteira transacional e traduz entre o mundo externo e o domínio.

Sem uma camada de aplicação explícita, a lógica de coordenação (transação, orquestração, autorização) vaza para a camada web (controllers) ou para o Domain Model. O Service Layer dá um lugar único e estável para essa coordenação, servindo múltiplos clientes (REST, mensageria, jobs) com a mesma API.

  • Quando há mais de um cliente/canal consumindo a mesma lógica.
  • Para demarcar transações e casos de uso de forma explícita.
  • Como fronteira de segurança/autorização e de mapeamento DTO ↔ domínio.
Vantagem Custo
Fronteira transacional clara Camada extra (mais indireção)
Casos de uso explícitos Risco de virar “gerente” anêmico
Reuso entre canais Pode duplicar contratos (DTOs)

Em aplicações pequenas com um único cliente, o Service Layer pode ser tão fino que praticamente coincide com o controller. Nesse caso, mantenha-o mínimo — não force uma camada cerimoniosa.

O Service Layer coordena, não decide regra de domínio. Se as invariantes e cálculos migram para os serviços, o Domain Model vira anêmico e o serviço vira um Transaction Script disfarçado. A regra de negócio pertence às Entidades/Agregados ou a Domain Services quando não cabe numa única entidade.

graph TD
    Controller[Controller / REST] --> SL[Service Layer]
    SL -->|orquestra| DM[Domain Model]
    SL -->|persiste| Repo[Repositórios]
    SL -->|integra| GW[Gateway]
    SL -.->|@Transactional| TX[(Transação)]
    DM -->|contém a regra| DM
@Service
public class PedidoAppService {
private final PedidoRepository pedidos;
private final EstoqueGateway estoque;
private final PagamentoGateway pagamento;
public PedidoAppService(PedidoRepository pedidos,
EstoqueGateway estoque,
PagamentoGateway pagamento) {
this.pedidos = pedidos;
this.estoque = estoque;
this.pagamento = pagamento;
}
@Transactional
public PedidoDTO confirmar(ConfirmarPedidoCommand cmd) {
Pedido pedido = pedidos.findById(cmd.pedidoId())
.orElseThrow(() -> new PedidoNaoEncontradoException(cmd.pedidoId()));
estoque.reservar(pedido.getItens());
pedido.confirmar();
pagamento.cobrar(pedido.getTotal(), cmd.meioPagamento());
pedidos.save(pedido);
return PedidoDTO.from(pedido);
}
}

Repare: a decisão de poder confirmar (estado válido, itens presentes, total calculado) está em pedido.confirmar(), dentro do Domain Model. O serviço só orquestra a sequência, integra sistemas externos via Gateway e demarca a transação.

  • Serviço gordo / domínio anêmico: regra de negócio migrando para o serviço.
  • Transação larga demais: @Transactional cobrindo chamadas externas lentas (gateways), causando locks longos.
  • Vazar entidades para a web: retornar entidades JPA em vez de DTOs.
  • Confundir com Domain Services: Domain Service contém regra que não cabe numa entidade; Service Layer (aplicação) apenas coordena.
  • Duplicar validação: revalidar no serviço o que a entidade já garante.

1. Qual é a responsabilidade essencial do Service Layer?

Resposta

Coordenar casos de uso: orquestrar objetos de domínio, delimitar a transação e mediar a integração com o exterior — sem conter a regra de negócio.

2. Como o Service Layer pode causar um domínio anêmico?

Resposta

Quando as invariantes e cálculos migram para os serviços em vez de morarem nas entidades/agregados. O domínio fica só com dados e o serviço vira um Transaction Script disfarçado.

3. Qual a diferença entre Service Layer e Domain Service?

Resposta

O Domain Service contém regra de domínio que não pertence naturalmente a uma única entidade; o Service Layer (aplicação) apenas coordena o fluxo do caso de uso e a transação.

4. Por que evitar transações longas no Service Layer?

Resposta

Porque envolver chamadas externas lentas dentro de @Transactional mantém locks e conexões abertos por muito tempo, prejudicando concorrência e escalabilidade.