Capas Conceptuales para Sistemas. J2EE.

Una realidad que no se puede ocultar es el hecho de que el desarrollo y la codificación de software gozan de complejidad. A pesar de su relativa sencillez, resulta difícil entender todo este grupo de tecnologías convergentes que llamamos J2EE (Java 2 Enterprise Edition). Esta plataforma, que tiene como objeto codificar sistemas de software de nivel empresarial, goza de gran complejidad. EJBs de sesión, de entidad y de mensajes, JSPs, Servlets, Web Services, JDBC, HTML, código SQL, etc., es complicado figurar en la mente todo un sistema software basado en J2EE. En ocasiones, no resulta muy claro el lugar que ocupa cada uno de estos elementos, y resulta aún más difícil explicarlo a un grupo de desarrolladores que está por introducirse en esta plataforma.

Las Capas Conceptuales
En este artículo les recomendamos cómo organizar sistemas basados en J2EE, utilizando una estrategia de organización en cinco capas conceptuales. Esta organización es un medio abstracto cuyo objetivo es el designar un orden lógico a cada elemento, agruparlo dentro de una capa y lidiar con la complejidad dentro de cada una. A fin de cuentas el objetivo es hacer más claro el desarrollo en J2EE.

Las capas en cuestión son: Presentación, Aplicación, Servicios, Dominio y Persistencia. Algunas de estas capas pueden no estar presentes en un sistema. Dependiendo de las características particulares de éste (el dominio del problema), de los marcos de trabajo que se empleen y de la estrategia con que es abordado el desarrollo, alguna de estas capas no serán codificadas. Teniendo esto último en mente, veremos cada una de ellas.

Presentación.- Compuesta por todos los elementos relacionados con la interfaz de usuario, tales como botones, ventanas, campos de textos, etiquetas, etc., si hablamos de clientes Win32, AWT, SWT o Swing; HTML, JSP, JavaScript, aplicaciones Macromedia Flash si se tiene a un navegador Web por cliente; Xlets o Midlets, y sus correspondientes controles de interfaz de usuario si se trata de una aplicación inalámbrica basada en J2ME (Java 2 Micro Edition). Ésta es la capa de interfaz de usuario, el rostro visible y, en cierta forma, estético del sistema. Sin lugar a dudas, la parte más importante para el usuario final del sistema.

Aplicación.- Responsable del control del flujo de trabajo del lado del cliente y de componentes de IU reutilizables. Éstos se caracterizan por presentar un acoplamiento con la capa inmediata siguiente (servicios). Para el caso del control del flujo de trabajo, se puede emplear HTTPSession o el marco de trabajo Apache Struts. En el caso de componentes, por ejemplo, se puede tener un control heredado de un “Combo Box” que despliega los nombres de clientes que están almacenados en la base de datos, y estos son obtenidos a través de un método de un EJB (capa de servicios) que es ejecutado en el constructor de dicho componente. Dependiendo del sistema que estemos construyendo, puede ser que no necesitemos administrar el flujo de control ni se empleen componentes, por tanto, esta capa no estaría presente en tal situación.

Servicios.- Si la capa de presentación es la más importante para el usuario final, la de servicios lo es para los desarrolladores. Sin lugar a dudas, la más importante e indispensable de un software, el API (Application Programming Interface) del sistema. Es el punto de entrada a la lógica de negocios, la cual se encuentra encapsulada a través de un conjunto de componentes de servicio.

En el caso de J2EE, los componentes de esta capa típicamente se implementan como EJBs de Sesión sin estado (stateless). La razón de que no tengan estado es que no guarden información de clientes particulares, y estén completamente desacoplados de éstos, además de que una instancia puede atender múltiples peticiones brindando un mayor desempeño. Estos Beans acostumbran servir como fachadas que proveen servicios utilizando información de las entidades de la capa de dominio.

Esta capa requiere un gran esfuerzo para las pruebas unitarias, ya que es imperativo asegurarse de que estos componentes respondan adecuadamente a las diferentes condiciones posibles de ejecución. De tenerlos, es aquí donde residirían los servicios web (web services) del sistema.

Dominio.- Si se desean los beneficios de un diseño orientado a objetos (el ser reutilizable y de fácil mantenimiento), esta capa debe estar presente dentro del sistema que se desee desarrollar. En ella está contenido nuestro modelo conceptual, mejor conocido como modelo de dominio —de allí el nombre de la capa.

Este modelo consiste en todas aquellas entidades (facturas, productos, ordenes de compra, etc.) y actores (clientes, bancos, empleados, etc.) que componen y/o interactúan en los procesos del negocio, y son creadas a raíz de la abstracción de sus atributos significativos para el sistema. Este modelo típicamente es ilustrado con diagramas de estructura, como el diagrama de clases de UML. Una característica de estas entidades es su capacidad para asociarse con otras entidades o, incluso con sí mismas. Es posible que un sistema no cuente con capa de dominio; en estos casos la capa de servicios estaría codificada de tal manera que dentro de los mismos métodos de sus objetos se accederían directamente los datos en donde estos se almacenen, por ejemplo usando JDBC en el caso de una base de datos relacional. Esta opción tiene la desventaja de que es de difícil mantenimiento y poco reutilizable, pero puede ser factible para sistemas de vida corta o para aquellos que no tendrán cambios significativos a través del tiempo, incluso para prototipos.

Persistencia.- Al hablar de persistencia hablamos de almacenamiento de información en un medio no volátil (bases de datos, archivos de texto plano, etc). Los elementos de esta capa típicamente funcionan como objetos de acceso a datos o DAOs (Data Access Objects), proveyendo métodos para leer y almacenar los datos de los objetos de negocio. Es por esto que la existencia de esta capa típicamente está condicionada a la existencia de la capa de dominio. Si no hay un modelo de dominio presente, no hay razón para hacerlo persistente.

Incluso con la presencia de un modelo de dominio, podría no ser necesario codificar esta capa cuando se empleen marcos de trabajo tales como persistencia manejada por el contenedor (Beans de tipo CMP), JDO (Java Data Objects) o Hibernate. Al codificar las entidades en la capa de dominio, estos marcos de trabajo se encargarán de la persistencia de cada una de ellas, liberando a los programadores de esta responsabilidad.

La persistencia manejada por el Bean (EJB de Entidad de tipo BMP) es un caso clásico de implementación de esta capa, ya que existe un modelo de dominio que debe ser persistente, y para ello los programadores codifican clases con sentencias SQL cuyo objeto es crear, modificar, eliminar y consultar registros en una tabla.

Orden de Desarrollo
Ya describimos las cinco capas recomendadas. Ahora hablemos sobre cómo nos pueden ayudar para definir el orden en que se debería desarrollar un sistema. ¿Cómo es eso? Sucede que estas capas presentan una característica adicional: cada una de ellas depende de la capa inmediata inferior. Ya sea en tiempo de compilación o de ejecución, los tipos en las capas superiores dependerán de los tipos de las capas inferiores. Por ejemplo, volviendo al ejemplo del componente que muestra los nombres de clientes, para que la capa de aplicación, en donde se encuentra codificado el componente, muestre esta información, necesita invocar un método que se encuentra en la capa de servicios. Es esta dependencia la que marca el orden de desarrollo.

De acuerdo con Floyd Marinescu, autor del libro EJB Design Patterns, lo primero que debe ser codificado es la capa de dominio, seguida por las de persistencia, servicios y por las de interfaz de usuario (aplicación y presentación). La de dominio es la primera debido a que aquí residen las entidades que deben estar listas y compiladas para poder ser utilizadas por la que capa de servicios, que es la que contiene la lógica de negocio; adicionalmente, estas entidades típicamente son sencillas de implementar. Una vez lista la capa de dominio, ésta desencadena ordenadamente el desarrollo de las otras capas. Es recomendable tener en operación la capa de servicios lo más pronto posible para lograr el desarrollo de la interfaz de usuario en paralelo con las demás capas.

Una importante observación, asumiendo que se está creando un sistema bajo un proceso de desarrollo iterativo e incremental: no es necesario desarrollar totalmente y con lujo de detalle cada capa. Sólo deben ser definidas aquellas piezas de código directamente relacionadas con el o los casos de uso que se estén llevando a cabo en la iteración actual.

Acerca del autor
Ramés Rodríguez es desarrollador de J2EE desde el 2002. Su especialidad es el empleo de software libre aplicado a Java y el diseño de arquitecturas orientadas a objetos. Actualmente se desempeña como Arquitecto de Sistemas en la Universidad Loyola del Pacífico.