Uma lógica de filtragem deve estar em um repositório ou em um serviço?

9

Gostaria de saber o seguinte: suponha que estamos construindo um sistema em que precisa haver alguma funcionalidade de filtragem para procurar alguma entidade. Por exemplo, pode-se aplicar a filtragem a uma tabela que lista as entidades para encontrar algo ou usá-lo para gerar um relatório em um conjunto filtrado, qualquer que seja.

O ponto é: precisamos ter uma lógica de filtragem em algum lugar. Uma maneira ruim de fazer isso seria replicar a lógica de filtragem sempre que necessário. Já fiz isso uma vez e é uma péssima ideia.

Por outro lado, acredito que deve haver um método como o Filter(FilteringOptions filteringOptions)projetado para executar a operação de filtragem e retornar a lista filtrada de entidades.

Agora, IMHO, a lógica de filtragem é uma lógica de negócios amável. Os especialistas em negócios são os que sabem como a filtragem ocorre, que coisas são filtradas e como. Por isso, acredito que a lógica de filtragem deve estar localizada na camada de domínio.

Eu encontrei duas opções para fazer isso: incorporar o método de filtragem no repositório correspondente para essa entidade específica ou criar um serviço de domínio como o EntityNameSearchServiceque consumiria o repositório para executar a filtragem.

Ainda estou confuso qual seria o melhor caminho. Então, se estou tentando usar o DDD corretamente, onde essa lógica de filtragem deve estar? No repositório ou em um serviço separado?

user1620696
fonte
2
Onde a lógica de filtragem faz mais sentido para você, do ponto de vista de manutenção e usabilidade?
21716 Robert Harvey
À primeira vista, parecia que no repositório, pois é o objeto responsável por, entre outras coisas, recuperar as entidades. Por outro lado, a lógica de filtragem não precisa ser aplicada apenas na recuperação, pode ser aplicada a qualquer lista de entidades. De fato, pensando um pouco mais sobre isso, a camada de domínio contém apenas as interfaces dos repositórios. A implementação real está em um projeto Data e precisa ser acoplada ao mecanismo de persistência real, enquanto os serviços são implementados no domínio. Desse ponto de vista, a criação de um serviço de filtragem parece fazer mais sentido.
user1620696
1
A filtragem na camada de serviço custará mais tempo do que a obtenção de dados filtrados do repositório por meio de um método direcionado, mas você pode reutilizar o Get*método genérico e introduzir filtros diferentes ou definidos pelo usuário na camada de serviço. A decisão depende principalmente de você.
Andy

Respostas:

4

Gostaria de saber o seguinte: suponha que estamos construindo um sistema em que precisa haver alguma funcionalidade de filtragem para procurar alguma entidade. Por exemplo, pode-se aplicar a filtragem a uma tabela que lista as entidades para encontrar algo ou usá-lo para gerar um relatório em um conjunto filtrado, qualquer que seja.

Você deve observar que, neste ponto, seus casos de uso para filtrar centralizam leituras , em vez de gravações. Esse é o padrão normal - uma gravação geralmente é endereçada a uma raiz agregada específica no seu domínio.

Se você está executando uma leitura, não se importa com agregados - não se importa com a imposição de invariáveis ​​negócios, porque na verdade não está tentando alterar nada. Você só se importa com o estado.

O que pode significar que faz sentido ignorar completamente o modelo de domínio.

Apenas algo para se pensar.

Agora, IMHO, a lógica de filtragem é uma lógica de negócios amável. Os especialistas em negócios são os que sabem como a filtragem ocorre, que coisas são filtradas e como. Por isso, acredito que a lógica de filtragem deve estar localizada na camada de domínio.

Sim e não. Você está utilizando a linguagem onipresente para descrever o filtro. Então você definitivamente está usando o vocabulário do domínio.

Mas você não tem nenhum "comportamento", na medida em que não está realmente modificando o livro de registro, para que não tenha o invariante com que se preocupar.

Por outro lado, acredito que deve haver um método como Filter (FilteringOptions filteringOptions) projetado para executar a operação de filtragem e retornar a lista filtrada de entidades.

Você está muito próximo da idéia de "especificação" . É basicamente um predicado que um repositório pode usar para identificar quais artefatos correspondem a alguns critérios arbitrários.

Existem algumas armadilhas para estar ciente. Greg Young tocou neles algum tempo atrás, mas vou resumir aqui.

Primeiro, a abstração de executar um predicado em uma coleção é O (N). Você provavelmente desejará algo melhor, especialmente se o seu armazenamento de persistência for inteligente quanto à indexação. Seu componente de persistência provavelmente poderá transformá-lo em uma restrição específica de implementação (exemplo: pegar uma especificação e transformá-la em uma cláusula where em uma instrução preparada).

Segundo, uma interface é um meio de documentar o contrato atendido pelo componente de persistência. "Tornar explícito o implícito" - se você descrever o que realmente precisa, a interface informará algo sobre quais características são importantes para o armazenamento de dados, o que fornece um único local para procurar ao tentar avaliar se uma alternativa loja é adequada.

(Obviamente, a implementação dessa interface pode ser apenas um adaptador que cria a especificação a partir dos argumentos do método e a encaminha adiante. Tudo bem, você capturou o requisito real).

VoiceOfUnreason
fonte