viernes, 18 de diciembre de 2009

Coloreando Python en blogs y html

Algo que me hizo renegar bastante hace poco, fueron mis ganas de que el código de ejemplo en python que posteaba en el blog tuviese coloreo de sintaxis.

Pasé por varias opciones, y por lejos esta fue la que me resultó más práctica para usar en blogspot o cualquier otro sistema de blogs que permita editar el html del blog. Su practicidad se debe sobre todo a que no necesito hostear archivos extras en ningún lado.

Armé un instructivo bastante sencillo de cómo lograrlo:


1) Instalar Pygments

Vamos a generar un html localmente a partir de un archivo de python, usando el paquete Pygments. Para instalarlo, podemos hacerlo con easy_install (paquete "pygments"), buscándolo y bajándolo de PyPi, o bajando sus fuentes (más info aquí):


2) Generar el HTML con Pygments

Teniendo instalado Pygments, podemos usarlo para generar un HTML coloreado a partir de un archivo de código python. No voy a explicar todas las alternativas, solo la que a mí me resulta práctica (para más info, vean aquí):


$ pygmentize -O noclasses -o pagina.html codigo.py 

Nos copiamos el contenido del html generado, lo ponemos dentro de nuestro post, y voila! Python coloreado en nuestro blog :D. Les dejo un ejemplito:



import antigravity 

print "wee, python!"

class Foo:
"""Foo fighters"""
def __init__(self):
self.bar = "donde sirven cerveza"

def baz(self):
"""Vamos al bazaar"""
print self.bar


Espero que les haya sido útil!

jueves, 17 de diciembre de 2009

De Windows Mobile a Android

Desde hace años que soy usuario de celulares con Windows Mobile. Los conocí por el trabajo (hacemos aplicaciones para ese tipo de aparatos), y rápidamente me entusiasmaron.

Lo que más me atraía era la idea de tener una computadora en el bolsillo. Y tengo que admitir que en gran parte es así con Windows Mobile: las aplicaciones, la manera de administrar los archivos, la interface, etc., siempre se sentía cierta similitud con el mundo desktop. Y me gustaba.

Pero a la mayoría de los usuarios comunes eso mismo les complicaba la existencia: no esperan eso de un celular, sino que buscan que sea mucho más simple y práctico que una pc.

Y se ve que esto es algo que quienes diseñaron Android conocían muy bien.

Hace poco más de un mes, decidí mudarme al mundo Android: me compré una HTC G1.

Al empezar a usarla el cambio se sintió. Era evidente que el objetivo del sistema operativo no era replicar una PC en el bolsillo, sino otra cosa diferente. Y por eso los primeros días me sentí "raro", como incómodo.

Pero esa sensación duró poco más de un día. Hoy ya no puedo imaginarme volver a Windows Mobile.

Comento un poco las principales cosas que me hacen pensar así, desde el punto de vista de usuario (no de desarrollador para la plataforma):

1) Verdaderamente táctil

Todo en Android está pensado para usar con los dedos. De hecho, la G1 ni siquiera trae stylus! (el "palito", jeje). Y no para dedos de aguja, todo lo contrario: tenés que usar las cosas con el dedo gordo, es la manera más cómoda y a la que mejor responde.

En Windows Mobile la interface del sistema operativo ni por casualidad es usable con los dedos. Hay interfaces de terceros más adaptadas para ello, como PointUI, o Touch Flo 3D, pero ninguna se acerca al nivel de usabilidad de Android. Siempre terminás sacando el stylus para realizar algunas tareas.

Parecería un tema superficial, pero de verdad es un aspecto central en un dispositivo móvil, es determinante en su facilidad de uso. No se puede, por ejemplo, caminar por la vereda mientras se está escribiendo con un palito sobre una pantalla de 3 pulgadas (al menos no sin correr el riesgo de chocarse un poste). Pero sí es posible hacerlo con una interfaz como la de Android, escribiendo con los dedos como lo hacemos con cualquier otro celular no táctil.

2) Practicidad:

Aparte del aspecto táctil, la otra gran ventaja de la interface de Android es su facilidad de uso, su practicidad.

Las funciones casi siempre están visibles, fácilmente accesibles. En comparación a Windows Mobile se usan poco los menúes y se aprovecha más la pantalla para mostrar botones grandes (y ni hablar que más lindos gráficamente :D).

Y donde hay menúes, también son grandes y con íconos (en Windows Mobile casi siempre son listas de textos a las que es difícil acertar si no es con el stylus).

Y la configuración de la mayoría de las cosas, en mi opinión, resulta bastante más sencilla. No hay opciones que uno vea y piense "y esto qué hará??", como pasaba en Windows Mobile (ejemplos: las opciones de "autenticación PAP o cHAP" para la línea de celular, o el tilde de "Funcionalidad de Red Avanzada" en la configuración de la conexión usb, ...).

3) Velocidad:

Windows Mobile pone tanto énfasis en la velocidad como el resto de los productos de Microsoft (Windows vista, Visual Studio, ...). Yo me había acostumbrado a esperar para cosas básicas, como abrir los mensajes.

Android no será tan rápido como iPhone, pero está bien por encima de Windows Mobile. Y eso es algo que se siente mucho en el uso diario del aparato.

4) Organización de la información:

En Windows Mobile estaba muy acostumbrado a manejar mis archivos en estructuras de carpetas, de igual manera que en mi pc de escritorio.

Cuando me mudé a Android me di cuenta de que, por más que podía hacerlo con aplicaciones de terceros, Android en sí mismo no me mostraba en ninguna parte un árbol de carpetas y archivos.

Primero me hizo sentir que de alguna forma me "restringía". Pero después entendí que es mucho más cómoda la manera en que Android me presenta la información: una idea más cercana a la de bibliotecas.

Para abrir una foto no tengo que navegar por carpetas hasta el lugar donde se haya guardado. En su lugar, entro a la aplicación Galería, que me presenta todo lo que es multimedia agrupado por tipos de elementos: videos, fotos, fotos sacadas con la cámara, etc. No necesito recordar dónde estaba almacenada :D.

(sí, tengo que admitir que la galería de HTC Touch Flo 3D era así. Pero eso es algo que no es parte de Windows Mobile, es una aplicación de HTC, un tercero).

5) Integración con herramientas web

Me encanta que todo lo que tengo en el celular esté perfectamente sincronizado con mi cuenta de correo en internet: contactos, calendario y correo.

(no tengamos en cuenta a Exchange, estamos hablando de usuarios finales)

Ya sé, en Windows Mobile también se puede sincronizar todo. Pero en Windows Mobile si quería mantener esas tres cosas tenía que tener el correo y los contactos sincronizados con Hotmail, y el calendario sincronizado con MyPhone.

Recordemos que Hotmail también tiene calendario... ¿será que en Microsoft creen que las personas viven dos vidas en simultaneo?, una planificada con el calendario de Hotmail, y otra planificada con el calendario del Celular (sincronizado con MyPhone).

En lugar de desarrollar MyPhone, ¿por qué simplemente no permiten sincronizar el calendario de Windows Mobile con el de Hotmail?

Conclusión

Esas son las cosas que como usuario me transformaron en partidario de Android. No hablo como desarrollador, por más que lo soy, sino como usuario diario de los celulares.

Ustedes que opinan?

jueves, 10 de diciembre de 2009

Frameworks web y lenguajes

Hace poco en la lista de correos de Ruby Argentina, alguien dijo una frase que me quedó picando en la mente: "Usar rails es la peor forma de aprender ruby :)".
Para quien no los conoce, Ruby es un lenguaje de programación muy interesante, y Ruby on Rails (o directamente Rails) es un framework para hacer aplicaciones web con Ruby (fué el que disparó a la fama al lenguaje).
(mas info sobre ruby aquí, y sobre Rails aquí)

No voy a debatir sobre las opiniones que salieron en la lista, y no voy a detenerme en qué habrá querido expresar la persona que lo dijo. Solo voy a comentar las cosas que a mí me hizo pensar.
Voy a generalizar un poco más, y "meter en la bolsa" a Django, un framework para aplicaciones web con Python bastante similar a Rails (info de Django aquí).

Me detengo solo en esos dos porque son los que usé para desarrollos reales, a los demás los conozco de vista/probar solamente.

La fiebre de la web (casi como la del oro)

La web es un terreno del desarrollo de software que está avanzando a velocidad imparable, no hace falta ser muy observador para darse cuenta (Google Docs, cloud computing, y muchas otras palabras de moda). Y por ello puede resultar tentador para alguien que nunca desarrolló web, pasarse a ese nuevo mundo de moda y con futuro.
Pero cuando la gente se pasa a una nueva tecnología esperando obtener beneficios de ella, y no solo por "amor al arte", generalmente espera resultados rápidos. Pocos estarían dispuestos a esperar un año hasta tener conocimientos como para poder hacer su primer sitio web.

Ahí es donde estos frameworks se ponen tentadores: una de las principales ventajas que ofrecen es el desarrollo rápido de aplicaciones. Rails tiene su famoso video de "un blog en 15 minutos", por ejemplo.
Y es verdad, comparados con otras tecnologías agilizan enormemente el desarrollo web. Traen resueltas un montón de problemáticas comunes. La aplicación de administración de Django es un ejemplo excelente: toda la administración del sitio ya resuelta "de fábrica" (autenticación, usuarios, permisos, ABMs de entidades, etc.).

Los caminos se separan

En este punto es donde nos encontramos con dos situaciones muy diferentes:

1) El desarrollador desktop de Python/Ruby, que aprovechando su conocimiento del lenguaje elije un framework web del mismo.

2) El desarrollador de otros lenguajes, que atraído por las ventajas de alguno de estos frameworks decide comenzar a desarrollar con él, lo que le implicará aprender también el nuevo lenguaje.

No hace falta decir que el camino para el desarrollador de la situación 1) es bastante simple. Además tengamos en cuenta que estos frameworks suelen seguir muy al pie de la letra la filosofía del lenguaje, por lo que se sentirá "como en casa".

Lo que preocupa es el camino del segundo desarrollador.
¿Por qué?

Aprendiendo a correr sin saber caminar

En primer lugar, estos frameworks asumen que uno posee conocimientos del lenguaje. Un tutorial de Django no va a explicar el manejo de listas de Python, por ejemplo.
Entonces va a ser una situación bastante normal la de encontrarse con partes de los tutoriales que no se lleguen a comprender del todo, porque al ver el código no "salta a la vista" tan fácil lo que está haciendo.
Y para empeorar la situación, muchas veces esto va a llevar a escribir código "porque estaba así en el tutorial", pero sin tener la menor idea de lo que hace. No es necesario mencionar los problemas de mantenimiento que una aplicación así puede tener...
Esa razón sola debería bastar para tener que aprender primero el lenguaje.

Y aunque logre entender dicho código, seguramente no va a conocer muchísimas cosas más que podría aprovechar del lenguaje para el desarrollo de su aplicación. Sus herramientas se van a limitar a lo que se muestra normalmente con el framework, probablemente desconociendo muchas otras facilidades que el lenguaje le brinda.
(mi post anterior habla sobre algo relacionado)

Como antes recordamos, estos frameworks también suelen seguir muy bien la filosofía de sus lenguajes respectivos. Por ende, alguien que no conoce esa filosofía tendrá un trabajo extra para "acomodarse" a la nueva manera de hacer las cosas.

Además, los frameworks toman muchas decisiones de diseño, y adoptan convenciones (muy fuertes sobre todo en Rails), que son buenas para el framework pero no necesariamente son buenas para otros entornos. El problema es que el programador que aprende el lenguaje desde dichas convenciones, seguramente asumirá que no existen otras maneras de hacer las cosas, o que si existen no son las correctas.
Este "vicio" no va a tener consecuencias directas en su etapa de desarrollador sobre ese framework, pero sí las va a tener cuando intente probar otros frameworks del mismo lenguaje, ya que no necesariamente el que aprendió es el mejor framework para todos los casos.

Conclusión

Por estas razones es que opino que antes de aprender uno de estos frameworks, es muy, muy saludable dedicar un tiempo a aprender el lenguaje a secas, sin web, como vino al mundo :D

De hecho, pude comprobarlo en mi experiencia personal:
- Intenté aprender Ruby on Rails directamente, sin conocer Ruby. Pude, pero seguramente no llegué a ver todo lo que es Ruby y a comprenderlo bien. Y me solía pasar de tener la sensación de que no sabía cómo funcionaban las cosas.
- Con Python me tomé el tiempo para aprender bien el lenguaje, y recién después comencé con Django. El pasaje fue natural, y me siento con mucho más control de lo que hago. Siento que lo entiendo y que puedo "sacarle bien el jugo".

¿Que opinan?

miércoles, 9 de diciembre de 2009

Python: Dinamismo aplicado

Me suele pasar que cuando comento alguna característica superior de un lenguaje a otra persona que no lo conoce, la persona reaccione con frases del estilo "y eso cuando lo vas a usar en la realidad?", o "todo muy lindo, pero eso es para la teoría, en la práctica no sirve", etc...

Es normal, ya que al no estar acostumbrado a pensar de una manera distinta, no va a ver tan fácilmente la utilidad de dicha característica.
Estas no son grandes iluminaciones mías, jeje, son ideas que Paul Graham explicó muy bien en este artículo (recomendado).

Pero lo que sí puedo aportar desde mi humilde experiencia, es un buen ejemplo de cómo una característica puede sonar "muy rara", pero cuando es bien aprovechada, puede resultar "muy práctica".

Puede haber cientos de cosas equivocadas en lo que estoy por decir, estaría bueno que me hagan conocer al menos algunas :D

La característica "extraña"

Ahora es donde hace su entrada la característica "extraña" que tiene Python. Va a sonar "extraña" para quien no esté acostumbrado a cosas por el estilo, se entiende.

La característica es la función getattr: llamándola podemos obtener un atributo o método de un objeto.
Este ejemplo es bien ilustrativo:



yo = "juan pedro"
met = getattr(yo, "upper")
met() #esto nos devuelve "JUAN PEDRO"


Para explicarlo un poquito:
Con getattr(yo, "upper") obtuvimos el método upper del objeto yo.
Atención! Dije "obtuvimos el método", no "el resultado de llamar al método". Son cosas bien diferentes.
Obtener el método es como darle un nuevo nombre con el cual después podemos llamarlo, como hicimos en "met()". Met es un nuevo nombre para llamar a ese método en particular, el método upper de yo.

Es destacable que usar una variable (met en este caso) es algo que hice solo para que sea más entendible a primera vista. Pero lo anterior perfectamente puede escribirse como:



yo = "juan pedro"
getattr(yo, "upper")() #esto nos devuelve "JUAN PEDRO"


No guardamos el método en una variable, simplemente lo llamamos en ese momento. Lo obtenemos y lo llamamos en una misma línea.


El problema

Tenemos una clase Foo. Esta clase Foo define 5 acciones diferentes, que se representan con 5 métodos: accion1, accion2, accion3, accion4, accion5.
La complicación se da en el hecho de que cada una de estas acciones es realizada comunicándose con un servicio, y hay 4 servicios completamente diferentes en los cuales se pueden realizar las acciones: A, B, C y D.
Ejemplo:
"Hacer acción 1 en el servicio B"
"Hacer acción 3 en el servicio D"
etc...

En la implementación, cada servicio cambia por completo el código que se tiene que ejecutar para realizar una acción. Es decir, el código de la acción 1 para el servicio A es completamente diferente al código de la acción 1 para el servicio B, etc.

La clase Foo necesita recibir el nombre del servicio como un parámetro de cada acción, para saber en qué servicio ejecutarla. De forma que después se utilice de la siguiente manera:



miFoo = Foo() #creamos un nuevo objeto foo
miFoo.accion1("A") #llamamos a la accion 1 en el servicio A
miFoo.accion1("C") #llamamos a la accion 1 en el servicio C
miFoo.accion3("B") #llamamos a la accion 3 en el servicio B



Primer solución "no dinámica"

Para muchos de los que lean esto, la primera solución que les vendrá a la mente será que cada método (accionX...) tenga dentro de sí un gran if, para cada servicio. Algo así:



class Foo:
def accion1(self, servicio):
if servicio == "A":
#codigo de la accion 1 en el servicio A
elif servicio == "B":
#codigo de la accion 1 en el servicio B
elif servicio == "C":
#codigo de la accion 1 en el servicio C
elif servicio == "D":
#codigo de la accion 1 en el servicio D



Esto va a funcionar, eso no lo voy a negar. ¿Pero qué es lo que no me gusta de esta opción? No me gustan estas cosas:

1) Este if va a estar repetido en cada una de las acciones, que son 5. Cuando se agreguen o modifiquen servicios, tengo que mantener actualizado el mismo if en los 5 métodos "accionX".
2) El código rápidamente se hace ilegible cuando es mucho código por acción.
3) Da la sensación de que estamos "amontonando" peras con manzanas, que esto podría separarse un poco para ordenarse mejor.
4) Estos if son 2 lineas por cada acción y servicio, con lo que para 5 acciones en 4 servicios, son 40 líneas de código solamente en los if, no incluyendo el código de las acciones mismas. Son 40 líneas de código que no hacen lo que queremos hacer, y que las necesitamos solo para decidir qué código ejecutar.

Mejorando la solución "no dinámica"

Para el problema del amontonamiento y el orden, a más de uno ya se le debe haber ocurrido la solución. Algo así:



class Foo:
def accion1(self, servicio):
if servicio == "A":
self.accion1_en_A()
elif servicio == "B":
self.accion1_en_B()
elif servicio == "C":
self.accion1_en_C()
elif servicio == "D":
self.accion1_en_D()

def accion1_en_A(self):
#codigo de la accion 1 en el servicio A

def accion1_en_B(self):
#codigo de la accion 1 en el servicio B

def accion1_en_C(self):
#codigo de la accion 1 en el servicio C

def accion1_en_D(self):
#codigo de la accion 1 en el servicio D



No puedo negarlo, la separación en varios métodos ayuda un poco a la legibilidad y mantenibilidad. Consideremos esa parte como resuelta y correcta, nos olvidamos de los métodos "accionX_en_Y".
Pero tenemos todavía esto:



def accion1(self, servicio):
if servicio == "A":
self.accion1_en_A()
elif servicio == "B":
self.accion1_en_B()
elif servicio == "C":
self.accion1_en_C()
elif servicio == "D":
self.accion1_en_D()



Esto es lo que sigue sin gustarme. ¿Por qué?
Porque seguimos teniendo el problema de los ifs horribles desparramados por todos lados.
Seguimos teniendo que mantener esas 40 líneas de código que solo sirven para elegir el código a ejecutar.
Mi opinión es que debería poder hacerse de otra forma.

La rareza viene al rescate: La solución dinámica

Bien, en teoría la cosa rara debería ahora ayudarnos con nuestro problema. ¿Y cómo nos va a ayudar esa cosa rara de Python?.
Recordemos que nos habíamos olvidado del código de los métodos "accionX_en_Y", esos estaban aprobados :). Lo feo era el código que elegía cuál método ejecutar según el servicio.

Veamos entonces la versión "rara" de ese código:



def accion1(self, servicio):
getattr(self, "accion1_en_" + servicio)()



Se nota lo que falta?? Ya no tenemos al if!

Antes teníamos esas 40 líneas de ifs, 8 líneas por cada acción que solo decidían qué código ejecutar. Ahora esa decisión se toma con 1 línea en cada acción, con lo que nos quedan (con 5 acciones) un total de.... 5 lineas!
5 líneas contra 40 es un ahorro del 87% menos de código.
Cuidado. La cuestión no es "tener pocas líneas porque es más lindo". En este caso, la ventaja es no tener que mantener código repetitivo e innecesario.

Y no solo eso, ganamos también otra ventaja muy importante: Si mañana agregamos o sacamos servicios, no es necesario tocar nada del código que elige el método a ejecutar. Solo agregamos las implementaciones (métodos accionX_en_Y), y la clase sabrá por si sola llamarlos, sin que tengamos que decirle nada extra. Así de práctico.

Conclusión

En un ejemplo bastante simple, se ve cómo una característica "extraña", bien usada puede transformarse en una característica "práctica".
Y cuidado, porque cuando se empiezan a aprovechar estas características, resulta bastante molesto volver a los lenguajes que no las tienen... Es adictivo, jeje.



PD: crédito a C.B. que me mostró el artículo de Paul Graham :D

Aplicaciones favoritas de Android

Otro día comentaré más de mi experiencia de haberme comprado un Android (les adelanto que no lo cambiaría por nada, jeje).

Hoy solo dejo un listado que me armé de mis aplicaciones preferidas. Podrán ver que me pasé un buen rato probando cosas :D

Charla Python

Desde hace rato ya que me "pythonisé". Viniendo del mundo .Net, en Python descubrí muchísimas cosas que me agradan y me hacen sentir más "comodo" (tipado dinámico, simplicidad, dry, etc.). Pero ahora no vienen al caso, otro día las comento más en detalle :D

Lo que sí viene al caso es que, por lo que me gustó Python, vengo no solo aprendiendo, sino que siempre les comento a mis compañeros de trabajo sobre las cosas que voy descubriendo. Y como en la empresa hace poco resurgió un proyecto de que demos charlas a la comunidad, entonces me propusieron dar una sobre Python (ya que les hinchaba tanto... jeje).

Así que el miércoles 2 de diciembre dí esta charla, que salió bastante bien. Poca gente, pero creo que les sirvió a ellos y a mí.
Para darla preparé una presentación, orientada más que nada a quienes vienen de .Net (no hace una comparación explícita, pero sí ordena los temas para que les resulten más familiares).

Aquí les dejo el link a la presentación:


Y también les dejo un link al sitio de PyAr, a la sección Charlas, de donde saqué mucho material para armar la mía. Gracias PyAr!!!:


Mi segunda aplicación libre: Cuoty

Bueno, como verán sigo con el impulso de liberar software. :D

En este caso estoy migrando una aplicación que antes había desarrollado a pedido de una parroquia, para la gestión de los aportantes (cuotas, cobradores, etc.).
En ese momento la había desarrollado con .Net, pero en este momento la estoy migrando a Python+Django, y al mismo tiempo haciéndola libre.

Pueden sumarse al proyecto, seguirlo, o realizar comentarios en: