viernes, 24 de mayo de 2013

Seguridad en aplicación web con Apache Tapestry

Apache Tapestry
Apache Shiro
Además de la persistencia en una base de datos, otra de las funcionalidades comunes que suele necesitar una aplicación es la seguridad. En la seguridad hay varios aspectos a tratar que son:
  • Autenticación: que consiste en identificar al usuario en el sistema y comprobar que el usuario es quien dice ser. Normalmente la autenticación se suele realizar pidiéndole al usuario su identificativo, nombre de usuario o correo electrónico y una contraseña que solo él conoce. Aunque hay otras formas de realizarlo entre ellas los certificados.
  • Autorización: que consiste en determinar si el usuario autenticado tienen permisos para realizar una determinada operación. La autorización puede realizarse mediante roles, permisos o una combinación de ambos dependiendo de lo adecuado para la operación. Pero en ocasiones no solo hay que validar si un usuario tiene permisos para para realizar una acción, también puede ser necesario restringir la operación sobre ciertos datos, los que se determinen que él está autorizado a modificar, si no se hiciese esto un usuario podría alterar los datos de otro y el sistema tener una brecha de seguridad.
La autenticación y la autorización son solo dos aspectos a considerar pero no son suficientes para considerar una aplicación segura. Otros aspectos a tener en cuenta son XSS (Cross Site Scripting), la inyección de SQL o las conexiones cifradas SSL/TLS pero estos serán tema para otras entradas.

La información de autenticación y autorización puede guardarse en diferentes formas en lo que se conocen como Realms comunmente en Java. Algunos Realms puede ser simples archivos de texto plano aunque por su dificultad de mantenimiento al añadir nuevos usuarios, permisos o roles y que puede requerir un reinicio de la aplicación se suele optar por opciones como una base de datos relacional, un sistema LDAP o una base de datos nosql.

Para tener un sistema seguro no basta con ocultar las opciones que un usuario no puede realizar. Ocultar las opciones está bien pero también hay que realizar las comprobaciones de autorización en el caso de una aplicación web en el servidor, al igual que no basta con realizar las comprobaciones de validación de datos en el cliente con javascript, en ambos casos las comprobaciones hay que hacerlas en el lado del servidor también, de lo contrario nada impediría a un usuario conociendo la URL y datos adecuados a enviar realizar algo que no debería (advertido estás si no quieres que te llamen un sábado de madrugada).

La seguridad puede aplicarse de dos formas o una combinación de ambas:
  • De forma declarativa: ya sea mediante anotaciones o en un archivo independiente del código. Esta es la opción preferida ya que de esta manera el código de la aplicación no está mezclado con el aspecto de la seguridad.
  • De forma programática: si la opción declarativa no no es suficiente para algún caso podemos optar por hacerlo de forma programática, mediante código, con la que tendremos total flexibilidad para hacer cosas más específicas si necesitamos aunque mezclaremos el código de la aplicación con el código de seguridad.
Para aplicar seguridad en una aplicación Java disponemos de varias librerías, entre las más conocidas están:
Las dos librerías son similares aunque se comenta que Apache Shiro es más fácil de aprender. Además de integraciones con estas librerías Apache Tapestry dispone de módulos para realizar autenticación con servicios de terceros como Facebook, Twitter o sistemas OpenID.

Pero veamos como aplicar seguridad a una aplicación web que use el framework Apache Tapestry. En el ejemplo usaré el módulo tapestry-security que a su vez usa Apache Shiro. El ejemplo consiste un una página a la que solo los usuarios autenticados pueden acceder, en ella los usuarios podrán realizar varias operaciones: sumar a una cuenta uno, dos, tres, restar uno o poner la cuenta a cero en función de los permisos y roles que tengan. Para autenticase se usa un formulario aunque perfectamente podría usarse una autenticación BASIC.

Por simplicidad en el ejemplo los usuarios, passwords, roles y permisos los definiré en un archivo de texto, aunque en un proyecto real probablemente usaríamos una base de datos accediendo con hibernate para lo cual deberíamos implementar unos pocos métodos de la interfaz Realm o si necesitamos autorización la interfaz AuthorizingRealm de Shiro. El archivo shiro-users.properties sería el siguiente:

Por una parte se definen los usuarios con su password y roles que posee y por otro se definen los roles y los permisos que tiene cada uno.

La única configuración que deberemos indicarle a Tapestry es la URL de la página que autenticará a los usuarios y la página a mostrar en caso de que el usuario no esté autorizado para realizar alguna operación y el Realm a usar, lo hacemos añadiendo el siguiente código al módulo de la aplicación:

La página que realiza la autenticación es muy simple, poco más se encarga de recoger el usuario y password introducidos en el formulario de autenticación y a través del Subject realiza el inicio de sesión.

Una vez configurado el módulo y hecha la página que realiza la autenticación solo debemos usar de forma declarativa las anotaciones que proporciona Shiro, en el caso de la página Index @RequiresUser para permitir solo a los usuarios autenticados entrar a esa página y sobre las operaciones @RequiresPermissions para requerir ciertos permisos para ejecutar las acciones o @RequiresRoles para requerir ciertos roles. Estas anotaciones podemos usarlas no solo en las páginas y componentes de Tapestry que forman parte de la capa de presentación sino también en los servicios que desarrollemos y que forman la capa de lógica de negocio.

Si las anotaciones no son suficientes podemos hacerlo de forma programática, este es el probable caso de que un usuario solo debería modificar los datos relativos a él  sin poder modificar los de otros usuarios. El código variará en función de la forma de determinar si el usuario tiene permisos para un dato. Para comprobar si un usuario tiene ciertos permisos de forma programática debemos usar el objeto Subject que tiene muchos métodos para realizar comprobaciones, como para  reinicializar la cuenta se ha de tener el permiso «cuenta:reset» se debe hacer lo codificado en el método onActionFromReset:

En la plantilla de presentación que genera el html también deberemos hacer algunas comprobaciones de seguridad, básicamente para mostrar los enlaces a los que un usuario tenga permisos.

A continuación unas capturas de pantalla de la aplicación de la página de inicio autenticación, de la página con el índice de acciones y de la página de acción no autorizada:

Para hacer uso de tapestry-security deberemos incluir la librería como dependencia en el archivo build.gradle del proyecto:

Como en el resto de entradas el código fuente completo lo puedes encontrar en mi repositorio de GitHub. Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada previamente (salvo java y git). Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip con el anterior enlace.

Para finalizar, a pesar de lo simple del ejemplo pero suficientemente representativo de lo que podría requerir una aplicación real comentar lo sencillo y limpio que ha sido aplicar la seguridad, por una parte gracias al uso de anotaciones y por otra gracias a Tapestry de por si.

Referencia:
Documentación sobre Apache Tapestry
http://tapestry.apache.org/security.html
http://tapestry.apache.org/
http://shiro.apache.org/
http://static.springsource.org/spring-security/site/index.html

viernes, 17 de mayo de 2013

Copia de seguridad con rsync

rsync
Las copias de seguridad son imprescindibles, si alguien piensa que no es que nunca se le ha estropeado el ordenador ya sea porque ha fallado el hardware o por una actualización que ha corrompido el sistema de arranque o peor por que el disco duro se ha estropeado, eso o no tiene datos importantes que tener a buen recaudo. Si aún no te ha pasado que se haya estropeado el ordenador y te has quedado sin esa información que no quieres perder quizá hayas tenido suerte pero has de saber que tarde o temprano te pasará y para no perder esa información los «backups» son imprescindibles.

Una vez que tener copias de seguridad nos parece importante y tenemos respondida la pregunta de por qué, se nos plantean algunas otras preguntas:
  • ¿De que hacer copias de seguridad?
  • ¿Cada cuanto hacer copias de seguridad?
  • ¿Que características han de tener las copias de seguridad?
  • ¿En que medio guardar las copias?
  • ¿Como hacer las copias de seguridad?
  • Y tan importantes como las anteriores, ¿como recuperar los datos?
Cada pregunta tiene diferentes respuestas según el usuario, entorno o la información de la que hacer las copias de seguridad. A la pregunta de que hacer copias de seguridad cada uno deberá conocer que información no quiere perder en caso de desastre, cuanto cambian los datos y que se perdería en un periodo de tiempo (día, semana, mes, ...), si las copias deben estar comprimidas para ahorrar espacio o cifradas y finalmente dependiendo de algunas respuestas anteriores que herramienta o herramientas usar.

Yo hasta ahora no usaba ninguna herramienta usaba el simple y manual método de copiar y pegar archivos del disco duro del ordenador a un disco duro externo. Cuando no tenía disco duro externo las copias de seguridad las hacía en CD y DVD pero hacerlas en un medio óptico como los anteriores no los recomiendo porque son lentos de realizar, en estos días no tienen capacidad suficiente para guardar todo y por tanto deberemos tener varios volúmenes y finalmente lo más importante porque son unos medios poco fiables. Dado el precio y capacidad que tienen hoy en día los discos duros USB externos además de su velocidad de transferencia es más recomendable esta opción y es la que a día de hoy uso. Pero aún con un disco duro externo el método de copiar y pegar tarda un buen tiempo y sigue siendo lento, con 70 GiB de archivos personales que no quiero perder, pero también el hecho de hacerlo manualmente es propenso a que algún día se me olvide hacer la copia de seguridad de todo y por la ley de Murphy ese día fallará el ordenador. Con lo que con esta situación he empezado a buscar alternativas a mi método manual de copiar y pegar.

Empece probando Déjà Dup pero no me ha convencido porque las copias de seguridad las guarda en un formato comprimido (y cifrado si se quiere) de modo que para recuperar los archivos se ha de utilizar la misma herramienta. Para mi una de las características de la copia de seguridad es que siga pudiendo tener accesibles los archivos independientemente de la herramienta. Viendo las posibilidades de los programas de copia de seguridad disponibles en Linux por la que me he decantado ha sido rsync. Es un método simple que mantiene sincronizados el contenido de dos carpetas, copiando los nuevos archivos, borrando los eliminados y solo actualizando los necesarios además de poder hacerse las copias entre dos máquinas diferentes a través de la red. Mediante rsync para hacer una copia de seguridad ahora tardo mucho menos ya que solo se copian los archivos que hayan cambiado además de estar automatizado con un script con lo que resulta más fácil y por ello se pueden hacer más a menudo.

Con el siguiente comando de rsync se puede hacer una copia de seguridad de una carpeta a otra:

La opción -a es una meta opción de utilidad que engloba otras con las más comunes para hacer copias de seguridad, -P hace que se muestre el progreso, --delete borra los archivos en la carpeta de destino que se hayan borrado en la carpeta origen.

Otro ejemplo para copiar varias carpetas de la carpeta home de un usuario es, con la opción --files-from, hay que indicar también la opción -r para que las carpetas se copien de forma recursiva:

Este simple comando ahorra mucho tiempo ya que con él no hay que copiar los XXX GiB cada vez que hay que hacer un copia de seguridad, solo se copiará lo que haya cambiado entre la copia de seguridad y el origen, que muy probablemente es una cantidad mucho menor que esos XXX GiB. Con lo simple que es se me hace extraño que haya pasado tanto tiempo haciendo las copias de seguridad manualmente.

Si quieres algunas otros ejemplos de uso de rsync como por ejemplo el como programar las copias de seguridad con cron o quieres conocer otras herramientas en la wiki de Arch Linux tienes unas cuantas más, algunas con interfaz gráfica.

Referencia:
https://wiki.archlinux.org/index.php/Backup_Programs
https://wiki.archlinux.org/index.php/Rsync

viernes, 10 de mayo de 2013

Modificar la base de datos con Liquibase

Liquibase
A lo largo del ciclo de desarrollo de todo proyecto se producen cambios algunos de los cuales casi con toda seguridad afectarán al esquema o modelo de la base de datos. Por una parte se pueden producir modificaciones de definición de datos (DDL, Data Definition Language) para añadir y borrar tablas y añadir, modificar y eliminar campos, crear índices y restricciones de integridad. Por otra parte se pueden producir manipulaciones de datos (DML, Data Manipulation Language) para añadir nuevos datos, modificar o eliminar algunos de los existentes. Estos cambios de la base de datos también puede ser útil que estén bajo el sistema de control de versiones que empleemos al igual que hacemos con los cambios del código fuente del programa para poder volver a un estado anterior. Una herramienta que nos permita hacer «refactor» de forma automatizada de la base de datos nos facilitará la tarea.

Para llevar a cabo estas modificaciones tenemos varias opciones la primera que se nos puede ocurrir es crear un archivo con las sentencias SQL de los cambios y lanzarlo contra la base de datos. Sin embargo, esta opción aunque sencilla y rápida puede que no sea la mejor opción. La primera desventaja es que las sentencias puede que solo funcionen en uno o unos pocos sistemas de base de datos con lo que tal vez tengamos que desarrollar varios scripts para cada uno de los sistemas de base de datos a los que debamos dar soporte. La segunda desventaja es que si queremos revertir los cambios de un «refactor» deberemos crear las sentencias de «rollback» que puede dar bastante trabajo nuevamente si tenemos diferentes DBMS. Además de estas desventajas podríamos necesitar volver a cierto estado de la base de datos deberemos gestionarlo de alguna manera nosotros mismos probablemente de forma manual.

Una de las herramientas que nos puede hacer más sencillo estas modificaciones que se producen a la base de datos es Liquibase. Los scritps que actualizan la base de datos se definen en un XML (o json entre otros) de cambios que es independiente del sistema de base de datos que usemos aunque se pueden incluir sentencias SQL específicas para uno de ellos, también se pueden definir las sentencias rollback que permiten volver a un estado anterior. Soporta las principales bases de datos entre ellas:
  • MySQL
  • PostgreSQL
  • Oracle
  • MS-SQL
  • SQLite
  • Y otras entre ellas Sybase Enterprise, Sybase, DB2, Apache Derby, HSQL, H2, Informix, InterSystems, Firebird, SAPDB.
Una de las primeras cosas que podríamos necesitar si empezamos a usar esta herramienta sobre una base de datos existente es obtener el primer xml changelog.xml con el estado actual de la base de datos.


Si queremos lanzar una actualización de la base de datos a partir de un archivo changelog.xml con algunas modificaciones ejecutaremos lo siguiente:


Para obtener las SQLs que son lanzadas en la consola sin que sean ejecutadas contra la base de datos usaremos «updateSQL» en vez de «update» de esta manera podremos revisar las sentencias que ejecutará Liquibase. También puede sernos de utilidad obtener las diferencias entre dos versiones de la bases de datos o hacer rollback de los cambios, cosa que podemos hacer de diferentes formas.
Un archivo changelog.xml tiene el siguiente aspecto, en él vemos como se definen las tablas, campos y restricciones de integridad:

Por supuesto, estas tareas se pueden automatizar con la herramienta de construcción que prefiramos ya sea Ant, Maven, Gradle o mediante linea de comandos.

Referencia:
Liquibase

viernes, 3 de mayo de 2013

Ejemplo de pruebas unitarias en javascript con Jasmine y Sinon

Jasmine
Backbone.js
Tener un conjunto de pruebas unitarias sobre el código de la aplicación que desarrollamos es importante para tener más seguridad de que lo que hacemos funciona como se espera y no introducimos errores en funcionalidades que ya existían al hacer modificaciones, además de que en el caso de que haya errores estos serán más fácilmente descubiertos y resueltos en menos tiempo lo que hará que seamos más productivos. Si en una aplicación web es posible que ya hagamos pruebas unitarias sobre el código del lado del servidor, ¿por que no hacerlo también en el lado del cliente? Si la aplicación tiene un peso importante de javascript en el lado del cliente, y esa es la tendencia, es recomendable tener también teses unitarios de esta parte del código.

Aprovechando el ejemplo que hice de una aplicación bastante completa de una lista de tareas que utilizaba Backbone, RequireJS, Mustache en el lado cliente y Tapestry y RESTEasy en el lado del servidor ahora le añadiré al código javascript el conjunto de pruebas unitarias con Jasmine y Sinon.

Jasmine es una herramienta para realizar pruebas basadas en BDD (behavior-driven development). BDD es parte de las metododologías TDD (test-driven development) haciendo énfasis en que la gente del dominio pueda trabajar con la gente técnica. Jasmine nos servirá para hacer las pruebas unitarias, Sinon nos permitirá usar spies, stubs y mocks en esas pruebas:
  • Spy: Un spy es una función que se envía como parámetro al sujeto bajo prueba para que recolecte datos sobre lo que sucede dentro de esa función y objeto, se llama espía porque se envía tras la lineas enemigas para que recolecte información. La información que puede recolectar es el número de veces que se llama una función, con que parámetros y cuales, los valores de retorno o si lanzó excepciones.
  • Stub: ofrecen un comportamiento parcial preprogramado del objeto real, se puede utilizar para que proporcione los datos que queramos al sujeto bajo prueba. Los stubs también pueden ejercer de espías.
  • Mock: que también son espías (funciones falsas) y stubs (ofrecen comportmiento preprogramado) conocen las expectativas de como han de ser usados, requiriendo que se llamen con ciertos parámetros, un número de veces, en cierto orden, .... Conocen cual es el comportamiento esperado del sujeto bajo prueba y una vez hecha la prueba se puede comprobar.
A continuación veremos el código de las pruebas para la aplicación, las pruebas se centrarán en el código en el código de la lista de tareas y de probar las diferentes partes por separado, el modelo, vista y controlador. Veamos primeramente las pruebas para los modelos Tarea y Tareas, las pruebas se centrarán en las funciones adicionales que hemos asociado a los modelos, es decir, probaran lo que hemos hecho no Backbone.

En la parte del controlador de la vista nos centraremos en probar los métodos y eventos como onChangeCompletada en TareaView y addTarea, resetTareas, onClickLimpiar y onKeypressNuevaTarea en TareasView. Dado que la lista de tareas hace uso de un servicio REST utilizaremos Sinon para atrapar esas peticiones AJAX que se harían en la realidad.

En la vista probaremos que dado un modelo el resultado del html contiene los elementos que esperamos:

Las pruebas se lanzan abriendo la página html SpecRunner.html en el navegador. Esa página html tiene la dependencia sobre RequireJS y este carga en el navegador el resto de dependencias que necesiten los diferentes módulos incluido el módulo bajo prueba de la lista de tareas. Las pruebas de Jasmine se definen en otro módulo de RequireJS que tiene como dependencia la librería de Jasmine, Sinon y por supuesto el módulo tareas que probará. El resultado es el siguiente:
Backbone se presta muy bien a las pruebas unitarias. Una gran característica es que para realizarlas no es necesario que las vistas se asocien a un DOM real, funcionan en memoria, de modo que no hace falta insertar ni quitar contenido de la página mientras se van ejecutando los teses, no hay necesidad de limpiar el DOM para los siguiente teses y así funciona más rápido. Como usa el patrón MVC cada una de las partes del modelo, vista y controlador pueden probarse por separado. Este ejemplo no muestra todas la posibilidades de Jasmine y Sinon pero da una idea de como son las pruebas con ellas.

En mi repositorio de GitHub puedes encontrar el código fuente completo del ejemplo de pruebas unitarias en javascript con Jasmine y Sinon.

Y con esta es por el momento la última entrada sobre javascript que escriba de esta serie, no descarto escribir alguna más sobre javascript en el futuro porque alrededor de este lenguaje de programación están surgiendo muchas utilidades y librerías.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript
Optimizar módulos de RequireJS y archivos Javascript
Patrón de diseño MVC del lado cliente con Backbone.js
Introducción y ejemplo de Backbone.js

viernes, 26 de abril de 2013

Ejemplo lista de tareas con Backbone, RESTEasy y Tapestry

Backbone.js
Normalmente escribo artículos con ejemplos que tratan sobre una única tecnología, al tratar cada tecnología por separado entender que puede ofrecer es más sencillo pero en una aplicación real normalmente se usan varias tecnologías combinadas y al mismo tiempo. Esta entrada aunque sigue siendo un ejemplo es mucho más parecido a lo que podría ser una aplicación real que lo que he explicado durante las últimas entradas. En esta serie sobre javascript he explicado un montón de cosas por separado entre ellas RequireJSMustacheBackbone, servicios rest con Tapestry y RESTEasy. En esta entrada haré un ejemplo haciendo uso de todas las anteriores y alguna cosa más adicional como twitter bootstrap.

El ejemplo consiste en una lista de tareas, pudiéndose introducir nuevas tareas y marcarlas como realizadas. También se podrá eliminar de la lista las tareas completadas y ver un resumen con el número de tareas completadas y de tareas totales.

En la parte cliente de la aplicación se hace uso de RequireJS para manejar la carga de los archivos javascript necesarios, de backbone para gestionar la lista de tareas y realizar la comunicación con el servicio REST del servidor y de Mustache como motor de plantillas para generar la vista (el html). En la parte del servidor usa Tapestry como framework web y RESTEasy como librería para implementar un servicio REST que proporcionará la persistencia en memoria de la lista de tareas.

Backbone permite organizar el código aplicando el patrón de diseño MVC (modelo-vista-controlador) ampliamente extendido en los frameworks web. Este patrón de diseño tiene la ventaja que separa la aplicación en tres partes diferenciadas:
  • El modelo: que contiene los datos del dominio que maneja la aplicación que cuando es modificado lanza eventos para que el controlador y la vista actúen en consecuencia.
  • El controlador: que reacciona ante los eventos que se produzcan en el modelo o por el usuario y modifica adecuadamente el modelo o la vista según el evento.
  • La vista: que a partir del modelo produce la interfaz que se ofrece al usuario para que pueda manipularlos, los eventos producidos en la vista son manejados por el controlador.
Como se ve las tres partes se relacionan entre si pero están separadas de forma que cada una se encargue de una tarea. El código queda bien organizado y se evita el código espagueti que podríamos obtener de otra forma.

En una aplicación con la combinación de Backbone, Mustache y un servicio REST el servidor devuelve el html de la página inicial, las plantillas y los datos del servidor y se delega en el navegador del usuario la tarea de renderizar el html final. Esto tiene la ventaja de que entre el navegador y el servidor viajan menos datos (los datos y las plantillas tendrán menos tamaño que los datos formateados a html) y la parte del servidor se simplifica (no es necesaria la lógica para formatear a html los datos que dependiendo del framework hacen los jsp, tml de tapestry o gsp de grails). Aunque el código de la parte cliente crecerá, el código de la parte del servidor se hará más simple. Una vez cargada la página inicial entre el servidor y el cliente solo viajan los datos en formato json.

Veamos el ejemplo a continuación empezando por el modelo. El modelo con Backbone se define con Backbone.Model.extend, donde podremos indicar las propiedades de los objetos, también podemos definir funciones de utilidad. En este caso el modelo estará formado por los objetos Tarea que tendrán las siguientes propiedades:
  • Un id que identificará la tarea.
  • La descripción de la misma.
  • Y un indicador de si está completada.
Pero en la lista de tareas no solo tendremos un objeto Tarea, tendremos una colección de ellas. Esta colección también forma parte del modelo y se define con Backbone.Collection.extend, los elementos de esta colección serán objetos del modelo Tarea y lo indicamos en la propiedad model, también podemos definir funciones de utilidad como una función para obtener un array con las tareas completadas y otra para eliminar las tareas completadas que nos interesarán para ofrecer la funcionalidad de la lista de tareas. Las propiedades urlRoot y url son importantes para que backbone sepa localizar el servicio REST que proporcionará la persistencia.

La interfaz del servicio web REST es:

En Backbone la vista y el controlador de define en una misma entidad con Backbone.View extend. Aunque se definen ambas cosas a la vez la vista principalmente está formada por el método render, el resto será parte del controlador. Otra sección importante de la vista es la propiedad events donde indicaremos que eventos manejará el controlador y sobre que elementos de la vista, básicamente se define como clave el evento (click, change, ...) y un selector similar a los usados en jquery y como valor el nombre de la función que manejará el evento. En la vista también podremos definir métodos de utilidad. Tendremos dos vistas: una para para una tarea y otra para la aplicación de la lista de tareas.

En el método render se hace uso de Mustache para generar la vista a partir de una plantilla que contiene el código html, la plantilla combinado con los datos del modelo genera un resultado que será incluido en el html de la página. En las funciones initialize se inicializa la vista principalmente para definir que eventos que produzca el modelo serán tratados por el controlador, estos son las funciones on sobre el modelo, por ejemplo, nos interesará saber que se añade, modifica o elimina una tarea de la colección de tareas para actualizar la vista adecuadamente.

En el caso de TareasApp en el método initialize además se inserta en el elemento «el» que se le pasa en el constructor la vista inicial de la aplicación. De esta forma podríamos crear varias instancias de TareasApp.

Las plantillas de Mustache las he definido entre elementos <![CDATA[ ... ]]> ya que las plantillas de Tapestry han de ser xhtml válido, algunas expansiones de Mustache como {{attrs.checked}} de la plantilla tarea-template Tapestry no las entiende como válidas ya que realmente la plantilla Mustache en este caso no es html válido.

Una vez desarrollada la parte del servicio REST en el servidor con RESTEasy integrarlo con Backbone es muy sencillo, únicamente deberemos llamar en los puntos adecuados a las funciones save y destroy de los modelos. Al método save se le llama cuando se añade una nueva tarea en TareasApp.addTarea y cuando se modifica en TareaView.onChangeCompletada. Cuando se hace clic en el botón para limpiar las tareas completadas se llama a la función destroy de cada uno de los modelos. Estos métodos lanzarán las peticiones AJAX al servicio REST de forma automática variando su método y con su correspondiente url según hemos definido con las anotaciones del servicio REST: POST (crear), PUT (actualizar) y DELETE (eliminar).

Petición al crear una nueva tarea
Petición al marcar como completada una tarea
Petición al limpiar tareas completadas
La carga de inicial de la lista de tareas puede hacerse de dos formas: devolviendo los datos de las tareas cuando se pide la página o una vez cargada la página mediante una petición AJAX adicional. En Backbone recomiendan la primera ya que así se evitan peticiones al servidor innecesarias. Además aunque hagamos que las peticiones AJAX sean rápidas probablemente sean lo suficientemente lentas para que el usuario vea como se va rellenando el contenido de la página y dependiendo del html verá como los elementos van cambiando de posición lo cual puede ser molesto. Aunque hay que decir que incluir los datos en la propia página impediría cachear la página. Al final de la página Index.tml, está la sección para cargar la lista inicial de tareas que se pasará a TareasApp después de su constructor en el método resetTareas.

Esta es una captura del ejemplo:

Después de haber usado Backbone en este ejemplo simplemente tengo que decir que es una gran herramienta y que facilita y ayuda a organizar el código javascript en gran medida. Permite separar los datos de la aplicación que forman el modelo del controlador y la vista que reaccionan mediante los eventos producidos en el modelo. También permite desarrollar aplicaciones con un gran peso de javascript en la parte cliente sin que el código se convierta posteriormente en un infierno de mantenimiento aún con la ayuda de jQuery. Es una ayuda tan grande para hacer algunas cosas de la interfaz del cliente como lo es jQuery para manipular los elementos html.

Algunas partes no las he explicado como las plantillas de Mustache, el uso de RequireJS o la parte del servidor del servicio RESTEasy ya que ya lo que he hecho en entradas anteriores que puedes visitarlas mediante sus enlaces.

Como en el resto de entradas el código fuente completo lo puedes encontrar en mi repositorio de GitHub. Si quieres probarlo en tu equipo lo puedes hacer de forma muy sencilla con los siguientes comandos y sin instalar nada. Si no dispones de git para clonar mi repositorio de GitHub puedes obtener el código fuente del repositorio en un archivo zip con el anterior enlace.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript
Optimizar módulos de RequireJS y archivos Javascript
Patrón de diseño MVC del lado cliente con Backbone.js

viernes, 19 de abril de 2013

Introducción y ejemplo de Backbone.js

Backbone.js
Las aplicaciones y páginas web están haciendo uso de código javascript cada vez en mayor cantidad para proporcionar aplicaciones con funcionalidades más complejas. En estos momentos las librerías para utilizarse en javascript son muchas y una aplicación puede hacer uso de varias de ellas.

A pesar de las facilidades que proporcionan librerías como jQuery para manipular los elementos de una página web de forma dinámica, mucho código mal estructurado puede llegar a convertirse en un perfecto código espagueti, aunque jQuery facilita y simplifica muchas tareas en el manejo de los elementos de una página no es suficiente, a pesar de jQuery se puede llegar a tener un código con un mar de selectores, mantener sincronizados con la interfaz con el estado de la aplicación y la base de datos puede convertirse en una tarea complicada dar como resultado código con el que apetece poco trabajar.

Backbone.js trata de de resolver algunos de estos problemas proporcionando un marco sobre que el que organizar el código. Backbone.js en esencia en una librería modelo-vista-controlador (MVC) para javascript. Basándose en este patrón de diseño cada parte es independiente del resto. El modelo conserva el estado de la aplicación y produce eventos al ser modificado de forma que la vista se pueda actualizar de una forma independiente para ambos, la vista proporciona la interfaz del controlador a través del que se modifica el modelo de forma adecuada, todos los elementos están relacionados pero cada uno se encarga de una parte.

Patrón de diseño Modelo Vista Controlador (MVC)

Backbone además proporciona una forma para trabajar con servicios REST tanto para recuperar los datos de los modelos como para actualizarlos, guardarlos y eliminarlos en el servidor. A continuación pondré un pequeño ejemplo usando backbone.js que calcula el área de un rectángulo dado su alto y ancho y que lo muestra en pantalla. Como backbone.js sigue el patrón de diseño MVC por un lado tendremos el modelo, en nuestro caso el rectángulo con las propiedades alto y ancho que nos servirán para calcular el área, por el otro la vista que se actualizará según los datos del modelo introducidos en dos campos de texto, finalmente el controlador que captura los eventos como los cambios en los campos de texto, modifica el modelo y el modelo notifica a la vista para que se actualice.

Vemos un ejemplo simple y que muestra parte del potencial de backbone.js. El modelo se define con el siguiente código, además de las propiedades se puede definir funciones que nos puede ser de utilidad, como calcular el área o obtener un objeto para ser utilizado con Mustache:


La otra parte es la vista y el controlador, ambas cosas se definen con Backbone.View.extend:

La inicialización del ejemplo:


Las partes de esta vista-controlador son:
  • el: el elemento html sobre el que actuará la vista.
  • events: los eventos que manejará el controlador, es un mapa donde la clave es un selector muy parecido a jquery y el nombre de la función a llamar cuando se produzca.
  • initialize: con la función de underscore _.bindAll haremos que la referencia a this sea la vista en las funciones indicadas (render, onChangeAlto, onChangeAncho). A continuación se crea el modelo y cuando se produzca algún cambio en él (evento change) se actualice la vista. Finalmente, cuando se inicia la aplicación se dibuja por primera vez la vista.
  • onChangeAlto y onChangeAncho: obtienen el alto o ancho de los campos de texto y modifican el modelo.
  • render: se encarga de actualizar la vista cuando haya algún cambio en el modelo tal y como hemos echo en la función initialize con la función on sobre el modelo. Actualiza los inputs de alto y ancho con los valores del modelo y mediante una plantilla de Mustache forma el mensaje que se visualiza en el  elemento con id resultado.
Finalmente, queda el pequeño código html de la aplicación que contiene los campos de texto para introducir el alto y ancho y el elemento div donde se mostrará el área calculado del rectángulo:



Backbone.js no es la única librería que implementa el patrón MVC en javascript otras alternativas son knockout y AngularJS aunque esta últimas tienen la notable diferencia de que se basan en añadir atributos especiales a las etiquetas html para definir el modelo y asociar los eventos. Backbone.js no necesita añadir esos atributos especiales a la etiquetas html o «instrumentalizarlo», esto se hace a través de javascript lo que da una mayor separación entre el código html y el código javascript. Por ahí se dice que usando backbone.js para realizar lo mismo se necesitan más lineas de javascript pero hay que tener en cuenta que a cambio el html necesario es mucho más simple que en knockout o AngularJS lo que facilita que el trabajo con motores de plantillas como Mustache o Handlebars también sea más simple.

Como en el resto de entradas sobre esta serie de javascript el código fuente del ejemplo completo lo puedes encontrar en mi repositorio de GitHub. Este ejemplo se basa en RequireJS y Mustache visto en anteriores entradas que puedes consultar en el apartado de referencia al final de la entrada.

En la siguiente entrada mostraré un ejemplo completo y usando muchas cosas al mismo tiempo de las que he estado hablando individualmente en las últimas entradas, será un ejemplo de una aplicación de lista de tareas por hacer que permite crearlas y completarlas, usará RequireJS, Mustache y Backbone (usándolo de forma más avanzada y completa de lo visto en esta entrada) en la parte cliente y Tapestry y RESTEasy en la parte servidor.

Referencia:
Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript

viernes, 12 de abril de 2013

Optimizar módulos de RequireJS y archivos Javascript

Una vez que tenemos desarrollada una aplicación que hace uso de RequireJS como herramienta para gestionar las dependencias y archivos de javascript podemos realizar una optimización para conseguir que haya menos archivos y tengan menor tamaño. Esta optimización hará que la aplicación web realice menos peticiones al servidor y necesite transferir menos bytes dando como resultado una aplicación más rápida.

Para conseguir esta optimización necesitamos tener instalado la herramienta node.js y descargar el javascript que realizará la optimización, r.js. En Arch Linux instalar node.js consiste en instalar su paquete con:

Teniendo instalado node.js y habiendo descargado r.js el proceso consiste en ejecutar un comando desde la terminal. Este es:

El contenido del archivo build.js contendrá alguna información como el archivo de salida y la localización del módulo principal de la aplicación, básicamente la configuración es:

Este sería el resultado de optimizar el ejemplo de introducción sobre RequireJS. En el resultado se han eliminado los espacios y tabuladores, los diferentes archivos se han fusionado en uno solo (en este caso únicamente figuras.js y main.js) y los nombres de las variables se han acortado, esto reduce el tamaño del Javascript final. Esta optimización sirve también en cierta forma como ofuscación del código si queremos dificultar a alguien (como a la competencia de un producto) se aproveche del código que hemos desarrollado:


Al optimizar los archivos es recomendable ver las notas que indican en la documentación de RequireJS.

Si se quiere optimizar archivos individuales de javascript o no usamos RequireJS se puede utilizar la herramienta Closure Compiler, es muy sencilla, no hace falta instalar nada en nuestro equipo sino simplemente usar el servicio y da un resumen de la optimización que realiza.

Referencia:

Introducción y ejemplo de RequireJS
Introducción y ejemplo de Mustache
Logging en Javascript con log4javascript
Capturar errores de Javascript
Related Posts Plugin for WordPress, Blogger...