Experiencias de Enseñanza de POO en WISIT 2014

El sábado pasado estuve participando del WISIT 2014. Junto con Pablo Suárez presentamos el enfoque estamos utilizando en FIUBA para enseñar Programación Orientada a Objetos.

En nuestra sesión destacamos 4 puntos que consideramos centrales en nuestro enfoque:

  • Uso de técnicas de educación centrada en el alumno (Learner Centered Teaching)
  • Uso de herramientas informáticas: Campus Virtual de la universidad, Foros, Sistema de gestión de TPs (alfred) y videos explicativos.
  • Uso de dos lenguajes: Smalltalk y Java
  • Test-Driven: no solo enseñamos y usamos TDD, sino que también el desarrollo de los trabajos tiene algo de TDD pues las especificaciones de los que los alumnos deben resolver, la entregamos siempre en forma de pruebas.

Creemos que la presentación salió muy bien y notamos a la audiencia muy interesada. De hecho al finalizar nuestra exposición recibimos varias consultas y más de una persona manifestó intenciones de probar Alfred.

Para facilitar la sesión sesión utilizamos un Prezi que armó Pablo y que está disponible aquí. También armamos este póster que enviamos en su momento a los organizadores del evento como parte de nuestra propuesta de sesión.

Curiosamente hubo otras dos sesiones en las que también se presentaron enfoques de enseñanza de POO. Una de esas sesiones estuvo a cargo de Alfredo Sanzo y Lucas Spigariol quienes contaron su enfoque fuertemente basado en actividades de representación/actuación y en el uso de objetos físicos.

La otra sesión sobre POO estuvo presentada por Nico Passerini, Javi Fernández y Pablo Tesone, quienes mostraron Wollok, una herramienta basada en Eclipse y un lenguaje desarrollado por ellos mismo con el fin específico de enseñanza de POO.

Ambos enfoques me parecieron muy interesantes.

Celebro la iniciativa Uqbar Project de llevar adelante este evento. ¡Que se repita!

Probando excepciones

¿Como probar que un método lanza una excepción ante una determinada situación excepcional? Usando NUnit o JUnit 4, basta con escribir el método de prueba y poner una simple anotación indicando el tipo de excepción esperada.

@Test(expected = ExceptionEsperada.class)  
public void xxxxxx(){
      // ejecutamos la código que debiera lanzar la excepción
}

Pero no todos los xUnit brindan esta posibilidad, entonces debemos apelar a una estrategia similar a la siguiente.

public void test_xxxxxx(){
     try{
         // ejecutamos la código que debiera lanzar la excepción
         fail(); // si ejecución llega hasta esta línea, entonces significa que no se lanzó la excepción esperada y por ende la prueba ha fallado
      }
      catch(ExceptionEsperada ex){
          /* si estamos aqui, entonces se ha producido la excepción esperada y no es necesario
             hacer nada pues a menos que se indique que algo ha ido mail, se asume todo estuvo 
             bien */
       }
       catch(Exception ex){
          // si estamos aqui, es que la excepción que se ha lanzado, no es la esperada, por lo tanto la prueba ha fallado
          fail();
       }
    }

Asi de simple, espero les resulte útil.

Escribiendo pruebas unitarias para código legacy

Desde que volví a trabajar en consultoría este es uno de los temas que más me he encontrado. Sinceramente no me sorprende pues:

  • TDD y la automatización de pruebas, son dos temas que están en claro ascenso de popularidad
  • Casi toda la bibliografía de TDD parte de la base de la creación de aplicaciones desde cero
  • Pero en una porción importante de casos, la gente ya cuenta con una aplicación, la cual muchas veces no ha sido diseñada de forma de facilitar su prueba

Casualmente ayer me crucé con un caso extremo. Resulta que hace un par de semanas dicté un workshop de TDD. Ayer me contactó uno de los asistentes para hacer una consulta de como encarar un caso concreto: tenia que agregar una funcionalidad a la una clase existente. La clase en cuestión tenia más de 3000 líneas de código. Si si, leiste bien, son tres ceros después del tres, o sea, tres mil líneas de código. El problema de una clase tan grande, es que resulta dificil que sea cohesiva. Se supone que pasar ser cohesiva, una clase debe hacer UNA cosa y hacer bien. Con tantas líneas, es muy posible que dicha clase esté haciendo demasiadas cosas.

Pero el problema que motivaba la consulta no eran las 3000 líneas de código, sino el constructor de dicha clase. Resulta que el constructor además de recibir varios parámetros, instanciaba un componente para conectarse a la base de datos. Eso impedia realizar una prueba unitaria de la clase, pues el solo hecho de instancialar implicaba conectarse a la base. Tampoco no habia chances de mockear la conexión pues era instanciada directamente dentro del constructor. ¿que hacer entonces?

Lo primero que uno intentaria es hacer un refactoring de la clase, pero dado que no existian pruebas de la misma, cualquier modificación implicaba un gran riesgo. Luego de analizar varias alternativas llegamos a una solución de compromiso, que nos permitiria escribir tests unitarios: agregar un constructor sin parámetros, que tenga la lógica para lanzar un excepción si era invocado en un ambiente distinto al de desarrollo/test. De esta forma podriamos instancias la clase en forma aislada en un ambiente de test y  aseguramos que no sea instanciada de esta forma en caso de estar en un ambiente distinto.

 

Desafio de diseño: objetos inteligentes (resolución)

(continuación de Desafio de diseño: objetos inteligentes)

Hay varias formas de atacar este problema de la “testeabilidad”.

La primera opción que muchas veces viene a la mente, es hacer públicos los métodos privados y testearlos unitariamente. Si desde el punto de vista práctico esta opción puede parecer viable, cuando la miramos desde el punto de vista conceptual resulta incorrecta, pues dichos métodos son conceptualmente privados y no seria correcto cambiar su visibilidad para solo probar la clase. Si estuvieramos trabajando con C# Visual Studio nos ofrece una alternativa basada en reflexion para acceder a miembros privados de la clase, pero conceptualmente esto sigue siendo incorrecto.

Si pensamos el problema un poco más, nos daremos cuenta que puede que la clase tenga algunos problemillas de responsabilidades. Para ser más explícitos, tiene demasiadas responsabilidades: decidir si moverse y en caso positivo hacerlo, decidir si disparar y en caso positivo hacerlo, etc, etc. Bueno, si asumimos este diagnostico entonces hemos dado el primero paso: identificar el problema.

Repensemos la cuestión una vez más. Una clase que toma muchas decisiones (si X, si Y, si X, etc) y hace muchas cosas (X, Y, Z, etc). Cada una de esas cuetiones las hemos encapsulado en un método privado de cara a tener un código más legible. ¿y si fueramos un paso más allá? ¿Que tal si convertimos cada uno de ese métodos privados en una clase? De esta forma tenenemos una clase con la lógica de movimiento, otra clase con la lógica de disparo y asi sucesivamente. Así nuestro objeto inteligente tiene mucho menos código y su responsabilidad está limitada a coordinar “las estrategias” de movimiento, disparo, etc, etc. Al mismo tiempo cada estrategia puede ser testeada independientemente.

Bueno, este ha sido el primer desafio, próximamente vendrán algunos más.

Titiritero Reloaded

Titiritero es un mini-framework que desarrollamos para Algo3 de cara a ocultar algunas complejidades técnicas como manejo de componentes Swing, threads y otro, que los alumnos suelen enfrentar al realizar sus trabajos prácticos. De esta forma, los alumnos pueden concentrarse en el modelado de objetos que es el principal objetivo de la materia.

Este framework lo comencé yo mismo como ejemplo de implementación de un gameloop siguiendo premisas de diseño MVC. Más tarde algunos otros docentes y alumnos de materia hicieron algunos aportes. De esta forma la base de código fue creciendo de forma medio caótica.

El fin de semana pasado estaba preparando la clase de MVC e introducción a Titiritero para lo cual me puse a desarrollar un nuevo ejemplo basado en Titiritero. Me crucé con un par de comportamientos inesperados y cuando intenté arreglarlos no hice más que sumar más inestabilidad. Claro, esto no me sorprendió porque titiritero tenia una cantidad mínima de pruebas y su cobertura no superaba el 20 %.

Entonces decidí cortar por lo sano y reescribir el framework completo usando TDD y contemplando algunas mejoras que tenia en mente desde hacia ya un tiempo. Para tener un mejor control de los aportes de código realizados por terceros, decidí hostear el proyecto en GitHub para asi poder usar el modelo fork-pull request.

Ttiritero v2.0 está publicado en GitHub y tiene una cobertura superior al 90% ;-)

Un ejemplo de cómo usarlo puede descargase desde aqui, para correrlo es necesario Java JDK 1.6+ y Ant.

Desafio de diseño: objetos inteligentes

Estaba preparando un ejemplo para algo3 cuando me surgió esta cuestión.

Como ya he mencionado en algo3 solemos programar juegos. En general los juegos tienen ciertos personajes que van actuando autonomamente con el paso del tiempo, a estos objetos es a lo que llamo objetos inteligentes. Por poner un ejemplo, tomemos el clásico juego de naves Gálaga, donde las naves enemigas actuan autonomamente con cierta lógica interna.

Cuando llevamos esto a código siguiendo el paradigma orientado a objetos, estas naves solo debieran tener un método público del tipo actuar, el cual seria invocado desde el GameLoop. Dentro de dicho método, cada nave decidiria si moverse en una determinada dirección, o si disparar, o si hacer ambas cosas al mismo tiempo, etc. Con el fin de que dicho método no quede demasiado largo, generalmente extraeremos varios métodos privados: uno con la lógica de movimiento, otro con la lógica de disparo, etc, etc.

Ahora la cuestión es: ¿como escribir pruebas unitarias para esta clase cuando tiene un solo método con tanta lógica? Es claro que es posible escribir pruebas unitarias para estos casos, pero si intentan hacerlo verán que no les quedará código muy feliz, pues el código de arrange de cada prueba podria resultar bastante largo y engorroso de escribir debido a todos los caminos posibles dentro del método bajo prueba. Una opción para evitar esta situación podria ser hacer públicos los métodos privados y asi escribir pruebas por separado para la lógica de movimiento, para la lógica de disparo, etc, etc, pero esto implicaría poner públicos ciertos métodos que naturalmente seria privados, con el solo fin de hacer pruebas. Definitivamente esta opción me hace ruido.

¿Entonces? Tengo una propuesta, pero será parte de otro post, mientras tanto, los invito a lo que piensen.

Continuará….

Resultados del relevamiento sobre POO

Hacé un tiempo publiqué una encuesta para relevar los lenguajes utilizados para la enseñanza de la POO. Esta encuesta la distribuí entre conocidos y también en algunas listas de correo en las que participo. En total obtuve 143 respuestas provenientes de 6 paises distintos de habla hispana (Argentina, Uruguay, Peru, España, Republica Dominicana y Guatemala).

Básicamente la encuenta preguntaba sobre el lenguaje utilizado en la primer materia de objetos, aquella en la que el alumno se cruza por primera vez con los conceptos de polimorfismo y herencia. También se preguntaba sobre la materia/institución y la época, pues entiendo que a lo largo del tiempo ha habido una variación.

El análsis de los resultados me ha llevado un tiempo, pues no se trata de contar resultados individuales, sino que es necesario agruparlas por institución y época.

Los resultados han arrojado que en los casos anteriores a 1990 los leguajes utilizados han sido Object Pascal (Delphi) y Smalltalk.

Durante los años 90 los lenguajes predominantes son C++ y Smalltalk

Ya  a partir del año 2000, comienza a descatarse Java en desmedro de C++ y Smalltalk.

Más allá de estos números, se confirma mi hiṕotesis, la gran mayoria de las intituciones utilizan UN solo lenguaje para la enseñananza del Paradigma OO en la primer materia dedicada al tema.

Con estos resultados puedo seguir trabajando en mi paper sin cambiar el enfoque ya que mi teoría se confirma. Cuando tenga el primer draft lo publicaré en este mismo medio.

Gracias a todos los participaron de la encuesta.

Relevamiento de la enseñanza de POO

Hace un par de dias comencé a trabajar en un artículo sobre la enseñanza de la programación orientada a objetos. En particular sobre la forma de encarar la primer materia de orientación a objetos, pues en la actualidad es común que dicho tema se trate en más de una materia, pero mi foco está en la primer materia, aquella que presenta los conceptosl s fundamentales de OO (polimorfisto, ocultamiento de information, etc, etc). Como parte de este trabajo he creado una encuesta para relevar como es este tema tratado en las distintas carreras. Lo ideal hubiera sido enviar la encuesta a profesores de distintas universidades/institutos, pero lamentablemente no tengo contacto en todas las universidades, con lo cual se me ocurrió hace una encuestas para ser llenada por los alumnos, contestando como fue que cada uno aprendio POO. Es cierto que de este modo seguramente obtenga varias respuestas sobre una misma institución, por eso es fundamental que quien complete la encuesta indique su institución para asi poder filtrar la información.

Por eso les pido a los lectores si pueden tomarse 2 minutos para completar las 6 preguntas de la encuesta y difundirla entre sus conocidos. Los links son:

Muchas gracias!

Eventos (académicos) 2012

Durante el año pasado mientras estudiaba para las materias que cursé en la maestría de la UNLP, se me ocurrieron dos artículos que me gustaría desarrollar para presentar en algún congreso y casualmente recien empezado el año tengo tres posibles eventos donde presentarlos.

El primero es ArgenCon, organizado por la sección argentina de IEEE. El mismo se desarrollará del 9 al 13 de Junio  en Córdoba. La fecha límite para el envío de trabajos es el 15 de Marzo.

El segundo evento es la edición 41 de las JAIIO, este año organizadas en conjunto con la UNLP entre el 27 y 31 de Agosto. La convocatoria de trabajos trabajos esta abierta hasta el 30 de Abril.

Finalmente el tercer evento que tengo en el radar es Foro Mundial de Educación en Ingenieria (WEEF: World Engineering Education Forum). Sinceramente nunca había nunca había escuchado hablar de este evento (tal vez porque no siempre se realiza en Argentina). El mismo será organizado por UTN y se desarrollará en Buenos Aires del 15 al 18 de Octubre. La fecha límite para el envio de trabajo es el 2 de Marzo.

Volviendo a los trabajos que tengo en mente, el primero es sobre el enfoque que estoy utilizando en UNQ para dictar ingeniería de software. El otro es sobre algunas ideas que he venido madurando para la enseñanza de la programación en los cursos introductorios de programación.

Orientación a Obejtos Pura

Es común cuando se presenta Smalltalk mencionar que es un lenguaje orientado a objetos puro. También es común que la audiencia no logré captar el significado de esta afirmación inmediatamente. Yo mismo he analizado esta afirmación montones de veces, pensando que tal vez sea un poco extrema, pero esta semana, vi la luz y me dí cuenta de que es absolutamente acertada.

Resulta que por estos dias, me encuentro entrenando a un grupo de programadores en C#. Fue en este contexto que me encontré hablando de las diferencias y relaciones entre interfaces, clases, estructuras (structs) y enumerados, ¡recorcholis! 4 artefactos del lenguaje que NO son objetos. ¡Y aún no expliqué eventos, delegados, tipos primitivos y atributos (anotaciones)!. ¡Cuantas cosas que explicar!

¡Cuanto más fácil seria explicar Smalltalk!