method_missing en JavaScript

Os decía en la última entrada que podíamos solucionar en JavaScript el problema de metaprogramación de generar los comandos sobre la marcha, en el momento mismo de ser invocados y no antes. Os decía también que creía que me había quedado muy bien y en honor a la verdad debo decir que la idea la saqué del artículo The Command Pattern in JavaScript de Peter Michaux, ¡pero sólo me había leído el primer párrafo!, en especial la parte en la que dice:

In JavaScript, building our own dot operator function is one way to make indirect object function property calls and escape the built-in paradigm.

En JavaScript, construir nuestro propia función operador punto es una manera de hacer llamadas a función de manera indirecta y así escapar del paradigma por defecto.

Así que me puse a implementar este operador «punto» y cuando hube terminado me di cuenta de lo parecido con la solución propuesta por Peter.

Antes de implementar nada merece la pena entender cómo JavaScript busca los atributos de un objeto: para empezar, busca en el objeto y si ahí no está, busca en su cadena de prototipos que es otro objeto. Si ahí tampoco está, busca en la cadena de prototipos de la cadena de prototipos y así, hasta alcanzar cierto objeto cuya cadena de prototipos es null. Entonces devuelve undefined. En Firefox y en node.js, podemos consultar la cadena de prototipos de un objeto mediante el atributo especial __proto__,

La manera que tiene JavaScript de establecer la cadena de prototipos de un objeto es mediante el operador new y la propiedad prototype presente en todos los objetos. Cuando hacemos var o = new F(), aparte de construir el objeto mediante F(), hacemos que la cadena de prototipos del mismo apunte al atributo F.prototype.

Veamos una interacción en node.js* asumiendo que hemos cargado el siguiente listado:

function HTTP() {};
HTTP.prototype.get = function() {
    function makeGet(path) {
        return function(){
            return 'GET ' + this.url + '/' + path;
        };
    }

    Array.prototype.forEach.call(arguments, function(name){
        this[name] = makeGet(name);
    }, this);
};

function MyCompany() {
    this.url = 'mycompany.com';
};
MyCompany.prototype = new HTTP();
MyCompany.prototype.get('projects', 'employees', 'customers');

function YourCompany() {
    this.url = 'yourcompany.com';
}
YourCompany.prototype = new HTTP();
YourCompany.prototype.get('projects', 'employees');
> mine = new MyCompany();
{ url: 'mycompany.com' }
> mine.__proto__
{ projects: [Function],
employees: [Function],
customers: [Function] }
> mine.__proto__.__proto__
{ get: [Function] }
> mine.__proto__.__proto__.__proto__
{}
> mine.__proto__.__proto__.__proto__.__proto__
null

* Si probáis esto mismo en Firefox, podéis llevaros la sorpresa de que el prototipo de mine contenga el método get(). Realmente esto no es así, lo que ocurre es que la consola de Firefox nos muestra todos los atributos de un objeto: los suyos y los disponibles a través de la cadena de prototipos. Podéis consultar si get() pertenece al objeto y no a su cadena con el método hasOwnProperty() que devolverá false para ‘get’ y true para ‘employees’, por ejemplo.

Ahora sí, hemos repasado todos los conceptos que nos hacían falta y parece, por tanto, que no hay forma de interceptar o manipular cómo se recuperan los atributos de un objeto… ¿o sí?

method_missing

Como el título de la entrada indica, la idea consiste en emular el comportamiento de method_missing de Ruby. Cuando Ruby busca un método en un objeto, busca en el propio objeto; sino está ahí, en su clase y si tampoco está, sube por la jerarquía de clases. Si aun así no se encuentra, se llama al método especial method_missing() y si este tampoco está, se lanza la excepción NoMethodError.

Voy a extender el prototipo de Object para que incluya un método similar cuya implementación por defecto consiste precisamente en lanzar una excepción con el mensaje ‘NoMethodError’. Si ya tenías cargados los listados anteriores puedes copiar y pegar los siguientes y añadirás los métodos nuevos sobre la marcha: piénsalo bien, añades los métodos en tiempo de ejecución. ¡Esa es la gracia!

Object.prototype.method_missing = function() {
    throw 'NoMethodError';
};

Como adelantábamos al comienzo de la entrada, construiremos nuestro operador ‘punto’. Una implementación podría ser:

Object.prototype.dot = function(name) {
    var args = Array.prototype.slice.call(arguments, 1);
    var f = this[name];
    if (!f) {
        args.splice(0, 0, name);
        return this.method_missing.apply(this, args);
    } else {
        return f.apply(this, args);
    }
};

Es interesante hacer notar que realmente, esto no sustituye al operador punto dado que no recupera un atributo sino que lo invoca así que sólo debería usarse para realizar llamadas a métodos. El nombre ‘dot’ es apropiado para recordar qué estamos haciendo pero resultaría más correcto que se llamase ‘send’ como ocurre en el artículo de Peter.

Podemos cargar los ejemplos anteriores y probarlos en node.js:

> yours = new YourCompany();
{ url: 'yourcompany.com' }
> yours.employees();
'GET yourcompany.com/employees'
> yours.dot('employees');
'GET yourcompany.com/employees'
> yours.customers();
TypeError: Object #<HTTP> has no method 'customers'
> yours.dot('customers');
NoMethodError
> yours.url
'yourcompany.com'
> yours.dot('url')
TypeError: Object yourcompany.com has no method 'apply'

Ahora es fácil, sencillamente reimplementaremos method_missing() en el prototipo de HTTP para que, si llega a invocarse, cree un nuevo método mediante get() y lo invoque. Vale la pena recalcar que method_missing() se llama de tal manera que this hace referencia al objeto para el que se trató de invocar el método:

HTTP.prototype.method_missing = function(name) {
    this.constructor.prototype.get(name);
    return this.dot.apply(this, arguments);
};

Mediante this.constructor.prototype llegamos al prototipo del constructor que es precisamente el objeto al que apunta la cadena de prototipos del objeto. Contra lo que dicta el sentido común, esto no añade los nuevos métodos al prototipo

Ahora sí, tenemos una forma de crear métodos sobre la marcha sin preocuparnos de si existían antes o no y resuelto como lo haría Ruby. Además, las nuevas funciones extienden el prototipo de Object por lo que cualquier objeto dispondrá de ellas.

No discutiré más y con esto doy por terminadas las entradas sobre metaprogramación a la espera de vuestros comentarios y aportaciones. Espero que os haya sido tan entretenido como a mí.

Si os ha gustado la entrada, compartidla, por favor.

Edit 2012/04/09: He corregido el código de la función dot(), añadido al repositorio de github los ejemplos y he extendido la explicación sobre this.constructor.prototype dado que no era del todo correcta.

Además, creo que voy a hacer un último post con algo de discusión… no sé, ya veré.

Tenéis todo el código de los ejemplos en:
https://github.com/lodr/metaprogramming

Si os gusta la entrada, ¡comentadla y compartidla!

Metaprogramación en JavaScript

¡Hola de nuevo!

Me he pasado toda la tarde del martes preparando esta entrada, pensando que iba a ser coser y cantar y ha resultado ser un horror debido en parte ciertos aspectos de JavaScript que hacen las cosas pesadillescas. Eso sí, me ha dado para una segunda entrada la mar de interesante que veréis dentro de poco.

Como os adelantaba en la entrada de metaprogramación en Python, aquí va la adaptación de la misma a JavaScript. Si queréis profundizar sobre metaprogramación podéis leer la entrada anterior y echarle un vistazo al material que colgué allí. Como entonces, es necesario un nivel intermedio de conocimientos teniendo claro el modelo de datos de JavaScript. De hecho, me vais a permitir advertiros que si cosas como…

  1. La cadena de prototipos
  2. Las funciones constructoras
  3. El hecho de que el objeto this sea dependiente de contexto en el que es utilizado

…os suenan a chino, leais antes esta estupenda introducción a JavaScript en la Mozilla Development Network o no entederéis na de na.

Como ocurría en el ejemplo de Python, nuestro objetivo será el de crear una clase de utilidad para obtener diversos recursos de una compañía con sitio web mycopany.com que publica su contenido en /projects, /customers y /employees. Una primera aproximación podría ser:

function MyCompany() {
    this.url = 'mycompany.com';
};

MyCompany.prototype.projects = function() {
    return this._get('/projects');
}

MyCompany.prototype.employeecs = function() {
    return this._get('/employees');
}

MyCompany.prototype.customers = function() {
    return this._get('/customers');
}

MyCompany.prototype._get = function(path) {
    return 'GET ' + this.url + path;
}

Como veis, los métodos tienen todos prácticamente la misma forma, la técnica del copy & paste nos permite añadir cuantos métodos nuevos necesitemos pero todos sabemos quién carga el copy & paste. Como decía en la última entrada, el objetivo de la programación dinámica es:

DRY
Don’t Repeat Yourself

Así que vamos a ver cómo expresar lo mismo sin escribir tanto:

function MyCompany() {
    this.url = 'mycompany.com';
};

function makeGet(path) {
    return function(){
        return 'GET ' + this.url + '/' + path;
    };
}

['projects', 'employees', 'customers'].forEach(function(name){
    MyCompany.prototype[name] = makeGet(name);
});

La función makeGet devuelve una función con el comportamiento deseado, derivado del nombre del método. Si ahora a la compañía le diera por cambiar los recursos a /items/projects, /items/employees e /items/customers, bastaría modificar la función anónima devuelta por makeGet() para actualizar el comportamiento.

Lo que hemos hecho es sencillamente construir una lista con los nombres de los métodos que nos interesan, por cada uno de ellos llamamos a makeGet() para obtener la función adecuada y la añadimos al prototipo de la función MyCompany bajo el campo indicado por name para que quede a disposición de todas las instancias creadas por dicha función.

Podéis usar la shell d8 del motor V8 de JavaScript, node.js o, simplemente, Firebug en algún navegador moderno para probar los ejemplos:

d8> load("mycompany2.js")
d8> c = new MyCompany();
[object Object]
d8> c.employees()
GET mycompany.com/employees
d8> c.customers()
GET mycompany.com/customers
d8> c.projects()
GET mycompany.com/projects

Bien, esto es bueno, tenemos una forma de mantener el código y de extender la funcionalidad fácilmente pero la solución está demasiado acoplada al problema. Veamos cómo la herencia puede ayudarnos:

function HTTP() {};
HTTP.prototype.get = function() {
    function makeGet(path) {
        return function(){
            return 'GET ' + this.url + '/' + path;
        };
    }

    Array.prototype.forEach.call(arguments, function(name){
        this[name] = makeGet(name);
    }, this);
};

function MyCompany() {
    this.url = 'mycompany.com';
};
MyCompany.prototype = new HTTP();
MyCompany.prototype.get('projects', 'employees', 'customers');

function YourCompany() {
    this.url = 'yourcompany.com';
}
YourCompany.prototype = new HTTP();
YourCompany.prototype.get('projects', 'employees');

No muy claro, ¿verdad? ¡bienvenidos a JavaScript! Veamos qué ocurre aquí:

Lo primero que hemos hecho es crear una función constructora HTTP() cuyo prototipo contiene el método get(). Éste toma uno o más parámetros con los nombres de los métodos que se quieren crear y se encarga de llamar a makeGet() para construirlos. Para ello recorre los argumentos utilizando la variable especial arguments que parece un array. Si en vez de parecerlo, fuera un array, podríamos hacer arguments.forEach() y reproducir el comportamiento de hace un par de listados, pero como sólo lo parece, tendremos que aplicar explícitamente la función forEach() sobre arguments mediante call().

function f() {
    arguments.forEach(function(item) {
        return item;
    });
};
f();
TypeError: Object #<Object> has no method 'forEach'

Aclarado cómo recorrer los nombres de los métodos, veamos qué ocurre por cada uno de ellos. Lo que hacemos es añadir al objeto al que apuntará this, el campo indicado en name y como valor la función construída con makeGet(). ¿Qué vale exactamente this? Bueno, pues vale lo que hayamos indicado como tercer parámetro del método forEach() que es precisamente… this también. Sí, esto es así de cierto pero ahora en serio, ¿a qué apuntará this? Pues apuntará al objeto desde el que se llame la función get(), es decir, apuntará al prototipo de MyCompany y por tanto estaremos añadiendo los métodos al prototipo de MyCompany tal y como ocurría anteriormente.

Ahora todo está modularizado: la función HTTP() puede dejarse en un fihcero http.js mientras que las compañías pueden situarse en otro companies.js (así lo encontraréis en el repositorio de github). Ambas compañías heredan (a la manera de JavaScript) de HTTP() por lo que sus prototipos son instancias de HTTP(). Probemos el código:

d8> load("http.js")
d8> load("companies.js")
d8> mine = new MyCompany();
[object Object]
d8> yours = new YourCompany();
[object Object]
d8> mine.projects();
GET mycompany.com/projects
d8> mine.employees();
GET mycompany.com/employees
d8> mine.customers();
GET mycompany.com/customers
d8> yours.projects();
GET yourcompany.com/projects
d8> yours.employees();
GET yourcompany.com/employees
d8> yours.customers();
(d8):1: TypeError: Object #<HTTP> has no method 'customers'

Bien, esto se comporta tal y como lo hacía el ejemplo de Python y el de Ruby aunque debo admitirlo: JavaScript no es precisamente amigable a la hora de metaprogramar. De hecho, JavaScript no es un lenguaje amigable pero posee un modelo de datos tan regular y versátil que otorga a los desarrolladores toda la libertad que necesitan. Como dirían los ingleses:

JavaScript gives the developers enough rope to hang themselves with if they want to

Ahora bien, cerrábamos la entrada anterior sobre Python mostrando una técnica en la que proporcionábamos los métodos sobre la marcha. Ni siquiera eran creados explícitamente llamando a get() sino que la clase los proporcionaba conforme se le iban pidiendo. Os voy adelantando que en JavaScript esto puede hacerse, y creo que la técnica me ha quedado tan bien, que le voy a dedicar una entrada completa y a mostrároslo en breve.

Tenéis todo el código de los ejemplos en:
https://github.com/lodr/metaprogramming

Dudas y opiniones, ¡a los comentarios! Espero que haya sido entretenido.

Metaprogramación en Python

Hace unos días os contaba en la entrada sobre la Codemotion que una de las charlas más interesantes fue la propuesta por Sergio Gil sobre metaprogramación en Ruby en la que se nos introducía esta técnica de programación de forma amena y coloquial. Como os prometí, aquí tenéis la adaptación a Python y en breve tendréis también su versión enfocada en JavaScript.

La charla de Sergio en la Codemotion estaba etiquetada con nivel intermedio no por requerir conocimientos avanzados de Ruby (yo soy un absoluto novato en este lenguaje) sino por precisar de comprender conceptos avanzados de los lenguajes dinámicos. Quizá, lo más importante sea el modelo de datos.

Aunque en realidad la memoria es una secuencia de celdas direccionables que guardan datos o referencias a otras celdas (lenguages como C lo hacen patente), Ruby, JavaScript o Python no se ejecutan directamente sobre nuestra máquina sino sobre un intérprete o máquina virtual que recubre la máquina real. El intérprete ofrece una visión de la memoria «en alto nivel» al programador llena de variables, métodos, objetos, clases, módulos y otras entidades que, junto con la forma en la que tales entidades se relacionan entre sí, forman lo que se llama el modelo de datos del lenguaje. Lo interesante de los lenguajes dinámicos y por lo que se llaman así es porque en tiempo de ejecución, no se limitan a ofrecer una descripción estática del modelo sino que permiten manipularlo. Por ejemplo:

>>> class Simple(object):
...   '''Simply a class'''
...
>>> o = Simple()
>>> dir(o)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> o.__class__
<class '__main__.Simple'>
>>> o.__doc__
'Simply a class'
>>> o.__init__
<method-wrapper '__init__' of Simple object at 0x7f8a016fabd0>
>>> def f(): print 'Hello!'
...
>>> f
<function f at 0x7f8a016fc668>
>>> o.say_hello = f
>>> o.say_hello()
Hello!
>>> p = Simple()
>>> p.say_hello()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Simple' object has no attribute 'say_hello'

Fijaos en la interacción anterior, la consola de Python proporciona un entorno de ejecución. En él creamos una clase nueva, Simple, e instanciamos un objeto o, mostramos sus atributos con dir, comprobamos el tipo de algunos de ellos y a continuación creamos una nueva función que asignamos sólo al objeto o. El objeto p no tiene esta función por lo que el intérprete falla al intentar encontrarla.

Ahora que tenemos la idea intuitiva de por qué Python es un lenguaje dinámico, indaguemos en la metaprogramación al fin. Metaprogramación es una palabra que se asocia comunmente a la idea de «programas que escriben programas»; yo prefiero concebir la metaprogramación como una técnica para automatizar la descripción de modelos. ¿Suena muy técnico? Veámoslo con un ejemplo:

Supongamos que queremos una clase que nos permita obtener información de una hipotética compañía mycompany.com Tal sitio web expone información de sus proyectos, empleados, compradores, etc a traves de las páginas /projects, /employees, /customers… Una posible implementación es la siguiente:

class MyCompany(object):
    url = 'mycompany.com'

    def projects(self):
        return self._get('/projects')

    def employees(self):
        return self._get('/employees')

    def customers(self):
        return self._get('/customers')

    def _get(self, url):
        return 'GET ' + self.url + url

Evidentemente, en un entorno real, la función _get() debería hacer algo más que devolver una cadena pero, para nuestros propósitos, nos sirve tal y como está.

La clase MyCompany es bastante clara y expresiva. Si quisiera acceder ahora a /products partiría de uno de los métodos existentes y cambiaría su nombre y la ruta de la URL. Cuando la clase tenga 15 métodos, y a la compañía le de por mover sus páginas a /items/projects, /items/employees, /items/customers… pues tendremos que revisar los 15 métodos. Las desventajas son evidentes pero, ¿podemos hacerlo mejor? Por supuesto:

class MyCompany(object):
    url = 'mycompany.com'

def make_get(path):
    def actual_get(self):
        return 'GET ' + self.url + '/' + path

    return actual_get

for name in ['projects', 'employees', 'customers']:
    setattr(MyCompany, name, make_get(name))

Ahora, añadir un nuevo método es tan sencillo como añadirlo a la lista de métodos, y modificar la funcionalidad es tan fácil como cambiar el método actual_get().

Como yo no tengo una limitación de 45 minutos (como ocurría en la presentación), podemos entrar en detalle: lo único que estamos haciendo es usar setattr() para añadir atributos a un objeto (sí, en Python las clases son objetos; en Python TODO son objetos). El primer parámetro es el objeto al que queremos añadir el atributo, el segundo es el nombre del atributo y el tercero es el valor del atributo. El valor lo produce la función make_get() que devuelve otra función actual_get() con el comportamiento deseado.

Ahora podemos hacer:

>>> company = MyCompany()
>>> company.projects()
'GET mycompany.com/projects'
>>> company.employees()
'GET mycompany.com/employees'
>>> company.customers()
'GET mycompany.com/customers'

De nuevo parafraseando a Sergio en su charla de la Codemotion, al final todo se reduce a:

DRY
D
on’t Repeat Yourself

El segundo listado resulta muy compacto pero adolece de algunos problemas de diseño: demasiado acoplamiento. Si ahora quiero crear otra compañía, pongamos yourcompany.com, ¿qué hago? ¿Otro módulo con casi el mismo código? ¡No! De nuevo ¡DRY!

Vamos a mejorar el diseño:

class HTTP(object):
    @classmethod
    def get(cls, *names):
        def make_get(path):
            def actual_get(self):
                return 'GET ' + self.url + '/' + path

            return actual_get

        for name in names:
            setattr(cls, name, make_get(name))

class MyCompany(HTTP):
    url = 'mycompany.com'
MyCompany.get('projects', 'employees', 'customers')

class YourCompany(HTTP):
    url = 'yourcompany.com'
YourCompany.get('projects', 'employees')

Ahora podemos coger la clase HTTP y meterla en un módulo aparte (por ejemplo http.py). Nuestras compañías pueden estar en otro módulo (tal vez companies.py) e importar y heredar de HTTP para a continuación llamar al método de clase get() que creará los métodos indicados.

El método de clase get() tiene algo de chicha: está decorado con el decorador classmethod que hace que, al ser llamado, reciba como primer parámetro la clase donde ha sido definido. Luego recibe una lista con los argumentos pasados a la función, en este caso, los nombres de los métodos. Por cada uno de ellos, crea una nueva función de la forma que vimos anteriormente.

El siguiente listado prueba las clases MyCompany y YourCompany:

>>> mine = MyCompany()
>>> mine.projects()
'GET mycompany.com/projects'
>>> mine.customers()
'GET mycompany.com/customers'
>>> yours = YourCompany()
>>> yours.projects()
'GET yourcompany.com/projects'
>>> yours.customers()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'YourCompany' object has no attribute 'customers'

Comprender el modelo de datos de Python resulta de vital importancia para explotar la metaprogramación, baste por el momento comprender cómo Python recupera un attributo de un objeto. Cuando en Python escribimos objeto.atributo, internamente se llama a la función __getattribute__ con el objeto y el nombre del atributo como parámetros. La implementación por defecto mira (no preguntéis cómo, que no acabamos nunca) en el objeto por un atributo con ese nombre y si no lo encuentra trata de encontrarlo en la clase del objeto. Si ahí tampoco está, mira en las superclases y de ahí hacia arriba por la jerarquía de clases. En caso de no encontrarlo se llama al método __getattr__ de la instancia el cual, por defecto, lanza una excepción del tipo AttributeError.

¿Y qué queremos decir con esto? Pues que podemos explotar más la metaprogramación hasta el punto de ni siquiera tener que crear los métodos de la clase explícitamente. La generación en sí puede ser dinámica, creados conforme se necesitan. Veamos cómo:

class HTTP(object):
    @classmethod
    def get(cls, *names):
        def make_get(path):
            def actual_get(self):
                return 'GET ' + self.url + '/' + path

            return actual_get

        for name in names:
            setattr(cls, name, make_get(name))

    def __getattr__(self, name):
        HTTP.get(name)
        return getattr(self, name)

class MyCompany(HTTP):
    url = 'mycompany.com'
MyCompany.get('projects', 'employees', 'customers')

class YourCompany(HTTP):
    url = 'yourcompany.com'
YourCompany.get('projects', 'employees')

Hemos reescrito __getattr__() para que en caso de que el método no exista, le pidamos a la clase que lo genere por nosotros. Luego lo recuperamos y devolvemos.

La misma interacción que antes fallaba con la excepción AttributeError ahora no fracasará:

>>> mine = MyCompany()
>>> mine.projects()
'GET mycompany.com/projects'
>>> mine.customers()
'GET mycompany.com/customers'
>>> yours = YourCompany()
>>> yours.projects()
'GET yourcompany.com/projects'
>>> yours.customers()
'GET yourcompany.com/customers'

¿Bastante impresionante, no? Ahora bien, ¿cuándo debemos usar metaprogramación? La respuesta no es sencilla pero yo tiraría por «siempre que sea expresivo y la alternativa sea peor» o quizá «siempre que se ajuste a la naturaleza del problema» La metaprogramación tiene mucho que ver con el diseño de interfaces, la interfaz de una utilidad tiene que ser agradable para sus usuarios pero mantenerla no puede resultar en una pesadilla para el programador: debemos llegar a un acuerdo entre usabilidad y mantenimiento.

La metaprogramación no es más que programación así que no pierdas las buenas costumbres. Documenta tus métodos y explícate qué estás haciendo en todo momento. Así, cuando recuperes tu proyecto 3 meses más tarde no invertiras horas y horas tratando de ver qué escribiste.

Vale la pena terminar con una comparación con Ruby. ¿Es cómodo metaprogramar en Python? En mi opinión: no tanto como en Ruby. Ruby está más orientado a manipular fragmentos de código, el hecho de que lo que existe entre un bloque do – end sea un dato simplifica considerablemente las cosas. En Python, el modelo de datos es poco regular y difícil con muchos casos y excepciones. Además, los decoradores, el anidamientos de funciones, los nombres especiales de función y el modelo de acceso a los atributos contribuyen a disminuir la claridad y limpieza de la implementación.

En la próxima entrada, exploraremos exactamente el mismo ejemplo pero en JavaScript. Será una entrada mucho más corta dado que no será necesaria la introducción ni las explicaciones previas, pero os aseguro que volverá a ser útil e interesante.

Tenéis todo el código de los ejemplos en:
https://github.com/lodr/metaprogramming

Codemotion Madrid 2012

El sábado pasado asistí a la Codemotion que se celebró en la Escuela de Ingeniería Informática de la Universidad Politécnica, allá a 12 minutos en coche y hora y media en tren (mal para mí que no tengo carné).

Hay que decir que no pude asistir a todo el evento: de los ocho ciclos de conferencia que se presentaban, estuve en 4, con tiempo para socializar un poco, pasarme a visitar a los patrocinadores y celebrar el día del padre (dado que el pasado fin de semana no pudo ser).

Lo peor del evento fue el espacio o el exceso de gente, según se mire. En cuanto al espacio elegido, demasiado lejos de todas partes: si bien contaba con línea directa a Sol por línea 1 y en cercanías, los autobuses universitarios no estaban en funcionamiento dado que era Sábado. Pero esto es un problema menor.

El mayor de los problemas radicaba en la abrumadora cantidad de personas que éramos en un espacio muy reducido, termómetro también del éxito del evento y que reflejaba la buena acogida de la iniciativa por parte de la comunidad española.  Pero el espacio era un problema: charlas abarrotadas de personas que se salían del propio aula, pasillos estrechos para los patrocinadores que formaban cuellos de botella entre las salas de conferencias y un circuito reducido (dado que la mayoría de los pasillos y salidas ajenas al evento permanecían cerradas) que impedía la libre movilidad de los asistentes.

Las charlas a las que sí pude asistir fueron Metaprogramación en Ruby, de Sergio Gil; Todo Microsoft Kinect en 45 minutos, de Vicenç García y Bruno Capuano; Template animation & OO CSS: Be nice with your Web Designer de Enrique Amodeo y Boot2Gecko, la Web es la plataforma de Rubén Martín y Guillermo López.

Con diferencia, la mejor de las charlas fue la de Sergio Gil por utilidad, claridad y simpatía. Mención especial tienen por mi parte los voluntarios de la comunidad Mozilla, desarrolladora de Boot2Gecko, Rubén Martín y Guillermo López que presentaron muy bien aún cuando el portátil los dejó tirados en más de una ocasión.

A nivel de utilidad, obtuve algunas ideas interesantes que compartiré con vosotros durante esta semana: adaptaré la charla de metaprogramación para Ruby a Python y JavaScript y subiré un plug-in para jQuery y Django inspirado en la charla de Enrique Amodeo sobre Template Animation. Hablaré también sobre lo desafortunado del nombre cuando llegue el momento.

Eché de menos quizá más tiempo para socializar, quizá alguna actividad / juego, grupos de interés, debates o sencillamente, más tiempo en los descansos. Por los patrocinadores, ninguna queja, se podía hablar con ellos y, al menos a mí, me informaron correctamente de todo, intercambiamos tarjetas y currículos y en general fue una experiencia de lo más provechosa.

Particularmente creo que eventos así valen la pena. La próxima vez espero que dure un par de días en algún lugar más amplio y quizá más talleres o charlas de nivel avanzado… Como sea, espero que sea pronto.