EJB 3 y DDD - Arquitecturas Incompatibles
EJB 3 y DDD - Arquitecturas Incompatibles
Si bien Eric Evans en su famoso libro Domain-Driven Design (filosofía que hemos adoptado para el desarrollo de SISTRANS) no impone una arquitectura definida, a través de conceptos y patrones enuncia lineamientos de diseño en los cuales se puede vislumbrar una separación de capas fundamental.
El objetivo principal de DDD es aislar el dominio del resto de la aplicación. Eso queda bien claro desde el primer capítulo. Lo primero que Evans nos dice es que el dominio es la única capa indispensable para DDD. Tranquilamente podríamos construir una arquitectura de solamente dos capas: [Capa de Dominio ó Lógica de Negocio] + [Capa de Aplicación].
Para satisfacer requerimientos no funcionales de distribución y/o manejo de concurrencia, SISTRANS ha adoptado la siguiente separación de capas:
Debido a que SISTRANS se plantea como una aplicación enterprise, que debe soportar concurrencia, transacciones de negocio y encima estar preparada para funcionar en un ambiente distribuido, nos pareció apropiado utilizar la tecnología más robusta que actualmente se conoce para aplicaciones enterprise escalables: EJB 3.0.
EJB 3.0 no sólo es un framework, también es un conjunto de bibliotecas que imponen una arquitectura, ya que, para aprovechar todo su potencial, deben correr en un servidor de aplicaciones que implemente la especificación correspondiente de SUN. Por lo tanto, EJB 3.0 es una plataforma, a menudo conocida como Plataforma Java EE (aunque, correctamente hablando, Java EE es una plataforma que soporta muchas más especificaciones que EJB).
A continuación, podemos ver cómo es la arquitectura de una aplicación enterprise estándar construida con EJB 3.0:
Esta arquitectura no es compatible con una arquitectura pura de DDD, ni con la arquitectura que propone SISTRANS. La incompatibilidad fundamental está en que en EJB 3.0 no existe una capa de dominio aislada donde vive el Modelo de forma independiente a la infraestructura y/o aplicación. Lo que EJB 3 llama Modelo es esa capa de Persistencia que vemos sobre la capa de Base de Datos. En esta capa viven los EntityBeans, que no son más que Objetos de Dominio con atributos, setters y getters, pero sin lógica de negocio. Toda la lógica de negocio se ubica en la capa de Lógica de Negocio, donde viven los SessionBeans. De esta forma, el conocimiento del Dominio se encuentra disgregado en dos capas separadas y, en el caso de la capa de Persistencia, mezclada con aspectos de infraestructura y, por ende, de tecnología.
En DDD, Evans rechaza este tipo de arquitecturas hasta el extremo de aducir que atentan contra la programación orientada a objetos, ya que, al separar los datos de los algoritmos que manipulan dichos datos, se vuelve a un diseño estructurado. Biseccionando de esta forma el Modelo, no sólo perdemos la forma de aislar el Conocimiento del Negocio, también perdemos la encapsulación que la POO propone al guardar atributos y métodos en una sola estructura lógica.
Pero por otra parte, una de las recomendaciones de DDD es que, cuando se tiene que utilizar un framework, no se debe luchar contra la filosofía esencial del mismo, porque el resultado puede quedar tan complicado que se corre el riesgo de perder la mantenibilidad y escalabilidad que un Modelo de Dominio es capaz de brindar. Por eso, Evans recomienda que, si nos vemos obligados a utilizar alguna de estas tecnologías que separan la lógica de negocio de los datos en distintas clases, por lo menos no ubiquemos esas clases en distintas capas.
No es trivial la razón por la que existen SessionBeans y EntityBeans. En los SessionBeans se debe escribir la lógica transaccional de negocio y en los EntityBeans deben vivir los datos que pueden persistirse. No podemos ir en contra de esa filosofía. La lógica de negocio se debe escribir en los SessionBeans porque es ésta la forma que tiene el servidor de aplicaciones de controlar el acceso concurrente de usuarios y manipular las transacciones declarativas de negocio para el acceso a los datos. En los EntityBeans vive el mapeo objeto-relacional necesario para que el DataMapper persista los atributos en las tablas de la base de datos. Pero los EntityBeans no son thread-safe. El servidor de aplicaciones no controlará el ciclo de vida de los EntityBeans ni el acceso concurrente a sus datos. Por eso: todos los EntityBeans deben ser accedidos a través de SessionBeans.
Para solucionar esta dicotomía entre ambos modelos, hemos establecido una convención sencilla. En nuestro modelo vivirán EntityBeans y SessionBeans. Cada Entidad de DDD que necesite ser persistida, estará compuesta por un EntityBean que contenga los atributos y un SessionBean que implemente la lógica de negocio para manipular dichos atributos. Cada ValueObject de DDD que necesite ser persistido, estará compuesto por un EntityBean que contenga los atributos y un SessionBean que implemente la lógica de negocio para manipular dichos atributos. Además, en la capa de Dominio vivirán Servicios, el tercero de los tipos de Objetos de Dominio que DDD propone. Los Servicios estarán implementados como SessionBeans.
Entity = EntityBean + SessionBean + Interface
ValueObject = EntityBean + SessionBean + Interface
Service = SessionBean + Interface
A partir de EJB 3.0, tanto el mapeo ORM como la configuración de los SessionBeans puede hacerse mediante anotaciones imbuidas en el código. Las anotaciones representan un incremento muy grande en la velocidad de desarrollo de una aplicación enterprise. No se puede negar que escribir el mapeo ORM, por ejemplo, en el mismo archivo donde se encuentra la clase que será el EntityBean es realmente cómodo; sin contar además que contamos con un mecanismo de compilación de anotaciones para solucionar problemas de sintaxis previos a la ejecución. Comparado con los XMLs, las anotaciones son una gran ventaja; escribir descriptores XML es demasiado verboso y propenso a errores.
Sin embargo, las anotaciones encajan perfecto en una arquitectura EJB 3.0, pero no en una arquitectura DDD. La razón: al agregar anotaciones en una clase, automáticamente agregamos una dependencia de tecnología. Si los EntityBeans viven en la capa de Persistencia, eso no es problema. Pero si los EntityBeans viven en la capa de Dominio, como será en el caso de SISTRANS, las anotaciones no son una buena opción. La capa de Dominio no puede tener absolutamente ninguna dependencia con el framework de persistencia o la plataforma EJB 3. Es por esto que hemos decidido utilizar los descriptores XML (orm.xml y ejb-jar.xml) para que los POJOs que pasarán a ser EntityBeans o SessionBeans no posean ninguna dependencia de tecnología. No olvidemos que el objetivo principal de DDD es aislar por completo el dominio: podríamos armar un paquete y usarlo en cualquier aplicación (no necesariamente una aplicación Java EE o EJB 3.0). Éste es el concepto de Dominio Portable.
Conclusión:
- Todos los objetos del modelo podrán componerse de dos clases y una interfase. Una de las clases será un EJB del tipo Entity, donde no se escribirá lógica de negocio; el Entity EJB solamente guardará los atributos que se quieran persistir y sus correspondientes setters y getters. La otra clase será un EJB SessionBean, que contendrá la lógica de negocio y hará uso de los datos del EJB Entity. La interfase expondrá los servicios que podrán ser invocados remotamente desde el Session Bean y será, por supuesto, la interfase que implemente la lógica de negocio. (No es necesario que existan las tres clases para cada objeto de dominio. Se crearán de acuerdo a los requerimientos del modelo.)
- Bajo ningún concepto se permite separar en distintos paquetes los datos de un objeto de dominio de su lógica de negocio. Si existen dos clases para representar un objeto del modelo en el código, las dos deben estar contenidas en el mismo paquete y siguiente la convención de los puntos anteriores.
- No se deben usar annotations que pertenezcan a la aplicación, en ninguna clase de la capa de dominio. Si deben incluirse parámetros de configuración o mapeo ORM para el motor de persistencia, se especificarán mediante el uso de archivos de configuración externos como XML o properties. Fuera de la capa de dominio, podrán utilizarse las annotations, que resultan más cómodas para el desarrollo.
- La capa de dominio debe construirse para ser completamente independiente de la aplicación que la utiliza. No debe existir ninguna dependencia de la capa de dominio hacia cualquier otra capa. La capa de dominio podrá ejecutarse fuera de la aplicación, ya que será la representación del modelo y la fuente de mayor valor para el negocio.
Estas cuatro Convenciones pueden encontrarse en la página Convenciones y Estándares en esta misma wiki.
Comments are disabled for this space. In order to enable comments, Messages tool must be added to project.
You can add Messages tool from Tools section on the Admin tab.