¿La "Inversión de control" promueve el "Modelo de dominio anémico"?

32

Cuando utilicé IoC Container en mi último proyecto, terminé con entidades anémicas y la mayor parte de mi lógica de negocios en Servicios sin estado.

He visto proyectos escritos por otros desarrolladores que utilizan "Inversión de control" y siempre están "anémicos".

Dado que el "Modelo de dominio anémico" es antipatrón, ¿es posible usar IoC y Rich Domain? ¿Son buenos ejemplos, proyectos de código abierto que hacen eso?

Mag20
fuente
Creo que necesitaríamos ver algunos ejemplos específicos de su caso particular para ayudar.
Martijn Verburg
1
Lo siento, quise decir fragmentos de código :)
Martijn Verburg

Respuestas:

11

Para empezar: DI e IoC no son sinónimos. Lo siento, pero debo señalarlo (me parece que crees que lo son).

En cuanto a su consulta ... Bueno, la inyección de dependencia es solo una herramienta. Cómo va a utilizar esta herramienta es algo completamente diferente. También hay otras herramientas (patrones de diseño) que podrían agregarse al problema. Por ejemplo, creo que la adopción generalizada del patrón MVC es uno de los ingredientes clave para formar el antipatrón del modelo de dominio anémico: los controladores (en aplicaciones más simples, en aplicaciones más complicadas que serían una capa de servicio adicional) asumen la responsabilidad de validar las reglas comerciales , imponiéndolos y transformando las entidades de base de datos en algo útil, mientras que Business Layer se convierte en simple Data Access Layer que es ORM simple con mapeo uno a uno a entidades de bases de datos.

Ciertamente, así es cómo diseña su aplicación: puede crear un modelo de dominio correcto si lo desea, y todos estos IoC, DI, MVC no lo detienen. Lo que podría detenerte es tu equipo. De alguna manera, debe convencerlos de que usen el camino correcto y puede ser difícil ya que muchos desarrolladores de software no tienen una sólida formación arquitectónica.

Paweł Dyda
fuente
Agregaré a esto que quizás podrías echar un vistazo al enfoque DDD adoptado por Eric Evans et al.
Martijn Verburg
1
Leí el libro de Eric Evans. Es bueno para la metodología general y el lenguaje ubicuo, pero de alguna manera carece de ejemplos del mundo real.
Mag20
Gracias por señalar la diferencia entre DI e IoC. Creo que el problema tuvo más que ver con IoC que DI. Cambió la pregunta para reflejar eso.
Mag20
En mi experiencia con los marcos de DI / contenedores (Primavera DI, CDI, la Unidad), que de hecho no le impida la creación de un "modelo de dominio correcto", lo que para mí significa que los desarrolladores no deben ser restringidos de usar verdaderas (es decir, con estado) objetos . Pero DI realmente no apoya eso.
Rogério
8

La mayoría de las aplicaciones (si no todas) son una combinación de problemas de infraestructura y dominio. Cuando alcance un cierto nivel de complejidad, facilitará la administración si el dominio está separado de la infraestructura, de modo que sea más fácil razonar y evolucionar independientemente.

Por supuesto, el modelo de dominio aún necesita comunicarse con el resto del sistema y generalmente será con servicios sin estado (que son parte del dominio) que tienen problemas de infraestructura (como el acceso a la base de datos) inyectados en ellos. El uso de un contenedor de IoC no elimina esta dependencia, mueve su configuración a un área separada, lo que nuevamente hace que sea más fácil razonar y mantener.

Las entidades almacenan el estado y deben ser responsables de las reglas comerciales. Si sus servicios hacen cumplir todas las invariantes y otras reglas comerciales, entonces es probable que la lógica esté en el lugar equivocado.

Ahora, si tiene la lógica en los lugares correctos y aún así ha terminado con servicios que no son más que envoltorios alrededor de cosas de infraestructura y entidades que son solo bolsas de propiedades, entonces es muy probable que el dominio no sea lo suficientemente complejo como para justificar la sobrecarga de su propio modelo. Casi cualquier cosa que lea sobre DDD contendrá un descargo de responsabilidad que en realidad solo está destinado a dominios complejos, pero parece que esto se olvida con demasiada frecuencia.

FinnNk
fuente
7

Ve a la fuente. Comience con la pieza de Fowler en modelos de dominio anémico . Hace referencia al diseño impulsado por dominio de Eric Evan como un ejemplo de buena práctica. El código fuente para eso está aquí . Descargalo.

Observe que usa la Inversión de control (busque @Autowired), y tiene clases de servicio (BookingService) y clases de "proceso de negocio" (por ejemplo, ItineraryUpdater).

El artículo original de Fowler comienza el camino hacia el ejemplo que está buscando.

jamie
fuente
Esa aplicación de muestra, de hecho, no está de acuerdo con DDD como se describe en el libro. Una contradicción específica con el libro es que viola completamente el concepto de "infraestructura", al permitirle contener código específico de dominio; por ejemplo, la VoyageRepositoryHibernateclase, que se colocó en la capa de infraestructura pero que en realidad depende de la capa de dominio.
Rogério
Sí, el libro dice en la página 73 que la capa de infraestructura está "debajo" de la capa de dominio y "no debe tener ningún conocimiento especial del dominio al que sirve". Esto nunca tuvo sentido para mí. Considere un proyecto que tiene dos implementaciones de VoyageRepository: VoyageRepositoryHibernate y una clase VoyageRepositoryJDBC. Sus implementaciones son necesariamente muy diferentes y específicas de la tecnología. ¿Pertenecen a la capa de dominio? ¿O la capa de infraestructura? En nuestro código, según el libro, lo hacemos al revés: la capa de infraestructura puede hacer referencia a la capa de dominio, pero no al revés.
jamie
Pertenecen a la capa de dominio, sí. La implementación basada en JDBC contendría código SQL vinculado a tablas y columnas en la base de datos de la aplicación, que son específicas del dominio. Poner cualquier código específico de dominio o aplicación en la capa de infraestructura es simplemente incorrecto, ya que el "código de infraestructura" solo debe usarse para resolver problemas técnicos, y (idealmente) debe ser completamente reutilizable entre diferentes aplicaciones y dominios. La solución para tener un código de "bajo nivel" (por ejemplo, SQL) en la capa de dominio no es moverlo completamente, sino implementarlo sobre una mejor infraestructura, como ORM.
Rogério
Para mí, la implementación de guardar (MyDomainObject foo) es una preocupación puramente técnica. YMMV.
Jamie
Solo si no te lleva a violar la regla fundamental de una arquitectura en capas: una capa inferior no puede depender de una capa superior. Entonces, si implementó save(foo)con código que está sujeto a cambios cuando cambia el modelo de dominio (por ejemplo, si se agrega un nuevo atributo MyDomainObject), entonces (por definición) debe pertenecer a la capa de dominio; de lo contrario, ya no se puede hablar de tener "capas".
Rogério
7

¿Es posible usar IoC y Rich Domain? ¿Son buenos ejemplos, proyectos de código abierto que hacen eso?

Supongo que te refieres a DI en lugar de IoC, y el proyecto en el que trabajaste usa un contenedor DI como Spring. IoC tiene dos sabores principales: DI y patrón de localización. No veo por qué el patrón Localizador debería ser un problema, así que centrémonos en DI.

No creo que sea posible, o al menos sería muy poco práctico. El aspecto principal de los contenedores DI es que controlan la creación de objetos cuando los inyectan en otros ("objetos administrados"). El conjunto de objetos administrados que está vivo cuando se ejecutan los proyectos es independiente de los elementos de dominio que existen en su proyecto, pero depende de cómo están conectados los objetos y qué ámbitos (singleton, prototipo) se les asignan.

Es por eso que no desea permitir que el contenedor DI administre sus objetos de dominio. Pero si crea objetos manualmente (con nuevo), no puede inyectar otros objetos a sus objetos de dominio. (Dejando a un lado las posibles soluciones alternativas con el cableado manual). Dado que necesita estas inyecciones para reemplazar las implementaciones con otras, no puede reemplazar la funcionalidad de los objetos de dominio enriquecido con DI. Por lo tanto, no querrá colocar la funcionalidad en objetos de dominio, o perderá las características de la DI.

No veo cómo podría funcionar un contenedor DI hipotético que no administra sus objetos, y ninguna de las implementaciones existentes lo permite. Por lo tanto, es justo afirmar que DI se basa en la gestión de objetos. Por lo tanto, siempre tendrá la tentación de dividir los objetos potenciales de Rich Domain en una clase anémica y una o varias clases de script de transacción.

Wolfgang
fuente
Esta respuesta realmente da en el clavo cuando se trata de la tensión entre un modelo de dominio rico y una inyección de dependencia.
jrahhali