Pergunta

Uma parte do Domain-Driven Design que não parece ser um monte de detalhes sobre, é como e por que você deve isolar seu modelo de domínio do seu interface. Estou tentando convencer meus colegas que esta é uma boa prática, mas eu não parecem estar fazendo muito progresso ...

Eles usam entidades de domínio onde quer que eles agradam nas camadas de apresentação e de interface. Quando eu discutir a eles que eles deveriam estar usando modelos de monitores ou DTOs para isolar a camada de domínio da camada de interface, eles respondem que eles não vêem o valor do negócio em fazer algo assim, porque agora você tem um objeto de UI para manter bem como o objecto de domínio original.

Então, eu estou procurando por algumas razões concretas que posso usar para fazer isso. Especificamente:

  1. Por que não devemos usar objetos de domínio em nossa camada de apresentação?
    (Se a resposta é o óbvio, 'dissociação', então por favor explicar por que isso é importante neste contexto)
  2. Será que devemos usar objetos ou construções adicionais para isolar os nossos objetos de domínio da interface?
Foi útil?

Solução

Muito simplesmente, a razão é um dos implementação e deriva. Sim, a sua camada de apresentação precisa saber sobre o seu negócio objetos para ser capaz de representá-los corretamente. Sim, inicialmente, parece que existe uma grande quantidade de sobreposição entre a implementação dos dois tipos de objetos. O problema é que, como o tempo passa, as coisas são adicionados em ambos os lados. alterações de apresentação, e as necessidades do evoluir camada de apresentação para incluir coisas que são completamente independente de sua camada de negócios (cor, por exemplo). Enquanto isso, seu domínio objetos mudança ao longo do tempo, e se você não tem dissociação apropriado da sua interface, você corre o risco de estragar a sua camada de interface, fazendo mudanças aparentemente benignos aos seus objetos de negócios.

Pessoalmente, acredito que a melhor maneira de abordar as coisas é através do paradigma de interface estritamente aplicadas; isto é, a sua camada de objeto de negócios expõe uma interface que é a única maneira que ele pode ser comunicado com; não há detalhes de execução (isto é, objectos de domínio) sobre a interface estão expostos. Sim, isso significa que você tem que implementar objetos seu domínio em dois locais; sua camada de interface e na sua camada BO. Mas isso reimplementação, enquanto ele pode inicialmente parecer um trabalho extra, ajuda a reforçar a dissociação que vai economizar toneladas de trabalho em algum momento no futuro.

Outras dicas

Tenho lutado com isso mesmo. Há casos em que um DTO faz sentido usar em presentaton. Vamos dizer que eu quero mostrar um drop down de Empresas no meu sistema e eu preciso de sua ID para vincular o valor a.

Bem em vez de carregar um CompanyObject que pode ter referências a subscrições ou quem sabe o que mais, eu poderia enviar de volta um DTO com o nome e id. Esta é uma IMHO bom uso.

Agora pegue um outro exemplo. Eu tenho um objeto que representa uma estimativa, esta estimativa pode ser feita de trabalho, equipamentos etc, pode ter lotes de cálculos que são definidos pelo usuário que tomar todos esses itens e resumi-los (Cada estimativa poderia ser diferente com diferentes tipos de cálculos). Por que eu deveria ter para modelar este objeto duas vezes? Por que não posso simplesmente ter o meu enumerate UI ao longo dos cálculos e exibi-los?

Eu geralmente não usam DTO de isolar a minha camada de domínio de minha UI. Eu faço usá-los para isolar minha camada de domínio a partir de um limite que está fora do meu controle. A ideia de que alguém iria colocar informações de navegação em seu objeto de negócios é ridículo, não contaminem o seu objeto de negócios.

A idéia de que alguém iria colocar validação em seu objeto de negócios? Bem, eu digo que isso é uma coisa boa. Seu UI não deve ser a única responsabilidade para validar seus objetos de negócios. Sua camada de negócios deve fazer sua própria validação.

Por que você colocar código de geração de interface do usuário em um objeto busienss? No meu caso eu tenho objetos separados que gera a seperatley código UI do UI. Eu tenho objetos sperate que tornam meus objetos de negócios em XML, a idéia de que você tem que separar suas camadas para evitar este tipo de contaminação é tão estranho para mim, porque por que você iria mesmo colocar código de geração de HTML em um objeto de negócios ...

Editar Como eu acho que um pouco mais, há casos em que informações UI pode pertencem à camada de domínio. E isso pode obscurecer o que você chama uma camada de domínio, mas eu trabalhei em uma aplicação multi-tenant, que teve um comportamento muito diferente tanto olhar UI e sentir e fluxo de trabalho funcional. Dependendo de vários fatores. Neste caso, tivemos um modelo de domínio que representava os inquilinos e sua configuração. A sua configuração aconteceu para incluir informações UI (de etiqueta para os campos genéricos, por exemplo).

Se eu tivesse que criar meus objetos para torná-los persistente, deve também tenho que duplicar os objetos? Tenha em mente se você quiser adicionar um novo campo agora você tem dois lugares para adicioná-la. Talvez isso levanta outra questão se o seu usando DDD, são todos persistiu objetos de domínio entidades? Eu sei que no meu exemplo que eram.

Você faz isso pela mesma razão que você mantenha SQL fora de suas páginas ASP / JSP.

Se você manter apenas um domínio objeto, para uso na camada de apresentação e de domínio, em seguida, que um objeto começa logo monolítica. Ele começa a incluir o código UI validação, código de navegação UI, e código de geração UI. Então, em breve você adicionar todos os métodos da camada de negócios em cima disso. Agora sua camada de negócios e UI estão todos misturados, e todos eles estão brincando na camada de entidade de domínio.

Você deseja reutilizar esse widget UI bacana em outro aplicativo? Bem, você tem que criar um banco de dados com este nome, estes dois esquemas, e estes 18 mesas. Você também deve configurar o Hibernate e Spring (ou suas estruturas de escolha) para fazer a validação de negócios. Oh, você também deve incluir esses 85 outras classes não-relacionados porque eles são referenciados na camada de negócios, o que só acontece de ser no mesmo arquivo.

Eu discordo.

Eu acho que a melhor maneira de ir é começar com objetos de domínio em sua camada de apresentação até que faz sentido para fazer o contrário.

Ao contrário da crença popular, "objetos de domínio" e "Value Objects" lata feliz co-existir na camada de apresentação. E esta é a melhor maneira de fazê-lo - você recebe o benefício de ambos os mundos, duplicação reduzida (e código clichê) com os objetos de domínio; ea alfaiataria e conceitual simplificação do uso de valor objetos através de pedidos.

Estamos usando o mesmo modelo no servidor e no ui. E é uma dor. Temos que refatorar-lo algum dia.

Os problemas são principalmente porque o modelo de domínio precisa ser cortado em pedaços menores para ser capaz de serializar-lo sem ter todo o banco de dados referenciado. Isso torna mais difícil de usar no servidor. links importantes estão faltando. Alguns tipos também não são serializáveis ??e não pode ser enviado para o cliente. Por exemplo 'Tipo' ou qualquer classe genérica. Eles precisam ser não-genérico e Tipo precisa ser transferido como string. Isso gera propriedades extras para serialização, eles são redundantes e confusas.

Outro problema é que as entidades na UI realmente não se encaixam. Estamos usando ligação de dados e muitas entidades têm muitas propriedades redundantes unicamente para fins de ui. Além disso, há muitos 'BrowsableAttribute' e outros no modelo de entidade. Isso é muito ruim.

No final, eu acho que é apenas uma questão de que maneira é mais fácil. Não pode por projetos em que ele só funciona bem e onde há necessidade de escrever um outro modelo DTO.

Resposta depende escala de sua aplicação.


CRUD simples (Create, Read, Update, Delete) aplicativo

Para aplicações básicas CRUD você não tem nenhuma funcionalidade. Adicionando DTO em cima de entidades woudl ser um desperdício de tempo. Seria aumentar a complexidade sem aumentar a escalabilidade.

enter descrição da imagem aqui


Moderadamente complicado aplicativo não-CRUD

Neste tamanho de aplicação que você terá poucas entidades que têm verdadeira lifeclycle e alguma lógica de negócios associados a eles.

Adicionando DTOs sobre este caso é uma boa idéia para alguns motivos:

  • Apresentação camada só podem ver subconjunto de campos que entidade tem. Você encapsular Entidades
  • No acoplamento entre backend e frontent
  • Se você tiver métodos de negócio dentro entidades, mas não em DTO em seguida, adicionando DTOs significa que o código do lado de fora não podem estado ruína de sua entidade.

enter descrição da imagem aqui


Complicated Enterprise Application

única entidade pode precisar de múltiplas formas de apresentação. Cada um deles terá conjunto diferente de campos. Neste caso você encontrar os mesmos problemas como no exemplo anterior mais precisa quantidade de campos visíveis para cada cliente controle. Tendo DTO separado para cada cliente irá ajudá-lo a escolher o que deve ser visível.

enter descrição da imagem aqui

Trata-se de dependências para a maior parte. A estrutura funcional núcleo da organização tem suas próprias exigências funcionais, ea interface do usuário deve permitir que as pessoas para modificar e visualizar o núcleo; mas o próprio núcleo não deve ser necessário para acomodar a interface do usuário. (Se ele precisa acontecer, é geralmente uma indicação do núcleo não é propriedade projetado.)

O meu sistema de contabilidade tem uma estrutura e conteúdo (e dados) que são supostamente para modelar o funcionamento da minha empresa. Essa estrutura é real e existe independentemente de qual software de contabilidade uso I. (Inevitavelmente um determinado pacote de software contém estrutura e conteúdo para seu próprio bem, mas parte do desafio é minimizar essa sobrecarga.)

Basicamente, uma pessoa tem um trabalho a fazer. A DDD deve coincidir com o fluxo eo conteúdo do trabalho. DDD é sobre fazer explícitas todas as tarefas que precisam ser ad feito totalmente e de forma independente quanto possível. Em seguida, a UI espero que facilita a começar o trabalho feito tão transparente quanto possível, da forma mais produtiva possível.

Interfaces são sobre as entradas e vistas fornecidos para o núcleo funcional adequadamente modelada e invariante.

Droga, eu jurar este disse persistência.

De qualquer forma, é mais um exemplo da mesma coisa: a lei de Parnas diz um módulo deve manter um segredo, eo segredo é uma exigência que pode mudar. (Bob Martin tem uma regra que uma outra versão desta.) Em um sistema como este, a apresentação pode mudar independentemente da domínio . Tais como, por exemplo, uma empresa que mantém os preços em Euros e usa francês nos escritórios da empresa, mas quer preços atuais em dólares com texto em mandarim. O domínio é o mesmo; a apresentação pode mudar. Assim, para minimizar a fragilidade do sistema - isto é, o número de coisas que devem ser mudadas para implementar uma mudança nos requisitos -. Você separar as preocupações

A sua apresentação pode referência sua camada de domínio, mas não deve haver nenhuma ligação diretamente de sua interface de usuário para seus objetos de domínio. objetos de domínio não são destinados para uso UI, uma vez que são muitas vezes, se devidamente projetado, com base em torno de comportamentos e não representações de dados. Deve haver uma camada de mapeamento entre a interface do usuário eo domínio. MVVM, ou MVP, é um bom padrão para isso. Se você tentar diretamente vincular sua interface do usuário para o domínio, você vai probalby criar um monte de dor de cabeça para si mesmo. Eles têm duas finalidades diferentes.

Talvez você não está conceituar a camada de interface do usuário em termos bastante amplos. Pense em termos de múltiplas formas de resposta (páginas web, resposta de voz, letras impressas, etc.) e em termos de múltiplos idiomas (Inglês, Francês etc.).

Agora, suponha que o mecanismo de fala para o sistema de telefonia chamada em corridas em um tipo completamente diferente de computador (Mac, por exemplo) a partir do computador que executa o site (Windows talvez).

Claro que é fácil cair na armadilha "Bem, na minha empresa que só se preocupam com Inglês, executar o nosso website em LAMP (Linux, Apache, MySQL e PHP) e todo mundo usa a mesma versão do Firefox". Mas o que dizer em 5 ou 10 anos?

Veja também a seção "propagação de dados entre as camadas" no seguinte, que eu acho que apresenta argumentos convincentes:

http: // galáxia .andromda.org / docs / AndroMDA-documentação / AndroMDA-getting-started-java / java / index.html

Com a ajuda da ferramenta como ' Valor injecter ' eo conceito de 'Mappers' na camada de apresentação ao trabalhar com pontos de vista, é muito mais fácil de entender cada pedaço de código. Se você tem um pouco de código, você não vai ver as vantagens imediatamente, mas quando o projeto vai crescendo mais e mais, você vai ser muito feliz ao trabalhar com os pontos de vista para não ter que entrar na lógica dos serviços, repositórios de entender o modelo de vista. Model View é um outro guarda no vasto mundo da camada anti-corrupção e vale seu peso em ouro em um projeto de longo prazo.

A única razão pela qual eu não vejo nenhuma vantagem de usar modelo de vista é se o seu projeto é bastante pequena e simples têm vista binded diretamente para cada propriedade do seu modelo. Mas se no futur, a mudança de requisitos e alguns controles nos pontos de vista não será binded ao modelo e você não tem um conceito vista do modelo, você vai começar a adicionar manchas em muitos lugares e você vai começar a ter um código legado que você não vai gostar. Claro, você pode fazer algumas refatoração para transformar seu viewmodel na visualização de viewmodel e siga o princípio de YAGNI enquanto não adicionar o código se você não precisa dele, mas para mim, é muito mais uma prática recomendada que devo seguir para adicionar um camada de apresentação expondo Somente para exibição do modelo objetos.

Aqui está um verdadeiro exemplo de por que acho que é uma boa prática para entidades de domínio separadas do ponto de vista.

Há alguns meses atrás eu criei uma interface simples para mostrar os valores de nitrogênio, fósforo e potássio em uma amostra de solo através de uma série de 3 medidores. Cada indicador tinha uma seção vermelha, verde e vermelho, ou seja, você poderia ter muito pouco ou demasiado de cada componente, mas não havia um nível verde segura no meio.

Sem pensar muito, eu modelei minha lógica de negócios para fornecer dados para estes 3 componentes químicos e uma folha de dados em separado, contendo dados sobre os níveis aceitos em cada um dos 3 casos (incluindo qual unidade de medida estava sendo usado, ou seja, moles ou percentagem). Eu, então, modelada minha UI usar um modelo muito diferente, esse modelo estava preocupado com rótulos calibre, valores, valores de limite e cores.

Isto significava quando eu mais tarde teve que mostrar 12 componentes, eu só mapeados os dados extras em 12 novos modelos de exibição calibre e que apareceu na tela. Também significava que eu poderia reutilizar o controle calibre facilmente e tê-los exibir outros conjuntos de dados.

Se eu tinha acoplado estes indicadores diretamente nos meus entidades de domínio, eu não teria qualquer da flexibilidade acima e quaisquer modificações futuras seria uma dor de cabeça. Eu me deparei com questões muito semelhantes ao modelar calendários na interface do usuário. Se houver um requisito para um compromisso do calendário a ficar vermelho quando há 10+ participantes, em seguida, a lógica de negócios para lidar com isso deve permanecer na camada de negócios e todo o calendário nas necessidades de interface do usuário para saber, é que ele foi instruído a fica vermelho, não deve precisa saber o porquê.

A única razão sensata para adicionar mapeamento adicional entre semântica generalizadas e específicas de domínio é que você tem (acesso a) um corpo existente de código (e ferramentas) que são baseados em uma generalizada (mas mappable) semântica distinta da sua semântica de domínio .

projetos Domain Driven funcionam melhor quando usado em conjunto com um conjunto ortogonal de quadros de domínio funcional (como ORM, GUI, Workflow, etc.). Lembre-se sempre que é somente nas adjacências camada externa que a semântica de domínio precisam ser expostos. Tipicamente, isto é a extremidade dianteira (GUI) e de back-end persistente (RDBM, ORM). Quaisquer camadas intervenientes efectivamente concebidas pode e deve ser invariante domínio.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top