domingo, mayo 24, 2009

Modelo de dominio matriarcal (II)

Antes que nada pedir disculpas, especialmente a Julio César Pérez porque hace ya varias semanas que, en la primera parte de este artículo, le prometí que iba a escribir un ejemplo para explicar cómo se implementaba la ignorancia de la persistencia ("persistence ignorance" en inglés) en un modelo de dominio al estilo DDD. Lo cierto es que he visto que me estoy metiendo en tantos fregados (incluídas mis labores familiares cotidianas) que cada día tengo menos tiempo de ponerme a programar con la mínima continuidad necesaria.

Cargo freighter passing under the Golden Gate bridge in San Fransisco. Image courtesy of FreeFoto.com
Bueno, como la respuesta a Julio la tengo más o menos elaborada, voy a utilizar código ajeno para explicarme. A ver si queda suficientemente claro. El código completo está disponible en el ejemplo "oficial" de DDD: DDDSample. Lo podéis bajar desde el repositorio de subversion (yo he utilizado la última versión etiquetada como 1.1.0) o podéis "navegar" por el código fuente coloreado e hipervinculado generado con el plugin maven jxr. Seguramente explicar este ejemplo daría para varios blogs, pero me voy a centrar en la explicación de la persistencia. Si queréis ver los ficheros de configuración de Spring e Hibernate no os quedará más remedio que acceder al SVN. Perdonad que no os hipervincule todas las clases pero ya os he explicado que ando justito de tiempo libre... :-(

Este DDDSample es la implementación del ejemplo empleado por Eric Evans en el libro azul y que se trata de una compañía de transporte de contenedores. Yo voy a seguir el camino de una petición de reserva del envío de un contenedor, que es algo sencillo pero que implica guardar datos en la base de datos. No voy a entrar en cómo se llama desde la UI al servicio para no extenderme demasiado, pues como dije más arriba tenéis todo el código disponible para descargarlo, pero sí que os explicaré (al final) el "truqui" que emplean aquí por si os suena un poco raro.

Todo empieza por una fachada llamada BookingServiceFacadeImpl (que implementa la interfaz BookingServiceFacade y que no sirve para otra cosa que para envolver al "verdadero servicio" (BookingServiceImpl, que implementa BookingService). El constructor de BookingServiceImpl tiene como parámetros un CargoRepository, un LocationRepository y un RoutingService, esto se podría cambiar por un constructor vacío y varios setters, pero siempre y cuando nos aseguremos de no usar BookingService sin antes haber "seteado" estos colaboradores. Por eso es más seguro inyectar los colaboradores imprescindibles en el constructor. En DDDSample se hace con Spring en context-application.xml:









El método que nos interesa es bookNewCargo:


@Override
@Transactional
public TrackingId bookNewCargo(final UnLocode originUnLocode,
final UnLocode destinationUnLocode,
final Date arrivalDeadline) {
// TODO modeling this as a cargo factory might be suitable
final TrackingId trackingId = cargoRepository.nextTrackingId();
final Location origin = locationRepository.find(originUnLocode);
final Location destination = locationRepository.find(destinationUnLocode);
final RouteSpecification routeSpecification = new RouteSpecification(origin, destination, arrivalDeadline);

final Cargo cargo = new Cargo(trackingId, routeSpecification);

cargoRepository.store(cargo);
logger.info("Booked new cargo with tracking id " + cargo.trackingId().idString());

return cargo.trackingId();
}


Fijaos que no hablamos con la BD para guardar el objeto Cargo que recién creamos, sino que hablamos con un CargoRepository: el que hemos inyectado en el constructor y que puede perfectamente guardar el objeto en la BD o en cualquier otro sitio, p.ej. una Collection. ¿Por qué no? Si no hubiera un requisito que nos pidiera poder recuperar la información de los envíos (Cargos) si la aplicación se reiniciara, no habría nada que nos impediría mantener en memoria esta información. ¿Verdad? En esto justamente consiste la ignorancia de la persistencia. Si cambiamos la política para guardar los datos, el código de los objetos Cargo no necesita ser modificado ni una línea. Es más, nuestro servicio (de dominio) BookingService tampoco. Sólo necesitamos cambiar el repositorio que inyectamos. Esto es fácil con Spring. Veamos cómo está hecho en context-infrastructure-persistence.xml:










No pongo los detalles de cómo se configuran transactionManager ni sessionFactory porque no son significativos: son idénticos a los de cualquier otra aplicación. Lo que sí es relevante aquí es CargoRepositoryHibernate. Fijaos en que está anotada con @Repository y extiende HibernateRepository (que simplemente sirve para tener el setSessionFactory y el getSession). Finalmente, echemos un vistazo al método store que es el que nos interesa ahora, pero echad un vistazo "de refilón" a los demás porque pueden ayudaros a situaros sobre cuál es la responsabilidad de este objeto (que es MUY parecido a un DAO).


public void store(Cargo cargo) {
getSession().saveOrUpdate(cargo);
// Delete-orphan does not seem to work correctly when the parent is a component
getSession().createSQLQuery("delete from Leg where cargo_id = null").executeUpdate();
}


Observad que alguien ha dejado un comentario explicando el borrado de ciertos objetos relacionados. Esto tiene un cierto "tufillo", yo hubiera extraído el comentario y la linea a la que se refiere a un método private llamado deleteOrphansWhenParentIsAComponent o algo así, y hubiera llevado el comentario al javadoc del método y me aseguraría de tener un buen test para esto que huele tan raro... pero es lo que hay...

Llegados a este punto algunos volveréis la vista atrás y diréis: "¡Demonios! ¿Dónde hace commit?". Aquí es donde tenemos que mostrar todas las cartas y enseñar dónde se configura aquella fachada de la que hablábamos al principio BookingServiceFacadeImpl:









hibernateInterceptor











Claro, ahora se entiende, usamos el HibernateInterceptor con la misma sessionFactory de nuestros repositorios. Je, je... Vale, es un poco "truqui", pero es la manera más limpia que hay de trabajar "puertas adentro" y olvidarte de historias.

¡Uy! Se me olvidaba explicar cómo es el objeto Cargo, que es lo que en DDD se denomina AggregateRoot y que es algo así como la raíz de un árbol de objetos dependientes, cuya existencia depende de la raiz. En este caso son Cargo, Itinerary, Leg, Delivery y RouteSpecification. No voy a profundizar aquí, pero diré que cuando guardamos un Cargo podemos estar guardando todos los que dependen de él. Cargo también es una Entity (en el sentido de DDD y también en el sentido de JPA, si lo usáramos).

¿Cómo se mapea este AggregateRoot con las tablas de la BD? Si usáramos JPA sería muy fácil viendo las anotaciones; en el caso de DDDSample han usado los ficheros de mapeo de Hibernate. No voy a entrar en detalles sobre esto porque sería explicar Hibernate, y no es mi intención ahora mismo.

Por último, el "truqui" del que os hablaba al principio que usan para exponer la fachada. Usan RmiServiceExporter, una utilidad (como otras muchas) de Spring, y que permite acceder a este objeto BookingServiceFacadeImpl como si de un EJB se tratara. Fácil, ¿verdad? Bueno, también podríais haberlo anotado con @EJB y todas esas cosas que explican en Java EE. Ya se sabe, para gustos, colores. :-)

Espero que haya quedado claro el "meollo" de la cuestión, que tiene mucho que ver con aquello que contaba hace ya bastante sobre la Arquitectura en Capas de Cebolla. La idea que me gustaría que os quedara después de este artículo (y sobre todo el anterior) es que la ventaja de hacer un modelo de dominio rico y carente de dependencias tecnológicas consiste en que tenemos un código más limpio y realmente desacoplado, lo que nos trae un montón de ventajas como que podemos comprobar unitariamente nuestro código con mucho menos coste y riesgo de errores.

Quedo a vuestra disposición para discutir lo que creáis conveniente.

Nota: Perdonad el formato de los xml, pero Blogger me reformatea los elementos vacíos y me monta un cristo, hasta que me he dado cuenta y los he cambiado a mano.

miércoles, mayo 20, 2009

Productividad vs agilismo

Estaba escribiendo una respuesta en la lista de Agile Spain a mi compañero Leo, y me he ido liando, liando... y al final me ha salido un alegato contra la falta de productividad. Y como queda un poco "off-topic" he decidido sacarlo al blog.

Pues bien, el caso es que el próximo día 3 de Junio, Ángel Medinilla dará una charla sobre Contratos ágiles subtitulada muy acertadamente "Vendiendo Scrum a tus clientes". Lo que pasa es, y esa era la razón por la que comencé a responder a Leo, que creo que Ángel puede encontrarse con preguntas chungas del tipo "en España eso no se puede hacer", "no veas cómo son mis clientes" y similares. No hace mucho unos amigos me dijeron justamente esto. Y lo peor de todo es que yo al menos no tengo argumentos suficientes para rebatirles.

Ayer estuve charlando con Xavi Albaladejo también sobre esto mismo y creo que ahora estoy mejor "armado", puesto que puedo explicar que es posible plantear dos relaciones comerciales con los clientes: una basada en el clásico "fixed price and time" (precio y fecha cerrados) y otra basada en el contrato ágil, es decir, "time and materials" (horas x hombre cerrados) con alguna matización. A este último hay que conseguir quitarle ese "tufillo a charcutería prestación de servicios sin valor añadido" que algunos le encuentran porque no se lo explicamos bien, pero creo que esto es un problema menor.

Pero yo soy un "creyente" y sospecho que la lucha por convencer a los "no creyentes" puede ser muy dura cuando lleguemos a los argumentos fatalistas de "en España eso no se puede hacer". Sobre todo porque muchos se escudan en ese fatalismo para no afrontar la realidad de su falta de productividad. Yo opino que el mayor problema que tenemos en nuestro sector no es que los clientes no nos quieran comprar proyectos ágiles (que no digo que no sea difícil) sino que no tenemos equipos productivos y capaces de adoptar una cultura ágil, donde todos debemos ser responsables y buscar la excelencia. Tengo la extraña sensación de que muchos equipos de desarrollo no son conscientes de que (hagan agilismo o no) no trabajan para su jefe (el que les paga las nóminas) sino para sus clientes (los que pagan las facturas y que sólo lo hacen de manera continuada si quedan satisfechos). Vale, también los continúan por razones "extra-comerciales": sólo tengo 3 proveedores y este contrato le toca a fulanito -aunque siempre me entrega los proyectos tarde y con una calidad demencial-, o la fase X del proyecto ha sido una porquería, pero no me queda más remedio que dar la fase X+1 a los mismos porque ningún otro podría entender lo que hay hecho... Pero estas razones son muy tristes, ¿verdad?

Lo siento si alguien se molesta, pero sinceramente es lo que pienso. ¡Ah! Y no me vale que me digan que en el extranjero es igual que en España. A mi lo que me importa es que la productividad en España viene descendiendo de manera continuada desde el año 1995 y que parecemos estar cómodos con ello. La noticia es de 2006 pero no creo que hayamos mejorado significativamente desde entonces. Además, hay otros artículos más recientes (todos pre-crisis) que argumentan con más datos esto que digo.

Claro, si nuestros equipos son poco productivos porque el proceso de desarrollo es mejorable, la respuesta es fácil: mejora el proceso de desarrollo y aumentarás la productividad. Pero qué pasa si el problema es de actitud. Si cuando pides que de iteración a iteración mejoren la productividad y desde el becario hasta el jefe de proyecto, pasando por todos los seniors, ninguno asume su responsabilidad y trata de hacer mejor su trabajo y el de su equipo. He dicho mejor, no bien. Y lo digo sobre todo porque, como yo lo veo, esto del agilismo va de ir mejorando de manera continuada. Y aportar valor al cliente, no a tu jefe, sino al cliente.

Toda esta reflexión "en voz alta" me ha recordado lo que decía Ken Schwaber (uno de los autores de Scrum) pero entonces llegamos a otro tema peliagudo: la meritocracia (léase "¿son capaces nuestros gerentes de despedir a los vagos y a los inútiles?"). Glub, mejor no sigo. :-)

Bueno, Ángel, prepárate para la charla del día 3, porque si nadie te pregunta esto ya te lo preguntaré yo. (Si no me pierdo otra vez para llegar, claro)  :-D

miércoles, mayo 13, 2009

Salvando las distancias

Voy en metro, ilusionado, camino del segundo día del curso de Scrum de Medinilla. Y me he pillado el libro de Gojko Adzic "Bridging the Communication Gap" porque ayer surgió el tema de las especificaciones ejecutables y los roles dentro del equipo. Pero estoy un poco desentrenado porque hace mucho que no voy en metro con tiempo para leer, y el iPod lo tengo vacío de podcasts por escuchar, así que me he puesto la "música aleatoria" y mientras escucho de lo más variado (desde la deliciosa Joy Denalane hasta M-Clan, que no veas cómo me animan) he pensado en tomar notas para cumplir con una "cierta obligación": explicar lo que me ha parecido el libro.

Gojko Adzic es un tipo que habla en inglés con un acento balcánico realmente difícil de seguir (al menos para mi), así que pensé que era buena idea comprar el libro para entender a qué se refiere cuando habla de talleres de especificaciones y de pruebas de aceptación ejecutables en entornos ágiles. Además, Gojko Adzic también imparte cursos sobre Domain-Driven Design y esa relación entre DDD y pruebas de aceptación es algo que me interesa bastante.

Voy a ser sincero, también compré el libro porque es el primero en el que se habla de Concordion, la herramienta open source en la que modestamente colaboro. Pero son apenas unas páginas y el valor del libro es mucho más que eso.

Adzic explica la importancia de que "la gente del negocio" hable el mismo idioma que "la gente técnica". Esto muchos lo entienden como obligar a clientes y usuarios a que hablen en términos tecnológicos como "altas, bajas, modificaciones y listados (CRUD en inglés)", o peor aún, de tablas, campos y relaciones.

En DDD hablamos de un lenguaje ubícuo, o único en todo el proyecto, y que es el que usan tanto técnicos como usuarios. Esto permite reducir los defectos producidos por malentendidos y tiende puentes entre ambos mundos, abriendo la posibilidad a una verdadera colaboración.

Un inciso melancólico. Voy ahora mismo montado (mientras escribo estas notas en mi moleskine) en el metro ligero y me he acordado de ese par de meses intensos que viví y trabajé (sobre todo lo primero) en Melbourne (Australia). Allí fui usuario del "tram" y he de decir que me parece un medio de transporte público de lo más interesante porque es a la vez rápido, cómodo y silencioso.

Pero sigamos con el libro. El grueso del mismo se basa en hablar del "agile acceptance testing" y de cómo buscamos ponernos de acuerdo en qué es lo que hay y lo que no hay que desarrollar. Para esto usamos ejemplos realistas en vez de requisitos abstractos. "Los ejemplos demuestran cómo debería actuar el sistema y cómo debería ayudar a los usuarios a hacer su trabajo". Adzic propone que estos ejemplos sean creados por todo el equipo de implementación, no sólo por un "experto del dominio" (también conocido como "analista de negocio") como en modelos de desarrollo más tradicionales. "Usamos los ejemplos para discutir el dominio y asegurarnos de que no hay malentendidos".

Según Adzic, el uso de ejemplos realistas obliga a pensar más acerca de los problemas. De hecho, comenta cómo se producen muchas discusiones entre los expertos cuando se plantean ejemplos para casos extremos; discusiones que incluso les hacen a veces revisar sus propios procesos de negocio. ¡Vaya! Si resulta que podemos ayudar a nuestros clientes en vez de simplemente observar su comportamiento "desde fuera", como si fueramos "supernanis con corbata".

Damned! ¡Me he saltado una parada! Estaba tan concentrado... Menos mal que la frecuencia del metro ligero éste es alta y he podido llegar sólo un par de minutos tarde. Buff...

De vuelta del estupendo curso de Ángel Medinilla, sigo con el resumen del libro y me fijo en que no he explicado esto de los ejemplos. Vamos, que no he puesto ejemplos de ejemplos. :-) Adzic pone un ejemplo en la página 45 de una regla de negocio relacionada con el descuento que le podemos ofrecer a un cliente, pero a mi me gusta más el que explica David Peterson en la web de Concordion. Es bastante más completo porque nos lleva desde la historia de usuario (el requisito) hasta la prueba de aceptación automatizada (en forma de ejemplos). Es interesante cómo David hace mucho hincapié siempre en que debemos especificar con ejemplos que expliquen comportamientos muy elementales y dejar para otras especificaciones todo aquello que quedaría fuera. Son los "Further details" en el ejemplo. También Adzic habla de esto en su libro, pero menos; y yo creo que es importante esta anotación al margen para aquellos que queráis "tomar este camino" para hacer pruebas de aceptación.

En "Bridging the communication gap" también se explica cómo conducir estas reuniones (talleres de especificación) e incluso aconseja sobre algunas herramientas. Pero creo que es interesante explicar cómo pueden encajar estos talleres en nuestro calendario semanal (ágil).

Adzic sugiere lo siguiente:



Release es todo aquello que hacemos después de la demo para dejar bien cerrado el sprint. Etiquetamos en subversion, hacemos copias de seguridad, ponemos las versiones del nuevo sprint en los pom.xml (si usamos Maven y si es que tenemos que cambiar de versión), limpiamos las pizarras... y mientras esto lo pueden ir haciendo algunos desarrolladores (típicamente los becarios, je, je) pues el resto puede estar preparando el sprint primero revisando el backlog y luego, ya con los becarios incorporados, estimando las historias y decidiendo lo que se podrá hacer razonablemente en el sprint (las próximas dos semanas).

Ojo, es una manera de organizar el trabajo durante un sprint, pero lo importante de esto es que el dueño del producto (también conocido como jefe de proyecto, analista de negocio, o incluso tester, según vuestro "mapeo" preferido) se encarga de trabajar las historias de usuario (redacción y priorización) y de los ejemplos (criterios de aceptación) antes de los talleres de especificación, pero realmente es el equipo en su totalidad quien acuerda lo esencial de los criterios de aceptación mediante la discusión que se ofrece en esta reunión. Para los que ya estéis algo picados con esto del agilismo, me permito recordar "las tres Ces" (card, conversation, confirmation). Éste es el momento ideal para la conversación, aunque ya se haya tenido una conversación previa cuando se han estimado las historias de usuario en el Sprint Planning Meeting (usando terminología Scrum).

Bueno, y hasta aquí hemos llegado. Espero que os resulte útil. Y si alguien más se ha leido este libro y quiere contrastar aquí su opinión, estaré encantado de poder charlar con vosotros porque mi intención es preparar una presentación (o un taller, ya veré) sobre este tema y exponerla bajo el "paraguas" de Agile Spain.

Estoy triste




Descansa en paz, poeta del tiempo.

Gestionar proyectos

Hoy he terminado el curso de Scrum que imparte Angel Medinilla y que tuve que dejar a medias en octubre porque me pilló el nacimiento de mi segundo querubín.

Vale que yo iba bastante motivado, pero en la retrospectiva que ha planteado Ángel al final del curso mis compañeros lo han calificado como "completo" y "ameno". Lo cierto es que no puede ser de otra manera. Ameno porque hemos jugado a pasarnos pelotas a ritmo de Jamiroquai o hemos visto videos como éste. Y completo porque no sólo hemos aprendido cómo se hace Scrum sino también sus principios y por qué es rentable para una empresa implantar esta metodología de gestión de proyectos.

Y además de todo esto, que es el objetivo estricto del curso, Ángel habla de muchas otras cosas y comparte su experiencia con los asistentes. Y favorece también que este intercambio de experiencias sea recíproco, con lo que todos nos enriquecemos muchísimo.

Pero yo no quería escribir para hacerle una cuña publicitaria (gratuita) a Ángel (bueno, quizás se la cobre más adelante... ya se me ocurrirá algo... je, je). Yo en realidad quería explicar que este curso de Scrum es también un curso de gestión de proyectos encubierto y, para qué engañarnos, es muy necesario formar a nuestros jefes de proyectos y líderes técnicos en lo que significa gestionar un proyecto y su relación con la rentabilidad si realmente queremos que nuestro sector sea competitivo (especialmente en estos tiempos de crisis y "cambios de modelos productivos").

Ojalá hubiera muchas empresas en España que se dieran cuenta de que sólo es posible mejorar nuestra competitividad mediante incrementos significativos de nuestra productividad y que, como bien se ve en uno de los ejercicios que hemos hecho hoy con Ángel, no es posible producir incrementos significativos de la productividad simplemente confiando en que con el paso del tiempo tenemos más experiencia o en que "vamos a echarle más ganas". Esperar que algo cambie sin hacer nada diferente es la definición de locura según Einstein.

martes, mayo 12, 2009

Iniciarse en Scrum

Hoy estoy en medio de un curso de Scrum de dos días que imparte Angel Medinilla. Acabo de leer un artículo de "El Raúl" titulado "No sé nada de Scrum. ¿Qué hago primero?" y no he podido evitar bloguearlo porque me parece un índice de recursos muy conciso, porque da un estupendo consejo ("Estudia") y porque me da la excusa perfecta para meter la "cuña publicitaria" de Agile Spain.

Agile Spain es la comunidad virtual donde nos encontramos muchos de los que estamos interesados en que en España haya un cambio en la manera de gestionar proyectos y se comiencen a implantar metodologías ágiles como Scrum. Creo que es el mejor lugar para comenzar a compartir vuestras dudas y para informaros de cuándo y dónde se celebran charlas, conferencias, cursos, etc. Echad un vistazo a la lista de correo y si luego os interesa, suscribíos y participad.

martes, mayo 05, 2009

Modelo de dominio matriarcal

En los últimos días he estado cruzando algunos mensajes en el blog de Julio César Pérez Arques y dado que hemos llegado a un punto donde no lo puedo "despachar" con un par de frases ocurrentes, creo que lo oportuno es explicarlo en un formato más "extenso".

En un artículo de su blog, Julio César resumía bastante bien una presentación de Neal Ford en InfoQ, pero dijo algo que nos llevó a iniciar esa "eterna" discusión sobre modelo anémico y modelo rico:
No me gustan nada los constructores con más de 2 parametros. Prefiero uno vacio y luego hacer sets.

Julio César en realidad luego explica la postura de Neal Ford sobre el uso de constructores, más alineada con los modelos ricos que con los modelos anémicos que defiende Julio.

Y ante mi crítica, Julio se excusa (en vano, je, je) diciendo lo siguiente:
No se si es que estoy demasiado Springizado pero me gusta más tener mi capa service y mi capa dao separaditas. Supongo que también tiene que ver con el tipo de aplicaciones en las que trabajo, basicamente de gestión sobre una bbdd ama y señora.
¿Por qué acaso en una aplicación de gestión no son todas las clases del modelo Value Objects? Para mi la unica diferencia es en si mueven los datos del cliente a la app o si de la app a la bbdd. Siempre desde mi pto d vista...

No voy a entrar a discutir si usar Spring y tener las capas de servicios y de acceso a datos desacopladas tienen algo que ver. Para mi no, pero no me interesa discutir ahora sobre frameworks, porque me interesa "atacar" esa idea de que una "aplicación de gestión" es poco más que una aplicación de "data entry". No estoy de acuerdo. Para nada, una aplicación de gestión es justamente donde más y mejor podemos aplicar el Domain-Driven Design.

Pero voy a usar un viejo artículo de Udi Dahan (al que, sí, es cierto, últimamente cito mucho) en el que explica muy, muy bien cómo y por qué debemos orientar nuestros diseños hacia el modelo de dominio en vez de al CRUD.

Udi pone el ejemplo de un sistema para hacer entrevistas a candidatos en una selección de Recursos Humanos. Y así, si modelamos esta aplicación como un conjunto de inserciones, actualizaciones y eliminaciones de objetos Cita, nuestro código para el servicio de citar a un entrevistado sería algo así como:


Cita cita = new Cita();

cita.setEntrevistador(entrevistador);
entrevistador.getCitas().add(cita);

cita.setCandidato(candidato);
candidato.getCitas().add(cita);

cita.setFechaHora(fechaHora);

dao.guardar(cita);


Pero, en cambio, si nos orientamos al dominio y modelamos el sistema como objetos con estado que se encargan ellos mismos de persistirse cuando cambian de estado (si es necesario), conseguimos que el código de nuestros servicios no sólo no esté acoplado al modelo de datos sino que es más fácil de entender al carecer de artificios tecnológicos:



entrevistador.planificaEntrevistaCon(candidato).enFechaHora(fechaHora);


Si entramos a discutir cómo se implementan estos métodos, a partir de este punto tendremos una gran discusión porque no todos se ponen (nos ponemos) de acuerdo sobre cómo hay que hacerlo. Muchos hablamos de la ignorancia de la persistencia, es decir, de que los objetos de dominio no deben llamar nunca a los DAOs directamente sino que para ello hablan con los Repositorios usando una interfaz tipo Collections. Otros dicen que por qué esa indirección si el 99% de las aplicaciones tienen que persistir los datos. Yo tengo claro que se trata de aplicar los principios SOLID y que, por tanto, lo correcto es desacoplar la lógica de negocio de la lógica de persistencia. Pero para gustos hay colores...

Esta semana lo voy a tener un poco difícil, pero puede que para la semana que viene pueda implementar completo este ejemplo usando Spring y JPA. Espero que la salud mía y de mis niños me lo permita. Je, je...

Para terminar, si a alguien le interesa todo esto del Diseño Orientado al Dominio, le invito a pasarse por la lista de DDD-es que hemos creado recientemente.