Pular para o conteúdo principal

Layered Architecture

Descrição​

A Layered Architecture divide o sistema em camadas coesas, cada uma com uma responsabilidade bem definida e dependências que apontam em uma única direção. Evans propõe quatro camadas clássicas: interface com o usuário (apresentação), aplicação, domínio e infraestrutura.

A camada de domínio concentra o modelo e as regras de negócio e é o coração do software. A camada de aplicação coordena casos de uso, sem conter regras de negócio, e a infraestrutura fornece suporte técnico, como persistência e mensageria. Camadas superiores dependem das inferiores, e o domínio fica isolado de detalhes de interface e de tecnologia.

O objetivo é que o código do modelo possa ser lido, testado e evoluído sem se misturar a preocupações técnicas, viabilizando o Model-Driven Design.

Problemas que resolve​

  • Regras de negócio espalhadas em telas, controladores e consultas SQL.
  • Modelo de domínio acoplado a framework, banco de dados e interface.
  • Dificuldade de testar regras sem subir infraestrutura.
  • Mudanças técnicas que forçam alterações no código do domínio.

Quando usar​

  • Em sistemas com domínio rico, onde o modelo precisa ser expresso com clareza.
  • Quando a equipe quer isolar a lógica de negócio de preocupações técnicas.
  • Quando há várias interfaces (web, API, jobs) sobre o mesmo modelo.

Quando evitar​

  • Em aplicações CRUD simples, sem lógica de domínio relevante.
  • Quando as camadas viram apenas repasse de chamadas, sem ganho de isolamento.

Trade-offs​

GanhoCusto / Risco
Domínio isolado e testávelMais código de mapeamento entre camadas
Separação clara de responsabilidadesRisco de camadas anêmicas que só repassam chamadas
Troca de tecnologia sem afetar o modeloExige disciplina para respeitar o sentido das dependências
  • Dependências: a inversão de dependência permite que o domínio defina interfaces implementadas pela infraestrutura.
  • Variações: arquiteturas hexagonal e em cebola seguem a mesma ideia de isolar o domínio.

Diagrama​

A interface chama a aplicação, que orquestra o domínio. A infraestrutura implementa as abstrações definidas pelo domínio e serve às demais camadas.

Exemplo​

Em um sistema de pedidos, o controlador (interface) chama um serviço de aplicação, que carrega o agregado, delega a regra ao domínio e persiste pelo repositório.

// application
class CancelOrderService {
constructor(private orders: OrderRepository) {}

async execute(orderId: string): Promise<void> {
const order = await this.orders.findById(orderId);
order.cancel(); // regra no domínio
await this.orders.save(order);
}
}

// domain
interface OrderRepository {
findById(id: string): Promise<Order>;
save(order: Order): Promise<void>;
}

Padrões relacionados​

  • Model-Driven Design — a camada de domínio isola o modelo para que ele seja refletido no código.
  • Domain Service — serviços de domínio e de aplicação ocupam camadas distintas.
  • Repository — interface no domínio, implementação na infraestrutura.
  • Bounded Context — cada contexto pode ter sua própria estrutura de camadas.
  • Service Layer — equivale, em linhas gerais, à camada de aplicação.

Referência​