jueves, 18 de diciembre de 2008

Patrones Enterprise (parte 2)

En el post anterior de Patrones Enterprise, me enfoqué principalmente en los Patrones de Dominio del libro de Martin Fowler: Patterns of Enterprise Application Architecture (ver catálogo). Para continuar con el tema, escribiré sobre los distintos patrones de persistencia, prestándole especial atención a los patrones de arquitectura y su relación con los patrones de dominio ya vistos.

Patrones de Persistencia


Dentro del universo de los patrones de Fowler, encontramos tres distintos tipos de patrones de Persistencia.

  • Patrones de Mapeo
  • Patrones de Comportamiento
  • Patrones de Arquitectura

Patrones de Mapeo

Dentro de los patrones de Mapeo tenemos también una subdivisión importante entre:
  • Patrones de Mapeo de Relaciones
  • Patrones de Mapeo de Jerarquías
Los patrones de Mapeo de Relaciones centran su atención en la forma en que los objetos se relacionan en memoria y la forma en que las tablas se relacionan en la base de datos. Cuando la gente habla de mapeos objeto-relacional, en general se refiere a estos patrones (y también a los de Mapeos de Jerarquías).

Principalmente, dentro de esta categoría, Fowler explica tres patrones:
  • Identity Field: consiste en generar un número y administrarlo; puede ser, por ejemplo, un contador en la base de datos, o un atributo de una clase genérica en memoria.
  • Foreign Key Mapping: sirve para mapear relaciones de uno a muchos; una relación de este tipo, que en memoria consiste en un objeto A con una colección de objetos B dentro, se mapea con una clave foránea del lado de la entidad contenida; la relación se invierte en la base de datos.
  • Association Table Mapping: sirve para mapear relaciones de muchos a muchos; en una base de datos esta relación se resuelve introduciendo una tercera tabla que contenga las claves primarias de ambas entidades involucradas en la relación.
Los patrones de Mapeo de Jerarquías, como su nombre lo indica, se dedican a resolver la representación de la herencia de clases/objetos en disco. Los tres patrones sugieren distintas formas de llevar a cabo esta proyección del dominio en la base de datos:
  • Single Table Inheritance: mapea toda la jerarquía en una única tabla, duplicando muchos datos, pero facilitando las búsquedas.
  • Class Table Inheritance: es exactamente el opuesto; mapea cada clase de la jerarquía en una tabla individual, sin ninguna duplicación de campos.
  • Concrete Table Inheritance: es una solución intermedia, en la que sólo se mapean las clases concretas y las abstractas simplemente duplican campos en sus clases hijas.

Patrones de Comportamiento

Los patrones de Comportamiento resuelven problemas de infreaestructura relacionados directamente con funcionalidades de soporte para el dominio.
  • Unit of Work: sirve para mantener un registro de todos los objetos que fueron modificados durante una transacción de negocio, es un controlador del mapeo a la base de datos y administra la transacción de negocio (esto significa: cuando tiene que ejecutar un commit, pide una conexión del pool de conexiones de la base de datos y repite las operaciones que fue registrando desde el begin).
  • Identity Map: sirve para evitar tener en memoria dos representaciones distintas del mismo objeto en una transacción de negocio; funciona como una caché de objetos de negocio; como corolario, minimiza las lecturas a la base de datos (el ciclo de vida de un Identity Map es una transacción de negocio).
  • Lazy Load: carga tardía o perezosa; resuelve problemas de carga desmesurada y dependencias circulares; el ejemplo clásico es una relación uno a muchos, donde un objeto de negocio posee una colección de otros objetos; cuando el objeto A es solicitado, se trae a memoria el objeto A y sólo el objeto A, con la colección de objetos B vacía; luego, los objetos B serán leídos cuando realmente se necesiten.

Patrones de Arquitectura

No me he detenido demasiado en los dos anteriores tipos de patrones de persistencia porque los primeros son muy sencillos y los segundos son bastante más complicados (una explicación más prolija merece un post propio, en el que debería explicar los conceptos de transacciones y concurrencia). Los patrones de arquitectura son los que en este momento más me interesan porque son los que más se relacionan con los patrones de dominio.

A grandes rasgos, podemos hacer una primera clasificación de estos patrones, considerando como característica determinante el tipo de relación que éstos establecen entre la capa de dominio y la capa de persistencia (de ahí su nombre de Arquitectura). Considerando esto tenemos los:


La dependencia es de izquierda a derecha; es el Dominio quien conoce a la Persistencia.
  • Mapper: son aquellos que invierten la dependencia (como estuvimos viendo en los post anteriores) mediante el uso de interfaces alojadas en el dominio; ejemplo: Data Mapper.


La dependencia es de derecha a izquierda; es la Persistencia quien conoce al Dominio, y no al revés.
  • Sin capa de persistencia: en este caso no existe una capa de persistencia; las clases del dominio saben cómo persistirse; la lógica entera de acceso a la base de datos se encuentra dentro de los mismos objetos de negocio; el acoplamiento con la base es infinito; ejemplo: Active Record.

Gateway

Table Data Gateway es un ejemplo que funciona a la perfección con el patrón de dominio Table Module. De hecho, Table Data Gateway es un Table Module sin la lógica de negocio. En el ejemplo que vimos para Table Module (en el post anterior), ProyectoGateway y PagoGateway eran dos ejemplos de Table Data Gateway. Existirá un Gateway por cada tabla/entidad en la base de datos.


Por otra parte, tenemos Row Data Gateway que se orienta un poco mejor a objetos y no a tablas, aunque igual no deja de ser un Gateway a la base de datos. Como su nombre lo indica, Row Data Gateway es una representación de un registro y no de una tabla como Table Data Gateway. Row Data Gateway puede funcionar con Transaction Script (aunque esto es discutible, ya que en un Transaction Script puro no tendríamos ni capa de persistencia, ni el concepto de entidad de negocio) o con un Domain Model extremadamente simple. Bajo ningún concepto, podría servir para la persistencia de un Table Module, porque no está orientado a tablas.


Active Record

En el mercado hay varias implementaciones de este patrón, y muy populares. Tenemos por ejemplo Ruby On Rails, el conocido framework para aplicaciones web de Ruby, o CakePHP, un framework para PHP. Como antes mencioné, el acoplamiento con la base es infinito, ya que no hay capa de Persistencia. Cada objeto de negocio sabe como persistirse.


Dado que son objetos de negocio de una capa de dominio, Active Record sólo funciona para cuando se está trabajando con un Domain Model. Por supuesto que, al igual que con Row Data Gateway, hablamos de dominios simples, sin lógica de negocio compleja, ya que de escalar, una aplicación hecha con Active Record, sería imposible de mantener.

Data Mapper

El Data Mapper es la estrella de la orientación a objetos. Es el patrón que soporta Modelos de Dominios complejos y enormes. Son los famosos ORM, como Hibernate o Top Link, que transforman de forma transparente los objetos del dominio en tablas y entidades del mundo relacional de las bases de datos.

A continuación, un ejemplo de implementación de un Data Mapper extraído de los apuntes de las clases de Arquitectura de Software de Guillermo Pantaleo, que aclarará un poco las cosas:



Lo más interesante que podemos ver en estos diagramas, creo yo, es la independencia de la capa de dominio. Si observamos con atención el diagrama de secuencia, podemos ver que el PersonMapper es quien se encarga de instanciar un objeto de dominio Person y de llenarlo con los datos que va a buscar a la tabla de la base de datos. PersonMapper implementa una interfase que está en la capa de dominio, que es la PersonFinder que contiene la especificación de los métodos necesarios para que se puedan hacer búsquedas sobre una persona específica de forma transparente. Noten que el cliente obtiene un PersonFinder a partir del DataMapper, que es entregado por la Registry, un patrón de base que todavía no he mencionado, y a través del cual obtiene la persona que necesita:


PersonFinder finder = Registry.getPersonFinder();
Person person = finder.find("Adrian Paredes");


A través de la interfase PersonFinder es que el Mapper logra invertir la dependencia del dominio.

Conclusión

Aislar el Dominio del resto de la aplicación no es una tarea sencilla. Para lograrlo se requiere un fuerte trabajo de diseño. Esto no significa que haya que reinventar la rueda. Los patrones de diseño que estuvimos viendo y los frameworks que hay en el mercado (muchos de ellos open source), que implementan varios de estos patrones, nos ayudan enormemente en esta tarea de construir aplicaciones enterprise escalables.

Martin Fowler, en su famoso libro Patterns of Enterprise Application Architecture, clasifica los patrones enterprise en patrones de:
  • Dominio
  • Persistencia
  • Concurrencia
  • Distribución
  • Presentación
  • Soporte


Y establece relaciones entre ellos:


Este diagrama de relaciones nos dice, por ejemplo, que si tenemos una aplicación simple podemos usar un Transaction Script o un Table Module. Si usamos Table Module, podemos usar Table Data Gateway. Si construimos un Domain Model y contamos con una lógica de negocio simple, podemos usar Row Data Gateway o Active Record, y sino Data Mapper. Si usamos un Data Mapper inevitablemente entramos en la complejidad inherente de un Domain Model y se nos abre una gama bastante compleja de patrones, que nos ayudan a resolver distintas cuestiones de una aplicación enterprise de gran volumen.

sábado, 13 de diciembre de 2008

Patrones Enterprise (parte 1)

En los post anteriores, me dediqué a definir qué es una aplicación enterprise, estableciendo la arquitectura de las mismas mediante cuatro capas estándares: Presentación, Acceso al Negocio, Negocio y Persistencia. Luego me detuve en la capa de dominio para resaltar su extrema importancia, hasta el punto de afirmar que el dominio es lo único importante. Gran parte de este segundo post la dediqué a la separación entre aplicación y negocio, y al objetivo primario de conseguir un dominio portable y rehusable entre distintas aplicaciones.

En este post, mostraré la forma de lograr esta deseada separación entre aplicación y negocio, mediante los famosos patrones de diseño de Martin Fowler, que pueden encontrarse en el "Nuevo Testamento" de los Patrones de Diseño titulado: Patterns of Enterprise Application Architecture (si consideramos al Design Patterns de GoF como el "Antiguo Testamento"). Las ideas que aquí explicaré son parte de ese libro y los diagramas y muchas otras ideas más pertenecen al material de la clase de Arquitectura de Software dictada por el Ing. Guillermo Pantaleo en la FIUBA.

Patrones de Dominio

A grandes rasgos, existen por lo menos tres formas de organizar la arquitectura de una aplicación enterprise:

TransactionScript

Supongamos que la aplicación enterprise que tenemos que diseñar es tan simple que no se justifica separar en demasiadas capas. Supongamos que, al querer forzar esta aplicación, incurrimos en un sobrediseño, que acaba complicando en extremo el producto final. Supongamos un negocio simple, una aplicación con pocas pantallas, en las que apenas mostramos lo que hay en una base de datos para que pueda actualizarse y realmente no tenemos relaciones complejas.

Construir un buen modelo de dominio es costoso y requiere un tiempo de setup bastante grande. Si se sabe que la aplicación será simple y que no evolucionará con el tiempo, no tiene sentido invertir en la construcción de un modelo de dominio. Para eso existe el patrón Transaction Script.

Transaction Script es escencialmente un procedimiento que toma el input de la presentación, lo procesa, trabaja con una base de datos o invoca operaciones de otro sistema y devuelve datos a la presentación para que se los entregue a la vista.

El siguiente ejemplo muestra el cálculo del Pago de un Proyecto:



Es interesante destacar que este diseño no es para nada Orientado a Objetos. No tiene nada que ver que haya clases y métodos. No existe un Modelo de Dominio, por ende no tendremos una clase Pago, ni una clase Proyecto, simplemente un ServicioPago que accede a la BD a través de un simple Gateway, que devuelve un ResultSet con los resultados que el Gateway ejecuta.

Como se imaginarán, un Transaction Script es lo más rápido de construir y lo más difícil de mantener.

Table Module

¿Qué tal si el dominio es un poco más complejo? Obviamente si estructuráramos la arquitectura de la aplicación con un Transaction Script al poco tiempo estaríamos en problemas. Pero, ¿y si la aplicación no es lo suficientemente compleja como para justificar la costosa curva de inicio de un Modelo de Dominio? Para eso contamos con un patrón intermedio llamado Table Module.

Con Table Module no tenemos un Modelo de Dominio puro, pero casi. Ya podemos tener nuestra aplicación dividida en capas físicas (tiers), como estuvimos viendo en los post anteriores. Ya tendremos una capa de Negocio y también una capa de Persistencia. En la capa de Negocio vivirán los objetos de dominio, como Proyecto y Pago si seguimos con el ejemplo anterior, pero la diferencia con un Modelo de Dominio puro es que por cada tabla tendremos una instancia de negocio; habrá una instancia de Proyecto que represente a todos los proyectos y una instancia de Pago que represente a todos los pagos.

El siguiente ejemplo muestra cómo sería el cálculo del Pago de un Proyecto con Table Module:



Table Module está diseñado para trabajar con Record Set. La capa de persistencia podría ser un conjunto de Gateways que tiren consultas a la base de datos y devuelvan los resultados en Record Sets (o DataSet, como se muestra en los diagramas), que no son más que una representación en memoria de los resultados que pudo haber arrojado un query de SQL.

Esta forma de trabajar fue muy popular en .NET y también es la que se podría construir encima de un driver JDBC, por ejemplo. Por supuesto que la forma de estructurar el código con este patrón es mucho más ordenada que Transaction Script, hay menos duplicación y es más fácil de mantener, pero aquí también nos enfrentamos al problema de que al no tener un Modelo de Dominio puro, perdemos muchas de las ventajas de la Orientación a Objetos, como la herencia, el polimorfismo, etc. (Imagínense que heredar de Proyecto no nos proporcionaría las mismas ventajas que en una capa de negocio pura, ya que recordemos que un objeto Proyecto en Table Module es algo así como un Singleton, tendremos una única instancia para todas las representaciones de Proyectos).

Domain Model

Llegamos a la estrella de la Orientación a Objetos. El patrón del que venimos hablando hace dos posts: Domain Model.

En un Modelo de Dominio puro tendremos muchas desventajas y muchas ventajas. Como todo en software, Domain Model no es un bala de plata. Implementar un Domain Model implica un costo altísimo de diseño y construcción de código de infraestructura que sólo es rentable si la aplicación es lo suficientemente grande y compleja, y/o se prevee que deberá escalarse en el futuro.

Volvamos al ejemplo del cálculo del Pago de un Proyecto:



Domain Model es el patrón opuesto a Transaction Script. Ya no tendremos un solo Proyecto para todos los proyectos y un solo Pago para todos los pagos. Habrá una representación en memoria para cada instancia de Proyecto y una para cada instancia de Pago. Además que tendremos objetos exclusivos para resolver cuestiones de lógica de negocio como objetos de Estrategias y demás.

Junto con la implementación de un Domain Model vienen muchas complicaciones de temas de infraestructura que son parte del costo al que antes me refería.

Tendremos la complicación de la impedancia entre el mundo de los objetos y el mundo de las tablas, resueltos por ejemplo por el patrón DataMapper (los ORM son ejemplos de implementación de este patrón: Hibernate, TopLink, etc). En la capa de persistencia necesitaremos patrones más complejos que los simples Gateways. Patrones como DataMapper o Active Record, que se encargarán de mapear de alguna forma el Modelo de Datos que vive en la base de datos, generalmente de tablas relacionales, y el Modelo de Dominio que vive en la capa de Negocio.

Tendremos que encontrar una forma óptima de manejar y manipular estos objetos en memoria. Si el modelo cuenta con diez millones de proyectos, no podremos mantener diez millones de representaciones en memoria al mismo tiempo, ya que no sería óptimo ni físicamente posible. Para resolver esta cuestión existen patrones de infraestructura como Lazy Load, que suelen utilizar los Data Mappers para manejar el "paginado" en las relaciones y colecciones de objetos.

Además, tendremos problemas de concurrencia a nivel capa de dominio, ya que los objetos trabajarán desconectados de la base de datos. Aparecerán lo que se llama transacciones de negocio, donde una transacción de negocio puede incluir muchas transacciones de sistemas (accesos a la base de datos). Los objetos de dominio serán modificados, borrados, dados de alta, por distintos usuarios que estarán manipulando las mismas entidades, pero distintas representaciones locales, y todo esto en memoria, sin que la base de datos se entere. Una Unit of Work se encargará de mantener el registro de las modificaciones en los objetos y de impactar dichos cambios en la base de datos al final de cada transacción (con un commit o un rollback), y otros patrones se encargarán de la concurrencia entre las modificaciones de los distintos usuarios, como Optimistic Offline Lock, Pessimistic Offline Lock y/o Coarse-Grained Lock (el último está basado en el concepto de Agregaciones de Eric Evans de su Domain-Driven Design).

Trabajar con objetos es hermoso, pero implica la construcción de una fuerte y sólida infraestructura. Dependiendo de qué tan robusta sea esta infraestructura, serán más o menos transparentes todas estas cuestiones para un diseñador/programador de la capa de dominio.

A la hora de elegir

A la hora de elegir, Fowler nos propone un excelente gráfico cualitativo/comparativo entre los tres patrones de arquitectura:


En él podemos ver que a medida que crece la complejidad de la lógica de dominio de la aplicación, el esfuerzo en el Transaction Script y en el Table Module se dispara al infinito. Sin embargo, el costo de entender la complejidad de un Modelo de Dominio y de diseñar la infraestructura necesaria para soportar el mismo, es demasiado costosa para una aplicación simple. En la práctica, nadie sabe a ciencia cierta qué tan compleja puede ser la lógica de un negocio, no hay métricas ni formas estándares de medir esa complejidad. Por eso no es fácil ponerle valores a los ejes de este gráfico.

Los tres patrones no son mutuamente exclusivos. Algunas de las funcionalidades de una aplicación podrían estar implementadas con Transaction Script y otras con Domain Model. Otro punto para destacar es que los patrones no muestran una implementación por sí mismos. Los diagramas de clases y de secuencias que expuse no son más que representativos. Los patrones de diseño encapsulan ideas, no implementaciones; el qué y no el cómo.

domingo, 12 de octubre de 2008

El Dominio Es Lo Único Importante

La capa de negocio es la más importante porque es la única que no depende de la tecnología. Comúnmente se le llama Aplicación a lo que comprende las capas de presentación, acceso al negocio y persistencia, y Negocio específicamente a la capa de dominio.

Tiers de Aplicación:
  • Presentación
  • Acceso al Negocio
  • Persistencia
Tiers de Negocio:
  • Capa de dominio
Esta separación parece trivial, pero encierra conceptos fuertísimos que implican una forma de llevar la programación de una aplicación sencilla, tradicional, a una aplicación compleja como es una enterprise.

El dominio no depende de la aplicación

El primer concepto es que el dominio no depende de la tecnología o aplicación. Al no depender de la aplicación, tenemos aislado lo que es el módulo donde trabajarán fuertemente los analistas funcionales para representar el negocio en un modelo. Este modelo o dominio, que no es más que un conjunto de objetos y clases interrelacionados al mejor estilo de la programación orientada a objetos, es el negocio, y puede ser reutilizado en distintas aplicaciones, puede ser desenganchado de una aplicación e injertado en otra, con una tecnología completamente diferente, como si se tratara de una pieza de Lego.


Tiers V.S. Layers

El segundo concepto es que la arquitectura del dominio es independiente de la arquitectura de la aplicación. Y aquí nos encontramos con una primera disonancia conceptual, que nos lleva a clasificar las capas en físicas (tiers) y lógicas (layers).
  • Capas Físicas o Tiers: Son las capas que ya estuvimos viendo en el post anterior. Se llaman capas físicas porque en general son las más propicias a ubicarse en servidores distribuidos físicamente. Podemos contar, por ejemplo, con un servidor de aplicaciones distribuido, el SGBD podría ubicarse en un servidor, el dominio podría ser accedido de forma remota (mediante RMI o similar), el acceso al negocio podría ser consumido quizá mediante SOA por diferentes plataformas y/o dispositivos y los clientes ni hablar que podrían ser muchos y ubicarse en cualquier parte del planeta. De todas formas, aunque no tengamos servidores disgregados en el espacio, separar la aplicación en capas físicas nos ayuda a distribuir la lógica de la aplicación.
  • Capas Lógicas o Layers: Estas capas nos sirven para separar las incumbencias en la lógica del negocio. Si bien cualquier capa física, por dentro, podría contar con varias capas lógicas, en este post lo que más nos interesa es concentrarnos en la lógica de dominio. Por eso, cuando me refiera a layers, me estaré refiriendo a las capas lógicas que viven en el tier del dominio. Cuando un dominio es muy complicado y extenso, a menudo resulta útil para el analista y/o diseñador optar por una arquitectura de capas, donde en cada capa vivirán distintos paquetes que sólo se relacionan entre sí y con unos pocos paquetes de la capa inferior, o para ser más prolijos, con la interfase que publica la layer inferior.

Domain-Driven Design

El tercer y más trascendente concepto es que el dominio es lo único importante. Es una idea fuerte, básica, simple, y muy difícil de aceptar y/o implementar. Por eso es que no se suele aplicar en muchos ambientes de desarrollo, donde parece que la tecnología y la forma de resolver los requerimientos no funcionales es lo más prioritario.

Domain-Driven Design (DDD) es un conjunto de buenas prácticas, patrones y recomendaciones para construir software sólido y robusto a partir de la creación del dominio. Las bases fundamentales de esta forma de trabajar fueron establecidas por Eric Evans en su famoso libro: Domain-Driven Design: Tackling Complexity in the Heart of Software (ISBN: 0-321-12521-5). Eric Evans es un defensor fanático de esta idea de que el dominio es lo único importante y propone que todo el desarrollo de una aplicación (sea enterprise o no), debería ser guiado por el dominio. Yo no he leído el libro completo, pero sí un resumen gratuito del mismo, llamado Domain-Driven Design Quickly, que fue elaborado por Abel Avram y Floyd Marinescu para el popular sitio de diseño y programación de software InfoQ y puede descargarse libremente desde aquí simplemente registrándose (la registración también es gratuita).

Domain-Driven Design está dividido en dos grandes incumbencias:

  • La construcción de buenos Modelos (Model-Driven Design): donde se introducen los patrones Entities, Value Objects, Services, Modules, Aggregates, Factories y Repositories, que sirven para la construcción efectiva de un modelo de negocio correcto. Evans establece el polémico concepto de lenguaje ubicuo, en el que propone que todos los integrantes de un equipo de trabajo (incluyendo los clientes y expertos del dominio) deben comunicarse utilizando una misma terminología. Esta terminología en general será la del experto del dominio o, en algunos casos excepcionales, la que el analista funcional estableció mediante mutuo acuerdo con el experto del dominio. Evans explica que es importante que en toda comunicación, verbal o escrita, que se efectúe dentro del marco del proyecto, se utilice el glosario que el analista y el experto del negocio convinieron, inclusive si la charla es entre programadores. Esta imposición acarrea un corolario polémico y fascinante: no sólo el modelo de dominio y los diagramas de diseño deben usar este lenguaje, también el código fuente. Evans propone un código escrito a muy alto nivel, donde los nombres de cada objeto y/o componente del código (sea método, clase, variable, paquete, etc) sean extraídos directamente del glosario del lenguaje ubicuo.



  • La preservación de la integridad del Modelo: no sólo es importante construir un buen modelo, también es fundamental mantenerlo. Muchos de los conceptos de Eric Evans van de la mano de la filosofía de las metodologías ágiles. Evans nos dice que si hay modificaciones en el código o el diseño, deben ser reflejadas automáticamente en el modelo y, si hay modificaciones en el modelo, deben ser reflejadas en el diseño y en el código. Esta segunda parte del libro habla de refactorear constantemente, de actualizar periódicamente el glosario del lenguaje ubicuo, de reconocer los conceptos claves del modelo y mantenerlos vigentes a lo largo de todo el proceso de desarrollo. A medida que los dominios van creciendo, van apareciendo patrones a nivel macro y formas de separar contextos y de distribuirlos de diferentes formas para facilitar el desarrollo. Es aquí donde entra más que nada el mundo de las aplicaciones enterprise, porque si de ellas hablamos, hablamos de negocios complejos y de dominios extensos. Evans presenta los patrones de Bonded Context, Continuous Integration, Context Map, Shared Kernel, Customer-Supplier, Conformist, Anticorruption Layer, Separate Ways, Open Host Service y Distillation, que atacan de diferentes formas la escalabilidad y reorganización de modelos grandes.


La importancia de un dominio portable

Todo esto nos lleva a la idea de construir un dominio portable. El negocio es el core, la estrella única e indiscutida de toda aplicación enterprise. Hoy en día los frameworks que hay en el mercado que logran la portabilidad del dominio son pocos. El framework es parte de la tecnología, pero como su nombre lo indica es el marco de trabajo del desarrollo de software. En mi opinión, si somos estrictos con las enseñanzas de DDD, llamarle ingenuamente framework a una herramienta de trabajo es contradecir la filosofía de DDD. Deberíamos llamarle framework al modelo, al dominio, y no a la tecnología que usamos para construir la aplicación que ejecute ese dominio.

En los comienzos, y durante muchos años, las aplicaciones enterprise fueron diseñadas en base a la tecnología, y creo yo que la culpa, en gran parte, la tuvieron metodologías como RUP, que son orientadas al plan y a los casos de uso, y ofrecen baja adaptabilidad al cambio. Las metodologías ágiles, como Scrum por ejemplo, son más compatibles con la construcción iterativa de modelos y de desarrollos guiados por el modelo y no por los casos de uso.

Hoy en día contamos con herramientas o plataformas que son compatibles con las filosofías de DDD y que nos ofrecen una forma de construir la aplicación sin resultar intrusiva con el dominio. Spring es una de ellas, Seam es otra que está tomando mucha fuerza (de la gente de JBoss que parece decidida a convertirse en líderes de tecnologías java para aplicaciones enterprise). Las enseñanzas de Eric Evans están tomando tanta fuerza en los últimos tiempos que Sun Microsystem ha tenido que replantear su pesada e intrusiva plataforma de EJBs y así fue como surgió la flamante especificación EJB 3.0, que incluye la especificación JPA para persistencia la cual respeta casi religiosamente el modelo de desarrollo de DDD. El cambio de paradigma exigió que a los viejos y queridos objetos de una aplicación Java común y corriente, se les cambiara el nombre de objetos a POJOs (Plain Old Java Object), de los cuales hace uso EJB 3. En el blog de tecnologías java, junto a Paola Grajeda, hemos dedicado algunos post teóricos y prácticos a EJB 3.0 y es muy posible que sigamos escribiendo al respecto (Ver: http://tecnologiasjava.blogspot.com/search/label/EJB 3).

La importancia de un dominio portable, independiente de la plataforma y de la tecnología, es crucial para el mundo de los negocios. La evolución más actual de todo esto son las aplicaciones orientadas a servicios (SOA), donde todo diseño es sublevado al negocio y a la flexibilidad y al cambio. Las interfases deben ser contratos de negocio, auténticos servicios a consumir por los expertos del dominio. Los servicios hablan de los casos de uso, pero el dominio puede también seguir esta filosofía utilizando la doctrina de DDD.

El lema de una las herramientas inspiradas en DDD, muy poco conocida, llamada Roma dice: "Piensa en el dominio, construye el modelo en simples clases Java, escribe la lógica de negocio y Roma hará el resto". Suena ambicioso. Eric Evans, en DDD, propone asignar a los analistas programadores más experimentados la construcción de las clases y paquetes del dominio y, al resto de los programadores con menor señority, la configuración de la plataforma, en otras palabras: la aplicación.

Conclusión

Si analizamos la historia de la Ingeniería del Software, podemos llegar a la conclusión de que la madurez de los procesos de desarrollo (no sólo de aplicaciones enterprise) se ve en el grado de separación de incumbencias entre la lógica de negocio y la lógica de aplicación. La construcción de sistemas de software ha comenzado siendo muy técnica para derivar cada vez más en abstracciones y nuevas abstracciones hasta alcanzar un objetivo final: modelar y programar procesos de negocios independientes de la tecnología.

En el siguiente post, basándome en el famoso libro de Martin Fowler: Patterns of Enterprise Application Architecture y en las fabulosas clases de Arquitectura de Software que el Ing. Guillermo Pantaleo dicta en la FIUBA, escribiré sobre los patrones enterprise que nos permiten lograr esta separación entre negocio y aplicación y las formas en que una arquitectura enterprise puede estar diseñada, independientemente de la plataforma y/o lenguaje de programación.

Entradas Relacionadas:

domingo, 28 de septiembre de 2008

Aplicaciones Enterprise

Una aplicación enterprise es un sistema fuertemente orientado a un negocio determinado, que debe cumplir ciertos requerimientos no funcionales. En general, las aplicaciones enterprise:
  • persisten datos de forma masiva
  • suelen ser multiusuarios (varios usuarios pueden acceder de forma concurrente)
  • cuentan con muchísimas interfaces de usuario
  • se integran con otros sistemas
  • presentan disonancia conceptual (usuarios con vistas contrapuestas)
  • tienen lógica de negocio
¿Una aplicación enterprise es aquella que cumple con todas las características recién enunciadas? No necesariamente. En mi opinión personal, la única característica importante e imprescindible es la última. Una aplicación enterprise es aquella que tiene lógica de negocio, por eso empecé el post afirmando que es un sistema fuertemente orientado al negocio y por eso en mucha bibliografía a las aplicaciones enterprise se las suele llamar aplicaciones de negocio (business applications).

En general, que tengamos una lógica de negocio acarrea que debamos guardar el estado (los conceptos o las entidades) de esa lógica para poder recuperarlo en todo momento. También implica que esos conceptos puedan ser mostrados de alguna manera a los usuarios del negocio, a los clientes, y en general, los clientes suelen ser muchos, y suelen ejecutar consultas en paralelo. Así es como un requerimiento no funcional lleva a otro y nos encontramos con que, cuando nos enfrentamos a una aplicación enterprise que va creciendo en tamaño y complejidad, son necesarias casi todas las características antes enumeradas.

Casi se podría decir que cualquier aplicación compleja y grande es una aplicación enterprise. Yo diría que no es tan así, pero tampoco la afirmación está tan lejos de la verdad.

El concepto de aplicación enterprise nació con el fin de modularizar y organizar el desarrollo de aplicaciones complejas de negocio, cuyo número de desarrolladores, analistas, diseñadores crecía exponencialmente al paso que se multiplicaban los requerimientos no funcionales. Como la posibilidad de automatizar negocios cada vez más complejos se hizo posible gracias al escalamiento de hardware y de paradigmas y técnicas de programación más efectivas (como la orientación a objetos y las metodologías de desarrollo), se necesitó una forma de separar lo que es la lógica de negocio (requerimientos funcionales) de lo que es la lógica de la aplicación (requerimientos no funcionales). Entonces comenzaron a surgir algunos frameworks, primero en el mundo de Java, que intentaban lograr esta separación. Surgió la especificación de Sun Microsystems para los Enterprise Java Beans (EJB) y un tiempo después Microsoft se metió en el mercado para hacerle frente con una plataforma bastante más sencilla llamada .NET, pero que demoró mucho en madurar.


Durante demasiados años, tanto la plataforma enterprise de Java (J2EE) como .NET tuvieron muchísimos problemas. Las especificaciones no eran del todo felices y, en el afán de abstraer al programador de los requerimientos no funcionales comunes a todas las aplicaciones enterprise (la lógica de aplicación), las herramientas para diseñar una buena lógica de negocio se vio limitada, brutalmente recortada, logrando que la programación orientada a objetos retrocediera unos cuantos pasos. Hasta se habló de anti-patrones en J2EE y se publicaron varias tesis y artículos al respecto. ¡Pero era lo que había!

Recién hace tres o cuatro años que el panorama está mejorando. No fue hasta que comenzaron a surgir los famosos frameworks livianos (como Spring por ejemplo) que los programadores pudieron volver a aplicar la programación orientada a objetos en todo su esplendor para construir lógicas de negocio más robustas, escalables y parecidas a la realidad. Sun Microsystem tomó muchas de las ideas de los frameworks livianos y lanzó una nueva especificación: EJB 3.0, a la vez que cambió el nombre de su plataforma J2EE a JavaEE.

Arquitectura de 4-tiers

Los requerimientos no funcionales más comunes en una aplicación enterprise son:
  • Bajo Tiempo de Respuesta
  • Alta Interactividad con el Usuario
  • Baja Latencia
  • Muchas Transacciones por segundo (throughput)
  • Alta Carga (número de usuarios concurrentes)
  • Baja Degradación (variación del Tiempo de Respuesta con la Carga)
  • Alta Eficienta (performance)
  • Alta Capacidad (máxima entre el throughput y la carga)
  • Alta Escalabilidad (horizontal: + servidores; vertical: +CPU,+memoria)
  • Alta Disponibilidad o Nivel de Servicio
Para satisfacer este tipo de requerimientos, en general, las aplicaciones enterprise han adoptado un tipo de arquitectura casi estándar, que consiste en dividir el sistema en cuatro capas físicas (tiers):
  • Presentación
  • Acceso al Negocio
  • Negocio o Dominio
  • Persistencia

El Cliente, por ejemplo un browser (si hablamos de una aplicación web) o una ventana gráfica del sistema operativo (si hablamos de una aplicación desktop), accede a la capa de Presentación. La capa de presentación es responsable del formateo de los datos para la visualización y de la interpretación de los comandos del usuario. En la capa de presentación podrían vivir los servlets, por ejemplo, si hablamos de una aplicación web en Java.

Esta capa podría acceder directamente a la capa de negocio o dominio, de hecho muchos autores proponen eso. Pero en realidad, lo más correcto sería contar con una capa (que a veces es muy delgada) entre la de presentación y la de dominio, para que desacople ambas y podamos construir distintas presentaciones que accedan concurrentemente y se abstraigan del uso de la lógica de negocio. Esta capa de la que hablo es la de Acceso al Negocio o Capa de Aplicación o Capa de Servicio (Martin Fowler la llama Service Layer). En la capa de Acceso al Negocio vivirán los casos de uso del sistema, los requerimientos funcionales, los servicios de la lógica de dominio, de la lógica de negocio, que deben ser expuestos. Esta capa tendrá permiso para manipular los objetos de negocio que viven en la Capa de Negocio, en el dominio de la aplicación. Podría decirse que se trata de un facade del dominio.

La Capa de Negocio es la más importante, ya que aquí es donde vive el modelo, donde vive la lógica de negocio y, como antes mencioné, la lógica de negocio es lo más importante en una aplicación enterprise. Prefiero no hablar mucho ahora del dominio ni de la clase de modelos que uno puede insertar ahí dentro, ya que planeo dedicar varios post en el futuro a su construcción y las implicaciones filosóficas y técnicas que ésta acarrea.

Por último, tenemos una capa de Persistencia, cuya función principal es la de desacoplar la aplicación de la base de datos para no depender de un SGBD específico y gestionar el acceso a la misma de forma eficiente. Esta capa debería hacernos menos dolorosa una posible migración futura de base de datos.

Si prestan atención al gráfico de arquitectura pueden ver que la capa de Acceso al Negocio apunta a la capa de Dominio, y a su vez, la capa de Persistencia también apunta a la capa de Dominio. Estas flechas que parecen tan inocentes están simbolizando dependencia. Según cómo el framework implemente la capa de Persistencia, el dominio apuntará a la de Persistencia o al revés. Lo que trata de hacer un ORM como Hibernate, por ejemplo, es invertir la dependencia del flujo normal de tiers para que el dominio no tenga que conocer absolutamente nada de la aplicación. De esta forma, logramos desacoplar por completo la lógica de negocio, para usarla en cualquier otra aplicación o plataforma.

En post futuros profundizaré sobre este tema.

jueves, 4 de septiembre de 2008

Val IT

La iniciativa Val IT, en la que se incluyen investigaciones, publicaciones y servicios de soporte, tiene como objetivo ayudar a la gerencia a garantizar que las organizaciones logren un valor óptimo de las inversiones de negocio posibilitadas por TI a un coste económico, y con un nivel conocido y aceptable de riesgo. Val IT proporciona guías, procesos y prácticas de soporte para ayudar al consejo/directorio y a la dirección ejecutiva a comprender y desempeñar sus roles relacionados con dichas inversiones.


En concreto, Val IT se centra en la decisión de invertir (¿estamos haciendo lo correcto?) y la realización de beneficios (¿estamos obteniendo beneficios?). CobiT se centra específicamente en la ejecución (¿lo estamos haciendo correctamente?) (¿lo estamos logrando bien?).


La aplicación eficaz de los principios, procesos y prácticas contenidas en Val IT permitirá a las organizaciones:
  • Aumentar el conocimiento y transparencia de los costes, riesgos y beneficios, dando como resultado decisiones de gestión mucho mejor informadas.
  • Aumentar la probabilidad de seleccionar inversiones que tengan el potencial de generar la mayor rentabilidad.
  • Aumentar la probabilidad de éxito al ejecutar las inversiones elegidas de modo que logren o sobrepasen su rentabilidad potencial.
  • Reducir costes no haciendo cosas que no deben hacerse y tomando rápidamente medidas correctivas o terminando inversiones que no están cumpliendo su potencial esperado.
  • Reducir el riesgo de fracaso, especialmente el fracaso de alto impacto.
  • Reducir sorpresas en relación con el coste y entrega de TI, y de esa forma aumentar el valor del negocio, reducir costes innecesarios y aumentar el nivel global de confianza en TI.
Val IT complementa a CobiT desde el punto de vista financiero y de negocio, y ayudará a todos aquellos con un interés en la entrega de valor a partir de TI. Es responsabilidad del consejo, del Director General y de todos los ejecutivos garantizar la optimización de la rentabilidad de los accionistas y socios mediante el uso juicioso de los recursos y oportunidades disponibles. Esta responsabilidad abarca las inversiones de negocio y recursos de TI donde los costes, la visibilidad de éxito o fracaso y los riesgos de destrucción de valor son altos, pero existe un evidente potencial para una creación importante de valor.

El Marco

Val IT consiste en un conjunto de principios directrices y varios procesos acordes con dichos principios, que además se definen como conjunto de prácticas de gestión.

Val IT permite soportar el objetivo de negocio de
Realizar un valor óptimo de las inversiones de negocio impulsadas por IT a un coste económico y con un nivel aceptable de riesgo

____y está guiado por
____Un conjunto de principios aplicados a procesos de gestión de valor

________que son impulsados por
________Prácticas claves de gestión con referencias cruzadas a los controles claves de CobiT

____________y que se miden por
____________Métricas de resultados y rendimiento

Principios

  • Las inversiones posibilitadas por TI se gestionarán como cartera de inversiones.
  • Las inversiones posibilitadas por TI abarcarán el pleno alcance de actividades que son necesarias para lograr el valor de negocio.
  • Las inversiones posibilitadas por TI se gestionarán a lo largo de su ciclo de vida económico completo.
  • En las prácticas de entrega de valor se reconocerá que existen distintas categorías de inversión cuya evaluación y gestión será diferente.
  • En las prácticas de entrega de valor se definirán y monitorizarán las métricas claves y se responderá rápidamente a cualquier cambio o desviación.
  • Las prácticas de entrega de valor implicarán a todos los stakeholders y se asignará la responsabilidad correspondiente para la entrega de capacidades y la realización de beneficios del negocio.
  • Se hará un monitoreo, evaluación y mejora conti nua de las prácticas de entrega de valor.

Procesos

  • Gobierno del valor
  • Gobierno de cartera
  • Gobierno de inversiones

Buen Gobierno del Valor: VG – Value Governance

El buen gobierno del valor tiene como objetivo optimizar el valor de las inversiones posibilitadas por TI de una organización:
  • Estableciendo el marco de buen gobierno, monit oreo y control
  • Marcando la dirección estratégica para las inversiones
  • Definiendo las características de la cartera de inversiones

Gestión de Cartera: PM – Portfolio Management

La gestión de cartera tiene como objetivo asegurar que la cartera global de inversiones posibilitadas por TI de una organización esté alineada con l os objetivos estratégicos de ésta, y contribuyendo valor óptimo a los mismos:
  • El establecimiento y gestión de perfiles de recursos
  • La definición, priorización y selección, aplazamiento o rechazo de nuevas inversiones
  • La gestión de la cartera global
  • El monitoreo e informes sobre el rendimiento de la cartera

Gestión de Inversiones: IM – Investment Management

La gestión de inversiones tiene como objetivo asegurar que los programas individuales de inversiones posibilitadas por TI entreguen un valor óptimo a un coste económico y con un nivel conocido y aceptable de riesgo, mediante:
  • La identificación de necesidades de negocio
  • La adquisición de un claro entendimiento de los programas de inversión candidatos
  • El análisis de las alternativas
  • La definición del programa y la documentación de un caso de negocio detallado, incluyendo detalles de los beneficios
  • La asignación clara de responsabilidad y propiedad
  • La gestión del programa durante todo su ciclo de vida económica
  • El monitoreo e informes sobre el rendimiento del program a
Existen tres componentes claves de la gestión de inversi ones:
  • Desarrollo del caso de negocio: Dando soporte a la selección de los programas de inversión oportunos
  • Gestión de programas: Gestionando la ejecución de los p rogramas
  • Realización de beneficios: Gestionando activamente la realización de los beneficios de los programas

Prácticas Claves de Gestión que Soportan los Tres Procesos


Fuentes

domingo, 31 de agosto de 2008

Tecnologías Java


Un nuevo blog de informática ha nacido: Tecnologías Java. Como bien indica su nombre, el blog estará dedicado a lo que es el vasto y maravilloso mundo de las tecnologías Java.

Los autores que mantendrán este blog son:
  • Paola A. Grajeda: quien cuenta con amplia experiencia en desarrollo de aplicaciones enterprise escritas en Java. Actualmente trabaja como consultora de tecnología y analista desarrolladora Java. Es estudiante de Sistemas en la Facultad de Ingeniería de la Universidad de Buenos Aires y se encuentra cursando las últimas materias de la carrera.
  • Adrián M. Paredes: el mismo que ya conocen, si siguen este blog. También desarrollador Java, y estudiante de la Facultad de Ingeniería de la UBA.
Tecnologías Java se ha abierto esta semana y ya pueden encontrarse dos interesantes entradas:
¿Qué podrán encontrar en el futuro en este blog? Esperemos que mucho. En principio sabemos que muy pronto se vendrá la segunda parte de la Introducción a EJB 3 (que planeo redactar durante el mes de septiembre), y tal vez más adelante tengamos notas sobre los contenedores JBoss y Glassfish, sobre RichFaces, JFreeChart, Seam, Hibernate, y no sólo tecnologías para JavaEE, también es posible que escribamos artículos dedicados a aplicaciones desktop y aplicaciones JavaME para celulares.

Es un proyecto ambicioso, considerando la disponibilidad horaria de los autores. Sin embargo, Tecnologías Java aspira a ser más que un blog; aspira a ser, en un futuro (esperemos) no tan lejano, una referencia muy útil para el mundo de desarrollo Java.

Como dice un viejo proverbio chino: "Un viaje de tres mil leguas empieza con un solo paso".


Espero que les sirva.

Por un mundo más libre!
Salud!

martes, 19 de agosto de 2008

El Sistema Operativo Más Sencillo

Sinceramente, no me imagino que pueda existir un usuario que prefiera utilizar un sistema operativo (SO) que no sea el más sencillo posible. Lo ideal es que resulte transparente al usuario final. Un SO no debe obstaculizar la ejecución de los programas que los usuarios utilizan a diario para trabajar. Por eso, nadie quiere tener problemas con él. Es más común encontrar usuarios dispuestos a tolerar bugs de aplicaciones, que bugs de SO. Los bugs de los sistemas operativos resultan altamente irritantes.

Durante muchos años, la publicidad de Microsoft nos ha vendido que Windows es el SO más sencillo de usar. Muchos, hoy en día, lo siguen creyendo. Me aventuro a pensar que más del 90% de los usuarios de PC deben tener esta convicción. En los últimos años, han surgidos miles de blogs y páginas idolatrando a las distintas distribuciones de Linux. Hoy, Linux es una opción muy estable y fuerte para PC. No es tan popular como el monstruo de Microsoft, pero los usuarios de Linux (muchísimo más fundamentalistas que los de Windows) se han encargado de propagar por todos los medios la idea de que Linux es más estable, sencillo y seguro.

Creo que no cabe duda que cualquier distribución de Linux es más segura que todas las versiones de Windows juntas. Practicamente no existen virus que ataquen al SO del pungüino (Tux para los amigos), ni fallas de seguridad importantes (agujero como el que se encontró hace poco en los algoritmos de encriptación que usa Debian no es nada comparado a todos los backdoor y vulnerabilidades que siempre tuvo Windows). En el terreno de estabilidad, los dos parecen bastante parejos (quizá Linux siga ganando un poco más la batalla como servidor). Pero si nos adentramos en el terreno de lo "sencillo", de la usabilidad, nos enfrentamos a conceptos subjetivos y a mucho-fanático-que-anda-dando-vuelta.

Parafraseando a Obi-Wan Kenobi en Star Wars Episode III: "Sólo los tiranos piensan en absolutos".

La mente humana tiende a ser fanática, tiende a pendular entre los extremos con cada decisión bivalente a tomar. Esto significa: hoy soy fanático a morir de Java, mañana descubro que Java no era perfecto y me hago fanático a morir de .NET, pero también encuentro que .NET no es perfecto y vuelvo a Java, pero no tan al extremo, y así mi fanatismo oscila como un péndulo que es detenido de a poco por la fricción, hasta paralizarse en un punto medio, que a menudo es el más indicado.

Hoy en día, decir que Windows es más fácil de usar que Linux es haberse quedado en el tiempo o haberse convertido en un fundamentalista. Lo mismo al revés. Linux no es más sencillo que Windows. Windows no es más sencillo que Linux.

La distribución de Linux que más se parece en prestaciones, difusión y usabilidad a Windows es Ubuntu. La última versión estable hasta el momento, Ubuntu Hardy Heron, es muy sencilla. Sinceramente, entre Windows Vista Ultimate y Ubuntu Hardy Heron, yo elijo el segundo, y no por cuestiones ideológicas. Ubuntu Hardy Heron me pareció más fácil de usar.

Pero, como toda opinión sobre usabilidad, la afirmación anterior es subjetiva. Seguramente habrá muchos usuarios que les parezca más sencillo Windows Vista.

Mi opinión tiene fundamento. Muchas veces me ha pasado que para hacer algo que necesito, en Windows tengo que instalar dos o tres aplicaciones (a veces privativas) y aprender a usar complicadas interfaces gráficas y, en cambio, en Ubuntu, basta con un único programa o un simple comando de consola.

Para los windowseros que no me creen, a continuación menciono tres simples ejemplos.

Mirar archivos de video 3GP capturados con un celular

Para Windows la solución fue instalar una aplicación pesada como QuickTime (que en particular a mí siempre me resultó molesta) o convertir los archivos a AVI con un conversor (como resultado los archivos terminan pesando más).

Para Ubuntu la solución fue abrir una consola y escribir:

$ sudo wget http://www.medibuntu.org/sources.list.d/hardy.list -O /etc/apt/sources.list.d/medibuntu.list

$ wget -q http://packages.medibuntu.org/medibuntu-key.gpg -O- | sudo apt-key add - && sudo apt-get update


Encontrar estas dos líneas para agregar el repositorio de medibuntu a mi sources.list y actualizar el sistema, me costó menos de cinco minutos de googleo. Bajar el QuickTime e instalarlo, todos saben lo molesto que es.

Y encima hay distribuciones de Linux en las que ni siquiera hace falta instalar los codecs necesarios porque ya vienen instalados por defecto.

Girar un video

Necesitaba puntualmente girar un video (también un 3gp). Con Windows la única opción que encontré fue bajarme un programa conversor de 3gp a AVI, un programa que permitiera rotar AVIs y después volver convertir a 3gp si lo deseaba.

Con Ubuntu simplemente tuve que bajar/instalar un codificador GPL llamado memcoder, tipeando en la consola:

$ sudo apt-get install mencoder

Y luego el comando para rotar la imagen los grados que yo necesitaba:

$ mencoder -vf rotate=3 -oac pcm -ovc lavc 27-05-07_2346.3gp -o salida.3gp


Si a alguien le interesa, la explicación de este comando la encontré en este post de mundogeek.

Montar una ISO

Si alguno aún sigue preguntándose por qué Ubuntu me parece más sencillo que Windows, espere a leer este ejemplo, que para mí es el mejor.

Para montar un archivo ISO de un CD o DVD en una unidad virtual, en Windows es necesario una aplicación como Daemon Tools, que encima es propietaria.

Con Linux, el montaje de un archivo ISO es trivial, ya que lo soporta el mismo comando mount del SO y no se necesita instalar ningún programa. Simplemente teniendo cargado el módulo loop del kernel, que casi siempre está, uno puede abrir una consola y escribir:

$ sudo mount -t iso9660 -o loop archivo.iso /media/iso

Y si no me creen, échenle un vistazo a esta página de guia-ubuntu.

Conclusión

Algunas tareas son más sencillas con Windows. Algunas tareas son más sencillas con Ubuntu. Hablo de estos dos SO porque son los que conozco. Lo importante es: lo que puede parecerle fácil a un usuario, puede resultarle difícil a otro, y viceversa. Quizá algunos necesiten sí o sí manipular una ventana y tengan miedo de abrir una consola; quizá otros, como yo, a veces se mareen con una interfaz gráfica rebuscada y prefieran algo más simple y directo como escribir una línea de texto. "Sobre gustos no hay nada escrito".

Espero que les haya servido.

Por un mundo más libre!
Salud!