jueves, 25 de julio de 2013

MinGW y las calling conventions

Ya hace más de 6 meses que no vemos publicada una nueva versión "oficial" de ZinjaI. Es normal que en el primer tercio del año los esfuerzos se dirijan mayormente a PSeInt, y este año se han presentado motivaciones adicionales para que así sea aún en mayor medida y por algo más de tiempo. Sin embargo, el desarrollo de ZinjaI nunca se detiene por completo, y quienes observan de tanto en tanto el repositorio saben que siempre hay algo nuevo, aunque solo sea un bug. Pero esta vez hay una razón más para retrasar el lanzamiento de una nueva versión, y esta es un cambio importante en mingw (el port del compilador gcc a Windows). Siempre lleva tiempo actualizar gcc ya que hay que "armarlo" por partes, compilar algunas bibliotecas que agrego en ZinjaI, y luego acomodar y empaquetar todo, pero esta nueva versión tiene algo especial. En qué consiste este cambio y cómo nos afecta a los usuarios de ZinjaI es lo que voy a tratar de explicar en este post.

miércoles, 10 de julio de 2013

En cajas de 12

Programar me divierte, y mucho. Pero estoy hablando de resolver problemas interesantes, no de hacer ABMs y páginas webs para el negocio de la esquina (no lo tomen a modo despectivo). Me refiero a problemas de optimización, algoritmos y estructuras de datos por ejemplo. Por eso, cuando veo algún contest de programación, intento participar. Un contest de programación es una competencia, donde hay que resolver problemas programando, y gana el que resuelve más problemas, o el que los resuelve en menos tiempo, o el que hace el código más eficiente. Allí suelen aparecer problemas muy interesantes, y suele ser además el pie para después sentarme a aprender algo nuevo (a pelear otra vez con ese problema que no me salió durante la competencia). Un contest de mucho nombre a nivel mundial es el Google Code Jam, y ya se imaginarán por qué. Empecé a participar ahí creo que en 2008, y hasta el día de hoy sigo más o menos igual: cada año avanzo dos o tres rondas, pero nunca llego a las finales, y usualmente ni siquiera estoy cerca. Solo un año me gané una remera, pero ese año el contest no era global, sino limitado a Latinoamérica.

Cuando me inscribí por primera vez en el sistema online para participar, tuve que llenar un formulario con varias preguntas, entre ellas una que decía si me gustaría trabajar en Google. Obviamente Google busca, además de buena publicidad, identificar buenos programadores para reclutar. Como todo geek que se precie de tal dije que sí sin pensarlo porque: a) ¿a quien no le gustaría trabajar en la empresa más importante del mundo en lo que a software se refiere? b) ¿qué importa qué responda, si total está claro que está fuera de mi alcance? Pero todo esto viene al caso, por algo que pasó hace poco.

martes, 2 de julio de 2013

Herramientas mágicas: CppCheck

En la primer entrega de la serie Herramientas Mágicas les presenté Valgrind, un analizador dinámico. Lo de dinámico es porque analiza al programa en movimiento, mientras se ejecuta. No es el único de este tipo, ya volveremos a eso, pero ahora voy a presentar un analizador estático: CppCheck. Esto quiere decir que, por el contrario, este tipo de analizador no ejecuta al programa en cuestión, sino que se basa solamente en inspeccionar muy minuciosamente su código fuente.

Para hacer una analogía con algo conocido, digamos que un analizador estático es parecido a medio compilador. Sería la parte del compilador que mira el código generando los warnings y errores, no la que traduce. Pero el objetivo del compilador es traducir a código máquina. Dado que para ello tiene que hacer un análisis previo del código fuente, va detectando "de paso" (como efecto colateral) potenciales errores que avisa en forma de warning. Pero solo hace el análisis necesario para traducir y eventualmente optimizar, y no pierde tiempo en otros detalles. Un analizador estático como CppCheck, en cambio, tiene por objetivo el encontrar errores, por lo que el tipo de análisis que hace toma más tiempo, para detectar cosas más específicas o intrincadas.

miércoles, 5 de junio de 2013

Sobre optimizaciones y precisión numérica

Recibí un correo diciendo que el siguiente código en PSeInt:
    a<-rc(13);
    Escribir a<a;

evidenciaba un error de lógica, ya que el resultado daba Verdadero, cuando debiera dar Falso (un número no puede ser menor que sí mismo). Pruebo el código en GNU/Linux y da Falso, pero el usuario dijo que usaba Windows. Entonces voy a Windows y efectivamente da Verdadero. Así que abro ZinjaI y me dispongo a Depurar en Windows, pero he aquí la sorpresa: en el depurador da Falso. Cuando se trata de variables sin inicializar, o manejo de direcciones de memoria, no es raro que una versión Debug dé mejor que una Release, pero en este caso estaba seguro que no se trataba de eso. Estaba a punto de ponerme a analizar el código objeto generado en cada caso (o sea, leer ensamblador, o tal vez saltar por la ventana, estaba decidiendo), pero antes noté algo interesante.

jueves, 30 de mayo de 2013

And the winner is....

Como muchos ya habrán notado, PSeInt fue uno de los nueve candidatos a proyecto del mes de junio en SourceForge. Con algún criterio cada semana en SourceForge se eligen los "proyectos destacados de la semana" y se muestran en la portada. Hace poco me entero que estos proyectos se eligen cada semana de entre los que hayan publicado actualizaciones la semana anterior, y no entre todos. Esto explica cómo PSeInt llegó a esa lista en tres oportunidades. A fin de mes, de entre los proyectos de las 4 semanas, se elige un subconjunto para posibles proyectos del mes, y se deja la decisión final al público en general mediante una votación. Para evitar que una persona vote muchas veces, el voto se autentica mediante una cuenta de twitter. Y así funciona. Ahora, habiendo finalizado la votación de mayo, vengo a hacer algunos comentarios y reflexiones acerca de cómo se dieron las cosas.

lunes, 27 de mayo de 2013

Algunos porqués del pseudocódigo

Tengo una eterna discusión (en el buen sentido de la palabra) con varios usuarios de PSeInt acerca de hasta dónde debe llegar este lenguaje. Me han sugerido agregar la posibilidad de leer y escribir archivos, de declarar estructuras o pseudo-clases, de usar tipos de datos más específicos, escribir las palabras claves en inglés, agregar operadores como el de desplazamiento de bits, o hasta en algún caso incorporar una instrucción para enviar y recibir datos por el puerto serie (¿?). El dilema es el de siempre, ¿cuánto de pseudo y cuánto de código? Pareciera que mucho de pseudo significa que no se parece casi nada a un lenguaje real y que tiene en principio poca potencia (digamos que muchas cosas no se pueden hacer); mientras que mucho de código pareciera implicar que será fácil pasar luego a un lenguaje real (será más parecido), y que tal vez se puedan hacer cosas bastante complejas.

lunes, 20 de mayo de 2013

Depuración (parte 3): Controlando la ejecución II

En el post anterior mencioné los mecanismos básicos para controlar la ejecución del programa: puntos de interrupción, step over y step in. En esta tercera parte voy a completar la idea con algunos más para detener el programa y una aclaración importante sobre el nivel de granularidad con que se pueden indicar estos puntos de la ejecución en el código fuente. También, les voy a contar sobre algunos otras formas especiales para volver atrás en el tiempo o alterar (casi) arbitrariamente la ejecución, cosas que en la práctica permiten analizar varias veces un mismo error, o ensayar algunas soluciones antes de codificarlas. La ventaja radica en no tener que reiniciar el programa y llegar nuevamente hasta el punto conflictivo, lo cual puede llevar bastante tiempo o ser tedioso. Pero además, como efecto colateral, esto sentará una base que permitirá hacer algunos trucos para sortear ciertas limitaciones más adelante cuando hablemos de inspección de expresiones y otras acciones similares.

martes, 23 de abril de 2013

Depuración (parte 2): Controlando la ejecución I

Habiendo introducido las nociones básicas en la parte 1, vamos a profundizar sobre los dos aspectos prácticos más importantes: el control de la ejecución y la inspección de los datos en memoria. En esta parte 2 (y la que sigue) voy a hablar del control de la ejecución. Con el control de la ejecución me refiero a cómo definimos cuándo y hasta dónde se ejecuta. Hay que saber que el mecanismo básico es el punto de interrupción, pero cualquier depurador nos provee un conjunto de instrucciones para avanzar de a poco sin tener que explicitar nuevos puntos de interrupción. Por ejemplo, si estoy detenido en cierto punto y quiero que ejecute una sola linea y vuelva a detenerse (ejecución paso a paso), tendría que poner un punto de interrupción en la siguiente línea y decirle luego que continúe ejecutando, y una vez detenido nuevamente quitar ese punto de interrupción. Si bien es un mecanismo válido, los depuradores tienen instrucciones para hacer todo esto junto y de forma transparente, de modo que al usuario el usuario ni se entere de ese punto de interrupción auxiliar. Y así, hay comandos para avanzar por linea o por instrucción (que no es lo mismo), hasta llegar a cierta línea, o hasta salir de cierta función, etc. También hay mecanismos para alterar la ejecución y volver a ejecutar una línea que ya pasamos, y otros trucos útiles. De eso habla este post.

lunes, 15 de abril de 2013

Herramientas mágicas: Memcheck (de Valgrind)

La caja de herramientas básica de todo programador debe contener mínimamente un editor, un compilador y un depurador. Y si están empaquetados en su IDE de confianza mucho mejor. Pero además del kit básico, hay varias otras herramientas dando vueltas que pueden resultar muy muy útiles en muchos casos, y que conviene conocer. Sin embargo, no siempre se conocen, y por eso empiezo esta sección, para presentarles las que yo fui encontrando con el tiempo. Son herramientas que antes no extrañaba porque no sabía que existían, a las que tal vez no les encontré el potencial de entrada, pero que después de usarlas un tiempo y explorarlas mejor me parecieron geniales. Por esto, las terminé integrando en ZinjaI, mediante el menú genérico "Herramientas", donde pongo todo lo que no es básico e imprescindible para el alumno, pero sí útil para otros usuarios algo más exigentes.

En esta primera entrega voy a hablar de memcheck, una de las herramientas incluidas en un paquete más grande que se conoce como Valgrind. Valgrind es un framerwork para herramientas de análisis dinámico. Es decir, una infraestructura para analizar automáticamente cómo se comporta un programa cuando se ejecuta (de ahí el "dinámico"). Sobre esta infraestructura se construyen herramientas específicas, por eso cuando instalamos valgrind estamos instalando varias (6 al menos) herramientas que comparten una base común respecto a cómo ejecutan y analizan el programa, pero que centran su atención en partes diferentes, y por ello extraen información diferente. La más interesante de ellas es memcheck, que sirve para analizar cómo usa la memoria un programa, y detectar errores.

lunes, 8 de abril de 2013

Depuración (parte 1): ¿para qué sirve y cómo funciona?

Si hay una habilidad imprescindible en todo buen programador, es la habilidad para depurar un programa. La depuración es en general el proceso de corregir errores, pero cuando hablamos de programación, yendo a la práctica, la clave es ejecutar el programa con un "depurador", una herramienta que nos permite interrumpirlo en cualquier momento para ver qué está haciendo o qué tiene en su memoria. Un programador habilidoso en la depuración, sabe dónde interrumpirlo o qué buscar en la memoria a la hora de encontrar la causa de un problema, o entender cierto comportamiento. Y esto se adquiere con la práctica, como todo en la programación. Hay que conocer qué pueden hacer en teoría las herramientas, pero la práctica y la experiencia nos ayudarán a decidir cómo utilizarlas. Sin embargo, hay muchas funcionalidades básicas de un depurador que puede aprovechar incluso el principiante para entender cómo funciona un ejemplo o una estructura en particular.

El problema es que a pesar de lo importante que nos parezca a muchos programadores, cuando se enseña a programar en general se le da poco y nada de importancia. En la mayoría de los casos, los libros de programación no dedican un capítulo a esto, ni los docentes dedican una de sus clases. Pareciera que es algo para aprender cuando ya sabemos programar, para dejar para cursos avanzados y segundas partes, y esa idea no puede estar más equivocada. Las nociones básicas y el hábito de usar un depurador se deben inculcar desde temprano (desde que dejamos el pseudocódigo y pasamos a un lenguaje real diría yo). Por eso, en esta serie les voy a empezar a contar a los principiantes qué se puede hacer con un depurador, y daré algunas pistas para los más curiosos o avanzados de cómo hace lo que hace, aunque esto último no sea necesario saberlo para comenzar a utilizarlo.

viernes, 22 de marzo de 2013

Ayuda, lo necesito urgente!

Una vez más vengo a atacar (solo un poquito) a los usuarios, esos que a veces defiendo tanto. No quiero generalizar, así que al que no le toca que no le toque. Tampoco es que yo tenga un trastorno bipolar, doble personalidad o alguna de esas condiciones psicológicas que no se exactamente qué significan. Lo que pasa es que valoro mucho y trato de fomentar la contribución de muchos buenos usuarios por un lado, pero también a veces me sacan de quicio los mensajes de otros por el otro. En el fondo, puede que todo sea mi culpa, así que vamos a tratar de hacer una crítica constructiva de ambos extremos de la comunicación (va con un poco de humor para no enojar a nadie).

La gente escribe (por mail, por formularios en el sitio web, por los foros, por el chat, da igual) preguntando/diciendo cosas de PSeInt, ZinjaI, C++, programación, o cualquier cosa que les parezca. Muchos mensajes son útiles, muchos habría que ignorarlos, otros no lo se porque ni siquiera los entiendo. Hay problemas en dos niveles: qué quieren decir, y cómo lo dicen. Empecemos por el primero, más básico, elemental, aplicable a cualquier comunicación escrita en cualquier ámbito. Para que entiendan bien todos (especialmente los que lo hacen), lo voy a tratar de poner su lenguaje:
 * PARA EMPEZAR NO GRITEN.
 * Ezkrivan vien x fabor q no kuezta muchio.
 * No den ordenes ni exijan respuesta inmediata nunca jamás!
 * Aprendan comunicar al español con otros persona antes que quiere comunicar la máquina para C++.
 * Usen una coma un punto seguido dos puntos algo los signos de puntuación no muerden ayudan a entender mejor las oraciones gracias
 * Sean amables, soperútanos.

lunes, 11 de marzo de 2013

¿Cómo escribir aplicaciones portables?

Antes de decir nada tengo que hacer una aclaración sobre el título, y es qué entiendo por "portable", ya que es una palabra que se puede usar para indicar varias cosas y su significado por defecto en relación a aplicaciones de software creo que ha cambiado con el tiempo. Cuando yo uso "portable", me refiero a aplicaciones que pueden correr en distintos sistemas operativos o arquitecturas de software y hardware (por ejemplo, que puedo hacer andar tanto en Windows como GNU/Linux). La idea es que una aplicación es más portable cuanto menos depende de elementos específicos de un sistema operativo en particular. Creo que los desarrolladores seguimos teniendo ese concepto asociado a "portabilidad".

Sin embargo, actualmente muchos usuarios finales asocian "portable" al hecho de poder llevar la aplicación de una PC a otra en su pendrive para usar sin necesidad de instalarla, como un solo exe que se ejecuta y ya, o como un zip que solo hay que descomprimir. De hecho pueden encontrar googleando que por ahí alguien ofrece PSeInt portable o ZinjaI portable en este sentido, y supongo que todo lo que hizo ese alguien fue instalarlo en una pc y luego comprimir la carpeta de instalación en un zip/rar/autoextraíble/lo-que-prefieran. No se dejen engañar, mis programas se pueden copiar sin necesidad de instalar, siempre, cualquier versión, sin problemas ni modificaciones. El único trabajo adicional que hace el instalador es crear accesos directos y asociar las extenciones, pero sacando eso, no es más que un gran zip preguntando donde descomprimirse (lugar que tranquilamente puede ser un pendrive). Pero esa no es la idea de portabilidad que me preocupa, sino la anterior, y de los detalles de implementación relacionadas a esa primer interpretación es de lo que habla este post.

sábado, 2 de marzo de 2013

La importancia del testing

Cualquiera que trabaja en un ambiente profesional sabe que en un proyecto de software se dedican tiempo y recursos planificados para testing y control de calidad en general (QA). Se requiere gente capacitada y con un sexto sentido para averiguar como reventar un sistema en dos simples pasos (mi novia trabaja como tester y creanme que es increíble la facilidad que tiene para encontrar errores que jamás se me habría ocurrido siquiera buscar). Pero también, cualquier programador que desarrolla un proyecto artesanalmente por hobbie, fuera de toda formalidad como sucede a muchísimos proyectos de software libre, sabe lo tedioso que puede ser lograr eso. Ya lo dije muchas veces, en ZinjaI, en PSeInt, y en MotoGT desarrollo a mi ritmo, lo que creo necesario, y soy accidentalmente mi propio tester cuando uso las dos primeras herramientas en mi trabajo, o cuando juego un rato con el tercero.

Pero como buen seguidor del modelo de bazar de Raymond, trato de liberar seguido y esto convierte a mis usuarios en mi mayor recurso de testing. El proceso suele ser: cambio algo, lo pruebo en mi notebook mientras lo desarrollo (una prueba para nada general), lo publico creyendo ingénuamente que les va a funcionar a todos, y luego recibo unos cuantos reportes de errores. A veces son solo detalles, otras veces burradas importantes que no debieron publicarse nunca. Estos errores pueden hacerme perder muchos usuarios, ya que se pueden llevar una muy mala primera imágen y no volver. Pero más allá de eso creo que tengo que hacer una consideración especial, principalmente para con PSeInt: los usuarios son estudiantes que recién empiezan, y el software promete facilitarles el aprendizaje, pero el estudiante por su inexperiencia podría no distinguir un error en la interpretación de un error en su algoritmo. Esto ocurre, y atenta directamente contra el objetivo del proyecto, confunde al estudiante, va en una dirección perfectamente opuesta. Y entonces es doblemente preocupante. Por eso, hace un tiempo empecé a construir de a poco un sistema muy muy básico de testing automático para el núcleo del intérprete, y de eso habla este artículo.

miércoles, 13 de febrero de 2013

Feliz Cumpleaño!

Hoy se cumple un año desde el primer post de Cucarachas Racing. Lo normal es que quien cumple años reciba algún regalo, pero ¿qué se le puede regalar a un blog? (tal vez un poco de difusión, nunca viene mal, es lo único que se me ocurre). En fin, el punto es que no tiene sentido regalarle algo a un blog, pero como para celebrar igual que después de un año hay gente que sigue viniendo a leer o al menos mirar rápidamente las cosas que escribo, voy a invertir la costumbre y regalarles yo algo a esos lectores. Algo así como lo que les pasa a muchos cuando crecen y empiezan a trabajar, que tienen que llevar comida al trabajo el día de sus cumpleaños (¿que no era al revés cuando eramos chicos?).

Así que yendo al grano, como regalo de cumpleaños les ofrezco El Gran Libro Negro de las Cucarachas Pixeladas (badum, tish...). Y sí, ¿o esperaban que sortee un auto, o licencias de Windows originales? No, no hay tanto presupuesto, es solo un libro. Y no, no tiene nada nuevo, más que el formato. Más allá de lo rimbombante que suene su nombre, se trata de una recopilación de todo lo que ha pasado este año en este blog, pero en formato de libro digital. Por supuesto que libre y gratuito (bajo licencia CC BY SA).

sábado, 2 de febrero de 2013

¿Ser o no ser una tortuga?

Alan Perlis fue un pionero que se dedicó a las ciencias de la computación, especializándose en el estudio de lenguajes de programación (no en programar con ellos, sino en discutir sus diseños y fundamentos), lo cual incluso le valió el primer premio Turing (podríamos decir el Nobel de la informática). Entre las muchas cosas que escribió, hay una frase muy popular en el mundo de la programación que es la siguiente: "To understand a program you must become both the machine and the program". Podría traducirse como "para entender un programa de computadora tenés que convertirte en los dos, el programa y la computadora". Es una frase muy interesante que siempre acepté como válida (según mi experiencia) y jamás se me ocurrió cuestionar.

Por otro lado, Seymour Papert es un matemático del MIT que investigó entre otras cosas sobre la enseñanza y el aprendizaje en niños, las ciencias de la computación y la inteligencia artificial. Como fruto de todo esto, surgió el lenguaje LOGO, el de la tortuga. Además, escribió muchas cosas, entre ellas un libro genial llamado "Mindstorm: children, computers and  powerful ideas", donde habla del aprendizaje de los niños, de la enseñanza de la matemática, de su esperanza de que el uso masivo de computadoras cambiaría todo eso, y de cómo el lenguaje de tortugas fue concebido para empezar a dar ese paso. Papert sin duda fue un adelantado.