viernes, 26 de octubre de 2007

Videos de Squeak BOF

Pueden bajarse de http://goran.krampe.se/blog/OOPSLA/OOPSLA07-1.rdoc unos videos sobre el Squeak BOF que ser realizó en OOPSLA este año.
Es interesante ver la OLPC en acción (o por lo menos como luce)

lunes, 22 de octubre de 2007

Sobre bloques

Que tal,
hace un par semanas que no puedo escribir porque la organización de Smalltalks 2007 me está llevando más tiempo del pensado, pero lo estamos haciendo con mucho entusiasmo así que es tiempo bien invertido.
Lo que quería hacer hoy era reflexionar sobre los bloques de Smalltalk. Como todos saben, los bloques son objetos que representan colaboraciones, o sea, en un lenguaje más básico, código.
Idealmente, los bloques deberían ser polimórficos con los métodos compilados, que son los otros objetos que modelan colaboraciones entre objetos, sin embargo en la realidad no lo son y además poseen algunas pequeñas diferencias que no tiene sentido nombrar ahora porque están fuera del objetivo de este post.
En realidad lo que me interesa es conversar un poco sobre las desventajas de los bloques puesto que las ventajas saltan a la vista (siendo la más importante, desde el punto de vista de "computer science" que representan funciones lambda).
Uno de los problemas surge al momento de enseñar qué son los bloques. Es muy difícil para los que recién empiezan a utilizar Smalltalk (y más si no conocen Lisp o algo similar) entender que las colaboraciones también se modelan con objetos. No entiendan que los bloques son objetos y los ven como construcciones sintácticas. En particular resulta complicado que entiendan que el contexto de evaluación del bloque no es el bloque mismo sino el contexto en el cual fue creado el bloque.
Otra desventaja es la tentación de poner colaboraciones muy complejas o muchas colaboraciones en un bloque. En realidad podemos decir que esto sucede con cualquier método, no solo bloques, pero como supuestamente los bloques existen para poder "escribir código" rápidamente es que parece que nos olvidamos que también deben seguir ciertas reglas básicas. Una cosa es "escribir código" rápidamente cuando se está trabajando en inspectores, workspace, etc., y otra es "escribir código" en un browser, puesto que este perdura.
Es muy común ver este caso cuando se usa el mensaje #select:, donde el motivo de la selección de objetos implica verificar muchas cosas sobre el objeto en cuestión y entonces se empiezan a componer condiciones lógicas con #and: y #or: que no permiten entender a primera vista la intención del #select:. Por ejemplo:

....
trades select: [ :aTrade |
(aTrade isPurchase or: [aTrade isSale])
and: [Date today bettween: aTrade aggrementDate and: aTrade settlementDate]].
....

Este ejemplo adolece de varios males. El primero, como comenté, no se entiende qué se está seleccionando a simple vista, hay que analizarlo detenidamente. El segundo un poco más conceptual, es que seguramente hay alguna característica del objeto en cuestión que debería saber responder él, debería reificarla él y no aquellos que lo usan.
Para resolver el primer caso, siempre mi consejo es no haya más de un envío de mensaje dentro de un bloque, y que dicho mensaje "revele la intención" del bloque. Por ejemplo:
....
trades select: [ :aTrade | self isActive: aTrade ]
....

Un comentario al margen; fijensé que el mensaje se llama #isActive: y no #isTradeActive: puesto que se lee mucho mejor "self isActive: aTrade" que "self isTradeActive: aTrade". El segundo caso comete el error de poner el tipo del colaborador en el nombre del mensaje, un error muy común realizado por aquellos que vienen de los lenguajes "parentisados" puesto que en dichos lenguajes deben poner en el nombre si o si alguna referencia a los colaboradores puesto que no se los lee de manera tan similar al lenguaje natural como Smalltalk.
Volviendo al ejemplo, ahora se puede leer mucho más claro qué objetos se están seleccionando y además en caso de querer modificar el motivo de selección, no habrá problema en hacerlo. Mientras se está iterando la colección, se puede modificar el método #isActive: sin problema, modificando el comportamiento on the fly y sin necesidad de reiniciar la ejecución de select.
Si por el contrario, dejamos el bloque como el primer ejemplo, cada vez que se lo modifique, el debugger reiniciará la ejecución desde el principio del método donde está definido el bloque. Esto es necesario porque el contexto de evaluación dejó de ser válido y es necesario reiniciarlo, aunque se podría argumentar que se modificó el bloque y no el método per-se.
Peor aún si tenemos el siguiente código:
....
trades select: self activeTradeBlock
....
activeTradeBlock

^[ :aTrade | (aTrade isPurchase or: [aTrade isSale])
and: [Date today bettween: aTrade aggrementDate and: aTrade settlementDate]]
....
En este caso, si queremos modificar el bloque desde el debugger, no podremos. En VisualWorks saldrá un error que dice que no se puede modificar el bloque porque su contexto no está en el stack de ejecución. En el caso de VisualAge, no chistará pero tampoco modificará el bloque.
Más confusión trae a los principiantes si van y modifican el método #activeTradeBlock desde un browser mientras están iterando los trades con el debugger puesto que el cambio no surtirá efecto!! y claro, no surtirá efecto porque el objeto instancia de Block que contiene las colaboraciones que se están evaluando ya existe y no se creará uno nuevo hasta que no se evalúe el método #activeTradeBlock nuevamente.
Es por este motivo que también aconsejo poner siempre un solo mensaje en el bloque puesto que si el ejemplo dijera:
....
trades select: self activeTradeBlock
....
activeTradeBlock

^[ :aTrade | self isActive: aTrade ]
....

modificar el comportamiento de #isActive: es factible y se logra la flexibilidad y dinamismo esperado de un ambiente de objetos.
Por último, y yendo al plano conceptual, el encargado de tener la responsabilidad de decidir si está activo o no es el mismo trade, por lo tanto el ejemplo debería quedar:
....
trades select: [ :aTrade | aTrade isActive ]
....

De esta manera no se pierde flexibilidad y además la responsabilidad está bien otorgada. (No siempre se puede delegar la responsabilidad de selección en el objeto que se está analizando, por eso dejé el ejemplo donde se envía el mensaje #isActive:, pero está claro que lo mejor es utilizar este último caso)
Otro problema que traen los bloques se observa trabajando con objetos distribuidos. ¿Qué significa distribuir un bloque es está bindeado a un stack de ejecución particular? En particular, utilizando GemStone se encuentra esta limitación rápidamente si se intenta pasar un bloque como objeto remoto (GemStone provee soluciones, como utilizar un decompilador para recrear el bloque en la imagen remota, pero no siempre dicho decompilador está disponible como por ejemplo en VisualAge). Para estos casos, la mejor solución es crear un objeto que sea polimórfico con el bloque que se utilizaría. Por ejemplo:
....
trades select: IsActiveTradeCondition new
....
IsActiveCondition>>value: aTrade

^aTrade isActive

....
La desventaja que tiene esta opción es que se pierde justamente la facilidad que ofrecen los bloques de no tener que crear un clase cada vez que se quiere modelar colaboraciones o que los mismos sean expresiones lamda, pero se gana en la posibilidad de modificar el comportamiento dinámicamente y en poder distribuir el objeto sin problema.
Un caso concreto de abuso de bloques es el framework de SmallLint. En esta herramienta las reglas pueden ser modeladas con bloques, sin embargo el código de las reglas que provee está escrita en el bloque mismo, produciendo los problemas ya comentados. Me acuerdo haber realizado varios extract method para poder modificar las reglas existentes de manera dinámica puesto que sino, me sucedía lo comentado más arriba.
En conclusión, los bloques son muy útiles, pero al momento de no estar trabajando únicamente con inspectores o el workspace, hay que usarlos con más cuidado y sin olvidar, como siempre, que el código que uno escribe debe poder ser modificado dinámicamente y que seguramente será leído muchas más veces que escrito y por lo tanto cuanto menos esfuerzo de lectura implique, mejor.

martes, 9 de octubre de 2007

Smalltalks 2007 - Primer Congreso Argentino de Smalltalk

Les comento que estamos organizando un congreso de Smalltalk en Argentina!!
La primera vez de este tipo. Seguro ya recibieron el anuncio por otro lugar, pero bueno, no podía dejar de anunciarlo aca!!

--------------------------------------------------------------------------

Smalltalks 2007

--------------------------------------------------------------------------

El Lunes 10 de Diciembre de 2007, desde las 9:30 hasta las 18:00 horas
se llevará a cabo en la Facultad de Ciencias Exactas y Naturales (FCEN) de
la Universidad de Buenos Aires, el Primer Congreso Argentino de Smalltalk,
denominado "Smalltalks 2007"

Todas aquellas personas que estén relacionadas con Smalltalk, sean
docentes, alumnos, investigadores, desarrolladores o empresarios, están
invitados a participar como oyentes o expositores de manera gratuita
inscribiéndose en http://www.dc.uba.ar/smalltalks2007 .

El objetivo de la conferencia es reunir a la comunidad Smalltalk Argentina
para estrechar vínculos compartiendo un día de exposiciones de trabajos,
experiencias y vivencias relacionadas con esta tecnología o temas afines.

La jornada estará dividida en dos secciones:
1) Sección de Investigación/Educación
2) Sección de Industria

En la "Sección de Investigación/Educación" se expondrán aquellos trabajos de
investigación y educación que se estén realizando o se hayan realizado con
Smalltalk, en ámbitos de universidades y establecimientos públicos o
privados.

En la "Sección de Industria" se expondrán trabajos relacionados al
Desarrollo de Software en Argentina utilizando Smalltalk.

Algunos temas sugeridos para las presentaciones, de manera no excluyente son:
* Prácticas Ágiles (XP, TDD, etc)
* Herramientas de Desarrollo
* Desarrollo con Prototipos
* Model Driven Development
* Desarrollos de Aplicaciones Web
* Meta-Modeling
* Nuevos Modelos o Frameworks implementados
* Nuevos Frameworks de UI
* Material Educativo
* Sistemas Embebidos y Robótica
* SOA y Web services
* Reportes de Experiencias de Desarrollo o Investigación
* Sistemas comerciales

Aquellos interesados en exponer, deben tener en cuenta los siguientes
hitos y tareas:

1) Deben presentar un Abstract de la presentación a más tardar para el
Lunes 5 de Noviembre de 2007. Dicho Abstract no debe superar dos carillas
y debe incluir mínimamente una descripción del trabajo a presentar sin
omitir el objetivo del mismo y la sección a la cuál se apunta la presentación.
Debe detallarse también si la presentación incluirá una demostración en vivo
del modelo Smalltalk relacionado. El Abstract se puede presentar enviando un
email a smalltalks2007@gmail.com indicando como subject "Presentación"

2) El Comité de Programa de la Conferencia definirá para el Lunes 19 de
Noviembre aquellos trabajos que serán elegidos para ser presentados durante
la jornada a partir de los Abstracts recibidos según lo especificado
en el punto anterior. Se dará mayor importancia a aquellos trabajos con
capacidad de mostrar ejemplos dinámicos y no únicamente presentaciones
estáticas.

3) Aquellos que sean seleccionados para realizar las exposiciones, deberán
como mínimo generar un presentación con Power Point o herramienta similar.
(Por restricciones de tiempo, no se exigirá presentación de paper, pero se
agradecerá a aquellos que puedan hacerlo). Todo material utilizado para
la exposición (presentación, paper si corresponde, etc.) deberá ser
entregado en su totalidad a más tardar el Miércoles 5 de Diciembre para la
realización de los Proceedings de la Conferencia.

4) La definición del Cronograma de la Conferencia se publicará a través
de la página web el Lunes 26 de Noviembre.

Las actividades se llevarán a cabo en el aula Magna del Pabellón de
Industrias de Ciudad Universitaria. Para más información sobre cómo llegar,
dudas, fechas, programa, etc., pueden acceder a
http://www.dc.uba.ar/smalltalks2007

Los esperamos a todos!
Comité Organizador de Smalltalks 2007

viernes, 5 de octubre de 2007

Morph en JavaScript!

Quién dijo que Morph está muerto? Miren en que mata el tiempo Dan Ingalls en Sun... (ahora yo me pregunto, en Sun le permiten hacer estas cosas porque JavaScript empieza con Java? :-) )
(Copio el mail que mando a la lista de Squeak)
---------------
Folks -

As many of you know, I and a couple of friends at Sun have been
playing around with JavaScript, and we've finally figured out out how
to have fun with a browser.

You can find out all about it at...

http://research.sun.com/projects/lively/

...and if you have a very recent build of Safari (preferably Webkit
nightly builds) or FireFox (preferably latest Gran Paradiso build),
then you can probably have fun with it too!

It's not at all polished, but it should look strangely familiar ;-)

Enjoy
- Dan

lunes, 1 de octubre de 2007

¿Cómo asegurar la evolución de un sistema?" - Parte II - Visitor

Que tal,
algo que estuve haciendo últimamente tiene que ver con cómo asegurar en un ambiente dinámicamente tipado la implementación correcta del patrón Visitor.
Los problemas que este patrón puede generar son:
1) La clase root de la jerarquía de clases que se visita no implementa el mensaje #accept: como subclassResponsibility
2) Los visitors no implementan todos los mensajes que envían lo objetos que se pueden visitar
3) Lo contrario de la 2), los visitors implementan mensajes que no se envían desde los objetos que se visitan

Aquellos programadores defensores del tipado estático arremeterían contra los lenguajes dinámicos argumentando que estos errores no sucederían en dichas herramientas. La verdad es que a simple vista pareciera que no sucederían, sin embargo no es tan así.
En el caso del punto 1) , este error se vería evidenciado solo al momento de utilizar un Visitor sobre dicha jerarquía y únicamente si la variable del objeto que se quiere visitar está "claseada" (tipada) con la clase root que acepta visitors. Este error puede por lo tanto, pasar inadvertido por bastante tiempo (a menos que se esté utilizando TDD)
El punto 2) es donde se hace efectivo el chequeo de tipos puesto que no sería factible que un objeto visitado pueda enviar un mensaje no definido en el visitor que recibe como colaborador. Sin embargo el punto 3), que es el caso que típicamente se da en la evolución de un sistema, no es evidenciado como error por un sistema de tipos. Este caso se da al borrar por ejemplo, una clase de la jerarquía que es visitada.
Como podemos ver, hay ciertos aspectos del patrón Visitor que un sistema de tipos no puede asegurar. Es por ello que muchas veces se ha hablado de reificar los patrones como "first class objects", hacerlos de alguna manera, parte del metamodelo.
Sin embargo, cómo puse más arriba, hay 3 condiciones que se deben cumplir para que un visitor esté correctamente implementado, es por ello que implementé 3 test utilizando SUnit que verifican dichas condiciones: (Estos test los llamamos test de "Estándares de Código" y solamente se corren antes de cerrar una "unidad de trabajo")
1) Toda clase que defina el mensaje #accept: debe tener una superclase que implemente el #accept: como subclassResponsibility o indicar cual es la clase root de la jerarquía que acepta el visitor (esta última parte se debe a aquellas clases que quedan mal clasificadas por diversos motivos, pero que aún así deben poder ser visitadas por el mismo visitor que las clases que se encuentran bien clasificadas). Es importante que este test no falle puesto que de hacerlo puede haber algún objeto instancia de una clase de la jerarquía visitada que no implemente el mensaje #accept:. Este test hace uso de otro test que verifica que todo mensaje definido como subclassResponsibility es implementado en las subclasses concretas.
2) Todo objeto que sepa responder a un mensaje #visitXXXX:, debe saber responder a todos los mensajes #visitXXX: que son enviados por los objetos que pertenecen a la jerarquía que define la clase root que acepta el visitor
3) Los mensajes #visitXXX: que sabe responder un objeto deben ser igual al protocolo que define el Visitor. Si hay algún otro mensaje #visitXXX: implementado por un objeto que no corresponde a los visitors que dicho objeto implementa, quiere decir que el método que implementa ese mensaje es candidato a ser eliminado.
Para implementar estos test reifique algunos conceptos como VisitorProtocol y VisitorImplementation, de tal manera que se puede crear el VisitorProtocol de esta manera:

visitorProtocol := VisitorProtocol for: aClassRootAcceptingVisitor

y luego colaborar con visitorProtocol de la siguiente manera:

visitorProtocol isValid <-- Indica si el protocolo es válido, i.e., no tiene mensajes #visitXXX: repetidos
visitorProtocol implementors <-- Devuelve todas las clases que implementan el protocolo

y con un VisitorImplementor se puede:

visitorImplementor isValid <-- Indica si este implementor implementa correctamente el visitor
visitorImplementor missingImplementors <-- Devuelve los mensajes que no están implementados por este visitor
visitorImplementor implementMissingImplementors <-- Crea un implementación default para todos aquellos mensajes que no están implementados
visitorImplementor extraImplementors <-- Devuelve los mensajes que sobran en la implementación
visitorImplementor deleteExtraImplementors <-- Borra los mensajes que sobran en la implementación

Lo interesante de esta implementación es que mientras se está desarrollando y experimentando con un modelo, se pueden romper estas reglas, de hecho se hace constantemente y solo son verificadas en el momento oportuno. Y como toda regla, puede tener sus excepciones, algo imposible de hacer con un sistema de tipos cerrado.
Conclusiones:
1) Reificar las reglas de desarrollo que define el grupo de trabajo en el que se encuentran
2) Implementar test que verifiquen dichas reglas
3) Hacer estos test de tal manera que solo corran en el momento oportuno, que no sean una molestia

En definitiva, hacer que los mismos objetos se responsabilicen de su evolución (en este caso a través de 1, 2 y 3).