A “Inversão de Controle” promove o “Modelo de Domínio Anêmico”?


32

Quando usei o IoC Container no meu último projeto, acabei com entidades anêmicas e com a maior parte da minha lógica de negócios no Stateless Services.

Eu já vi projetos escritos por outros desenvolvedores que utilizam "Inversion of Control" e eles são sempre "Anêmicos".

Como o "Modelo de Domínio Anêmico" é antipadrão, é possível usar IoC e Rich Domain? São alguns bons exemplos, projetos de código aberto que fazem isso?


Acho que precisaríamos ver alguns exemplos específicos do seu caso em particular para ajudar.
Martijn Verburg

1
Desculpe, eu quis dizer trechos de código :)
Martijn Verburg

Respostas:


11

Para iniciantes: DI e IoC não são sinônimos. Sinto muito, mas devo salientar isso (parece-me que você pensa que são).

Quanto à sua pergunta ... Bem, injeção de dependência é apenas uma ferramenta. Como você vai usar essa ferramenta é uma coisa completamente separada. Existem também outras ferramentas (padrões de design) que podem resultar no problema. Por exemplo, acho que a ampla adoção do padrão MVC é um dos principais ingredientes para formar o antipadrão do Modelo de Domínio Anêmico: Controladores (em aplicativos mais simples, em aplicativos mais complicados que seriam Camada de Serviço adicional) assumem a responsabilidade de validar regras de negócios , aplicando-as e transformando entidades de banco de dados em algo útil, enquanto a Camada de negócios se transforma em uma Camada de acesso a dados simples que é ORM simples com mapeamento individual para entidades de banco de dados.

Certamente, é assim que você cria seu aplicativo - você pode criar um Modelo de Domínio correto, se quiser, e todos esses IoC, DI, MVC não o impedem. O que poderia parar você é sua equipe. De alguma forma, você precisa convencê-los a usar o caminho certo e pode ser difícil, pois muitos desenvolvedores de software não possuem um forte histórico arquitetural.


Acrescentarei a isso que talvez você possa dar uma olhada na abordagem DDD adotada por Eric Evans et al.
Martijn Verburg

1
Eu li o livro de Eric Evans. É bom para metodologia geral e linguagem onipresente, mas falta um pouco nos exemplos do mundo real.
Mag20

Obrigado por apontar a diferença entre DI e IoC. Acho que o problema tinha mais a ver com IoC do que com DI. A pergunta foi alterada para refletir isso.
Mag20

Na minha experiência com frameworks de DI / contentores (Primavera DI, CDI, Unidade), eles realmente não impedi-lo de criar um "modelo de domínio correto", o que para mim significa que os desenvolvedores não devem ser restringidas de usar verdadeiros (ou seja, stateful) objetos . Mas o DI realmente não suporta isso.
Rogério

8

A maioria dos aplicativos (se não todos) é uma mistura de preocupações de infraestrutura e domínio. Quando você alcança um certo nível de complexidade, facilita o gerenciamento se o domínio estiver separado da infraestrutura, para que seja mais fácil raciocinar e possa evoluir independentemente.

É claro que o modelo de domínio ainda precisa se comunicar com o restante do sistema e, geralmente, isso ocorrerá com serviços sem estado (que fazem parte do domínio) que têm problemas de infraestrutura (como acesso ao banco de dados) injetados neles. O uso de um contêiner de IoC não remove essa dependência, ele move sua configuração para uma área separada - novamente facilitando o raciocínio e a manutenção.

As entidades estão armazenando o estado e devem ser responsáveis ​​pelas regras de negócios. Se seus serviços estão aplicando todos os invariantes e outras regras de negócios, é provável que a lógica esteja no lugar errado.

Agora, se você tem a lógica nos lugares certos e ainda assim acabou com serviços que não passam de invólucros em torno de coisas e entidades de infraestrutura que são apenas itens de propriedade, é muito provável que o domínio não seja complexo o suficiente para justificar a sobrecarga de seu próprio modelo. Qualquer coisa que você ler sobre o DDD conterá um aviso de isenção de responsabilidade que realmente é destinado apenas a domínios complexos, mas isso parece ser esquecido com muita frequência.


7

Vá para a fonte. Comece com a peça de Fowler sobre os modelos de domínio anêmico . Ele refere o Domain Driven Design de Eric Evan como um exemplo de boas práticas. O código fonte para isso está aqui . Baixe.

Observe que ele usa Inversion of Control (procure por @Autowired) e possui classes de serviço (BookingService) e classes de "processo de negócios" (por exemplo, ItineraryUpdater).

O artigo original de Fowler inicia a trilha para o exemplo que você está procurando.


Na verdade, esse aplicativo de exemplo não está de acordo com o DDD, conforme descrito no livro. Uma contradição específica com o livro é que ele viola totalmente o conceito de "infraestrutura", permitindo que ele contenha código específico do domínio; por exemplo, a VoyageRepositoryHibernateclasse, que foi colocada na camada de infraestrutura, mas na verdade depende da camada de domínio.
Rogério

Sim, o livro diz na página 73 que a camada de infraestrutura está "abaixo" da camada de domínio e "não deve ter nenhum conhecimento especial do domínio que está servindo". Isso nunca fez sentido para mim. Considere um projeto que possui duas implementações VoyageRepository: VoyageRepositoryHibernate e uma classe VoyageRepositoryJDBC. Suas implementações são necessariamente muito diferentes e específicas da tecnologia. Eles pertencem à camada de domínio? Ou a camada de infraestrutura? Em nosso código, de acordo com o livro, fazemos isso ao contrário: a camada de infraestrutura pode fazer referência à camada de domínio, mas não vice-versa.
51316 jamie

Eles pertencem à camada de domínio, sim. A implementação baseada em JDBC conteria código SQL vinculado a tabelas e colunas no banco de dados do aplicativo, que são específicas para o domínio. Colocar qualquer código específico de domínio ou aplicativo na camada de infraestrutura está errado, pois o "código de infraestrutura" deve ser usado apenas para solucionar problemas técnicos e deve (idealmente) ser totalmente reutilizável entre aplicativos e domínios diferentes. A solução para ter código de "baixo nível" (por exemplo, SQL) na camada de domínio não é movê-lo completamente, mas implementá-lo sobre uma infraestrutura melhor, como ORM.
Rogério

Para mim, a implementação do save (MyDomainObject foo) é uma preocupação puramente técnica. YMMV.
Jamie

Somente se isso não o levar a violar a regra fundamental de uma arquitetura em camadas: uma camada inferior não poderá depender de uma camada superior. Portanto, se você implementou save(foo)com código que está sujeito a alterações quando o modelo de domínio é alterado (por exemplo, se um novo atributo é adicionado a MyDomainObject), ele deve (por definição) pertencer à camada de domínio; caso contrário, você não poderá mais falar em ter "camadas".
Rogério

7

é possível usar IoC e Rich Domain? São alguns bons exemplos, projetos de código aberto que fazem isso?

Suponho que você queira dizer DI em vez de IoC, e o projeto em que você trabalhou usa um contêiner DI como Spring. A IoC possui dois sabores principais: padrão DI e Locator. Não vejo por que o padrão Locator deve ser um problema, então vamos nos concentrar no DI.

Não acho que seja possível, ou pelo menos seria muito impraticável. O principal aspecto dos contêineres DI é que eles controlam a criação de objetos quando os injetam em outros ("objetos gerenciados"). O conjunto de objetos gerenciados ativos quando os projetos são executados é independente de quais itens de domínio existem no seu projeto, mas depende de como os objetos são conectados e quais escopos (singleton, protótipo) são atribuídos a eles.

É por isso que você não deseja permitir que o contêiner de DI gerencie seus objetos de domínio. Mas se você criar objetos manualmente (com o novo), não poderá injetar outros objetos nos objetos do seu domínio. (Deixando possíveis soluções alternativas com a fiação manual de lado.) Como você precisa dessas injeções para substituir implementações por outras, não é possível substituir a funcionalidade de objetos de domínio avançado usando DI. Portanto, você não desejará colocar a funcionalidade em objetos de domínio ou perderá os recursos do DI.

Não vejo como poderia funcionar um contêiner de DI hipotético que não gerencia seus objetos, e nenhuma das implementações existentes permite isso. Portanto, é justo afirmar que o DI depende do gerenciamento de objetos. Portanto, sempre tentará que você divida objetos em potencial do Rich Domain em uma classe anêmica e em uma ou várias classes de scripts de transação.


Essa resposta realmente atinge a cabeça quando se trata da tensão entre um Modelo de Domínio Rico e a Injeção de Dependência.
precisa saber é
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.