Jobsket.com, Grails en un proyecto real
Sunday, July 25th, 2010Dejo por aquí mi presentación del sábado.
A ver si en estos días saco algo de tiempo y escribo sobre que tal estuvo la Lan Party
Dejo por aquí mi presentación del sábado.
A ver si en estos días saco algo de tiempo y escribo sobre que tal estuvo la Lan Party
El sábado 24 a las 12:00 de la mañana, daré una charla en la Tenerife Lan Party 2010: Jobsket.com, Grails en un proyecto real.
La charla será una explicación de qué es Grails y cómo lo usamos en Jobsket, una startup pequeñita con unos recursos muuuucho menores que otras empresas, y como nos ayuda a ser una de las compañías más innovadoras tecnológicamente en el sector de empleo en internet.

También hay otras actividades muy interesantes para desarrolladores en el programa. Aunque yo voy a destacar las relacionadas con la gente de Agile-Canarias, el viernes por la mañana a las 10:00 Yeray Darias y Fran Reyes impartirán un taller de Integración continua, y seguidamente a las 12:00 Carlos Blé organiza un Code Retreat.
Leyendo la lista de correo de grails, me encuentro un pequeño script, que al menos a mi me parece muy útil para los que a veces andamos cambiando entre varias versiones de grails: grails.sh.
Sencillo y cumple su función. Al parecer funciona perfectamente en Mac, Linux y Windows con cygwin. Y para los despistados como yo, recordad darle permisos de ejecución al script
Desde que trabajé hace algo más de un año con los cracks de Linking Paths y Rails que no tocaba Cucumber, hasta este fin de semana, que he estado haciendo algunas pruebas con el plugin grails-cucumber. Cucumber es una herramienta para hacer tests de aceptación(a la Behaviour Driven Development) escrita en Ruby que ayuda a bajar la barrera que separa a la gente de negocio o de testing(hay una leyenda urbana que dice que existen XD) con los programadores, utilizando un DSL de por medio.
Por un lado gracias a la JVM y JRuby podíamos aprovecharnos de esta interesante herramienta utilizando Ruby, y por otro, hace cosa de un año y algo que se han ido añadiendo soporte a otros lenguajes de la JVM con el proyecto cuke4duke. A día de hoy, también podemos escribir los tests con Java, Groovy, Scala, Clojure, Javascript y Ioke; cada uno que elija el lenguaje que más le guste
. Y siguiendo con la recapitulación, a principios de primavera surgió el plugin para grails y desde entonces que tenía pendiente probarlo, pero por falta de tiempo unas veces o simplemente no acordarme otras, lo había ido retrasando
.
En fin, pues después de encontrarme varios problemas para instalar y hacer funcionar el plugin, preferí hacer un fork para modificar el código bajo mis necesidades y luego hacer un pull request en github para que se pudieran aprovechar los cambios. Arreglé un problemilla con el script Gant de ejecución de cucumber con mi versión de grails(1.2.2), aproveché a actualizar las depenencias con jruby y cuke4duke a las últimas versiones y eliminé la dependencia con picocontainer.
Tras estos pasos me puse a escribir una feature como esta:
Feature: Search job offers
Scenario: Search job offers in zaragoza, we should have results
Given I'm at jobsket.es
And I write zaragoza into the seachbox
When I submit the form
Then the result should contains Promotora
And the result should contains zaragoza
Supongo que a los que conozcáis otras herramientas de BDD os resultará familiar o imaginaréis por donde van los tiros del significado de este DSL(pre-condiciones, proceso, post-condiciones). Pero como supongo que a algunos les resultará útil, ahí va una mini-explicación con mis palabras
Feature: Es la funcionalidad que vamos a testear, en este caso la búsqueda de ofertas de empleo en jobsket.
Scenario: El escenario vendría a ser una historia de usario de la funcionalidad, esto quiere decir que cada scenario sería probar una funcionalidad en un contexto distinto.
Given: El estado inicial del escenario, se pueden concatenar varios con And’s.
When: El proceso que queremos probar, también se pueden concatenar varios usando And’s… pero de inicio no tiene sentido, deberíamos probar sólo una cosa en cada escenario.
Then: Las comprobaciones para saber si el escenario se está ejecutando correctamente o no.
Bueno, una vez escritos los pasos de la feature, nos queda escribir los steps para que se ejecute el test del escenario. Como en nuestro caso queremos aplicar el test de aceptación a una interfaz web, utilizaremos el archi-conocido Selenium. El código en Groovy quedaría algo parecido a esto:
import org.openqa.selenium.By
import org.openqa.selenium.WebDriver
import org.openqa.selenium.WebElement
import org.openqa.selenium.htmlunit.HtmlUnitDriver
import static groovy.util.GroovyTestCase.*
this.metaClass.mixin(cuke4duke.GroovyDsl)
WebDriver driver
WebElement element
Before() {
driver = new HtmlUnitDriver()
}
Given(~"I'm at jobsket.es") {
driver.get("http://www.jobsket.es/home")
}
Given(~"I write (\\w+) into the seachbox") {keywords ->
element = driver.findElement(By.id("keywords"))
element.sendKeys(keywords)
}
When(~"I submit the form"){
element.submit()
}
Then(~"the result should contains (\\w+)") { someContent ->
assertFalse(-1 == driver.getPageSource().indexOf(someContent))
}
Si os fijáis, lo único raro es this.metaClass.mixin(cuke4duke.GroovyDsl), que hace la “magia” para que funcione el DSL. Los Given, When y Then se ejecutarán cuando coincida una cadena de las features, internamente funcina mediante expresiones regulares. El Before() se ejecuta antes de cada escenario, y para ser re-utilizable entre features distintas debería estar en el directorio support. El resto del código no deja de ser de selenium/webdriver normal y corriente, además de usar GroovyTest(basado en JUnit) para comprobar que se cumplen las post-condiciones.
Hasta aquí no hay diferencias con utilizar cuke4duke con Groovy sin Grails. Lo que aporta el plugin de grails es que ayuda a olvidarse de instalar jruby y la gema de cuke4duke, lo integra como herramienta de línea de comandos(ejecutando grails cucumber) y entonces tampoco es necesario configurar nada nuevo en el servidor de integracion contínua para ejecutar estos tests.
En mi opinión, todavía está lejos de la integración de Cucumber con Rails, al menos por lo que yo recuerdo. Con Rails tras cada escenario se devuelve la base de datos al mismo estado inicial, es posibl combinar comprobaciones a nivel de interfaz y a la vez acceder a los métodos de los modelos para preparar o comprobar el escenario… vamos, que ayuda a que puedan ser tests menos frágiles, que es lo negativo que se suele ver en los test de aceptación(también llamados funcionales o de sistema).
De todas formas, sigue siendo un plugin muy interesante por poder conocer en un lenguaje cercano al natural si un escenario está en un estado aceptable o no, y si hay gente no técnica de por medio puede ser una herramienta perfecta para acercar mundos.
Ala! Fin del tocho! XD
Estoy con un pequeño trabajillo entre manos, una migración de una base de datos, y necesitaba conocer el próximo valor de un identificador AUTO_INCREMENT de MySQL. Por si a alguien le sirve(o tengo que echar mano en el futuro
), es tan sencillo como hacer una consulta a la tabla tables de information_schema.
select AUTO_INCREMENT from information_schema.TABLES where TABLE_SCHEMA='soy_la_db' and TABLE_NAME='y_yo_la_tabla';
Actualización 26/07/2010:
Gracias a un comentario de Venkman, me entero que es posible conocerlo del siguiente modo:
SHOW TABLE STATUS LIKE ‘mitabla’
Si alguien sabe si hay grandes diferencias y lo quiere compartir, será bienvenido
Hace un par de semanas, Teresa Oliver avisaba en la lista de correo de Agile Spain que ya estaba preparado el II encuentro Agile Aragón. Este jueves 17 de Junio en el edificio del ITA en Zaragoza, por problemas logísticos se cambia el día al Lunes 21 de Junio a las 18:30.
En esta ocasión será un evento formal, donde gente de Frogtek, en mi humilde opinión, una de las startups tecnológicas con mejor pinta en Aragón; nos explicará cómo trabajan y el ecosistema de herramientas que utilizan.
Hay un video que ronda desde hace unas semanas por youtube y en algunas listas de correo a las que estoy suscrito, en donde se puede intuir de que hablaran este jueves
Como supongo que muchos ya sabréis, una especificación de HTML5 es Web SQL Database para persirtir datos en una base de datos relacional embebidos en el navegador web(la otra alternativa es Web Storage, para persistir datos como clave valor). Esto puede tener muchas aplicaciones, en mi caso lo he utilizado para implementar el sistema de favoritos de DNDzgz.
Cuando pretendamos sacar partido de las nuevas características de HTML5 debemos tener en cuenta que cada navegador puede soportar sólo algunas especificaciones, no es un todo o nada, por lo que lo primero que deberemos hacer es comprobar que soporta la especificación que queremos usar, por ejemplo:
function supports_local_database() {
return !!window.openDatabase;
}
Si existe openDatabase, crearemos la conexión a la base de datos:
db = openDatabase('dndzgz', '1.0', 'DNDzgz', 65536);
Una vez abierta la conexión, podremos ejecutar cualquier tipo de query SQL(compatible con SQLite), dentro de una transacción. Por ejemplo crear una tabla:
db.transaction(
function(transaction) {
transaction.executeSql(
'CREATE TABLE IF NOT EXISTS favorites ' +
' (id INTEGER NOT NULL, ' +
' service VARCHAR(255) NOT NULL, ' +
' date DATE NOT NULL,' +
' name VARCHAR(255) NOT NULL, ' +
' latitude REAL NOT NULL, ' +
' longitude REAL NOT NULL, ' +
' PRIMARY KEY (id,service));'
);
}
);
Insertar datos:
db.transaction(
function(transaction) {
transaction.executeSql(
'INSERT INTO favorites (id, service, date, name, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?);',
[id, service, new Date(), name, latitude, longitude],
callBack,
errorCallBack
);
}
);
Eliminar datos:
db.transaction(
function(transaction) {
transaction.executeSql('DELETE FROM favorites WHERE id=? AND service=?;',
[id,service], null, errorCallBack);
}
);
Y por supuesto mostrarlos:
db.readTransaction(
function(transaction) {
transaction.executeSql(
'Select * from favorites;', [],
function(transaction, result){
for (var i=0; i < result.rows.length; i++) {
var row = result.rows.item(i);
alert(row.name);
alert(row.service);
}
},
errorCallBack
);
}
);
Como podéis ver, a executeSql se le pasa primero la query, seguidamente un array con los valores de los argumentos de la query, y finalmente una función de callback y otra de callback para el caso de que existan errores. Y existen dos tipos de transacciones: transaction y readTransaction, la primera es de lectura-escritura, mientras que la segunda es de sólo lectura.
En fin, supongo que a otros también os pasará lo mismo, resulta bastante raro estar tirando queries SQL desde javascript. Pero puede resultar útil para muchos casos, empezando por descargar de responsabilidades y carga al lado servidor.
Lo prometido es deuda, tenía pendiente escribir un poco acerca de la parte técnica del fin de semana del desafío AbreDatos y de DNDzgz. A grosso modo las tecnologías utilizadas fueron Google App Engine(GAE) y Python del lado servidor; del lado cliente fueron Javascript con jQuery, la versión 3 del API de Google Maps, algunas de las novedades de HTML5, unas gotas de CSS3 y jQTouch para ayudarnos para que tuviera pinta de aplicación nativa iPhone. Usamos Git como repositorio de código, el repositorio está concretamente en github; para los documentos, diseños, fotos, etc. utilizamos dropbox(antes del fin de semana yo no tenía ni cuenta
).
La elección de GAE fue casi instantánea cuando empezamos a hablar con gimenete acerca de presentarnos al AbreDatos, las razones: hosting gratis y capacidad de escalar mucho sin tener que gastarnos ni un euro, despreocuparnos de la parte de sistemas, ningún problema con las limitaciones por correr sobre la plataforma de Google.
Que usáramos Python, aún siendo más javeros que otra cosa, fue por que ninguno de los 2 teníamos experiencia con GAE en Java(okok, yo había hecho un pequeño experimento, pero muy poca cosa para llegar a ninguna conclusión). Por eso preferimos aprovechar su experiencia desarrollando la primera versión de debug_mode=ON con Python+GAE; mientras que varias semanas antes yo me ojeé un par de manuales de inicio rápido, retomé el ebook Python para todos que tenía a medio leer(hace muuuucho
) y un par de días antes, me hice en poco rato el proyecto de ejemplo de GAE. Para extraer los datos utilizamos tanto Beautiful Soup como expresiones regulares para hacer scraping de HTML o Javascript de Tuzsa y Bizi, y simplejson para cargar los datos JSON de datos.zaragoza.es.
Que utilizáramos jQuery como framework Javascript, fue una elección posterior a jQTouch(que está basado en jQuery) pero de todas formas, seguramente lo hubiéramos elegido. Google Maps es la elección “por defecto” para todo el que quiere hacer algo con mapas
. Gimenete es quien estuvo peleando con esto, teníamos problemas con la fluidez en la navegación de los mapas, que al final consiguió mejorar… Eso sí, fuera del navegador Safari del iPhone no conseguimos que los mapas funcionaran correctamente, ni en terminales con distintas versiones de Android y ni si quiera en el Safari de Mac(tenemos que ver que pasa exactamente, tras algunas pruebas, el sospechoso principal es jQTouch).
Gracias a que iPhone(y las últimas versiones de Android) soportan parte de HTML5, se ponían a nuestra disposición algunas de esas novedades que molan tanto (Flash, tiemblaaa!!
):
En fin, que debemos molar, porque nuestro proyecto es una pequeña colección de buzzwords: Cloud Computing vía Google App Engine, HTML5, iPhone… XD
El lunes me quedé sorprendido por la respuesta ante el primer encuentro Agile Spain en Aragón, que había convocado Teresa Oliver, alrededor de 20 personas terminamos asistiendo a esta primera toma de contacto. Gente que nos dedicamos a crear nuestros propios productos de software, que da servicios de desarrollo de software, de administraciones públicas… y de diferentes roles dentro de cada organización.
Personalmente fuí a tomar el pulso de la situación del agilismo en mi tierra y a aprender lo que pudiera, y aunque me quedé con la sensación que por estos lares andamos bastante verdes, creo que hay potencial para que esto vaya mejorando. Tampoco tuve oportunidad de absorver conocimiento
, por ser la primera reunión y estar bastante gente terminamos discutiendo en corrillos, aunque yo tuve conversaciones que me hicieron pensar y estrujarme la cabeza XD.
En fin, esperaremos al siguiente encuentro, a ver si la respuesta de la gente es al menos igual, tratamos ya un tema concreto para ver que se puede aprender de experiencias ajenas, y porqué no… hasta intentar aportar algo
Ya que estamos, por si alguien anda despistado con esto de las metodologías ágiles, dejo aquí el manifiesto ágil, que además siempre queda bien ponerlo
:
Estamos poniendo al descubierto mejores métodos para desarrollar software, haciéndolo y ayudando a otros a que lo hagan. Con este trabajo hemos llegado a valorar:
- Individuos e interacciones sobre procesos y herramientas
- Software que funciona sobre documentación exhaustiva
- Colaboración con el cliente sobre negociación de contratos
- Responder ante el cambio sobre seguimiento de un plan
Aunque los elementos a la derecha tienen valor, nosotros valoramos por encima de ellos los que están a la izquierda.
Y pos supuesto un placer ver a gente conocida interesada por el tema, conocer caras nuevas del mundillo, y coincidir por fin con Jorge Rubira, que ya era hora!!
Este viernes noche después de cenar me puse a programar(o a jugar) uno de esos mini-pet-projects, lo suficientemente pequeño para no comprometerme a dedicarle más tiempo fuera del fin de semana y lo suficientemente grande para que sea algo más que un hello world. Y salvo a que tenga algún momento de aburrimiento en el que me de por mejorar o añadir alguna cosilla, así se va a quedar.
El proyecto es un agregador de twitts que hablan del Real Zaragoza(o #realzaragoza
). Y como uno no quiere hacerse de oro, no lo hace ni del Madrid ni del Barça
.
Hablando ya desde el punto de vista puramente técnico, es una aplicación muy sencillita que corre en la nube de Google, osea en App Engine (aquí voy a ahorrarme varios comentarios de lo que mola la nube, además de confundirlo con internet… No voy a dar nombres…
)
He utilizado un framework web ligero, hecho expresamente para correr en App Engine y muy sencillo llamado gaelyk, donde el código que escribimos es Groovy.
Gaelyk permite separar las vistas(Groovy Tempaltes) de las acciones(Groovlets). Inyecta en las acciones los elementos del SDK de GAE(datastore, memcache, mail, images…), y algunas variables para facilitar la vida y tener un código más escueto.
En mi caso he dejado la lógica de negocio en los mismos scripts de los Groovlets. Tan sólo hay tres: la home, la vista de un usuario(ej: @dani_latorre) y otro que es llamado cada 10 min para hacer una búsqueda en twitter e insertar los twitts nuevos.
Para la búsqueda de twitts, se hacen tan sólo dos peticiones cada 10 min y se parsea la respuesta atom de la búsqueda con XmlSlurper, se comprueba si no está duplicado y se crea y guarda una nueva Entity de GAE (gaelyk facilita su uso, para que sea más a la groovy).
Para recuperar lo que hemos persistido, por el momento no aporta novedades, a partir del datastore lanzaremos las queries. En el futuro es posible que surjan novedades en este apartado.
Para quien le interese conocer más detalles de gaelyk, le recomendaría pegarle una ojeada al tutorial.
Ver una presentación de Guillaume Laforge y Patrick Chanezon.
O un screencast de Pratik Patel(ojo, que a los elementos de GAE inyectados ya no se les llama loqueseaService, sólo loquesea)
Gaelyk & Groovy & Google App Engine – ATL2G from Pratik Patel on Vimeo.
Y aunque este año nos toca sufrir, aupa Zaragoza! XD