Arquitetura limpa no Node.js na prática (sem dogma)

March 28, 2026 (1mo ago)

Problema

“Clean Arch” virou pastas entities/usecases/adapters vazias ou frameworks dentro do domínio. O time para de entregar valor e a arquitetura vira desculpa para burocracia.

Solução

Aplicar o espírito: regras de negócio independentes de framework; dependências apontando para dentro; IO na borda. Começar pelo núcleo que muda menos (regras de preço, elegibilidade, políticas) e introduzir portas só onde há troca real (Postgres hoje, outro DB amanhã).

Arquitetura

domain/
  order.ts           # entidade + invariantes
application/
  place-order.ts     # caso de uso (orquestra)
ports/
  order-repository.ts
  payment-gateway.ts
infra/
  prisma-order-repository.ts
  stripe-gateway.ts

O caso de uso não importa Express ou Prisma — recebe portas injetadas.

Código

// application/place-order.ts
export class PlaceOrder {
  constructor(
    private readonly orders: OrderRepository,
    private readonly payments: PaymentGateway
  ) {}
 
  async execute(cmd: PlaceOrderCommand) {
    const order = Order.create(cmd.items);
    const charge = await this.payments.charge(order.totalCents, cmd.customerId);
    await this.orders.save(order.paid(charge.id));
    return order.id;
  }
}
// infra/http/order-controller.ts (adapter)
@Post()
async place(@Body() body: PlaceOrderBodyDto) {
  return this.placeOrder.execute({ ...body });
}

Performance

Camadas extras não precisam custar: evite alocar DTOs gigantes; use lazy init em adapters pesados; profile antes de “otimizar” domínio.

Melhorias futuras

Eventos de domínio + handlers; testes de contrato nas portas; anti-corruption layer para integrações legadas.

Conclusão

Clean Architecture é ferramenta de isolamento de risco, não religião de pastas. Demonstrar esse equilíbrio é forte sinal de senioridade.