Mais uma dúvida sobre Entites X Repositories dentro de DDD

No caso, o repositório serviria como fachada para a camada de persistência. Ou seja, só o fato de minha camada de negócios depender de uma abstração da persistência já vale o uso.

Mas agora eu entendi seu ponto. Tudo o que eu estava buscando com a abordagem que ilustrei era exatamente evitar que o repositório dependa do DAO.

Será que não teria uma forma de eu fazer de minha interface Repositorio uma classe concreta usando um DAO genérico ( exatamente o que você disse ), mas sem usar objetos da API de persistência dentro dele?

Não me leve a mal, é que não me entra na cabeça a idéia de um repositório depender de um DAO, ou de qualquer tecnologia de persistência específica. Isso é misturar responsabilidades de domínio com infra-estrutura, queira ou não. Gostaria da opinião de outros membros do grupo sobre essa questão.

Ah, e concordo plenamente com você quando você diz que a abordagem que ilustrei aqui acaba fazendo com que métodos de negócio sejam implementados no DAO, o que é de fato uma desvantagem.

Mas como mostrei, o repositório definiria todos os métodos de negócio necessários relativos à busca de objetos de domínio. O meu DAO usaria Criteria por trás dos panos, sem “estourar” nada pra camada de negócios. Ou seja, nada de Criteria na definição dos métodos. Realmente há desvantagens nisso, como o inevitável estouro de métodos e o fato de reimplementar todos os métodos de consulta ao mudar de implementação de persistência ( como você bem observou ), mas como eu nunca passei por esse tipo de situação, nunca senti falta de trabalhar de uma forma diferente.

Bom, brevemente vou ter a oportunidade de reavaliar tudo isso. Estou prestes a começar um projeto na faculdade e pretendo estudar um pouco mais pra resolver essas “idiossincrasias”.

É, Sérgio, definitivamente dou meu braço a torcer.
Acabei de reler o capítulo de repositórios no resumo do DDD publicado pela InfoQ e vi muita coisa que você citou:

Quando eu li o livro do Eric Evans, tive dificuldades em assimilar alguns conceitos e acabei deduzindo coisas. Felizmente comecei a lê-lo novamente e já estou no capítulo 3 :smiley:
Vou tirar da minha cabeça essa neurose de deixar o repositório independente da camada de persistência…

[quote=pcalcado]
Pois é, você acaba não usando uma Camada separada para persistência e sim aglomerando classes com duas responsabilidades distintas (persistência e neócios) na mesma Camada (acho que foi isso que você quis dizer por namespace).

Usar DIP pura e simplesmente faz com que o domínio não dependa da persistência e a persistência dependa do domínio.

//Dominio
interface AlgumaCoisaRepository{}

//Persistencia
class AgumaCoisaDao implements AlgumaCoisaRepository

O DAO é injetado na Camada de Negócios por algum intermediário imparcial e pronto.[/quote]

Essa é a solucao mais comum, mas não evita a dependencia de baixo pra cima.

O que tenho utilizado é uma camada de persistencia independente sim do dominio, generica a ponto de poder ser utilizada em diferentes projetos.

No dominio/negocio eu tenho os repositorios da forma que você descreveu, usando DIP.

A implementacao trata a persistencia a partir de um nivel mais alto porque delega para a camada de infraestrutura os detalhes e também não contém regras de negócio apesar de depender de objetos de dominio.

Esta atua traduzindo as solicitacoes do cliente da interface para o mecanismo de persistencia. No caso de integracao etnre sistemas eu costumo fazer parecido distribuindo a implementacao num jar separado para fortalecer a ideia de que nao pertence ao dominio apesar de estar dentro dos seus limites. E também porque integracao entre sistemas geralmente é mais comum alterar a anticorruption layer do que a integracao entre o seu sistema e o dominio da persistencia.

No caso, o repositório serviria como fachada para a camada de persistência. Ou seja, só o fato de minha camada de negócios depender de uma abstração da persistência já vale o uso.
[/quote]

Podemos entender o repositorio como uma instancia do padrão Façade , mas não com a camada de persistencia.
O repositorio é principalmente um Façade para a camada de busca. Esta camada normalmente tem a ver com a persistencia, mas não é necessáriamente assim ( Lucene).
É necessário esclarecer é que Repository não tem métodos insert/update/delete como o DAO.
Ele só terá esses métodos em casos particulares em que a coleção de objetos é editada pelo proprio dominio.
Se os dados do dominio são alimentados fora dele, o repositorio não tem métodos de alteração.

Acontece que normalmente o dominio faz algum tipo de alteração e é então que é mais logico usar o repositorio como centralizador dessa necessidade. Mas isso é dar ao repositorio responsabilidades a mais. A base dele não é essa. Não é para isso que ele é criado. Não é para isso que ele existe. Mas uma vez que existe, ele pode também ter essas responsabilidade. ( por isso que nem todas as entidades têm um repositorio)

O DAO não é um objeto sozinho quando fazemos pesquisas. Eles usa alguma linguagem para essa pesquisa.
Estamos partindo do principio que o DAO tem essa linguagem. Se não tem, ele tem métodos especiais do tipo getClientesAtivos() o que o torna não reaproveitável e uma violação do principio de SoC. (um DTO-sabe-tudo)
Portanto, durante a pesquisa o DAO tem um objeto associado. Esse objeto (SQL=String, Criteria, queryObject, etc…) é que é o problema. Não queremos depender desse objeto. Se o DAO é reaproveitável queremos aproveitá-lo em outros sistemas. E ao mesmo tempo queremos ser livres de mudar nosso DAO por um melhor (por exemplo, um que usa melhores implementações ou avançados do JDBC ).
Mas se o DAO depende de uma linguagem de pesquisa e não isolamos essa linguagem, não podemos mudar de DAO.

Na prática, vc tem um DAO para banco de dados e usa SQL para os queries.Um dia vc quer lançar um demo readonly do seu sistema. Ai vc pensa em usar XML porque o overhead do banco seria inutil. Mas ai como vc vai transformar as queries SQL em XPath ? Colocar SQL como linguagem de procura de XML é estranho. Ai vc vai disistir do XML e forçar o uso de um banco em memoria (quando vc sabe que não quer isso). Vc se amarrou a si próprio (lock down) ao uso de SQL. O repositorio evita isso.

E relembro que não se troca de repositorio. Ele é sempre o mesmo. O repositorio é que troca de estratégia.
O repositorio não é definido por uma interface. Ele não é um contrato, é um “braço” do sistema.

Não. Imagine que eu crio um DomainStore muito bom , que usa QueryObject. Estas classes não dependem de dominio e não dependem de API de persistencia. Vc pensa: “legal, agora posso ligar o dominio com este storage porque não dependo do DAO. Os query objets não vão mudar porque o DomaisStore vai isolar isso de mim e traduzir o query para a tecnologia subjacente ( Xpath, SQL, etc…)”

Neste cenário o uso de Repository parece inutil. Só que uma outra empresa desenvolveu um DomainStore que é 100 vezes mais rápido que este. As queries são escritas de forma mais simples e é compativel com mais tecnologias de persistencia (bancos OO , por exemplo). Vc quer mudar para este novo DomainStore muito bom.
Mas vc não pode, porque teria que reescrever os queries com a nova API.
Se estiver usando repository, vc cria uma nova estratégia e pronto. Quando a empesa nova começar a cobrar pelo uso e vc não quiser pagar, vc volta à estratégia antiga.

Este exemplo é muito simples de entender. Todo o mundo usava JDBC com SQL. Todas as queries eram escritas directamente no codigo ( mesmo que dentro do DAO-sabe-tudo). Um dia veio o hibernate. Vc acha que alguem vai algum dia mudar aqueles SQL para Criterias do Hibernate ? Claro que não, porque isso custa dinheiro.

Claro que é sempre possivel refactorar um codigo e introduzir um repositorio onde nenhum existia antes. Afinal a pessoa/equipe aprendeu com seus erros. Mas isso tb é caro. A opção mais barata é usar o repositorio de um principio.

Agora, o repositorio pode receber objetos QueryObject e traduzir para o DAO. Mas ele também pode ter métodos do tipo getCLientsAtivos() e implementar directamente para o DAO. Do ponto de vista OO é a mesma coisa porque invocar find(QueryObject) ou getClientsAtivos() é a mesma coisa. Vc está enviando uma mensagem ao repositorio e ele responde. A escolha é sua.
Repare que se o repositorio usar queryObject esse query será especifico do dominio , logo, não ha perigo disso ter que mudar depois.

OK, tudo entendido. Só ficou mais uma dúvida:

[quote=sergiotaborda]Podemos entender o repositorio como uma instancia do padrão Façade , mas não com a camada de persistencia.
O repositorio é principalmente um Façade para a camada de busca. Esta camada normalmente tem a ver com a persistencia, mas não é necessáriamente assim ( Lucene).
É necessário esclarecer é que Repository não tem métodos insert/update/delete como o DAO.
Ele só terá esses métodos em casos particulares em que a coleção de objetos é editada pelo proprio dominio.
Se os dados do dominio são alimentados fora dele, o repositorio não tem métodos de alteração.

Acontece que normalmente o dominio faz algum tipo de alteração e é então que é mais logico usar o repositorio como centralizador dessa necessidade. Mas isso é dar ao repositorio responsabilidades a mais. A base dele não é essa. Não é para isso que ele é criado. Não é para isso que ele existe. Mas uma vez que existe, ele pode também ter essas responsabilidade. ( por isso que nem todas as entidades têm um repositorio)[/quote]
Ué, mas se o repositório não deveria fazer isso, quem deveria então? Services?

Concordo com essa afirmação do Sérgio e discordo da afirmação do Shoes quanto a repositorios não conter regras.
Exemplos comuns e úteis para o negócio:

  • Alguns objetos do domínio podem precisar de algo como histórico de transações - normalmente objetos inserido em algum flow de processos. Esse histórico não é simplesmente um controle de rastreabilidade, pode ser que o usuário utilize o histórico para copiar informações do processo para um novo processo, isso é negócio. Ao utilizar o repositório para armazenar estes dados, seria prudente que ele armazenasse também uma cópia deste para um outro repositório, o de histórico. Essa atividade seria comum para todas as atividades de armazenamento para este tipo específico de repositório, deixa-la em um Service seria perigoso, lembrando de sempre ter que invocar o repositorio de historicos depois de algum adicionar, atualizar ou remover no repositório do objeto de domínio.

  • Existem dados que devem ser criados quando se efetua, por exemplo, operações de adição no repositório. Toda vez que um determinado objeto for adicionado, deve ser atribuído a ele uma identificação serial com base em uma estratégia pré determinada. Note que isso não deve ser feito quando o objeto é criado (o que pode ser comum na maioria dos casos), mas somente quando ele for persistido… isso pode vir a ser um requisito de negócio.

Ou seja, não existe uma posição absoluta em dizer que jamais se deve usar isso em um repositório. Tanto para o time quanto para o cliente, pode vir bem certeiro atribuir certas regras para a área de atuação no armazenamento dos dados. Utilizar sempre Services para isso, pode ser um desperdício tremendo …

[quote=tnaires]OK, tudo entendido. Só ficou mais uma dúvida:

[quote=sergiotaborda]Podemos entender o repositorio como uma instancia do padrão Façade , mas não com a camada de persistencia.
O repositorio é principalmente um Façade para a camada de busca. Esta camada normalmente tem a ver com a persistencia, mas não é necessáriamente assim ( Lucene).
É necessário esclarecer é que Repository não tem métodos insert/update/delete como o DAO.
Ele só terá esses métodos em casos particulares em que a coleção de objetos é editada pelo proprio dominio.
Se os dados do dominio são alimentados fora dele, o repositorio não tem métodos de alteração.

Acontece que normalmente o dominio faz algum tipo de alteração e é então que é mais logico usar o repositorio como centralizador dessa necessidade. Mas isso é dar ao repositorio responsabilidades a mais. A base dele não é essa. Não é para isso que ele é criado. Não é para isso que ele existe. Mas uma vez que existe, ele pode também ter essas responsabilidade. ( por isso que nem todas as entidades têm um repositorio)[/quote]
Ué, mas se o repositório não deveria fazer isso, quem deveria então? Services?[/quote]

Se o seu dominio escreve/altera a coleção que ele próprio consulta, então o repositorio tem metodos de alteração.
Para os dados que o dominio não manipula a aplicação pode se encarregar disso usando o DAO diretamente.


Pegando um pouco no que o Lezinho falou, existem regras que devem ser implementadas quando é algo é guardado. Esse evento indica que a partir daquele momento aquela instancia de uma entidade pertence ao dominio. Isso pode provocar a criação de outras instancias de outras entidades, etc…
Mas isso tb pode acontecer quando a aplicação usa o DAO automaticamente. Ai teriamos que forçar a aplicação a usar o Repositorio para forçar as regras. O problema é que input do repositorio está preparado para comunicar com o dominio e a apicação teria que usar elementos do dominio para invocar o repositorio nessas ocasiões. (violando assim o SoC). Poderiam criar um Serviço que a aplicação chame. O Serviço esta para a camada de aplicação como o repositorio para a de persistencia, portanto deveria funcionar. O problema é criar um serviço de dominio que faz coisas de infra.

Mas , supondo que responder a save não é um problema de infra e sim de dominio, é o hook que fica meio complicado de escolher. Ambos (aplicação e dominio) irão provocar save de entidades.

algumas aproximações a considerar:

  1. Se persistir provoca acontecimentos no dominio, a persistencia em si ( não o local ou a tecnologia ) fazem parte do dominio. Neste caso o façade pode ser criado como a única interface para ler e escrever dados.
  2. Um mecanismo de chain of responsability semelhante aos filtros de sevlet (conhecido como o padrão Interceptor) pode ser usado para injetar “triggers”. O objeto de persistencia irá chamar os interceptores em ordem e so no fim persistir realmente. Desta forma os dados podem ser manipualdos e novos dados podem ser adicionados à persistencia. è como se novos dados se adicionassem ao dado original no seu caminho para a persistencia.
  3. Um mecanismo de listeners e eventos pode ser criado para o objeto de persistencia. Objetos interessados podem responser aos eventos. Os eventos podem ser consumidos por vários objetos.

Se é um requisito de negócio deve ser representado no modelo de dominio, repositorios não expressam o modelo de dominio. Qual o benefício em esconder algo que é importante pro negócio em um mecanismo puramente de acesso?

Repositorios e factories não são como entities, value objects e services e não é à toa que eles possuem um capítulo a parte no livro.

A regra geral é simples, se for regra de negócio deve ser expresso no modelo de dominio.

Meu repositório atuando no domínio, que é sua camada, pode inclusive pertencer a modelagem natural, tudo depende da situação.

Eu tenho uma conversa fluente como especialista de negócio dizendo que ao armazenar determinado dado, um determinado evento acontece. Inclusive desenhando um repositorio de dados e ligando um conjunto de dados (de uma entidade) a ela é totalmente entendível nas reunioes.

Não existe regra simples, existe situações simples e complexas. Qual estratégia tomar, depende da contextualização do meio.

É o mesmo exemplo que tem no livro só que com generics no lugar de casts.

Perguntas:

  • como você faz para ter uma consulta personalizada parametrizável? Todas as vendas entre 1/2 e 2/3 de 98 feitas por senhoras com mais de 90 anos.

Este tipo de coisa não é geralmente possível com um Data Mapper genérico.

Eu costumo resolver de três formas:

1 - Usando QueryObjects
2 - Usando metadados (named queries e etc) nos objetos de negócio
3 Criar um framework de consultas genérico (talvez backed por Criteria API), montar as consultas com abstrações de negócio e mapear para consultas reais.

A opção 1 não segue sua idéia, é a mesma coisa que falei anteriormente.
A opção (2), além de não se alicar em sistemas sem um ORM poderoso, inclui metadados de persistência nos objetos de negócio e apesar do valor prático ser interessante não deixa de ser quebra de Camadas.
A opção (3) provavelmente é a melhor para mantêr, mas depende da infra-estrutura disponível -EJB ainda não tem criteria, creio.

Eu prefiro a opção (1) em geral porque eu prefiro inverter a dependência de Camadas do que depender tanto da inra-estrutura, mas a verdade é que os meanismos de ORM modernos tiraram boa parte da funcionalidade do DAO.

Eu diria que se seu teu domínio tem algo que dispensa um repositório provavelmente ele tem outro nome. Repository é um padrão criado para rpeencher um buraco na maioria dos domínios, que dificilmente possuem um conceito bem estruturado sobre para onde vão e de onde vêm as instâncias.

Eu não falei que Repositório não contêm regras, o que eu falei é que diicilmente o domínio vai exigir regras no repositório -simplesmente porque Repositório é uma abstração artifical.

Isso é regra de persistência, não de negócio. Para o negócio uma conta é o resultado das operações, o fato de que trazer todas as operações para a memória é custoso e por isso elas não estão disponíveis de graça (diferente de dados mais simples como nome do titular da conta) Não é regra de negócio.

Esse é um exemplo razoável, mas eu faria isso num Service que processaria qualquer regra necessária e passaria para o Repositório para persistência.

O meu dominío não tem algo que dispensa o repositório, na realidade o pensamento é o inverso, meu domínio conhece o repositório (o que é natural para um Data Model). Note que conhecer o repositório não fere camada alguma (não me refiro em momento algum a abstração de persistência) e dá mais sentido ao negócio.

Não é infra, nem o especialista e nem o time esta dando detalhes como o objeto será persistido, mas todos estão tratando que invariavelmente uma ação deve ocorrer no momento que o sistema preservar o estado de determinado objeto.

De fato, quem esta abstraindo a infra é uma Strategy membro do repositório e a QueryObject, e não a implementação do repositório em sí. Por isso, um conceito estruturado de onde vão e de onde vem as instancias, continuam abstraídos.

Somado a isso, como tentei exemplificar, em determinados casos um próprio armazenamento de dados pode ser de interesse ao negócio e transparente para o Domain Especialist. Não foi apenas uma vez que eu ouvi casos como : SEMPRE SEMPRE SEMPRE que guardar esse conjunto de dados, a tarefa “X” deve ser executada. Um Service realizando tal requisito poderia servir, mas atribuir a ele um “adicionar(objetoDeNegocio)”, apenas para satisfazer a consciência de alguns desenvolvedores, parece mais distante do cliente e perigoso no decorrer do desenvolvimento da aplicação. Se um desenvolvedor resolve comumente adicionar o objeto diretamente pelo repositorio (o que não seria difícil de acontecer e gramaticamente faz sentido), a aplicação não vai se comportar conforme esperado. Isso poderia ser evitado sem grande esforço, sem fugir do domínio e sem sair do universo proposto pelos Stakeholders.

Reforçando, não são simples regras de persistências, são relevantes para o domínio e este as conhecem. Mas concordo que estas são algumas situações, que talvez não se aplique a qualquer projeto, mas que não raramente acontecem.

Qual livro? E se não for pedir muito, a página… :smiley:

[quote=pcalcado]
Perguntas:

  • como você faz para ter uma consulta personalizada parametrizável? Todas as vendas entre 1/2 e 2/3 de 98 feitas por senhoras com mais de 90 anos.

Este tipo de coisa não é geralmente possível com um Data Mapper genérico.

Eu costumo resolver de três formas:

1 - Usando QueryObjects
2 - Usando metadados (named queries e etc) nos objetos de negócio
3 Criar um framework de consultas genérico (talvez backed por Criteria API), montar as consultas com abstrações de negócio e mapear para consultas reais.

A opção 1 não segue sua idéia, é a mesma coisa que falei anteriormente.
A opção (2), além de não se alicar em sistemas sem um ORM poderoso, inclui metadados de persistência nos objetos de negócio e apesar do valor prático ser interessante não deixa de ser quebra de Camadas.
A opção (3) provavelmente é a melhor para mantêr, mas depende da infra-estrutura disponível -EJB ainda não tem criteria, creio.

Eu prefiro a opção (1) em geral porque eu prefiro inverter a dependência de Camadas do que depender tanto da inra-estrutura, mas a verdade é que os meanismos de ORM modernos tiraram boa parte da funcionalidade do DAO.[/quote]

Eu uso specifications. Há limites no nivel de personalizacao obtido mas tem atendido minhas necessidades.

Isso eu acho muito improvável!

[quote=Lezinho]
Um Service realizando tal requisito poderia servir, mas atribuir a ele um “adicionar(objetoDeNegocio)”… …parece mais distante do cliente e perigoso no decorrer do desenvolvimento da aplicação. Se um desenvolvedor resolve comumente adicionar o objeto diretamente pelo repositorio (o que não seria difícil de acontecer e gramaticamente faz sentido)[/quote]

Você tocou na questão chave, a nomenclatura!

Você nao vai criar um metodo no service dessa maneira porque ele nao expressa na UBIQUITOUS LANGUAGE o tal evento de interesse do negocio.

Bem que eu tbm gostaria de achar improvável, mas não fui eu que defini o caso de uso, foi o usuário, e os termos foram os dele e não os meus.

… eu não tenho outro nome para uma regra que o usuário definiu para persistir os dados. A segunda ação esta definida tbm, inclusive poderia esta em uma real entidade do negócio, mas quem a executa é o repositorio no momento da inserção. E olha, se um argumento, que não seja simplesmente “você nao pode fazer isso, simplesmente pq não pode”, fizer sentido… eu não exitaria de acatá-lo.

Eu sei como é esse tipo de gente…

DDD, Não sei a página porque estou quotando do Safari:

[quot]Typically teams add a framework to the infrastructure layer to support the implementation of REPOSITORIES. In addition to the collaboration with the lower level infrastructure components, the REPOSITORY superclass might implement some basic queries, especially when a flexible query is being implemented. Unfortunately, with a type system such as Java’s, this approach would force you to type returned objects as “Object,” leaving the client to cast them to the REPOSITORY’S contained type. But of course, this will have to be done with queries that return collections anyway in Java.
[/quote]

[quote=cmoscoso]
Eu uso specifications. Há limites no nivel de personalizacao obtido mas tem atendido minhas necessidades.[/quote]

A única maneira que eu vejo de usar specifications no meu exemplo (e é o que uso) é no caso (1) com a dupla QuryObject/Specification, que é uma aplicação do tipo (1). Se você fizer isso ainda cria uma dependencia entre os query objects e o domínio, caindo no mesmo problema do DAO vs Repository, então acho que não deve ser isso.

Como você faz exatamente? Retorna todos os objetos e aplica uma Specicication como se fosse um Visitor?

[quote=Lezinho]O meu dominío não tem algo que dispensa o repositório, na realidade o pensamento é o inverso, meu domínio conhece o repositório (o que é natural para um Data Model). Note que conhecer o repositório não fere camada alguma (não me refiro em momento algum a abstração de persistência) e dá mais sentido ao negócio.

Não é infra, nem o especialista e nem o time esta dando detalhes como o objeto será persistido, mas todos estão tratando que invariavelmente uma ação deve ocorrer no momento que o sistema preservar o estado de determinado objeto.
[…]
Somado a isso, como tentei exemplificar, em determinados casos um próprio armazenamento de dados pode ser de interesse ao negócio e transparente para o Domain Especialist. Não foi apenas uma vez que eu ouvi casos como : SEMPRE SEMPRE SEMPRE que guardar esse conjunto de dados, a tarefa “X” deve ser executada. Um Service realizando tal requisito poderia servir, mas atribuir a ele um “adicionar(objetoDeNegocio)”, apenas para satisfazer a consciência de alguns desenvolvedores, parece mais distante do cliente e perigoso no decorrer do desenvolvimento da aplicação. Se um desenvolvedor resolve comumente adicionar o objeto diretamente pelo repositorio (o que não seria difícil de acontecer e gramaticamente faz sentido), a aplicação não vai se comportar conforme esperado. Isso poderia ser evitado sem grande esforço, sem fugir do domínio e sem sair do universo proposto pelos Stakeholders.
[/quote]

Eu acho que você está confundindo persistência com worflow /troca de estados.

Para Orientação a Objetos em si não existe persistência, o fato que um objeto deve ser persistido em um SGBD ou o que for é uma limitação. Um objeto não precisa ser pasado para ser salvo pelo repositório para estar ‘vivo’. Na verdade, o Repositório idealmente apenas serve para pesquisar, não para salvar objetos. O fato de que o objeto tem que ser salvo em algum onto explícito -se você não usar uma Unit of Work da vida- é uma deformação do modelo.

Se seu usuário mencionou ‘salvar’ provavelmente ele está com o vocabulário poluído com termos técnicos, porque ele está acostumado a fazer isso (da mesma forma um editor de texto pede que você salve o documento quando precisar porque ele não pode mantêr todas as versões e salvar a cada alteração) , mas no final das contas isso vira uma regra de negócio e deve ser implementado como qualquer outra regra. O que ele quer dizer é que quando o bojeto atingir o estado ‘salvo’ tal coisa deve acontecer, não quando o objeto for persistido (i.e. salvo em uma tabela relacional).

No seu exemlo acima eu considero SALVO como o estado que um objeto atinge. Pode ser que seja necessário um Service para "executar a tarefa X"mas acho que na maioria dos casos ela pode ficar como Observer do objeto em questão.

[quote=Lezinho]
(…)não me refiro em momento algum a abstração de persistência(…)[/quote]

… como você pode notar Shoes, eu nãO estou me referindo a persistência, nem especifiquei que o usuário se referiu a ela. A história do usuário implica que toda vez (se e somente se) determinada entidade estiver “pronta” (tipada em “guardar determinados dados”) execute a tarefa X.

Sim, isto pode ser classficado como estado do objeto, mas não muda o problema. Como também mencionei, o fato do user case exigir esta dependecia durante a “ação de manter” o estado da entidade, atribuir isso a um Service pode vir dar problemas, como escrevi no post anterior:

… ja o Observer pode ser mais interessante. Contudo, registrar o listener no Repository pode ser tão intrusivo quanto realizar nele a chamada para execução da tarefa “X”, como descrevi:

Quem mantém o estado é o repository, não vejo como garantir o comportamento requerido sem que ele invoque alguma regra do domínio para este caso, mesmo caracterizando ele como um Event do Observer. Talvez eu não tenha enxergado ainda uma implementação do Observer que possa ajudar neste caso… você pode dar uma dica?

PS: Insisto neste assunto pq já implementei isso em Service e realmente não fiquei satisfeito, justamente pelos problemas que explanei.