Más sobre modelos anémicos

109 views
Skip to first unread message

jcesarperez

unread,
Jan 13, 2011, 2:46:27 PM1/13/11
to Artesanos de Software
Nuestro compañero de lista Alfredo Casado ha escrito un interesante
artículo en su blog sobre modelos anémicos. Además se ha atrevido a
contarnos su opinión sobre el tema usando un código Java como ejemplo.

Como os podéis imaginar ha surgido el debate pertinente en el que a lo
mejor os gustaría participar.

Os dejo el enlace: http://weblogs.javahispano.org/artesanodeprimera/entry/modelos_anemicos1

Un saludo,
Julio.

Alfredo Casado

unread,
Jan 13, 2011, 3:21:17 PM1/13/11
to artesanos-...@googlegroups.com
jeje, si mejor seguimos por aquí el debate que con la limitación de 100 caracteres del blog no hay quien escriba :P

Como dices un ejemplo que implicará persistencia estaría bien, en el código que he puesto sólo muestro el uso de los objetos pero no su construcción, o más bien, reconstrucción, desde la persistencia, a ver si lo puedo esbozar rápido:

public void RepositorioCompras {

     Connection conexionBD;
     RepositorioProductos repositorioProductos;
     FactoriaCompras factoriaCompras; 
 
      public RepositorioCompras(Connection conexionBD, RepositorioProductos repositorioProductos, FactoriaCompras factoriaCompras) {
            this.conexionBD = conexionBD;
            this.repositorioProductos = repositorioProductos;
            this.factoriaCompras = factoriaCompras;
      } 

      Set<Compra> find(CriterioBusqueda criterio) { 
                
                 Set<Compra> comprasQueSeAjustanAlCriterio = new HashSet();

                 Query query = connection.createQuery(criterio.toSqlQueryString());
                 ResultSet result = connection.executeQuery();
                 while(result.next()) {
                         long idCompra = result.getInt("idCompra");
                         Set<Productos> productos = repositorioProductos.productosDeLaCompraConId(idCompra);
                         comprasQueSeAjustanAlCriterio.add(factoriaDeCompras.crearCompra(idCompra,productos));
                 }
                 
                 return comprasQueSeAjustanAlCriterio; 
      }



Algo así, la idea es que el repositorio de compras utiliza la factoría de compras para crear las compras, como para crear las compras necesitas los productos pues usas el repositorio de productos para obtenerlas que será parecido a este y internamente utilizara la factoría de productos. Este tipo de diseño para la persistencia es el que más me encaja con las ideas de DDD y me cuesta bastante encajar esas ideas con un ORM. (por supuesto me he saltado todo el control de excepciones, tampoco cierro nada, es un boceto :P).

Otra cosa, en este ejemplo considero que hay un agregado cuya raíz es compra y productos esta dentro, esto quizá no sería muy correcto porque producto tiene más bien pinta de entidad, así que en lugar de esto debería construir la compra pasandole el repositorio de productos, vamos es como hacer lazy loading o eager loading con un orm pero manualmente, quizá algo más costoso pero con más control de lo que estas haciendo. También se podría tener una opción en el repositorio de compra para leerlas en modo eager/lazy...

Otra cosa que me gusta de este enfoque es que los objetos siempre los construyo a través de las factorías, es decir, yo controlo el ciclo de vida y no el ORM, de esta manera no hay ningún problema para poner los colaboradores que haga falta en el objeto sin los malabarismos que hay que hacer con AOP usando spring/hibernate.

Con un api de acceso a datos un poco más "apañao" que JDBC a pelo (que es puro dolor) no veo la necesidad de un ORM tan complejo y que haga tantas cosas. Aunque también se podría usar, simplemente mapeando clases que estén en la capa de infraestructura usandolas como estructuras de datos y meramente como utilidad para facilitar la lectura de la base de datos. Quizás ese sea el problema que una librería que sólo debería ser una utilidad para facilitar una parte de mi aplicación se convierta en una pieza central de la misma y condicione tanto un diseño.

Eduardo Ferrández

unread,
Jan 13, 2011, 4:14:52 PM1/13/11
to artesanos-...@googlegroups.com
En java existe una solución un poco más "apañada" que JDBC sin llegar a ser un ORM. Es Apache DBUtils. Con eso y un poco de reflection puedes automatizar notablemente la persistencia sin necesidad de introducir la complejidad accidental a la que te obligan los ORM.

jcesarperez

unread,
Jan 14, 2011, 8:07:49 AM1/14/11
to Artesanos de Software
Joder cómo te lo has currado!
Aunque en realidad me refería a tener un método de negocio en Compra u
otra entidad nueva que usara un repositorio y no cómo implementas los
repositorios. Eso sí, es todo un placer ver un código tan inspirador y
diferente como el tuyo. Gracias.

No termino de ver eso de usar el ORM para tener clases que equivalen a
tablas (¿también crearías una clase para las tablas de relaciones
N:M?) y luego convertir sus objetos a lo que serian las verdaderas
entidades del modelo. No lo veo porque me sigue pareciendo que las
nuevas entidades del modelo tienen demasiadas responsabilidades. Lo
que te comentaba en el blog: (1) métodos get/set o similares (antes o
después terminas necesitando una buena parte de ellos), (2) equals,
hascode toString y en ocasiones hasta algun compareTo, (3) métodos de
lógica de negocio simple y (4) métodos de lógica de negocio compleja
con acceso a la capa de persistencia.
Llega un momento, cuando la complejidad crece, que te planteas si
realmente es responsabilidad de Compra añadir un producto con la
lógica de negocio que implica validar el stock o restricciones por
tipos de clientes, etc. o si habría que crear una nueva clase
GestorCompra donde mover esa lógica, dejando a Compra sólo el trámite
de asociar el producto siempre que no sea null. Y no creo que esto
convierta al modelo en anémico, sólo estás moviendo responsabilidades
y creando nuevas clases para tener más clases pero más simples y de
mayor cohesión.

Para mi el modelo es realmente anémico cuando tus entidades son sólo
esos get/set y anotaciones orm, mientras que la lógica de negocio la
encuentras dispersa en los controladores de las acciones del usuario.

@Eduardo: DBUtils está muy chulo. Lo he usado en algún proyecto
pequeñito, pero para cosas de mayor tamaño me quedo con el spring-
jdbc.

Saludos.
Julio.
> julio.cesar.perez.arq...@gmail.com> escribió:

Alfredo Casado

unread,
Jan 14, 2011, 10:02:12 AM1/14/11
to artesanos-...@googlegroups.com
lega un momento, cuando la complejidad crece, que te planteas si
realmente es responsabilidad de Compra añadir un producto con la
lógica de negocio que implica validar el stock o restricciones por
tipos de clientes, etc. o si habría que crear una nueva clase
GestorCompra donde mover esa lógica, dejando a Compra sólo el trámite
de asociar el producto siempre que no sea null

Estoy de acuerdo en que el balance de responsabilidades es complicado y puede que estas entidades reciban demasiada responsabilidad en algunos casos. En el ejemplo que comentas, lo que no me gusta del GestorDeCompras es que entoces puedo escribir esto:

Producto productoQueElUsuarioSeleccionaParaComprar = RepositorioDeProductos.porId(...);
Compra.incluirEl(productoQueElUsuarioSeleccionaParaComprar);

y ese código no me asegura que el producto se pueda añadir a la compra, tengo que usar un gestor de compras para poder añadir productos a la compra de forma "segura", en mi opinión despista bastante y la compra debería hacerse responsable de su integridad.

Aunque si que estoy de acuerdo en estas reglas no deberían estar en la clase compra, en lugar de usar un gestor que maneje la compra y el producto lo puedes pensar de otro modo y que la compra utilice un colaborador que sea el que implemente estas reglas, desde la clase compra harías algo como:

public boolean incluirEl(Producto producto) {
       if (!reglasDeInclusionDeProductoEnCompra.puedoIncluirEl(producto)) {
         return false;
       }
       // lo que tengas que hacer para añadir el producto
       return true;
}

Cuando no controlas el ciclo de vida de estas entidades, si es el ORM quien las crea por ejemplo, no te puedes plantear este tipo de cosas porque ¿como le inyectas el colaborador con las reglas de inclusión de productos?. Si tu controlas la creación de tus entidades a través de una factoría puedes hacer lo que quieras y añadirle los colaboradores que consideres necesarios. Por ejemplo, en función del tipo de cliente podrías pasarle una tipo de reglas u otras... 

Aún así tampoco es una solución perfecta, te puedes encontrar fácilmente con que la compra recibe 20 colaboradores si la cargas de responsabilidad. Tienes que vigilar esto y siempre tener presente principios como SOLID y demás para ir moldeando poco a poco tu dominio sin caer en estos problemas, y lo malo es que no hay soluciones, arquitecturas o patrones que se puedan aplicar ciegamente, cada dominio es un mundo. Bueno esto es lo malo, y también es lo bueno jeje, es lo que hace todo esto divertido :P.

Alejandro Cuesta

unread,
Jan 14, 2011, 11:36:19 AM1/14/11
to Artesanos de Software
Alfredo, gracias por ese articulo.
Mejor explicado, imposible!
Chapo!

Alex


On Jan 14, 3:02 pm, Alfredo Casado <casado.alfr...@gmail.com> wrote:
> *lega un momento, cuando la complejidad crece, que te planteas si
> realmente es responsabilidad de Compra añadir un producto con la
> lógica de negocio que implica validar el stock o restricciones por
> tipos de clientes, etc. o si habría que crear una nueva clase
> GestorCompra donde mover esa lógica, dejando a Compra sólo el trámite
> de asociar el producto siempre que no sea null*
> *
> *
> julio.cesar.perez.arq...@gmail.com> escribió:

jcesarperez

unread,
Jan 17, 2011, 2:07:51 AM1/17/11
to Artesanos de Software
> Tienes que vigilar esto y siempre tener presente principios como SOLID y
> demás para ir moldeando poco a poco tu dominio sin caer en estos problemas,
> y lo malo es que no hay soluciones, arquitecturas o patrones que se puedan
> aplicar ciegamente, cada dominio es un mundo. Bueno esto es lo malo, y
> también es lo bueno jeje, es lo que hace todo esto divertido :P.

Cuánta razón tienes Alfredo! Es precisamente ahora, tras años de
experiencia, tras muchos proyectos y compañeros, tras libros y
artículos leidos, tras estudiar nuevas prácticas y metodologías, tras
debates como éste,... cuando más me divierto en mi trabajo y eso que
ya sólo "me dejan" programar un 20% de mi tiempo como mucho.

Un saludo.
Julio.

>
> El 14 de enero de 2011 14:07, jcesarperez <
> julio.cesar.perez.arq...@gmail.com> escribió:
Reply all
Reply to author
Forward
0 new messages