08 febrero 2008

Los prefijos "set" y "get" en Java son un dolor de bolas

Canilla

¿Para que lado se gira una llave de paso de una canilla... izquierda o derecha?

Es difícil responder a esta pregunta de forma instantánea. Uno se tiene que poner a pensar en como usa canilla, y quizás hasta hacer el gesto con la mano de como se gira la llave de paso. Sin embargo cuando nos vamos a lavar las manos, lo hacemos de forma inmediata, y ni siquiera tememos que pensarlo.

¿Por que pasa esto?

Por que la canilla en si misma tiene la información para utilizarla. Según Don Norman, en su libro “The Design of Everyday Things”, todas las cosas que usamos diariamente contienen una cantidad enorme de información. Información que no nos interesa retener de forma exacta en la cabeza, pero que tenemos presente a la hora de utilizarlas.

Es por eso que desde el punto de vista de usabilidad, las cosas bien diseñadas no requieren un manual de uso: el mismo objeto nos da información de como utilizarlo.

¿Y de que forma se nos presenta esta información?

Siguiendo con el libro de Norman: esta información se nos presenta por medio de affordances y restricciones (constraints).

En el caso de la canilla, la misma forma nos incita a girarla (affordance) y es la rigidez de la llave de paso nos dice: “para este lado no abre... proba para el otro” (constraint).

Estos constraints pueden ser físicos, como en el caso de la canilla. O bien culturales.

A simple vista pareciera que los constraints culturales son más “leves”, sin embargo pueden tan fuertes como los físicos, por ejemplo si tengo un muñeco para armar sé que la cabeza tiene cierta dirección (a menos que este armando un modelo de la chica de Poltergeist).

Playmobil

En los lenguajes de programación pasa mas o menos los mismo. Hay constraints “físicos”: si no uso la sintaxis correcta el programa no compila. Y constraints culturales, por ejemplo en Smalltalk o Java nadie usa nombres de clase en minúsculas.

Este blog post parte de la hipótesis de que en programación estas restricciones culturales a veces pueden influir en la forma en que pensamos los problemas.

Por ejemplo en Smalltalk, se suele tener la convención “cultural” de hacer que los métodos tengan nombres cuya escritura sea similar a un texto en ingles, por ejemplo:

client loginWith: credentials toServerAt: address.

En cambio si uno ve cosas de este estilo:

client setCredentials: credentials; setServerAddress: address; login.

Suena raro. Por lo que esta convención tiene un impacto en como esta diseñado el framework: uno pone más énfasis en la comunicación de la intención, que en los detalles de implementación.

Hecha toda esta introducción voy a ir al tema que le da titulo a este post.

JavaBeans

Entre las las “restricciones culturales” que existen los lenguajes de programación, identifico dos grupos:

  • Las que provienen de hacer mas legible el código
  • Las que provienen de una cuestión de implementación

En el caso de Java, entran en el primer grupo cuestiones como: las clases van en CamelCase, los paquetes en minúsculas, los métodos en minuculasMayusculas sin usar “_” como separador de palabras, etc.

Y en el segundo grupo cuestiones como poner el prefijo “set” o “get” si el método es un accessor a una variable de instancia.

Este uso de “set” y “get” se lo debemos principalmente al framework de JavaBeans.

Para los que no conozcan el framework de JavaBeans, les cuento un poco la historia:

Con la aparición de editores gráficos, muchas veces se hace necesario contar con metadata que permita manipular a los objetos gráficamente. El problema de esta metadata es que agrega una complejidad que suele ser bastante molesta: la metadata es importante para el framework, pero no para el problema que tratamos del modelar.

Por esta razón los diseñadores del framework, separaron la metadata de los objetos que modelan el problema. En el caso de JavaBeans, un editor que manipula objetos gráficamente puede utilizar la metadata proveniente de una clase que implementa BeanInfo.

Esta clase entre otras coas posee información sobre que atributos se pueden manipularse gráficamente.

El problema es que crear estas clases BeanInfo es bastante molesto. Por lo que los diseñadores del framework agregaron un shortcut: si no hay BeanInfo se asume que la clase sigue una convención de nombres (el “set” y “get”) para saber que métodos se utilizan para modificar el estado del objeto.

Luego la misma metadata fue utilizada para paginas web, con la intención de hacer editores gráficos. Y así fue como la convención de “set”, “get”, “is” se empezó a utilizar en todos lados. Hasta que finalmente, no importa si un objeto va a ser manipulado gráficamente o no: todos los desarrolladores en Java usan la convención del prefijo “set”/”get”.

Consecuencias del “set”/”get”

Sin embargo esta convención tiene sus consecuencias: uno empieza a pensar en los objetos como si fuesen estructuras de datos potenciadas.

Cualquier fanatico de objetos diria: un objeto no es una estructura de datos con métodos!

Pero entonces... ¿Cual es la diferencia?

Bueno desde el punto de vista de implementación uno puede ver a los objetos como si fuesen estructuras de datos con métodos. Al igual que uno puede ver a todos los sistemas computacionales como una gran maquina de estados.

El problema no es que este punto de vista sea erróneo, el problema es que no es un punto de vista útil para diseñar un sistema orientado a objetos. Ocurre lo mismo con las maquinas de estados: plantear todo sistema como maquina de estados es útil para utilizar herramientas de model checking, pero hace que el sistema sea más difícil de entender por un humano. (es análogo a lo que ocurre en matemática: si uno se pone a demostrar todo con una formalidad lógica exacta el problema se hace mucho más difícil de manejar).

Voy a mostrar lo que comenté con un ejemplo, si uno ve este código:

display(directory.getFiles());

Uno lee: “mostrar, directorio obtener archivos”.

En cambio si no ve:

display(directory.files()).

Uno lee literalmente: “mostrar archivos del directorio”.

La diferencia es sutil, pero ese “get” en el medio hace que uno piense en el objeto directorio como si fuese una estructura de datos con una variable files adentro.

A lo que quiero llegar con este largo post es que habría que eliminar de una vez por todas la convención de “set”/”get” de Java!

No aporta mucho desde el punto de vista de comunicación ya que es muy fácil por contexto darse cuenta si un método cambia el estado de un objeto, y resulta perjudicial para plantear problemas desde el punto de vista de orientación a objetos.

Fotos:
La foto de la canilla fue obtenida de esta dirección http://flickr.com/photos/cwalker71/1021798486
Y la del playmobil de: http://flickr.com/photos/eleftheriag/370683078
Ambas tienen licencia Creative Commons, y pertenecen a sus respectivos autores.

2 comentarios:

  1. Me gustó la explicación que se da, empezando por la introducción...

    En fin, yo lo que esperaba era aprender a usarlos (get y set).

    Estoy aprendiendo a programar y hasta el momento lo había hecho sin usar estas palabritas y ahora, que me ha tocado usarlos en un programa que me dejo la maestra, estoy viendo que es un poco complicado.

    Pero en mi opinión, así como inexperto que soy en el tema, creo que para ser un buen programador no importa que obstaculos se le presenten, hay que buscar la forma de resolver todos estos aun por metodos en que no estemos acostumbrados a realizar. Algo de informacion y experiencia que se obtiene al tratar de resolver el problema no hace daño.

    ellechuguero@hotmail.com

    ResponderBorrar
  2. @temoc
    Gracias por tu comentario.
    Y bienvenido al mundo de la programación... espero que disfrutes de crear programas y resolver problemas con la maquina. (entre otras cosas :P)

    Generalmente en el blog escribo conclusiones "sueltas" de cosas que lei o que estuve viendo. Pero tu comentario me hace pensar que sería interesante quizas empezar a postear notas de algunas de las clases que di (una de las cosas q hago para ganar plata es dar cursos de Java y J2EE).
    Tengo el blog bastante olvidado... asi que quizas en los proximos posts escriba una introducción a POO.

    Sobre tu comentario de la programación:
    "Algo de información y experiencia que se obtiene al tratar de resolver el problema no hace daño"

    No solo "no hace daño" si no que para mi es lo principal! (busca en este blog los posts de Programming as Theory Building).

    Saludos,
    Diego

    PD: Vi que en tu comentario pusiste tu mail... no te lo recomiendo! Dejar un mail asi es propenso a que te llenen de spam. (hay programas que escanean paginas en busca de direcciones de mail)
    En blogspot tenes una opción de seguir los comentarios por mail, asi cuando contesto te llega a la casilla

    ResponderBorrar