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
}