25 enero, 2010

Las aplicaciones web en 2010. Thin Server Architecture

Aviso que se trata de un artículo un poco largo en el que trato las tecnologías web más actuales relacionadas con Javascript y el cambio de paradigma que se está produciendo con la capa de presentación en las aplicaciones web.

Hay algunos artículos (por ejemplo 1,2,3) que hacen hincapié en la que probablemente constituya la nueva plataforma web más importante de la década. La combinación de las mejoras y los estándares que rodean a ECMAScript (Javascript) junto con los nuevos motores que han multiplicado en varios factores la velocidad del lenguaje, el interés por AJAX y nuevas formas de comunicación (Comet, Google SPDY, websockets nativos), y los proyectos emergentes que no dejan de aparecer para usar el lenguaje en el lado del servidor, se están uniendo para empujar el desarrollo web basado en Javascript hacia la vanguardia de la tecnología web. Puede que los entornos corporativos tarden más en aceptar la simplicidad, flexibilidad y del lenguaje, al igual que resisten con XML respecto a JSON o con Java respecto a Ruby o Python, pero es cuestión de tiempo que la fuerza que alberga un lenguaje extremadamente simple y a la vez extremadamente potente salga a flote y por fin se le haga justicia. Recordemos que JS parte con una resistencia adicional y es que muchos programadores, especialmente de Java, mantienen cierto grado de odio hacia el lenguaje, procedente de la falta de distinción entre el lenguaje en sí, que apenas varía entre navegadores, y la patética implementación del DOM en cada navegador.

La capa de presentación ahora en el navegador

Gmail supuso un antes y un después en la tecnología web. Sigue siendo la aplicación modelo, la que demuestra que es posible tener un aplicativo casi tan rápido como el de escritorio. Tradicionalmente, la presentación se ha generado en el servidor escupiendo una secuencia HTML que debería ser interpretada por el navegador. Esto es así porque se tiene un control de la salida desde el punto en el reside la lógica de negocio. Recientemente se ha extendido el paradigma MVC (Modelo-Vista-Controlador) que permite separar de forma lógica estas tres capas de una aplicación de forma que el código pueda crecer fácilmente sin que la mantenibilidad de ésta se resienta. Sin embargo, la forma tradicional de generar ese código HTML a enviar al navegador ha sido mediante templates o lo que es mucho peor: entrelazando código del servidor de aplicaciones con el de presentación hasta alcanzar límites como el siguiente (fuente):
<select name="type">
<c:forEach items="${types}" var="type">
<option value="${type.id}"
<c:if test="${item.defaultType == type.id}">
 selected</c:if>>
<c:out value="${type.name}"/>
</option>
</c:forEach>
</select>
<input type="button" value="Add <c:out
value="${item.name}"/> to cart"
onClick="addItem('<c:out value="${item.guid}"/>')"/>
Los problemas que esta arquitectura, utilizada ampliamente en la actualidad, presenta son innumerables, entre ellas:
  • Mala distribución de la potencia de procesamiento. Prácticamente todo el trabajo lo realiza el servidor, a pesar de que los clientes a los que se sirve la aplicación tienen potentes máquinas que apenas se aprovechan.
  • Modelo de programación complicado, ya que toda interacción con el servidor implica una interfície de petición/respuesta, que además genera esperas al usuario.
  • Mayor vector de ataque y, por tanto, menor seguridad. Entremezclar lógica de negocio con la presentación supone que el crecimiento de la aplicación genere nuevos puntos débiles en la seguridad por la que ésta puede ser atacada.
  • Consumo elevado de memoria en el servidor para mantener estructuras de datos sobre las sesiones abiertas por los usuarios.
  • Uso ineficiente de los recursos de conexión al requerir que documentos relativamente extensos en HTML (o sea, poco optimizados para el ancho de banda) sean enviados al navegador para cualquier cambio de estado en la aplicación.
  • Complicación a la hora de generar la versión offline de las aplicaciones web. Una capa de presentación generada por el servidor necesita de conexión para ser accesible desde el navegador. Readaptar la aplicación para ello implicará, probablemente, reescribir entera dicha capa a parte de la lógica propia del funcionamiento offline.
La aparición de frameworks como jQuery, MooTools, Prototype o Dojo han eliminado la parte de peor fama que injustamente cargaba Javascript: la de las incompatibilidades con el modelo de objetos del documento o DOM. Y con ello han aparecido las mejores partes del lenguaje. Además, una serie de proyectos están facilitando no ya la manipulación de los elementos generados en las que destacan las frameworks anteriores, sino la creación de dichos elementos para constituir complejas interfícies de usuario desde el mismo navegador. Por ejemplo:
  • El estándar E4X (ECMAScript for XML) permite definir elementos directamente como variables JavaScript:
    var sales = <sales vendor="John">
      <item type="peas" price="4" quantity="6"/>
      <item type="carrot" price="3" quantity="10"/>
      <item type="chips" price="5" quantity="3"/>
    </sales>;
    
    alert( sales.item.(@type == "carrot").@quantity );
    alert( sales.@vendor );
    for each( var price in sales..@price ) {
    alert( price );
    }
    
  • JAML permite definir elementos usando una sintaxis muy sencilla basada en llamadas a funciones:
    div(
    h1("Un titulo"),
    p("Un texto o parrafo cualquiera"),
    br(),
    ul(
     li("Primer item"),
     li("Segundo item"),
     li("Tercer item")
    )
    );
  • JSONML es una aplicación del formato JSON que puede representar XHTML perfectamente:
    [ "ul", { style : "list-style-type:none"},
     [ "li",
       "Primer item"],
     [ "li",
       "Segundo item"],
     [ "li",
       "Tercer item"],
     ];
  • El Zen-coding es un formato pensado para generar código XHTML rápidamente en un editor de texto, pero más de uno ha adaptado a jQuery o Mootools la misma sintaxis permitiendo, por ejemplo, generar el mismo código XHTML del ejemplo anterior con la cadena ul>jQuery('ul li:3[innerHTML="item"]').satisfy(); o $('body').zen('ul>li*3>span');
Una de las ventajas de dejar la parte de presentación exclusivamente al navegador es que es posible utilizar fácilmente distintas opciones para reescribir la interfície sin tocar la parte del servidor. Por ejemplo, una aplicación web 2.0 pura puede convertirse fácilmente en una aplicación XUL para navegadores Mozilla, o Flash, o Flex, o OpenLaszlo, o un applet Java, o Air, o Titanium, o un framework como Ext.js o Ajax.org, o una aplicación para Android, Palm Pre o iPhone con PhoneGap. Además los clientes web están en medio de un profundo proceso de mejora en el que tendrán disponibles una cantidad de nuevas opciones impensables hasta hoy:
  • WebSockets que les permitirá mantener una conexión abierta bi-direccional con el servidor, optimizando así la información transmitida, el tamaño de los datos, el tiempo de respuesta y posibilitando la nuevas aplicaciones web en tiempo real (chats, información de bolsa o juegos multijugador, por ejemplo) y dejando AJaX desfasado ante la llegada, por fin, de Comet.
  • WebWorkers que permitirá que las aplicaciones web puedan disponer de un sucedáneo de la programación concurrente en el navegador, de forma que procesos pesados no hagan más lenta la respuesta de la interfície de cara al usuario.
  • Web SQL Database para ofrecer el lenguaje SQL en el cliente y posibilitar trabajar offline con una aplicación web.

Javascript en el servidor

Como comentaba al principio, JavaScript está escapando del navegador con una fuerza destacable, sólo achacable a la potencia de un lenguaje bastante viejo que sólo unos pocos han sabido reconocer. No sólo aparece en la capa del servidor de aplicaciones, también lo está haciendo en la base de datos. Dos estándares CommonJS y JSGI están cubriendo rápidamente la falta de acuerdo en un terreno tan cambiante. EL primero define una serie de APIs críticas para construir módulos reutilizables en el entorno del servidor. Por ello cubre facetas como la interacción con la base de datos, el acceso al sistema de archivos, el servidor web o la generación de formatos. El segundo define la forma Javascript con la que interactuar desde el servidor web con las conexiones HTTP, definiendo una representación del protocolo mediante un objeto JSON/Javascript. Entre lo más puntero de la tecnología web en el servidor se encuentra la utilización de bucles asíncronos de eventos para tratar con las conexiones entrantes en lugar de usar hilos del sistema operativo para ello. En las comparaciones entre los servidores NginX y Apache, que siguen precisamente cada una de esas técnicas, se puede ver que no sólo NginX consume mucha menos memoria sino que también es capaz de soportar muchas más conexiones concurrentes. Siguiendo esa misma filosofía han aparecido proyectos como Twisted para Python, EventMachine para Ruby y ahora Node.js para Javascript. Los tres han sido creados de forma que no contienen llamadas bloqueantes como las que se realizan al sistema operativo para leer un archivo. Para ello se basan en un mecanismo que JavaScript ya incorpora de forma natural: las funciones callback que son llamadas cuando el trabajo solicitado ha sido completado, dejando que mientras tanto el sistema siga ejecutando otros procesos del bucle de eventos y, por tanto, incrementando exageradamente el rendimiento. Muchos incorporan un mecanismo llamado promises que permiten escribir código de la forma más parecida al sistema procedimental tradicional (en secuencia) y evitar así romper una misma función como bloque conceptual en varias funciones distintas cada vez que se necesite una llamada bloqueante (acceso a disco, base de datos o nueva conexión). Helma NG es la nueva versión del proyecto activo más antiguo que, siguiendo el estilo MVC ofrecía la posibilidad de usar el motor Rhino de Java y el servidor web Jetty para generar aplicaciones con JS. Pero en relativamente poco tiempo han aparecido muchas más opciones:
  • Persevere es un servidor de aplicaciones que ofrece una arquitectura REST para intercambiar datos (preferentemente en JSON) con un cliente rico posibilitando así aplicaciones complejas. Así mismo ofrece persistencia de datos, gestión de la seguridad, notificaciones Comet y capacidades avanzadas de comunicación para múltiples plataformas. Con la aparición de nuevas plataformas CommonJS, este proyecto probablemente ofrecerá opciones para instalarse sobre ellos (por ejemplo sobre Node.js).
  • Flusspferd es un proyecto que aúna SpiderMonkey (el motor de JS en C++) con una serie de módulos (SQLite,GMP,Zest,Juice,cUrl...) para ofrecer un entorno de ejecución muy rápido aunque está un poco verde.
  • En la misma situación se encuentra EJScript, que además añade algunas extensiones de JavaScript que fueron eliminadas del estándar. Su principal baza es el rendimiento que se acerca al de Node.js pero con una décima parte del consumo de memoria de aquel.
  • Narwhal es la implementación de CommonJS más avanzada y madura ya que incluye todos sus módulos, ofreciendo soporte completo de entrada/salida, una colección de módulos de librería, un sistema de gestión de paquetes llamado tusk y se ha diseñado para funcionar sobre varias plataformas Javascript.
  • node.js está generando una auténtica riada de reacciones en la comunidad web. Básicamente porque mata tres pájaros de un tiro: consigue un rendimiento escandaloso para tratarse de Javascript aunando el motor V8 y su filosofía asíncrona; su tratamiento de bajo nivel de las conexiones permite usarlo como servidor HTTP pero también Comet adelantándose al futuro; y aprovecha el mecanismo de funciones callback al que estamos más que acostumbrados los programadores. Actualmente está muy bien posicionado para coronarse en el rey de los servidores de aplicaciones basados en lenguajes dinámicos. Además se espera que Narwhal funcione sobre Node con las ventajas adicionales de un sólido software orientado totalmente a la gestión segura de datos en el servidor. Como limitaciones: es demasiado inmaduro porque acaba de ser publicado; de momento sólo implementa el sistema de módulos de CommonJS y no el resto de APIs; aún no puede aprovechar los servidores con varios núcleos; no soporta la especificación JSGI.
  • appjet.com era un entorno de ejecución de aplicaciones JS basado en Rhino/Java. Por desgracia ha sido comprado por Google y el enlace de descarga del archivo .jar que contenía todo el entorno ya no está accesible.
  • Aptana Jaxer también se adelantó en unos meses a su tiempo. Enfocaron el desarrollo en incorporar el motor de renderizado Mozilla Gecko en el lado del servidor y en reutilizar el mismo código en cliente y servidor en un sistema que quizá no resulte demasiado intuitivo para el programador tradicional y que fomenta la generación de la presentación en el servidor. Por desgracia, aunque no ha desaparecido, este proyecto también ha sido relegado por la empresa que lo desarrolla.

Futuro

Con todo ello, es fácil plantearse si sería posible realizar hoy día una aplicación web conociendo únicamente JavaScript. La respuesta obvia es que no, pero ya son muy pocas las piezas que quedan:
  • Datos. Existen ya servidores de bases de datos que hablan JS como CouchDB con su revolucionario enfoque a la hora de realizar consultas de datos basadas en el sistema MapReduce. También MongoDB ofrece una interfície REST para tratar con sus documentos JSON, el formato de datos propio de Javascript. No es casualidad que ambas pertenezcan al ámbito de la las nuevas bases de datos conocidas como NoSQL, donde el paradigma relacional que se ha demostrado como problemático para la escalabilidad es dejado atrás a favor de otras opciones menos rígidas. Se echa en falta un estándar para definir consultas basadas en el lenguaje Javascript. SQL está muy extendido, pero estoy seguro que se puede hacer lo mismo que CouchDB ofrece con menos complejidad. Quizá al estilo de Microsoft Linq pero siguiendo la sintaxis de Javascript, o bien basándose en la base de datos para navegador TaffyDB.
  • Servidor de aplicaciones. Son muchas las opciones, como he mencionado antes. Pero la amplia adopción de CommonJS crea un rico ecosistema de opciones que otros lenguajes no cubren. Esa variedad que ha aparecido en muy poco tiempo es la mejor prueba de que, probablemente, esta nueva década sea la de la amplia adopción de Javascript. Otros estándares que ya están en el cliente, como los Web Workers o el ya famoso y estudiado XMLHTTPRequest que mueve a AJaX, serían de mucha utilidad en el servidor.
  • En el navegador se echa en falta un sistema de empaquetado de aplicaciones al estilo los .jar de Java que optimizaría la descarga al no exigir varias conexiones para obtener todos los datos. Otro estándar que echo en falta es un lenguaje basado en JSON, que equivalga a HTML y que sea aceptado por los navegadores. Que index.jsml empezase a sustituir al omnipresente index.html sería un buen paso. Ya hay proyectos que sustituyen el CSS y al XHTML, pero un estándar que, al igual que XUL, permitiese crear formularios optimizados para aplicaciones web podría dar un empuje definitivo que arrinconase más a las aplicaciones tradicionales de escritorio...

Conclusiones

El abanico de estándares, plataformas, bases de datos, motores de interpretación y mecanismos de interoperación que se ha abierto en relativamente poco tiempo abre una cantidad de opciones inmensa que hace posible lo que hasta hace poco era impensable: que la lingua franca de la web gane terreno en el servidor con soluciones de tecnología punta vetadas hasta ahora a plataformas mucho más extendidas como PHP, Java o ASP.NET. Resulta sorprendente como tres pares de símbolos: [] arrays/listas/pilas, {} objetos y () funciones permiten componerse con tanta flexibilidad como para dar cabida a todos estos proyectos y además desafiar el statu quo.



Últimos links en indiza.com