[quote=sergiotaborda][quote=MarkKnopfler]Estou surpreso, perplexo e maravilhado. O que eu li agora foi realmente algo muito embasado, no qual eu nem havia parado para pensar. Fica aqui meus cumprimentos.
Aprendi trocentas coisas:
- que estava usando DAO de uma maneira mecânica
- que essa forma “consagrada” viola princípios FUNDAMENTAIS
- que tenho que investir mais em livros em INGLÊS, porque em praticamente TUDO que se lê por aí em português, temos DAO’s que simplesmente criam os Criterias e delegam o trabalho pesado para o framework de ORM. Bem, isto seria na verdade um repositório sendo chamado de DAO, não seria? Claro, um repositório meio acoplado (acoplado e meio) com a infraestrutura do framework, e nada coeso (pois assume também as tarefas de incluir/atualizar/excluir), mas que por dentro a única coisa que faz é definir critérios de pesquisa (o resto delega para o ORM).
Cito este post: http://blog.aspercom.com.br/2009/08/11/repositorios-ddd/
É outro blog que gosto muito de ler. Queria saber a opinião do Sérgio sobre o que o cara diz ali. Para mim parece que se encaixa. Será?[/quote]
1.A mania de usar interfaces
Ora, imaginemos que o repositorio não é uma interfaces. É apenas uma classe normal implementada normalmente. O que ela teria ?
public class RepositorioProduto {
private QueryInterpreter interpreter;
public Repositorio (QueryInterpreter interpreter){
this.interpreter = interpreter;
}
public List<Produto> findDisponiveis(){
QueryObject query = new QueryObject();
query.add(new FieldCriteria("disponivel", Operator.Equals, true);
return interpreter.execute(query);
}
}
Dois componentes vitais do repositorio são o QueryObject (mais conhecido como Criteria, mas o nome do padrão é QueryObject) e o Interpeter que é um padrão associado ao queryObject que realmente executa a pesquisa.
O trabalho do repositório é apenas construir estes QueryObject. O exemplo que coloquei ali é trivial, mas a pesquisa pode ser arbitrariamente complexa.
Para injetar dependências se usa o construtor ou métodos set. A interface é irrelevante para este processo de injeção. A testabilidade é obviamente simples pois a necessidade de mock é nula.
Se ha algo a mocar é o interpretador não o repositório.
Porque o repositório precisaria de várias implementações ? Apenas se vc tiver dois ou mais conjuntos de regras para fazer as pesquisas. Mas isto faz sentido ? É como dizer que existem duas formas de pesquisar produtos disponíveis. Não faz sentido.
Mesmo que haja a necessidade de mudar a query porque o modelo mudou ou o negocio mudou Essa alteração é imediata e se reflete imediatamente no sistema. Não existe essa de “vamos fazer a regra hoje e amanhã não”.
O problema, como sempre, é que se confunde a implementação do repositorio com a implementação do DAO mesmo quando se diz que o repositorio e o dao são conceptualmente diferentes. Se são conceptualmente diferentes porque raios têm o mesmo tipo de implementação. Se vc for ver no livro do Eric Evans em nenhum momento o repositorio aparece como interface+implementação. Na realidade é ao contrário. Ele sempre aparece como uma classe concreta que tem uma dependência de uma interface ( que é o interpreter, mas o fowler chama de strategy e outros chamam de datamapper)
- Os nomes
A ideia de ter um repositorio de PedidosFaturados e ou outro de TodosOsPedidos é correta pois o Repositorio além de ser um objeto do dominio, ele é associado a Agregados. Agregados são entidades especiais que agregam em si muita informação na forma de composição (agregação) com outras entidades. Isto serve para provar que o repositorio não é um DAO, pois o Dao existe apenas para aquilo que é persistido.
Sobre a diferença entre “Repository” e “Repositorio” não vejo o ponto. É como dizer que Estratégia não é uma boa tradução de Strategy. Alguns nomes são dificies de traduzir , por exemplo Singleton, mas repository não é um deles. O que é um repositorio ? O dicionário responde : Lugar onde se deposita ou guarda alguma coisa. Bem adquado, quanto a mim. Então qual o problema de usar Repositorio no nome da classe ? Para mim nenhum. As pessoas têm usado DAO e Service no nome desde sempre. Alguns até usam BO (Business Object) e até mesmo Entity (ProdutoEntity, em vez de Produto). nomes são nomes. Sim, existem formas mais simples e padronizadas, mas discutir de o repositorio deve ou não ter “Repositorio” no nome é uma questão abaixo de secundária. O principal é se o conceito é entendido.
3.O repositorio como objecto inteligente do dominio
De fato o repositório não serve apenas para criar queries. Isso é o fim do seu trabalho. O repositório pode realizar decisões (ifs) baseado nos parâmetros de pesquisa e/ou em parâmetros do sistema e de configuração. O ponto é que no fim de todas as decisões o resultado será uma instrução de pesquisa que será executada no interpretador.
- Preciso procurar tudo usando repositórios ?
A ideia do artigo é que coisas simples como listas que alimentam combos não precisa. O objeto pesquisador ( seja um action ou alguém na ui etc… ) poderia acessar diretamente o local onde estão os dados. O entitymanager ou o hibernate, etc…
O ponto aqui é entender que :“qualquer instrução de pesquisa é uma regra de negócio”. Este é o conceito básico que dá origem ao repositório. É por isso que a criação da instrução de pesquisa é isolada e desacoplada. É isso que o repositorio + queryobject+interpreter fazem. Então, se eu tenho uma simples pesquisa de estados isso é uma regra de negocio ? Afinal os estados são fixos (mentira, a lista muda no tempo) porque eu preciso de um repositório ? A moral é : não é fixo. Vai mudar. Não hoje, não amanhã, mas é passível de mudar. Caso mude é bom que esteja desacoplado. às vezes existem filtros que limitam os estados (conforme alguma regra de negocio, por exemplo, a empresa não trabalha com aqueles estados e por isso eles não aparecem, mas à media que a empresa cresce mais estados são adicionados - o mesmo ao contrário quando a empresa deixa de estar presente numa região). Portanto, em termos de design desacoplar nunca é um problema. Na prática dá um pouco mais de trabalho, mas não é tanto assim que vai impedir de usar. Fora que usando o Repositório e o Interpreter para uma entidade X qualquer o código já vai ficar desacoplado do EntityManager de qualquer jeito para o X, então porque não usar para o resto ?
E porque a organização de repositorios não necessáriamente é 1 para 1 com as entidades fica mais facil de agrupar as coisas e deixar o código limpo.
Por outro lado, pensemos o que significa deixar a camada de cima (action, ui, etc…) acessar o entityManager. O EntityManager está em qual camada ? Na de domínio ? Teoricamente sim, mas na prática não, porque é um objeto do application server. Ou seja, embora ele seja um DomainStore, vc ainda pode se preocupar com o fato de um dia, outro objeto ocupar esse lugar ( o session do hibernate, por exemplo, ou alguma API nova do futuro). Então o EntityManager deveria ser injetado na implementação do DomainStore da sua aplicação e não ser o DomainStore em si. Do ponto de vista de um bom design é isso. Mas nem sempre as pessoas querem seguir um bom design e preferem cortar caminho (cut corners).
Usar o entitymanager diretamente no repositório no papel de interpreter é possível e funciona, usado Criteria API para o papel de QueryObject. Seja com session ou seja com jpa é a mesma coisa porque esses frameworks ja implementam as peças necessárias. Então qual é o problema ? Acoplamento. O seu codigo de negocio está acoplado à tenologia. Se a tecnologia precisar mudar ( por exemplo, hibernate=> jpa 1 => jpa 2) será um inferno reescrever todas as regras outra vez. Desacoplando isso não será necessário.
Mas quem gosta de desacoplar ? Muito poucos. A desculpa é sempre a mesma “isso não vai mudar”. Se podemos ter certeza de algo é que sim vai mudar. Só não sabemos quando.
A historia mostra que vários sistema são abandonados porque o trabalho para os ajustar a novas tenologias é maior que fazer de novo. Isto é ótimo para quem faz software , mas não é ético. Ao fazer um novo software as regras de negocio já implementadas se perdem. Novos levantamentos são necessários. E eles sempre são incompletos. O ideal seria manter o core do sistema velho ( que é a camada de domínio) e alterar a tenologia em volta dele. Por isso que o desacoplamento é tão importante na camada de domínio e por isso que o Repositório existe. Caso contrário deixaríamos a UI executar as pesquisas no entitManager e pronto.
Como opinião geral e não em relação ao artigo em si, o que se vê é que as pessoas comprar a ideia que o repositório é diferente do DAO mas têm problemas em saber exatamente em quê e como eles são diferentes. O que leva a coisas estranhas como
E não é apenas o autor desse blog que incorre neste problema de “eu sei que é diferente, mas chamo a mesma coisa”. Para mim isso significa que não se sabe realmente poque é diferente.Ou seja, comprou-se a ideia do padrão, mas não se entende qual é o principio que lhe dá origem. todos os padrões nascem de princípios como o DRY ou o SRP por exemplo. O Repositório nasce do principio que todas a queries são regras de domínio. Se aceitamos isto como verdade e por consequência aceitamos o repositório como padrão válido e utíl, então não podemos violar esse principio depois quer na implementação do padrão ou dizendo que “às vezes não precisamos do repositório” pois seria equivalente a dizer que “nem todas as queries são regras de domínio” o que contraria o principio que aceitámos.
É tudo uma questão lógica. O objetivo do padrão é bem claro. O resto é aplicação de principio de SRP que leva ao desacoplamento e ao uso de outros padrões. Mas parece que as pessoas pararam no tempo e só conseguem ver uma forma de implementar tudo : interface+implementação . Esse é o padrão Service, e serve para muitas coisas, mas não para todas.
Que fique bem claro que qualquer critica que fiz aqui é em relação aos conceitos errados e não às pessoas que os divulgam.[/quote]
Ótimos post, muitas informações conceitos aprendidos de muita importância…
sergiotaborda contribuiu muito com nosso conhecimento, obrigado!!