DAO's nas classes de negócio

Vamos considerar a busca do melhor “design possivel”(se é que isso é possivel)

Não

Não

Não

Não

Minha visão…
O Action, deve pegar os dados da fonte(web, swing) e repassar pra alguem… Se usarmos DDD, o action poderia conversar com uma fachada que manipularia os objetos de negocio (é claro que com as regras desses objetos dentro deles mesmos)

Actions deveriam ser “burros” e apenas fazer validações de dados(não de negócios) conversões e formatações

Existe um livro muito legal que da uma passada em algumas “opções” de design chamado POJOs in Action

É um livro teorico/pratico e tem vários exemplos de código… recomendo (Mas ele é um pouco superficial)

É claro que dependendo da situação, fazer um action acessar um DAO não é nenhuma heresia… não vou dizer que nunca fiz isso…

Eu tb tenho feito a coisa assim… Meu erro foi ter chamado essa classe que recebe os dados da action de JobManager, o que passa a idéia errada da coisa. Melhor seria JobLogic, JobSession, JobWork, etc. (alguém teria um nome melhor?)

Me restou a seguinte dúvida:

A action deve passar os dados para um JobWork desses da vida ou deve passar direto para um objeto Job de forma que o job saiba se virar para carregar tudo que ele precisa e fazer as operações no banco.

se virar = possuir dentro dele uma instância de JobRepository ou JobDAO de forma que ele possa se auto-carregar, e carregar outras dependencias que ele venha a ter.

O impasse aqui é que usando um JobWork, meu objetos podem ter uma tendencia de ser apenas envelope de dados… mas acho que uma coisa não tem nada haver com a outra, ou seja, usar um JobWork da vida não significa que meus objetos serão anêmicos…

[quote=saoj][quote]
O Action, deve pegar os dados da fonte(web, swing) e repassar pra alguem… Se usarmos DDD, o action poderia conversar com uma fachada que manipularia os objetos de negocio (é claro que com as regras desses objetos dentro deles mesmos)
[/quote]

Eu tb tenho feito a coisa assim… Meu erro foi ter chamado essa classe de JobManager, o que passa a idéia errada da coisa. Melhor seria JobLogic, JobSession, JobWork, etc. (alguém teria um nome melhor?)

[/quote]

*Service talvez

Ai que ta…
Fachadas ou não?
Eu usaria as fachadas… não acho legal os actions conhecerem os objetos de negocio. Pra mim actions devem fazer somente o que eu falei anteriormente…

Eu faria como no uml que estou postando em anexo

Problema com seu exemplo: Action não tem nada a ver com Repository. Action é MVC e MVC é Camada de Apresentação, estamos falando da integração entre negócios e Persistência.

[quote=saoj]Eu acho teoria importante, mas acho tb que um código/exemplo prático fala melhor do que 10 teorias:
[/quote]

Ponto interessante.

  1. Já foram citados neste artigo diversas documentações que possuem vários exemplos, alguém se deu ao trabalho de ler pelo menos alguma?

  2. Um exemplo, vinte exemplos,t rinta exemplos não conseguem explicar todos os casos, então não, ele não vale mais que 10 descrições de uma teoria (ou exemplo e teoria são antagônicos?)

Na boa, Sérgio, leia a documentação, depois poste aqui. Fica muito repetitivo ter a mesma pergunta feita de 30 maneiras diferentes e por mais que tentemos provavelmente não seremos tão claros quanto as pessoas que criaram ou catalogaram estas práticas. Fica difícil debater as idéias do Domain-Driven Design sem saber o que é Domain-Driven Design.

Segundo este pensamento dá na mesma fazer Action chamar DAO, ou nem ter DAO, afinal dá tudo na mesma. Ou melhoir: pra que interfaces? Use logo as implementações, dá na mesma.

Não, não dá. Se vale a pena usar no caso X ou não é outro assunto, mas pela enésima vez: DAO pode ser a implementação de repositório, repositório não precisa ser implementado por um DAO.

Sinceramente não entendo esse tipo de colocação, Phillip. Todos aqui estão trocando idéias e debatendo com educação, e acredito que eu e todo mundo aprendemos bastante com o tópico. Vc tb estava contribuindo bastante e de repente vêm com essa de “Na boa, Sérgio, leia a documentação para o tópico não ficar repetitivo”, como se o foco negativo desse post estivesse em mim. É lamentável esse tipo de postura… É um comportamento no mínimo indelicado, para economizar nos adjetivos…

Pode dar a entender que vc está mais preocupado comigo do que com o tópico em si.

Bom, agradeço a todos que contribuiram e debateram, principalmente ao Fábio Kung e ao FelipeC… Aprendi bastante e agora mesmo estou refatorando meu sistema para melhor aplicar esses conceitos.

Ok, vou estudar mais. Me desculpe por vc ter perdido o seu precioso tempo discutindo com pessoas que não sabem o que é DDD.

[quote=felipec]Fachadas ou não?
Eu usaria as fachadas… não acho legal os actions conhecerem os objetos de negocio. Pra mim actions devem fazer somente o que eu falei anteriormente…[/quote]
Eu não vejo problema que as actions conheça os objetos de negócio. As minhas actions conhecem minhas classes de repositório e minhas classes de serviço.

Uma dúvida, no seu diagrama o que você chama de fachada? O TransferService?

[]'s

Rodrigo Auler

[quote=pcalcado]Problema com seu exemplo: Action não tem nada a ver com Repository. Action é MVC e MVC é Camada de Apresentação, estamos falando da integração entre negócios e Persistência.

[quote=saoj]Eu acho teoria importante, mas acho tb que um código/exemplo prático fala melhor do que 10 teorias:
[/quote]

Ponto interessante.

  1. Já foram citados neste artigo diversas documentações que possuem vários exemplos, alguém se deu ao trabalho de ler pelo menos alguma?

  2. Um exemplo, vinte exemplos,t rinta exemplos não conseguem explicar todos os casos, então não, ele não vale mais que 10 descrições de uma teoria (ou exemplo e teoria são antagônicos?)

Na boa, Sérgio, leia a documentação, depois poste aqui. Fica muito repetitivo ter a mesma pergunta feita de 30 maneiras diferentes e por mais que tentemos provavelmente não seremos tão claros quanto as pessoas que criaram ou catalogaram estas práticas. Fica difícil debater as idéias do Domain-Driven Design sem saber o que é Domain-Driven Design.

Segundo este pensamento dá na mesma fazer Action chamar DAO, ou nem ter DAO, afinal dá tudo na mesma. Ou melhoir: pra que interfaces? Use logo as implementações, dá na mesma.

Não, não dá. Se vale a pena usar no caso X ou não é outro assunto, mas pela enésima vez: DAO pode ser a implementação de repositório, repositório não precisa ser implementado por um DAO.[/quote]

Philip, às vezes para abstrair alguns conceitos, precisamos no mínimo de alguns exemplos tangíveis, para ver sua aplicação.

Acho válida a argumentação do Sérgio.

Fica complicado apenas citar Patterns e dar link para os mesmos , pois alguns conseguem abstrair outros não e tais exemplos, ajudariam reforçar o entendimento e até mesmo corrígi-los, pois alguns podem entender algo que na prática é diferente.

Já vi vários tópicos seus, com grande auxílio, mas falta o tal do exemplo tangível e acredito que para muitos, a referência acaba ficando confusa e seu empenho foi em vão.

Parece que ficou no ar alguma duvida sobre DAO X Repository e que Repository pode ser / implementar um DAO (Data Access Object)
Repository (Repository) é onde as entidades estão. Não onde os “dados brutos” estão , mas os objectos de negocio. A entidade Cliente tem quantas instâncias ? Onde elas estão ? no repository. Como uma entidade encontra as entidades que lhe cabem ? Por exemplo , como um pedido encontra seus itens ? Pelo repositório. Claro que os itens são injetados no pedido, mas como ?


Pedido p  = Repository.get ( Pedido.class, 14 ); // 14 é a chave

O Repositório internamente identifica que Pedido tem um associação com PedidoItem e automaticamente faz (internamente)


Pedido p  =  new Pedido(14);

p.setItens (Repository.get ( PedidoItem.class, p));

Ou poderia injetar uma implementação de Collection, que fizesse lazy loading


Pedido p  =  new Pedido(14);

p.setItens ( new LazyList( this,  PedidoItem.class, p));

Que depois faria o codigo de cima quando alguém consultasse a lista.

Por outro lado, o repositório está associado ao dominio. Um DAO está associado aos dados brutos e à tecnologia paras os acessar (Data Access Object)
Mas como o repositório preenche os dados das instâncias ?
Ele tem que usar um DAO. Porque? Porque os dados não estão em objetos na memória. Mesmo que estejam, provavelmente não estão na mesma forma em que o domínio os quer. O comum é estarem no banco de dados, mas poderiam estar no mecanismo prevalente, ou numa simples List ( por exemplo em ambiente de teste)
O repository isola a instancia do dominio do local onde as outras instancias estão , o DAO isola o repositorio de saber onde os dados estão.
Veêm a diferença ? Um trabalha com instancias do dominio, o outro com dados brutos.

O DAO isola também o mecanismo de procura. Para bancos ele usa SQL, mas para list provávelmente usa um filtro. O repository apenas passa ao DAO “o quê ele quer” e não o “como encontrar”. O mesmo para os objectos de negocio que pedem o que querem e não dizem ao repository como encontrar.

Mas isto é a camada de negocios. Como seria na camada de visualização.
Se eu quiser listar todos os pedidos num table num html tenho que passar pelo repository ? Não. Basta usar o DAO. Não ha logica de negocios aqui. Apenas transferência de dados brutos.

O repositório é a forma como as instancias das entidades de negocio se comunicam e se encontram (repositório : onde todo o mundo está)
O dao é a forma como um repositório especifico executa esse trabalho.
Poderíamos ter repositório sem dao. Um exemplo classico é que o repositório seja um grafo gigante em que a raiz é um objeto anônimo que contém todas as coleções de todas as entidades de negocio que cotêm todas as referencias aos objetos que necessitam. Isso seria OO puro, mas isso não é tecnologicamente viável. Somos obrigados a guardar os dados de forma mastigada , e para isso que serve o DAO.

A interface de um DAO e de um Repository são muito semelhantes, mas elas não significam a mesma coisa. Não se pode pedir a um repository que encontre um objeto com base numa frase SQL, a um DatabaseDao, pode.
Mas a um InMemoryListDao não pode. Ou seja, a comunicação da intensão tb tem que ser abstraida de forma que o programador/objecto de negocio diga “o que quer” e "não como quer"
Claro que isto pode ser muito complicado, e, no caso geral serei obrigado a escrever o SQL na mão. Isto viola o encapsulamento que estou construindo com os DAO e os Repository. Isso nunca é bom. Claro, podem dizer que 99,99% dos casos usam banco de dados e que portanto usar SQL é tranquilo (quem diz SQL , diz EQL, HQL ,etc…) Mas , na verdade , é uma violação sim.
Quando no futuro , a tecnologia de persistência for outra, e o SQL não for mais a forma de procurar pela informação danou. Vai ter que haver outro software. Não se fizermos as coisas como deve ser. A lógica de negocio não depende do banco. Ela sempre será a mesma. Então se a tecnologia muda para outra coisa - digamos XQuery como exemplo - so teria que escrever um XQueryDAO. Mas e para as SQL que tive que escrever na mao ?

Para essas é criado um DAO especial que contém as SQL sofisticadas e retorna os dados. Ou seja, eu não passo o SQL , ele já está lá dentro. O repositório traduz isso para a camada de negocio. A camada de negocio não sabe que existem dois DAO no repositório. Mas ele sabe que DAO chamar dependendo da pergunta que lhe foi feita pelas classes de negocio. Se a tecnologia mudar eu crio um DAO com as consultas XQuery dentro dele e o repositório nunca saberá a diferença.

São duas responsabilidades diferentes. Ser o ponto de encontro das instancias das entidades - Repository, ou ser o cara que garimpa os dados avulsos que constituem essas entidades - DAO.


Alguem falou que um DAO generico seria algo como

Dao<T , I>{

T find (I id)
}

Na realidade o DAO mais genérico é

Dao {
<T> T find (Class<T> entity , Object id);
}

Que é o que o EntityManager do EJB 3 usa , embora ele seja um Repository e não um DAO.

[quote=pcalcado]
Segundo este pensamento dá na mesma fazer Action chamar DAO, ou nem ter DAO, afinal dá tudo na mesma. Ou melhoir: pra que interfaces? Use logo as implementações, dá na mesma.

Não, não dá. Se vale a pena usar no caso X ou não é outro assunto, mas pela enésima vez: DAO pode ser a implementação de repositório, repositório não precisa ser implementado por um DAO.[/quote]

Peraí cara.

Eu digo que dá na mesma pois você mesmo disse que a unica diferença entre uma interface UserDAO e UserRepository é o nome! Por isso da na mesma, das duas maneiras eu abstraio o código de persistência da minha lógica de negócios. Só o nome da interface vai ser diferente.

Não tem nada haver com a ACtion chamar o DAO ou nem mesmo ter o DAO, pois nisso há o grave problema de uma clara violação de camadas.

Pessoal,

Muito boa a discussão. Tenho uma pequena dúvida. Imagine uma classe do dominio do problema. Esta classe (um POJO com atributos e métodos de negócio) não é uma classe “gerenciada” por um container IOC correto (ex: Spring)? Então imagine que necessito de fazer algo do tipo:

DomainObject domainObject = new DomainObject();
domainObject.setAttribute1("A");
domainObject.setAttribute2("A");
//... N atributos
domainObject.businessMethod();

E que meu metodo businessMethod precise de uma referência do repositorio para realizar a logica usando tb os atributos preenchidos anteriormente. A pergunta é: como o objeto que implementa o repositório pode ser injetado/atribuido visto que a classe DomainObject não é uma classe gerenciada.
Já pensei em três maneiras:

  • AOP: no new eu faria essas injeções. Não sei me parece um overkill… Acho que alguém me disse que o Rod Johnson faz assim… BTW, não gosto muito pois o código não fica muito evidente… mas é uma alternativa
  • usar uma Factory ao invés de fazer o new, onde terei oportunidade de injetar os repositórios. Muito manual, um objeto “artificial” à mais, eu sei… Mas é a alternativa que mais me atrai…
  • recuperar o repositorio antes e atribui-lo como mais um atributo da minha classe (ARGH!).

Existem mais maneiras? Qual é a mais recomendada? Como vocês estão fazendo isso hoje?

Desde já agradeço a atenção!

[quote=duardor]E que meu metodo businessMethod precise de uma referência do repositorio para realizar a logica usando tb os atributos preenchidos anteriormente. A pergunta é: como o objeto que implementa o repositório pode ser injetado/atribuido visto que a classe DomainObject não é uma classe gerenciada.
Já pensei em três maneiras:

  • AOP: no new eu faria essas injeções. Não sei me parece um overkill… Acho que alguém me disse que o Rod Johnson faz assim… BTW, não gosto muito pois o código não fica muito evidente… mas é uma alternativa
  • usar uma Factory ao invés de fazer o new, onde terei oportunidade de injetar os repositórios. Muito manual, um objeto “artificial” à mais, eu sei… Mas é a alternativa que mais me atrai…
  • recuperar o repositorio antes e atribui-lo como mais um atributo da minha classe (ARGH!).[/quote]
    Nos meus repositórios eu tenho um método create que já recebe os dados mínimos que o objeto precisa pra ter um estado válido e já injeta as dependências, ou seja, é proibido dar new nos objetos do domain, como uma factory mesmo. E pros objetos vindo do banco pelo hibernate eu uso um interceptor do hibernate que usa o Spring pra injetar as dependências byName.

[]'s

Rodrigo Auler

Ótima questão! Estava pensando comigo mesmo se mais ninguém se perguntava sobre isso…

Eu ia responder aqui, mas achei melhor blogar a respeito: http://blog.caelum.com.br/2007/06/09/repository-seu-modelo-mais-orientado-a-objeto/.

(tá, tá… eu também sou contra ficar linkando para blog no fórum. Mas nesse caso não teve como!)

Ok, eu me exedi e peço desculpas.

Frequentemente trabalhamos exemplos com pessoas aqui quando elas estão com dificuldades em aplicar conceitos, mas quando eles estão com dificuldades em entender conceitos geralmente é melhor ler sobre o tal conceito antes de perguntar. Como falei antes um exemplo não vai mostrar o que o conceito representa, do contrário não haveriam livros com seus capítulos cheios de exemplos e textos.

Tudo que foi pedido consta na bibliografia -e boa parte disponível online gratuitamente- mas a impressão que tenho é que se acha que é eficaz inferir informação baseado em meia dúzia de postagens num fórum sem conhecer a base da discussão e sem nem querer conhecer.

Existe uma tendência em todas as áreas de se esconder atrás de ‘pragmatismo’ para não ler e pesquisar mas ainda assim dar opiniões sobre as coisas que não conhecem.

Eu disse isso? Onde?

[quote=microfilo]
Por isso da na mesma, das duas maneiras eu abstraio o código de persistência da minha lógica de negócios. Só o nome da interface vai ser diferente.

Não tem nada haver com a ACtion chamar o DAO ou nem mesmo ter o DAO, pois nisso há o grave problema de uma clara violação de camadas.[/quote]

Não, o que eu venho falando aqui há alguns posts é que objetos de negócio lidam com Repository, não com DAO. O DAO pdoe ser a real implementação do Repository -ou não- mas apra o objeto de negócios é um Repository, não um DAO que ele nem sabe do que se trata.

Da mesma maneira, se um método receber java.util.List Para ele é uma lista. Se for na verdade um trabolho mega-complexo que guarda os elementos em bases de dados distribuídas não improta, é uma lista. Um Repository não rpecisa ser uma interface, o ponto aqui é a abstração entre List–&gtListamegaDistribuida e Repository-&gtDAO.

Acho que conseguimos simplificar este problema apra: como fazer quando um objeto requer outro para funcionar, não?

Bom, temos 2 questões aí. Primeiro, a relação entre os objetos (Usuario–>RepositoryDao) pode ser parte da invariante do objeto Usuario. Neste caso quando o objeto for criado ele deve ser populado. Factory é normalmente a melhor alternativa para criar objetos complexos, Factories genéricas como o Spring podem ajudar (mas eu abstrairia seu uso).

Na segunda possibilidade temos a relação como pré-condição para a invocação do método. Ou seja: a relação não rpecisa existir, exceto ao se invocar o método que faz uso desta. Neste caso você poderia fazer um itnerceptor para popular a relação on-demand.

Tenho a impressão que esta última abordagem é overkill para a maioria dos problemas. Se você tem objetos com relações delicadas crie-o através de Factories.

Se ter uma Factory é um estorvo muito grande use um FactoryMethod. Poderia ser um método estático na classe, Ruby-like, mas cuidado para não criar elefantes brancos.

Se tivesse um ranking com as melhores discussões do GUJ, eu votaria nesta!

Primeiro, obrigado pelas respostas, este topico realmente têm me ajudado muito e me tendencionado a adotar DDD…
Fabio, muito instrutivo o seu post no teu blog.

[quote=pcalcado]
Se ter uma Factory é um estorvo muito grande use um FactoryMethod. Poderia ser um método estático na classe, Ruby-like, mas cuidado para não criar elefantes brancos.[/quote]
Gostei da idéia mais do que da própria Factory. Algo como Domain.create() ou Domain.getNew()…
Mas pcalcado, um método estático tiraria o repository de onde? Falando um pouco mais de implementação, por ex. usando Spring… O repository sendo um objeto “gerenciado” pelo Spring… Dá até pra fazer uns pequenos “arranjos” (entenda coisas não muito bonitas e não convencionais) para guardar em um atributo estático uma referência ao ApplicationContext e assim ter acesso aos objetos gerenciados pelo Spring… Deste modo o método estático teria acesso a esta referência e conseguiria “injetar” o repository em seu objeto… Mas como já disse não ia ficar muito bonito não… Incluiria fazer as classes do dominio implementar aquela ApplicationContextAware (ARGH!) do Spring…
Como você está implementando isso hoje em seus sistemas? Recomenda algo?

PS: Como o aviso por email tá fazendo falta!!!

Do post do Fabio Kung:

public class Repository {
  private final Session session;
  public Repository(Session session) {
    this.session = session;
  }
  
  public void get(Long id) {
    // poderia delegar para um dao, se fosse necessário
    Usuario u =  session.load(id);
    u.setRepository(this);
  }
}

O problema de injetar as dependências assim é quando se faz buscas. Se você faz uma busca que retorna 50 objetos como injetar essas dependências? Por isso que uso interceptor do Hibernate.

Não gosto de métodos estáticos. São ruins de testar. Faço os repositórios gerenciados pelo Spring e o create fica no repositório. Tenho tudo a mão pra criar meus objetos.

[]'s

Rodrigo Auler

Segundo alguns textos que li sobre DDD, os factories servem tanto para CRIAR objetos complexos quanto para RECONSTITUIR objetos (por exemplo, objetos carregados do repositório).

Então, seu repositório faz a query utilizando seja lá o que for (jpa, hibernate etc). Seu repositório também terá uma referência a um factory (relativo ao aggregate em questão) e o utilizará para recompor esses objetos antes de repassá-los para a aplicação.

Não não, o estático foi ilustrativo. Use métodos de instãncia com objetos gerenciados pelo Spring mesmo. Eu costumo fazer exatamente assim. Dificilmente existe um Entity (falando no jargão DDD) que seja criado manualmente, geralmente ele é criado por um Factory Method em um Service (outra vez DDD) que já cuida destas coisas.


Um Factory lida com lógica de inicialização complexa. O papel de uma Factory numa paltaforma como Java é agrantir que a invariante do objeto seja cumprida.

Como fatalmente o Repository (ou mesmo um Context Mapper ou algo do tipo) precisa criar novos objetos válidos e apra isso precisa verificar e garantir a invariante. Como esta lógia é da Factory é normal que o Repository utilize a Factory (não o contrário). Um Rpoeisotyr pode também abstrair funções do tipo “procure X, caso não encotnre crie um novo”.