Pular para o conteúdo principal

Aggregate

Descrição​

Um Aggregate é um grupo de entidades e Value Objects tratado como uma unidade para fins de mudança de dados. Uma entidade é a raiz (Aggregate Root), a única com identidade global e a única referenciada por objetos de fora; os demais membros têm identidade local ao agregado.

A raiz garante as invariantes de todo o grupo. Objetos externos só mantêm referências para a raiz e só a modificam por meio de seus métodos. A fronteira define o escopo da transação: uma transação altera um único agregado, e a consistência entre agregados é eventual.

Referências entre agregados devem ser feitas por identidade, e não por referência direta ao objeto, o que mantém os agregados pequenos e desacoplados.

Problemas que resolve​

  • Grafos de objetos emaranhados, sem fronteira clara de consistência.
  • Invariantes violadas por modificações feitas direto em objetos internos.
  • Transações grandes que bloqueiam muitos dados e geram contenção.
  • Dificuldade de decidir o escopo de carga e de persistência.

Quando usar​

  • Quando há invariantes que precisam valer de forma consistente entre vários objetos.
  • Quando é preciso definir a unidade de transação e de persistência.
  • Quando se quer limitar o acoplamento entre partes do modelo.

Quando evitar​

  • Quando os agregados ficam grandes demais, causando contenção e custo de carga.
  • Quando a fronteira é imposta por conveniência técnica, sem invariantes reais.

Trade-offs​

GanhoCusto / Risco
Invariantes garantidas dentro da fronteiraAgregados grandes causam contenção e lentidão
Unidade clara de transação e persistênciaConsistência entre agregados é eventual
Acoplamento reduzido por referência via identidadeConsultas entre agregados exigem mais trabalho
  • Tamanho: prefira agregados pequenos, projetados em torno de invariantes reais.
  • Eventos: mudanças que afetam outros agregados costumam ser propagadas por Domain Events.
  • Acesso: o Repository trabalha por raiz de agregado.

Diagrama​

Order é a raiz e controla OrderItem e ShippingAddress. A referência a Customer, outro agregado, é feita apenas por identidade.

Exemplo​

O pedido protege a invariante de limite de itens; ninguém altera OrderItem diretamente.

class Order {
private items: OrderItem[] = [];
constructor(readonly id: string, readonly customerId: string) {}

addItem(productId: string, qty: number, price: Money): void {
if (qty <= 0) throw new Error("Quantidade inválida");
if (this.items.length >= 20) throw new Error("Limite de itens excedido");
this.items.push(new OrderItem(productId, qty, price));
}

total(): Money {
return this.items.reduce((sum, i) => sum.add(i.subtotal()), Money.zero());
}
}

Padrões relacionados​

  • Entity — a raiz do agregado é uma entidade.
  • Value Object — compõe o agregado ao lado de entidades internas.
  • Repository — persiste e recupera um agregado por vez, pela raiz.
  • Factory — cria o agregado inteiro, garantindo invariantes na criação.
  • Domain Event — propaga mudanças entre agregados com consistência eventual.
  • Domain Model — o agregado organiza o modelo de domínio em fronteiras de consistência.

Referência​