Repositórios e Unit of Work

232 visualizações
Pular para a primeira mensagem não lida

Régis Soares

não lida,
5 de jul. de 2010, 17:30:2805/07/2010
para dotnetar...@googlegroups.com
Pessoal,
 
Vejo ultimamente muita gente falando de MVC com Repositórios e UOW aqui no DNA. Alguém pode me explicar o que querem dizer com isso?
 
Pois pelo que entendo, quando trabalhamos com NHibernate a Session é a UOW, e quando usamos o padrão Session per request, isso fica mais evidente. Ou seja, isso é transparente para quem está usando. Quando dizem "Repositórios e UOW" parece estar se tratando de algo diferente.
 
abs
Régis Soares

Alexandre Valente

não lida,
5 de jul. de 2010, 17:34:0105/07/2010
para dotnetar...@googlegroups.com
É um nome mais bonito pra exatamente isto! :-)

abs,

Alexandre Valente
MCSE+I, MCSD, MDCBA, ITIL, CSM

2010/7/5 Régis Soares <regis...@gmail.com>
--
Você recebeu esta mensagem porque faz parte do grupo .Net Architects hospedado no Google Groups.
Para postar envie uma mensagem para dotnetar...@googlegroups.com
Para sair do grupo envie uma mensagem para dotnetarchitec...@googlegroups.com
Para mais opções visite o grupo em http://groups.google.com/group/dotnetarchitects?hl=pt-br

Régis Soares

não lida,
5 de jul. de 2010, 17:37:3605/07/2010
para dotnetar...@googlegroups.com
Então é como dizem: "Para quê facilitar se a gente pode complicar?" rs
 
abs

2010/7/5 Alexandre Valente <alexandre...@gmail.com>

Alexandre Valente

não lida,
5 de jul. de 2010, 17:56:2905/07/2010
para dotnetar...@googlegroups.com
Rsrs...  a idéia de qualquer pattern é abstrair algo comum a várias cenários para facilitar o reuso do mesmo em outros.

Mas justamente o uso típico do UOW é um request web transacional. Mas sempre é bom saber com que estamos lidando né? Pode ser que o uso em outros cenários não seja tão óbvio :-)

Alessandro de Souza

não lida,
5 de jul. de 2010, 19:35:0105/07/2010
para dotnetar...@googlegroups.com
Amigos... aqui vale uma ressalva..
Se estivermos falando de DDD os repositórios devem ser abstraídos para que fique bem desacoplado com o domínio e o restante da aplicação. Ou seja: indiferente de qual tecnologia for usada para implementação dos repositórios concretos o domínio e o restante da aplicação devem funcionar da mesma forma.
Como os repositórios devem ser abstraídos o UOW também. Assim, indiferente de qual tecnologia for usada para a implantação concreta dos repositórios o UOW também deverá ser implementado para funcionar corretamente.
Em resumo o UOW deve ser abstraído para ser possível usá-lo tanto com o NH como o EF, EF4 ou qualquer outro ORM ou mesmo acesso direto, ADO.NET e assim vai....

Acho que é isto.....

Alexandre Valente

não lida,
5 de jul. de 2010, 20:40:1005/07/2010
para dotnetar...@googlegroups.com
Oi Alessandro,

Mais ou menos né? Se vc quiser fazer um UOW genérico, vc vai ter um custo que dificilmente se paga a não ser que vc troque de framework, o que é raríssimo. E o pattern é tão simples que refazer provavelmente é muito mais simples do que tentar fazer algo genérico.

Na minha experiência, quase a totalidade dos casos de NH se resolve com um SessionScope sendo criado per request e um transactionScope qdo necessário... Claro que com o ActiveRecord fica ainda mais simples... Assim não temos razões para complicar muito.... :-)

abs,

Alexandre Valente
MCSE+I, MCSD, MDCBA, ITIL, CSM

2010/7/5 Alessandro de Souza <alessandr...@gmail.com>

Rafael Noronha

não lida,
5 de jul. de 2010, 20:52:5005/07/2010
para .Net Architects
Alessandro,

Conto com sua visita ao meu blog:
http://rafanoronha.net/pt/abstraia-com-moderacao/

Abraços!

Ricardo Borges

não lida,
5 de jul. de 2010, 20:53:2805/07/2010
para dotnetar...@googlegroups.com
O padrão = http://martinfowler.com/eaaCatalog/unitOfWork.html

Eu entendo que o proprio NH implementa o Unit of Work pattern, uma vez que ele por default não dispara os comandos DML no momento da chamada, mas sim ao final da session.

Alguém sabe se o EF trabalha assim?
Ricardo Borges

Alessandro de Souza

não lida,
5 de jul. de 2010, 20:56:2505/07/2010
para dotnetar...@googlegroups.com
Oi Alexandre...
eu concordo com vc...
Só que o custo do que eu quiz dizer com um UOW genérico é muitissimo baixo... não passa de uma interface com uns 3 metodos apenas: IniciarTransação, FinalizarTransação e AbortarTransação.
Na classe concreta apenas usamos o session no caso do NH ou ObjectContext no caso do EF...
Baixo custo creio eu.....

Abraços...


Em 5 de julho de 2010 21:40, Alexandre Valente <alexandre...@gmail.com> escreveu:

Alessandro de Souza

não lida,
5 de jul. de 2010, 21:11:2705/07/2010
para dotnetar...@googlegroups.com
Oi Rafael...
fui ao seu blog... e... concordo com TUDO o que vc disse lá. Vc está coberto de razão...
Apenas no caso deste tópico aqui eu gostaria de me explicar.
Eu jamais criaria um UOW ou qualquer abstração sobre um ORM maduro como o NH ou EF.... nunca, isto é o mesmo que queimar dinheiro, sem dúvida.
O que eu quiz dizer em abstrair o UOW seria apenas criar uma interface com uns 3 métodos no máximo, conforme disse na outra resposta, para iniciar finalizar ou abortar a transação apenas para facilitar o teste e seguir a abstração dos repositórios... nada além disto...
Toda a implementação serie em cima do SESSION do NH mesmo... com certeza...

Deu pra entender?

Grato pelas dicas.....


Giovanni Bassi

não lida,
5 de jul. de 2010, 22:17:3605/07/2010
para dotnetar...@googlegroups.com
Se vc está trabalhando com DDD, um repositório atende uma raiz de agregração.
Nenhuma operação no domínio deve necessitar de atomicidade entre agregações. Portanto, UoW são desnecessárias. Se vc está precisando, há algo errado no seu desenho.

Eu já defendi o contrário.

Mas a gente aprende.

[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/5 Régis Soares <regis...@gmail.com>
--

Thiago Alves

não lida,
5 de jul. de 2010, 23:56:1905/07/2010
para dotnetar...@googlegroups.com
Caramba, Giovanni, eu nunca tinha olhado o conceito de UoW por esse ponto de vista do DDD.

Vou precisar de algum tempo pra processar essa sua afirmação e ver se concordo ou não :)
...Mas o raciocínio faz muito sentido.

Abraço,
Thiago Alves


2010/7/5 Giovanni Bassi <gig...@giggio.net>

Hamon Vitorino

não lida,
6 de jul. de 2010, 05:40:5206/07/2010
para dotnetar...@googlegroups.com
Giovanni, não sei se entendi bem o que você quis dizer com "Nenhuma operação no domínio deve necessitar de atomicidade entre agregações", mas se entendi, você está dizendo que só pode haver transações em operações que envolvem uma única agregação, é isso?
Se é isso, então como um serviço de ser portar na execução de operações que envolvem mais de uma agregação? Pois um serviço pode realizar operações entre várias agregações e, do meu ponto de vista, essas operações muitas vezes podem/devem ser executadas dentro de um contexto transacional.

[]'s
Hamon Vitorino
http://hamonvitorino.wordpress.com
http://zonadotnet.wordpress.com

Alessandro de Souza

não lida,
6 de jul. de 2010, 08:28:2306/07/2010
para dotnetar...@googlegroups.com
Fala Giggio....
estava esperando a sua opinião nesta.. hehehe....

Então, mais tem operações no sistema que vão precisar iterar com mais de uma agregação no domínio (ex: um serviço de cobrança pode negativar o cliente e mudar seu status - agregação cliente e agregação cobrança... apenas um exemplo), neste caso vc acha que devemos ter um novo repositório para atender este serviço tipo uma agragação de agregações??? (nossa falei besteira heim...)... é isto? Nunca li nada em DDD sobre isto....

Att,

Alessandro de Souza

não lida,
6 de jul. de 2010, 08:31:0106/07/2010
para dotnetar...@googlegroups.com
Outro detalhe Giggio:
já vi alguns exemplos seus onde vc injeta via constructor o Context no caso de EF ou o Session no caso do NH nos seus repositórios... Esta injeção não seria pensando em uma atomicidade?

Att,
Alessandro....

Em 5 de julho de 2010 23:17, Giovanni Bassi <gig...@giggio.net> escreveu:

Régis Soares

não lida,
6 de jul. de 2010, 10:25:1406/07/2010
para dotnetar...@googlegroups.com
Não entendi ainda qual a justificativa para usar tal abstração.
 
Tudo bem que criar um IHttpModule introduz uma dependência do NH na aplicação Web, pois o módulo deve conhecer a ISession. Mas mesmo assim acho tal dependência tão pequena que não justifica introduzir mais código (e mais complexidade) para removê-la.

Régis Soares

não lida,
6 de jul. de 2010, 10:29:2506/07/2010
para dotnetar...@googlegroups.com
Giovanni,
 
Não entendi muito bem sua colocação. Pode exemplificar melhor?

2010/7/5 Giovanni Bassi <gig...@giggio.net>

Alessandro de Souza

não lida,
6 de jul. de 2010, 10:37:3606/07/2010
para dotnetar...@googlegroups.com
Depois do comentário do Giovanni, que também estou aguardando uma melhor explicação (please Giggio)... foi tudo por terra.....
Mais a abstração seria em caso de compartilhar a mesma issession por vários repositórios.....

Régis Soares

não lida,
6 de jul. de 2010, 11:00:4906/07/2010
para dotnetar...@googlegroups.com
Para compartilhar a sessão por vários repositórios vc pode usar session per request ou conversação. Nos repositórios vc tem apenas NhHelper.GetCurrentSession().


 
2010/7/6 Alessandro de Souza <alessandr...@gmail.com>

tucaz

não lida,
6 de jul. de 2010, 11:14:0806/07/2010
para .Net Architects
Acredito que o Giovanni tenha feito essa colocação a respeito de
atomicidade ser por Root Aggregation, pois teoricamente quando
trabalhasse com um root aggregation todos os objetos que ele precisa
usar estão de alguma forma relacionados a ele. Dessa forma, utilizando
qualquer framework de ORM, quando você mandar persistir o root os
objetos associados e alterados de um jeito ou de outro vão ser
persistidos tb pelo ORM.

Exemplo: Pedido e Produto. Por mais que os dois sejam root
aggregations eles tem um relacionamento direto (Pedido contem produtos
e um Produto pode estar em pedidos). Dessa forma quando você altera os
dois e manda persistir um só, os dois vao acabar sendo persistidos.

Att.,
Tuca

On Jul 6, 12:00 pm, Régis Soares <regissoa...@gmail.com> wrote:
> Para compartilhar a sessão por vários repositórios vc pode usar session per
> request ou conversação. Nos repositórios vc tem apenas
> NhHelper.GetCurrentSession().
>
> 2010/7/6 Alessandro de Souza <alessandro.de.so...@gmail.com>
>
> > Depois do comentário do Giovanni, que também estou aguardando uma melhor
> > explicação (please Giggio)... foi tudo por terra.....
> > Mais a abstração seria em caso de compartilhar a mesma issession por vários
> > repositórios.....
>
> > Em 6 de julho de 2010 11:25, Régis Soares <regissoa...@gmail.com>escreveu:
>
> >  Não entendi ainda qual a justificativa para usar tal abstração.
>
> >> Tudo bem que criar um IHttpModule introduz uma dependência do NH na
> >> aplicação Web, pois o módulo deve conhecer a ISession. Mas mesmo assim acho
> >> tal dependência tão pequena que não justifica introduzir mais código (e mais
> >> complexidade) para removê-la.
>
> >>   2010/7/5 Alessandro de Souza <alessandro.de.so...@gmail.com>
>
> >>> Oi Alexandre...
> >>> eu concordo com vc...
> >>> Só que o custo do que eu quiz dizer com um UOW genérico é muitissimo
> >>> baixo... não passa de uma interface com uns 3 metodos apenas:
> >>> IniciarTransação, FinalizarTransação e AbortarTransação.
> >>> Na classe concreta apenas usamos o session no caso do NH ou ObjectContext
> >>> no caso do EF...
> >>> Baixo custo creio eu.....
>
> >>> Abraços...
>
> >>> Em 5 de julho de 2010 21:40, Alexandre Valente <
> >>> alexandre.g.vale...@gmail.com> escreveu:
>
> >>> Oi Alessandro,
>
> >>>> Mais ou menos né? Se vc quiser fazer um UOW genérico, vc vai ter um
> >>>> custo que dificilmente se paga a não ser que vc troque de framework, o que é
> >>>> raríssimo. E o pattern é tão simples que refazer provavelmente é muito mais
> >>>> simples do que tentar fazer algo genérico.
>
> >>>> Na minha experiência, quase a totalidade dos casos de NH se resolve com
> >>>> um SessionScope sendo criado per request e um transactionScope qdo
> >>>> necessário... Claro que com o ActiveRecord fica ainda mais simples... Assim
> >>>> não temos razões para complicar muito.... :-)
>
> >>>> abs,
>
> >>>> Alexandre Valente
> >>>> MCSE+I, MCSD, MDCBA, ITIL, CSM
> >>>> agvalente.wordpress.com
> >>>>www.whitefox.com.br<http://www.whitefox.com.br%20/>
>
> >>>> 2010/7/5 Alessandro de Souza <alessandro.de.so...@gmail.com>
>
> >>>> Amigos... aqui vale uma ressalva..
> >>>>> Se estivermos falando de DDD os repositórios devem ser abstraídos para
> >>>>> que fique bem desacoplado com o domínio e o restante da aplicação. Ou seja:
> >>>>> indiferente de qual tecnologia for usada para implementação dos repositórios
> >>>>> concretos o domínio e o restante da aplicação devem funcionar da mesma
> >>>>> forma.
> >>>>> Como os repositórios devem ser abstraídos o UOW também. Assim,
> >>>>> indiferente de qual tecnologia for usada para a implantação concreta dos
> >>>>> repositórios o UOW também deverá ser implementado para funcionar
> >>>>> corretamente.
> >>>>> Em resumo o UOW deve ser abstraído para ser possível usá-lo tanto com o
> >>>>> NH como o EF, EF4 ou qualquer outro ORM ou mesmo acesso direto,
> >>>>> ADO.NET <http://ado.net/> e assim vai....
>
> >>>>> Acho que é isto.....
>
> >>>>> Em 5 de julho de 2010 18:37, Régis Soares <regissoa...@gmail.com>escreveu:
>
> >>>>>  Então é como dizem: "Para quê facilitar se a gente pode complicar?"
> >>>>>> rs
>
> >>>>>> abs
>
> >>>>>> 2010/7/5 Alexandre Valente <alexandre.g.vale...@gmail.com>
>
> >>>>>> É um nome mais bonito pra exatamente isto! :-)
>
> >>>>>>> abs,
>
> >>>>>>> Alexandre Valente
> >>>>>>> MCSE+I, MCSD, MDCBA, ITIL, CSM
> >>>>>>> agvalente.wordpress.com
> >>>>>>>www.whitefox.com.br<http://www.whitefox.com.br%20/>
>
> >>>>>>> 2010/7/5 Régis Soares <regissoa...@gmail.com>
>
> >>>>>>>>   Pessoal,
>
> >>>>>>>> Vejo ultimamente muita gente falando de MVC com Repositórios e UOW
> >>>>>>>> aqui no DNA. Alguém pode me explicar o que querem dizer com isso?
>
> >>>>>>>> Pois pelo que entendo, quando trabalhamos com NHibernate a Session
> >>>>>>>> é a UOW, e quando usamos o padrão Session per request, isso fica mais
> >>>>>>>> evidente. Ou seja, isso é transparente para quem está usando. Quando dizem
> >>>>>>>> "Repositórios e UOW" parece estar se tratando de algo diferente.
>
> >>>>>>>> abs
> >>>>>>>> Régis Soares
>
> >>>>>>>> --
> >>>>>>>> Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> >>>>>>>> hospedado no Google Groups.
> >>>>>>>> Para postar envie uma mensagem para
> >>>>>>>> dotnetar...@googlegroups.com
> >>>>>>>> Para sair do grupo envie uma mensagem para
> >>>>>>>> dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>
> >>>>>>>> Para mais opções visite o grupo em
> >>>>>>>>http://groups.google.com/group/dotnetarchitects?hl=pt-br
>
> >>>>>>> --
> >>>>>>> Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> >>>>>>> hospedado no Google Groups.
> >>>>>>> Para postar envie uma mensagem para
> >>>>>>> dotnetar...@googlegroups.com
> >>>>>>> Para sair do grupo envie uma mensagem para
> >>>>>>> dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>
> >>>>>>> Para mais opções visite o grupo em
> >>>>>>>http://groups.google.com/group/dotnetarchitects?hl=pt-br
>
> >>>>>> --
> >>>>>> Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> >>>>>> hospedado no Google Groups.
> >>>>>> Para postar envie uma mensagem para dotnetar...@googlegroups.com
> >>>>>> Para sair do grupo envie uma mensagem para
> >>>>>> dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>
> >>>>>> Para mais opções visite o grupo em
> >>>>>>http://groups.google.com/group/dotnetarchitects?hl=pt-br
>
> >>>>> --
> >>>>> Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> >>>>> hospedado no Google Groups.
> >>>>> Para postar envie uma mensagem para dotnetar...@googlegroups.com
> >>>>> Para sair do grupo envie uma mensagem para
> >>>>> dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>
> >>>>> Para mais opções visite o grupo em
> >>>>>http://groups.google.com/group/dotnetarchitects?hl=pt-br
>
> >>>>   --
> >>>> Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> >>>> hospedado no Google Groups.
> >>>> Para postar envie uma mensagem para dotnetar...@googlegroups.com
> >>>> Para sair do grupo envie uma mensagem para
> >>>> dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>
> >>>> Para mais opções visite o grupo em
> >>>>http://groups.google.com/group/dotnetarchitects?hl=pt-br
>
> >>> --
> >>> Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> >>> hospedado no Google Groups.
> >>> Para postar envie uma mensagem para dotnetar...@googlegroups.com
> >>> Para sair do grupo envie uma mensagem para
> >>> dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>
> >>> Para mais opções visite o grupo em
> >>>http://groups.google.com/group/dotnetarchitects?hl=pt-br
>
> >> --
> >> Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> >> hospedado no Google Groups.
> >> Para postar envie uma mensagem para dotnetar...@googlegroups.com
> >> Para sair do grupo envie uma mensagem para
> >> dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>
> >> Para mais opções visite o grupo em
> >>http://groups.google.com/group/dotnetarchitects?hl=pt-br
>
> > --
> > Você recebeu esta mensagem porque faz parte do grupo .Net Architects
> > hospedado no Google Groups.
> > Para postar envie uma mensagem para dotnetar...@googlegroups.com
> > Para sair do grupo envie uma mensagem para
> > dotnetarchitec...@googlegroups.com<dotnetarchitects%2Bunsu...@googlegroups.com>

Alessandro de Souza

não lida,
6 de jul. de 2010, 12:15:2506/07/2010
para dotnetar...@googlegroups.com
Não é tão simple assim.
No método que está coordenando os repositórios (NO CASO DO MVC os CONTROLLERS por exemplo) você precisará abortar, por exemplo, uma transação quando houver um erro.
Isto não pode ser feito dentro de um único repositório quando há outros envolvidos na transação....
Ai neste caso o seu CONTROLLER tb deveria chamar o NhHelper.GetCurrentSession() e é ai que eu vejo uma mistura de responsabilidades... O Controller vai ter que saber como criar esta sessão e vai ter que referenciar todas as DLL´s do NH por exemplo. Não acho isto legal e vai contra alguns princípios estabelecidos para OO bem projetado.

É apenas minha opinião... não sou nenhum expert (como já deu pra perceber)...

Alessandro de Souza

não lida,
6 de jul. de 2010, 12:22:4906/07/2010
para dotnetar...@googlegroups.com
Desculpe TUCAZ... mais o Giovanni falou de modo geral:

"Nenhuma operação no domínio deve necessitar de atomicidade entre agregações"
Pelo que entendi, ele quiz dizer que em nenhum momento será necessário, nas operações de domínio, passar um UOW ou uma ISession (NH) entre repositórios. Se isto estiver acontecendo (e como ele disse que mudou de opinião sobre isto, então já deve ter feito assim antes) temos um problema no desenho das agregações do domínio.
Estou fazendo exercícios mentais para este cenário e até agora achei coerente (sou suspeito, pois sou fã do Giggio faz tempo). Apenas teremos que ter mais objetos específicos e relacionados para isto.. mais OO prega isto mesmo....

Mais, gostaria de uma explicação melhor sobre esta afirmação dele....

Giggio, agora que vc "bagunçou o coreto" aqui.. ajude a arrumar... hehehehe..  brincadeirinha.....

Att,
Alessandro....

Régis Soares

não lida,
6 de jul. de 2010, 12:50:5706/07/2010
para dotnetar...@googlegroups.com
Se vc usar o padrão Session Per Request todos os seus repositórios compartilharão uma única Session (que será obtida por GetCurrentSession()). O caminho mais natural para implementar esse padrão é definindo uma classe que implemente IHttpModule, nela vc faz o Rollback caso algo dê errado.
 
Essa questão que motivou o início dessa thread, pois quando mencionam UOW com repositório e bla bla bla parece se tratar de algo ultra-mega-complexo, quando na verdade é algo simples

Alessandro de Souza

não lida,
6 de jul. de 2010, 12:58:3006/07/2010
para dotnetar...@googlegroups.com
Você terial algum exemplo de como capturar um erro na IHttpModulo para dar o Rollback?

Régis Soares

não lida,
6 de jul. de 2010, 13:26:2706/07/2010
para dotnetar...@googlegroups.com

Alessandro de Souza

não lida,
6 de jul. de 2010, 15:08:3006/07/2010
para dotnetar...@googlegroups.com
Neste exemplo a simplicidade que vc disse foi por água abaixo.
Foi criado um wapper completo do NH no UOW.....
Achei exagerado.
Eu concordo com o IHPPTMODULE para controlar as transações, mais ainda não achei um jeito de controlar corretamente as transações sem que meu controller (asp.net mvc) participar nisto.
Só que não é nada complicado o que eu propus. Segue um exemplo didático (não olhe para a sintexe):

class uow_nh: Iuow {

_ISession = httpmodule.GetSession()

IniciarTransacao() { _ISession.BeginTransaction() }
FinalizarTransacao() { _ISession.Commit() }
AbortarTransacao() {_Isession.RollBack() }

}

Ai no meu CONTROLLER eu injeto este IWOW.

Não vejo trabalho algum nisto... Muito simples, abstrato e desacoplado, fácil para testar e meu controller não precisa conhecer o NH, apenas os repositórios abstratos e o IUOW do mesmo modo.

Concordam?

Giovanni Bassi

não lida,
6 de jul. de 2010, 18:01:3406/07/2010
para dotnetarchitects
Se as operações devem ser executadas num contexto transacional, então talvez elas façam parte da mesma agregação.

Por exemplo, imagine que eu liguei em uma empresa de tv a cabo, e quero comprar o pacote de programas, e nunca fui cliente deles. Nesse cenário, vc quer incluir um cliente novo e já incluir um pedido, apesar de essas entidades fazerem parte de agregações diferentes. Vc pode ter uma tela que tem o cliente e o pedido, que já faz as duas coisas. Só que é possível que o cliente possa ser incluido com sucesso, e um problema impeça a inclusão do pedido. Sua tela vai ter que tratar isso.

Mas não sou radical. Se por algum motivo você não quer trabalhar isso na tela, e entende que precisa então fazer as duas coisas ou nenhuma, estamos tratando de uma operação de domínio que é atômica além da agregação. Um serviço de domínio pode resolver isso.
Mas é um smell. Eu evitaria, e na tela exibiria algo como "cliente incluido, sistema de pedidos indisponível".

Sabe porque?

Porque pode ser que o repositório de clientes seja no seu SQL Server, mas o de pedidos seja no DB2, via batch, e a operação vai ficar numa fila até de noite. Não tem atomicidade nesse cenário.

UoW entre agregações assumem incorretamente que a tecnologia de persistência por trás dos repositórios é a mesma.

Sempre é bom lembrar do que significa um repositório no contexto do DDD. Os conceitos são a base de tudo.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/6 Hamon Vitorino <cham...@gmail.com>

Giovanni Bassi

não lida,
6 de jul. de 2010, 18:02:5806/07/2010
para dotnetarchitects
É como eu disse, se for o caso, talvez as duas entidades deste caso devessem participar da mesma agregação.

Lembrando que DDD não é só repositórios, entidades, serviços, etc. Lembrem-se da segunda metade do livro: contextos, etc...


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/6 Alessandro de Souza <alessandr...@gmail.com>
Fala Giggio....

Giovanni Bassi

não lida,
6 de jul. de 2010, 18:05:5606/07/2010
para dotnetarchitects
Não, é pra facilitar injeção de dependência.
E tenho trabalho diferente de vez em quando, quando uso sessões contextuais. Nesse caso a sessão não vem no construtor. Nesse caso uso Service Location em vez de DI. Tem espaço pras duas depende do problema. Uma discussão sobre isso:
http://unplugged.giggio.net/post/Injecao-de-dependencia-ou-Service-Locator.aspx


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/6 Alessandro de Souza <alessandr...@gmail.com>
Outro detalhe Giggio:

Giovanni Bassi

não lida,
6 de jul. de 2010, 18:07:4906/07/2010
para dotnetarchitects
Vc resolve isso com cascade. Assim, se eu alterar pedido, produto não é alterado, e vice versa.

Na prática, com ORM, é o cascade que marca fisicamente as fronteiras das agregações.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/6 tucaz <tuc...@gmail.com>

Giovanni Bassi

não lida,
6 de jul. de 2010, 18:09:5206/07/2010
para dotnetarchitects
Se eu hoje usasse UoWs eu também não usaria a sessão diretamente, eu encapsularia, justamente pra evitar essa dependência direta nos meus controllers.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


Alessandro de Souza

não lida,
6 de jul. de 2010, 21:52:0506/07/2010
para dotnetar...@googlegroups.com
Giggio,
para este caso onde um serviço de domínio pode resolver esta exceção, eu deveria ter um UOW neste serviço? Ou tem outra forma de resolver?

Att,
Alessandro

Hamon Vitorino

não lida,
6 de jul. de 2010, 23:12:3906/07/2010
para dotnetar...@googlegroups.com
Giovanni, concordo em parte.

Quando você diz que "se as operações devem ser executadas num contexto transacional, então talvez elas façam parte da mesma agregação", concordo e dou ênfase ao "talvez". Então, diria que depende.

Sobre o exemplo da empresa de tv a cabo, concordo que seria mesmo um smell implementar uma operação como a descrita, mas vejo que esse é um cenário muito simplista.
Então, suponhamos uma aplicação simples, que tem três funcionalidades:

1. Registrar vendas
2. Controlar estoque
3. Controlar receitas/despesas

Poderíamos ter um modelo como o seguinte:

Entidades
    - Produto (root)
    - Pedido (root)
        * lista de produtos
    - Estoque  (repositório de produtos)
    - Vendedor (serviço de venda de produtos)
        * efetuar venda
    - Contador (serviço de controle financeiro)
        * registrar receita

Acredito que seria plausível definirmos a operação "efetuar venda" como a remoção dos produtos vendidos do estoque e o registro da receita proveniente da venda realizada. Segue a "implementação" do Vendedor:

Vendedor
{   
    efetuar venda(pedido)
    {
        foreach produto in pedido
        {
            remover produto do estoque
            contador registra receita proveniente da venda do produto
        }
    }
}
       
Acho que esse cenário, apesar de simplista, dá uma visão melhor sobre quando seria necessário usar transação entre agregações. Ou há algo errado com o modelo. Acredito que não, mas isso é só a minha opinião.

[]'s

Giovanni Bassi

não lida,
7 de jul. de 2010, 02:45:5507/07/2010
para dotnetar...@googlegroups.com
Vamos falar de contexto:

No contexto de compra de alguma coisa, a compra tem que ser registrada, o estoque tem que ser baixado, e a contabilidade lançada. Isso é tudo atômico, faz sentido.
O que me impede de ter uma agregação com todos estes itens, com a raiz no pedido?

Alguém dirá: oras, mas o que estoque tem a ver com pedido? Eu dou entrada no estoque sem precisar de um pedido, não faz sentido. Aí sou eu quem diz: oras, estamos falando de entrada de estoque ou de venda de produto? Qual o contexto? Se é venda, então é venda, não entrada de estoque. Nesse contexto, estoque é parte da raiz de pedido. Separo os contextos, crio classes separadas por namespaces, etc. O banco de dados que segura as informações de estoque pode até ser compartilhado entre os contextos, mas isso pouco me importa, banco de dados é chateação, o que me interessa é o domínio, bd é fácil de resolver.
Fica claro que a mesma coisa vale para o lançamento contábil.

Por isso que eu falei que não adianta achar que DDD é só entidade, serviço, repositório, etc. Temos que ler a segunda parte do livro. E temos que parar de encarar tudo como se fosse CRUD. Não é um insert de pedido e item, um update de estoque e um insert de linha contábil. É uma operação de negócio, baseada em entidades relacionadas, acopladas e coesas dentro daquela operação. Se algo vai ser alterado no banco de dados, isso é problema dos data access objects por trás dos repositórios.

E nada de unit of work.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/7 Hamon Vitorino <cham...@gmail.com>

Daniel Silva

não lida,
7 de jul. de 2010, 06:54:4007/07/2010
para dotnetar...@googlegroups.com
Giovanni,

Estoque é repositório de produtos (root de sua agregação). Por isso Produto não pode fazer parte da agregação de Pedido. Afinal, para criar um novo Produto não precisamos de Pedido de venda, certo?

Se temos um repositório de Produtos e (apesar de o Hamon não ter citado), precisamos de um repositório de Pedidos, estamos diante de uma situação em que existe atomicidade entre diferentes agregações. E eu poderíamos enumerar N outras situações onde isso acontece.

O Evans fala que se estamos diante de uma funcionalidade que não é responsabilidade específica de uma entidade, utilizamos serviço. Dado o exemplo do Hamon, temos: vender não é responsabilidade de produto e atualizar quantidade de Produtos não é responsabilidade de Pedido. Por isso o Hamon criou um serviço de vendas, que trabalhará Produtos e Pedidos.
Como não podemos salvar Pedido sem que a quantidade do produto seja atualizada, precisamos de um contexto transacional. Vejo o Unit of Work (UoW) como a solução para isso.

Enfim, se estivermos em uma agregação trabalhando com um repositório, teremos o UoW. Se estivermos em um serviço trabalhando repositórios de mais de uma agregação, também teremos UoW.

O que pode ter causado dúvida no Régis é a própria utilização do nome UnitofWork para uma funcionalidade que ele já utiliza no NHibernate. Mas, na verdade, este é um padrão tão antigo quanto os SGDBs. Em qualquer lugar que tivermos (BeginTransaction -> Commit), teremos uma unidade de trabalho (Unit of Work).

Como o próprio Fowler escreveu em PoEAA: "No momento em que você estiver lendo este livro, alguns padrões já podem ter sido absorvidos pela tecnologia vigente". Os ORMs fazem o UoW para nós...
No caso do EF4 temos o ObjectContext. No caso do NHibernate temos a Session. Assim por diante...

Abs!
São Frei Galvão, rogai por nós!

Daniel Silva

não lida,
7 de jul. de 2010, 08:36:5507/07/2010
para dotnetar...@googlegroups.com
Desculpem-me pelo "eu poderíamos". A princípio eu ia escrever "eu poderia", depois resolvi mudar para poderíamos, mas esqueci de trocar o "eu"...

Giovanni Bassi

não lida,
7 de jul. de 2010, 08:46:3707/07/2010
para dotnetarchitects
Daniel, um serviço de vendas sempre pode existir. Isso não tem absolutamente nada a ver com as responsabilidades das entidades, dos repositórios ou com as fronteiras da agregação. Persistir no repositório não é necessariamente responsabilidade do serviço, pode ser feito pelo coordenador da ação, um controller MVC por exemplo.

Você continua vendo o sistema todo de forma como se só existisse um contexto para atender a venda e outras ações, como a entrada no estoque, por exemplo. No cenário que propus não há mais do que um único repositório no contexto de venda. Talvez existam outros repositórios, em outros contextos, que tratam outras entidades. No contexto de venda, o repositório atenderia o pedido como raiz, e persistiria todo o resto, porque é isso que o usuário entende que é isso que deve ser feito na linguagem ubiqua.

DDD não é um padrão para estruturação de entidades, serviços e repositórios. Pra isso vc compra um livro de padrões, como o PoEAA. DDD é uma abordagem completa. Ignorar isso e tratá-lo como uma coleção de padrões é perder 80% do livro.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/7 Daniel Silva <daniels...@gmail.com>

Daniel Silva

não lida,
7 de jul. de 2010, 09:17:5707/07/2010
para dotnetar...@googlegroups.com
Giovanni,

Serviço de vendas é um serviço de domínio. Então ele tem tudo a ver com responsabilidade das entidades, uma vez que a motivação para criá-lo foi a não identificação de uma entidade que seria responsável pela funcionalidade como um todo.

No cenário que você propôs não pode haver somente o repositório que atende pedidos. Pois Produto não faz parte da agregação de Pedidos e alguém precisa atualizar a quantidade dele. Ele não faz parte da agregação de Pedido porque considero que se você está vendendo um Produto, foi porque você o criou de alguma forma. E para criá-lo, eu duvido que seu usuário precisará de um Pedido de venda... 

Então precisamos de um repositório que atenda exclusivamente Produto, porque ele se caracteriza como uma entidade independente de Pedidos de venda.

Volto a afirmar que temos uma atomicidade entre entidades de diferentes agregações. Temos uma operação de venda que cria Pedidos e atualiza quantidade de Produtos. E essas duas sensibilizações precisam ser persistidas em conjunto. Ou tudo, ou nada. UoW FTW!

Abs!

Gerson Dias

não lida,
7 de jul. de 2010, 09:56:5407/07/2010
para dotnetar...@googlegroups.com
Acho (e é um belo de um chute) que o que o Giovanni quis dizer é que teriamos entidades diferentes para cada contexto. No contexto de "vendas" o produto, estoque, etc tem uma série de propriedades e comportamentos que são diferentes do contexto de "logistica". Estas entidades e agregações seriam separadas e teriam formas diferentes e seriam diferenciados pelo namespace (se quero vender uso Sistema.Vendas.Produto, se quero repor o estoque uso Sistema.Estoque.Produto).

Acho que é uma visão legal, já que mesmo para o negócio o depto de logistica ve o produto de forma diferente que um vendedor.

O que vcs acham? Viajei? heheh

Régis Soares

não lida,
7 de jul. de 2010, 11:42:4207/07/2010
para dotnetar...@googlegroups.com
Dias,
 
Eu entendi isso tb, principalmente quando afirmou que "No cenário que propus não há mais do que um único repositório no contexto de venda".
 
Nunca tinha pensado na aplicação dessa forma. Achei interessante.
 
Vamos aguardar para ver (ler) as cenas do próximo capítulo.
abs
2010/7/7 Gerson Dias <gerson....@gmail.com>

Giovanni Bassi

não lida,
7 de jul. de 2010, 13:45:2107/07/2010
para dotnetarchitects
Daniel,

No contexto de criação de produtos, vc pode ter um repositorio de produtos.
No contexto de pedido, vc simplesmente não precisa. Vc cria outra classe de produto, especifica para este contexto.

Veja bem, não estou dizendo que vc não deve usar UoW entre repositórios, vc usa como quiser. Só não está atendendo ao melhor principio de design, IMO. Cada um escreve o software como quer. Pra mim, UoW denota vazamento de regras além da agregação, e a ilusão de um contexto único para todo o sistema, algo irreal em qualquer software corporativo.

Do livro:
Although this problem surfaces as technical difficulties in database transactions, it is rooted in the
model—in its lack of defined boundaries. A solution driven from the model will make the model
easier to understand and make the design easier to communicate. As the model is revised, it will
guide our changes to the implementation.

Ainda assim, o Evans levanta o ponto das UoWs:
Leave transaction control to the client. Although the REPOSITORY will insert into and delete
from the database, it will ordinarily not commit anything. It is tempting to commit after
saving, for example, but the client presumably has the context to correctly initiate and
commit units of work. Transaction management will be simpler if the REPOSITORY keeps its
hands off.

Mas não se deixe levar por essa afirmação. Isso não significa que updates devem acontecer entre Repositórios. Sugiro a leitura do capítulo 14 do livro, Maintaining model integrity.
Deste capitulo:

Explicitly define the context within which a model applies. Explicitly set boundaries in
terms of team organization, usage within specific parts of the application, and physical
manifestations such as code bases and database schemas. Keep the model strictly
consistent within these bounds, but don't be distracted or confused by issues outside.
Que é exatamete o que estou dizendo.

Giovanni Bassi

não lida,
7 de jul. de 2010, 13:46:3807/07/2010
para dotnetarchitects
É isso mesmo. O cap. 14 do livro trata destes assuntos mais claramente.

[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/7 Régis Soares <regis...@gmail.com>

Hamon Vitorino

não lida,
7 de jul. de 2010, 14:12:3607/07/2010
para dotnetar...@googlegroups.com
Giovanni,

Se não tiver um repositório de produtos no contexto de um pedido, como saberei quais produtos foram solicitados em um determinado pedido?
Mantendo-me no modelo que propus, não vejo a necessidade de criação de um novo contexto. E acho que o trecho do livro que foi exposto não reforça a sua opinião (da qual não discordo completamente, como já disse antes).


"Leave transaction control to the client"

Posso traduzir esse trecho para: "implemente um módulo http para gerenciamento de transações".
Sendo uma aplicação web o cliente do domínio, ele assumiria a responsabilidade de criar o contexto transacional da operação, bastando implementar o pattern OpenSessionInView.

[]'s

Daniel Silva

não lida,
7 de jul. de 2010, 16:16:2107/07/2010
para dotnetar...@googlegroups.com
Perfeitamente, Giovanni.
Compreendi o que você disse anteriormente.

Abs!

Régis Soares

não lida,
7 de jul. de 2010, 16:35:3207/07/2010
para dotnetar...@googlegroups.com
Giovanni,
 
Quando vc usa NH ou EF não está implicitamente usando UOW? Eu entendo que sim, independente do contexto. Foi justamente isso que gerou toda essa discussão.
 
abs

2010/7/6 Giovanni Bassi <gig...@giggio.net>

Giovanni Bassi

não lida,
7 de jul. de 2010, 23:55:1907/07/2010
para dotnetarchitects
Oi Regis,

Está sim, claro! O Contexto do EF, e a Sessao do NH são claramente uma implementaÇão de UoW. Isso não significa que o conceito deva ser usando entre repositórios.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/7 Régis Soares <regis...@gmail.com>

Giovanni Bassi

não lida,
7 de jul. de 2010, 23:57:5607/07/2010
para dotnetarchitects
Se não tiver um repositório de produtos no contexto de um pedido, como saberei quais produtos foram solicitados em um determinado pedido?
O Pedido provavelmente vai ter um campo que é uma lista de itens, cada item vai ter uma propriedade produto.

Com Linq, se Itens for um enumerador publico de itens do pedido:

var produtos = from i in pedido.itens select i.Produto;

JR

não lida,
8 de jul. de 2010, 08:19:0008/07/2010
para .Net Architects
Boa Gerson,

O teu chute é bem parecido com o meu. Tudo depende dos contextos, o
pessoal não está conseguindo separar as coisas.

[]s

On 7 jul, 10:56, Gerson Dias <gerson.dias....@gmail.com> wrote:
> Acho (e é um belo de um chute) que o que o Giovanni quis dizer é que
> teriamos entidades diferentes para cada contexto. No contexto de "vendas" o
> produto, estoque, etc tem uma série de propriedades e comportamentos que são
> diferentes do contexto de "logistica". Estas entidades e agregações seriam
> separadas e teriam formas diferentes e seriam diferenciados pelo namespace
> (se quero vender uso Sistema.Vendas.Produto, se quero repor o estoque uso
> Sistema.Estoque.Produto)..
>
> Acho que é uma visão legal, já que mesmo para o negócio o depto de logistica
> ve o produto de forma diferente que um vendedor.
>
> O que vcs acham? Viajei? heheh
>
> 2010/7/7 Daniel Silva <danielsilva...@gmail.com>
> >> entende *que é isso que deve ser feito na linguagem ubiqua*.
>
> >> DDD não é um padrão para estruturação de entidades, serviços e
> >> repositórios. Pra isso vc compra um livro de padrões, como o PoEAA. DDD é
> >> uma abordagem completa. Ignorar isso e tratá-lo como uma coleção de padrões
> >> é perder 80% do livro.
>
> >> []'s
>
> >> Giovanni Bassi
> >> Arquiteto de software
> >>+55 (11) 8522-5774begin_of_the_skype_highlighting              +55 (11) 8522-5774      end_of_the_skype_highlighting
> >> Consultoria:www.giovannibassi.comBlog: unplugged.giggio.net
> >>  <https://mvp.support.microsoft.com/profile/Giovanni.Bassi>
> >> [image: Linkedin] <http://br.linkedin.com/in/giovannibassi>[image: Blog
> >> RSS] <http://feeds.giggio.net/DotNetUnplugged>[image: Twitter]<http://twitter.com/giovannibassi>
>
> >> 2010/7/7 Daniel Silva <danielsilva...@gmail.com>
>
> >> Giovanni,
>
> >>> Estoque é *repositório* de produtos (root de sua agregação). Por isso
> >>>>+55 (11) 8522-5774begin_of_the_skype_highlighting              +55 (11) 8522-5774      end_of_the_skype_highlighting
> >>>> Consultoria:www.giovannibassi.comBlog: unplugged.giggio.net
> >>>>  <https://mvp.support.microsoft.com/profile/Giovanni.Bassi>
> >>>> <http://www.scrumdev.com.br>
> >>>> [image: Linkedin] <http://br.linkedin.com/in/giovannibassi>[image: Blog
> >>>> RSS] <http://feeds.giggio.net/DotNetUnplugged>[image: Twitter]<http://twitter.com/giovannibassi>
>
> >>>> 2010/7/7 Hamon Vitorino <chamo...@gmail.com>
> >>>>> alessandro.de.so...@gmail.com> escreveu:
>
> >>>>> Giggio,
> >>>>>> para este caso onde um serviço de domínio pode resolver esta exceção,
> >>>>>> eu deveria ter um UOW neste serviço? Ou tem outra forma de resolver?
>
> >>>>>> Att,
> >>>>>> Alessandro
>
> >>>>>> Em 6 de julho de 2010 19:01, Giovanni Bassi <gig...@giggio.net>escreveu:
>
> ...
>
> mais »- Ocultar texto das mensagens anteriores -
>
> - Mostrar texto das mensagens anteriores -

Ricardo Borges

não lida,
8 de jul. de 2010, 08:25:0808/07/2010
para dotnetar...@googlegroups.com
Acho que está havendo uma confusão aqui.


Unit of Work é um pattern que pode existir numa aplicação independente de como esta foi desenhada. DDD, ORM, TDD não importa...

 Só diz respeito a uma coisa... de que maneira os comandos de uma transação será enviado ao banco.

A grosso modo é: Ao invés de a cada chamada pro banco o programa fazer um acesso, mantenha um rastreamento disso concentrando esses comandos, para executar de uma vez quando seu algoritmo tiver terminado.

( http://martinfowler.com/eaaCatalog/unitOfWork.html )

"When you're pulling data in and out of a database, it's important to keep track of what you've changed; otherwise, that data won't be written back into the database. Similarly you have to insert new objects you create and remove any objects you delete.

You can change the database with each change to your object model, but this can lead to lots of very small database calls, which ends up being very slow. Furthermore it requires you to have a transaction open for the whole interaction, which is impractical if you have a business transaction that spans multiple requests. The situation is even worse if you need to keep track of the objects you've read so you can avoid inconsistent reads.

A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work."


-------------------
Interpretando isso, se o pattern for implementado, significa que se sua aplicação possuir uma classe de negocio que utiliza 3 classes de acesso à dados numa transação, todos os comandos não serão enviados de imediato ao banco, independente de qual classe de acesso...

se a sua arquitetura proibe por algum motivo que voce nao pode ter mais de uma classe de acesso ao banco num seviço, essa já é uma outra questão...


[]'s
Ricardo
Ricardo Borges

Alessandro de Souza

não lida,
8 de jul. de 2010, 08:46:3108/07/2010
para dotnetar...@googlegroups.com
Fala Ricardo.
Então, não vejo confusão alguma.
O que vc falou é pura verdade, só que, ninguém está dizendo para NÃO usar UOW, apenas COMO usá-lo.
Dentro do mesmo repositório no caso específico de DDD o ObjectContext (EF) ou o Session (NH) já são implantações de um UOW e certemente são usados (até porque não tem como ser de outro jeito usando estas tecnologias).

Mais a sua definição de UOW está perfeita, é isto mesmo.

Att,
Alessandro

Giovanni Bassi

não lida,
8 de jul. de 2010, 21:52:5508/07/2010
para dotnetarchitects
Alessandro, é isso mesmo. É o como, não o o que.
Eu estou defendendo que talvez não seja uma boa ideia fazer o flush da UoW quando há pendências que cruzam fronteiras de agregações.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/8 Alessandro de Souza <alessandr...@gmail.com>

Daniel Silva

não lida,
8 de jul. de 2010, 22:27:0408/07/2010
para dotnetar...@googlegroups.com
Faz sentido realmente, Giovanni. Além dos trechos que você destacou do livro, me lembrei de outro detalhe no capítulo sobre repositórios.
Ele faz o seguinte comentário quando fala sobre uma refatoração no modelo que ele usa como exemplo:

"The need to update Delivery History when adding a Handling Event gets the Cargo AGGREGATE involved in the transaction. If some other user was modifying Cargo at the same time, the Handling Event transaction could fail or be delayed. Entering a Handling Event is an operational activity that needs to be quick and simple, so an important application requirement is the ability to enter Handling Events without contention. This pushes us to consider a different design."

Abs!

Daniel Silva

não lida,
9 de jul. de 2010, 07:04:4309/07/2010
para dotnetar...@googlegroups.com
A questão é que, se este foi o motivo pelo qual você escreveu "talvez não seja uma boa idéia fazer o flush da UoW quando há pendências que cruzam fronteiras de agregações", no caso do cenário que você expôs não há como não haver interferência. Mesmo em contextos separados, alguém pode estar atualizando a quantidade de Produtos no Estoque ao mesmo tempo em que alguém efetua algum Pedido de Venda.

No seu exemplo, seria somente questão de design mesmo?

Abs!

Hamon Vitorino

não lida,
12 de jul. de 2010, 07:18:0512/07/2010
para dotnetar...@googlegroups.com
Giovanni,

Tenho algumas considerações a fazer, pois ainda não sei ao certo como você sugere que esse problema(operação de venda) deva ser tratado, levando em conta o que você afirmou sobre contextos, agregações e UoW. Seguem:
  1. O ponto que está em questão(para mim) é quando você afirma que "se as operações devem ser executadas num contexto transacional, então talvez elas façam parte da mesma agregação". Talvez, e só talvez, isso seja desejável ao invés de obrigatório.

  2. Em certo momento você disse:
          Com Linq, se Itens for um enumerador publico de itens do pedido:

          var produtos = from i in pedido.itens select i.Produto;

          Então pergunto: E sem ORM? Como seria? Acessaríamos um repositório de produtos, certo?
          Nem todo mundo usa ORM. Diria mais. Diria que a maioria não usa ORM e acrescentaria que a corretude de um sistema não depende do uso de um.
          Para não deixar dúvidas se uso ou não ORM, trabalho com NHibernate desde 2005 e, salvo engano, a primeira versão que usei foi a 0.9.1.

     3.  Não há como discordar que UoW pressupõe um único mecanismo de armazenamento de dados para todos os contextos de uma aplicação. Mas vejo também que isso é desejável em quase que qualquer tipo de aplicação. Já trabalhei com sistemas que tinham dados armazenados em bancos três bancos diferentes(sql, db2 e vsam), mas afirmo que todos eram legados. No caso específico dessa empresa em que trabalhei tínhamos à disposição um software capaz de realizar TWO-PHASE-COMMIT em operações evolvendo mais de um banco de dados e assim resolvemos a questão.

     4. Ok. Dividimos a aplicação em três contextos: ALMOXARIFADO, CONTABILIDADE e VENDAS. A operação de venda continua envolvendo agregações de contextos diferentes, não? Na minha definição a operação envolve a baixa do produto no estoque e o registro da receita. Onde essa definição está errada? De que forma uma refatoração no modelo pode me levar a uma operação de venda que afete apenas uma agregação?

[]'s

Giovanni Bassi

não lida,
12 de jul. de 2010, 09:57:5112/07/2010
para dotnetar...@googlegroups.com
Hamon,

A ideia é compor uma agregação que reproduza o domínio. Se o domínio pede por um objeto que faça a inserção do pedido, a baixa do estoque o registro da receita, então modelamos a agregação para ter o pedido (provavelmente) como raiz da agregação, o estoque e a receita como partes da mesma agregação. O repositório de pedidos faria a atualização nos bancos de dados, mesmo se fossem distribuidos, mesmo se fossem com 2PC, de forma ACID, e se isso não fosse possível, de forma BASE. Resolve o problema do pedido, não resolve? Contexto atendido, certo?

Em outro contexto, por exemplo, o de entrada de itens no estoque, eu teria outra classe de estoque, que talvez fosse raiz de sua própria agregação. Essa classe teria as propriedades e métodos necessários à essa operação, e não teria nada a ver com pedido ou registro de receita.

Quanto à exibição dos dados, com o LINQ, como mostrei, é bom lembrar que LINQ não depende de ORM. E o exemplo que dei foi somente uma possibilidade. Na verdade, o problema de exibição de dados é muito maior que esse. Sugiro ver analisar Comand And Query Separation, já que repositórios e entidades se prestam muito mal a exibição de dados.


[]'s

Giovanni Bassi
Arquiteto de software
+55 (11) 8522-5774
Consultoria:
www.giovannibassi.com Blog: unplugged.giggio.net
LinkedinBlog RSSTwitter


2010/7/12 Hamon Vitorino <cham...@gmail.com>

Diogo Menezes

não lida,
12 de jul. de 2010, 10:14:2812/07/2010
para dotnetar...@googlegroups.com

Koga, Diego

não lida,
13 de jul. de 2010, 07:36:1213/07/2010
para dotnetar...@googlegroups.com
Giovanni,

Fiquei na dúvida, então haveria duplicação de código da classe produto?

E fazendo desta forma não estaria infringindo o SRP?


[]´s



Att.,
------------------
Koga, Diego



2010/7/12 Diogo Menezes <diogol...@gmail.com>

Hamon Vitorino

não lida,
13 de jul. de 2010, 13:42:2213/07/2010
para dotnetar...@googlegroups.com
Diego,

Tentando responder à sua pergunta, a idéia é que o produto possuiria representações diferentes em cada contexto, pois cada um tem sua maneira de entender esse objeto.

Giovanni,

Compreendo a separação de contextos proposta pelo DDD e vejo o seu valor. Se ainda não ficou claro o meu ponto ou se realmente discordamos, tento mais uma vez esclarecer.
Bom, meu questionamento é quanto à operação de venda, da maneira como a defini, que no meu modo de ver pode "atravessar" contextos (ALMOXARIFADO e  VENDAS).
Imagine que a venda do produto só possa ser realizada se também for confirmada a baixa dele do estoque. Realmente, como você sugeriu, posso modelar todos esses objetos de maneira que se encontrem em uma mesma agregação, logo, em um mesmo contexto.
Ganhamos um "problema". Pois, ainda assim, preciso que o contexto de almoxarifado seja notificado de que o produto foi vendido.
Há muitas maneiras de se fazer isso e cito a troca de mensagens como uma provável ferramenta na solução desse problema.
Porém, como a baixa do produto no contexto do almoxarifado não faz parte da operação de venda, estou sujeito a vender mais produtos do que tenho em estoque, pois a notificação da venda pode não chegar a tempo de a próxima venda se realizar, quando o último produto tiver sido vendido.
Talvez uma liquidação num grande site de vendas seja um bom exemplo de negócio que pode passar por essa situação.

[]'s

Giovanni Bassi

não lida,
14 de jul. de 2010, 00:05:3414/07/2010
para dotnetar...@googlegroups.com
Oi Hamon,

Se estamos assumindo que as entidades foram todas modeladas no contexto de vendas, e é neste contexto que acontecem todas as vendas, então não vejo problemas. O contexto do almoxarifado não precisa ser notificado para permitir que as vendas continuem, já que no contexto de vendas temos entidades responsáveis por essas operações.
Vamos voltar à linguagem ubiqua:
Se o especialista de domínio, aka usuário que sabe o que sistema tem que fazer, diz que precisa fazer a venda, baixar estoque, e alterar alguma outra coisa, tudo junto, temos que refletir isso no código. Todas essas operações podem ser modeladas como sub partes de uma única operação principal (vender) que seria parte da raiz da agregação, e entraria em contato via associação com as outras entidades relacionadas.

Se por qualquer outro motivo o almoxarifado precisa saber que precisa comprar mais produtos para vender, ou sei lá, isso pode ser modelado via filas, domain events, etc, etc, e não impacta em nada a venda, nem mesmo se fosse uma liquidação, que você sugeriu.

[]s

GB


2010/7/13 Hamon Vitorino <cham...@gmail.com>
Responder a todos
Responder ao autor
Encaminhar
0 nova mensagem