domingo, 2 de diciembre de 2012

Idas y vueltas entre aplicaciones web

Una vez al año no hace daño.

Cuando se trabaja en un entorno en el que conviven varias aplicaciones es natural que tarde o temprano se comuniquen entre ellas o incluso que desde un principio estén diseñadas para ello. El objetivo es conseguir un sistema modular en el que se duplique la mínima cantidad posible de información y de esfuerzo de los desarrolladores y mantenedores de las aplicaciones.

Esta comunicación puede hacerse a muchos niveles y de muchas formas pero lo ideal es que las dependencias sean lo mas flexibles posibles y no haya acoplamientos rígidos, que el sistema sea distribuido y que use protocolos estándar no propietarios.

 En los últimos tiempos hay una arquitectura en alza que parece puede cumplir esos objetivos en mayor medida que otras alternativas mas aparatosas: hablamos de REST, claro esta. Sin embargo cuando hablamos de aplicaciones con interfaces gráficas surge la aspiración de extender esa reutilización hasta la misma interfaz y no quedarse solo a nivel del API. Así a bote pronto se me ocurren pocas alternativas para reusar dinamicamente, en tiempo de ejecución, interfaces graficas complejas de diferentes aplicaciones web: portlets tal vez. Si conoceis alguna no dudeis en apuntarla, si es posible con sus ventajas e inconvenientes.

En mi caso inspirandome en el flujo de una autenticación vía http del tipo oauth opté por lo que me pareció una solución directa y sencilla (demasiado tal vez), al menos a simple vista: hacer una llamada estándar http de una aplicación a otra  con el objetivo de presentar el html servido por la segunda. Este html no es embebido ni transformado: simplemente la pagina servida por la otra aplicación se carga en el navegador. En la llamada la aplicación "cliente" o llamadora incluiría en los parámetros la url (que puede ser de la misma aplicación cliente) y parámetros de vuelta. La aplicación servidora los utilizara en determinados puntos para que el usuario pueda volver a la aplicación original o a la url siguiente en el flujo de la operación, añadiendo mas información en los parámetros si es necesario.

Por ejemplo tenemos el típico caso en el que una aplicación tiene que elegir un recurso o recursos de otra para completar una operación. Una llamada al API teniendo su identificador es muy sencilla pero para conseguirlo de una forma cómoda pueden hacer falta varias pantallas de filtro y navegar entre varios recursos y pantallas. Es lógico querer reutilizar toda ese flujo y la interfaz y que la aplicación cliente no dependa de si cambia la lógica tanto de negocio como de la presentación. La llamada tendría este esquema:

http://server/aplicacion-tramitacion/expediente/201001?select=informe.inicial&ciudadano.id=dni&client.urlback=/aplicacion-atencion-ciudadana/peticion/&client.urlback.params=usuario=x


Para ello la aplicación servidora debe estar preparada para gestionar esas peticiones externas, modificando ligeramente su propia interfáz para añadir los puntos donde el usuario puede volver a la aplicación originál (o a cualquier otra), bien seleccionando uno o varios recursos o cancelando la selección. El usuario navega entre el filtro, los listados y los detalles de los recursos hasta encontrar el deseado y volver usando "client.urlback"

http://server/aplicacion-atencion-ciudadana/peticion/3?informe.inicial=12&usuario=x


Este es justamente el caso en el que efectivamente lo he usado. Sin embargo no estoy totalmente seguro de los posibles inconvenientes de esta solución, sobre todo a la hora de generalizarla a otros casos diferentes y como puede escalar en función de la complejidad de las llamadas. Tampoco tengo una referencia de posibles alternativas con las que comparar y evaluar los pros y los contras. Por ejemplo el número de parámetros de las llamadas puede hacerse inmanejable y en cualquier caso no es muy elegante, al menos superficialmente (aunque siempre pueden usarse llamadas de tipo POST para ocultarlos)

6 comentarios:

  1. Yo he utilizado algo parecido, a través de un filtro proxy, pero siempre para acceder a funcionalidades completas (tipo muestra esta otra aplicación en esta otra) pero para acceder a funcionalidad más básica, soy un no-creyente de la reutilización de GUI.
    Básicamente por que la re-utilización viene con su amiga la dependencia, y los cambios a nivel de APIs (REST, XML sobre HTTP...) son más fáciles de manejar/detectar. Y aunque para un caso concreto pueda valer, con cuidado, como herramienta general en proyectos ya medianos con equipos de desarrollo variados, las probabilidades de que al tocar alguien una aplicación, rompa otras va creciendo rápidamente. Y los GUIs es de lo que más cambia. Por eso prefiero que el GUI de cada app. este contenido en cada app.

    En todo caso, hay que tener cuidado al implementar estas técnicas para no dejar abiertos agujeros de seguridad por los que se cuele el XSS o facilitar el phishing, por lo que es conveniente recortar la flexibilidad y, por ejemplo, no permitir indicar el host de las apps externas.

    De todas formas, ex un tema complejo al que no le veo solución general. En mi caso tengo muchas aplicaciones pequeñas de larga duración y ciclos de desarrollo diferentes, por lo que tener dependencias fuertes entre ellas me da dolores de cabeza. Así que de momento opto por reutilizar menos y tenerlas más autocontenidas.

    My 2ec

    ResponderEliminar
  2. Interesante aviso para navegantes. Tal vez debí haber descrito el contexto en que he aplicado la técnica ya que tal vez los posibles problemas esten mitigados: las dos aplicaciones estan inscritas en una intranet con un mecanismo de autenticacion,una interfaz grafica, un marco de desarrollo y de despliegue comun. En ambas participo de alguna u otra manera en su desarrollo que ha sido mas o menos paralelo y si no fuera así supongo que este tipo de integración no tendria mucho sentido.

    Aparte el mecanismo intenta hacer la dependencia lo menos rigida posible al tratar a las aplicaciones como "funciones" y fijar solamente los parámetros de entrada y salida. Cierto es que la definición de estos parámetros son fruto de la convención y por tanto no hay ninguna seguridad "técnica" de que las aplicaciones los cumplan. Pero vamos no mucho menos seguro que las llamadas a un método en un lenguaje dinámico :-P

    En el caso de ejemplo mientras la aplicacion "servidora" acepte y trate correctamente la url inicial con los parametros "client.urlback" y "select" y devuelva siempre el parámetro "entidadSeleccionada.id" podemos abstraernos de como realiza los pasos intermedios o en que tecnología esta implementada (al usar http).

    Esta claro que de extender la técnica tendría que ser en un contexto similar y por ello no es general como bien dices.
    La opcion de depender "solamente" del api (sea rmi,soap,rest etc) y, opcionalmente, de reutilizar estatícamente la parte gráfica (con taglibs,plugins o similar) de forma independiente siempre esta ahi aunque me parece que tambien puede a llegar a ser demasiado rigida (mas dependiente de la solucion técnica adoptada) aunque mas controlada.

    ResponderEliminar
  3. Entiendo, pero las aplicaciones son como las reuniones, sabes cuando/como empiezan pero no como van a acabar :D. Ahora estas tú en las dos aplicaciones, de aquí a un tiempo, vete a saber. Yo tengo aplicaciones en marcha que se arrancaron en 1998.

    Pues eso, que puede ser una solución para un problema concreto, pero las dependencias me gusta tenerlas, como mucho, un punto más abajo.

    ResponderEliminar
  4. A mi esto me suena a lo que hace, p.ej. cualquier tienda que use PayPal para procesar un pago. Llaman a una URL de PayPal y le pasan (entre otros parámetros relacionados con el cobro) una "callback url". Cuando PayPal termina su proceso, te manda a esa URL que vuelve a ser de la tienda para decirte "eh, gracias por darnos tu dinero! Te mandaremos las cosas pronto".

    La diferencia, claro, es que en tu caso controlas las dos partes. Por lo demás, a mi la idea me parece razonable si el proceso a realizar en la aplicación llamada es aceptablemente autocontenido.

    ResponderEliminar
  5. ¡Espero que lo siga siendo! He reflexionado sobre las sabias palabras de @greeneyed: las aplicaciones pueden divergir, incluso cambiar de desarrolladores. La aplicacion servidora no es una "caja negra" ya que el usuario esta interactuando con ella y esa interaccion pueden tener que ser diferentes en un momento dado. Cuando las aplicaciones clientes se multiplican el tema se complica exponencialmente.
    Sin embargo hay otros elementos del contexto "real" a tener en cuenta:
    * Las modificaciones en la aplicacion para "abrir" su interfaz grafica no han sido muy costosas (por lo bien que estaba diseñada desde un principio :-P)
    * La aplicacion tiene un api a la que se puede recurrir si la integracion a nivel de ui no es valida.
    * En los parametros es obligatorio señalar cual es la aplicacion cliente (para permitir modificaciones en la aplicacion servidora caso de que fuera absolutamente necesario)
    * El flujo compartido por la aplicacion servidora es bastante simple y estable. No *tan* simple y estable como la autenticacion o el pago por paypal que ponias de ejemplo pero espero que lo suficiente.

    ResponderEliminar
  6. Los temores de @ElJavato son más que razonables, sin embargo, existen cada vez más cantidad de "componentes web" que se integran perfectamente en la forma descrita por @jneira. Un buen ejemplo es precisamente el ejemplo que él (tú) has puesto; la autenticación por tercero es ya un estándar y muy habitual integrarlo en las app web.

    De hecho la tendencia es esa, ¿no era esa la idea de la web 2.0? XD XD

    Los problemas comentados por @ElJavato son como todo, o se hacen las cosas bien o se hacen mal, o tienen sentido en un contexto o no lo tienen, pero en sí mismo yo veo perfecto reutilizar, y si es la UI ¡mejor!.

    Otra cosa es que los problemas a los que te encuentras son matadores... (eg. cuando hay que implementar "marca blanca" en app's web complejas).

    Pero si has abstraído correctamente la funcionalidad (eg. OpenID, PayPal, ...), la has implementado adecuadamente y ha quedado bien documentada, no debe haber ningún problema.

    ;)

    ResponderEliminar