La web

En estos días hubo una discusión en el blog de Sergio sobre la web. Sergio escribió por qué le gusta la web. Yo iba a responder ahí, pero lo que escribí se me alargó y además quería revivir el blog, así que decidí publicarlo aquí. Primero voy a dar una descripción de lo que, a mi juicio, es la historia de la web. Esto no está precisamente en orden cronológico y puede tener errores si mi memoria ha fallado. Las correcciones son bienvenidas.

La web no fue diseñada para hacer aplicaciones. La web fue diseñada como un medio para compartir documentos conectados por enlaces en Internet. El detalle aquí fue la web se popularizó de una manera increíble, llevando a que se quisiera usar para muchas otras cosas más. El resultado de todo esto es que la web tal y como la conocemos actualmente es sólo una suma de hacks sobre aquel sistema de documentos con enlaces.

Uno de los primeros hacks fue CGI. La web, como el correo electrónico o el FTP, no estaba diseñada para correr programas. Pero a alguien se le ocurrió que sería interesante que se pudiera mostrar contenido creado dinámicamente por un programa. Junto con el CGI vinieron los formularios. Y el sistema de documentos ahora también servía para ingresar información y mandarla a un servidor web, el cual podía responder y generar un documento personalizado acorde a los datos ingresados.

Después vino la explosión de la web. Y el primitivo sistema era cada vez insuficiente para mostrar los contenidos que se querían. Llegaron lo GIFs animados, los MIDIs de fondo, los frames, las tablas para hacer el “layout” de la página, los “blink”, etc. Aquí vino el primer colapso de la web. Resultó que hacer sitios web era un trauma increíble. El código HTML de cualquier página medianamente compleja era horrible. Decidieron que había que cambiar muchas cosas. Crearon CSS para separar el contenido de la presentación, comenzaron las campañas en contra de los frames y las tablas. Pero ahí no terminó todo. Con la web cada vez más popular, ya no queríamos sólo documentos bonitos, ahora queríamos cosas parecidas a las aplicaciones de escritorio: menús desplegables, drag and drop, etc.

En esa carrera por ampliar un centímetro más las capacidades de la web, los navegadores dejaron de ser simples visualizadores y se convirtieron en entornos de ejecución. Aparecieron los lenguajes como Javascript o VBScript. Con esto las páginas, originalmente pensadas para ser estáticas, se volvieron dinámicas. Con Javascript era posible cambiar la página a medida que corre un programa en el navegador. Esta abominación se llama DHTML. Luego, resultó que no era tan útil sólo tener páginas dinámicas, que no pudieran comunicarse con el exterior. Y casi por casualidad, en algún momento de la guerra de los navegadores, a alguien se le ocurrió agregar una función de Javascript que pudiera acceder a un servidor web. Y nació otra abominación: AJAX.

En el lado del servidor las cosas tampoco eran fáciles. El esquema de trabajo de la web era bien simple: el cliente manda una petición de un documento y el servidor la recibe y manda el documento. Se acabó, eso era todo. Pero ahora la web no era para mostrar documentos, sino para ejecutar aplicaciones. Había un problema enorme y era que el esquema de petición-respuesta de la web no tenía un concepto de sesión. ¿Cómo saber que una petición fue realizada por el mismo cliente que antes hizo otra relacionada? Los hacks para que hubieran sesiones en HTTP no se hicieron esperar: nacieron los campos de formulario ocultos, las crípticas largas cadenas HTTP GET con información de la sesión, etc.

Y esta es la historia de la web: hack tras hack, machetazo tras machetazo. La historia del desarrollador web es un continuo batallar por hacer que algo funcione en una forma para lo que no fue diseñado. La web es una mala experiencia para el usuario y para el desarrollador.

Una mala experiencia para el usuario se evidencia en varios sitios. ¿Alguien ha probado YouTube en HTML5? (por cierto HTML5 es el último machetazo de moda) ¡Qué mal que funciona! Por Dios, estamos en 2010, hacer un sencillo reproductor de vídeo debería ser trivial ¿no? Si a los brillantes desarrolladores de Google les cuesta hacer esto, ¿qué podríamos esperar de hacer un editor de vídeo como Adobe Premier? Tocará esperar al 2050. Mis experiencias con Google Docs también son frustrantes. Son programas con características muy simples, más simples que sus equivalentes de escritorio de hace décadas, y llenos de bugs, incluso cuando corren en Chrome.

Hay un aplicación web que me gusta, a pesar de que es bastante simple: Flickr. Pero no dudo de que sus desarrolladores sudaron bastante.

La web también es mala experiencia para los desarrolladores, especialmente en el lado del cliente. Por ejemplo, si en una aplicación de escritorio yo quiero pintar un cuadro, simplemente digo algo como pintar_cuadro(x, y, w, h). En la web, para crear el mismo efecto hay que crear un bloque donde iba a ir un párrafo, sólo que sin ponerle ningún texto adentro. Utilizar CSS para que ese cuadro tenga el tamaño y apariencia deseado, que se ajuste adecuadamente al documento, que no corra el texto a su alrededor. Luego hay que decirle que tenga la propiedad de ser invisible. Y por último, para lograr el efecto “pintar cuadro” hay que hacer que la propiedad del cuadro pase de “invisible” a “visible”. Y eso que no hablamos de los hacks que se tienen que hacer para X y Y navegador. Es por esto que la gente no hace esto a mano, sino que usa herramientas como JQuery o GWT. Pero estas capas hacen las cosas lentas y son difíciles de extender. Por eso, por más que uno tenga un computador potente, la aplicación web funciona como si estuviera en un 286.

Para aplicaciones con interacciones sencillas la web está bien. Pero cualquiera que esté al tanto de las innovaciones en experiencias de usuario e interfaces, sabrá que la web se queda muy corta. Hacer aplicaciones web que tengan una interacción con el usuario medianamente compleja es una labor titánica hoy en día. No conozco ninguna aplicación web que me convenza. Y las que más o menos impresionan, tienen un excesivo trabajo de sus desarrolladores.

Otra cosa: la web sólo permite un lenguaje en el cliente: Javascript. Y según la gente de StackOverflow.com, es uno de los lenguajes con cosas más raras que existen.

Bueno, aparte de rajar. Me gustaría decir que hay cosas de la web que me gustan mucho: La ubicuidad, como mencionaba Sergio. Que chévere es poder acceder a las cosas desde cualquier PC y tener ahí los datos y todo. (Aunque esto a veces puede ser una pesadilla, preguntenle a mi amigo Diego Escalante a quien Google le cancelo sin motivo aparente su cuenta y quedó frito). Que bueno que las aplicaciones sean multiplataforma. Que se actualicen automáticamente, etc. Hay algunas tecnologías que usan las ventajas de la web, con mayor flexibilidad en el desarrollo: un ejemplo es Silverlight o Flash/Flex/Air. Pero no me gusta mucho que detrás de estas estén empresas tratando de ser amo y señor de la web. A mi me gustan los estándares. Pero HTML5 me desilusiona. La W3C debería replantear todo, ya no queremos más hacks sobre lo mismo, sino algo que realmente esté diseñado para lo que debe hacer.

Optimizing a Python Program

These days, I’ve been optimizing a Python program I wrote. Optimizing is a fun task, but very difficult. Most of the time, the first solution I think is even worse than the previous situation. I need more experience.

Some processes were too slow in my program and I realized it was because I was performing too much disk I/O operations. I thought a solution could be read more data in memory and operate there. Now I have excessive memory consumption.

Here is a very simplified description of my memory consumption problem:

I have a text file. Each line in the file represents an item of a large list. Each line has two string values separated by a character. Something like a CSV file. I have to read the file content and put it in a list.

A line in the file looks like this:

Content of the first value|Content of the second value

The separator is '|'

Here is a simple Python program that read the file:

class Field:
    def __init__(self, line):
        self.value1, self.value2 = line.split('|')

fields = []

with open('test_data') as file_:
    for line in file_:
        fields.append(Field(line))

Running this program with a test file of about 42 MB gives this results:

Execution time (time): 0m4.108s
Memory consumed (pmap): 166652K

I was surprised by the high memory usage of the program. If the file is 42MiB, I thought the program should use a similar amount of memory, obviously a higher amount, but not almost four times the size of the file.

An equivalent program in C (error checking is omitted):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define VALUE1_MAX 30
#define VALUE2_MAX 80
#define LINE_SIZE VALUE1_MAX + VALUE2_MAX + 3
#define BUFFER 10000

typedef struct
{
    char value1[VALUE1_MAX+1];
    char value2[VALUE2_MAX+1];
} field;

int main()
{
    FILE *file = fopen("test_data", "r");

    field *fields = (field*) malloc(BUFFER*sizeof(field));
    char line[LINE_SIZE];
    char *part;
    long i=0;
    long size = BUFFER;
    while(fgets(line, LINE_SIZE, file) != NULL) {
        part = strtok(line, "|");
        strcpy(fields[i].value1, part);
        part = strtok(NULL, "|");
        strcpy(fields[i].value2, part);

        i++;
        if (i == size) {
            size += BUFFER;
            fields = (field*) realloc(fields, size*sizeof(field));
        }
    }
    fclose(file);
    free(fields);
    return 0;
}

Results for the C program:

Execution time (time): 0m0.537s
Memory consumed (pmap): 57548K

This is much better.

The problem with the Python program seems to be the Field objects using more memory than they need. Testing the program without the Field creations, changing fields.append(Field(line)) withfields.append(line) seems to perform better:

Execution time (time): 0m0.575s
Memory consumed (pmap): 66808K

Clearly, the Field object is the bottleneck both in memory consumption and execution time. This is probably because of some default memory allocations that Python makes for the object and its fields. Python is a really cool language, but it doesn’t let you control the way the memory is used. This is a positive thing in most of the cases, but in some of them, like this one, is negative.

Most of the times, there are only very small parts of a program that really need to be optimized. And a programmer is much more productive with Python than with C. It doesn’t make sense to rewrite the program in C. Instead, a C module could be written for the bottlenecks.

I was too lazy to learn how to use the Python C API, so I looked a this project called Cython. Cython is a language designed for writing Python extensions. It’s very similar to Python, but is translated to C and compiled to an easy to use Python module. Cython also lets you mix C code and Python code easily. It lets you use high level python objects or low level C data types as you need and mix them properly.

I decided to rewrite the Field class in Cython:

#field.pyx 
DEF VALUE1_MAX = 30
DEF VALUE2_MAX = 80

cdef extern from "string.h": 
    char *strcpy(char *dest, char *src)

cdef class Field: 
    cdef readonly char value1[VALUE1_MAX+1] 
    cdef readonly char value2[VALUE2_MAX+1] 
    def __init__(self, line):
        v1, v2 = line.split('|')
        strcpy(self.value1, v1)
        strcpy(self.value2, v2)

This extension type can be used almost in the same way than a real Python object:

>>> f = Field('Hello|World')
>>> f.value1
'Hello'
>>> f.value2
'World'
>>>

I had to modify the original Python script to use the new module:

from field import Field

fields = []

with open('test_data') as file_:
    for line in file_:
        fields.append(Field(line))

Results of the new program:

Execution time (time): 0m1.257s
Memory consumed (pmap): 69800K

This is a huge improvement. With a very small change, the program now consumes almost 100MB less memory and it runs three times faster. I could write more parts in Cython, using strtok() instead of str.split(), or even rewriting the entire list and reading process. I would probable get a performance very similar to the C program. But I’m comfortable with the results now. I’m still surprised with the small effort compared to the awesome results.

If you want to do your own tests. Here is a simple script to generate a test file with 500k values:

import string
import random

with open('test_data', 'w') as f:
    for i in range(500000):
        value1 = ''.join(random.choice(string.letters)
                         for s in range(random.randint(15, 30)))
        value2 = ''.join(random.choice(string.letters)
                         for s in range(random.randint(50, 80)))
        f.write(value1 + '|' + value2 + '\n')

Python vs C#: Queries

One of the most beloved C# 3.0 features is Linq. Linq brings great power to C#, it allows you to easily write structured queries over collections or remote data sources. Now with C# is possible to make queries as easy as with other languages like Python. I decided to compare the way you make queries with C# and with Python. I found a great page showing 101 Linq examples, I decided to write Python versions of this examples. Which version do you like more?

Where – Simple 1

C# version:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var lowNums = from n in numbers where n < 5 select n;

Python version:

numbers = [5, 4, 1, 3, 9, 8, 6, 7, 2, 0]
low_nums = (n for n in numbers if n < 5)

 

Where – Indexed

C# version:

string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
var shortDigits = digits.Where((digit, index) => digit.Length < index);

Python version:

digits = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine']
short_digits = (digit for index, digit in enumerate(digits) if len(digit) < index)

 

Select – Simple 1

C# version:

var numsPlusOne = from n in numbers select n + 1;

Python version:

nums_plus_one = (n + 1 for n in numbers)

 

Select – Anonymous Types 1

C# version:

string[] words = { "aPPLE", "BlUeBeRrY", "cHeRry" };

var upperLowerWords =
    from w in words
    select new {Upper = w.ToUpper(), Lower = w.ToLower()};

Python version:

The exact Python version would be something like:

words = ['aPPLE', 'BlUeBeRrY', 'cHeRry']

upper_lower_words = ( type('', (), {'upper': w.upper(), 'lower': w.upper() })
                      for w in words)

But I feel more Pythonic this:

upper_lower_words = ( (w.lower(), w.upper()) for w in words)

Or even this:

upper_lower_words = ( {'upper': w.upper(), 'lower': w.upper() }
                      for w in words)

SelectMany – Compound from 1

C# version:

int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };

var pairs =
    from a in numbersA,
         b in numbersB
    where a < b
    select new {a, b};

Python version:

numbersA = [0, 2, 4, 5, 6, 8, 9]
numbersB = [1, 3, 5, 7, 8 ]

pairs = ( (a, b) for a in numbersA 
                 for b in numbersB 
                 if a < b)

SelectMany – from Assignment

C# version:

var orders = from c in customers,
                  o in c.Orders,
                  total = o.Total
             where total >= 2000.0M
             select new {c.CustomerID, o.OrderID, total};

Python version:

I couldn’t find how to make the assignment in Python, so the version is:

orders = ( {'customer_id': c.customer_id,
            'order_id': o.order_id,
            'total': o.total }
           for c in customers
           for o in c.orders
           if o.total > 2000)

SelectMany – Multiple from

C# version:

var orders = from c in customers
             where c.Region == "WA"
             from o in c.Orders
             where o.OrderDate >= cutoffDate
             select new {c.CustomerID, o.OrderID};

Python version:

orders = ( (c.customer_id, o.order_id)
           for c in customers if c.region == 'WA'
           for o in c.orders if o.date >= cutoff_date)

Take Simple

C# version:

var first3Numbers = numbers.Take(3);

Python version:

if we are working with something like a list, we could do:

first_3_numbers = numbers[:3]

but, if we are working with iterators, we must do:

first_3_numbers = itertools.islice(numbers, None, 3)

Skip – Simple

C# version:

var allButFirst4Numbers = numbers.Skip(4);

Python version:

all_but_fist_4_numbers = numbers[4:] # list version all_but_fist_4_numbers = itertools.islice(numbers, 4, None) # iterator version 

TakeWhile – Simple

C# version:

var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);

Python version:

fist_numbers_less_that_6 = itertools.takewhile(lambda x: x < 6, numbers)

SkipWhile – Simple

C# version:

var allButFirst3Numbers = numbers.SkipWhile(n => n % 3 != 0);

Python version:

all_but_first_3_numbers = itertools.dropwhile(lambda x: x % 3 != 0, numbers)

First & Last

C# version:

numbers.First()
numbers.Last()

Python version:

numbers[0]  # first for a list numbers[-1] # last for a list 
numbers.next()   # first for iterator list(numbers)[0] # first for iterator 
list(numbers)[-1] # last for iterator 

First – Indexed

C# version:

int evenNum = numbers.First((num, index) => (num % 2 == 0) && (index % 2 == 0));

Python version:

even_num = [n for i, n in enumerate(numbers) if n%2 == 0 and i%2 == 0][0]

or:

even_num = (n for i, n in enumerate(numbers) if n%2 == 0 and i%2 == 0).next()

to be continued…

PyWeek Ended

PyWeek is over. It was absolutelly fun!. My final entry is not what I would call a finished product, but it’s not bad. A couple of hours before the challenge end, the pyweek.org server went down. We had to send a md5 sum of our final entries to one of the event’s coordinators via e-mail.

Video of my game:

http://video.google.com/googleplayer.swf?docId=-3566000892545301155&hl=en

My code and more detailed comments in my PyWeek Entry Page.

PyWeek

Tomorrow, I’m going to participate in the fifth edition of PyWeek. PyWeek is a challenge in which participants must develop a video game in one week using Python. I like the idea because it brings a possibility to finish a project and have some fun by the way.

Some of the games created during PyWeek are really awesome. It’s amazing the fact that they were made in only one week. My favorite games of previous editions of PyWeek are:

I also like the competition and challenge feeling that you can breath in PyWeek.s

It’s possible to participate in two categories: Individual and Team. This time I am going to participate as Individual. I am thinking in use PyGame only. Even when some people are talking about Panda3D. I also want to use Blender to create pre-rendered sprites. I have been learning it secretly for a while. The result has been exactly what I expected: I suck as a graphic artist. My models are absolutely ugly, but at least I can do something for a game. By the way, now I prefer Blender to Wings3D for 3D modelling.

Screenshots of my attempt to model an aircraft with Blender. I also tried some kind of cell-shading or toon-shading redering:

If I suck with Blender. I prefer not even talk about my talent with sounds and music.

See you in one (py)week!

Vala

These days, a lot of people on GNOME planet are talking about Vala, a new programming language aimed to facilitate the development of applications and libraries for the GNOME platform. Vala is very similar to C#, but what is interesting about it, is that it’s perfectly integrated with the Glib/GObject object system. The compiler translates the Vala source code into C. It uses GObject to create classes and interfaces, and GIDL metadata for introspection. This has some advantages: there is no need for any additional runtime, Vala programs are compatible at ABI level with C programs, writing bindings for existing GNOME libraries is really easy and straightforward. Alberto Ruiz wrote about how simple was to write a binding for GtkMozEmbed. After look at howtraumatic were the Java bindings for Gtk, or how difficult has been the creation of GStreamer bindings for Mono, I think this is the best feature of Vala.

Anyway, I think Vala still lacks some key tools in order to become a real choice for GNOME developers. In the case of Mono, there is a great advantage called MonoDevelop. Days ago, version 0.15 of this awesome IDE was released. With no doubt, I think this is the best IDE for GNOME. The GUI editor, the subversion integration, the localization support and autotools integration are very appreciated features. Of course, is not perfect, It lacks a debugger and fixes for some annoying bugs, but it’s a very active project and has a great community behind it.

And talking about languages, at the end of this month, it should be released the alpha version of Python 3.0. On June, Guido van Rossum published a report about the final decisions concerning Python 3000. I am very happy with most of the changes, it was time to break some backwards compatibility. Python will be even better that what it is now.

Dolor de cabeza con Python

Un problema de usar lenguajes dinámicos es que, al no tener etapa de compilación, no es posible detectar muchos de los errores sino hasta que se lanza alguna excepción mientras el programa se ejecuta. Un problema peor es cuando por alguna razón el error no produce una excepción y el programa termina funcionando erróneamente si dar ninguna pista sobre dónde puede estar el problema.

Examinen este pedazo de código en Python:

class MyClass:
	pass

if MyClass() < 1:
	do_something()
else:
	do_something_else()

o algo más curioso todavía:

if MyClass() < float('-infinity'):
	do_something()

do_something() siempre se ejecuta.

Lo correcto debería ser que al hacer este tipo de comparaciones se lanzara una excepción. La única forma de poderlo hacer debería se cuando sea explícito que el objeto puede compararse.

Noten que este código si lanza una excepción del tipo TypeError:

a = MyClass() + 1

Según lo que me dijeron en #python, parece ser que todos los objetos en Python están habilitados para hacer comparaciones. Esta es la razón por la cual se pueden ordenar fácilmente listas con cualquier tipo de datos en ellas. Debido a que arreglar esto supondría un corte con la compatibilidad hacia atrás, sólo podremos disfrutar de una adecuado comportamiento hasta que tengamos Python 3.0. Si esto hubiera estado listo ahora mismo me habría ahorrado un gran dolor de cabeza buscando un error.

Scratch

Quedé impresionado con Scratch, el nuevo lenguaje para introducir a los niños en la programación desarrollado por el MIT Media Lab. Lo bueno es que es libre (Licencia MIT), aunque sólo está para Mac y Windows, pero dicenque ya lo están portando para el X0 del proyecto OLPC. ¡Que bacano sería ser niño y tener este juguete!

Mas rapido, pero mas lento

En estas vacaciones de diciembre, fui a visitar a mi familia en Medellín. Mi tía Patricia tenía un viejo computador portátil Toshiba Satellite Pro 440 CDT que ya no usaba y decidió regalárselo a mi Papá. Es un portátil que ya tiene sus 11 años, pero, dado que mi papá escasamente usa el PC para leer y escribir correos electrónicos, navegar por Internet y de vez en cuando escribir una carta, le sirve perfectamente. Por supuesto, como buen entusiasta de software libre, pensé que si se le instalara Linux se podría explotar más su potencial. Sin embargo, rápidamente descubrí algo que me dejó atónito y me motivó a escribir esta entrada en mi blog.

El Toshiba Satellite Pro 440 CDT tiene las siguientes características:

Procesador
Intel Pentium MMX de 166 Mhz
Memoria
32 MB
Disco Duro
2 GB.
Software
Microsoft Windows 98 y Microsoft Office 97.

Después de ver las características tan bajas del equipo, hay algo que me da muchísima tristeza. Office arranca mucho, muchísimo más rápido que el OpenOffice de mi PC. Casi cuatro veces más rápido. Aún cuando mi PC tiene 32 veces más memoria que el portátil y un procesador con 20 veces más Mhz. No estoy muy seguro de esto pero, en mi opinión, Office 97 y OpenOffice 2.0 tienen prácticamente la misma funcionalidad.

Después de jugar un rato con el portátil me di cuenta que la velocidad general de sistema, arranque del sistema operativo, apertura de archivos, etc es bastante buena, muy comparable a la de mi PC. Es cierto que hay varias cosas que no pueden ser iguales, por ejemplo, creo que el portátil explotaría antes de poder usar algo como F-Spot o editar imágenes de 8MP con GIMP. La interfaz de mi PC también es más bonita, con más resolución y efectos interesantes. En fin, creo que hay un millón de cosas que no podría ser iguales, pero en el caso de programas como OpenOffice y Office, que son prácticamente iguales, el hecho de que haya un rendimiento similar, o incluso superioridad en el computador de 11 años de edad, me parece algo desgarrador.

¿Qué es lo que pasa? Culpo a los programadores. Somos especialistas en derrochar toda cantidad de recursos que tengamos disponibles. Anteriormente los computadores venían con 32 MB de memoria y los programas tenían que funcionar con eso, y funcionaban. Eso hacía que los programadores se interesaran por mejorar el uso de los recursos. Ahora hay abundancia y se puede derrochar.

Aunque hoy en día tenemos hardware decenas de veces más rápido que hace diez años, parece ser que la calidad y rendimiento de los programas no ha crecido en la misma proporción (si es que ha crecido en algo).

Hay casos mucho más extremos aún. En el mundo del desarrollo de juegos siempre se ha mantenido una tradición de explotar al máximo las capacidades del PC. Es quizás por esto que los juegos son los únicos que parecen mostrar un verdadero avance proporcional a los adelantos en hardware. Recuerdo cuando alguna vez escribí un sencillo juego para PlayStation. El sistema contaba con la miserable cantidad de 1MB de memoria de vídeo y 2MB de memoria de sistema. A mi me parecía demasiado difícil hacer algo con tan pocos recursos, sin embargo los expertos hacían juegos espectaculares con eso. Sabían usar muy bien los recursos.

El tema no necesariamente da para comparar programas viejos con nuevos. Hoy en día también hay buenos programadores que saben utilizar adecuadamente sus recursos. Hay un perfecto ejemplo de dos programas contemporáneos que tienen funcionalidad muy similar pero difieren enormemente en el uso de recursos: uTorrentAzureus.

La descarga de uTorrent es de 170KB, la de Azureus es de 9.4 MB, eso es 57 veces más, todo esto sin contar detalles como que Azureus requiere un runtime de Java (~50MB) y que viene en un instalador comprimido (bz2) mientras que uTorrent viene en un ejecutable standalone listo para ser ejecutado. El consumo promedio de Memoria de uTorrent es de 4.6MB, mientras que el de Azureus es de 40MB. El consumo de CPU es difícil de medir, pero los desarrolladores de uTorrent dice puede correr hasta en un CPU 486, eso ni siquiera cumple los requisitos mínimos del runtime de Java, en el caso de Azureus.

Ambos programas tienen casi las mismas funcionalidades, Azureus era el más popular, sin embargo, gracias a la superioridad en rendimiento de uTorrent, este le ha ganado el puesto y su popularidad crece en forma exponencial.

Hay otra razón por la cual hay tanta diferencia en estos programas: El lenguaje de programación. Aceptémolo, por más que varios estudios aseguren que la velocidad de los programas escritos en lenguajes como Java, C#, Python, Lisp, etc. sea igual o, algunos se atreven a decir, superior que C o C++, la verdad es que en la práctica todos los programas realmente eficientes están escritos en C o C++. uTorrent está escrito en C++, Microsoft Office está escrito en C++. Azureus está escrito en Java, OpenOffice está en gran parte escrito en Java. Pero ojo, esto no quiere decir que todos los programas de C++ sean necesariamente eficientes.

Es cierto que otros lenguajes hace al programador más productivo y en general más feliz, pero creo que es difícil negar que con C y C++ se puedan obtener programas más rápidos. ¿O tal vez sea mejor decir que con un poco más de esfuerzo a la hora de programar, esfuerzo al que casi siempre nos obliga C++, se obtengan mejores programas?

C++ siempre me encantó y lo usé mucho para muchos proyectos. Hace un tiempo me enamoré de Python y ha pasado bastante tiempo desde la última vez que usé C++ ¿Será que es tiempo de abrir el baúl y volver a sacar esos conocimientos de C++? ¿O será mejor seguir con los lenguajes de alto nivel y más bien tratar de hacer esfuerzos para lograr un balance entre felicidad del programador y eficiencia del programa?