Domain Driven Design e Serviços na camada de modelo

Olá parceiros de guj,

Lí o livro Domain driven design quickly, que é um “resumo” dos conceitos apresentados no livro do Eric Evans e fiquei com uma grande pulga atras da orelha.
Minha dúvida é em relação aos serviços na camada de modelo. Essa abordagem é necessária em qual situação?

No livro, ele cita o exemplo de uma transferência de valores entre contas correntes. O método que contem a lógica da transferência deveria ficar em que objeto Conta Corrente? No objeto que está recebendo ou no que está enviando o dinheiro.
A sugestão do autor foi criar um serviço de modelo. Este serviço teria a lógica para executar esta operação recebendo dois objetos conta corrente e realizando a operação.

Agora eu pergunto: Isso é realmente necessário?

Estou pensando que as contas devem estar em algum lugar. Provavelmente deve existir o objeto “Banco” neste modelo. Não seria coeso que o método de realizar a transferencia entre contas esteja no objeto em que as contas estão contidas (Banco). Essa não seria uma solução “mais DDD”? Essa abordagem minha pode causar algum impacto negativo no design?!

Bom essa é minha duvida. Ainda não fui atraz da fonte, o livro escrito pelo Eric Evans, mas assim que for possível vou comprar o livro e estuda-lo de acordo.

Está aberta a discussão. Serviços de dominio são necessários?

Abraço a todos,
Ferry

Cara… eu já me confundi com isso muitas vezes… vou explicar como eu vejo o que você descreveu.

No domínio do problema apresentado no livro, não existe a entidade Banco.

Banco: com um nome, cnpj etc… (uma empresa de verdade).

Mas o que ele modela, faz parte do Banco(conceito) e um banco tem serviços, incluindo um de transferência. Sendo assim, as contas estão no repositório de contas que são acessados pelos serviços. E dessa forma se fez necessário um serviço.

Se o dominio tivesse vários bancos (várias empresas) e cada banco tivesse suas contas por exemplo, faria sentido existir a classe banco e faria sentido essas classes terem os métodos de transferência, mas imagine que você quisesse fazer uma transferência entre contas de Bancos diferentes… você precisaria de um serviço, já que não é responsabilidade de um banco fazer uma operação envolvendo contas de bancos diferentes

Espero ter ajudado

Opa valeu pela reply.

Entendi o que você quis dizer. Só que ainda estou “resistente” a essa idéia. Se um serviço de transferência é necessário, quem pode fornecer este serviço pode ser uma entidade, então prefiro criar a entidade.

Mesmo que seja uma transferencia entre bancos diferentes. Alguem deve ter a responsabilidade de fazer a transferência (neste exemplo eu não sei de quem seria).
Criando serviços assim eu sinto como se estivesse fugindo da OO, pois sinto como se estivesse criando uma classe que não é um objeto, mas sim um algoritmo que irá receber dados e processar.

Alguem concorda?

Bom…

No exemplo do livro, o banco não é uma entidade (não tem um “ID”), logo ele não é instanciado por uma Factory nem acessível por um Repository.

Dessa forma, ele é como se fosse um Serviço (segundo a definição do livro também), ele realiza uma operaçõ que fugiu do escopo da classe Account

Entao seria mais uma questão de nomeclatura… Banco X **Service

[quote=Ferryman]Olá parceiros de guj,

Lí o livro Domain driven design quickly, que é um “resumo” dos conceitos apresentados no livro do Eric Evans e fiquei com uma grande pulga atras da orelha.
Minha dúvida é em relação aos serviços na camada de modelo. Essa abordagem é necessária em qual situação?

(…)
Agora eu pergunto: Isso é realmente necessário?
[/quote]

Sim, é realmente necessário.
A razão é o principio de separação de responsabilidade.
Não é responsabilidade da conta X transferir dinheiro para a conta Y.
Essa responsabilidade é da transação monetária.

Nada impede vc de modelar a transação monetária como um objeto com estado. E nesse sentido a transação não seria um service.
O autor do livro apenas dá esse exemplo, partindo do principio que esse tipo de transação não tem estado. Um objeto sem estado não é uma entidade (não tem identidade) , logo ,tem que ser outra coisa. O DDD chama a essa outra coisa Serviço. Veja, o Serviço não é uma classe com apenas com métodos estáticos, é um objeto normal, só que sem estado.

Serve apenas para encasuplar algoritmos ? Sim, exatamente. Aliás, como todos os objetos servem. A diferença é que um serviço apenas atua sobre argumentos dos seus metodos e não sobre nenhum estado interno.

Valeu Sergio

Entendi o que você disse e concordo que essa responsabilidade não é da conta e sim de outra “Coisa”.
Como essa outra coisa não tem estado então ela é definida como um serviço.

Entendi.
Valeu

Abraço,
Ferry

[quote=sergiotaborda][quote=Ferryman]Olá parceiros de guj,

Lí o livro Domain driven design quickly, que é um “resumo” dos conceitos apresentados no livro do Eric Evans e fiquei com uma grande pulga atras da orelha.
Minha dúvida é em relação aos serviços na camada de modelo. Essa abordagem é necessária em qual situação?

(…)
Agora eu pergunto: Isso é realmente necessário?
[/quote]

Sim, é realmente necessário.
A razão é o principio de separação de responsabilidade.
Não é responsabilidade da conta X transferir dinheiro para a conta Y.
Essa responsabilidade é da transação monetária.

Nada impede vc de modelar a transação monetária como um objeto com estado. E nesse sentido a transação não seria um service.
O autor do livro apenas dá esse exemplo, partindo do principio que esse tipo de transação não tem estado. Um objeto sem estado não é uma entidade (não tem identidade) , logo ,tem que ser outra coisa. O DDD chama a essa outra coisa Serviço. Veja, o Serviço não é uma classe com apenas com métodos estáticos, é um objeto normal, só que sem estado.

Serve apenas para encasuplar algoritmos ? Sim, exatamente. Aliás, como todos os objetos servem. A diferença é que um serviço apenas atua sobre argumentos dos seus metodos e não sobre nenhum estado interno.[/quote]

Se um serviço não possui estado, então, como setar as dependências de repositories para que os métodos desse serviço possam executar suas regras de negócio ?!?

As implementações de DDD-services que tenho visto (ddd-sample) são sempre ou classes abstradas sem implementação ou interfaces.

O problema é que sendo classes abstradas ou interfaces, a implementação da lógica do serviço acaba ficando em uma classe *Impl que, normalmente, fica em algum package de infraestrutura, ou seja, parte das regras de negocio do dominio ficarão fora dele.

É isso mesmo ou tem algo que não estou vendo ?

[quote=marcosurata]Se um serviço não possui estado, então, como setar as dependências de repositories para que os métodos desse serviço possam executar suas regras de negócio ?!?

As implementações de DDD-services que tenho visto (ddd-sample) são sempre ou classes abstradas sem implementação ou interfaces.

O problema é que sendo classes abstradas ou interfaces, a implementação da lógica do serviço acaba ficando em uma classe *Impl que, normalmente, fica em algum package de infraestrutura, ou seja, parte das regras de negocio do dominio ficarão fora dele.

É isso mesmo ou tem algo que não estou vendo ?
[/quote]

Quando o Sergio disse que nao possuem estado, ele se refere a estado persistente.

Note que esses Services a que estamos nos referindo fazem parte do dominio, entao nao, parte das regras de negocio nao estarao fora do dominio. Até porque os services nao contem regras, eles apenas “pedem” aos objetos do dominio que executem suas regras de forma coordenada. Eles, no maximo, “cuidam” para que a operacao de transferencia (como no exemplo do autor do topico) se mantenha consistente.

Eu tambem ja tive essa duvida sobre ter um objeto persistente cuidando desses servicos, até perceber que eu mantinha eles persistentes somente para a execucao dos servicos, e estavam me dando um trabalho extra desnecessario. E muitas vezes, diferente do exemplo dado aqui, a funcao deles nao era tao obvia como a do banco.

Particularmente, apesar de correto, o exemplo do banco/transferência não é muito bom. O service é uma classe que coordena uma transação que não é naturalmente alocada a nenhuma entity. O exemplo que forneço no meu curso é o faturamento de um Pedido. Quando um pedido é faturado:

  1. O pedido é verificado
  2. Uma nota fiscal é gerada
  3. Duplicatas são geradas
  4. Um estoque é atualizado
  5. O limite de crédito do cliente é atualizado
  6. etc… etc… etc…

Alguns podem dizer que podemos alocar essas responsabilidades à Pedido.faturar(). Essa operação pode até existir pela Ubiquitous Language (afinal, o cliente DIZ que pedidos são faturados), mas a orquestração (não sei se essa palavra existe) de tudo isso acima são responsabilidades muito grandes para o próprio pedido. Seria legal que ele delegasse isso para um <<Service>> Faturamento (podendo ser uma estratégia de Pedido).

Logicamente, esse serviço existe porque isso faz sentido para o usuário (é DDD que estamos falando, certo?). É a classe Faturamento que lida com as coisas que o cliente entende como sendo o Faturamento. Nada impede também que um serviço acione outros serviços do domínio.

[quote=rodrigoy]Particularmente, apesar de correto, o exemplo do banco/transferência não é muito bom. O service é uma classe que coordena uma transação que não é naturalmente alocada a nenhuma entity. O exemplo que forneço no meu curso é o faturamento de um Pedido. Quando um pedido é faturado:

  1. O pedido é verificado
  2. Uma nota fiscal é gerada
  3. Duplicatas são geradas
  4. Um estoque é atualizado
  5. O limite de crédito do cliente é atualizado
  6. etc… etc… etc…

Alguns podem dizer que podemos alocar essas responsabilidades à Pedido.faturar(). Essa operação pode até existir pela Ubiquitous Language (afinal, o cliente DIZ que pedidos são faturados), mas a orquestração (não sei se essa palavra existe) de tudo isso acima são responsabilidades muito grandes para o próprio pedido. Seria legal que ele delegasse isso para um <<Service>> Faturamento (podendo ser uma estratégia de Pedido).

Logicamente, esse serviço existe porque isso faz sentido para o usuário (é DDD que estamos falando, certo?). É a classe Faturamento que lida com as coisas que o cliente entende como sendo o Faturamento. Nada impede também que um serviço acione outros serviços do domínio.[/quote]

Olá, rodrigo concordo com o que você falou, além do mais fazer soment pedido.faturar() tornaria o metodo “gordo demais”. Agora só faço uma observação, não seria interessante, tbm separar a geranção da nota Fiscal em um serviço, e usar um serviço orquestrado, como um façade para chamar os dois serviços, necessários.

Digo isso pois a nota fiscal, pode depender de serviços externos,como por exemplo a NF eletronica.

Foi só um exemplo. Como falei, dentro de <<service>>Faturamento você vai ter um monte de coisas, nada impede de um serviço chamar o outro. Você pode até dizer que esse service atua como uma Façade, mas para o domínio isso é irrelevante. Um service pode ser uma façade (mas não por isso você vai deixar de chamá-lo de service).

[quote=rodrigoy]Foi só um exemplo. Como falei, dentro de <<service>>Faturamento você vai ter um monte de coisas, nada impede de um serviço chamar o outro. Você pode até dizer que esse service atua como uma Façade, mas para o domínio isso é irrelevante. Um service pode ser uma façade (mas não por isso você vai deixar de chamá-lo de service).
[/quote]

Entendi que foi só um exemplo. Então, extamente isso quando falei do Façade, era o que quis dizer, os serviços orquestrados, irão sempre atuar como Façades, mas continuarão a ser serviços.