<$BlogRSDUrl$>

Esos aparatos del demonio

Mis notas sobre lo que voy leyendo de ordenadores y periféricos

domingo, abril 23, 2006

Y hablando de Javascript... 


¡Ja! Y después de mi última parrafada sobre Javascript, resulta que voy a entrar en Microsoft Passport (para poder poner comentarios en un blog) y me dice que naranjas de la china.

Resulta que tengo instalada desde hace tiempo la extensión para Firefox NoScript. A veces me da problemas navegando, pero me suelo dar cuenta, activo el script sólo para esa sesión (o para siempre si es un sitio de confianza que sé que voy a usar mucho), se recarga sola la página y Santas Pascuas. Sin embargo los hábiles de Microsoft se están pasando a la Web 2.0 a su manera: haciéndolo mal. En la página de entrada de Passport, si no tienes Javascript, te redirecciona a otra página con un mensaje diciéndote que es necesario el Javascript... Así que ya no me vale con activarlo para esta sesión y que se recargue sola la página porque... ¡ya no estoy en la misma página!

Por cierto, que no sé si tendrá relación con eso, pero en los blogs de MSN no me deja abrir pestañas. Odio los blogs de MSN.

Javascript, hilos y setTimeout 


Voy a contar con un poco de detalle el problema de los hilos del otro día. Aunque al final no tenía nada que ver con hilos, me ha resultado un ejercicio interesante.

Estaba programando una extensión para Mozilla Thunderbird que sacase estadísticas sobre los mensajes. Las extensiones se programan en Javascript. El código que tenía era algo así:


var MiExtension {
listaCarpetas: new Object(),

onMenuCommand: function() {
this.prepararListaCarpetas();
this.calcularEstadisticas();
this.mostrarResultados();
},

calcularEstadisticas: function() {
for (var carpeta in this.listaCarpetas)
this.calcularEstadisticasCarpeta(carpeta);
}
};


Eso lo hice el viernes, pero el sábado, como ya he contado, me levanté con ansias refactorizadoras: como a un profeta de tiempos antiguos, durante la noche en sueños un ángel me habló y me hizo ver lo que estaba mal. Estaba mezclando procesamiento y presentación. ¡Anatema! Avergonzado íntimamente de mí, hice la siguiente refactorización*:


var VentanaMiExtension {

onMenuCommand: function() {
CalculadorEstadisticas.calcular();
this.mostrarResultados(CalculadorEstadistas.obtenerResultados());
}
};

var CalculadorEstadisticas() {
listaCarpetas : new Object(),

calcular: function() {
this.preparaListaCarpetas();
this.calcularEstadisticas();
},

calcularEstadisticas: function() {
for (var carpeta in this.listaCarpetas)
this.calcularEstadisticasCarpeta(carpeta);
}

};


Es decir, dejé el código de manejo del interfaz en un objeto y el procesamiento en otro.

El problema estaba en que calcularEstadisticas() lleva mucho tiempo**. Eso tenía dos consecuencias:

1) El interfaz de Thunderbird quedaba parado mientras procesaba. Eso es muy malo porque al usuario le da la sensación de que el programa está parado.

2) Después de unos 10 segundos, Thunderbird sacaba este mensaje:


Unresponsive script

A script on this page may be busy, or it may have stopped responding. You can stop the script now, or you can continue to see if the script will complete.



Me pareció muy curioso: Para protegerse de malos desarrolladores de extensiones como yo, tenían por ahí una especie de watchdog y cuando el hilo de interfaz estaba mucho tiempo ejecutando un script, avisaba.

Para arreglar el primer problema, había decidido que la solución era poner una barra de progreso para que el usuario viese cómo avanzaba el análisis. Por lo tanto, hice algo así:


var VentanaMiExtension {

onMenuCommand: function() {
CalculadorEstadisticas.calcular();
this.mostrarResultados(CalculadorEstadistas.obtenerResultados());
},

actualizarProgreso: function(nuevoProgreso) {
// Actualizar la barra de estado y de progreso
}
};

var CalculadorEstadisticas() {
listaCarpetas : new Object(),

calcular: function() {
this.preparaListaCarpetas();
this.calcularEstadisticas();
},

calcularEstadisticas: function() {
var numCarpetas = this.listaCarpetas.length;
var carpetasProcesadas = 0;
for (var carpeta in this.listaCarpetas) {
this.calcularEstadisticasCarpeta(carpeta);
carpetasProcesadas++;
VentanaMiExtension.actualizarProgeso(carpetasProcesadas/numCarpetas);
}
}

};


El problema es que la barra de progreso no se actualizaba. Ahora me parece obvio, pero tuve que alejarme un poco del ordenador (no hay nada como tener que hacer la compra) para darme cuenta de lo que estaba pasando: el código de mi extensión se estaba ejecutando en el mismo hilo que actualizaba el interfaz de Thunderbird, así que no repintaba y daba igual que incrementase la barra de progreso.

Ahí fue cuando me puse a buscar soluciones y escribí aquello de esos hilos del demonio. No encontré una función repaint o similar, así que al final no me quedó más remedio que meter hilos.

El problema es que estábamos hablando de hilos en Javascript sobre un programa que no he hecho yo: el Thunderbird. Yo soy muy prudente (otros dirían cobarde) y eso me parecía muy arriesgado. El código para recorrer los mensajes estaba inspirado en el de otra extensión, Remove Duplicate Messages (muy útil, por cierto), y vi que tenía por ahí unos setTimeout que no entendía para qué servían. Después de mis problemas, creí llegar a entenderlo: lo utilizaba para generar un nuevo hilo.

Ahora puedo decir que sé que no es así: no hay API de hilos en Javascript. Lo que se hace con la función setTimeout es dejar el procesamiento para más tarde y así se da tiempo a hacer otras cosas. Tiene una especie de cola de scripts a ejecutar y lo que se hace es meter la función con que se llame a setTimeout en esa cola.

El caso es que, como no me quedaba más remedio porque me parecía extremadamente chapucero que apareciese el mensaje de «Unresponsive script», me puse a meter el setTimeout. El código quedó algo así:


var VentanaMiExtension {

onMenuCommand: function() {
CalculadorEstadisticas.calcular();
},

actualizarProgreso: function(nuevoProgreso) {
// Actualizar la barra de estado y de progreso
},

onEstadisticasCalculadas: function() {
this.mostrarResultados(CalculadorEstadistas.obtenerResultados());
}
};

var CalculadorEstadisticas() {
listaCarpetas : new Object(),

calcular: function() {
this.preparaListaCarpetas();
this.calcularEstadisticas(0);
}

};

function calcularEstadisticas(index) {
if (indiceCarpeta >= CalculadorEstadisticas.listaCarpetas.length) {
VentanaMiExtension.onEstadisticasCalculadas();
return;
}

var numCarpetas = CalculadorEstadisticas.listaCarpetas.length;
var carpeta = CalculadorEstadisticas.listaCarpetas[index];
CalculadorEstadisticas.calcularEstadisticasCarpeta(carpeta);
index++;
VentanaMiExtension.actualizarProgeso(index/numCarpetas);
setTimeout(calcularEstadisticas, 10, index);
}

Como se ve, ha habido muchos cambios en el código. El problema es que al meter el setTimeout se pierde el flujo de ejecución normal: las instrucciones después del setTimeout se ejecutan inmediatamente, pero la función que se llama en el setTimeout se ejecuta un rato después. Eso hace que después de llamar a calcularEstadisticas no pueda hacer nada más, porque se haría antes de que acabase de verdad de calcularlas. Por eso metí la función onEstadisticasCalculadas.

Por otra parte, de alguna manera se perdía el this al llamar a una función a través del setTimeout***, así que tuve que sacar esa función del objeto en el que estaba. El código que antes era muy bonito, con cada cosa en su objeto y un interfaz claro entre ellos, es ahora un jaleo de objetos que se llaman unos a otros.

Eso funcionó. Más o menos. El nuevo problema es que cuando tenía una carpeta con muchos mensajes (lo que hace que se tarde mucho en procesar sin haber un setTimeout) volvía a salir el odioso mensaje de «Unresponsive script». La solución: hacer el setTimeout no en el procesamiento de carpetas sino en el procesamiento de mensajes. No voy a contar los detalles, pero eso fue todavía más complicado: si hacía el setTimeout en cada mensaje, el script, en lugar de ejecutarse en 15 segundos para mi caso de prueba, se ejecutaba en 200. Así que tuve que hacerlo sólo cada cierto número de mensajes, con otras cuantas líneas de código más para liarlo todo.

Al final funciona (parece). Pero el código resultante es un jaleo mucho más difícil de entender que el código original. Por eso yo hubiese preferido una función del tipo update o PeekMessage en lugar de tener que meter hilos o la versión pobre de Javascript: el ínclito setTimeout.

Notas:

* Probablemente haya muchas cosas que mejorar en el código. Hay que tener en cuenta que en lugar de aprender Javascript y luego ponerme a programar en él, me puse a programar y cuando algo no salía, buscaba por ahí, así que no entiendo bien ni cómo funciona la herencia ni los objetos, con lo que es normal que haya burradas.

** Por las pruebas que he hecho, la mayor parte de ese tiempo ocurre en una función de librería a la que llamo y que no he hecho yo.

*** No estoy muy seguro de esto, y la verdad que me parece raro, pero creo que pasaba y ahora no tengo ganas de volver a probarlo.

domingo, abril 16, 2006

Anuncios de Firefox 


Hace tiempo oí hablar de un concurso con anuncios en vídeo de Firefox, pero no llegué a ver ninguno. Hoy me he encontrado con Firefox Flicks, que es el sitio donde organizaron el concurso. Algunos que me han hecho gracia:

- Double-Click Relief: Uno de cada diez profesionales de IT prefieren Firefox. Descubre que pasa con los otros nueve...

- Whee

- Drama Queen

- Billy's Browser

- Pop-up Proposal

sábado, abril 15, 2006

La curva cuesta de aprendizaje 


Creo que estoy a punto de empezar un nuevo blog en el que sólo me dedicaré a comentar el blog de Kathy Sierra. ¡Tengo todas sus últimas marcadas marcadas como «Mantener como nuevo» en Bloglines!

Parece que cada cosa que escribe la escribe para mí: eso es un usuario apasionado de los que habla el título de su blog, ¿no? En Pushing your skill set, por ejemplo, habla de lo conveniente que es de vez en cuando hacer cosas que no sabes hacer. En lugar de dejarte llevar por la rutina y aplicar otra vez esa herramienta que dominas, forzarte a aprender una nueva herramienta. A la larga puede ser muy beneficioso. Y, si no lo hacemos de vez en cuando, se nos reblandece el cerebro.

Precisamente por eso me lancé este fin de semana a escribir una extensión para el Thunderbird. Javascript, XUL, XPCOM... Todo un mundo nuevo. Pasé la mitad del jueves sólo intentando hacer el «Hola, mundo», pegándome contra errores que no tenía ni idea de dónde venían. ¡Ni siquiera tenía un mensaje por el que buscar! Simplemente no pasaba nada. A última hora del jueves conseguí hacer por primera vez algo útil. Creí que ya estaba controlado y me fui feliz a la cama. El viernes añadí más cosas y me encontré con más problemas que fueron duros, pero acabé el día convencido de que ya estaba: ya dominaba todo lo básico y ahora era ya sólo cuestión de echar tiempo haciendo aburridas funciones. Pero me levanté hoy sábado con ganas de hacer refactorización del código. Últimamente he descubierto que lo de la refactorización es uno de los pequeños placeres de la programación. Como la mejora del interfaz: se me ocurrió poner una barra de progreso y esa tontería me acabó llevando a lanzar hilos en Javascript. Por no contar cuando en una refactorización me puse a utilizar funciones con número de parámetros variables...

Aunque dice Kathy que a nadie le gusta enfrentarse con la curva de aprendizaje (que debería llamarse «cuesta de aprendizaje»), la verdad es que los momentos más divertidos son cuando te estás pegando contra algo y por fin lo consigues. Cuando estás desarrollando código rutinario, es mucho más aburrido.

Otra idea interesante de la entrada de Kathy es que estudiando para exámenes de certificación se aprenden cosas que nunca habrías aprendido si sólo te dedicaras a hacer un trabajo... pero que luego te sirven para hacer mejor tu trabajo.

Y en los comentarios hay alguien que dice:


Try teaching. Students are quite good at wanting to know 1. latest and greatest 2. Not understanding the perfect explanation that you came up with last semester. So your forced to consatntly re-examine your craft and it's tools over and over again.


No sé si seguir con la extensión o leer la siguiente entrada de Kathy Sierra. ¿Me obligará a hacer otro comentario?

Nuevos escritorios 


No, no me refiero a KDE, Gnome y esas cosas, sino al sitio físico donde tienes el ordenador. Imagino que con la moda de comprar portátiles, habrá mucha gente que tenga algo como esto. Y es que donde esté un teclado de verdad...

(El escritorio pertenece a Jonathan Riddell y aparece en una entrevista que le hacen. Vía Barrapunto.)

Esos hilos del demonio 



«Si te sabes reír de tus propias miserias, siempre hallarás motivos para ser feliz.»

Yo mismo


Esta soberana tontería se me ocurrió al encontrarme, en medio de mi miseria, soltando una carcajada. Resulta que estoy teniendo un problema de programación: me pongo a hacer una tarea costosa computacionalmente y se bloquea el interfaz de la aplicación. ¿A quién no le ha pasado alguna vez? Conozco dos posibles soluciones:

1) Crear un hilo para la tarea costosa y liberar al hilo de interfaz de usuario (precisamente la solución de la que hablé para hacer que las aplicaciones Swing respondan más rápido).

2) Dejar tiempo de vez en cuando al hilo de interfaz de usuario llamando a una función tipo repaint o DispatchMessage.

La primera solución es probablemente la mejor... pero introduce hilos y los hilos producen más problemas que un yonki con una navaja y con síndrome de abstinencia. Así que estaba investigando la segunda, cuando me encontré con una entrada de un desarrollador de Mozilla en la que discutía los problemas de los hilos. Lo que me hizo gracia fue que en los comentarios alguien dijo:


This problem has been addressed by programmers of real-time and reliable systems for more than 20 years. Take a look at the ideas behind occam2 and the transputer which date back to the early 80's, wikipedia will tell you all about it. [...]

Lets hope that these ideas and methods will finally make their way into the desktop to produce more reliable and faster software.


La mención de los Transputers me hizo soltar la carcajada. No necesito que la Wikipedia me cuente nada para saber que así no se va a solucionar el problema: yo estuve allí. O como dicen los angloparlantes: «Been there, done that». Y allí pasé alguno de mis peores momentos luchando contra programas imposibles de depurar. Así que, aunque también me han proporcionado historias para reírme durante media vida, casi prefiero los hilos...

Mejorando el manejo de descargas en Firefox 


Me acabo de encontrar con una extensión para Firefox que me ha parecido muy buena: Download Statusbar. Básicamente, hace que las descargas aparezcan con una barra de estado en lugar de la ventana nueva que sale con el gestor de descargas integrado por defecto. Además, da más opciones para manejar las descargas. Sencilla y cómoda, ¿qué más se puede pedir?

jueves, abril 13, 2006

Extesión "Hola, mundo" para Thunderbird 


He estado toda la mañana intentando conseguir, siguendo el tutorial para hacer Hello World!, hacer que funcione una extensión que simplemente añada una opción de menú al Thunderbird y saque un mensaje. El problema es que el tutorial está hecho para Firefox y hay que cambiar algunas cosas para Thunderbird... y lo que hay que cambiar no lo pone en ningún sitio.

Creo que es esto:

- En el fichero manifest.chrome, en vez de:


overlay chrome://browser/content/browser.xul chrome://helloworld/content/overlay.xul


como en Thunderbird la ventana principal se llama de manera distinta, hay que poner:


overlay chrome://messenger/content/mailWindowOverlay.xul chrome://helloworld/content/overlay.xul



- En el fichero install.rdf, hay que añadir esto para indicar que también sirve para Thunderbird:



<em:targetApplication>
<Description>
<em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
<em:minVersion>1.0</em:minVersion>
<em:maxVersion>1.5</em:maxVersion>
</Description>
</em:targetApplication>



- En el fichero overlay.xul, hay que cambiar el nombre del menú «Tools», porque en Thunderbird es taskPopup en vez de menu_ToolsPopup, así que en vez de:


<menupopup id="menu_ToolsPopup">


hay que poner


<menupopup id="taskPopup">


Tres tonterías que me ha llevado horas encontrar.

Actualización: Y después de todo, sí había versión para Thunderbird en el tutorial, por ahí escondida al final... Veámoslo por el lado positivo: he aprendido bastante en toda la búsqueda.

jueves, abril 06, 2006

Sistemas operativos que arrancan en muchas plataformas 


Es la moda este año, señora: permitir que los sistemas operativos arranquen en varias plataformas. Vea, si no, cómo Apple ha lanzado un producto, Boot Camp, que permite que Windows arranque en Mac. Y Microsoft ha dicho que va a dar soporte a los Linux que funcionen en su Virtual Server. Ver para creer.

Así trabaja Bill Gates 


Bill Gates ha escrito un artículo en CNN Money contando qué herramientas usa para trabajar. Por supuesto, no utiliza Linux. Pero sí 3 pantallas planas: en una tiene la lista de correos electrónicos, en otra el correo electrónico que está leyendo y en la tercera el navegador. Dice que quien lo prueba, no puede volverse atrás. A ver si me hace una donación para probarlo: aparte de tres pantallas planas, necesito fondos para una mesa y un despacho más grandes...

martes, abril 04, 2006

Sobre la segmentación en el mercado de portátiles 


Muy buena entrada de Al otro lado del mostrador sobre modelos de portátiles, explicado claro y con ejemplos. A mí es que casi me apetece ir a su tienda a comprar :-)

sábado, abril 01, 2006

Guías de reparación de portátiles 


Pues eso: unas guías de reparación, desmontaje y actualización de portátiles clasificadas por fabricante.

This page is powered by Blogger. Isn't yours?

Blogroll
Enlaces
Archivos

Licencia Creative Commons
Este trabajo tiene licencia Creative Commons License.