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.

Ya en otro post quise plantear la pregunta de ¿qué tenía que cambiar para mejorar el pseudolenguaje? pero no tuvo mucho éxito no se bien por qué. Abrí un hilo en el foro para debatir sobre eso de forma organizada y muy pocos participaron, pero después me llegaron todo tipo de sugerencias como las que mencioné antes en otros hilos bastante desparramados (incluso en la sección de reporte de errores). Voy a empezar a analizar algunas desiciones de diseño del lenguaje para justificarlas y dar un pauta más específica de qué busco con PSeInt, qué puedo cambiar/agregar y qué no. La idea es hacer un análisis desde el punto de vista del docente que lo utiliza en el aula, que debe diseñar una estrategia de enseñanza y aprendizaje coherente para poder desarrollar en su materia, y evaluar para qué nos tomamos el trabajo de agregar una etapa en pseudocódigo en lugar de usar directamente un lenguaje real.

Como ya aclaré alguna vez en otro post, para resolver un problema programando hay que conocer varias cosas: hay que conocer bien el problema, hay saber diseñar algoritmos computacionales (entender la lógica y tener cierta capacidad de abstracción principalmente), hay que saber plasmar ese algoritmo en un código siguiendo las reglas de algún lenguaje de programación, y hay que saber utilizar las herramientas que nos permiten llevar ese código a un ejecutable (utilizar un IDE/editor/compilador/intérprete/lo que sea). Y esto suponiendo que todo salga derecho, pero en general no es así, por lo que también hay que saber identificar y corregir los errores, errores que pueden tener que ver con cualquiera de los aspectos mencionados y en principio no sabemos cual. Sin contar que los lenguajes y el material en general están en inglés, lo cual agrega un componente extra para los estudiantes de este lado del mundo. En conclusión, aprender a programar implica aprender muchísimas cosas, y todas tienen su complejidad. Por eso, tratar de aprenderlas todas al mismo tiempo parece una locura. No es imposible, muchísimos buenos y malos programadores han aprendido así, pero estoy convencido de que hay caminos más fáciles y como docentes es nuestro trabajo investigarlos un poco y tratar de aprovecharlos.

Creo que el objetivo de utilizar pseudocódigo en una primera etapa es atacar una de las competencias a desarrollar por el alumno, la de saber diseñar algoritmos computacionales, de forma aislada, tratando de minimizar la necesidad y el impacto de las otras. Esta la más importante a mi gusto. Se puede cambiar de lenguaje y de herramientas, pero el diseño de algoritmos sigue en el fondo los mismo principios, y por eso es importante que formen una base bien sólida. En un primer curso de programación hay que dedicarle a esto el mayor esfuerzo y dejar el lenguaje en un segundo plano. La idea entonces de usar pseudocódigo en lugar de un lenguaje real es hacer que ese "dejar el lenguaje en segundo plano" sea más fácil. Sería ideal que el alumno deba diseñar su algoritmo utilizando estructuras de datos y de control, poniendo el 99% de su esfuerzo en analizar el problema a resolver y buscar la forma correcta de combinar esos elementos, y solo el 1% en pensar cómo escribirlo. El alumno debe entender por ejemplo el funcionamiento de las estructuras de control más allá de una u otra sintaxis. Por eso, es deseable que escriba su algortimo "como quiera" o "como le salga", siempre y cuando respete esas reglas básicas, y se atenga a la lógica subyacente de esas estructuras. El pseudocódigo intenta reproducir ese "como quiera" o "como le salga", trantado de presentar construcciones que parezcan naturales, coloquiales, casi que obvias. Esa debe ser su principal virtud a mi criterio, no meterse en el camino del alumno, ser transparente, casi invisible. Para lograrlo, intento ponerme en el lugar del alumno, y no en el del docente o del programador.

Entonces, es cierto que un pseudocódigo más parecido a un lenguaje real hace que sea más fácil después dar el siguiente paso, pero atenta directamente contra el objetivo de usar pseudocódigo en primera instancia. Por ejemplo, si las palabras claves estuviesen en inglés, los alumnos que no dominen bien el inglés deberían hacer un esfuerzo extra en ese 1% que hablaba. Si les obligamos a poner punto y coma al final de cada instrucción, les estamos creando un buen hábito, pero también los estamos distrayendo de su verdadero problema con un montón de errores tontos e innecesarios en este punto del aprendizaje. El alumno debe ir incorporando los conceptos de a poco y en algún orden adecuado para sus objetivos. ¿Qué tienen de pseudo el uso del punto y coma y el inglés? ¿Realmente importa que pongan o no un punto y coma, o que use "while" en lugar de "mientras" a la hora de evaluar si entienden cómo trabaja y para qué sirve una estructura repetitiva? Personalmente recomiendo el uso del punto y coma de forma opcional si quieren crear el hábito, o para enfatizar qué cosas son estructuras de control y qué cosas acciones secuenciales, pero no creo que deba ser obligatorio ni mucho menos, ya que entorpece el proceso de prueba más de lo que ayuda en las buenas costumbres. Y definitivamente estoy en contra del inglés, o los nombres de funciones que se asemejen a las de los lenguajes reales (para eso programen en basic, pascal, python, etc, que hay muchos lenguajes fáciles para empezar y con buenos intérpretes).

En otros aspectos la discusión es más abierta. Un ejemplo es la opción de los perfiles de permitir o no utilizar variables para definir las dimensiones de un arreglo. Si no se permite, se añade una complejidad extra tempranamente que tal vez tampoco sea necesaria. Se justifica en algunos casos desde lo conceptual porque interesa que aprendan esta idea de "sobredimensionamiento" cuando el lenguaje no permite tamaños variables (como ocurre por ejemplo con C/C++ estándar para los arreglos estáticos). Pero aún así es un concepto algo arcaico, que tal vez pueda esperar. En casi cualquier lenguaje tenemos arreglos dinámicos de una forma más o menos transparente (con gcc hasta podemos hacer dinámicos los estáticos simplemente dimensionandolos con variables, aunque no es estándar). Si después vamos a enseñarles ese lenguaje de forma práctica, sin destripar los mecanismos internos, vamos a usar esos arreglos dinámicos (como la clase vector en C++) y entonces no vamos a necesitar ese concepto. Si más adelante vamos a llegar a los detalles, igual es probable que sea mejor dejar ese problema del sobredimensionamiento para ese más adelante, cuando la base ya esté firme, y la atención esté apuntando al verdadero manejo de memoria y sus desafíos. Entonces, en la mayoría de los casos no parece buena idea prohibirles usar variables para dimensionar, ya que agrega un problema adicional al diseño del algoritmo, y no parece tener una justificación sólida.

Pero a pesar de lo que digo, en mi facultad les enseñamos a usar el punto y coma y les prohibimos dimensionar con variables. Esto ya era así cuando yo entré, y supongo que se debe a que luego pasamos a C++, donde el punto y coma es importante, y a que en realidad empezamos por C (la orientación a objetos llega más tarde), y entonces usamos arreglos estáticos, y queremos apegarnos al C estándar, etc. No estoy del todo de acuerdo con estas cosas como ya expliqué, pero somos muchos, hay varias opiniones, y hay alguna inercia también. Por ejemplo, el pseudocódigo con el que estudié se pensó (mucho antes de que yo si quiera considerara hacer el intérprete) para pasar luego a Pascal y por eso tiene muchas similitudes. Se manifiesta en instrucciones como Para o Dimensión, que no parecen muy naturales/coloquiales que digamos, sino más bien traducción de un lenguaje real al castellano. Me gustaría más adelante encontrar sintaxis alternativas con más de pseudo, porque estas instrucciones tienen sentido conociendo el futuro (el siguiente paso en el aprendizaje), pero no tienen ninguno pensando en el pasado (lo que el alumno trae como base), y como el alumno solo conoce el pasado, no le resulta para nada intuitivo (por muy natural que le parezcan al docente o a cualquier programador ya formado).

Me quedaron algunas cosas en el tintero para una parte dos, tanto sobre el uso de pseudocódigo en general, como de las reglas particulares de PSeInt y sus perfiles, pero hasta aquí llego por hoy para no aburrir demasiado.

2 comentarios:

  1. te estas enredando en la computación...
    la computación es una ciencia abierta...
    no hay dos personas que piensen lo mismo...
    C != C++ ...
    El proyecto debe tener su propia identidad, ser sencillo...

    ResponderEliminar
  2. me parece muy interesante tu punto de vista, tu planteamiento de PSeInt y me llama la atención no haber visto algo similar hasta ahora.
    he llegado a pseint de rebote leyendo los comentarios en un artículo de neoteo. lo probaré para enseñar a mi hija, a ver como responde.... un saludo desde Barcelona.

    ResponderEliminar