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.

lunes, 28 de enero de 2013

Nada que no pueda hacer un script de bash (parte 2)

Siguiendo con esta idea de utilizar bash para combinar algunas de las cientos de pequeñas herramientas que se encuentran en casi cualquier GNU/Linux para automatizar tareas varias, en este segundo post traigo algunos ejemplos adicionales. Hay que aclarar, que al igual que en la primer parte, los ejemplos no están explicados 100%, sino que se comenta rápidamente qué hacen y cómo. Un lector con algunos conocimientos mínimos de programación y del uso de la linea de comandos debería poder entender los ejemplos, pero seguramente necesitará googlear un poco más o consultar los manuales para poder modificar estas ideas para sus propias necesidades. De todas formas, el objetivo era solo tirar la primera piedra, para despertar un poco la curiosidad, y si les interesa podrán encontrar fácilmente mucho más material.

lunes, 21 de enero de 2013

Nada que no pueda hacer un script de bash (parte 1)

El título de este post es una frase que uso mucho. Bash, el shell más común en sistemas GNU/Linux, es un intérprete de comandos en modo consola. Soy de esos que usan mucho mucho la consola, porque creen que así las cosas se hacen más rápido. Mucho más rápido, solo que hay que saber un montón muy grande de trucos, nombres comandos, y argumentos, en apariencia crípticos. Por eso la gente prefiere las ventanitas gráficas, porque no hay que recordar nada, todo es intuitivo. Y las ventanas son geniales para eso, pero es ridículo a mi criterio (y el de otros, recomiendo mucho esta vieja lectura, también en español), comparar las limitaciones de una interfaz gráfica simple, con la potencia de una simple linea de comandos.

Pero tampoco es que tengamos que recordar tantos comandos. Diría que la mayoría de los que usamos las terminales usamos regularmente un 5% de los comandos disponibles, y solo sabemos un 3% de sus argumentos. Es así, se puede hacer mucho con poco. Y si somos haraganes, o nos gusta automatizar todo, podemos tomarnos el trabajo de armar un script con las partes difíciles, largas o tediosas, para luego nunca más tener que escribirlas otra vez, sino simplemente invocar al script. Yo tengo mi notebook llena de pequeños scripts, para todo. Y por eso en realidad no sé tanto de bash, porque las operaciones simples son pocas, y las complicadas están dentro de scripts, así que no necesito memorizarlas. Pero sí necesité ejemplos en primera instancia para hacer esos scripts. Y de eso se tratan estos posts. Pienso presentar algunos ejemplos cortos y explicarlos para que vean la potencia de bash y otras herramientas con las cuales se combina, y para que vean el tipo de cosas que se pueden hacer. Espero que aprendan algo, los motive a acercarse a las lineas de comandos, y se les ocurran ideas para sus propias tareas.

jueves, 10 de enero de 2013

¿Todos para uno o uno para todo?

Ya expliqué hace poco que PSeInt está compuesto por varios programas separados, la mayoría de ellos independientes. El usuario percibe al conjunto de programas como si fuera uno, con varias partes trabajando en conjunto. wxPSeInt es el programa que se encarga de ser la interfaz con el usuario, y de gestionar la ejecución de los otros de forma más o menos transparente. Veamos ahora porqué esto es así y qué tiene de interesante o no, según mi experiencia con este modelo.

Empezando por el porqué, tengo que decir que es más bien una cuestión histórica. Primero que nada, lo que quería escribir cuando empecé con PSeInt era solo un intérprete (el módulo pseint), el editor de texto surgió inmediatamente como agregado necesario para poder mostrar las bondades del intérprete, pero los demás módulos no estaban previstos. Desde ese punto de vista, tendría solo dos módulos, un editor de texto y un intérprete de consola. La comunicación sería mínima: el editor guardaría el pseudocódigo en algún temporal y lanzaría el intérprete diciéndole por argumento en la linea de comandos donde estaba ese temporal. Si había errores, el camino de vuelta también sería mediante un archivo temporal. Esto sonaba razonable, y este era más o menos el modelo que seguían la mayoría de los IDEs en lenguajes reales, así que jamás se me cruzó por la cabeza plantear otra alternativa. Mucho tiempo después se fueron agregando algunos módulos nuevos que tampoco requerían de mayor comunicación, como el visualizador (no editor) de diagramas de flujo, o el que exporta a código C++. Por eso seguí con el mismo esquema. Tal vez la primer duda respecto a si este era el camino a seguir vino cuando quise integrar la ejecución paso a paso, y también más tarde para el análisis sintáctico en tiempo real.

domingo, 30 de diciembre de 2012

Destripando PSeInt

PSeInt es un programa compuesto por muchos programas. Es decir, consta en realidad de varios ejecutables que se invocan y comunican entre ellos, de forma tal que para el usuario final se ven como partes de un único entorno. En este artículo voy a comentar cuales son esas partes (desde ahora módulos, cada uno un ejecutable), y cómo y cuando se comunican. La idea es que sirva de referencia para el siguiente artículo donde discutiré porqué es así, porqué las cosas están separadas o juntas, porqué se comunican de esa manera, y qué tiene esto de bueno o de malo según mi experiencia y las necesidades particulares de este proyecto. De paso, también sirve de documentación para mí y para los que quieran mirar el código fuente.

Primero voy a hacer una descripción rápida de qué hace cada módulo, y luego cómo se relacionan. En este análisis dejo de lado intencionalmente a psdraw, ya que sus funcionalidades serán absorbidas por psdraw2 (algunas ya lo fueron, y las que no, lo serán en las próximas versiones).  Los módulos que componen entonces al sistema de PSeInt son: