Estou mergulhando no Domain Driven Design e alguns dos conceitos que estou me deparando fazem muito sentido na superfície, mas quando penso mais sobre eles, tenho que me perguntar se essa é realmente uma boa ideia.
O conceito de agregados, por exemplo, faz sentido. Você cria pequenos domínios de propriedade para não precisar lidar com todo o modelo de domínio.
No entanto, quando penso sobre isso no contexto de um aplicativo Web, frequentemente acessamos o banco de dados para recuperar pequenos subconjuntos de dados. Por exemplo, uma página pode listar apenas o número de pedidos, com links para clicar para abrir o pedido e ver seus IDs de pedidos.
Se eu sou Agregados entendimento correto, eu normalmente usaria o padrão de repositório para retornar um OrderAggregate que conteria os membros GetAll
, GetByID
, Delete
, e Save
. OK isso parece bom. Mas...
Se eu chamar GetAll para listar todos os meus pedidos, parece-me que esse padrão exigiria a devolução de toda a lista de informações agregadas, pedidos completos, linhas de pedidos, etc ... Quando eu precisar apenas de um pequeno subconjunto dessas informações (apenas informações do cabeçalho).
Estou esquecendo de algo? Ou existe algum nível de otimização que você usaria aqui? Não consigo imaginar que alguém advogaria o retorno de agregados inteiros de informações quando você não precisar.
Certamente, pode-se criar métodos no seu repositório GetOrderHeaders
, mas isso parece anular o propósito de usar um repositório como o padrão em primeiro lugar.
Alguém pode esclarecer isso pra mim?
EDITAR:
Depois de muito mais pesquisa, acho que a desconexão aqui é que um padrão de Repositório puro é diferente do que a maioria das pessoas pensa que um Repositório é.
Fowler define um repositório como um armazenamento de dados que usa semântica de coleção e geralmente é mantido na memória. Isso significa criar um gráfico de objeto inteiro.
Evans altera o Repositório para incluir Raízes Agregadas e, portanto, o repositório é amputado para suportar apenas os objetos em um Agregado.
A maioria das pessoas parece pensar nos repositórios como objetos de acesso a dados glorificados, onde você apenas cria métodos para obter os dados que deseja. Essa não parece ser a intenção, conforme descrito em Patterns of Enterprise Application Architecture de Fowler.
Outros ainda pensam em um repositório como uma abstração simples usada principalmente para facilitar testes e zombarias, ou para desacoplar a persistência do resto do sistema.
Acho que a resposta é que esse é um conceito muito mais complexo do que eu pensava.
fonte
Respostas:
Não use seu Modelo de Domínio e agregados para consulta.
De fato, o que você está perguntando é uma pergunta bastante comum e foi estabelecido um conjunto de princípios e padrões para evitar exatamente isso. É chamado CQRS .
fonte
Lutei e ainda estou lutando com a melhor maneira de usar o padrão de repositório em um Design Orientado a Domínio. Depois de usá-lo agora pela primeira vez, criei as seguintes práticas:
Um repositório deve ser simples; é responsável apenas por armazenar objetos de domínio e recuperá-los. Toda outra lógica deve estar em outros objetos, como fábricas e serviços de domínio.
Um repositório se comporta como uma coleção como se fosse uma coleção de raízes agregadas na memória.
Um repositório não é um DAO genérico, cada repositório tem sua interface exclusiva e estreita. Um repositório geralmente possui métodos de busca específicos que permitem pesquisar a coleção em termos de domínio (por exemplo: dê-me todos os pedidos abertos para o usuário X). O próprio repositório pode ser implementado com a ajuda de um DAO genérico.
Idealmente, os métodos localizadores retornarão apenas raízes agregadas. Se isso for ineficiente, ele também poderá retornar objetos de valor somente leitura que contenham exatamente o que você precisa (embora seja uma vantagem se esses objetos de valor também puderem ser expressos em termos de domínio). Como último recurso, o repositório também pode ser usado para retornar subconjuntos ou coleções de subconjuntos de uma raiz agregada.
Escolhas como essas dependem das tecnologias usadas, pois você precisa encontrar uma maneira de expressar com mais eficiência seu modelo de domínio com as tecnologias usadas.
fonte
Eu não acho que seu método GetOrderHeaders derrote o objetivo do repositório.
O DDD está preocupado (entre outras coisas) em garantir que você obtenha o que precisa por meio da raiz agregada (você não teria um OrderDetailsRepository, por exemplo), mas isso não o limita da maneira que você está mencionando.
Se um OrderHeader é um conceito de Domínio, você deve defini-lo como tal e ter os métodos de repositório apropriados para recuperá-los. Apenas certifique-se de estar passando pela raiz agregada correta ao fazê-lo.
fonte
Meu uso do DDD pode não ser considerado DDD "puro", mas adaptei as seguintes estratégias do mundo real usando o DDD em um armazenamento de dados do banco de dados.
** Você não precisa trazer de volta um agregado inteiro. No entanto, se você quiser mais, peça à raiz, não a algum outro serviço ou repositório. Este é um carregamento lento e pode ser feito manualmente com um carregamento lento e inadequado (injetando o repositório / serviço apropriado na raiz) ou usando um ORM que suporte isso.
No seu exemplo, eu provavelmente forneceria uma chamada de repositório que trouxesse apenas os cabeçalhos dos pedidos se quisesse carregar os detalhes em uma chamada separada. Observe que, ao termos um "OrderHeader", estamos realmente introduzindo um conceito adicional no domínio.
fonte
Seu modelo de domínio contém sua lógica de negócios em sua forma mais pura. Todos os relacionamentos e operações que suportam operações de negócios. O que está faltando em seu mapa conceitual é a idéia da Camada de Serviço de Aplicativo, a camada de serviço envolve o modelo de domínio e fornece uma visão simplificada do domínio comercial (uma projeção, se você desejar) que permite que o modelo de Domínio seja alterado conforme necessário sem impactar diretamente os aplicativos usando a camada de serviço.
Indo além. A ideia do agregado é que exista um objeto, a raiz agregada, responsável por manter a consistência do agregado. No seu exemplo, o pedido seria responsável por manipular suas linhas de pedido.
Para o seu exemplo, a camada de serviço exporia uma operação como GetOrdersForCustomer que retornaria apenas o necessário para exibir uma lista resumida dos pedidos (como você os chama OrderHeaders).
Finalmente, o padrão de repositório não é apenas uma coleção, mas também permite consultas declarativas. No C #, você pode usar o LINQ como objeto de consulta , ou a maioria dos outros O / RMs também fornece uma especificação de objeto de consulta.
Como você pode criar consultas no repositório, também faz sentido fornecer métodos de conveniência que lidam com consultas comuns. Ou seja, se você quiser apenas os cabeçalhos do seu pedido, poderá criar uma consulta que retorne apenas o cabeçalho e expô-lo a partir de um método de conveniência em seus repositórios.
Espero que isso ajude a esclarecer as coisas.
fonte
Sei que essa é uma pergunta antiga, mas parece que cheguei a uma resposta diferente.
Quando eu faço um Repositório, ele geralmente envolve algumas consultas em cache .
Mantenha esses repositórios em seus servidores ram. Eles não passam apenas objetos para o banco de dados!
Se eu estiver em um aplicativo Web com pedidos de listagem de páginas, nos quais você pode clicar para ver detalhes, é provável que eu queira que minha página de listagem de pedidos tenha detalhes sobre os pedidos (ID, Nome, Valor, Data) para ajudar um usuário a decidir para qual deles deseja procurar.
Neste ponto, você tem duas opções.
Você pode consultar o banco de dados e recuperar exatamente o que precisa para fazer a listagem e, em seguida, consultar novamente para obter os detalhes individuais que você precisa ver na página de detalhes.
Você pode fazer 1 consulta que retira todas as informações e as armazena em cache. Na próxima página, solicite a leitura dos servidores ram em vez do banco de dados. Se o usuário responder ou selecionar a próxima página, você ainda não fará nenhuma viagem ao banco de dados.
Na realidade, como você implementa é exatamente isso e detalhes da implementação. Se meu maior usuário tiver 10 pedidos, provavelmente eu quero ir com a opção 2. Se estou falando de 10.000 pedidos, a opção 1 é necessária. Nos dois casos acima e em muitos outros casos, quero que o repositório oculte esses detalhes de implementação.
A partir de agora, se eu receber um ticket para informar ao usuário quanto gastaram em pedidos ( dados agregados ) no último mês na página de listagem de pedidos, prefiro escrever a lógica para calcular isso no SQL e fazer mais uma ida e volta para o banco de dados ou você prefere calculá-lo usando os dados que já estão nos servidores ram?
Na minha experiência, os agregados de domínio oferecem enormes benefícios.
fonte