sábado, diciembre 13, 2008

Facebook publica su versión modificada de memcached

[Vía reddit] Facebook acaba de publicar su versión de memcached, el sistema de cachés genéricas más usado en aplicaciones web, tras hacer modificaciones para afrontar sus necesidades de rendimiento y escalabilidad. Las modificaciones principales han sido entre otras la eliminación de un buffer por conexión en favor de un pool, reducción de bloqueos innecesarios para un mejor rendimiento en máquinas multicore y el uso intensivo de UDP. El resultado final ha sido la posibilidad de gestionar 200.000 peticiones UDP por segundo con una latencia media de 173 microsegundos. Han subido los cambios a GitHub: facebook-memcached y esperan que los cambios sean incorporados al memcached oficial. Curiosamente hemos hablado recientemente por aquí de memcached en Un vistazo al interior de memcached.

Actualización: Olvidé mencionar que habían toqueteado el kernel :/ JAM hace muy bien resumen de esos apaños
Parece relevante también comentar lo que dicen en High Scalability sobre el memcached de Facebook y las conclusiones que se pueden sacar:
A summary of potential strategies:
  • Profile everything. Problems are always specific. The understanding of the problem must be specific. The fix must be specific.
  • Burn profiling into your regression tests. Detect when and where performance tanks as a regular part of your build.
  • Use resources in proportion to what grows slowest. This requires multiplexing, but at least your resource usage is more predictable and bounded.
  • Batch work. When you have the CPU do all the work you possibly can in the quantum or the whole system grinds to a halt in processing overhead.
  • Do work and maintain resources per task. Otherwise locking for shared resources takes more and more time when there's less and less time to do the work that needs to be done.
  • Change algorithms. Sometimes you simply need to do things differently. Tweaking will only get you so far.


La misma entrada y más comentarios en Facebook publica su versión modificada de memcached en barrapunto

martes, diciembre 09, 2008

El código fuente como documento definitivo del diseño

Se trata, cómo no, de Code as Design: Three Essays by Jack W. Reeves. Son unos ensayos muy ilustrativos de la naturaleza particular del desarrollo de software, que por usar la palabra diseño de un modo no usual acaban resultando muy polémicos, pero a mi me parecen más bien esclarecedores. Se recomienda leer enteros antes de opinar :P

Suelo aprovechar cualquier mención para volver a enlazarlo y esta vez ha sido Ricardo Galli en "Los problemas derivados del abuso de las analogías" quien me da la oportunidad de volver a hacerlo :)

Se ha hablado de ellos por aquí en El código fuente visto como diseño y POO, el código como diseño y más cosas.

La misma entrada y más comentarios en El código fuente como documento definitivo del diseño en barrapunto

jueves, noviembre 27, 2008

Memoria transaccional ¿Sólo un juguete para investigadores?

En Software Transactional Memory: why is it only a research toy? de Calin Cascaval et al. se repasan algunas de las razones por las que, tras unos años de investigación, la memoria transaccional no ha dado el salto para ser usada en otros entornos. Se nombran sobre todo razones de rendimiento, de usabilidad (semántica confusa) y de interacción con sistemas que no la usan. No obstante no todo el mundo se da por vencido y por ejemplo Larry O'Brien escribe en Cascaval et al.'s skepticism on transaction memory una visión un poco más optimista indicando que aún queda espacio para la investigación y la optimización. ¿Acabaremos usando STM o morirá antes de nacer?

La misma entrada y más comentarios en Memoria transaccional ¿Sólo un juguete para investigadores? en barrapunto

viernes, noviembre 21, 2008

Universos paralelos, cuerdas y divulgación científica

Hay un debate, apasionante y por supuesto no resuelto acerca de cómo divulgar la ciencia, de cómo equilibrar la precisión de lo que se cuenta con lo entretenido de la forma.

Pues bueno, a mi me parece que esto en la divulgación de la ciencia más básica es especialmente importante. Suele uno leer en periódicos, revistas y últimamente en blogs artículos sobre la teoría de cuerdas y sobre universos paralelos sin hacer la menor mención acerca de lo especulativo del asunto. Por eso me ha gustado mucho un apunte de Clifford Johnson en el que lo explica estupendamente (vía Not Even Wrong de Peter Woit) Habla de su participación en un programa de divulgación sobre universos paralelos. Cito y "traduzco":
Para ser sincero estoy un poco preocupado porque es un tema que puede ser aprovechado muy fácilmente por chiflados por personas sensatas por igual, y es, de diversos modos, alimento para mucha charlatanería y sinsentido místico. Cualquier programa de ciencia sobre este tipo de material tiene que ser doblemente -triplemente- cuidadoso, para no dar a la gente una excusa para decir que "los científicos han comprobado esto".

¿Por qué estoy un poco preocupado? Bueno, yo no he visto un montaje final del espectáculo y y no me quiero exceder, pero un primer montaje en bruto que he podido ver sufre de un problema que estos programas pueden tener a veces: un conjunto de científicos en activo muy cuidadosos al hacer comentarios acerca de lo que se conoce, de lo desconocido, de lo que es probable y de lo que es poco probable, y así sucesivamente, y después mucha de esa cautela puede ser socavada por la intercalación de sus observaciones con fragmentos del favorito de cualquier cineasta de la física documental, del tipo que puede ser invocado para decir cosas salvajes y maravillosas - Michio Kaku.

Por favor, no me malinterpreten. No tengo nada en contra de Kaku, me parece un muy buen tipo, y creo que ha realizado un excelente y divertido trabajo para este tipo de programas (tales como el documental sobre Einstein de la otra noche ), pero hay momentos en que sus observaciones más, ermmm, emocionadas e imprudentes pueden ser colocadas en un lugar en el programa que no ayuda en nada a ser prudente con la ciencia. A menudo (quizás siempre?) no es su culpa, un director que no se da cuenta de cómo un detalle puede ser crucial llega a un punto en el que debe elegir entre la inserción de:

* (a) un fragmento de alguno de nosotros que tratamos de ser cuidadosos y no hacer declaraciones equivocadas y/o sensacionalistas, y
* (b) un fragmento un distinguido caballero con un entusiasmo contagioso, agitando sus brazos y diciendo cosas que suenan maravillosas

...Y 99 veces de cada 100 va a elegir la opción (b) si ninguna de las personas de (a) están ahí para orientarle. Esta es, por supuesto, la razón por la que siempre espero [...] que estos espectáculos se realicen de un modo colaborativo entre científicos y cineastas[...]


Hace ya unos días, bastante relacionado con esto, rvr en un par de entradas, El nivel de la divulgación científica (I) y El nivel de la divulgación científica (II) repasaba el mismo problema a la inversa, con la tesis de que debe haber sitio también para la divulgación más superficial.

Sin estar en desacuerdo con esta tesis si debo reconocer que me gustaría que hubiese menos confusión entre ciencia aceptada y especulación. Creo que la diferencia debería ser subrayada por todo el mundo y que conceptos como Método Científico, Reproducibilidad y Falsabilidad tuviesen mayor eco. Cuestión de educación, supongo.

Y bueno, por acabar y por ser algo constructivo recomendar una entrada sobre el tema en Ecos del futuro (que he conocido hace poco, muy bueno): La interpretación de los universos múltiples, en la que sí queda claro lo que es especulativo y lo que no, y porqué.

La misma entrada y más comentarios en Universos paralelos, cuerdas y divulgación científica en barrapunto

lunes, noviembre 17, 2008

Varios sobre concurrencia y rivales de GCC

Ración de varios variados:

Movidillo parece el micromundo de los compiladores libres, veremos si la competición les sirve para mejorar a todos ellos.

La misma entrada y más comentarios en Varios sobre concurrencia y rivales de GCC en barrapunto

martes, noviembre 11, 2008

Publicado LLVM 2.4

Acaba de ser anunciada la versión 2.4 de LLVM (Low Level Virtual Machine). A LLVM y su compilador asociado clang se les ha querido ver como un competidor de GCC, en parte por su licencia BSD, por su diseño más modular, por su novedoso enfoque de las optimizaciones y por el apoyo de Apple. La versión 2.4 trae una buena cantidad de novedades entre las que destacan la mejora en la generación de código, compilación más rápida y soporte para la arquitectura PIC16. En el propio anuncio se apunta a una serie de presentaciones y vídeos para saber más. [Vía reddit]


La misma entrada y más comentarios en Publicado LLVM 2.4 en barrapunto

lunes, noviembre 10, 2008

Un vistazo al interior de memcached

Leo en El valle del Viento Helado un artículo acerca de la arquitectura interna de memcached. memcached es un sistema de cachés genéricas muy usado en aplicaciones web. En el artículo se repasa tanto la elección de libevent como sistema de gestión de eventos sobre descriptores de fichero, el uso de funciones de entrada/salida no bloqueantes y sobre todo una gestión de memoria basada en un slab allocator. Contiene además enlaces con más información sobre el tema aunque como siempre la información última está en el código fuente.

La misma entrada y más comentarios en Un vistazo al interior de memcached en barrapunto

miércoles, octubre 29, 2008

Completado el borrador de C++0x

Como comenta Herb Sutter en su blog, se ha publicado el borrador (pdf) de C++0x que se pasará a la votación internacional. Creo que es una buen noticia para todos los usuarios de C++, porque como dicen en reddit, map<string, string>::iterator, tu larga década de terror se ha acabado :) Además, y no menos importante, toda una serie de características como rvalues, lambdas, conceptos, librería de operaciones atómicas, librería de threads, soporte para expresiones regulares...

Y uno de los arreglos más importantes, el modelo de memoria. Del borrador:
The fundamental storage unit in the C++ memory model is the byte. A byte is at least large enough to contain any member of the basic execution character set and the eight-bit code units of the Unicode UTF-8 encoding form and is composed of a contiguous sequence of bits, the number of which is implementationdefined.
The least significant bit is called the low-order bit; the most significant bit is called the high-order bit. The memory available to a C++ program consists of one or more sequences of contiguous bytes. Every byte has a unique address.
[...]
A memory location is either an object of scalar type or a maximal sequence of adjacent bit-fields all having non-zero width. [...] Two threads of execution can update and access separate memory locations without interfering with each other.

Enhorabuena a los premiados. Ahora falta que los implementadores hagan su trabajo. MS VC++ parece que va avanzando para llegar a VC++2010. (Estoy seguro que la coincidencia del borrador de C++0x y la publicación este post en el blog de VC++ no es casual...) gcc, aunque más lento, también va avanzando y ya se pueden probar algunas características.

La misma entrada y más comentarios en Completado el borrador de C++0x en barrapunto

martes, octubre 14, 2008

Las matemáticas 'innatas' en el ser humano

Nota: Para los lectores de PlanetaCódigo. Esta es una entrada sobre ciencia y matemática y no sobre programación. Si no te interesa no tienes más que saltártela :)

Ayer en la cola de pendientes de menéame leí una noticia demasiado escueta que hablaba de niños aborígenes australianos capaces de contar sin números. Rebuscando un poquito encontré la nota de prensa original, que por lo menos es un poco más explicativa.

Y es que este tipo de estudios sacan resultados que al menos a primera vista pueden resultar antiintuitivos: nuestra capacidad matemática parece estar más allá de nuestra capacidad verbal. O dicho de otro modo, parece que la evolución nos ha hecho más viables con un pequeño coprocesador matemático, aparentemente no específica a nuestra especie porque, como decía otro estudio de hace un tiempo, los monos tienen células dedicadas a contar.

También acerca del equipamiento matemático del ser humano se oyó hace un tiempo (quizás Log or Linear? Distinct Intuitions of the Number Scale in Western and Amazonian Indigene Cultures) que las escalas logarítmicas pueden resultar más intuitivas que las lineales a un humano sin formación cultural y/o matemática.

Me parecen muy reveladoras este tipo de investigaciones ¿Conocéis más publicaciones y/o artículos de este estilo? ¿Qué opináis de la relación entre el ser humano y la matemática?


La misma entrada y más comentarios en Las matemáticas 'innatas' en el ser humano en barrapunto

martes, septiembre 30, 2008

Reescribiendo una cola sin bloqueos

Herb Sutter se quejó en Lock-Free Code: A False Sense of Security(*) de lo difícil que es escribir código sin bloqueos incluso para expertos y lo hizo poniendo un ejemplo de una implementación errónea de una cola. Ahora ha retomado el tema para demostrar como sería una implementación correcta en Writing Lock-Free Code: A Corrected Queue.

(*) Hablamos de este artículo en Varios sobre concurrencia: los peligros de 'Lock-Free' y JVM


La misma entrada y más comentarios en Reescribiendo una cola sin bloqueos en barrapunto

miércoles, septiembre 03, 2008

Un vistazo al código de chrome

Una de los aspectos que más me ha interesado de chrome es su arquitectura, aquello de ejecutar un proceso por pestaña para dejar que el sistema operativo haga unos de los trabajos para los que está diseñado: aislar procesos independientes y gestionar la memoria. Entonces he decidido a echarle un vistazo al código, que para eso está ahí ;)

Lo primero que hay que decir es que el IPC se hace mediante pipes con nombre, como parece que debería ser, aunque sea una de esas características de los SO en decadencia, o por ser más preciso, menos de moda. El documento que describe el IPC en chromium es escueto así que he hecho una inmersión en el código, aunque superficial, sobre todo para encontrar detalles de implementación. Los mensajes se gestionan con una clase ChannelProxy (definida en src/chrome/common/ipc_channel_proxy.h) Las pipes se gestionan con la clase Channel (mismo directorio, icp_channel.h) Curiosamente está implementada llamando directamente a la API de win32, ella misma hace de capa de abstracción y de interfaz a implementar.

Otro aspecto que me llamaba mi curiosidad es la serialización de los mensajes y lo hacen especializando Read, Write y Log de ParamTraits (en src/chrome/common/ipc_message_utils.h) a la estructura o tipo de dato en concreto. La serialización los tipos de datos primitivos están en Pickle (src/base/pickle.cc), que es base de Message (src/chrome/common/ipc_message.cc)

Como uno de mis intereses es la multiplataforma he buscado como solucionaban la gestión de threads y procesos. Acerca de los threads se han creado un interfaz sencillo en src/base/platform_thread.h con dos implementaciones, platform_thread_win.cc y platform_thread_posix.cc. Cabe destacar el siguiente comentario de este último fichero:

The POSIX standard does not provide for naming threads, and neither Linux
nor Mac OS X (our two POSIX targets) provide any non-portable way of doing
it either. (Some BSDs provide pthread_set_name_np but that isn't much of a
consolation prize.)
Que creo que dice algo de su política y no se si gustará mucho a los BSDros... El buceo por la gestión de procesos ha sido un poco decepcionante porque sólo existe un process_util::LaunchApp que básicamente llama a un CreateProcess de nuevo de la API de win32. Seguramente han ido pensado previamente en los interfaces y solo están a falta de la implementación en distintas plataformas, pero da una sensación de trabajo a medias, quizás reflejo de un proyecto real (en contraposición de una prueba de concepto) saliendo de su fase temprana. Cabe preguntarse cuanto les costará implementar y testear esas funcionalidades... Ah, calla, que somos millones los betatesters.

(Actualización) Un tímido buceo en src/net/base me dice que el código de red es muy windowscéntrico, con muchas inclusiones de winsock2.h, incluso en cabeceras :/ aún les queda trabajillo por delante. Los interfaces de las clases parecen bien definidos y eso les ahorrará trabajo, pero es bien sabido que un interfaz no es válido y está maduro hasta que no funciona en todas la plataformas a las que se dirige...

Uhmmm, acabo de ver un enlace de donde se baja las fuentes que se suponen del desarrollo en linux. Seguiremos informando, pero ya sólo esta distinción de obtención de fuentes no da buena espina...

(Actualización2)Ya lo he bajado pero es básicamente el mismo código. Me debo estar perdiendo algo, porque sino está muy verde...

(Actualización3) Leo en kriptópolis que Chrome usa CSP en lugar de PKCS :O No hay rastro de ningún PKCS (11 por ejemplo, el que usa El DNIe) ni de NSS (la librería criptográfica de Netscape que usa firefox) Me temo que la portabilidad no se la han tomado en serio o quieren que se la hagan otros... Alucino.(fin actualizaciones).

Desde el punto de vista gráfico he visto que tiene muchas de dependencias de la WTL, lo que dice también poco de la portabilidad en primera instancia. Ya veremos a ver como solucionan ese temilla, aparentemente con lo que figura en src/base/gfx. No obstante hay pocos restos de WTL en los .h, así que quizás ya van bastante adelantados... Misma sensación de a medias.

Seguro que habría mucho más que decir, sobre todo del diseño e implementación de JavaScript, V8 pero creo que se escribirá de eso suficiente (ya se ha escrito mucho de su eficiencia, veremos cuanto hay de hype) y de temas relacionados como la ejecución de ruby sobre V8... Ains que bien se lo hace google ;)

La misma entrada y más comentarios en Un vistazo al código de chrome en barrapunto

viernes, agosto 22, 2008

(Aún otra) entrevista (más) a Stroustrup sobre C++0x

Veo, vía Slashdot, aún otra entrevista más a Bjarne Stroustrup sobre C++0x: The State of the Language: An Interview with Bjarne Stroustrup por Danny Kalev. La verdad es que me ha parecido mejor que la media y diría que es un buen repaso introductorio a esta nueva estandarización de C++. (Las entrevistas a Stroustrup son ya un clásico en esta bitácora :) )

La misma entrada y más comentarios en (Aún otra) entrevista (más) a Stroustrup sobre C++0x en barrapunto

miércoles, agosto 13, 2008

Varios sobre concurrencia: los peligros de 'Lock-Free' y JVM

Ración de varios sobre concurrencia:La misma entrada y más comentarios en Varios sobre concurrencia: los peligros de 'Lock-Free' y JVM en barrapunto

lunes, agosto 04, 2008

Sobre los aspectos estéticos de la programación

Jonathan Edwards en una entrevista en un webzine de reciente creación, Wheel Me Out, ha tocado uno de los temas que le hacen a uno seguir teniendo pasión por esto de la programación. Cito (traduciendo) lo que más me ha gustado(*):
Veo la programación como una actividad profundamente creativa, pero no exactamente como una forma de arte en el sentido usual del término. Los programas no expresan sentimientos humanos entonces no creo que tengamos derecho a llamarlos arte. Los programadores desarrollan cierto sentido estético que hace de un programa bien diseñado un programa bonito, pero es una clase de belleza fría y matemática. De hecho sostengo que la estética puede ser una mala guía para los programadores.

[...]

La belleza de la programación es intelectual. Es el placer que sentimos cuando un problema complejo de pronto se revela bastante simple visto desde la perspectiva adecuada. Esta sensación de profundidad es la que motiva a algunas personas a ser matemáticos o físicos. [...] Programar es también un tema de poder. Es la lucha del programador para crear orden del caos. Somos como pequeños dioses en nuestros universos de bolsillo. Estamos limitados solo por nuestra imaginación. Desgraciadamente nuestra imaginación es más limitada de lo que nos gusta admitir, lo que en mi opinión es el trágico defecto de la programación, aunque esta opinión no es compartida ampliamente.

Obviamente, se resalta el aspecto más sublime, cuando todos los que nos dedicamos a esto sabemos que el día a día puede ser bastante distinto, bastante poco elevado. No obstante, en lo que a mi respecta me sigue enganchando la posibilidad de simplificar lo complejo, de encontrar una buena solución y el poder de hacerlo en el universo de bolsillo :)

(*)Pedí permiso para traducirlo íntegramente y me pidieron la dirección del blog. No me contestaron después. Espero que me ampare el derecho de cita...(Actualización: desde Wheel Me Out me han dado permiso para traducirlo, pero creo que con el extracto ya traducido será suficiente. Gracias al webzine de todos modos por el permiso y por generar la entrevista)

La misma entrada y más comentarios en Sobre los aspectos estéticos de la programación en barrapunto

martes, julio 29, 2008

Varios sobre D

Se acumulan cosillas sobre D que me he ido guardando, así que, haciendo un dump:

La misma entrada y más comentarios en Varios sobre D en barrapunto

sábado, julio 12, 2008

Bugs antiguos y moralejas

A veces coinciden en el tiempo sucesos de los que se puede sacar una especie de moraleja común y la serie reciente de errores con muchísimos años de historia me parece una de ellas. La grave vulnerabilidad en el protocolo DNS, que ha hecho actualizar a toda internet ha sido el ejemplo más claro, pero no el único y las tres historias son muy instructivas...

El primero, hace unos dos meses detectó un bug de 25 años en los BSD, en seekdir()[1] en el que, en algunos casos seekdir() no daba el resultado correcto. Como comentan en la propia historia, un bug muy difícil de encontrar y muy fácil de corregir.

El segundo es un bug con 33 años de antigüedad en yacc, encontrado por Otto Moerbeek[2], quien curiosamente también ha tenido un papel muy relevante en el descubrimiento del bug anterior.

El último es más peliagudo: problemas de diseño en el protocolo DNS permitían a un atacante hacer DNS cache poisoning de modo más efectivo que anteriores técnicas[3]. El descubridor de la vulnerabilidad, Dan Kaminsky, hace comentarios muy interesantes al respecto (las negritas son mías):
DJB was right. All those years ago, Dan J. Bernstein was right: Source Port Randomization should be standard on every name server in production use.

There is a fantastic quote that guides a lot of the work I do: Luck is the residue of design. Dan Bernstein is a notably lucky programmer, and that's no accident. The professor lives and breathes systems engineering in a way that my hackish code aspires to one day experience. DJB got "lucky" here — he ended up defending himself against an attack he almost certainly never encountered.

Such is the mark of excellent design. Excellent design protects you against things you don't have any information about. And so we are deploying this excellent design to provide no information.


Es muy curioso seguir los enlaces, porque la historia del parche es muy poco común y puede enseñar de la parte técnica y de la parte social del ecosistema internet.

Creo que la moraleja de todos ellos es clara, sobre todo leyendo las historias. Pero por recopilarlas (aún a riesgo de decir obviedades):

[1]Un buen resumen en castellano, con interesantes conclusiones en El valle del viento helado "Un bug de 25 años en los BSD: seekdir()"
[2]Comentado en barrapunto en Corregido un error de hace 33 años en Yacc
[3]Comentado en barrapunto en Un agujero de seguridad en el protocolo DNS causa gran alarma
[4]Me ha llamado la atención el caso de un bug casi trivial en el en interop de .NET desde C++ nativo que lleva la menos seis años sin ser resuelto. No es el único caso ni el más grave ni la única empresa donde sucede eso, por supuesto. Sólo me ha parecido un ejemplo ilustrativo...

La misma entrada y más comentarios en Bugs antiguos y moralejas en barrapunto

jueves, julio 03, 2008

Parámetro "lo digo en serio" en Content-Type para IE8

Pues esa es la propuesta que se puede leer en el blog de desarrollo del Internet Exporer 8: añadir un authoritative=true al Content-Type, o sea, fiarse de cual es el tipo de contenido que está proporcionando el servidor, pero sólo si lo dice en serio...

Por supuesto esta propuesta ha levantado bastantes reacciones. Unos, como Sam Ruby en authoritative=true, lo ven desde el punto de vista pragmático como un mal menor al evitar content-sniffing. Otros, como Daniel Stenberg en This is the type and I mean it se lo toman con humor. Más en las listas de la w3c y en reddit: Microsoft's "I mean it" content-type parameter

La misma entrada y más comentarios en Parámetro "lo digo en serio" en Content-Type para IE8 en barrapunto

jueves, junio 26, 2008

Lenguajes de la A a la Z: Entrevistas

En Computerworld están publicando extensas entrevistas acerca de un montón de lenguajes de la A a la Z. La verdad es que había visto alguna referencia, pero después de la de Stroustrup (y sus repercusiones en Slashdot y reddit) le he prestado más atención y parece que pueden ser bastante curiosas. También en LtU - The A-Z of Programming Languages prometen seguirles la pista, enlazando a su vez a las pasadas:Actualización: La entrevista a Stroustrup también se comenta en la portada de barrapunto

La misma entrada y más comentarios en Lenguajes de la A a la Z: Entrevistas en barrapunto

viernes, junio 20, 2008

Propuesta para introducir C++ en gcc

Volviendo al tono un poco menos noticioso de esta bitácora, me gustaría referenciar la propuesta de Ian Lance Taylor de permitir determinadas características de C++ en el código de gcc, sobre todo aquellas que permiten hacer el código más compacto y mantenible. Nombra explícitamente STL, polimorfismo y punteros inteligentes en contraposición a la recolección de basura que se usa en gcc. Hay que hacer notar que la propuesta debería ser aprobada (no sin antes haber pasado por el adecuado flame C vs C++) aunque Ian propone crear una rama gcc-in-c++ para experimentar.

Me ha parecido una propuesta muy razonable, con una exposición muy clara de lo que se ganaría con el cambio. Es precisamente el (moderado) uso de las características de C++ lo que me ha parecido más reseñable. C++ es un lenguaje grande y no todas son adecuadas a todos los problemas, con lo que hay veces que es sano delimitar como se usa. Esto da lugar no obstante a estándares de codificación con casi obsesivo nivel de detalle, pero de los que se puede aprender si se lee con atención crítica.

Por cierto que para evitar dependencias indeseadas (y que C++ se convieta en el caballo de troya que potencialmente es) se propone un enlazado estático con la libstdc++. No sé que opinará Ulrich Drepper.

Se puede leer más sobre el tema en el propio blog de Ian , en reddit (posteado por un servidor), en LWN y (con poco éxito de crítica y público) en menéame.

La misma entrada y más comentarios en Propuesta para introducir C++ en gcc en barrapunto

miércoles, junio 18, 2008

martes, junio 17, 2008

code_swarm: visualización del desarrollo de proyectos libres

Acabo de ver vía slashdot (y me lo perdí en reddit) un proyecto de visualización del desarrollo de proyectos libres: code_swarm. A partir del control de fuentes genera vídeos en los que se puede seguir la evolución histórica del desarrollo de Python, PostgreSQL, Eclipse o Apache httpd. El autor promete además liberar el código para que cualquiera lo pueda aplicar a otros proyectos. Bonito, hipnótico y hasta revelador...

Actualización: Ya ha liberado el código en codeswarm - Google Code. A disfrutar...

La misma entrada y más comentarios en code_swarm: visualización del desarrollo de proyectos libres en barrapunto

miércoles, junio 04, 2008

Elizabeth Loftus y los recuerdos falsos

Vía El psicoanálisis ¡vaya timo! de El cerebro de Darwin me he encontrado con los estudios de Elizabeth Loftus acerca de un tema tan atractivo como los recuerdos falsos. En particular hay un buen resumen en "Our changeable memories: legal and practical implications". Me quedo con la cita de Eduardo Galeano a modo de resumen (que no he podido encontrarla en castellano, la traduzco de la traducción :\)
La memoria nace cada día, brotando del pasado y contraponiéndose a él.


La misma entrada y más comentarios en Elizabeth Loftus y los recuerdos falsos en barrapunto

jueves, mayo 29, 2008

Varios sobre concurrencia: Lock-free en Java, STM vs locks y consejos

Varios sobre concurrencia (versión n)Pequeña nota sentimental: hoy hace cinco años que escribí mi primera bitácora en barrapunto y hace muy poquito yapw ha sobrepasado las 100 entradas. Casi no me lo creo, como pasa el tiempo...

La misma entrada y más comentarios en Lock-free en Java, STM vs locks y consejos en barrapunto

lunes, mayo 26, 2008

Firefox 3, SQLite, fsync, ext3 y otras abstracciones

Vía LWN leo un buen resumen de uno de los grandes problemas de Firefox 3 en linux: es fácilmente observable como dicho navegador se congela durante bastantes segundos hasta que vuelve a responder. Es debido, al parecer al (ab)uso de las actualizaciones en SQLite, que usa fsync, que a su vez tiene un más que pobre rendimiento en ext3. La buena noticia es que todos ellos están tratando de mejorar.

A la vez que me parece un enlace interesante del que se pueden aprender bastantes cosas y un ejemplo de la tesis que manejaba el otro día en ¿Demasiadas capas de abstracción?: Los sistemas tienden a ser cada vez más complejos, y esto genera algunos problemas, pero la tendencia no tiene marcha atrás... En este caso además se le une la complejidad de la portabilidad. El mismo código usa implementaciones distintas de las mismas abstracciones, con lo que el testeo se complica enormemente y probablemente sólo es viable en un escenario de software libre.

La misma entrada y más comentarios en Firefox 3, SQLite, fsync, ext3 y otras abstracciones en barrapunto

martes, mayo 20, 2008

¿Demasiadas capas de abstracción?

Vuelve otra vez uno de mis temas favoritos, el de la complejidad inherente y creciente de los sistemas de información, tratado esta vez por Ian Lance Taylor en Layered Programming. Me permito citraducir un párrafo, un poco al vuelo:
Cada vez es más difícil ser un experto en sistemas. Cuando aprendí a programar, era posible entender todo tu programa, desde el código fuente hasta el código máquina. Sin embargo, cuando escribes una aplicación moderna en Ajax esto es se vuelve imposible. Hay demasiados intérpretes diferentes. Hay demasiado código ejecutándolo. Ni arreglarlo con un nuevo nivel base por encima del procesador (el navegador(?)) ayudaría. Todo esto nos conduce a una pérdida de rendimiento a veces notable y, lo que es a veces más importante, una perdida de seguridad.

No podemos volver atrás. Pero me pregunto si podremos confluir en un modelo de programación que pueda ser comprendido en su totalidad en todas sus capas. O si las cosas simplemente van a ser más complicadas cada vez.[0]

Y no sólo me permito la cita, sino que además respondo :) Y mi respuesta (que me perdonen Alvin y Heidi Toffler) es pesimista, en el sentido de que no hay vuelta atrás al idílico pasado en el era posible comprender completa, local y globalmente un sistema. La tendencia es la de más lenguajes, más plataformas y más capas, incluso dentro de los propios procesadores y nunca la contraria.

Pero no es por los ejemplos concretos que vemos a diario por que creo que esto va a seguir siendo así, sino por el trasfondo. Los sistemas de información van evolucionando unos sobre otros y rara vez se da el caso de retroceso de una paso evolutivo exitoso[1], lo que se conoce como Ley (o hipótesis) de Dollo[2] en evolución biológica, que nos vuelve a dar un ejemplo de uno de mis juegos mentales preferidos, el paralelismo entre sistemas biológicos e informáticos [3]. A quien mejor he leído referirse a este paralelismo es a Richard P. Gabriel en su Objects Have Failed y que explora de nuevo en Design Beyond Human Abilities (pdf)

No obstante, a pesar de la tendencia natural, creo que uno de los deberes de un diseñador, arquitecto, desarrollador, programador o comoquierallamársele es contener en lo posible la complejidad del sistema global [4]


[0] El primer comentario apunta, yo creo que con acierto, a "The Law of Leaky Abstractions" de Spolsky.
[1] Existen sistemas que tienen diversos enfoques o paradigmas, que yo asimilaría a distintas ramas evolutivas. La tesis de Dollo aplicada a los sistemas informáticos sería válida sólo en el progreso de una rama evolutiva. En diversas ramas evolutivas se pueden dar una tendencia y la contraria, claro...
[2] Hablé hace tiempo de esta ley en La ley de Dollo y los sistemas informáticos
[3] Otro ejemplo de dicho paralelismo podría ser el del monocultivo, del que escribí hace ya mucho en Los peligros del monocultivo y Los peligros del monocultivo (de nuevo)
[4] Conviene recordar un par de mantras clásicos: "Controlar la complejidad es la esencia de la programación de ordenadores" de Brian Kernighan y "Cualquier problema de computación puede ser resuelto con un nuevo nivel de indirección, excepto si el problema es que hay demasiados niveles de indirección" de David Wheeler (La exactitud de esta última es dudosa, pero me gusta esa versión)

La misma entrada y más comentarios en ¿Demasiadas capas de abstracción? en barrapunto

viernes, mayo 02, 2008

Varios sobre concurrencia: Erlang, MPI y C++0x

Varios rápidos sobre concurrencia;

La misma entrada y más comentarios en Varios sobre concurrencia: Erlang, MPI y C++0x en barrapunto

martes, abril 29, 2008

Generación automática de exploits aprovechando los parches

La idea, hay que reconocerlo, es buenísima: crear automáticamente el programa que explotará la vulnerabilidad que trata de solucionar un parche mediante la información del mismo parche. La generación se realiza a través de la comparación entre el programa parcheado y el original. El artículo que desarrolla las posibles técnicas es Automatic Patch-Based Exploit Generation is Possible: Techniques and Implications. Parece que la cosa últimamente va de diferencias binarias :) (como en Actualizando el kernel Linux sin reiniciar )

Más comentarios en Bruce Schneier: Reverse-Engineering Exploits from Patches, programming reddit: Automatic Patch-Based Exploit Generation y LtU: Automatic Patch-Based Exploit Generation.

Actualización: Como Apunta Drizzt en las publicaciones de la gente de bindiff se examina más detenidamente el tema de la comparación binaria. En la misma entrada Drizzt también aporta algún enlace más al respecto.

La misma entrada y más comentarios en Generación automática de "exploits" aprovechando los parches en barrapunto

lunes, abril 28, 2008

Entrevista a Mario Bunge

Nota: Si eres lector de planeta código y sólo te interesa el desarrollo, sáltate esta entrada. Pero es un enlace que me parece de interés general :)

Vía Cuchitril Literario me encuentro con una buena pero breve entrevista a Mario Bunge. En ella se dice de la filosofía de Heidegger:
[...] se aprovechó de la tradición académica alemana según la cual lo incomprensible es profundo.
[...] fenomenología, existencialismo, esas cosas abstrusas que nadie entiende pero si usted dice que no entiende, pasa por tonto
O dicho de otro modo: no todas las veces que no entiendes algo es porque tú seas limitado. Plantéate que quizás no tenga ningún sentido...

Mario Bunge en la wikipedia

La misma entrada y más comentarios en Entrevista a Mario Bunge en barrapunto

viernes, abril 25, 2008

Actualizando el kernel Linux sin reiniciar

Leyendo el blog de Daniel Stenberg me entero de que ksplice ofrece la posibilidad de hacer actualizaciones de seguridad en el kernel Linux sin reiniciar, siempre y cuando los cambios no supongan modificaciones semánticas en los datos. Según el autor este tipo de modificaciones son aproximadamente un 80% del total de vulnerabilidades críticas. Es, aparentemente, el sueño de muchos administradores de sistemas...

Más información en el artículo de presentación, Ksplice: An automatic system for rebootless Linux kernel security updates (pdf), en la lista del kernel, A system for rebootless kernel security updates y en programming.reddit.

Actualizando el kernel Linux sin reiniciar en barrapunto

jueves, abril 24, 2008

La vida privada de volatile

El estándar de C(++) tiene unas cuantas esquinitas. Seguramente volatile es una de ellas. Para aclarar el significado exacto de este calificativo en Coding Relic han publicado La vida privada de volatile, en donde no solo se analiza la letra del estándar sino que se examina el código generado para MIPS en distintos casos.

Conviene recordar los posibles usos de volatile, así como para qué no debe usarse:
La vida privada de volatile en barrapunto

miércoles, abril 09, 2008

La aritmética de punteros, su desbordamiento y la seguridad

Me he enterado vía el valle del viento helado de una nueva polémica acerca de gcc y su implementación. El hecho es que gcc cambió su comportamiento en cuanto a comparaciones entre punteros incrementados y ha provocado muchos meses después una alerta de seguridad desproporcionada y según los desarrolladores de gcc, falsa (Se puede oír desde aquí el ruido y la furia)

El caso es que, entrando en profundidad, es una optimización casi "trivial" que hace que p + C1 < p + C2 pase a ser C1 < C2 sin tener en cuenta el posible desbordamiento (overflow) de ambas operaciones. Hay que decir además que el estándar (de C y de C++) declara no definido el valor del resultado de la suma entre un puntero y un entero cuando se sobrepasa el tamaño del objeto al que apunta.

Es muy importante este último punto, porque deja traslucir un error de concepto: la comprobación de overflow propuesta en la alerta(*) es muy burda porque sólo se comprueba el desbordamiento de la operación aritmética, no que nos estamos saliendo del rango permitido. Sin embargo lo que deben saber el programador y el programa a la vez, cuando están manejando aritmética de punteros es cual es el desplazamiento (offset) máximo, de cuanta memoria se dispone. Si eso no lo sabe, es inútil cualquier otra comprobación...

Hay que hacer notar además que la optimización de la que se habla aquí la aplican casi todos los compiladores y lo que provoca la alerta es en realidad el cambio de comportamiento, no que sea incorrecto.

También recuerda esto que es muy mala política basar el código en detalles de implementación específicos de la plataforma. En este caso y en muchos otros, los desarrolladores de gcc tiran de cita del estándar para argumentar sus decisiones. Los usuarios se quejan, llamándoles abogados del lenguaje (language lawyer) pero en momentos como esos hay que recordar que probablemente están defendiendo sus decisiones de implementación y lo importante de esas decisiones para el éxito de una tecnología.

(*)char *buf;
int len;
len = 1 << 30;
if (buf+len < buf){ Overflow }


La aritmética de punteros, su desbordamiento y la seguridad en barrapunto

martes, abril 01, 2008

Un par de enlaces más (sobre C++)

Sólo un par de enlaces más para complementar la entrada anterior, la entrevista con Stroustrup (lástima que hayan salido después, hubiesen quedado bien en la misma entrada...)
Un par de enlaces más (sobre C++) en barrapunto

sábado, marzo 29, 2008

(Otra) entrevista a Stroustrup

Por si alguien había pensado que me había olvidado de C++0x y de Stroustrup esta entrada viene a demostrar que no :) Uno no tiene porqué estar de acuerdo con Bjarne Stroustrup, incluso puede odiar C++ por las milsetecientascincuetaydos razones por las que puede resultar odioso, pero lo que no se puede negar es que Bjarne ha tenido una gran influencia y sus opiniones son, por lo menos dignas de ser leídas. Algunas de las entrevistas que se le han hecho (incluso alguna que no le han hecho ;) ) me suelen parecer intensas y con elementos para la reflexión.
Pues bueno, en DDJ le han hecho una nueva entrevista. Extractaré lo que me ha interesado (Espero me sepan disculpar que no traduzca esta vez. Si me ha costado más de un mes hacer una nueva entrada no quiero imaginarme cuando publicaría esto con traducción...):

Sobre los distintos paradigmas de programación:
No programming paradigm is best for everything. What you have is a problem and a solution to it; then, you try to map that solution into code for execution. You do that with resource constraints and concerns for maintainability. Sometimes, that mapping is best done with OOP, sometimes with generic programming, sometimes with functional programming, etc.

OOP is appropriate where you can organize some key concepts into a hierarchy and manipulate the resulting classes through common base classes. Please note that I equate OO with the traditional use of encapsulation, inheritance, and (run time) polymorphism. You can choose alternative definitions, but this one is well-founded in history.

Sobre C++0x:
The progress on standard libraries has not been what I hoped for. We will get regular expressions, hash tables, threads, many improvements to the existing containers and algorithms, and a few more minor facilities. We will not get the networking library, the date and time library, or the file system library.
The standard will be finished in late 2008, but it takes forever to go through all the hoops of the ISO process. So, we must face the reality that "C++0x" may become C++10.

C++0x y el multithreading:
The new memory model and a task library was voted into C++0x in Kona. That provides a firm basis for share-memory multiprocessing as is essential for multicores. Unfortunately, it does not address higher-level models for concurrency such as thread pools and futures, shared memory parallel programming, or distributed memory parallel processing.

Consejos para el desarrollo en el mundo real. Me gusta especialmente cuando se recuerda el carácter complejo y casi orgánico de los sistemas (como Richard P. Gabriel en Objects Have Failed):
Think. Discuss with colleagues and potential users. Get a good first-order understanding of the problem domain. If possible, try to be a user of an existing system in that field. Then, without too much further agonizing, try to build a simplified system to try out the fundamental ideas of a design. That "simplified system" might become a throwaway experiment or it may become the nucleus of a complete system. I'm a great fan of the idea of "growing" a system from simpler, less complete, but working and tested systems. To try out all the tool chains before making too grand plans.
Sobre las habilidades que les suelen faltar a los estudiantes:
I saw so many students who simply didn't have the notion that code itself is a topic of interest and that well-structured code is a major time saver. The notion of organizing code to be sure that it is correct and maybe even for someone else to use and modify is alien: They see code as simply something needed to hand in the answers to an exercise.


Vía programming.reddit.

"(Otra) entrevista a Stroustrup" en barrapunto

miércoles, febrero 20, 2008

Firefox usará el asignador de memoria experimental de FreeBSD

Leo en (cómo no...) en programming.reddit que Firefox 3 beta 3 utiliza el asignador de memoria dinámica experimental de FreeBSD (jemalloc) en lugar del asignador de la plataforma de ejecución. Al parecer ha dado buenos resultados en cuanto velocidad y reducción de la fragmentación en los test de rendimiento para las tres plataformas mayoritarias (Windows, Mac OS X y Linux)

Para el que esté interesado en estos temas hay disponible un artículo muy interesante sobre jemalloc: A Scalable Concurrent malloc(3) Implementation for FreeBSD (pdf) en el que se explica su implementación, que coge ideas entre otros de hoard, y ciertamente tiene muy buena pinta. Hablé de hoard hace poco en Problemas de memoria (y algunas soluciones).

Firefox usará el asignador de memoria de FreeBSD en barrapunto

miércoles, febrero 13, 2008

Notas sobre errores fatales y portabilidad

Es escasa y dispersa la información que he encontrado acerca de la gestión de errores fatales en distintos sistemas operativos y lo que afecta al funcionamiento de los programas sobre ellos. Así que voy a juntar lo que he ido recopilando en una sola entrada. Puede ser un poco batiburrillo, pero igual le es de utilidad a alguien... (Para mi seguro, que así no pierdo los enlaces). Ordenadas de general a específico[1]:


  • En ANSI C existe signal que permite cambiar la gestión este tipo eventos, entre los que se encuentran SIGSEGV, violación de segmento y SIGFPE, error aritmético. No obstante, por desgracia, su comportamiento en programas con más de un thread no está especificado. Además por si fuese poco ANSI tampoco especifica el handler por defecto, es decir, qué es lo que pasa si salta una señal de ese tipo.

  • De hecho, de los que he probado, en windows con la librería de C del VisualStudio al menos, las señales funcionan por thread y en linux es global por proceso...

  • En POSIX si que se define el comportamiento por defecto de las señales. En concreto SIGSEGV y SIGFPE abortan el proceso completo . Se pueden ver los comportamientos por defecto de las distintas señales en POSIX en la documentación de <signal.h> del OpenGroup. Además, POSIX(R) recomienda pasarse a sigaction (que sólo es POSIX(R), no ANSI).

  • Windows NT no genera señal de violación de segmento, pero se le puede instalar handler

  • En win32 un error fatal se gestiona como una excepción estructurada (SHE) que en C++ se mapea a un excepción normal[2]. Además, una excepción estructurada no capturada, por defecto, supone la muerte del thread en el que se produce, pero no del proceso global .

  • Existe una forma de sobrescribir este comportamiento por defecto y es SetUnhandledExceptionFilter. Recomiendan en Nynaeve[3] no hacer cosas demasiado complicadas en el manejador, como parece lógico.

  • En un artículo de DeveloperWorks comentan un modo de convertir señales en excepciones pero que es un hack completamente erróneo: C++ exception-handling tricks for Linux porque da a entender que se puede replicar el comportamiento por defecto de Windows. Sin embargo, como se puede leer en "Program Error Signals" de la documentación de la glibc:
    La acción por defecto de todas estas señales es terminar el proceso. Si se bloquean o ignoran estas señales o se establece un handler que retorna normalmente, tu programa cascará espantosamente en el momento en que suceda la señal no ser que(*) haya sido generada a través de raise o kill en lugar de un error real.
    cosa que he podido comprobar con el código de DW tratando de ignorar una violación de segmento.

  • En resumen, lo más juicioso (y homogéneo entre plataformas) sería parar el proceso completo en caso de uno de estos errores y tratar de informar lo más completamente posible del error. En caso de win32 habría que forzar el fin del proceso, ya que no es la acción por defecto[4].


[1]El orden es de mayor a menor, de general a específico. Debería ser obvio para un programador: a igualdad de condiciones, se debería usar lo que funcione en el estándar más aceptado y amplio ¿por qué limitar el ámbito de aplicación? Primero, buscar en ANSI, y si la funcionalidad no está elegir conscientemente una solución más específica. En el fondo para mi no es más que una consecuencia de la ley de Postel sobre el el código: "Cuanto más estricto (más estándar) es lo que escribes, más aumentarás la interoperabilidad". Puede parecer una obviedad, pero en esas pequeñas microdecisiones de los programadores no es nada extraño usar extensiones del estándar sin necesidad. Y en caso de necesidad se puede echar mano de librerías libres, muchas de ellas con un alto nivel de portabilidad.

[2]Pongo en cursiva normal porque entra la duda si en esos casos, de tan bajo nivel, una excepción, que se confunde con excepciones de de otro tipo, es lo más clarificador para el usuario-programador, máxime cuando el C++ estándar no posee excepciones para gestionar estos casos...

[3]Un blog que he descubierto hace poco... interesante. Además sobre el mismo tema: Beware of custom unhandled exception filters in DLLs y You might be using unhandled exception filters without even knowing it

[4]Cabe preguntarse porque se permite la ejecución del proceso en un caso tan excepcional... habida cuenta además de que una excepción no capturada de de C++ provoca, por defecto el fin del proceso... En este caso está sin duda justificado el Fail Fast: lo que hay que hacer es arreglar el programa, no dejarlo seguir...

(*)Me despisté al traducir. Gracias a Javier Noval por leerse los enlaces y hacerme notar el error ;)

Notas sobre errores fatales y portabilidad en barrapunto

lunes, febrero 04, 2008

(Otros) problemas con la memoria y (otras) soluciones

Alguien en programming.reddit hizo una pregunta de esas difíciles: ¿Cómo manejar en un programa en C los casos en los que la memoria se agota? Y digo que es una de esas preguntas difíciles porque depende del tipo de software que estás haciendo, de su criticidad y del nivel requerido de robustez. Ya se sabe, el difícil compromiso de la gestión de errores críticos.

Y como se ve en las respuestas de los redditenses no sólo depende de nuestro sistema, sino de detalles de implementación de más abajo, como suele ser usual en los casos no del todo raros en los que las abstracciones que usamos comienzan a flaquear. En este caso se habla del comportamiento de Linux (el kernel) a la hora de tratar la falta de memoria, que por defecto usa una estrategia optimista que deja reservar (pero no usar, claro) más memoria de la disponible. No obstante este comportamiento se puede cambiar a uno un poco más controlable a través del parámetro overcommit_memory, que se introdujo no hace tanto... El comportamiento por defecto es llamar al OOM Killer que es un método tan drástico como poco predecible. Todo esto esta muy bien explicado en When Linux Runs Out of Memory que vi referenciado por aquí en tiempos de mayor intensidad técnica :)

Además en las respuestas se apunta a un libro online de los que vienen bien cuando las condiciones son más extremas de lo usual: Small Memory Software. Patterns for systems with limited memory. Apuntado en éste mi del.icio.us particular.

(El título es "(Otros) problemas con la memoria y (otras) soluciones " porque no hace mucho escribí Problemas de memoria (y algunas soluciones), sobre el cuello de botella que supone la gestión de memoria sobre todo en sistemas multicore)

"(Otros) problemas con la memoria y (otras) soluciones" en barrapunto

martes, enero 22, 2008

Los usuarios y la primera impresión

Repasando la pila de cosas pendientes de leer me he encontrado con un inspiradísimo Larry O'Brien en una frase que es solo lateral en su razonamiento de que se nota más a los programadores muy malos que a los muy buenos
Medir la satisfacción [para medir la calidad de un desarrollo] es un indicador insuficiente, porque la satisfacción tiende a ser un delta de la última experiencia, no un valor absoluto.
Y es curiosísimo, porque tengo exactamente esa percepción tanto en un lado como en el otro, de programador y de usuario: no importa lo que ocurra posteriormente a un error fatal del sistema; el sistema llevará para siempre ese estigma. Da igual que se corrigiese para siempre, en la siguiente versión. Para no ser absolutamente pesimistas, a nivel interno ayuda muchísimo que exista (y se use) un sistema de seguimiento de incidencias, que esté documentado cuándo, dónde y cómo se producía el problema y cuándo (desde que versión) y cómo se solucionó. A nivel externo... ya digo, un estigma :/ Aunque una labor continuada de comunicación, que tal mal se les suele dar a los desarrolladores, puede ayudar bastante...

Es también por el miedo a que la primera impresión no sea buena por lo que muchos programadores se resisten al famoso release early, release often. Pero no publicar versiones también es fuente de mala imagen, de eso los desarrolladores deben de ser conscientes... Y es que es difícil conjugar el causar una buena impresión con publicar pronto. Yo tengo en esto una política que no sé si es la más acertada, pero es la mía: minimizar la funcionalidad de la primera iteración, limitarla a lo esencial, que sea mínima pero bien testeada. Por cierto, que Joel no está de acuerdo con esta estrategia desde el punto de vista estratégico/comercial/ISV... Mucho que discutir desde distintas vertientes, incluido el modelo de negocio y de desarrollo de software, claro :)

Por cierto que este mismo tema, desde el punto de vista estrictamente estético, fue tratado por Jeff Atwood con un ejemplo muy desafortunado, comparando Frets on Fire con Guitar Hero. No puedo ser imparcial en este caso porque estoy enganchado al FoF en el que uno se puede creer que toca con el teclado como Stevie Ray Vaughan con su guitarra en Texas Flood. Aquí, al menos para mi, es el sonido y no la imagen lo importante :)

Los usuarios y "la primera impresión" en barrapunto