Jugando con el sistema

Mi juego favorito

Hace algunos días leí “Gaming de system”, un articulo del blog Rands in Response, y me impacto la claridad de este párrafo:

Vemos el mundo como un complejo pero conocible diagrama de flujo donde hay una finita cantidad de entradas, lo que causa una similar finita cantidad de salidas. Este imposible diagrama nos da la reconfortante ilusión de control y entendimiento del caótico mundo, pero su existencia es un efecto secundario de una vida mirando, deduciendo, y construyendo sistemas. Es también porque nos gustan tanto los juegos – ellos son solamente sistemas mas pequeños – y mientras mas entiendas esta fascinacion con los juegos, mejor vas a ser manejándonos.

En espíritu, el hacker how to expresa las mismas ideas:

Es muy divertido ser un hacker, pero es la clase de diversión que requiere mucho esfuerzo. El esfuerzo requiere motivación. Los atletas triunfadores obtienen su motivación a partir de un tipo de placer físico que surge de trabajar su cuerpo, al forzarse a sí mismos más allá de sus propios límites físicos. De manera similar, para ser un hacker deberás sentir un estremecimiento de tipo primitivo cuando resuelves problemas, afinas tus habilidades y ejercitas tu inteligencia.

Cómo convertirse en hacker, El mundo está lleno de problemas fascinantes que esperan ser resueltos, Eric S. Raymond.

Las derivaciones de este principio son muy importantes, con el ambiente necesario, y planteándolo como un juego, nuestro trabajo de desarrollo se convierte en algo que nos atrapa y nos permite estar sin perder concentración o interés durante horas. ¿No nos pasa lo mismo cuando jugamos un MMORPG y estamos en la tarea de matar 1000 bichitos?

Este articulo es una de las lecturas recomendadas de la semana.

Google Public DNS es rápido

Como sabrán esta semana Google anuncio que abrió un DNS server publico.

Google Public DNS

Las ventajas de usar los servicios de Google las conocemos: Son gratis (la mayoría), tienen un uptime decente y lo mas interesante: son rápidos. Pero, como con todo anuncio de una compañía grande, surgieron en internet un por de dudas:

  • ¿Que información guarda Google sobre el uso que le de a su servidor de DNS?
  • ¿Porque no ayudaron a un proyecto como OpenDNS en lugar de crear su propio proyecto.
  • Google tiene control sobre tantas cosas ya (email, búsquedas, publicidad) que empieza a asustar un poco.

De hecho en sitios como cgisecurity salieron serias criticas, todas relacionadas con la cantidad que de información que le damos a Google, ya que esto les permite hacer un perfil sobre el uso que le damos a internet, aun en sitios que no tengan Google Adsense/Analytics.

La conclusión a la que llegaron algunos bloggers es que a Google le interesa que Internet sea mas rápida, ya que esto les permite imprimir mas banners y ganar mas plata.

Así que me decidí a investigar un poco que tan rápido es Google Public DNS.

Encontré varios artículos criticando la velocidad del servicio, diciendo que no era tan rápido. Pero no me convencían así que decidí hacer mis propias pruebas con nslookup y para mi sorpresa, al menos en mi ISP, Google Public DNS es 5 veces mas rápido que OpenDNS (el cual ya era el doble de mas rápido que mi ISP).

Después de usarlo un par de horas en mi desktop decidí pasar la red de mi casa a este servicio.

En mi caso es fácil, uso un router wifi Linksys WRT54GL que tengo flasheado con DD-WRT (un firmware opensource que me brinda opciones como conectarme a la VPN de la oficina) así que lo único que tuve que hacer fue ir a la opción de Commands, dentro del menú Administration, escribir el siguiente script:

echo “nameserver 8.8.8.8” > /tmp/resolv.dnsmasq
echo “nameserver 8.8.4.4” >> /tmp/resolv.dnsmasq
sleep 1
killall -HUP dnsmasq

Y clickear sobre “Save Firewall”.

Para no tener que reiniciar el router simplemente corrí esos comandos a traves de la interface SSH del mismo.

Conclusión: La velocidad se nota.

¿NetBSD rapido?

Yo tengo la costumbre de pensar así:

  • Desktop: Linux (Gentoo, Fedora, Ubuntu o Arch)
  • Server: Linux (Gentoo o Debian) o FreeBSD.

Pero este benchmark me lleno de sorpresas:

Benchmark de MySQL sobre el mismo hardware en distintos OS con SMP.

¿NetBSD con SMP mas rápido que el resto? Voy a tener que hacer algunas pruebas…

Namespaces

Hoy en el blog de Christopher Lenz salio un interesante esbozo de articulo sobre los namespaces y como la mayoría de los lenguajes de programación manejan mal ese concepto.

El ejemplo en C# es clarisimo:

using System;
using System.IO;

public class HelloWorld {
public static void Main(string[] args) {
Console.WriteLine("Hello, World!");
}
}

¿De donde sale Console? Y no queda en C#, hoy por hoy estoy trabajando mucho en C++:

#include <iostream>

int main()
{
std::cout << "Hola mundo!" << std::endl;
}

¿De donde sale std? Y lo que es peor, muchos include te pueden llenar a std de distintas cosas.

La parte que mas me gusto es del articulo es esta:

Resulta que los lenguajes en los que estoy actualmente interesado entienden esto (mas o menos) bien: Python, Erlang, Go, y (aunque no es un lenguaje) node.js.

+1 Python otra ves.

Como obtener el Window Handle (HWND) de una ventana en Windows y 4 momentos epicos de MSDN

La documentación de Microsoft para desarrolladores es mala. Esta es la conclusión a la que llegue después de ver que en MSDN no sabían unicode.

Pero lo que mas gracia me causa de MSDN es cuando documentan pequeños workarounds para las limitaciones de sus productos. Este es un ejemplo: How To Obtain a Console Window Handle (HWND).

Un HWND se utiliza para acceder a propiedades de la ventana, el problema es que en viejas versiones de la API de Windows no había un método para listar las ventanas de una aplicación que retornara el HWND de estas, así que Microsoft surgió con este hack:

  • Llame a GetConsoleTitle() para guardar el título de ventana de consola actual.
  • Llame a SetConsoleTitle() para cambiar el título de la consola a un título único.
  • Se actualizó Sleep(40) de llamada para garantizar el título de la ventana.
  • Llamada a FindWindow (NULL, uniquetitle) para obtener el objeto HWND esta llamada devuelve el HWND–o NULL si no se pudo realizar la operación.
  • Llamada SetConsoleTitle() con el valor se recupera del paso 1, para restaurar el título de ventana original.

Plop!

¿Soy al único que le parece un hack horrible?

Otros momentos épicos de MSDN:

¿Quien llamaria a una funcion bugfix?

PHP bugfix

¿Quien en su sano juicio llamaría a una función bugfix()? Solo en PHP, un lenguaje que ni siquiera sabe sumar.

Que pena que no se pueda linkear a contenido de Code Complete 2, ese libro es la mejor referencia sobre programación que existe.

Código que no se usa, se borra

Every Line Is A Child Of Mine

Comic via Geek and Poke.

Código que no se usa, se borra, para algo quedo en el SCM ya.

Lectura recomendada: Source Control How To.

Como configurar Buildbot

En el post anterior sobre django-yabe escribí sobre que es la Continuos Integration y como, de las distintas herramientas que existen, mi preferida para el caso era Buildbot.

Buildbot esta programado en Python y fue presentado en la PyCon 2003 de Estados Unidos. Desde entonces cada commit que se hace al SVN de Python dispara un proceso que compila el core del lenguaje y corre los tests cases de la stdlib en todos los sistemas operativos soportados. En caso de error notifica a quien halla hecho el commit y aparte lo publica en una pagina web.

Para poder realizar la compilación en varios sistemas operativos Buildbot se separa entre un servicio “Maestro” y muchas instancias “Esclavos”.

La instancia “Maestro” tiene varias responsabilidades:

  • Saber cuando hay que iniciar el proceso de build.
  • Avisarle a los nodos “Esclavos” que hay que realizar el build.
  • Darle a estos las instrucciones de como realizar el build.
  • Notificar del resultado del mismo.

En cambio las instancias “Esclavo” son mucho mas bobas: No llevan configuración sobre como compilar el código ni cuando deben hacerlo: Reciben notificaciones del maestro con esta información.

Este es un gráfico (tomado de la documentación oficial) que ilustra esta arquitectura:

Arquitectura de Buildbot

Instalación

La instalación es muy fácil, hay tres opciones:

Usando setuptools:

easy_install buildbot

Utilizando el package manager de nuestra distribución (Recomendada):

# Gentoo
emerge buildbot
# Debian y Ubuntu
apt-get install buildbot
# Arch
yaourt -S buildbot

Siguiendo la guiá de instalación en la documentación oficial.

En cualquiera de los tres casos es necesario tener instalado Twisted (el framework para aplicaciones de red asincronicas en Python) y Zope-Interface.

Al finalizar la instalación es necesario crear un directorio donde vallamos a crear las instancias maestro y esclavo del Buildbot:

bitfactory ~ # mkdir /var/lib/buildbot

Configuración del Maestro:

En el diagrama que mostraba la arquitectura vimos que el Maestro prácticamente hace todo, de hecho los esclavos no llevan configuración (solamente se les dice a que maestro deben conectarse).

Por esto es que primer configuramos la instancia del maestro: La instalación de buildbot nos dio un nuevo comando “buildbot” con una serie de opciones, la que nos interesa ahora es “create-master”:

bitfactory ~ # buildbot create-master /var/lib/buildbot/django-yabe-master
mkdir /var/lib/buildbot/django-yabe-master
chdir /var/lib/buildbot/django-yabe-master
creating master.cfg.sample
populating public_html/
creating Makefile.sample
buildmaster configured in /var/lib/buildbot/django-yabe-master

Si miramos /var/lib/buildbot/django-yabe-master veríamos algo así:

bitfactory ~ # ls -l /var/lib/buildbot/django-yabe-master
total 20
-rw-r--r-- 1 root root 434 Nov 20 16:21 Makefile.sample
-rw-r--r-- 1 root root 736 Nov 20 16:21 buildbot.tac
-rw------- 1 root root 7471 Nov 20 16:21 master.cfg.sample
drwxr-xr-x 2 root root 4096 Nov 20 16:21 public_html

El archivo Makefile es legacy de cuando Buildbot se iniciaba y paraba utilizando make. El archivo buildbot.tac es utilizado por Twisted para iniciar el servicio (no hace falta que lo editemos), y master.cfg.example es un archivo de configuración de ejemplo, yo no lo voy a utilizar porque es muy completo, y prefiero algo mas minimalista que se ajuste a lo que necesito, pero es bueno como referencia.

Así es que creamos un nuevo archivo master.cfg:

bitfactory ~ # vim /var/lib/buildbot/django-yabe-master/master.cfg

(Si no les gusta vim usen su editor de texto preferido para editarlo)

Y empezamos. La primer linea es medio confusa y merece aclaración:

c = BuildmasterConfig = {}

Ahí estamos creando un diccionario de Python accesible a través de dos nombres “BuildmasterConfig” y “c”. Cuando Buildbot lea la configuración va a buscar “BuildmasterConfig”, pero nosotros podemos ahorrar letras guardando los valores que queramos en “c”.

Siguiendo con la configuración:

from buildbot.buildslave import BuildSlave
c["slaves"] = [BuildSlave("Esclavo01", "sarasa")]
c["slavePortnum"] = 4484

Ahí definimos una lista con los esclavos y definimos el puerto donde el maestro va a esperar por conexiones de estos.

Lo que sigue es lograr que Buildbot se entere cuando hay una actualización en el repositorio:

from buildbot.changes.pb import PBChangeSource
c["change_source"] = PBChangeSource()

PBChangeSource utiliza el puerto que se declaro para escuchar respuestas de los esclavos para escuchar por “avisos” de que se cambio el código fuente. Estos avisos se pueden enviar con el comando buildbot sendchange, pero también se pueden configurar hooks en Mercurial o Subversion que avisen al Buildbot de cambios en el repositorio.

Con esa configuración Buildbot ya sabe cuando se cambio el código fuente, ahora tenemos que decirle cuando queremos que lo compile:

from buildbot.scheduler import Scheduler

c["schedulers"] = []
c["schedulers"].append(
Scheduler(
name="EveryCommit",
branch=None,
treeStableTimer=5,
builderNames=["Builder01"]
)
)

Un scheduler define cuando debe hacerse la compilación y quienes deben hacerla. En este caso en particular le estamos diciendo que el Scheduler llamado “EveryCommit” va a ver los cambios que se le hagan al trunk (branch=None), y cuando halla un cambio en el repositorio y no halla habido cambios en los últimos 5 segundos va a hacer que el builder “Builder01” haga un build.

Ya tenemos definidos quienes van a compilar (el esclavo que definimos), y cuando van a hacerlo (cuando le avisemos al maestro), ahora tenemos que definir que es lo que van a hacer.

from buildbot.process import factory
from buildbot.steps.source import Mercurial
from buildbot.steps.shell import ShellCommand

f1 = factory.BuildFactory()
f1.addStep(Mercurial, baseURL="/var/lib/hg/django-yabe/", defaultBranch="", mode="clobber")
f1.addStep(ShellCommand(command=["./manage.py", "test"]))

Ahí definimos un Factory: una serie de instrucciones sobre como compilar el código.

En el caso de un proyecto en Django es muy simple: Se baja el código y corre “./manage.py test”.

Para bajarse el código le decimos que tipo de repositorio es y los parámetros que necesita para hacer el checkout, hay una lista completa con los SCM y sus parámetros en la documentación de buildbot.

Sobre este primer paso hay un parámetro que merece una mención especial: mode=”clobber”

Mode no es un parámetro que utiliza el SCM, si no una instrucción que le damos a Buildbot para que reutilice o no los viejos checkouts. En este caso le estamos diciendo “clobber” que para Buildbot significa “cada ves que recibo la instrucción de hacer un build borro mi directorio de trabajo y hago un checkout limpio”.

El segundo paso se explica solo: Ejecuta el comando “./manage.py” con el parámetro “test”, si lleva mas de un parámetro seguimos agregando elementos a la lista command.

Cada Factory va dentro de un Builder:

b1 = {
"name": "Builder01",
"slavename": "Esclavo01",
"builddir": "django-yabe",
"factory": f1
}

c["builders"] = [b1]

Los Builders asocian Factory con esclavos. Esto es porque el Factory necesario para compilar nuestro código en Windows puede ser distinto que en Linux, pero por ahí hay algunos Builds que se tienen que hacer siempre igual en todas las plataformas. Eh ahí la flexibilidad que nos da la herramienta.

Lo único que nos falta es “como avisar” si algo sale mal:

c["status"] = []

from buildbot.status.html import WebStatus

c["status"].append(WebStatus(http_port=8101))

Listo, con eso le dijimos que levante un webserver en el puerto 8101 donde va a estar la información sobre los distintos builds.

Finalmente necesitamos algo de información sobre el proyecto:

c["projectName"] = "Django-yabe"
c["projectURL"] = "http://bitbucket.org/cuerty/django-yabe/"
c["buildbotURL"] = "http://cuerty.com:8101/"

Con todo esto tenemos configurado el buildmaster. Con el siguiente comando levantamos el mismo para probarlo:

bitfactory ~ # buildbot start /var/lib/buildbot/django-yabe-master/
/usr/lib64/python2.6/site-packages/twisted/internet/_sslverify.py:4: DeprecationWarning: the md5 module is deprecated; use hashlib instead
import itertools, md5
Following twistd.log until startup finished..
/usr/lib64/python2.6/site-packages/buildbot/scripts/logwatcher.py:48: PotentialZombieWarning: spawnProcess called, but the SIGCHLD handler is not installed. This probably means you have not yet called reactor.run, or called reactor.run(installSignalHandler=0). You will probably never see this process finish, and it may become a zombie process.
env=os.environ,
/usr/lib64/python2.6/site-packages/twisted/persisted/sob.py:12: DeprecationWarning: the md5 module is deprecated; use hashlib instead
import os, md5, sys
/usr/lib64/python2.6/site-packages/twisted/python/filepath.py:12: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import sha
/usr/lib64/python2.6/site-packages/twisted/mail/smtp.py:32: DeprecationWarning: the MimeWriter module is deprecated; use the email package instead
import MimeWriter, tempfile, rfc822
2009-11-20 17:16:58-0800 [-] Log opened.
2009-11-20 17:16:58-0800 [-] twistd 8.1.0 (/usr/bin/python2.6 2.6.2) starting up
2009-11-20 17:16:58-0800 [-] reactor class:
2009-11-20 17:16:58-0800 [-] Creating BuildMaster -- buildbot.version: 0.7.11p3
2009-11-20 17:16:58-0800 [-] loading configuration from /var/lib/buildbot/django-yabe-master/master.cfg
2009-11-20 17:16:58-0800 [-] adding new builder Builder01 for category None
2009-11-20 17:16:58-0800 [-] trying to load status pickle from /var/lib/buildbot/django-yabe-master/django-yabe/builder
2009-11-20 17:16:58-0800 [-] no saved status pickle, creating a new one
2009-11-20 17:16:58-0800 [-] added builder Builder01 in category None
2009-11-20 17:16:58-0800 [-] adding IStatusReceiver
2009-11-20 17:16:58-0800 [-] twisted.web.server.Site starting on 8101
2009-11-20 17:16:58-0800 [-] Starting factory
2009-11-20 17:16:58-0800 [-] WebStatus using (/var/lib/buildbot/django-yabe-master/public_html)
2009-11-20 17:16:58-0800 [-] adding 1 new schedulers, removed 0
2009-11-20 17:16:58-0800 [-] notifying downstream schedulers of changes
2009-11-20 17:16:58-0800 [-] adding 1 new changesources, removing 0
2009-11-20 17:16:58-0800 [-] twisted.spread.pb.PBServerFactory starting on 4484
2009-11-20 17:16:58-0800 [-] Starting factory
2009-11-20 17:16:58-0800 [-] BuildMaster listening on port tcp:4484
2009-11-20 17:16:58-0800 [-] configuration update started
2009-11-20 17:16:58-0800 [-] configuration update complete
The buildmaster appears to have (re)started correctly.

¡Errores! No hay que preocuparnos. La mayoría de lo que vemos es porque parte del código de Twisted imprime DeprecationWarning dado que no se actualizo para Python 2.6. Si vamos a http://127.0.0.1:8101 (o la dirección de donde este el buildbot) vemos una pagina que dice “Welcome to the Buildbot!” y nos da distintas opciones, una es el waterfall es quizá la mas interesante, donde vamos a poder ver si falla algo, o si todo esta perfecto.

Esto fue la configuración del maestro, ahora hagamos un esclavo que se conecte a este.

Configuración del Esclavo:

bitfactory ~ # buildbot create-slave /var/lib/buildbot/django-yabe-slave 127.0.0.1:4484 Esclavo01 sarasa
mkdir /var/lib/buildbot/django-yabe-slave
chdir /var/lib/buildbot/django-yabe-slave
creating Makefile.sample
mkdir /var/lib/buildbot/django-yabe-slave/info
Creating info/admin, you need to edit it appropriately
Creating info/host, you need to edit it appropriately
Please edit the files in /var/lib/buildbot/django-yabe-slave/info appropriately.
buildslave configured in /var/lib/buildbot/django-yabe-slave

Listo, tenemos el esclavo configurado. Los parámetros que le pasamos son para que sepa donde conectarse:

  • 127.0.0.1 es la IP del Buildmaster
  • 4484 es el puerto que configuramos en el Buildmaster para escuchar conexiones de los esclavos.
  • El usuario (Esclavo01) y password (sarasa) son los parámetros que le dimos al BuildSlave en el master.cfg.

Ahora puedo arrancar el buildslave:

bitfactory ~ # buildbot start /var/lib/buildbot/django-yabe-slave
/usr/lib64/python2.6/site-packages/twisted/internet/_sslverify.py:4: DeprecationWarning: the md5 module is deprecated; use hashlib instead
import itertools, md5
Following twistd.log until startup finished..
/usr/lib64/python2.6/site-packages/buildbot/scripts/logwatcher.py:48: PotentialZombieWarning: spawnProcess called, but the SIGCHLD handler is not installed. This probably means you have not yet called reactor.run, or called reactor.run(installSignalHandler=0). You will probably never see this process finish, and it may become a zombie process.
env=os.environ,
ERR: 'tail: cannot open `twistd.log' for reading: No such file or directory
'
/usr/lib64/python2.6/site-packages/twisted/persisted/sob.py:12: DeprecationWarning: the md5 module is deprecated; use hashlib instead
import os, md5, sys
/usr/lib64/python2.6/site-packages/twisted/python/filepath.py:12: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
import sha

The buildmaster took more than 10 seconds to start, so we were unable to
confirm that it started correctly. Please 'tail twistd.log' and look for a
line that says 'configuration update complete' to verify correct startup.

¡Mas errores! En principio son parecidos a los anteriores, pero al final no dice que “inicio el servicio”, si no que no sabe si inicio, y que deberíamos hacer un tail del log para ver si arranco bien, así que hacemos eso:

bitfactory ~ # tail /var/lib/buildbot/django-yabe-slave/twistd.log
2009-11-20 17:40:38-0800 [-] Log opened.
2009-11-20 17:40:38-0800 [-] twistd 8.1.0 (/usr/bin/python2.6 2.6.2) starting up
2009-11-20 17:40:38-0800 [-] reactor class:
2009-11-20 17:40:38-0800 [-] Starting factory
2009-11-20 17:40:38-0800 [Broker,client] message from master: attached
2009-11-20 17:40:38-0800 [Broker,client] SlaveBuilder.remote_print(Builder01): message from master: attached
2009-11-20 17:40:38-0800 [Broker,client] sending application-level keepalives every 600 seconds

Lo que nos importa aca es el mensaje “message from master: attached”, eso quiere decir que funciono. Si volvemos a ver el waterfall del buildmaster vamos a ver que el buildslave se conecto:

connect
Esclavo01

¡Excelente! Tenemos un buildbot configurado, ¿Ahora que? Lo integramos con Mercurial.

Configurando Mercurial

Yo tengo en /var/lib/hg/django-yabe un clone del repositorio del proyecto, voy a configurar para que cualquier commit a ese repositorio dispare un build en el buildbot.

bitfactory ~ # cd /var/lib/hg/django-yabe
bitfactory django-yabe # vim .hg/hgrc

(Devuelta, no usen vim si no quieren, elijan la herramienta que prefieran)

Agrego las siguientes lineas:

[hooks]
changegroup.buildbot = python:buildbot.changes.hgbuildbot.hook

[hgbuildbot]
master = 127.0.0.1:4484

Las primeras dos un hook que se activa ante un push o un commit a este repositorio. Las ultimas dos son la configuración para ese hook, ahí tenemos configurada la IP y el puerto del buildmaster.

Con eso basta para hacer que Mercurial se comunique con el buildbot.

El clone del repositorio que tengo en /var/lib/hg/django-yabe esta ahí para que lo acceda remotamente (utilizando el servidor web), solamente para simular una prueba voy a hacer un clone local del repositorio y probarlo:

bitfactory ~ # hg clone /var/lib/hg/django-yabe django_yabe

Pongo mi proyecto dentro del directorio django_yabe y “programo” hasta que “./manage.py test” corra sin problemas:

bitfactory django_yabe # ./manage.py test
Creating test database...

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK
Destroying test database...

Entonces agrego los archivos al repositorio:

bitfactory django_yabe # hg add __init__.py manage.py settings.py urls.py

Commiteo a mi repositorio local:

bitfactory django_yabe # hg commit

Y finalmente hago un push al repositorio en /var/lib/hg/django-yabe:

bitfactory django_yabe # hg push
pushing to /var/lib/hg/django-yabe
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 4 changes to 4 files
/usr/lib64/python2.6/site-packages/twisted/spread/pb.py:64: DeprecationWarning: the md5 module is deprecated; use hashlib instead
import md5
rev fe9688cab329fb43eb6169a541c663dac8c134b5 sent
change sent successfully

Las lineas interesantes son las siguientes:

rev fe9688cab329fb43eb6169a541c663dac8c134b5 sent
change sent successfully

Eso quiere decir que Mercurial le aviso al buildbot sobre el cambio, si voy a ver el Waterfall de nuevo:

django-yabe
last build build
successful

Se puede editar el css del buildmaster para hacer un poco mas amigable la vista a través del Waterfall, el mismo esta en /var/lib/buildbot/django-yabe-master/public_html/buildbot.css (En mi caso, reemplacen el path en el suyo).

Eso es todo, ya hay un build por cada push que hagamos al repositorio de Mercurial. Despues un detalle extra que se puede agregar al master.cfg es que aparte de notificar en el waterfall nos envie un reporte de los builds que fallan por email:

c["status"].append(
MailNotifier(
fromaddr="buildbot@cuerty.com",
extraRecipients=[“cuerty@gmail.com”],
sendToInterestedUsers=False,
mode="failing"
)
)

mode=”failing” significa que solamente me envie un email cuando el build falla.

Esto fue todo por ahora, espero que en lo próximo que empiece a trabajar ya sea el código del blog.

Buildbot: ¿Que?

Este es el segundo post sobre django-yabe, mi propio blog engine.

Primero un poco de background, a principio de año lei el libro “The productive programmer”.

The Productive Programmer

La verdad no es un gran libro, me deje llevar por un par de reviews y el glosario parecía interesante, pero resulto ser una colección de anécdotas (algunas muy buenas) y alguna que otra analogía que me ayudaron a entender mejor algunos conceptos, pero el resumen del libro se puede hacer en una palabra: automatizar.

Automatizar es genial: cualquier trabajo repetitivo es propenso a errores cuando lo realiza una persona, en cambio cuando lo hace una computadora no. Una computadora no se “olvida de un parámetro” o “se saltea un paso”, la computadora hace lo que le digamos y listo (Si sabemos decírselo es otro tema). Y dentro de la creación de software existen muchas tareas que se pueden hacer de forma automática, una de ellas es la integración continua (del ingles Continuous Integration):

Integración continua es una practica del desarrollo de software donde los miembros de un equipo integran su trabajo frecuentemente, normalmente cada persona integra su trabajo al menos una ve por día – dando múltiples integraciones por día. Cada una de estas integraciones es verificada por una construcción automática del software (incluyendo los tests) para detectar errores de integración tan rápido como sea posible. Muchos equipos encontraron que este acercamiento llevo a reducir significativamente los problemas de integración y permitió al equipo a desarrollar software de una forma mas rápida.

Martin Fowler, Continuous Integration

El primer paso para la integración continua se logra teniendo el código fuente de la aplicación en algún sistema de control de versiones (SCM por sus siglas en ingles). Particularmente a mi me gusta Mercurial por ser distribuido y simple, pero existen otras opciones como GIT y Subversion. El segundo paso es tener una construcción automática (automated build).

¿Que es un “automated build”? Del mismo texto de Fowler:

Hacer que el código fuente se convierta en un sistema funcionando puede ser un proceso complicado que involucre compilar, mover archivos, cargar esquemas en las bases de datos y mas. Pero, como la mayoría de las tareas en el desarrollo de software, puede ser automatizada y, como consecuencia de esto, debe ser automatizada. Pedirle a personas que escriban comandos o hagan clicks en ventanas de dialogo es una perdida de tiempo y un campo fértil para errores.

Así que entendemos a un automated build como tomar el código fuente y llevarlo a un sistema andando, en el que corremos las pruebas de forma automática. ¡Eso es perfectamente scripteable! Puede hacerse un hook para el SCM que elijamos que cuando recibe un commit se encargue de correr un script que compile el código (en este caso en particular estoy usando Python para el proyecto, así que no se compila, ¡pero puede correr los tests!), es tan fácil que me sorprende que nadie lo halla hecho ya… Hudson, CruiceControl o Bitten (de los creadores de Trac) son algunos de los que ya lo hicieron, y hay muchos mas en la pagina de Wikipedia al respecto. De hecho ayer anunciaron en Mozilla que van a empezar a utilizar Hudson para el desarrollo de la pagina de Addons de Firefox y Thunderbird.

Mi gusto particular en herramientas de CI es BuildBot. La primer razón por la que me gusta es porque esta hecho en Python, y se puede extender y configurar utilizando este lenguaje. Eso es una ventaja grande porque en el espíritu de ser DRY puedo hacer que configuraciones como “a quienes avisarles por email cuando falla un build” puedo, en lugar de escribirlas en la configuración, hacer que las lea dinamicamente de la base de datos de Redmine o Trac para el proyecto en cuestión. La segunda es que es muy completo, tiene distintas formas de notificarte, trabaja con muchos SCM (Subversion, Mercurial, GIT, ¡hasta CVS!) y tiene una documentación que es muy buena como referencia, aunque lamentablemente es pésima como introducción.

Así que el plan para el próximo post es configurar que cuando subo código al repositorio de Mercurial para django-yabe, BuildBot haga un build (Django tiene un framework de unittesting muy completo) y me avise por email si fallo.

YABE (Yet another blog engine) #1

Este es mi primer post sobre django-yabe, un proyecto que acabo de empezar.

¿Que es yabe? Yet Another Blog Engine. Es simplemente otro blog programado en Django.

Sinceramente no creo que haga falta otro blog engine, el problema es que es divertido programar uno, aparte de fácil, y que me  sirve como escusa para practicar algunas cosas en las que estoy medio oxidado, o que directamente no se (CSS y Javascript).

Los objetivos del proyecto son:

  • Que soporte la API de Blogger o Metaweblog (Para poder actualizarlo usando BloGTK).
  • Que soporte unicode “de punta a punta”.
  • Tener los posts y los comentarios en markdown.
  • Mantener las URLs de mis posts actuales después de migrar.

Pero si hiciera solamente eso seria aburrido:

  • El código va a estar disponible en bitbucket, así que voy a utilizar mercurial para el versionado.
  • Voy a aplicar TDD a todo lo que se pueda.
  • Desde un principio voy a tener un buildbot (y mostrar como lo configuro).
  • El código va a ser adaptativo y modular.

Si bien se que estoy reinventando la rueda, el ecosistema de Django es muy completo. Espero poder reutilizar muchas de las apps que ya existen, así como el mismo admin de Django.

La próxima entrega es sobre la configuración del repositorio y el buildbot.