DEV Community

Yan.ts
Yan.ts

Posted on

4 3

DDD Services

Today I Learned — 04/05/2022

Aggregates

Um Aggregate é um padrão em DDD onde temos um conjuntos de objetos de dominio e value objects podem ser tratados como uma unidade

Exemplo de aggregates

Value Objects

Value objects são como o nome diz, um objeto que não tem operações associadas, ele serve somente para guardar valores, no exemplo acima o Address é um value object pois quando uma pessoa muda para a rua ao lado, mesmo que a unica parte que tenha mudado no endereço dela seja a rua, nós não falamos que ela ATUALIZOU a rua no endereço, e sim que ela MUDOU de endereço, o que no sistema se traduziria em um novo value object e não em um update dentro de um value object já existente

Services

Quando falamos em DDD o Service é uma operação sem estado que cumpre uma tarefa especifica do domínio. A melhor indicação que devemos criar um service é quando queremos fazer uma operação que não parece fazer sentido como o método em um Agreggate ou um Value Object.

Cuidados
  • Caso existam muitos services no projeto isso pode indicar que os aggregates estão anêmicos
  • Services são Stateless, O que significa que eles não carregam valores de uma chamada para a outra

Implementação

Para o mesmo sistema demonstrado acima podemos ter por exemplo uma entidade de orders que contem items como value object

export class Order{ 
  private _id: string;
  private _customerId: string;
  private _items: OrderItem[];
  private _total: number;

  constructor(id: string, customerId: string, items: OrderItem[]){
    this._id = id;
    this._customerId = customerId;
    this._items = items;
    this._total = this.total();
  }

  total(): number{
    return this._items.reduce((acc, item) => acc + item.price, 0)
  }

}
Enter fullscreen mode Exit fullscreen mode

Nessa classe de order temos um método para retornar o total dá order em especifico mas e se quisermos calcular o total de todas as orders? Não faz sentido ficar como método de uma order já q esse método vai precisar receber outras orders para fazer a conta, é nesse caso que devemos criar o service de Orders

export class OrderService{
  static total(orders: Order[]): number {
    return orders.reduce((acc, order) => acc + order.total(), 0);
  }
}
Enter fullscreen mode Exit fullscreen mode

O OrderService pode conter todas os métodos que não fazem sentido ficarem dentro de Order inclusive por exemplo criar uma nova order

export class OrderService{
  static total(orders: Order[]): number {
    return orders.reduce((acc, order) => acc + order.total(), 0);
  }

  static placeOrder(customer: Customer, items: OrderItem[]): Order{
    if(items.length === 0){
      throw new Error("Order must have at least one item")
    }

    const order = new Order(uuid(), customer.id, items);
    return order
  }
}
Enter fullscreen mode Exit fullscreen mode

Ainda estou aprendendo sobre DDD e se quiser ver melhor o código pode dar uma olhada nesse Repositório

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay