Creio que você esteja se referindo a esse trecho:
Se for, nem me esforçando consigo ver referencia a camadas nao-empilhadas.
Creio que você esteja se referindo a esse trecho:
Se for, nem me esforçando consigo ver referencia a camadas nao-empilhadas.
[quote=cmoscoso]Creio que você esteja se referindo a esse trecho:
Se for, nem me esforçando consigo ver referencia a camadas nao-empilhadas.[/quote]
Pode ser problema do idioma.
Vamos lá:
[quote=POEAA, pagina 17]
When thinking of a system in terms of layers, you imagine the principal subsystems in
the software arranged in some form of layer cake, where each layer rests upon a lower
layer. [/quote]
Quando você pensa nas Camadas de um sistema você imagina os principais subsistemas dispostas em Camadas, como num bolo onde as Camadas superiores icam em cima das inferiores.
Neste esquema as Camadas superiores usam os serviços das inferiores, mas as inferiores não estão cientes das superiores.
Então a Camada geralmente esconde suas inferiores de suas superiores
Nem todas as arquiteturas de Camadas são opacas como estas, mas a maioria é[…]
Não pra mim e acho que pra você também não, considerando a sua traducao…
Vejamos (assumindo que a definicao de “opaco” seja de conhecimento do leitor):
Geralmente a camada 4 nao esta ciente da camada 2, portanto a camada 3 é opaca.
Nem sempre camadas são opacas, em algumas situacoes a camada 4 pode acessar a camada 2 diretamente, ou seja, a camada 3 é transparente.
Acho que o problema então é o conceito de empilhar. Eu usei o termo pela primeira vez em 2005-2006 e sinceramente não sei de onde tirei, acho que do Buschmann mas não estou com o livro em mãos. Todas as outras referências que tenho sequer falam em stacks -exceto pelo Larman que cita network stacks como exemplo de Camadas opacas/empilhadas.
Para mim você empilha Camadas quando faz uma depender da imediatamente inferior. Uma pilha de Camadas é composta de Camadas opacas. É o mesmo conceito da estrutura de dados, você não consegue ver o próximo item e não tirar o que está em cima dele.
Nem todas as Camadas são empilhadas porque (1)você pode ter Camadas não-relacionadas na sua alicação que estao em paralelo (e.g. distribuição, persistência, segurança…) e (2) porque as Camadas não precisam obedecer um protocolo de comunicação. Eu posso ter a Camada do topo falando com a de baixo, qual o sentido de falar nisso como uma pilha?
“Pilha de camadas” ou “camadas empilhadas” é redundante. Precisa nomenclatura melhor para o que reside no mesmo nivel.
[quote=DDD, pagina 69]
The metaphor of layering is so widely used that it feels intuitive to most
developers. Many good discussions of layering are available in the literature, sometimes in the
format of a pattern (as in Buschmann et al. 1996, pp. 31?51). The essential principle is that any
element of a layer depends only on other elements in the same layer or on elements of the layers
"beneath" it.[/quote]
Não entendi o que você quis dizer. Para mim pilha de camadas e camadas empilhadas eh a mesma coisa. Como pode-se ver pelo trecho que você citou o Evans discorda do Fowler e do Larman -e eu discordo dele-, qual o ponto?
O ponto é que eu discordo de você…
[quote=Utilizando UML e Padrões, pagina 274]
Uma arquitetura multicamadas pode ser caracterizada como composta de camadas e/ou partições… As camadas de uma arquitetura representam os elementos dispostos ao longo da vertical, enquanto que as partições representam uma divisão horizontal de subsistemas, relativamente paralelos, de uma camada…
As camadas, na maioria das arquiteturas multicamadas orientadas a objetos, não estão acopladas no mesmo sentido limitado de um protocolo de redes baseado no Modelo OSI de 7-Camadas… é mais comum que a arquitetura seja uma arquitetura de camadas “relaxada” ou uma arquitetura de camadas “transparente” [Buschmann], na qual os elementos de uma camada se comunicam com diversas outras camadas.[/quote]
E concordo com Evans, Fowler e Larman!
Eu acho que ou eu não entendi anda que você falou ou você está com problemas para interpretar os textos.
Eric Evans só fala do modelo opaco/empilhado/strict.
Você mesmo já clou o trecho onde Fowler fala que as camadas geralmente são empilhadas/opacas/strict mas que isso não é uma obrigação, então convido a reler o texto e talvez explicar o que você entendeu dele.
Quanto à Larman, o trecho que você mesmo colou te contradiz:
Ou seja: para Larman e Fowler Camadas não recisam ser empilhadas/opacas/strict. Para Evans elas precisam, ams ele não dá soluçòes para os problemas que surgem num modelo empilhado/strict/opaco.
Logo voc6e pode concordar com a dupla ou com o Evans, não com os três.
“…any element of a layer depends only on other elements in the same layer or on elements of the layers beneath it.” - Evans falando de camadas transparentes.
[quote=pcalcado]
Você mesmo já clou o trecho onde Fowler fala… …então convido a explicar o que você entendeu dele.[/quote]
“é mais comum que a arquitetura seja uma arquitetura de camadas “relaxada” ou uma arquitetura de camadas “transparente” [Buschmann], na qual os elementos de uma camada se comunicam com diversas outras camadas.” - Larman falando de camadas transparente.
Portanto, todos falam de camadas como camadas de um bolo, dispostas verticalmente (Larman ainda sugere outro nome para organizacao horizontal) sendo transparente no sentido de permitir que a camada do topo acesse diretamente a primeira ou opaca, quando a camada comunica apenas com a camada imediatamente inferior, sem ser atravessada.
Você está certo quanto ao Evans -eu não vi que o próprio diagrama mostra acamadas transparentes- mas isso e o próprio trecho do Larman que você repetiu pela terceira vez apenas volta para meu ponto inicial:
Como você mesmo provou todos os três autores citados nesta thread concordam com isso. A menos que ocê esteja confundindo empilhamento com disposição eu não entendo como você poderia discordar disso. Vou colar a mensagem onde eu defini empilhamento:
[quote=pcalcado]Acho que o problema então é o conceito de empilhar. Eu usei o termo pela primeira vez em 2005-2006 e sinceramente não sei de onde tirei, acho que do Buschmann mas não estou com o livro em mãos. Todas as outras referências que tenho sequer falam em stacks -exceto pelo Larman que cita network stacks como exemplo de Camadas opacas/empilhadas.
Para mim você empilha Camadas quando faz uma depender da imediatamente inferior. Uma pilha de Camadas é composta de Camadas opacas. É o mesmo conceito da estrutura de dados, você não consegue ver o próximo item e não tirar o que está em cima dele.
Nem todas as Camadas são empilhadas porque (1)você pode ter Camadas não-relacionadas na sua alicação que estao em paralelo (e.g. distribuição, persistência, segurança…) e (2) porque as Camadas não precisam obedecer um protocolo de comunicação. Eu posso ter a Camada do topo falando com a de baixo, qual o sentido de falar nisso como uma pilha?[/quote]
Voltando à analogia da pilha numa estratéia de camadas empilhadas a camada N só acessa N-1. N-1 acessa N-2 e por aí vai. Numa estratégia transparente você não tem e ssa limitação, N pode acessar qualquer outra Camada diretamente.
Entao concordamos que camadas estao sempre dispostas verticalmente?
Sim e não.
Sim na teoria, não no problem original: negócios depende da persistência e persistência depende do negocio. Em Java eu não sei como resoler este problema sem quebrar Camadas (e sem usar DTOs).
Eu falei da dificuldade aqui:
E a minha solucao:
[quote=cmoscoso] Eu já desencanei do isolamento total faz tempo… eu gosto de ter a camada de insfraestrutura independente. Pra isso eu crio um modulo de infraestrutura de persistencia, e geralmente ele reside no namespace do dominio. É a tal área cinzenta que havia dito.
E DIP é lei, mas estou falando de camadas e camadas…[/quote]
A implementação do repositório pertence à infraestrutura, e não ao domínio. O domínio só conhece a interface; a implementação é injetada de alguma forma na camada de negócios (containers DI, factories, aspectos, etc). Se a implementação do repositório contém X métodos a mais que a abstração, a camada de negócios não sabe nem que esses X métodos existem.[/quote]
A implementação do repositorio pertence ao dominio e não à infra. A implementação do repositorio pode comunicar-se com a infra se for necessário. A implementação do repositório depende do dominio porque é necessário conhecer a organização do objetos de dominio para responder às pesquisas. Imagine que o seu dominio
usa informações que vê de um WebService. Não ha DAO nem banco. O WebService retorna informações na forma de objetos proprios do WS. E a pesquisa é feita com informações própria do WebService.
O Repositoriotem que traduzir os objetos que chegam do WS para objetos do dominio e as pesquisas do dominio para as pesquisas do WebService. Ele só pode fazer isto se conhecer o dominio.
O repositorio não é construido seguindo o padrão Bridge (ou seja, uma interface + uma implementação) Ele é uma classe. E mais do que isso, ele é um membro de primeira classe na camada de dominio. A sua ideia de que o dominio conhece a interface não se aplica. Nem ha necessidade de injeção uma vez que todas as classes do dominio pertecem juntas. Em muitos casos truques como métodos de visibilidade de pacote são necessários num dominio rico. Isso cai se houve desacoplamento.
Veja bem, todas as classes são do dominio, elas estão acopladas por esse fim : o dominio. Não faz sentido desacopla-las ( seja como DI ou qq outro mecanismo)
[quote=sergiotaborda]A implementação do repositorio pertence ao dominio e não à infra. A implementação do repositorio pode comunicar-se com a infra se for necessário. A implementação do repositório depende do dominio porque é necessário conhecer a organização do objetos de dominio para responder às pesquisas. Imagine que o seu dominio
usa informações que vê de um WebService. Não ha DAO nem banco. O WebService retorna informações na forma de objetos proprios do WS. E a pesquisa é feita com informações própria do WebService.
O Repositoriotem que traduzir os objetos que chegam do WS para objetos do dominio e as pesquisas do dominio para as pesquisas do WebService. Ele só pode fazer isto se conhecer o dominio.
O repositorio não é construido seguindo o padrão Bridge (ou seja, uma interface + uma implementação) Ele é uma classe. E mais do que isso, ele é um membro de primeira classe na camada de dominio. A sua ideia de que o dominio conhece a interface não se aplica. Nem ha necessidade de injeção uma vez que todas as classes do dominio pertecem juntas. Em muitos casos truques como métodos de visibilidade de pacote são necessários num dominio rico. Isso cai se houve desacoplamento.
Veja bem, todas as classes são do dominio, elas estão acopladas por esse fim : o dominio. Não faz sentido desacopla-las ( seja como DI ou qq outro mecanismo)[/quote]
Mas a forma como eu imagino a utilização de um repositório ( foi a forma que eu entendi, claro que posso estar errado ) é a seguinte ( bastante simplificado ):
public interface ClienteRepositorio {
// Métodos para manutenção de objetos de domínio
}
public class ClienteDAO implements ClienteRepositorio {
// Implementação dos métodos de ClienteRepositorio
// Outros métodos implementados pelo DAO
}
Nesse exemplo, todas as classes que usam repositórios ( Services, por exemplo ) possuem declarados em seu corpo atributos do tipo Repositorio, mas os DAOs são injetados de alguma forma no domínio sem que essa camada os conheça.
Assim, você tem ClienteRepositorio pertencendo ao domínio e ClienteDAO pertencendo à infraestrutura.
Mais uma coisa Sérgio, no seu artigo sobre repositórios você fala que o repositório depende diretamente da estratégia de mapeamento. Mais uma vez, posso estar errado, mas eu não penso assim. O repositório deve abstrair o domínio de todos esses detalhes, que pertencem à infra-estrutura. Se você quiser manter um mapeamento em memória, deve criar um MemoryDAO, e não um MemoryRepository. Você sugeriu o padrão Strategy pra resolver esse problema, mas eu não consigo conceber um repositório sem implementar Strategy.
É o velho problema. Se vc enxerga repository=dao não tenho mais nada a dizer.
Caso contrário, o esquema é o seguinte.
Application — > DAO
Application — > DomainService & Entitys --> Repository --> DAO
O DAO não pode ser acessado pelo dominio. Isto é o que queremos evitar. Se não quer evitar isso, a conversa é futil.
O DAO pode ser acessado directamente da aplicação. Por exemplo: listagens. Um Fastlane enviado pelo DAO é sempre mais eficiente que qq outra coisa no meio. Pesquisas não são logica de negocio. É algo automático, a camada de aplicação (AL) pode cuidar disso sozinha. Contudo, quanto ha um processo qualquer envolvido a AL não pode delegar ao DAO. Ai ela delega a algum Façade/Proxy do dominio. Em algum ponto os serviços precisa conhecer outras entidades existentes. (Por exemplo, quando faz um trasnferencia bancária vc passa duas contas
e um valor, mas vc precisa dos saldos. Os saldos são a soma de da entidade Lançamento. então vc precisa enviar uma pesquisa para o dominio - não para o banco - que lhe retorne todos os lançamentos das duas contas.
E depois soma para ver se pode fazer a transação. Obviamente na prática vc precisa de mecanismo eficazes de fazer isso, mas conceptualmente - do ponto de vista do serviço - é isso que vc está fazendo, e é só isso que interessa)
Vc pode usar o QueryObject (aka Criteria) do seu DAO para fazer a pesquisa, mas isso pula um nivel. Vc não pode user Criteria do DAO no Dominio (layer leak). Então o que vc faz ? Vc isola o dominio com o repositorio.
Vc cria um objeto de qeury proprio do dominio ( sei lá : LancamentosContaQuery pex) e envia ao repositorio.
O repositorio cria o criteria com base no query recebido e enviar ao DAO. Agora, o DAO é maepador de tecnologias e ele NAO É generico. Um dao usando hibernate use criteria para queries, mas um jdbc puro usa sql. etc… Ou seja, o objeto de pesquisa do DAO depende do DAO. A menos que vc use um DomainStore+QueryObject genericos a pesquisa do DAO não e´feita da mesma forma.
Repare que o obtivo principal não é isolar update/insert/delete mas sim o select ( o R de CRUD).
Bom, então vc pode ter um DAO+SQL , um DAO+Criteria, o proprio Hibernate puro + Criteria ( que é um domain store) um EntityManager+SQL , etc… não é só o dao que está em causa é o proprio objeto/forma de pesquisa.
É por isso que vc precisa de várias estratégias. Mas vc só precisa delas se vc pensa em mudar no futuro. Se vc garante que vai usar sempre DAO+SQL (mesmo que o DAO seja implementado via hibernate ou entitymanager etc… ) vc não precisa de estratégias de repositorio.
O strategy é um padrão simples de implementar depois. Ou seja, vc começa com um repositorio que conversa com DAO+SQL. No futuro vc descobre que é melhor DAO+Criteria, vc não apaga o codigo que tem e escreve ouro. Vc passa o codigo do DAO+SQL para uma estratégia e escreve outra para DAO+Criteria. Ha um timing para aplicar o padrão strategy. Eu estou falando dele para mostrar porquê é necessário pensar em termos de strategy.
O repositorio ele mesmo não é uma estratégia. Quantas formas diferentes e simultanear de traduzir o LancamentosContaQuery existem ? Uma só. É a tradução disso para a tecnologia da API de persistencia que muda. quando vc descobrir uma forma mais eficiente de tradução vc apaga a velha. não cria uma estratégia para a velha ( vc nunca a usaria de novo).
Não sei se ficou claro
Domain --------------------------- Repository ---------------------------------------------- DAO
(DomainQuery) ---- > Traduz para linguagem especifica do DAO —> executa e retorna. (é burro)
Se o DAO executa na memoria ou no banco não interessa ao repository. O que interessa é se as queries são feitas do mesmo jeito. uma query em memoria (Filtro) não é passada como no banco (SQL)
P.S: LancamentosContaQuery pode ser encarado como Specification ou QueryObject depende de implementação do repositorio
Definitivamente, não. Não sei nem de onde você inferiu isso.
[quote=sergiotaborda]Caso contrário, o esquema é o seguinte.
Application — > DAO
Application — > DomainService & Entitys --> Repository --> DAO
O DAO não pode ser acessado pelo dominio. Isto é o que queremos evitar. Se não quer evitar isso, a conversa é futil.[/quote]
Não quero necessariamente evitar isso. Eu fico satisfeito se o domínio “pensar” que tá acessando um repositório, apesar de estarmos injetando uma implementação do mesmo - um DAO ou qualquer outra estratégia de persistência.
[quote=sergiotaborda]O DAO pode ser acessado directamente da aplicação. Por exemplo: listagens. Um Fastlane enviado pelo DAO é sempre mais eficiente que qq outra coisa no meio. Pesquisas não são logica de negocio. É algo automático, a camada de aplicação (AL) pode cuidar disso sozinha. Contudo, quanto ha um processo qualquer envolvido a AL não pode delegar ao DAO. Ai ela delega a algum Façade/Proxy do dominio. Em algum ponto os serviços precisa conhecer outras entidades existentes. (Por exemplo, quando faz um trasnferencia bancária vc passa duas contas
e um valor, mas vc precisa dos saldos. Os saldos são a soma de da entidade Lançamento. então vc precisa enviar uma pesquisa para o dominio - não para o banco - que lhe retorne todos os lançamentos das duas contas.
E depois soma para ver se pode fazer a transação. Obviamente na prática vc precisa de mecanismo eficazes de fazer isso, mas conceptualmente - do ponto de vista do serviço - é isso que vc está fazendo, e é só isso que interessa)
Vc pode usar o QueryObject (aka Criteria) do seu DAO para fazer a pesquisa, mas isso pula um nivel. Vc não pode user Criteria do DAO no Dominio (layer leak). Então o que vc faz ? Vc isola o dominio com o repositorio.[/quote]
Entendo perfeitamente. E o código que postei também é capaz de isolar isso do domínio, uma vez que os objetos Criteria são utilizados somente dentro das implementações ( nesse caso, DAOs ). O que o domínio conhece - através da interface Repositorio - são métodos específicos, como listarClientesInadimplentes(). O DAO que se vire pra retornar esses objetos.
[quote=sergiotaborda]Vc cria um objeto de qeury proprio do dominio ( sei lá : LancamentosContaQuery pex) e envia ao repositorio.
O repositorio cria o criteria com base no query recebido e enviar ao DAO. Agora, o DAO é maepador de tecnologias e ele NAO É generico. Um dao usando hibernate use criteria para queries, mas um jdbc puro usa sql. etc… Ou seja, o objeto de pesquisa do DAO depende do DAO. A menos que vc use um DomainStore+QueryObject genericos a pesquisa do DAO não e´feita da mesma forma. [/quote]
Isso não é retrabalho? Recriar um mecanismo de busca para o domínio? Além disso, o repositório terá que ter referências a detalhes específicos da tecnologia de persistência empregada. Aqui, por exemplo, é preciso importar para o repositório o pacote que contém a classe Criteria do Hibernate ou JPA.
[quote=sergiotaborda]Repare que o obtivo principal não é isolar update/insert/delete mas sim o select ( o R de CRUD).
Bom, então vc pode ter um DAO+SQL , um DAO+Criteria, o proprio Hibernate puro + Criteria ( que é um domain store) um EntityManager+SQL , etc… não é só o dao que está em causa é o proprio objeto/forma de pesquisa.
É por isso que vc precisa de várias estratégias. Mas vc só precisa delas se vc pensa em mudar no futuro. Se vc garante que vai usar sempre DAO+SQL (mesmo que o DAO seja implementado via hibernate ou entitymanager etc… ) vc não precisa de estratégias de repositorio.
O strategy é um padrão simples de implementar depois. Ou seja, vc começa com um repositorio que conversa com DAO+SQL. No futuro vc descobre que é melhor DAO+Criteria, vc não apaga o codigo que tem e escreve ouro. Vc passa o codigo do DAO+SQL para uma estratégia e escreve outra para DAO+Criteria. Ha um timing para aplicar o padrão strategy. Eu estou falando dele para mostrar porquê é necessário pensar em termos de strategy.[/quote]
Mas você não vê que está trazendo para a camada de domínio detalhes específicos de infra-estrutura? Um repositório de uma entidade específica deve ser um só, e não ter uma versão para cada método de persistência. Essas estratégias a gente passa pro DAO.
Entendi. Mas isso eu costumo fazer na camada de persistência, e não na de domínio, conforme expliquei anteriormente.
[quote=sergiotaborda]Não sei se ficou claro
Domain --------------------------- Repository ---------------------------------------------- DAO
(DomainQuery) ---- > Traduz para linguagem especifica do DAO —> executa e retorna. (é burro)
Se o DAO executa na memoria ou no banco não interessa ao repository. O que interessa é se as queries são feitas do mesmo jeito. uma query em memoria (Filtro) não é passada como no banco (SQL)
P.S: LancamentosContaQuery pode ser encarado como Specification ou QueryObject depende de implementação do repositorio[/quote]
A abordagem que eu mencionei anteriormente isola igualmente o domínio desses detalhes. Você teria MemoryDAO, XMLDAO, LapisEPapelDAO… Só seria necessário configurar o mecanismo de injeção para injetar um ou outro.
Primeiro que tudo, esqueçamos injeção. DI não tem que ser automático.
O ponto não é esse. Use qualquer objeto e vc pode injetá-lo onde quiser. Não é um problema.
Bom, então esqueça o Repositorio. Vc não precisa dele.
[quote=tnaires]
Não é questão se pode. Obviamene pode. A questão é como fazer direito.
Vc pode usar o DAO para isolar. Ok. Mas ai seu DAO não é generico.
Vc gosta de DAO generico ? Eu gosto. Por isso não coloco logicas nele e uso QueryObject.
Se vc não gosta/precisa de um DAO generico, esqueça o Repositorio.
Não ha nehum mal nisso.
O que estou tentando evitar é que vc pense que DAO e Repositorio são a mesma coisa.
Dao é reaproveitável e depende apenas da tecnologia de prevalencia/persistencia.
Repositorio não é reaproveitável e depende do dominio e do DAO.
Vc escreve métodos getClientesAtivos() no DAO em vez de escrever
Query q = Query.newQuery(Cliente.class).add(Restriction.eq("activo", true));
Dao dao
dao.execute(q)
Ok. Nada contra.
Repositorio so se aplica se vc usa a segunda forma.
A primeira forma tem problemas de design (não reutilização do dao em outros dominios, etc…) mas se isso não o desagrada , otimo. Continue usando.
Não é retrabalho se é necessário. E vc não está implementando mecanismo de busca. apenas tradução de queries. O repositorio não tem detalhes da persistencia. Ele usa a interface do DAO ( que por definição isola as tecnologias de persistencia). Criteria do Hibernate não é um detalhes de persistencia, é uma API do hibernate.
Sim, vc tem que importar, e dai ? Esse é o ponto. Vc isola o dominio usando o repositorio como mediador.
Qual é a vantagem ? Polimorfismo.
Se vc tem 10 serviços que controem 1000 Criteria e enviam ao DAO (contruido com hibernate) , na hora que vc quiser reaproveitar esses serviços com XML vc tem que criar outras 1000 criteria e enviar oa DAO XML.
Injetar o DAO não o inibe de ficar dependente da interface do DAO. E se o DAO só aceita Criteria, ou so aceita SQL ou so aceita XPath vc fica agarrado a isso. É isso que não queremos ao usar Repositorio.
Com repositorio vc tem 1000 queries. E ao mudar para XML vc re-escreve 0 queries.
O seu sistema faz mais select ou insert/update/delete ? Na hora de mudar , o que se ferra mais ?
[quote=cmoscoso]
[quote=cmoscoso] Eu já desencanei do isolamento total faz tempo… eu gosto de ter a camada de insfraestrutura independente. Pra isso eu crio um modulo de infraestrutura de persistencia, e geralmente ele reside no namespace do dominio. É a tal área cinzenta que havia dito.
E DIP é lei, mas estou falando de camadas e camadas…[/quote][/quote]
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.