Lo estás haciendo mal

Todos recordarán el antennagate, cuando el diseño de antena exterior del iPhone 4 mostró un pequeño fallo: el usuario era capaz de puentear las antenas con su mano al agarrarlo, degradando la recepción hasta el punto de no tener señal en algunas ocasiones. El problema era gordo, aunque también es cierto que tampoco era para empezar la tercera guerra mundial como muchos quisieron hacer. Yo mismo he tenido el iPhone 4 y el fallo se convertía en problema básicamente en zonas de baja recepción; no quito peso al fallo, pero si a la publicidad que se le hizo.

Pero vayamos a lo que interesa, lo que dijo Steve Jobs al respecto: “Lo estás agarrando mal”. El meollo del asunto no fue que hubiera un error en el diseño, sino la gestión que se hizo del problema desde la empresa: ga-rra-fal.

Hace unos meses se hizo viral un vídeo (así como sus clones) titulado “10 cosas que estabas haciendo mal”. El vídeo en cuestión pertenece a un canal de hackings (trucos caseros), la gran mayoría muy útiles, por cierto.

Puse el ejemplo del iPhone 4 antes porque uno de esos “trucos” básicamente dice lo mismo: estás agarrando mal el brick. A todos nos ha pasado que salpicamos todo cuando se vierte la leche o el zumo desde un brick. Esto se debe a la turbulencia creada cuando el aire que entra en el envase se encuentra de frente con el líquido que sale. A continuación se puede ver el truco propuesto para evitar ese problema.

En resumen, se propone girar el envase de forma que el agujero de salida quede arriba en lugar de abajo (donde todo el mundo lo usa), permitiendo que el aire entre libremente sin crear turbulencia.

El problema está que esto no es un fallo de uso de parte del consumidor, que lógicamente pone la boca del envase lo más cerca posible del recipiente para maximizar la puntería (con la boca puesta como en el truco se hace más difícil acertar). El problema está en el diseño del envase que prioriza otros factores como volumen óptimo y almacenamiento frente a su uso, dejando como única salida el poner la boquilla en un lugar tan poco apto.

No es que “lo estés agarrando mal”, es que está mal diseñado. No es culpa del consumidor sino del fabricante. Y el vídeo no hace sino acentuar esa percepción de “inutilidad” del usuario al llamarlo algo que “estabas haciendo mal” en lugar de llamarlo un simple truco para compensar el fallo de diseño.

Esto ocurre en muchos otros ámbitos, incluido el mío profesional (programación). Creemos que es el usuario el que lo hace mal (aunque no faltan ejemplos) cuando nuestro trabajo, en su clímax, ¡es lograr que el usuario lo haga bien sin tener que explicárselo! Ya lo dice Jony Ive (CDO de Apple): “Pienso que nuestra meta es que tengas la sensación de que no hay diseño”, de que las cosas funcionan y ya, de que son intuitivas, de que tenían que ser así.

En este sentido me gustaría mostrar dos envases de los que compramos en casa. El de la derecha es el típico brick tetraédrico con la boquilla en una esquina (y su consiguiente turbulencia y derrame). El de la izquierda es de otra marca donde han querido evitar ese problema con un diseño mejorado: la forma en pico de la parte superior hace que la boquilla quede por encima del líquido durante el vertido, facilitando la entrada del aire y eliminando la turbulencia. Para evitar que la pérdida de resistencia colapse el envase al apilarlos, se agregó un tabique de cartón en el medio de los empaques de 6 unidades para absorber parte del peso. En términos de coste no sé cómo afectará, pero no es el producto más caro de su género y creo que han llegado a una solución más que buena.

OS X: crear DMG (servicio)

Como regalo de Navidad os dejo un servicio de OS X que he creado para crear un disco DMG a partir del contenido de un directorio (o si hay varios directorios seleccionados, creará un fichero por cada uno).

Para instalarlo basta con descomprimirlo y copiarlo al directorio ~/Library/Services (en Finder, abrir el menú Go (Ir) mientras se presiona la tecla de Opción (alt), y elegir Library (Biblioteca). Como veis, tengo mis sistemas en inglés, dejo el servicio con el nombre en ambos idiomas.

Descargar (español)

Descargar (inglés)

Si tenéis algún problema, dejad un comentario y procuraré resolverlo.

Optimización 90-10

Ya dicen que el 90% del tiempo de ejecución está en el 10% del código, y en situaciones como la que menciono hoy es muy patente.

En un código para leer un determinado tipo de fichero tenía la siguiente secuencia (la función completa es unas 7 veces más larga):

for (ii = 0; ii < 3; ++ii) {
 if (tokens[ii].empty()) {
 break;
 }
 elem.clear();
 boost::split(elem, tokens[ii], boost::is_any_of("/"));

 if (elem.empty()) {
 break;
 }
 a[ii] = stoi(elem[0]) - 1;
}

Este fragmento se repite unas 80000 veces en el fichero de pruebas (los ficheros más grandes pueden requerir más de 2 millones de iteraciones). La función contenedora ya estaba optimizada en términos de uso de memoria, creación de objetos temporales, rutas más probables, etc.

Aunque en la versión de despliegue la función es suficientemente rápida (0,45 segundos de media), en modo depuración se vuelve insoportablemente lenta, en torno a los 60 segundos.

Analizando el problema se ve que lo único importante es el primer elemento del vector, es decir, lo que va desde el comienzo de tokens[ii] hasta el primer carácter “/”, por lo que la función puede re-escribirse como sigue:

for (ii = 0; ii < 3; ++ii) {
 if (tokens[ii].empty()) {
 break;
 }

 int p = tokens[ii].find('/');
 a[ii] = stoi(tokens[ii].substr(0, p)) - 1;
}

En modo depuración ahora tarda 28 segundos: ¡50% menos!. En modo final la optimización es menos notable para ficheros pequeños, ya que la función de Boost en cuestión es mucho más eficiente en este modo. De todas formas, los tiempos han mejorado y ahora tardo menos en abrir mis ficheros para corregir errores.

Daemon-start-stop

Hoy estuve creando un servicio en Debian para iniciar automáticamente un pequeño servidor (el demoniodaemon en inglés) en la empresa. El proceso en sí es bastante sencillo, basta con copiar el fichero /etc/init.d/skeleton a /etc/init.d/<nuestro_daemon>, darle permisos de ejecución y modificar los valores correspondientes a nuestro demonio.

Detallo los puntos de “ensayo y error” en los que trabajé y que me parecen más interesantes. Al final del post dejo, para los curiosos, el servicio de arranque finalizado (he cambiado el nombre por motivos internos).

  • Si se pasan argumentos al ejecutable, lo más sencillo es invocar al mismo con la ruta absoluta.
  • Los argumentos deben ser lo último en la línea de comandos del daemon-start-stop, y no justo después del –exec (como pensaría uno de primeras). Ejemplo: daemon-start-stop –start –quier –exec $DAEMON_EXEC –test — $DAEMON_ARGS
  • Muchas veces queremos ejecutar el demonio como un usuario diferente (permisos, seguridad). En ese caso, se usa el parámatro –chuid [<user>][:<group>], siendo opcionales cualquier de ellos (y siempre los argumentos de ejecución del demonio al final, recordad esto).
  • El parámetro –background ejecuta el programa en segundo plano y no tenemos que preocuparnos nosotros de hacer el fork de nuestro proceso. Importante cuando el demonio se lanza durante el arranque, para no frenarlo.
  • Si nuestro programa no crear su pidfile podemos pedirle al sistema que lo haga por nosotros con la opción –make-pidfile. El pidfile es un fichero especial del tipo /var/run/<nombreproceso>.pid que únicamente tiene dentro el identificador de proceso, y que se utiliza para localizar procesos de forma rápida.

Más información sobre el daemon-start-stop.

Continue reading

OpenSSL y la intuición: exportando claves RSA

Pocas cosas hay menos intuitivas en este mundo que el exportar las claves RSA privada y pública en OpenSSL: de entrada uno piensa que son PEM_write_bio_RSAPrivateKey y PEM_write_bio_RSAPublicKey. Todo compila, las salidas son coherentes y parece que todo va bien, pero pronto uno descubre no hay manera de hacer que el programa no falle al usar la clave pública. El problema radica en que la función a utilizar es ¡PEM_write_bio_RSA_PUBKEY!

Una explicación a fondo de la diferencia entre ambas en http://dmiyakawa.blogspot.com.es/2013/03/pemwritebiorsapubkey-vs.html.

Sonido de arranque de los Mac

Este es un post clásico en el mundo de usuario de Macs y no pretendo añadir nada novedoso, simplemente comentarlo entre los seguidores de este blog.

El famoso chime de los Mac al arrancar es más un sonido de “diagnóstico”* que una característica esencial para el usuario. De hecho, por mi parte encuentro que algunas veces puede ser hasta molesto, no para uno, sino para los que están alrededor, por ejemplo si encendemos nuestro MacBook Air en una biblioteca, si nos despertamos antes que el resto de la familia y encendemos el iMac de la sala. Y es que el sonido de arranque tiene el mismo volumen que el ordenador cuando lo apagamos por última vez; imaginad que pasa si estabais viendo una película o escuchando vuestro disco favorito: la jefa de la biblioteca puede que nos traspase con la mirada al encender nuestro Mac.

La solución básica a este inconveniente: acordarnos de bajar el volumen o dejar el sonido apagado, en mute. Pero seamos honestos, no siempre nos acordamos, o nuestro sobrino fue el último en jugar Call of Duty y lo dejó a tope.

Existen utilidades que permiten desactivar el sonido de arranque, aunque por debajo lo que hacen casi todas es ejecutar la siguiente línea de comandos. Para los que no estéis familiarizados, abrid la aplicación “Terminal” en una cuenta de usuario con permisos de administrador y escribid la siguiente línea y presionad enter (se os pedirá vuestra clave):

sudo nvram SystemAudioVolume=%80

¡A disfrutar de un arranque discreto y silencioso!

* El sonido de arranque indica que los sistemas más básicos del ordenador se han inicializado correctamente y marca el punto en el que el resto del sistema operativo se ejecutará. Algunos diagnósticos técnicos requieren que en este momento se presionen determinadas combinaciones de teclas. Normalmente no hay ningún problema porque al sonido le acompaña el hecho de que la pantalla se enciende, pero para los más auditivos, podéis simplemente revertir al estado original ejecutando:

sudo nvram -d SystemAudioVolume