Artículos

jueves, 4 de julio de 2013

Influencia de SOAP y REST en la creación de arquitecturas SOA y Web Services

Introducción 


¿Cuál es la mejor forma armar una arquitectura SOA y cuál para crear Web Services abiertos a Internet?

Desde hace tiempo que vengo leyendo información sobre la exposición de Web Services en formato  SOAP y REST, prestando especial atención a sus características pero también a sus objetivos.
Y en este punto es donde me voy a detener para presentar en este breve ensayo mi postura respecto de la elección de uno u otro formato a la hora de construir una arquitectura SOA o simplemente exponer servicios web

Supuestos


Para responder a las preguntas de la introducción voy a manejarme con definiciones solo conceptuales sobre cada tema sin entrar en detalles técnicos de cada uno dado que abunda la información en Internet y libros respecto de los detalles de SOAP, REST, SOA y Web Services.

En caso de no encontrarse el lector familiarizado con estos conceptos o sus pormenores dejo enlaces de interés que brindan tal información. Sin embargo aconsejo revisar múltiples fuentes de información para completar mejor el conocimiento.






Desarrollo


Es muy importante tener en claro cuáles son los fundamentos y diferencias que existen entre SOA y Web Services a la hora de decidir aplicar REST o SOAP

SOA


Como sabemos, SOA es una arquitectura de software que busca dar soluciones a los proceso de negocio de una empresa que atraviesan múltiples sistemas informáticos para su cometido.
Por ejemplo, una empresa adquiere un nuevo beneficio para sus empleados (por ejemplo, contrata los servicios de un restauran que le da 20% de descuento en los almuerzos a sus empleados). Este proceso de negocio: "adquirir beneficio corporativo" si bien generalmente es disparado por el área de RRHH tiene implicancias en otras áreas de la empresa. Por ejemplo podría afectar al área de proveedores, facturación, marketing, etc.
Y esta afectación se ve reflejada cuando cada una de estas áreas tiene que cargar en sus sistemas alguna información proveniente de esta adquisición u otras áreas.
El proceso es uno , "adquirir beneficios corporativos" y las implicancias son muchas.

Sin una arquitectura SOA la solución a esta situación son dos: empleados de diferentes áreas cargan datos en sistemas por separado (incluso a veces datos repetidos) y se mandan entre sí archivos  para completar otros sistemas, o el mismo proceso pero automatizado, es decir, cada sistema prepara una "integración" con otro sistema y se ponen de acuerdo en la forma en que se trasmitirán los datos. En muchos casos esto es una solución que consiste en inventar la rueda con cada sistema nuevo a integrarse.

Con una arquitectura SOA los sistemas implicados deberían exponer como servicios bien definidos, basados en protocolos estándar (nada de cosas a medida o propietarias) aquellas funcionalidades que son importantes para la organización y ésta tendría la posibilidad de interconectar estos servicios diversos para cumplir con un proceso de negocio.
En este sentido,  "adquirir beneficios corporativos" podría ejecutarse desde una interfaz gráfica centralizada ( o distribuida en varias dependiendo de la necesidad )  y detrás se encontrarían llamadas a diversos servicios expuestos por los sistemas propietarios de cada área.
Estas llamadas requieren, por supuesto, un proceso de orquestación de parte de quien los integra y esto lo podría realizar personal propio de la empresa o encargar el trabajo a alguna empresa con experiencia en este tipo de arquitecturas.

Entonces podemos comprender que SOA en realidad tiene, al menos, dos grandes desafíos: 

  • Hacer que los sistemas ( los más importantes de cara a la empresa) expongan su funcionalidad como servicios con protocolos estándar y bien definidos (documentados)
  • Orquestar los servicios en función de los diferentes procesos de negocio que atraviesan múltiples áreas ( implica un proceso previo de relevamiento para detectar estos procesos y la prioridad de los mismos ) 

Web Services


Desde un punto de vista de alto nivel, los Web Services son una excelente forma de implementar llamadas a procedimientos remotos (RPC). La excelencia está dada por sus características técnicas (protocolo HTTP, independencia entre cliente y servidor, etc.) y la idea subyacente es realmente muy simple: ofrecer funcionalidad remota a quien la necesite para construir así sistemas cada vez más grandes y más desacoplados.

Supongamos este escenario: una empresa de energía utiliza un sistema de cobranzas que operan los empleados para cobrarle a los clientes. Como todo sistema, requiere algún gasto de mantenimiento y/o soporte, de manera que, en realidad, el sistema es un activo de la empresa pero que genera costo. Si se aplicare un proceso de re-ingeniería que permitiere exponer como Web Services las funcionalidades más importantes del sistema, la empresa podría ofrecer estos servicios a otras empresas y abrir así su canal de cobranza (por ejemplo, permitir que se pueda cobrar los servicios en un supermecado).
De esta forma se necesitarían menos puntos de cobranza exclusivos de la empresa y se abrirían nuevos puntos variables, generando así ahorro de gastos y hasta podría llegar a comercializar estos Web Services para obtener algún otro ingreso adicional.

Las características técnicas de los Web Services implican un desafío importante en la toma de  decisiones de arquitectura porque se debe aplicar un formato de comunicación lo más estandarizado y eficiente posible.

Dado que estamos hablando de la posibilidad de hacer llamadas a procedimientos remoto basadas en estándares es natural comprender que la implementación de SOA generalmente se hace por medio de Web Services. Pero es igual de cierto que no toda implementación de Web Services es sinónimo de estar aplicando una arquitectura SOA.

SOAP y REST


¿De dónde nace entonces la dicotomía SOAP / REST?

REST es una arquitectura, no un protocolo en particular o una tecnología. Básicamente parte de una premisa fundamentalmente distinta de la de SOAP y esta más alineado con el funcionamiento ideal del protocolo HTTP.
Esta premisa supone que todo lo que existe en la web ( o intranet ) en realidad son recursos (URL) y por lo tanto podemos aplicar distintas acciones sobre ellos (verbos de HTTP).
En un nivel mayor de abstracción entonces nos encontramos que quienes pensaron el protocolo HTTP pensaron que si los recursos son sustantivos, las acciones serían verbos que se aplican sobre estos sustantivos ( ver http://blog.tordek.com.ar/2008/03/como-le-explique-rest-a-mi-esposa/ ).
Por eso la propuesta de REST es muy natural a la forma en que los humanos interactuamos con las  cosas.
Los verbos Delete, Put, Get, Set, en esta perspectiva cobran sentido si pienso que al utilizarlos le estoy diciendo al servidor (borrar NNN, obtener NNN, etc.).
Sin embargo no debemos perder de vista la premisa fundamental de REST: lo que hay remoto son recursos (sustantivos), no operaciones.

SOAP es un protocolo basado en XML que sirve para el transporte de mensajes y respuestas entre cliente y servidor que, junto con WSDL, generan un contrato, una especificación que dice claramente cómo debe realizarse una llamada a un procedimiento remoto, cual será el tipo de dato devuelto y cuáles son los tipos y cantidad de parámetros a recibir.
Pero lo más importante es que parte de una premisa fundamentalmente distinta a REST: aquí el protocolo HTTP es solo un medio de transporte de mensajes.
La operación (o verbo ) no se hace explícita en la llamada HTTP, sino que se encuentra implícita dentro del procedimiento remoto que atiende la llamada.
No le digo al servidor "borrar XXX" sino "llamar a XXX y darle YYY", siendo YYY el mensaje para que XXX haga lo que tenga que hacer (por ejemplo un borrado).

La dicotomía entonces se presenta porque hay quienes argumentan la creación de Web Services en favor de uno u otro, con premisas válidas en todos los casos, pero que a mi juicio no consideran el objetivo de lo que estamos hablando.
Generalmente el debate pasa por cuestiones técnicas: que si me ahorro más Bytes, que si tengo menor acoplamiento entre cliente y servidor, que puedo usar objetos tipados, que la seguridad, etc.
Planteada la discusión en esos términos la conclusión generalmente es que termina siendo casi una cuestión de gustos o tendencia ( me decepciona creerlo pero lo he visto, hay quienes siguen patrones o metodologías solo porque lo hace la mayoría solamente ).

No estoy planteando que  hay que desconocer las tendencias, sino que hay que usar la herramienta/técnica adecuada para el problema/momento indicado, no solo porque nos gana la pereza y entonces hacemos lo que hacen todos.

Conclusión


Si nuestro objetivo es utilizar la herramienta más indicada no solo por cuestiones técnicas, podré valorar todas las opciones, reconocer las adecuadas para cada momento y aplicarlas cuando sea necesario.

En este sentido creo que si lo que necesitamos es una arquitectura SOA (es decir, darle solución de integración a sistemas para atender los procesos de negocio) la solución sería que mis sistemas ofrezcan operaciones cerradas, atómicas, bien definidas, basadas en estándares que sean fácil y seguras de interconectar. Es decir, la premisa de SOAP (exponer operaciones por medio de mensajes) se acomoda más naturalmente a la solución que necesito.

Pero si lo que estoy buscando es una arquitectura orientada a Web Services, los cuales puedan ofrecer recursos concretos (más allá de HTML incluso, por ejemplo imágenes, archivos, etc.) entonces mi enfoque se ajusta más a REST, donde puedo pensar una arquitectura basada en recursos a los cuales según mi necesidad puedo aplicarle diferentes acciones (Get, Put, etc.).

Ahora, ¿cómo decidir si necesito SOA o solo Web Services?.

A mi juicio, si la aplicación va a estar en  Internet y permitirá realizar operaciones sobre diferentes recursos, donde quienes quieran consumir estos recursos deberán seguir mi estándar y documentación para interpretarlos con el formato JSON correspondiente, creo que corresponde una arquitectura orientada a Web Services en formato REST.

Pero si mi aplicación utiliza el entorno Web solo como medio de despliegue, pero en realidad es una aplicación comercial que busco poder integrarla por medio de operaciones con otras aplicaciones comerciales de manera segura, basada en estándares, entonces creo que corresponde una arquitectura orientada a SOA con Web Services en formato SOAP.

Las cuestiones técnicas y las modas/tendencias no deberían ser, a mi juicio, el factor decisivo para tomar una decisión de Arquitectura tan importante.

Fuentes






Rest Vs Web Services: Rafael Navarro Marset. ELP-DSIC-UPV
Modelado, Diseño e Implementación de Servicios Web 2006-07


miércoles, 22 de mayo de 2013

Ejemplos prácticos de Asociación, Agregación, Composición y Dependencia con C# .Net

Motivación

En la actualidad (Mayo 2013) existe mucho material en Internet que habla sobre asociación, composición, agregación y dependencia pero en la mayoría no se pone énfasis en la implementación de los conceptos sino en el análisis conceptual.

La realidad es que la forma de implementar cada tipo de relación es diferente (aunque parezcan mínimas las diferencias) pero es muy importante para un programador conocerlas a la hora de leer un diagrama de clases.

Es importante también aclarar que un diagrama de clases realizado por un analista funcional no es un modelo que se debe implementar así directamente, sino que debe ser analizado y comprendido por el programador para producir el verdadero diagrama de clases a implementar.

Eso es así debido a que durante el análisis y relevamiento se piensa en "describir" y no en solucionar. Así, el diagrama del analista funcional explica el domino del problema, mientras que el diagrama que realiza el programador explica el dominio de la solución. En este último pueden surgir clases que originalmente no estaban pero son necesarias para realizar una buena implementación  (cuestiones de arquitectura, patrones, etc.).

Aplicación práctica y conceptual


Es necesario acostumbrarse al término implementación, el cual se refiere al código de programación concreto de algo.
Por ejemplo, si dicen "esta clase es la implementación de aquella " están diciendo "este es el código fuente específico que aplica lo que dice aquella clase abstracta (o interfaz) ".
Por tal motivo, en adelante, me referiré directamente al término implementación.

Tanto la asociación, agregación, composición y dependencia son formas de representar las relaciones que existen entre clases.

Por ejemplo el siguiente diagrama:



La clase Persona tiene una relación de composición con la clase Domicilio.

Conceptualmente esto significa que los domicilios son una parte inseparable de la persona, por lo que si no existiera una persona entonces el domicilio de la misma debería desaparecer.
Si analizamos más en profundidad encontramos también que, si hubiera que persistir esta relación en una base datos tendríamos una tabla Domicilios cuyo ID sería IdPersona, y una tabla Personas con el mismo ID.
El hecho de que la tabla Domicilios no tenga su propio ID sino el de la otra tabla significa que cada registro de la tabla no tiene el peso propio suficiente, que depende 100% de la existencia del mismo ID en la tabla de Personas.
Si se llegase a borrar un registro de la tabla Personas habría que borrar su correspondiente registro de la tabla Domicilios para mantener la integridad de la información.
Por esta razón también se dice que la relación de composición es una relación fuerte, ya que una instancia arrastra a la otra en caso de eliminación (tanto de objetos en memoria como de registros en base de datos).

Ahora, es válido preguntarse ¿por que razón si es algo inseparable de la persona no lo pongo como un atributo más de la clase persona, por ejemplo de tipo string y no me complico tanto?

Efectivamente la clase Domicilio es un atributo de la clase Persona, y justamente la línea que las conecta es lo que indica la presencia del atributo. Domicilio existe como clase aparte porque en realidad no es un simple string sino un conjunto de atributos, por ejemplo: calle, localidad, numeración, piso, departamento, etc. Todos esos atributos forman parte de una entidad, el Domicilio, y no sería correcto dejarlos sueltos dentro de la clase Persona. Por eso también se persisten en tablas separadas si fuera necesario.

La clase Persona tiene una relación de Agregación con Categoría.

Conceptualmente esto significa que las categorías existen independientemente de la persona que la tenga asignada. En el modelo conceptual esto se corresponde con un enunciado como "una persona puede tener una categoría pero una categoría puede estar presente en muchas personas".
En un modelo de persistencia relacional tendríamos por un lado la tabla Categorías con su IdCategoría y la tabla Persona con un IdCategoría que señale la relación entre ambas tablas.
A diferencia de la composición, en la agregación la clave primaria de la tabla Categorías es independiente de la clave primaria de la persona, lo cual significa que se puede eliminar un registro de Personas sin que ello afecte la integridad de la tabla Categorías.

Ambos tipos de relación muestran que la forma del objeto (persona en este caso) está formado por partes externas.

La clase Persona tiene una relación de Dependencia con Postulación.

Conceptualmente esto significa que la Postulación es un objeto que la Persona utiliza para algún fin, dentro de alguna operación que ella realice (por ejemplo Postularse a un cargo). Pero una Persona no tiene en su interior una Postulación, sino que solo lo utiliza para realizar ciertas operaciones.
Esto es lo más importante y diferenciador respecto de las otras dos relaciones; aquí se pone énfasis en el uso de clases dentro de operaciones, es decir, para que una Persona pueda enviar una postulación depende la clase Postulación , quien es capaz realmente de realizar esa operación.
Al no tratarse de una relación que vincula la forma de los objetos, no existe una forma de persistir esta relación.

La clase Persona tiene una relación de Asociación con Sucursal.

Conceptualmente la asociación en un diagrama de clases implica transitividad y bidirección de clases. Por ejemplo una persona tiene como atributo interno a una Sucursal, pero (y aquí está la diferencia) una Sucursal también tiene un atributo de tipo Persona; la cardinalidad de la asociación indicará si Sucursal tiene una o muchas instancias de Persona, con lo cual en realidad el atributo de Sucursal podría ser una Lista o Vector de Personas.
Otra característica fundamental es que la vida de las instancias de ambas clases no dependen una de la otra.
En un modelo de persistencia relacional podrían suceder dos cosas: si se trata de una cardinalidad de 1 a 1 tendríamos la tabla Personas con su IdPersona más un IDSucusal y la tabla Sucursales con su IdSucursal más un IdPersona.
Cualquier otra cardinalidad requerirá la tabla Personas y Sucursales con sus Id individuales más una tabla que unifique ambas entidades (tabla de relación) con los campos IdPersona e IdSucursal, la cual permite la navegación en dos direcciones sin invadir a ninguna de las tablas reales.

El caso especial se presenta cuando en una asociación es necesario reflejar atributos de información. Por ejemplo, es necesario registrar la fecha de inicio y la fecha de fin de la vinculación entre empleados y sucursales.
Desde el punto de vista de la persistencia no es una complicación ya que la tabla intermedia que vincula a Personas y Sucursales tendrá más campos de información.
Pero desde el punto de vistas de entidades hay un cambio más importante: es necesario crear una nueva entidad. Si un vínculo necesita guardar información deja de ser un vínculo y pasa a ser una entidad nueva, con derecho a tener su propio nombre (no simplemente la unión de los nombres Persona y Sucursal) porque en el paradigma orientado a objetos todo lo que tenga atributos (características) debe ser una entidad. Sin embargo en el modelo de persistencia la tabla intermedia sí suele tener por nombre simplemente la unión de las dos tablas.



Lo que tiene de particular esta entidad es que solo tiene sentido si existen las dos partes, con lo cual en el modelo de persistencia no debe tener clave primaria a menos que esto no sea cierto y la información del vínculo deba persistir más allá de la existencia de las partes que participaron (si así lo dice el negocio...). En este supuesto sí correspondería agregarle una clave primaria a la tabla intermedia.

La implementación de esta entidad intermedia puede resolverse con una clase "TiempoEnSucursal" (disculpen por el nombre, importa ver que tiene nombre propio), la cual no tendrá un identificador propio, pero tendrá una propiedad de tipo Sucursal y otra de tipo Persona (además de la fecha de inicio y fecha de fin propias de la clase).
Por último, estas propiedades de Sucursal y Persona deberían provenir desde afuera de la clase PasoPorSucursal, es decir, por medio de algún constructor o en el "set" de las propiedades.





Para finalizar les dejo la implementación de las clases donde se puede ver en detalle como se aplican los tres tipos de relaciones.



Espero les sea de utilidad este artículo y cualquier inquietud/observación me avisen.

Aquí les dejo todo el fuente más la base de datos.

https://skydrive.live.com/redir?resid=4285FB631C82DC8C!572&authkey=!AM9HFlz_uXOOTUE


Hasta la próxima entrega.


Diego Camacho
dcamacho31@hotmail.com



miércoles, 24 de abril de 2013

Patrón Observer con Delegados y Eventos

Resumen

El patrón observer es un excelente recurso que todo buen desarrollador debe saber utilizar cuando se presente la ocasión.

La síntesis del patrón es que permite que un objeto se entere y reaccione (observador) ante el cambio en otro objeto (observado), sin generar un acoplamiento entre el observado y el observador (mecanismo de suscripción).

Supongamos este ejemplo de la vida real: 

Yo soy un objeto profesor y ustedes son objetos alumno. Ustedes están interesados en saber si mi propiedad "Va a dar clases" está en false para no venir a clases en tal caso. Entonces me llaman por teléfono para corroborar el estado de mi propiedad.
Pero como no saben en que momento esta propiedad puede pasar de estar en true a estar en false entonces me llaman varias veces al día (léase, consultan la propiedad varias veces).

Claramente esto produce un nivel de llamadas y estrés innecesario en el objeto profesor.

Entonces como estoy cansado les propongo un cambio.

Les pido que ya no me llamen para saber si voy a dar clases y me anoto el número de cada uno de ustedes para llamarlos si cambio de estado true a false.
Aquí mejoramos un poco pero igual seguimos con alto nivel de acoplamiento porque el objeto profesor tendría que tener una instancia de cada uno de ustedes para consultar la propiedad "teléfono" y llamarlos cuando ocurra el cambio en mi estado.

Finalmente encontramos la solución. Metemos entre nosotros un intermediario, la recepción del instituto y además agregamos en evento en mi objeto llamado "NoDoyClases" que lo disparo cuando algo me impida asistir al curso. Pero este evento es administrado (notificado) solo a este intermediario, es decir, a la recepción.
Cuando la recepción recibe el evento se fija todos los objetos alumnos que están suscriptos al evento (los observadores) y les notifica a cada uno que ocurrió el evento del profesor para que cada uno "reaccione" como quiera.

Implementación técnica en .Net

Supongamos que tenemos una clase impresora con un método imprimir que en cada llamada descuenta del total de papel disponible las hojas que se quieren imprimir.

namespace EjemploEventos
{
 
    //Declaro el intermediario al cual le voy a notificar el evento que necesito
    delegate void ManejadorDeEventos ();
 
    class Impresora
    {
 
        int cantidadHojas = 10;
 
        //Declaro el evento que se va a disparar cuando mi regla de negocio así lo indique
        public event ManejadorDeEventos NoHayMasPapel;
 
        
        // Método que aplica la regla de negocio que indica: "Disparar un aviso cuando la impresora se quede sin papel"        
        public bool Imprimir(int cantidad)
        {
            bool respuesta = false;
 
            if (cantidadHojas < cantidad)
                //Si se cumple esta condición disparo el evento
                NoHayMasPapel();
            else
            {
                cantidadHojas -= cantidad;
                respuesta = true;
            }
 
            return respuesta;
 
        }
 
    }
}

Ahora necesito un formulario que utilice un objeto de la impresora y "LO SUSCRIBO" al evento "NoHayMasPapel" para mostrar un mensaje por pantalla si no hay más papel.

namespace EjemploEventos
{
    public partial class FrmImpresion : Form
    {
        //Creo un campo con la impresosa
        Impresora objImpresora = new Impresora();
 
        public FrmImpresion()
        {
            InitializeComponent();
            //En el constructor me suscribo a los eventos que me interesa por medio del delegado 
            //y propongo un método como reacción ante la ocurrencia de ese evento
            objImpresora.NoHayMasPapel += new ManejadorDeEventos(objImpresora_NoHayMasPapel);
        }
 
        //Solo se dispara este código si el evento ocurre
        void objImpresora_NoHayMasPapel()
        {
            MessageBox.Show("No hay papel suficiente para esa cantidad de hojas.");
        }
 
        //Solo se dispara si el usuario presiona el botón
        private void button1_Click(object sender, EventArgs e)
        {
            if (objImpresora.Imprimir(int.Parse(textBox1.Text)))
                //Si se pudo disparar el evento entoces muestro el mensaje 
                MessageBox.Show("Impresion finalizada");
        }
    }
}




Conclusiones

Programar con el patrón Observer por medio de Delegados y Eventos permite crear una arquitectura basada en componentes independientes. Podemos tener objetos con estado (propiedades), operaciones (métodos) y reacciones (eventos).
Esto significa que puedo propagar la ejecución de código en otros componentes sin conocer o pensar en ellos al momento de crear la clase observada (dueña del evento).

Aquí les dejo el código fuente completo del proyecto para descargar.



https://skydrive.live.com/redir?resid=4285FB631C82DC8C!501&authkey=!AM9HFlz_uXOOTUE




Hasta la próxima entrega.

Diego Camacho
dcamacho31@hotmail.com