De vuelta del Greach 2013

Este viernes 25 y sábado 26 de Enero se ha celebrado en Madrid el segundo Greach, el evento en España centrado exclusivamente en Groovy y su ecosistema, donde nos hemos juntado buena parte de la comunidad gracias al trabajo de Alberto Vilches en su organización.

Asistentes al Greach 2013, foto de @jerolba

Tuve la oportunidad de volver a participar como ponente en esta edición al aceptarme la propuesta de charla que llamé Testing en proyectos Grails del día a día, que como nombre era menos feo que Testing como lo hago yo. En la que pretendía centrarme, más que en las herramientas de testing en sí y en sus posibilidades (acerca de lo que ya se iba a hablar en otras charlas), en como practico yo el testing en mis proyectos y como les saco partido a esas herramientas.

No me veo capaz de hacer un resumen exaustivo de las charlas a las que asistí, además fueron grabadas y las podréis ver en cuanto las publiquen (pronto), pero estas fueron a las que asistí:

Al acabar las sesiones del primer día Escuela de Groovy – Salenda invitaban a cervezas en un bar cercano, y uno es educado y no rechaza una invitación así ;). Después un poco de tapeo con buena gente de la Zona Norte no muy lejos de Preciados y no muy tarde de vuelta al hotel a descansar.

En el segundo día:

@jorgeuriarte en Greach 2013

Sobre el contenido de las charlas: Aunque en ocasiones algunas me sobrepasaban por la mezcla de mi dificultad para seguir algunas charlas en inglés y el tratamiento de temas en los que no he profundizado, en otras por el contrario me quedé con las ganas de que se profundizara algo más y en unas pocas eché en falta algo más de sentido práctico; salí bastante satisfecho de casi todas a las que asistí. También me quedé con las ganas de haber asistido a otras charlas que pintaban muy bien, tocará verlas en video.

Sobre mi charla: Soy totalmente consciente de que no ha sido ni mucho menos una de las mejores charlas que haya hecho últimamente, tenía claro que mensaje quería dar desde que propuse la charla, pero no cómo hacerlo. Aún tras haberle dado muchas vueltas a la presentación, seguía sin convencerme totalmente, y eso (junto a mi archienemigo en las presentaciones: el micrófono de mano :)) me hizo empezar con unos nervios y presión que no sentía desde cuando hacía mis primeras charlas. Luego poco a poco me calmé, remonté y empecé a comunicar mejor, pero desde luego que no me quedé para nada satisfecho con el resultado; espero que algunas de ideas hicieran mella y sirviera de utilidad a los que asistieron.

Sobre el lugar: Me pareció un acierto el que fuera en el centro de Madrid, para los que venimos de fuera es mucho más atractivo y facilmente accesible en transporte público, además de la comodidad de comer en el mismo hotel. Por poner un par de pegas, los contras para mi fueron los pequeños atascos en los ascensores para cambiar de sala, aunque había bastante tiempo entre charlas que lo compensaban, y principalmente que en una de las salas, por su disposición, las líneas de abajo de algunas proyecciones no se veía bien desde el fondo (terminé de pie en varias ocasiones por ello) y que su acústica era bastante mejorable.

Algunas pequeñas impresiones que me llevo:

  • Ya hay un buen puñado de proyectos de entidad que utilizan grails en españa, para los que aún creen que no es una herramienta “seria”
  • Seguimos siendo una comunidad muy pequeñita, con 2-3 focos geográficos donde hay más desarrolladores utilizando estas tecnologías, pero muchos estamos un tanto aislados
  • Spock definitivamente está empezando a ser (o está ya siendo) el framework de testing más utilizado, de 5 charlas de testing 4 tocaron (tocamos) este framework
  • Creciente interés por arquitecturas orientadas a eventos/asíncronas (vert.x, el roadmap de grails, algunos plugins…)
  • Me pareció muy interesante que se intentara internacionalizar con la mayoría de charlas en inglés, creo que es un camino a seguir para tratar de atraer a más público europeo

Por cierto, hay un buen puñado de fotos del greach en el evento de google plus, y un resumen del movimiento en twitter, slidesahre y demás en eventifier.

SpotyWhere, nuestro proyecto en el Grails48

El segundo fin de semana de Noviembre, se celebró el primer Grails48, un hackathon a nivel mundial en el que se debía desarrollar una aplicación web hecha con Grails en el transcurso de un fin de semana.

Pues bien, yo participé en un equipo junto a Raúl Gracia (desde Londres), Fernando Val (desde Dublín), Rafael Ramos (desde Zaragoza) y Alberto Vilches (desde Madrid); lo que viene siendo un equipazo, que además del evidente handicap de que supone la deslocalización tenía alguno más. Salvo Raúl y yo, el resto no habíamos trabajado nunca juntos (o no más que en proyectos pequeños por amor al arte). También sabíamos que no íbamos a pegarnos todo el fin de semana programando (por ejemplo, yo mismo me fui con Rafa de concierto el sábado, con su posterior resaca :P) y que la dedicación de algunos iba a ser bastante limitada por tener otro tipo de obligaciones. Pero, con el equipo que montamos, tenía claro que del fin de semana saldría un resultado interesante de todas formas.

La idea a desarrollar era de Raúl, una aplicación web donde localizar canciones en un mapa, que era la idea que más nos convenció de las que barajamos. Terminamos decidiendo centrarnos únicamente en Spotify y su API, y a partir de ahí empezó la gestación de SpotyWhere.

Spotywhere

El día antes hicimos algunos bocetos y wireframes, para intentar tener todos una idea lo más común posible de lo que iba a ser lo que íbamos a hacer y ponernos más o menos de acuerdo. Aunque al final las decisiones de la interfaz eran principalmente criterio de Fernando.

Para organizarnos y comunicarnos usamos varias herramientas: en una sala de HipChat procurábamos llevar el grueso de la comunicación, un poco de Skype para aclarar algunos puntos, Trello para gestionar nuestras historias de usuario y tareas, y un repositorio git privado en GitHub que ponía la organización.

La aplicación está desplegada en AppFog, que proponía de nuevo la organización, y decidimos utilizar MongoDB (en MongoHQ) como base de datos. Una base de datos documental encajaba bien con nuestras necesidades, además de permitir hacer búsquedas geo-espaciales (aunque ahora no las usamos) y el plugin de MongoDB GORM que lo deja muy facilón.

Decidimos habilitar el login/registro de usuarios con Facebook y Twitter, así dejábamos el registro más fácil a los usuarios y no teníamos que preocuparnos de montar todo el sistema de gestión de usuarios. Para esto y para la integración con la búsqueda de canciones de Spotify tiramos del plugin REST client facilities y HTTPBuilder.

Mientras que para la parte de front se usa Foundation, Google Maps junto a MarkerClusterer en los mapas y jQuery para algunos detalles de interacción.

Yo creo que nos quedó un resultado más que presentable, pero algunas mejoras y funcionalidades se tuvieron que quedar fuera. Cosas como un mapa en los perfiles de usuario o que pueda funcionar bien en terminales móviles son cosas bastante evidentes. También a nivel de código hay parches nada elegantes, como controladores con más código de la cuenta, no hay un miserable test, bastante javascript guarro y mezclado con el html… Lo típico en un hackathon de estas características, vamos :D.

En fin, el tema es que el domingo conseguimos terminar (no sin nervios en las últimas horas) y hicimos el despliegue, otro entregable era un video donde se explicara el proyecto. No había un tipo de video establecido, y el marrón recayó en Raúl, os lo dejo aquí :P.

Al final resultó que en el podio terminaron 3 equipos hispanos (2 españoles y 1 mexicano). Mientras que nosotros nos llevamos una de las 3 menciones especiales, cosa que no ha estado nada mal :).

Una cosa que también me llamó la atención es que, al parecer, la organización contaba (¿cuenta?) con mentores y partners que en su momento podrían ayudar de algún modo a evolucionar a algo más serio a los proyectos participantes.
Veremos si alguno de los proyectos lo hace, en nuestro caso no creo que tuviera sentido. No deja de ser un proyecto bonito y que puede ir creciendo, pero muy complicado de hacer algo monetizable alrededor, o ganar dinero con él, que decimos los de pueblo.

Bueno… siempre nos podría comprar spotify XD.

VandalArt, ¿arte o vandalismo?

Los últimos meses he andado trabajando en proyectos de esos en los que no se luce, que bien son más empresariales, que se ha retrasado su salida al público y/o es trabajo alejado de la interfaz de usuario.

Quizás sea por eso que desde este verano ande un tanto disperso entre proyectos personales, tanto arreglando pequeñas cosas de algunos existentes, como trabajando en algunos nuevos. Tema aparte es el auto-enmarronamiento de la coordinación del grupo de trabajo de CachiruloHub, pero ese es otro tema.

Pues bien, uno de los pequeños experimentos a los que le he ido dedicando algunas horas es VandalArt.org. Una aplicación web que extrae referencias a fotos en instagram que se hayan etiquetado con ciertos hashtags (en este caso varios relacionados con arte urbano).

¿Por qué?

Por un lado porque instagram es uno de esos servicios que consulto y uso a diario, me gusta. Por otro, porque me gusta caminar por la calle y sorprenderme encontrando graffitis u otro tipo de obras que no conocía, o quedarme mirando de vez en cuando alguna que ya conozco.

Y al final se me pasó por la cabeza mezclar ambas cosas para poder ver arte urbano de cualquier parte del mundo.

¿Cómo?

La verdad que es una aplicación bastante simple. Desarrollada con Grails (el look and feel de la web lo delata ;)), utilizando el plugin de Quartz para hacer peticiones al API de instagram cada 30 minutos, de donde extrae la información de la foto y sus enlaces, pero las fotos siguen estando en instagram, por supuesto.

Como una cosa que me parecía muy curiosa era ver fotos sobre un mapa, implementé esa funcionalidad para las últimas 50 fotos subidas (y geolocalizadas). Se muestran usando la librería leaflet para interactuar con mapas, y los tiles son de cloudmade. Realmente no es gran cosa, pero creo que queda resultón.

El código está publicado en github con licencia MIT.

Be like a panda

¿Roadmap?

Tengo varias funcionalidades en mente, que supongo que haré poco a poco, principalmente:

  • Que te puedas registrar para guardar fotos como favoritas, simplemente porque te gusten o te puedan servir como forma de inspiración o por lo que sea…
  • Que funcione en tiempo real. Para este caso pienso que quedaría muy molón ver como aparecen nuevas fotos, y me apetece bastante jugar con el API Real-Time.

Y por cierto, que el proyecto ya tiene su primer fork. Para la Semana del Cine y de la Imagen de Fuentes de Ebro estaban organizando un concurso de instagram, tomando unas cervezas les comenté que posiblemente podrían aprovechar el código para hacer la web del concurso.

Y vaya si lo han hecho! Me encanta como les ha quedado la web del concurso de instagram de SCIFE :)

Grails tip: Importar direcciones de email de LaunchRock

Sigo trabajando en minchador, no al ritmo que hubiera querido (espero escribir sobre ello), pero sigo dándole.

Estoy ya preparando el lanzamiento de la beta cerrada arreglando detalles: mejorando textos, ajustando cositas de la UI, dándole vueltas al email de bienvenida, importando los mails de los que se han ido registrando en la landing hecha con LaunchRock

Pues bien, para sacar las direcciones de LaunchRock dejan a tu disposición la posibilidad de descargar los datos en un fichero en formato CSV con la siguiente estructura:

“timestamp”,”email”,”domain”,”user_clicks”,”user_signups”,”referred_by”,”ref_url”

Entonces lo que hice fue prepararme un sencillo Service de grails para importar tan sólo las direcciones, el código es el siguiente:
 

class LaunchRockService {
def emails
    def getEmailsFromCSV(csv) {
     def emails = []
     def lines = csv.split(‘\n’)
     lines.each{
     def email = it.split(‘,’)[1]
     emails << email.replaceAll(‘”‘,”)
     }
     return emails
    }
    def getEmailsFromFile(file){
     def lines = file.text.split(‘\n’)
     def total = lines.size()-1
     lines = lines[1..total]
     emails = getEmailsFromCSV(lines.join(‘\n’))
    }
    def emailIsForBeta(email){
     return emails.contains(email)
    }
}

 

Lo que hago es pasarle una instancia de File del csv de LaunchRock a getEmailsFromFile y recuperar todas las direcciones de email. En mi caso ejecuto ese método en el BootStrap de grails para tenerlas cargadas en memoria y acceder a launchRockService.emails desde otras partes de mi aplicación.

Ya puestos dejo el código junto a los tests los hice con especificaciones de Spock en un gist, por si a alguien le interesa.

Grails tip: Manejar uploads múltiples con mismo nombre de parámetro.

Una cosilla que he tenido que volver a hacer últimamente es tener que implementar un upload múltiple sencillito. En esta ocasión, sin necesidad de utilizar flash-javascript de por medio, gracias a la capacidad de selección multiple que viene con Html5:

<input name="images" type="file" accept="image/*" multiple="multiple">

El problema es que así todos los archivos que queremos subir vienen con el mismo nombre de parámetro, y el código habitual no se puede más que recuperar los ficheros subidos con distinto nombre.

request.fileNames.each { fileName ->
   def file = request.getFile(fileName)
   //hacer cosas
}

Pues bien, tras un par de búsquedas encontré una de esas pequeñas cosas que (por desgracia) no eres capaz de encontrar fácilmente en la documentación de grails: getMultiFileMap, que viene implementado desde Spring 3.

En fin, su uso en un controller de grails es el siguiente, es un map que contiene la colección de elementos que representa a cada fichero. Colección que recorreremos normalmente, o trataremos para lo que queramos hacer.

request.multiFileMap.images.each { file ->
   //hacer cosas
}

Reutilizar un custom validator en Grails

En estos momentos ando colaborando con Sergio del Amo en un producto propio para su empresa Softamo, un producto que estamos desarrollando con Grails.

El tema es que teníamos un puñado de clases de dominio que están relacionadas con un propietario, una clase User. Cada instancia de esa clase de dominio debía tener un nombre único por propietario, por lo que debíamos usar un custom validator. Al final, tras varias refactorizaciones llegamos a una solución que creo que quedó bastante elegante.

Las clases de dominio heredan de una clase padre con varios métodos comunes, además de una clausura estática que contiene la lógica de la validación uniqueByUser, que es lo que nos interesa para esto.

static uniqueByUser = { value, object ->
   propertyName = propertyName[0].toUpperCase() + propertyName[1..propertyName.size()-1]
   def methodName = "findByUserAnd${propertyName}"
   def obj = object.class."$methodName"(object.user, value)
   if(obj && (obj.id != object.id)) {
     return 'unique'
   }
}

Vale, por si no queda del todo claro, intento detallar que hace el código:

  • propertyName, es el nombre de la propiedad/atributo sobre la que se ejecutará la validación, variable que está implícita en la clausura.
  • propertyName[0].toUpperCase() + propertyName[1..propertyName.size()-1], ponemos en mayúscula el primer carácter del nombre del atributo (por ejemplo “name” pasa a “Name”).
  • def methodName = “findByUserAnd${propertyName}”, ponemos el método al que vamos a llamar para saber si ya existe un valor con mismo usuario y atributo buscado (por ej: findByUserAndName).
  • def obj = object.class.”$methodName”(object.user, value), ejecutamos ese findBy* estático sobre la clase del objeto instanciado que se está validando, pasándole el usuario relacionado y el valor del atributo (algo que podría ser equivalente por ejemplo a Drink.findByUserAndName(drink.user, “vodka”)).
  • if(obj && (obj.id != object.id)), comprobamos que si se devuelve un valor, no sea el mismo que la instancia del actual.
  • return ‘unique’, en este caso devolvemos el código de mensaje de validación como unique, por lo que aprovecharemos los mismos mensajes i18n del unique estándar de grails.

Entonces, en nuestras clases de domino que hereden de ahí, para el atributo donde queramos utilizar ese constraint simplemente deberemos indicar validator: uniqueByUser. Algo como:

static constraints = {
   name blank: false, validator: uniqueByUser
   description blank: false
}

Lo único que no contempla ahora mismo esta solución es tener más de un custom validator, principalmente porque no nos ha hecho falta. Si lo llegamos a necesitar, veremos como lo hacemos, claro :P.

Mejoras y propuestas bienvenidas.

ACTUALIZACIÓN: Mejor que darle tantas vueltas como hicimos nosotros, es utilizar el soporte multi-column de la constraint unique (Nota mental: No dar por supuestas según que cosas, e ir a verlo a la documentación). Gracias al comentario de @jneira.

Resumen del Spring IO 2012 (muy resumido)

Bueno, pues os voy a contar un poco mis impresiones y las charlas a las que asistí en el Spring IO, aparte del taller que estuve impartiendo, claro :).

El primer día sólo asistí a unas pocas charlas, llegué un poco tarde y luego anduve pendiente de finiquitar el contenido de mi taller del segundo día. Deambulé por algunas charlas pero prefiero no nombrar ni valorar el contenido, principalmente porque de esas no me enteré más que de el título y quien era el ponente :D.

- El primer día asistí a:

  • Creación de plugins para Grails, con Juan Reyes. Que, aprovechando, sirvió para el que quiso como introducción teórica a mi taller del segundo día. Juan explicó como es la arquitectura de un plugin de Grails, hizo un ejemplo y remarcó las capacidades dinámicas de groovy y como utilizarlas para extender los artefactos de aplicaciones que utilicen esos plugins.
  • Vitaminas para tu proyecto Java, con Alberto Vilches. Donde se hacía uso de groovy escalonadamente en una aplicación Java a base de Servlets, JDBC… Para mostrar que hasta en esas aplicaciones se puede sacar partido al lenguaje groovy. Realmente me metí en el taller para tener una mesa cómoda donde trabajar en mi taller, pero principalmente me sirvió para darme cuenta que la wifi no tiraba y que debía reenfocar parte de mi taller por no tener wifi para descargar plugins de internet.
  • Using Grails in a Startup, con Tomás Lin. Donde nos compartió sus experiencias, problemas y recetas que les han ido surgiendo en Secret Scapes. Para mi, allí donde voy, suelen resultarme el tipo de charlas más enriquecedoras: problemas reales en un contexto y las soluciones a las que se han ido llegando.
  • Pilotando con Spock, con Ruben Eguiluz. Nos estuvo hablando del framework de testing Spock, ya le había pegado un ojo pero todavía tengo pendiente utilizarlo en algún proyecto. Por ahora sigo dándole a Groovy Unit Testing con sus extensiones para los artefactos de Grails y Groovy Mocks
  • Atlassian Party. Qué puedo decir: copazos, cervezas, sorteos y gente interesante con la que charlar, que siempre es lo mejor. Lo malo: creo que jamás me había ido tan pronto de una fiesta desde que tenía 14 años :D, de todos modos, un 10 para Atlassian.

- El segundo día, volví a llegar tarde y me quedé por los pasillos durante las charlas previas al café, pero tras mi taller y la comida asistí a:

  • Polyglot Grails, con Marcin Gryszko. Marcin expuso las posibilidades políglotas de Grails con otros lenguajes de la JVM usando sus respectivos plugins: Clojure, Scala y JRuby. Me pareció una charla interesante, pero se me hizo muy dura, cometí el error de no tomar el café después de comer y mi capacidad de atención terminó tendiendo a 0 XD.
  • Grails, opción real y escalable para sitios web de alta carga, con Domingo Suarez. Nos estuvo explicando acerca de clickonero, al parecer la plataforma ecommerce más grande de Latinoamérica, al estilo club de compras. También fue una de esas charlas en las que se explica la experiencia del trabajo y problemas dentro de una empresa de internet; tanto desarrollando nuevas funcionalidades como manteniendo un alto tráfico en sus servidores.
  • Aplicando elasticidad en la búsqueda con Grails, con Enrique Medina, el pobre de nuevo cerrando con la última charla. Que estuvo hablando de Elastic Search, que es un proyecto que desde que apareció he tenido a la vista como alternativa (aparentemente) más ligera que solr para búsquedas full-text sin tener que “bajar” a lucene. Personalmente, no me decepcionó para nada. Seguramente para el próximo proyecto que necesite búsquedas full-text, elegiré esa solución.
  • Cervezas de despedida, cortesía de Zero Turnaround. Para mi que tenía que volver a Zaragoza en el último AVE, fueron más bien pocas.

Me he perdido cantidad de charlas y talleres, me ha gustado bastante el contenido y forma de casi todo lo que pude atender. Para mi gusto, las más destacables fueron las de Tomás Lin y Domingo Suárez.

Y pienso que posiblemente vaya a ser la última vez que proponga un taller para un evento. Me lleva más o menos el mismo trabajo que preparar una presentación en condiciones. Me evito dolores de cabeza con temas logísticos del tipo a la conexión a internet, versiones de las instalaciones de los asistentes… Y también pienso que viste menos que una charla.

En fin, hasta la de 2013!

PD: Agradecimientos a Yurena, Tana y Yeray por acercarme hasta atocha desde Boadilla el viernes. Mucho más rápido que el metro y, una compañía y conversación difícilmente mejorable la del comando muyayo :).

Presentación y código: Modulariza tus aplicaciones Grails

Sobre el taller que impartí el viernes en el Spring IO, el código está en mi cuenta de github y la presentación la he subido a mi cuenta en slideshare.

En resumen, en el taller trabajamos sobre una pequeña aplicación que es un pequeño gestor de contenidos, donde se puede categorizar el contenido y asociarle varias imágenes.

El ejercicio era sacar la funcionalidad completa de subida de fotos a un plugin. Esto es: Clase de dominio, controlador y vistas.

A ver si esta semana escribo con calma sobre las charlas que asistí y el evento en general, pero no prometo nada :P.

Bitly Shortener Plugin para Grails

A raíz de mi colaboración trabajando con UniversalPlaces, surgió la necesidad de integrar el acortador de urls de bit.ly. Principalmente para aprovechar las estadísticas que da este servicio alrededor de los enlaces compartidos, teniendo además uplac.es como dominio propio para este uso.

Lo desarrollé en un plugin que usamos internamente a modo de core, donde tenemos funcionalidad común. Porque, entre otras cosas, había que implementarlo en el buscador de hoteles en playas, en el portal de playas y en otro buscador vertical que saldrá a la luz próximamente.

Durante la semana pasada saqué un rato un par de noches para extraer la funcionalidad y escribir la documentación para poder publicarlo a modo de plugin de grails. No es gran cosa, pero quizás a alguien le ahorre un poco de trabajo :).

La documentación en inglés está en el README del repositorio en github, pero la dejo aquí en español:

¿Qué es?

Un plugin para grails que encapsula el método shorten de la API de bitly, para acortar urls.

Instalación

grails install-plugin bitly-shortener

Configuración:

En el Config.groovy se debe configurar el login de usuario de bitly, el apiKey de ese usuario; y si corresponde el dominio que se quiera utilizar.

bitly.login = "danilat"
bitly.apiKey = "R_FooBar"
bitly.domain = "j.mp" //optional

Cómo usarlo:

Hay 2 artefactos de grails que se pueden utilizar, un servicio bitlyService:

def shortened = bitlyService.shorten("http://www.danilat.com")
shortened.statusCode // 200 si la petición ha ido bien.
shortened.statusText // "OK" si la petición ha ido bien.
shortened.url // Nos da la url acortada si todo ha ido bien.

Y un taglib bitly:shorten:

${bitly.shorten(url:'http://www.danilat.com')}

<bitly:shorten url="http://www.danilat.com" />