Estou (re) projetando aplicativos em larga escala, usamos arquitetura multicamada baseada em DDD.
Temos MVC com camada de dados (implementação de repositórios), camada de domínio (definição de modelo de domínio e interfaces - repositórios, serviços, unidade de trabalho), camada de serviço (implementação de serviços). Até o momento, usamos modelos de domínio (principalmente entidades) em todas as camadas e usamos DTOs apenas como modelos de exibição (no controlador, o serviço retorna modelos de domínio e o controlador cria um modelo de exibição, que é passado para a exibição).
Já li inúmeros artigos sobre como usar, não usar, mapear e transmitir DTOs. Entendo que não há resposta definitiva, mas não tenho certeza se está tudo bem ou não retornando modelos de domínio de serviços para controladores. Se eu retornar o modelo de domínio, ele ainda nunca será passado para a visualização, pois o controlador sempre cria um modelo de visualização específico da visualização - nesse caso, parece legítimo. Por outro lado, não parece certo quando o modelo de domínio sai da camada de negócios (camada de serviço). Às vezes, o serviço precisa retornar um objeto de dados que não foi definido no domínio e, em seguida, precisamos adicionar um novo objeto ao domínio que não está mapeado ou criar um objeto POCO (isso é feio, pois alguns serviços retornam modelos de domínio, alguns efetivamente retornar DTOs).
A questão é: se usarmos estritamente os modelos de exibição, não há problema em retornar modelos de domínio até os controladores ou devemos sempre usar DTOs para comunicação com a camada de serviço? Em caso afirmativo, é possível ajustar modelos de domínio com base em quais serviços precisam? (Sinceramente, acho que não, pois os serviços devem consumir o domínio que possui.) Se devemos seguir rigorosamente os DTOs, eles devem ser definidos na camada de serviço? (Acho que sim.) Às vezes, fica claro que devemos usar DTOs (por exemplo, quando o serviço executa muita lógica de negócios e cria novos objetos), outras vezes, fica claro que devemos usar apenas modelos de domínio (por exemplo, quando o serviço Membership retorna Usuário anêmico ( s) - parece que não faria muito sentido criar DTO igual ao modelo de domínio) - mas prefiro consistência e boas práticas.
Artigo Domínio vs DTO vs ViewModel - Como e quando usá-los? (e também alguns outros artigos) é muito parecido com o meu problema, mas não responde a essas perguntas. Artigo Devo implementar DTOs no padrão de repositório com EF? também é semelhante, mas não lida com DDD.
Isenção de responsabilidade: não pretendo usar nenhum padrão de design apenas porque existe e é sofisticado; por outro lado, gostaria de usar bons padrões e práticas de design também porque ajuda a projetar o aplicativo como um todo, ajuda na separação de preocupações, mesmo que o uso de determinado padrão não seja "necessário", pelo menos no momento.
Como sempre, obrigado.
fonte
Respostas:
Faz você se sentir como se estivesse puxando as entranhas, certo? De acordo com Martin Fowler: a Camada de Serviço define os limites do aplicativo, encapsula o domínio. Em outras palavras, protege o domínio.
Você pode fornecer um exemplo desse objeto de dados?
Sim, porque a resposta faz parte da sua camada de serviço. Se for definido "em outro lugar", a camada de serviço precisará fazer referência a "outro lugar", adicionando uma nova camada à sua lasanha.
Um DTO é um objeto de resposta / solicitação, faz sentido se você o usar para comunicação. Se você usar modelos de domínio em sua camada de apresentação (MVC-Controllers / View, WebForms, ConsoleApp), a camada de apresentação será fortemente acoplada ao seu domínio, qualquer alteração no domínio exigirá que você altere seus controladores.
Essa é uma das desvantagens do DTO para novos olhos. No momento, você está pensando na duplicação de código , mas à medida que o projeto se expande, isso faria muito mais sentido, especialmente em um ambiente de equipe em que equipes diferentes são atribuídas a diferentes camadas.
O DTO pode adicionar complexidade adicional ao seu aplicativo, mas suas camadas também. O DTO é um recurso caro do seu sistema, eles não são de graça.
Por que usar um DTO
Este artigo fornece vantagens e desvantagens do uso de um DTO, http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html
Resumo da seguinte forma:
Quando usar
Quando não usar
Argumentos contra o DTO
Argumentos com DTO
fonte
Parece que seu aplicativo é grande e complexo o suficiente, pois você decidiu passar pela abordagem DDD. Não retorne suas entidades poco ou as chamadas entidades de domínio e objetos de valor na sua camada de serviço. Se você quiser fazer isso, exclua sua camada de serviço porque não precisa mais dela! Os objetos Exibir modelo ou transferência de dados devem estar na camada Serviço, porque devem ser mapeados para membros do modelo de domínio e vice-versa. Então, por que você precisa ter DTO? Em aplicativos complexos com muitos cenários, você deve separar as preocupações das exibições de domínio e de apresentação, um modelo de domínio pode ser dividido em vários DTO e também vários modelos de Domínio podem ser recolhidos em um DTO. Portanto, é melhor criar seu DTO na arquitetura em camadas, mesmo que seja o mesmo que seu modelo.
Devemos sempre usar DTOs para comunicação com a camada de serviço? Sim, você deve retornar o DTO por sua camada de serviço enquanto conversa com seu repositório na camada de serviço com membros do modelo de domínio e mapeá-los para o DTO e retornar ao controlador MVC e vice-versa.
É possível ajustar modelos de domínio com base em quais serviços precisam? Um serviço apenas fala com métodos e serviços de domínio e repositório, você deve resolver os negócios em seu domínio com base em suas necessidades e não é tarefa do serviço informar ao domínio o que é necessário.
Se devemos seguir rigorosamente os DTOs, eles devem ser definidos na camada de serviço? Sim, tente ter o DTO ou o ViewModel apenas em serviço mais tarde, porque eles devem ser mapeados para membros do domínio na camada de serviço e não é uma boa ideia colocar o DTO nos controladores do seu aplicativo (tente usar o padrão de Resposta de Solicitação na camada de Serviço). !
fonte
Na minha experiência, você deve fazer o que é prático. "O melhor design é o design mais simples que funciona" - Einstein. Com isso é mente ...
Absolutamente tudo bem! Se você possui Entidades de Domínio, DTOs e Modelos de Visualização, incluindo tabelas de banco de dados, todos os campos do aplicativo são repetidos em 4 locais. Trabalhei em grandes projetos nos quais as Entidades de Domínio e os Modelos de Exibição funcionaram bem. A única exceção é se o aplicativo for distribuído e a camada de serviço residir em outro servidor. Nesse caso, os DTOs deverão enviar através da conexão por motivos de serialização.
Geralmente, eu concordo e digo não, porque o modelo de domínio é geralmente um reflexo da lógica de negócios e geralmente não é moldado pelo consumidor dessa lógica.
Se você decidir usá-los, eu concordo e digo que sim, a camada de Serviço é o lugar perfeito, pois retorna os DTOs no final do dia.
Boa sorte!
fonte
Estou atrasado para esta festa, mas essa é uma pergunta tão comum e importante que me senti obrigado a responder.
Por "serviços" você quer dizer a "Camada de Aplicação" descrita por Evan no livro azul ? Suponho que sim, nesse caso a resposta é que eles não devem retornar DTOs. Sugiro a leitura do capítulo 4 do livro azul, intitulado "Isolando o domínio".
Nesse capítulo, Evans diz o seguinte sobre as camadas:
Há uma boa razão para isso. Se você usar o conceito de ordem parcial como uma medida da complexidade do software , ter uma camada depende da camada acima dela aumenta a complexidade, o que diminui a capacidade de manutenção.
Aplicando isso à sua pergunta, os DTOs são realmente um adaptador que é uma preocupação da camada Interface do Usuário / Apresentação. Lembre-se de que a comunicação remota / entre processos é exatamente o objetivo de um DTO (vale a pena notar que, nesse post, Fowler também argumenta que os DTOs fazem parte de uma camada de serviço, embora ele não esteja necessariamente falando a linguagem DDD).
Se sua camada de aplicativo depende desses DTOs, depende de uma camada acima de si mesma e sua complexidade aumenta. Posso garantir que isso aumentará a dificuldade de manutenção do seu software.
Por exemplo, e se o seu sistema fizer interface com vários outros sistemas ou tipos de clientes, cada um exigindo seu próprio DTO? Como você sabe qual DTO deve retornar um método do seu serviço de aplicativo? Como você resolveria esse problema se o seu idioma de escolha não permitir sobrecarregar um método (método de serviço, neste caso) com base no tipo de retorno? E mesmo se você descobrir uma maneira, por que violar sua camada de aplicativos para dar suporte a uma preocupação da camada de apresentação?
Em termos práticos, este é um passo em frente que terminará em uma arquitetura de espaguete. Eu já vi esse tipo de devolução e seus resultados em minha própria experiência.
Onde trabalho atualmente, os serviços em nossa Camada de Aplicativos retornam objetos de domínio. Não consideramos isso um problema, pois a camada Interface (por exemplo, UI / Apresentação) depende da camada Domínio, que está abaixo dela. Além disso, essa dependência é minimizada para um tipo de dependência "apenas referência" porque:
a) a camada de interface só pode acessar esses objetos de domínio como valores de retorno somente leitura obtidos por chamadas para a camada de aplicativo
b) os métodos nos serviços da Camada de Aplicação aceitam como entrada apenas entradas "brutas" (valores de dados) ou parâmetros de objeto (para reduzir a contagem de parâmetros, quando necessário) definidos nessa camada. Especificamente, os serviços de aplicativos nunca aceitam objetos de Domínio como entrada.
A camada de interface usa técnicas de mapeamento definidas na própria camada de interface para mapear dos objetos do domínio para os DTOs. Novamente, isso mantém os DTOs focados em adaptadores controlados pela Camada de Interface.
fonte
Cheguei atrasado à festa, mas estou enfrentando exatamente o mesmo tipo de arquitetura e estou inclinado a “apenas DTOs de serviço”. Isso ocorre principalmente porque eu decidi usar apenas objetos / agregados de domínio para manter a validade dentro do objeto, portanto, somente ao atualizar, criar ou excluir. Quando estamos consultando dados, usamos o EF apenas como repositório e mapeia o resultado para DTOs. Isso nos torna livres para otimizar as consultas de leitura e não adaptá-las aos objetos de negócios, geralmente usando as funções do banco de dados à medida que são rápidas.
Cada método de serviço define seu próprio contrato e, portanto, é mais fácil de manter com o tempo. Eu espero.
fonte
Como o Modelo de Domínio fornece terminologia ( Linguagem Ubíqua ) para toda a sua aplicação, é melhor usar amplamente o Modelo de Domínio.
O único motivo para usar os ViewModels / DTOs é uma implementação do padrão MVC em seu aplicativo para separar
View
(qualquer tipo de camada de apresentação) eModel
(Modelo de Domínio). Nesse caso, sua apresentação e modelo de domínio são fracamente acoplados.Suponho que você fale sobre os serviços de aplicativos / negócios / lógica de domínio.
Sugiro que você retorne entidades de domínio quando puder. Se for necessário retornar informações adicionais, é aceitável retornar o DTO que contém várias entidades de domínio.
Às vezes, as pessoas que usam estruturas de terceira parte, que geram proxies sobre entidades de domínio, enfrentam dificuldades para expor entidades de domínio de seus serviços, mas isso é apenas uma questão de uso incorreto.
Eu diria que é suficiente retornar entidades de domínio em 99,9% dos casos.
Para simplificar a criação de DTOs e mapear suas entidades de domínio para eles, você pode usar o AutoMapper .
fonte
Se você retornar parte do seu modelo de domínio, ele se tornará parte de um contrato. É difícil mudar um contrato, pois as coisas fora do seu contexto dependem dele. Dessa forma, você tornaria difícil alterar parte do seu modelo de domínio.
Um aspecto muito importante de um modelo de domínio é que é fácil mudar. Isso nos torna flexíveis aos requisitos de mudança do domínio.
fonte
Eu sugeriria analisar essas duas perguntas:
Suas camadas superiores (ou seja, exibir e visualizar modelos / controladores) estão consumindo os dados de uma maneira diferente do que a camada de domínio expõe? Se houver muito mapeamento sendo feito ou mesmo lógica, sugiro revisitar seu design: provavelmente deve estar mais perto de como os dados são realmente usados.
Qual a probabilidade de você alterar profundamente suas camadas superiores? (por exemplo, trocando o ASP.NET por WPF). Se isso for altamente diferente e sua arquitetura não for muito complexa, é melhor expor o maior número possível de entidades de domínio.
Receio que seja um tópico bastante amplo e que realmente se refira à complexidade do seu sistema e aos seus requisitos.
fonte
Na minha experiência, a menos que você esteja usando um padrão de interface do usuário OO (como objetos nus), expor os objetos de domínio à interface do usuário é uma má idéia. Isso porque, conforme o aplicativo cresce, as necessidades da interface do usuário são alteradas e forçam seus objetos a acomodar essas alterações. Você acaba servindo 2 mestres: UI e DOMAIN, o que é uma experiência muito dolorosa. Acredite, você não quer estar lá. O modelo de interface do usuário tem a função de se comunicar com o usuário, o modelo DOMAIN para manter as regras de negócios e os modelos de persistência lidam com o armazenamento de dados de maneira eficaz. Todos eles atendem a diferentes necessidades do aplicativo. Estou no meio de escrever uma postagem no blog sobre isso, e a adicionarei quando terminar.
fonte