Probleminha OOAD (DDD Repositórios)

Você acha que é um pecado imperdoável um repositório de Reservas retornar Quartos, mesmo que isso faça sentido para os especialistas do domínio e os usuários?

[essa pergunta é para todos, não só para o taborda]

Você acha que é um pecado imperdoável um repositório de Reservas retornar Quartos, mesmo que isso faça sentido para os especialistas do domínio e os usuários?

[essa pergunta é para todos, não só para o taborda][/quote]

O que eu acho ruim é metodologia ou arquitetura tentando me dizer o que eu posso ou não posso fazer, ou pior, seguidores cegos destes falando o mesmo.

Se os usuários, especialistas e você, o desenvolvedor, falam A, não tem gente de fora que diga B ou C. Não quer dizer não vou ouvir nem considerar, mas sem meter o dedo onde não é chamado.

Você acha que é um pecado imperdoável um repositório de Reservas retornar Quartos, mesmo que isso faça sentido para os especialistas do domínio e os usuários?

[/quote]

Como qualquer teosofo sabe todos os pecados são perdoáveis :lol:
Nâo acho que seja um pecado. Acho que é uma falha lógica.Sendo uma falha acho que dá para fazer melhor.
Se o especialista de domínio e os usuários disserem que dois hospedes nunca terão o mesmo nome você modela o sistema seguindo essa regra ? Eu não o faria porque sei que isso é uma falha lógica.

Na minha experiência a realidade do mundo vem primeiro que a opinião dos usuários ou dos especialistas pela simples razão que a realidade não tem falhas lógicas. É por isso que estudamos matemática e lógica. Outros programadores que virão depois mexer no código sempre poderão apelar para a lógica para entender o sistema. Eles não terão esse guia se a opinião falhada dos usuários se sobrepuser. Mas isso, acaba sendo um problema entre você e eles : os usuários e especialista por um lado e os seus peers desenvolvedores por outro…

Colocar um repositório de X retornar Y acho que não é lógico. Sendo assim o detalhe tem que ser contornado no design e no modelo para que seja lógico. às vezes temos que ir mais longe. Temos que chegar em algo como Hotel.getQuartosLivresParaReservaEm(Periodo) : Quartos. Isto dá o que você quer, é ainda mais realista que um objeto chamado TodasReservas e é semântico o suficiente para usuarios e programadores.

Mesmo que os pecados sejam perdoáveis a graça é não os cometer em primeiro lugar.

Esquecendo a UL por um pouco, do ponto de vista puramente OO um repositório de X retornar Y é uma violação do objetivo do próprio objeto repositório. Se vc não quer que o repositorio de X retorna sempre X porque vc afirmar que é o repositorio de X se na realidade posso encontrar nele outras coisas ? É como ter um TodasPessoas e ter um TodasPessoas.getAnimaisDeEstimação() : AnimaisEstimação … animais de estimação não são pessoas, que magia é essa que me permite tirar animais de onde só ha pessoas ?

Claro que vc pode optar por dizer que o repositório é agnóstico, que ele não é de X ou Y e que não ha problema algum em TodosX retornarem Y. Ok. Mas por esse mesmo agumento não ha por que ter dois repositórios , um para X e outro para Y. Basta ter um RepositorioGeral que encontra tudo de qualquer tipo.

Não sei se ficou claro. O ponto é: Se você divide responsabilidade de procura para objetos diferentes baseado na associação a uma entidade , isso tem que significar algo. Não pode simplesmente ser ignorado quando é tentando a violar essa divisão que você mesmo criou por algum motivo de simplificação técnica ou porque lhe pediram para ser assim. Ou vc divide em N repos e mantém a coerencia (coesão) dessa divisão sempre, ou vc só tem 1 repositório universal e pronto. Coisas no meio não são lógicas. Para mim não são.

Concordando com o Bruno Laturner eu também acho que seguir as coisas cegamente é ruim. A diferença é que eu considero que boa arquitetura e design dão visão e não tiram como vcs parecem achar. Não é preciso ter poderes mágicos ou ser visionário para criar um bom design. É só seguir a regras. O argumento que as regras podem ser dribladas em condições especiais não é lógica para mim e realmente eu vejo isso como um pecado de corrupção.

Bom design , principios e regras, nunca trazem problemas. Não os seguir é que sim traz.

[quote=rodrigoy] Você acha que é um pecado imperdoável um repositório de Reservas retornar Quartos, mesmo que isso faça sentido para os especialistas do domínio e os usuários?

[essa pergunta é para todos, não só para o taborda][/quote]

Falar pecado imperdoável acho meio forte pra isso, mas ao meu ver parece fazer sentido, pois se não houver quartos não haverá reservas, logo se vc receber reservas (orientação do repositório) como resposta logo haverá quartos associados fornecendo-lhe respostas a respeito desta entidade. Talvez a questão não seja o fazer sentido e sim se isto é realmente necessário. Acredito que os requisitos ajudem nesta hora.

flws

[quote=sergiotaborda] Concordando com o Bruno Laturner eu também acho que seguir as coisas cegamente é ruim. A diferença é que eu considero que boa arquitetura e design dão visão e não tiram como vcs parecem achar. Não é preciso ter poderes mágicos ou ser visionário para criar um bom design. É só seguir a regras. O argumento que as regras podem ser dribladas em condições especiais não é lógica para mim e realmente eu vejo isso como um pecado de corrupção.

Bom design , principios e regras, nunca trazem problemas. Não os seguir é que sim traz. [/quote]

Gostei bastante desta parte.

[]'s

[quote=fantomas] Você acha que é um pecado imperdoável um repositório de Reservas retornar Quartos, mesmo que isso faça sentido para os especialistas do domínio e os usuários?

essa pergunta é para todos, não só para o taborda][/quote]

@fantomas
:arrow: Acredito que no sentido de repositorio o sergio esta corrento sim, o que esta fazendo confusão ai é o que o objeto tem em sua real responsabilidade.

@Sergio Taborda
Bom design , principios e regras, nunca trazem problemas. Não os seguir é que sim traz.

:arrow: O design(requisito) esta ligado a ação do ator(comportamento) indiretamente, abstração é sempre alvo de redesenho na Orientação a Objeto(refatoração)

@Todos

Falar pecado imperdoável acho meio forte pra isso, mas ao meu ver parece fazer sentido, pois se não houver quartos não haverá reservas, logo se vc receber reservas (orientação do repositório) como resposta logo haverá quartos associados fornecendo-lhe respostas a respeito desta entidade. Talvez a questão não seja o fazer sentido e sim se isto é realmente necessário. Acredito que os requisitos ajudem nesta hora.

:arrow: Aqui não concordo, novamente existe outros fatores de circunstanciais a se considerar ou onde podem projetar na navegação da ação ao use case, se não houver quartos não haverá reservas ? ou se não houver quartos “temos outro estabelecimento proximo de sua localização nas mesmas condições desejadas”, ou se não houver quartos temos no hotel temos a estadia de estilo diferenciado, master premium, e assim vai

Mas aí é que está a graça da coisa Marcio, sempre haverá um quarto para uma reserva; a força disto é tão grande que vc arrumou quartos até em outras instancias rsrsrsrsr. Arrisco a dizer que deve haver uma regra neste mundinho dizendo que vc não pode concretizar uma reserva sem um quarto (levando em conta data/hora).

flws

Entramos agora numa questão filosófica: “Vale a pena ferir as regras há muito estudadas por especialistas em favor de uma possível ‘facilitação’ no desenvolvimento da arquitetura?”

Acho que podemos criar outro tópico pra isso, o que vocÊs acham?

:smiley:

Poxa agora me veio um pensamento… reservas estão sempre associadas a um quarto… vc so pode fazer uma reserva para um quarto disponivel correto? não poderemos fazer reservas para algo que não seja um quarto… em meio disto vemos uma relação: “reserva x quarto” para existir uma reserva deve existir um quarto disponivel… vendo desta forma um esta ligado com outro… pq então não unimos os 2 e matamos a reserva? pq não utilizamos apenas o repositorio quartos com atributo com o periodo de indisponibilidade?

Carinha, essa frase entre aspas ficou parecendo um tipo de elixir revigorante para pogueiro.

Se todos estiverem de acordo blz, mas ainda acho que a assunto ainda é pertinente ao tópico criado pelo rodrigoy; acredito que no fundo éra justamente este o questinamento dele; É de um lado ou é do outro? Se é do outro e esse outro é agregador ele pode expor as entidades agregadas diretamente? e por aí vai…bem interessante isto tudo.

flws

Não mate a reserva, por favor! :smiley: Se fizer isso poderá ter muitos problemas futuros! (Eu já fiz isso :cry: )

No primeiro sistema no qual trabalhei, que foi para uma pequena pousada, interpretamos que não haveria necessidade de uma entidade Reserva, pois quando uma pessoa reservava um quarto nós criávamos direto uma conta com as diárias e através das diárias tínhamos como saber se a pessoa já havia efetuado o check-in, ou seja, se já havia ocorrido uma ocupação. Nós ignoramos o fato de que na linguagem do especialista no domínio a palavra reserva aparecia constantemente e tinha um significado essencial para o negócio. Isso se mostrou um erro com o passar do tempo.

[quote=“fantomas”]
Link_pg wrote:Entramos agora numa questão filosófica: “Vale a pena ferir as regras há muito estudadas por especialistas em favor de uma possível ‘facilitação’ no desenvolvimento da arquitetura?”

Carinha, essa frase entre aspas ficou parecendo um tipo de elixir revigorante para pogueiro. [/quote]

ahuehueaheua vou imprimir e colar aqui na minha baia, do lado do Dijkstra is watching e do poster do curintia!!

[quote=Link_pg]Entramos agora numa questão filosófica: “Vale a pena ferir as regras há muito estudadas por especialistas em favor de uma possível ‘facilitação’ no desenvolvimento da arquitetura?”

Acho que podemos criar outro tópico pra isso, o que vocÊs acham?

:smiley: [/quote]

O que acontece quando os especialistas pensam uma coisa, mas o caminho ótimo para alcançar o objetivo é outro? Quando seguir a risca o DDD piora o sistema (em performance)?

Isso me lembra um pouco a questão do “Object-relational impedance mismatch”, o mapeamento é menos que perfeito.

É, isso é verdade. Até porque o foco do DDD não é a performance em si, o que acaba depreciando-a nesse caso, o que não é nada bom pois em software a performance é sim muito importante. Acredito que o melhor dos casos é o bom senso… não há como uma teoria (como o DDD) garantir que todos os aspectos não funcionais (performance, escalabilidade, manutenabilidade, *idade) de uma aplicação sejam otimizados, algumas vezes até prejudicando-os, portanto não seria nada de outro mundo darmos uma adaptada na modelagem para contemplar um requisito não funcional (sem exageiros, claro).

É, isso é verdade. Até porque o foco do DDD não é a performance em si, o que acaba depreciando-a nesse caso, o que não é nada bom pois em software a performance é sim muito importante. Acredito que o melhor dos casos é o bom senso… não há como uma teoria (como o DDD) garantir que todos os aspectos não funcionais (performance, escalabilidade, manutenabilidade, *idade) de uma aplicação sejam otimizados, algumas vezes até prejudicando-os, portanto não seria nada de outro mundo darmos uma adaptada na modelagem para contemplar um requisito não funcional (sem exageiros, claro).[/quote]

É ai que entra o bom senso e a capacidade do desenvolvedor de escolher a melhor ação a ser tomada…
um bom desenvolvedor não é aquele que resolve o problema pois isto todos fazem… mas sim aquele que escolhe a melhor solução para o problema…

Não me parece lógico em Domain-Driven eu ter um elemento chamado Hotel sendo que o que eu estou modelando é o funcionando do mesmo. Já tinha respondido aqui que ter esse “Hotel” gera outros problemas também lógicos.

Não exagera!!! :wink: No meu exemplo não estou misturando tanto as coisas. Reserva é algo intimamente relacionado com Quartos. Repositórios simplesmente representam uma coleção, geralmente de entidades. Portanto, mensagens que eu atire para este objeto denotam a responsabilidade dele. Não me parece sem lógica perguntar algo para um repositório sobre uma coisa que só ele sabe. Só as reservas sabem os quartos disponíveis.

Exagerou de novo. O EntityManager é o RepositorioGeral, mas usá-lo deste jeito não é Domain-Driven.

Eu já sou da opinião que design é algo criativo. Padrões existem como um guia não como regra. Só conhecimento em padrões não faz ninguém um bom designer.

Na sua solução (listada abaixo), você está construindo entidades transientes somente para que seu repositório TodasReservas retorne Reserva[0…*]. Para mim isso não é lógico, e qualquer programador que pegar esse código no futuro não vai ter a mínima idéia de porque você montou uma lista transiente de reservas se no fim o que você queria eram quartos.

Isso aqui abaixo é do agrado de todos?

Acredito que não importa o lado (quarto ou reserva) os questinomentos serão sempre os mesmos, um depende do outro.

A princípio prefiro (ainda) a solução no repositório das reservas, porque estou considerando quarto uma entidade fraca na relação quarto x reserva, inclusive ela (quarto) é agregada da reserva.

E ao observar seu exemplo, me recorre o questionamento: O resultado desta operação é necessário para satisfazer algum requisito?

[]'s

Neste caso, não é uma regra que um repositório deva sempre retornar a mesma coisa. Repositórios simplesmente representam coleções.

Não me lembro em nenhuma literatura de padrões falando sobre regras. É mais empírico. Quando o GOF foi escrito eles foram claros em dizer que Padrões eram soluções comuns que apareciam no código para problemas específicos. Um padrão é a repetição de um determinado mecanismo dada uma situação. NÃO É UMA REGRA. Se fosse o nome do livro seria Software Design Rules.

Você deve fazer o mesmo caminho para voltar para casa todos os dias. Isso é um padrão. Se você por alguma razão não fizer o mesmo caminho não estará violando uma regra.

Repara na contradição : “Não me parece sem lógica perguntar algo para um repositório sobre uma coisa que só ele sabe” X “Só as reservas sabem os quartos disponíveis”.

As reservas não sabem dos quartos disponiveis já que cada reserva só sabe do seu quarto.
Se o Repositório sabe, então não ha problema. O problema é que ele não sabe. Quem sabe qual é o animal da pessoa é a própria pessoa. Quem sabe do quarto da reserva é do próprio quarto.

O repositorio não sabe. Ele vai encontrar. É a sua função no sistema. Como ele encontra é uma questão modelada na implementação. O quê ele encontra é uma questão modelada no contrato .
Então, seja como for que ele procura ele sempre encontra reservas.

Por outro lado repositórios podem comunicar entre si. Portanto, do ponto de vista OO é sempre válido vc executar dentro do repositorio de reservas codigo referente a qualquer entidade. no caso quartos.
O codigo a seguir é válido dentro de TodasReservas

 // usando uma mecanismo de busca qq , vc invoca o seguinte
 Collection<Quarto> quartos = store.execute(
Criteria.search(Quarto.class).where("reserva").isNull()
);

 return OnDemandCollection<Reservas> (quartos, Periodo);

A reserva tem 1 quarto, mas o quarto tem 1,0 reservas. O quarto está reservado quando ha no sistema uma reserva que o possui.

O OnDemandCollection é um objeto especial que tem a interface do contrato (digamos que Collection) mas ele só criar os objetos quando o iterador passa por eles. É claro que vc pode fazer isso num for antes e retornar a coleção já preenchida. O ponto é apenas demonstrar como na realidade, na implementação, não estou manipulando reservas. Contudo, do lado de fora vc veria:


Collection<Reservas> reservas = TodasReservas.reservasDisponiveis(Periodo);

for ( Reserva r : reservas){
  System.out.println(r.getQuarto().getNumero());
}

O seu requisito era : "- Ao efetuar a reserva o sistema deverá exibir uma lista de quartos disponíveis para o período da estadia do hóspede. "

Ele está exibindo essa lista. Isso é 100% o que foi requisitado. Não foi requisitado como essa lista seria obtida. Mas existem regras implícitas de como isso vai ser feito. São as regras de OO, as boas práticas, o SoC , a não gambiarra, etc…
Acho que esta solução não viola nem a UL nem OO e portanto tem prioridade sobre as outras.
Acho que já ficou claro que qualquer uma das outras soluções apresentadas como opção não satisfazem todo o mundo.

Cuidado. EntityManager é o DomainStore. O DomainStore não é um reposiotrio porque ele não contém regras de dominio de como procurar entidades. Eles executa os critérios, mas ele não é responsável por os montar, ou saber quais são. Um RepositorioGeral seria uma classe que consome um EntityManager(DomainStore) e tem métodos para encontrar qq tipo de coisa. VC teria getHospedes e getQuartos e getReservas tudo na mesma classe.
Sendo assim, re-analise o que eu falei. O ponto era: Objeto unico com todos os métodos de pesquisa (RepositorioGeral) vs Repositorio por Entidade e qual é a regra/força que o faz preferir o segundo ao primeiro.
Essa mesma força é a que impede que Repositório de X retorne Y.

Claro que faz. Um processo criativo sem regras não serve para nada porque ninguem o vai entender. Isso é arte abstrata onde não ha bom nem ruim. Fazer software ainda não é uma arte abstrata. É uma arte concreta. As outras pessoas podem qualificá-la simplesmente conhecendo as regras. É por isso que ha bom design e mau design. É por isso que ha padrões e anti-padrões. É por isso que ha refactoring e bad smells. O valor do design (bom/mau) advem das regras e não da opinião ou gosto de ninguem. Assim, bom design é bom para todos e mau é mau para todos. Ainda estamos falando de um oficio baseado em ciência e não apenas em estética ou empirismo.

Fazer o que vc gosta e acha que dá certo é empirismo. Fazer o que as regras dizem é ciencia. A diferença é clara. A primeira vai lhe causar problemas ( como o testemunho do colega que ao não colocar Reservas no sistema se ferrou depois).

Correção. Estou criando objectos transientes. Entidades nunca não são transientes.
Isso é um truque de implementação que posso fazer em OO. Em nada isso define o contrato do objeto repositorio.

Hummm… na realidade ultima, o que eu quero são os identificadores dos quartos, pois sem eles ninguem vai saber de nada. No caso o numero serve como identificador (normalmente até ha uma regra para que o andar esteja contido no numero do quarto e assim ter 2 informações com um unico dado).
Eu quero ver o identificador. Isso não significa que eu procure pelo identificador. Acho que é passivo e aceitável que :

TodosQuartos.disponiveis(): Collection<Integer>

É um mau uso de OO e um modelo muito capenga.
O fato de querer obter e manipular X não significa que tenho que procurar X. Isso é uma falácia.
Eu vou procurar a entidade agregada mais próxima. No caso de Quarto é Reserva. No caso, de item de pedido é Pedido, e assim vai. Eu não procuro item de pedido sem o pedido. Entendo que muitos o façam, mas eu considero isso uma violação do modelo OO para esses objetos. O mesmo que para quarto e reserva.
Enfim, não vejo nenhum mal em utilizar-me da reserva para procurar pelos quartos.

Olá a todos , no livro do Page Jones ‘Fundamentals of object-oriented design in UML’, logo no capitulo 4 onde ele fala de Classes diagrams,ele define e cita um exemplo de associação que o seguinte:

LibraryPatron and LibraryBook geram a associação Borrowing, neste caso a associção é somente ‘conceitual’, pois eu nao preciso definir( no contexto do livro) nenhuma operacao em Borrowing. Mas no caso do exemplo temos:

Hospesdes-Quarto -> Reservas

A relação Hospesdes- Quarto gera uma associação Reservas, que neste caso faz sentido transformar a associção em uma classe concreta, visto que esta associação tem responsabilidades proprias.Uma delas seria de encontrar os quartos disponiveis, visto que a disponibilidade do quarto depende da reserva.

Entao essa operacao deveria estar no Repository Reserva, mas concordando com o taborda, o Repository Reserva deve retornar uma lista de reservas, porque isso?

Pensando um pouco, se voce pede a um repositorio que busque informacoes de reserva, porque ele deveria retornar quartos? nao vejo o sentido disso. Ora se quero informacoes do quarto pergunto ao quarto, se quero informacoes de reservas(entenda que reserva aqui e o que diz se um quarto esta disponivel ou nao), peço ao Repository de reservas, uma vez que com a reservas consigo chegar ate o quarto.

Portanto minha opção seria a segunda, com as ressalvas acima.