Archivo para la categoría ‘Informática’

Ruta para las librerías en desarrollo en Linux

Cuando estás desarrollado alguna librería en Linux, es probable que durante este desarrollo no tengas la librería instalada en los directorios por defecto del sistema (que son /lib, /usr/lib y /usr/local/lib) por lo que cuando vayas a probar el programa que hace uso de esa librería se produzca el siguiente error:

diego@box:~/projects/my_lib/test:$ ./test
test: error while loading shared libraries: libsxxx.so: cannot open shared object file: No such file or directory
diego@box:~/projects/my_lib/test:$

Para solucionarlo basta que con insertes en la variable de entorno LD_LIBRARY_PATH el directorio donde está esta librería:

diego@box:~/projects/my_lib/test:$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../lib

Suponiendo que la librería está en ../lib.

Con esto ya se ejecutará tu programa de prueba sin problemas, aunque hay que tener en cuenta que cuando salgas de ese terminal esta variable va a volver a su valor original (que suele ser la cadena vacía).

Una vez que instales tu librería en alguna ruta del sistema (generalmente las librerías propias irán en /usr/local/lib) debes ejecutar el comando ldconfig para que se actualice la caché de librerías y todos los programas que la usen la encuentren sin problemas.

Windows en procesadores ARM

¿Recuerdan ustedes que comenté que mi previsión era que los procesadores ARM conquistasen el escritorio y que, probablemente, no sería Windows el sistema operativo que los controlase? Pues parece que Microsoft no quiere perder esa parte del pastel (como es lógico) y ya planea portar sus Windows a esta arquitectura.

Dicen que Windows NT es (o era) bastante portable y que lleva años funcionando en procesadores ARM dentro de los laborarios de Microsoft, pero ¿cuánto de Windows NT tiene Windows 7?

Además, espero que sea rápido porque Android ya está muy metido en harina, sobre todo en tablets que, a mi entender, son el futuro cercano de las comunicaciones móviles junto con los teléfonos “inteligentes” o smartphones.

Estaremos atentos a los movimientos en el patio.

Script con Zenity para mostrar un dialogo de descarga mediante wget

Mediante el script mostrado a continuación, desarrollado en BASH, se pueden descargar archivos de Internet con el comando wget y mostrando una interfaz gráfica con una barra de progreso mediante Zenity. La ventana mostrada se cierra cuando alcanza el 100%.

#!/bin/bash

function download() {
rand="$RANDOM `date`"
pipe="/tmp/pipe.`echo ‘$rand’ | md5sum | tr -d ‘ -’`"
mkfifo $pipe
wget -c $1 2>&1 | while read data; do
if [ "`echo $data | grep '^Longitud:'`" ]; then
total_size=`echo $data | grep "^Longitud:" | sed ‘s/.*\((.*)\).*/\1/’ | tr -d ‘()’`
fi
if [ "`echo $data | grep '[0-9]*%’ `" ];then
percent=`echo $data | grep -o "[0-9]*%" | tr -d ‘%’`
current=`echo $data | grep "[0-9]*%" | sed ‘s/\([0-9BKMG.]\+\).*/\1/’ `
speed=`echo $data | grep "[0-9]*%" | sed ‘s/.*\(% [0-9BKMG.]\+\).*/\1/’ | tr -d ‘ %’`
remain=`echo $data | grep -o "[0-9A-Za-z]*$" `
echo $percent
echo "#Descargando «$1»…\n\nDatos descargados\t\t: $current de $total_size ($percent%)\nVelocidad de descarga\t: $speed/s\nTiempo estimado\t\t: $remain"
fi
done > $pipe &

wget_info=`ps ax | grep "wget.*$1" | awk ‘{print $1"|"$2}’`
wget_pid=`echo $wget_info | cut -d’|’ -f1 `

zenity --progress --auto-close --window-icon "/usr/share/icons/hicolor/48×48/status/aptdaemon-download.png" --text="Conectando a «$1»…\n\n\n" --width="350" --title="Descargando «`basename $1`»…" < $pipe
if [ "`ps -A |grep "$wget_pid"`" ]; then
kill $wget_pid
fi
rm -f $pipe
}

if [ $1 ]; then
download "$1"
else
dllink=$(zenity --entry --text "Indique el enlace a descargar:" --width="350" --entry-text "" --title="Descargar archivo de URL")
if [ $dllink ]; then
download "$dllink"
fi
fi

Para hacerlo funcionar basta guardar el código anterior en un archivo de texto (por ejemplo zdownload) para luego darle los permisos de ejecución (chmod 755 zdownload). Cuando se ejecute este programa sin parámetros, mostrará una ventana para introducir la URL de descarga. Una vez hecho esto, se ejecutará la aplicación mostrando una ventana como esta:

Progreso de Zenity

El script original lo vi en Ubuntu Life aunque yo lo he retocado un poco para que reconozca que el comando wget está en español.

ARM a por el escritorio

Que ARM de el salto a ordenadores de escritorio es cuestión de tiempo. Ya lo comentaba Diego Calleja, pero cuanto más tiempo pasa más claro está.

Porque resulta ARM está preparando un procesador destinado no sólo a teléfonos móviles, sino también a ordenadores portátiles. Y eso es asaltar el escritorio.

Pero no sólo eso, además está preparando otro procesador ¡para servidores! Sí, habéis oído bien: un ARM en servidores. Y puede que las características no sean muy halagüeñas (1,6 GHz de velocidad) pero hay que tener en cuenta que sólo consumirá 10 W.

Ahora mismo Intel tiene que estar un poco nervioso por lo que se avecina. Pero no creo que estén parados. Puede que intenten sacar un nuevo procesador que consuma poco y tenga el mismo rendimiento que los ARM, incluso puede que lo consigan, pero recordemos que su handicap principal es la arquitectura x86 (que es CISC y tiene más de 25 años) con su amplísimo juego de instrucciones, no la tecnología de fabricación. ARM tiene una arquitectura RISC muchísmo más sencilla con un juego de instrucciones más simple y con un mayor número de registros. Esto, a priori, hace que sea mucho más escalable que la de Intel que creo que ya ha dado bastante de sí.

Pero aún sí, este no es el punto más fuerte del tema. El punto más fuerte es saber cual será el sistema operativo que se llevará el gato al agua de los ordenadores personales con esta nueva arquitectura. Porque Windows domina en x86, pero creo que no hay port para ARM. Y Linux sí que está portado a esta arquitectura y con muy buenos resultados. De hecho Android, MeeGo y WebOS son Linux y todos funcionan perfectamente en sus correspondientes teléfonos cuya arquitectura es ARM y sería muy fácil llevarlos al ordenador de escritorio.

Digamos que gracias a este cambio (que es una suposición, no se vayan ustedes a pensar que soy adivino) todos los sistemas operativos parten desde el mismo punto: Windows gracias a su solera —aunque no tenga port para ARM— y Linux porque sí funciona en ARM pero no está tan difundido.

¿Conseguiremos ver esto en un plazo razonable? ¿Conseguirá triunfar el software libre entre el gran público? Eso espero…

Ahora vamos con los deseos: existe “el otro” sistema operativo, esto es, Haiku, el clon de mi querido y desaparecido BeOS. Si se ponen las pilas y emplean su tiempo en una implementación para ARM (en lugar de hacerla para los Amiga M68k, que también, pero ahora no) quizás consigan salir con unas ventajas y capacidades cercanas a las de los dos sistemas operativos principales y quizás lograrían entrar en el juego. Pero ya digo, sólo quizás, aunque me gustaría.

NetworkManager no se lleva bien con las interfaces virtuales

Vamos, no es que no se lleve ni bien ni mal, directamente no se lleva. NetworkManager, el gestor de conexiones de redes en Linux, no soporta interfaces virtuales de red como, por ejemplo, eth0:1.

Para centrarnos un poco pero sin profundizar, una interfaz virtual es una interfaz ficticia asociada a una interfaz real, esto es, simular dos tarjetas de red teniendo sólo una. También se llaman “alias”.

¿Y esto para que sirve? Pues para acceder, por ejemplo, a dos redes diferentes desde el mismo equipo. Por ejemplo, la IP real de nuestro equipo es 192.168.1.42 con máscara de subred 255.255.255.0 y queremos acceder a un equipo cuya IP es 192.168.2.100 con máscara de subred 255.255.255.0. Como están en distinta red no se puede acceder directamente, a no ser que creemos una interfaz virtual o alias de red.

Para ello basta con configurar en el archivo /etc/network/interfaces la nueva interfaz. Suponiendo que nuestra interfaz principal se llame eth0, el archivo de configuración quedaría así (además de lo que hubiese antes):

auto eth0:1
iface eth0:1 inet static
address 192.168.2.42
netmask 255.255.255.0
network 192.1638.2.0
broadcast 192.168.2.255

En caso de que nuestra interfaz tuviese un nombre diferente, por ejemplo ra0, el nombre de la interfaz virtual debería ser ra0:1 (o cualquier otro número entero detrás de los dos puntos).

Una vez hecha la configuración, la nueva interfaz virtual se activa mediante el comando:

diego@box:~:$ sudo ifup eth0:1

Pero, como reza el título de esta entrada y como ya iba siendo hora de contarlo, si usas Ubuntu con NetworkManager, en el próximo reinicio de la máquina la interfaz virtual no se activará porque NetworkManager no soporta interfaces virtuales.

Pero como (casi) siempre, en Linux hay solución. Para ello hay que hacer uso de la ejecución de los scripts que usa NetworkManager. Estos scripts se encuentran en el directorio /etc/NetworkManager/dispatcher.d. Ahí hay que crear un archivo —al que llamaré updownaliases— con el siguiente contenido (cambiando el nombre de la interfaz según corresponda):

#!/bin/bash

iface="$1"
shift

action="$1"
shift

if [ "$iface" == "eth0" ]; then
case "$action" in
up)
/sbin/ifup eth0:1
;;
down)
/sbin/ifdown eth0:1
;;
*)
echo "updownaliases: Invalid action for $iface: $action" 1>&2
exit 1
;;
esac
fi

Este archivo debe pertenecer a root (los que no pertenecen a root son ignorados) y luego hay que darle los permisos de ejecución mediante el comando:

diego@box:~:$ sudo chmod 755 updownaliases

Para probarlo basta con que desactivéis y activéis la red desde el NetworkManager (botón derecho sobre el icono y hacer clic en el menú «Activar red»). Para comprobar si todo es correcto hay que ejecutar el comando:

diego@box:~:$ ifconfig

Y ahí tienen que salir todas las interfaces, tanto la real (que generalmente es eth0) como la virtual o alias, que, en este caso, es eth0:1.

Con Eclipse mejor Sun JDK que OpenJDK

Una nota rápida: si usas Eclipse en Linux seguramente este esté usando OpenJDK para ejecutarse. OpenJDK es la implementación libre de la plataforma Java y es generalmente el paquete que viene por defecto en la mayoría de las distribuciones, entre ellas en Ubuntu.

Pero de vez en cuando a Eclipse le da por petarse con un SIGSEGV. Vamos, con una violación de segmento de toda la vida. Y esto es porque el OpenJDK tiene algún error.

Para solucionarlo basta con desinstalar el OpenJDK e instalar la versión oficial de Java que está en los repositorios:

diego@box:~:$ sudo apt-get remove openjdk
[...]
diego@box:~:$ sudo apt-get install sun-java6*
[...]
diego@box:~:$

Con estos simples comandos, aunque perdemos la pureza que algunos quieren darle a los sistemas GNU/Linux de que todo el software sea libre, tu Eclipse estará contento y trabajarás mucho mejor. Porque de lo que se trata es de que trabajes bien y a gusto con tu sistema informático. La filosofía la dejamos para otro día.

Parche para el módulo site_map de Drupal

He creado un parche para el módulo site_map de Drupal para poder incluir en el mapa del sitio todos los menús que estén ocultos, porque a veces es necesario que el menú de cada página (que suele estar en un lateral) no tenga tanta profundidad, pero sí debe salir en el mapa del sitio.

Actualmente el parche no está dentro de la rama principal de desarrollo pero, una vez instalado el módulo, se puede aplicar a partir de los archivos *.patch (generados con svn diff) con la herramienta patch.

Es la primera vez que contribuyo a un proyecto libre y, por supuesto, esta entrada es únicamente para engordar mi ego (a veces pasa…), aunque espero que el parche sea incluido y al menos le sirva a alguien a parte de a mi ;) .

Manifiesto por el Desarrollo Ágil de Software

De lo primero que he visto en el libro de ingeniería del software ágil ha sido el manifiesto por el desarrollo ágil de software, donde estos son sus principios:

  1. Nuestra mayor prioridad es satisfacer al cliente mediante la entrega temprana y continua de software con valor.
  2. Aceptamos que los requisitos cambien, incluso en etapas tardías del desarrollo. Los procesos Ágiles aprovechan el cambio para proporcionar ventaja competitiva al cliente.
  3. Entregamos software funcional frecuentemente, entre dos semanas y dos meses, con preferencia al periodo de tiempo más corto posible.
  4. Los responsables de negocio y los desarrolladores trabajamos juntos de forma cotidiana durante todo el proyecto.
  5. Los proyectos se desarrollan en torno a individuos motivados. Hay que darles el entorno y el apoyo que necesitan, y confiarles la ejecución del trabajo.
  6. El método más eficiente y efectivo de comunicar información al equipo de desarrollo y entre sus miembros es la conversación cara a cara.
  7. El software funcionando es la medida principal de progreso.
  8. Los procesos Ágiles promueven el desarrollo sostenible. Los promotores, desarrolladores y usuarios debemos ser capaces de mantener un ritmo constante de forma indefinida.
  9. La atención continua a la excelencia técnica y al buen diseño mejora la Agilidad.
  10. La simplicidad, o el arte de maximizar la cantidad de trabajo no realizado, es esencial.
  11. Las mejores arquitecturas, requisitos y diseños emergen de equipos auto-organizados.
  12. A intervalos regulares el equipo reflexiona sobre cómo ser más efectivo para a continuación ajustar y perfeccionar su comportamiento en consecuencia.

Pero con los que no estoy de acuerdo con todos. Me explico:

Los puntos uno y tres son lógicos: es bueno que se entregue al cliente software. Y, además, rápido. De hecho es lo mejor para que se vea que el desarrollo avanza.

El punto dos, el de los requisitos es más peliagudo: los requisitos pueden cambiar, pero no la base principal del software, es decir, cierta funcionalidad puede variar, pero no se puede cambiar de aplicación de un momento para otro (y de eso hay mucho).

El equipo debe estar unido y motivado, pero eso se consigue de dos formas: o que el jefe de proyecto sea un buen jefe de proyecto (todavía no he conocido a ninguno), o tener equipos autogestionados sin jefe de proyecto (como en algunas metodologías ágiles). Quizás este sea el punto más complicado de cumplir.

Eso de que la comunicación “cara a cara” (punto seis) siempre es la mejor… disiento. Está bien para etapas tempranas, donde se está decidiendo el principio de la aplicación, las tecnologías, etc. Pero cuando ya ha pasado bastante tiempo de desarrollo, lo mejor es usar herramientas de comunicación, como el simple correo electrónico o pizarras compartidas. Y esto es porque así queda registrado todo lo que se comenta, mientras que con el “cara a cara” se pierde la mitad de la información.

Como dicen en el libro, el diseño de la aplicación es el propio código fuente (la construcción la hace el compilador, no el programador), por eso, como dice el punto siete, el software funcional es la mejor medida de avance.

Los últimos puntos también son algo lógico, pero también algo muy complicado de cumplir: la excelencia, es decir, tener a buenos desarrolladores, utilizar metodologías ágiles y, sobre todo, simplicidad.

Este manifiesto está bien, sobre todo para la época en que fue escrito, allá por 2001 (9 años en informática es una eternidad), cuando la Ingeniería del Software se tomaba como cualquier otra ingeniería siguiendo procesos tayloristas. Incluso hoy en día todavía seguimos esos procesos aún sabiendo que en la mayoría de los casos no funcionan (¿conocéis algún proyecto informático grande —por ejemplo de alguna administración pública— que haya terminado en plazos y sin salirse del presupuesto? Yo no.), por eso recomiendo seguir estos principios para el desarrollo de software aunque con algunas excepciones, pero no estas, sino las que vosotros hayáis deducido de vuestra experiencia.

IBM Lotus Symphony

Captura de IBM Lotus Symphony en Ubuntu

Por casualidad he visto la nueva suite ofimática de IBM llamada Lotus Symphony y, como tenía paquete .deb y era fácil de instalar, me he decido a probarla.

Esta suite es la apuesta de IBM por el software de oficina intentando hacer la competencia al omnipresente Microsoft Office, aunque creo que sus objetivos principales son OpenOffice.org y, ahora, LibreOffice, ya que esta, a su vez, está basada en OpenOffice y en Eclipse.

La primera impresión ha sido buena. No tarda demasiado en iniciar la primera vez y en las sucesivas aún menos ya que queda ejecutando en segundo plano un lanzador rápido. Es totalmente compatible con los archivos OpenDocument (para mi ahora es lo más importante) y, lo que más me ha llamado la atención, es su cuidada aunque inacabada interfaz de usuario. Digo inacabada porque he detectado algunos problemas de dibujado en la misma, sobre todo al pasar el ratón por encima de algunos elementos.

Además, mayoría de los menús y opciones son similares a todas las aplicaciones ofimáticas del mercado, especialmente a OpenOffice.org.

En general está bien. Es otra alternativa más que siempre viene bien para el monopolizado mundo de las suites ofimáticas.

Lo siguiente será probar LibreOffice. Pero eso para cuando el desarrollo y las paquetes están más estables, a parte de las traducciones al español. Ya os contaré.

RAE: Recursividad

recursividad.

(Del ingl. recursivity)

1. f. Véase recursividad.

El chiste fácil del día. Por cierto que recursividad no viene en el diccionario de la RAE.

La programación es…

La programación es fundamentalmente una actividad de diseño y la única representación definitiva y verdadera de ese “diseño” es el código fuente.

Jack W. Reeves, desarrollador de software con 30 años de experiencia, como resumen de sus ensayos sobre desarrollo de software.

Ubuntu 10.10 Maverick Meerkat

A veces padezco de versionitis, como ahora, por lo que he actualizado mi versión 10.04 de Ubuntu a la versión 10.10 desde el instalador gráfico. Y, cómo no, aquí están los comentarios de rigor:

  • La actualización ha sido perfecta, a pesar de los más de 2 GB que he tenido que descargar (tengo muchos paquetes, sobre todo de desarrollo). Eso sí, ha tardado lo suyo, unas cinco horas entre descarga e instalación de paquetes.
  • La nueva tipografía, “Ubuntu”, aunque se instala, hay que aplicarla a mano desde las preferencias. Pero sí que merece la pena el cambio. Es una fuente sensacional, de muy fácil lectura y de una muy buena apariencia.
  • En general el sistema va más fluido. No es un cambio radical pero sí que se nota en ciertas partes.
  • El menú de sonido que integra Rhythmbox (entre otros) está bien. No es que sea la panacea pero está bien.
  • He aprovechado para instalar Chromium (Google Chrome para Linux) desde su repositorio oficial y me ha dado un error al cargar la librería libmoon. Este librería es la encargada de dar soporte al navegador para Moonlight, la versión de Silverlight de Microsoft para Linux. Para solucionarlo simplemente desinstaladla. De hecho, desinstaladla.
  • Además, también he instalado Cardapio, un sustituto del menú principal de Gnome bastante bueno que se parece al de Windows 7 (sí, he dicho Windows…). Pero lo interesante es que puedes buscar como en Spotlight para lanzar aplicaciones, con lo que casi seguro prescindo de Gnome Do (aunque todavía estoy probándolo).
  • El único problema que he notado es que el calendario y ubicaciones que salen cuando haces clic en el reloj de la barra de tareas sale a la derecha del todo de la pantalla pero a media altura, no pegado a la barra de tareas. Y el caso es que todavía no he visto quejarse a nadie, así que no se si seré yo sólo (aunque me ha pasado en dos equipos).

Resumiendo, la tipografía nueva es sensacional y se agradece en la lectura y el sistema va más fluido en general, así que aunque esta versión no es LTS (tres años de soporte), sí que merece la pena el cambio, así que, ya sabéis ;) .

Discos duros tradicionales vs. discos duros SSD

Ya he comentado algo de los discos SSD, pero ahora quiero comparar sus características:

Disco duro normal Disco duro SSD
Capacidad 2 TB 160 GB
€/GB 0,7 €/GB 3 €/GB
Velocidad de transferencia mantenida 150 Mb/s (aprox.) 250 Mb/s (aprox.)
Latencia lectura aleatoria 8,5 ms 0,065 ms (65 µs)
Latencia escritura aleatoria 9,5 ms 0,085 ms (85 µs)
Consumo inactivo 6,39 W 0,075 W
Consumo activo 9,23 W 0,15 W
Tasa de errores de lectura 1 en 1014 bits 1 en 1016 bits

Que los discos duros SSD son el futuro no tiene discusión; y que serán, probablemente, los fabricantes de memorias en lugar de los actuales fabricantes de discos duros los que se lleven el gato al agua.

De hecho, como se puede apreciar en la tabla, de momento sólo el precio y la capacidad es lo que no hace a estos discos competitivos, mientras que cuanto más se avance en el tiempo, mejores capacidades y precios conseguiremos, con lo que o la tecnología actual da un salto de gigante en algún sentido (o bien en capacidades o bien en velocidades) o está avocada a la desaparición.

Yo ahora mismo ya me estoy planteando tener un disco duro SSD para el sistema y otro normal para datos. Y vosotros ¿qué opináis?

Llamadas a métodos protegidos desde clases externas en C++

Seguro que esta solución ya está implementada por ahí pero yo no la he encontrado.

Para ponernos en antecedentes, tenemos una clase Thread en C++ que representa hilos de ejecución. Esta clase tiene un método execute() que es el que realmente ejecuta el hilo. De esta se puede heredar para implementar dicho método y que este se ejecute en un hilo independiente. La clase Thread cuenta con métodos protegidos (protected) para que sólo los usen las clases derivadas.

Pero, además de derivar la clase Thread, esta clase tiene una clase anidada llamada Thread::Worker que también se puede derivar con la ventaja de que se pueden pasar muchas instancias de Thread::Worker a una sola instancia de la clase Thread para que las ejecute.

El problema surge cuando desde la clase Thread::Worker, al igual que desde las subclases de Thread, se desea acceder a los métodos protegidos (que, en teoría, son sólo para ayudar en la funcionalidad de las clases derivadas). Inicialmente esto no es posible ya que no se puede acceder a métodos protegidos de una clase si no es desde la propia clase o desde clases derivadas, no importa si son clases anidadas, a efectos de protección, son como clases externas.

Con algunas omisiones de código, la implementación de las clases es la siguiente:

/* Clase Thread (gestión de hilos) */

class Thread {
[...]
public:

/* Clase Worker (tareas que se ejecutan en los hilos) */

class Worker {
protected:
Thread * const getOwnerThread() const;
public:
virtual void execute();
[...]
};

private:
Worker* _worker;
[...]
protected:
bool isThreadRunning();
virtual void execute();
[...]
public:
Thread(Worker* worker) : _worker(worker) {
// Al añadir el Worker que asigna el hilo al que pertenece
_worker->_owner = this;
}
[...]
[...]
};

/* Clase MyThread derivada de Thread */

class MyThread : public Thread {
protected:
virtual void execute() {
while(isThreadRunning()) { // llamada correcta porque esta función es protegida en la clase padre
// hacer las cosas del hilo
}
}
};

/* Clase MyWorker derivada de Thread::Worker */

class MyWorker : public Thread::Worker {
protected:
virtual void execute() {
while(getOwnerThread()->isThreadRunning()) { // llamada incorrecta porque esta función es protegida en la clase Thread, que no es la clase padre
// hacer las cosas del hilo
}
}
}

/* Función de entrada de la aplicación */

int
main() {
MyThread* mt = new MyThread(); // correcto
Thread* t = new Thread(new MyWorker()); // incorrecto, no se pueden llamar a funciones protegidas desde fuera de la clase
return 0;
}

La funcionalidad deseada es que la clase Thread::Worker se comporte como la clase Thread cuando se hacen clases derivadas de ella, para poder usar la funcionalidad de gestión de la clase Thread desde la clase Thread::Worker (las funciones protegidas).

Pero al compilador no le gusta que se llamen funciones protegidas desde clases externas aunque sean anidadas.

La solución pasa por crear un puntero a método en la clase anidada que sea asignado a la función que hay que ejecutar. Cuando la instancia de la clase Thread::Worker es añadida a la instancia de la clase Thread, esta última asigna las direcciones de memoria de sus métodos a las variables internas de la clase Thread::Worker, con lo que una llamada mediante dichos punteros funcionará sin problemas y ejecutará el método protegido de la clase Thread desde la clase externa Thread::Worker.

La implementación sería, más o menos de la siguiente forma:

class Thread {
[...]
public:
typedef bool (Thread::*ThreadMethod1)();

class Worker {
[...]
private:
ThreadMethod1 _isThreadRunning;
protected:
bool isThreadRunning() {
return (getOwnerThread()->*_isThreadRunning)();
}
[...]
};

Thread(Worker* worker) : _worker(worker) {
_worker->_owner = this;
_worker->_isThreadRunning = &Thread::isThreadRunning;
}

[...]
}

Con esto se consigue que la clase Thread::Worker se comporte, a efectos de derivación de clases, como si se derivase de la clase Thread. Hay que tener en cuenta que las clases derivadas de la clase Thread::Worker siempre se tienen que añadir a una instancia de la clase Thread para todo funcione correctamente.

Como es bastante difícil interpretar código fuente desde esta lectura, he preparado una pequeña aplicación en C++ para mostrar el funcionamiento de este tipo de solución.

Espero que esto sirva para alguien a parte de mi. Y si lo encontráis por algún otro sitio me lo comentáis, porque como he dicho al principio, seguro que no soy el primero en hacerlo.

Máquinas virtuales y smartphones

Resulta que dicen que las máquinas virtuales estaban bien en los smartphones antiguos ya que los procesadores que llevaban en la época no tenían memoria protegida, con lo que la propia máquina virtual la implementaba y se conseguía mucha seguridad en sus aplicaciones.

Pero, hoy en día, donde un procesador de muy bajo consumo es ya un sistema con mucha potencia y con todas las características de procesadores de ordenadores más grandes, el uso de máquinas virtuales es sólo un impedimento debido a su falta de rendimiento por el hecho de tener código intermedio y necesitar de dicha máquina virtual para ejecutar las aplicaciones.

El artículo comentado se centra en Android, el sistema operativo de Google para teléfonos inteligentes, pero se podría aplicar a cualquiera que usase máquina virtual, con lo que aboga por sustituirlas.

Pero ¿cómo después de tanto trabajo, de desarrollar una nueva máquina virtual, de la ingente cantidad de aplicaciones desarrolladas en Java, se van a parar los de Google a desarrollar otro lenguaje para hacer el sistema y las aplicaciones?

Para mi hay dos opciones:

  1. Usar Go, su propio lenguaje. Pero sería demasiado caro cambiar todo el sistema, todas las librerías y, sobre todo, implementar todas las aplicaciones de nuevo.
  2. Compilar las aplicaciones en Java a código nativo del procesador, que es lo que principalmente hace su copilador JIT.

Para mi la única opción viable sería la segunda y, como ya lo hace, pues la opinión del artículo no tiene demasiado fundamento. Además, la primera opción obligaría a que cada programador se preocupase de tener en cuenta todas las características de cada teléfono y procesador, mientras que con la opción dos, de ello se encargaría el propio compilador.

Por ejemplo, al iPhone no le hace falta, porque usa un hardware muy limitado (vamos, es en todos los equipos el mismo) mientras que Android está pensado para correr en multitud de hardware, y no sólo en teléfonos, sino también en tablets, electrodomésticos,…

El único problema es que con Android haciendo esto me sale un analogía muy clara: Apple corre en hardware específico y Windows en hardware muy variado. Justamente como hace iOS y Android.

Optimizando sitios Web

Muy buen artículo de Ricardo Galli, el creador y mantenedor de Menéame, sobre cómo optimizar sitios Web.

Más o menos viene a decir:

  • Reducir al máximo tus CSS y Javascript; y no incluyas los que no necesites (o cárgalo más tarde).
  • Si es posible, carga los elementos bloqueantes (widgets,…) de forma paralela (hay muchas formas de hacerlo, por ejemplo usando iframes).
  • Maquetar de forma que se pueda ir “dibujando” la página antes de tener todo el HTML. Con esto se reducirá el tiempo de carga percibido por el usuario.
  • Usar dominios, no subdominios, diferentes para contenido estático.
  • Comprimir el HTML y usar sprites para las imágenes (siempre que dichos sprites no sean demasiado complejos).
  • Intercalar la generación del contenido con el envío, mandando antes las partes que primero se generan (como la cabecera) para ir “dibujando” la página en el menor tiempo posible.

De esto yo deduzco que el modelo MVC es una auténtica mierda a la hora de optimizar sitios Web: lo que hace es procesar todo y luego generar y enviar el HTML al usuario, que es justamente lo que dice Ricardo Galli que es lento y que lo que realmente reduce el tiempo de carga percibido por el usuario es dibujar la página cuanto antes, aunque todavía no se halla generado completamente.

Mira que cosas, todos poniendo al MVC como la panacea y resulta que las pruebas dicen otra cosa… ¡Ains!