DDD Services
Tags: ddd, javascript, todayilearned, braziliandevs
Published: 2022-05-04 23:52:30

#### Today I Learned — 04/05/2022

- [Aggregates](#aggregates)
- [Value Objects](#value-objects)
- [Services](#services)
- [Implementação](#implementação)

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5oa7tp0unsr5wk4hh0gv.png)
 
## 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

```js
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)
  }

}
```

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

```js
export class OrderService{
  static total(orders: Order[]): number {
    return orders.reduce((acc, order) => acc + order.total(), 0);
  }
}
```
O OrderService pode conter todas os métodos que não fazem sentido ficarem dentro de Order inclusive por exemplo criar uma nova order

```js
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
  }
}
```

> Ainda estou aprendendo sobre DDD e se quiser ver melhor o código pode dar uma olhada nesse [Repositório](https://github.com/Yansb/full-cycle-course/tree/master/domain-driven-design)