Reiniciando…

Últimamente estoy dándole vuelta a muchas cosas sobre mi situación profesional, sobre lo mucho que me he equivocado alrededor del último año y medio. Yo lo que quiero es dedicarme a producto propio y a ir participando en proyectos de terceros. Pero como he cometido demasiados errores en mis decisiones, estoy en un punto donde jamás quise estar

Pienso que mis principales errores han sido no haber acertado eligiendo a mis clientes, no haber gestionado bien nuestra relación, no ser tan exigente con ellos como procuro serlo conmigo y/o no haber sabido cortar con ellos a su debido momento. Y es que hay algo que tengo más que asumido, si tengo problemas con un cliente el principal responsable soy yo.

Esto me ha llevado a situaciones que a uno le apetecen poco a estas alturas del partido:

  • Haber palmado pasta en un proyecto a un nivel indecente. Eso que tengo una sensación de que casi he invertido más dinero en el proyecto yo que el propio cliente.
  • Cobrar por debajo de mi precio (que de por sí era excesivamente barato) como apuesta y compromiso personal en un par proyectos. Para que luego se terminasen desvaneciendo todas las promesas de futuro, por supuesto.
  • Desarrollar un proyecto que ha acumulado una deuda técnica enorme por andar con prisas, debería haberme impuesto y parado el desarrollo hasta no haberlo renegociado y solucionado.
  • Tener retrasos en pagos, cosa que además en una ocasión acepté en como mal aceptable durante una colaboración y finalmente tuve que asumir un impago durante varios meses.

Siendo un desarrollador que trabaja para sí mismo y que quiere ganarse bien la vida, haciendo las cosas lo mejor posible, trabajar en proyectos bonitos y colaborar con grandes profesionales; cosas como esas no me han dejado avanzar en proyectos propios y colaboraciones, además de hacerme pasar momentos duros y situaciones poco agradables.

Ahora es momento de recuperar esos pasos e ir más allá, estoy procurando retomar un camino que quiero que me lleve hacia donde realmente quiero. Para eso estoy procurando elegir mejor a mis clientes, empezar a gestionar mejor nuestra relación, ser más exigente con ellos a todos los niveles y, si es necesario, cortar mi colaboración si no se cumplen unos mínimos de respeto y entendimiento profesional.

En fin, espero que no se perciba simplemente como un post de lloriqueo o un pataleo, nada más lejos. Que también he trabajado en algunos proyectos chulos; además ahora tengo cositas interesantes entre manos y espero ir compartiendo evoluciones :)

Git tip: Aumentar el postBuffer para push con cambios grandes

Ayer me surgió un problema al hacer push a un repositorio remoto de git (en bitbucket). El tema es que el repositorio, además de para las gestión de versiones del código en sí; se va a empezar a utilizar para mantener versiones del .war de una aplicación Grails, donde se va a usar también un hook para actualizar y desplegar la aplicación a un entorno de preproducción.

Como resulta que git por defecto tiene un postBuffer de 1MB, y los .war pesan algo más de 40MB, me daba el siguiente error:

Error: RPC failed; result=22, HTTP code = 411

Para aumentar el postBuffer es tan sencillo como cambiar la configuración en el repositorio local:

git config http.postBuffer bytes

Donde bytes será el tamaño máximo de los que se permitirá hacer push.

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
}

Agile Manifesto. Camino del AOS

Ayer hubo un evento de introducción a las metodologías ágiles Camino del AOS, donde estuve explicando el manifiesto ágil y sus principios.

Os dejo la presentación:

La verdad que hubo una asistencia más que aceptable para un evento un lunes, además de ver un número de no-desarrolladores interesante :)

Y ya puestos, aprovecho a invitar a cualquier persona a que se venga este fin de semana al AOS 2012 para aprender o profundizar en temas relacionados con las metodologías ágiles. Seguro que nos lo pasamos bien :)

Como se hizo elDisparate.de, en BetaBeers Zaragoza

Este viernes estuvimos Mamen Pradel y yo hablando en el 2º BetaBeers Zaragoza. Presentamos como hicimos elDisparate.de durante el desafío AbreDatos 2011.

En la presentación explicamos rápidamente el proyecto, los principales retos y problemas que surgieron durante el fin de semana y dimos algunas pinceladas de como cada miembro del equipo ejecutó su trabajo.

Sólo teníamos 15 minutos, pero creo que fue suficiente para poder hacerse una idea de qué hicimos en márketing, diseño, video y programación; y las limitaciones del resultado no haber tenido datos abiertos.

En fin, os dejo aquí el clásico video:

Y un post del año pasado en el que expliqué un poco lo que fue la parte de obtención de datos y programación.

¿Cuánto vale una web?

De vez en cuando algún conocido-amigo que sabe que me dedico a algo que tiene que ver con esto del interné me hace esta temida pregunta… Está bien que gente de fuera del sector se empiece a interesar en introducirse e invertir parte de sus ahorros, pero algo mal hemos hecho como sector para que se crea que es barato montar algo en internet.

Tengamos en cuenta que, sobre todo para alguien que no conozca el sector, tendrá que contratar cosas relacionadas con: Diseño, programación, contenido y marketing. Y esperemos que conozca o, al menos, tenga contactos en el nicho al que se pretende dirigir.

Entonces, ¿Cuánto vale una web? Mi respuesta inicial, suele ser algo del estilo:

  • Ufff!!
  • Eeeeh…
  • Pfff!!
  • Mmmmm…

Y termino con algo como “A saber, si quieres algo en plan presencial y serio, desde 1000 y pico o 2000 euros. Si es más, hasta lo que tengas. Depende”. A veces la gente se asusta.

Lo mismo me pasa recibiendo algunas peticiones de presupuesto por email, que se limitan a “quiero una web”, “un ecommerce”, “una red social”… Pareciendo esperar que les mandes una propuesta detallada, hasta el último euro.
O por otro lado a gente pidiendo que les hagas un clon de alguna killer application; usando wordpress, joomla, ruby on rails… sin tener ni idea de lo que supone, y por 3000 euros, por supuesto. Y lo preocupante es que a veces llegan ese tipo de peticiones de gente que, aparentemente, llevan un tiempo moviéndose en eventos relacionados con el sector.

Seamos serios, también en internet si quieres algo que se parezca a un negocio, te puede costar lo mismo que montar un bar. Y sí, como a los bares también les pasa, si no entra nadie a consumir, tendrás que cerrar.

- ¿Y cuanto cuesta montar un bar?
- Depende.

¿Cuánto vale una web?

En fin, que si tu intención NO es hacer algo serio donde pueda ayudarte programando y/o colaborando en la conceptualización del producto, ahorremos nuestro tiempo y nos vemos en los bares.

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.

Open Space. Código como Expresión.

Este fin de semana estuve en Valencia en el open space convocado por agilismo.es, que llevaba por nombre Código como Expresión. La verdad que hacía tiempo que me apetecía asistir a un open space exclusivo sobre código, además de volver a visitar Valencia, conocer un poco la escena de desarrolladores y ver las oficinas de beCode (aún tengo pendiente pasar unos días con ellos).

Finalmente fui desde Zaragoza con Miguel Ángel Baztan y Fernando Pérez, 2 de los habituales del grupo Agile Aragón. En el evento también había gente llegada desde Castellón, Madrid, Segovia… incluso Pepe que se pegó una auténtica paliza de viajes desde Santiago de Compostela. Entre unos y otros, estuvimos algo más de 30 personas.

A niveles generales, me gustó bastante el evento, salvo un par de detalles/sensaciones que tuve durante algunos debates. He intentado hacer un pequeño resumen de cada sesión, pero por el formato del evento y mi torpeza, no he sido capaz.

Tablón. Open Space Código como Expresión

¿De qué se habló?, en las conversaciones y debates que estuve yo:

  • De la (poca) expresividad de las APIs REST, aunque para exponer e integrar sistemas diferentes, hasta el momento, es habitualmente la mejor alternativa.
  • Del spaghetti code relacionado con el uso de javascript asíncrono y algunas buenas prácticas para mejorar ese código.
  • De lenguajes y paradigmas de programación (orientado a objetos, funcional, procedimental); y como conocer varias opciones nos hacen enfocar soluciones desde más puntos de vista.
  • De la nomenclatura y expresividad en los tests. De frameworks de testing tipo BDD para diferentes lenguajes.
  • De identación y comentarios en el código.
  • De herramientas: IDEs, editores, tableros tipo kanban, software para hacer pair programming…

Os dejo las fotos que ha publicado Emma del evento.