swing agenda

Estoy encantado de hacer público un pequeño experimento que he bautizado con el arrebatador nombre de swagenda. Para lanzar la aplicación basta con clicar un link: lanzar swagenda. Hay una página desde la que ese link será accesible permanentemente y que contendrá siempre la última versión estable. Los fuentes de la aplicación están disponibles en un proyecto de Google code.

Swagenda es una aplicación java que accede a la agenda de un usuario en 11870.com (los sitios que tenga guardados). Sólo permite verlos, no modificarlos, y comparado a acceder directamente a 11870.com ofrece las siguientes ventajas:

  • Velocidad supersónica aplicando filtros
  • Funcionamiento offline
  • Filtros y ordenaciones alfabéticas de los sitios
  • Diseño sexy

Está bien, la última la borramos 🙂

Por supuesto todas estas ventajas no desmerecen en absoluto el desarrollo técnico tras la web de 11870.com, desarrollo del que personalmente soy arte y parte. Las características de swagenda son fruto de un enfoque técnico diferente, enfoque no aplicable a 11870.com en general, pero que la API posibilita.

El poder del escritorio

Swagenda es un cliente Swing de la API de 11870.com. Se publica por Java web start y hace uso de Apache Abdera. Es un prototipo que tiene el objetivo de demostrar al mundo, incluyendo en ese mundo a mí mismo, que las aplicaciones de escritorio resuelven muchos problemas mejor que las aplicaciones web. Por muy rich client que sean esas aplicaciones web.

swagenda screenshot swagenda filters swagenda place details

Honestamente creo que es así. Creo que hay un hueco importante en el desktop que la web aún no ha cubierto y probablemente no vaya a cubrir. No obstante esta aplicación no va a ser la que demuestre estos extremos, seguramente porque no le he podido proporcionar el tiempo y la dedicación que merecía o directamente por mi falta de destreza en el escritorio, por no hablar de mi particular gusto plástico, que hace que lo que yo veo como arrebatadoramente hermoso haga que otros se planteen mi salud mental.

He liberado el código de la aplicación, y si alguien se toma la molestia de mirarlo y tiene algún comentario estaré encantado de escucharle. Si a alguien le apetece participar en el desarrollo de lo que tenga que venir, estaré aún más encantado.

Pendiente

Las tareas en las que me debería ocupar en adelante, de mayor a menor prioridad:

  • Acabar la pantalla de detalle de opinión.
  • Editar opiniones.
  • Subir fotos y vídeos. La integración con el escritorio es uno de los puntos fuertes de swing, la subida de multimedia una de las grandes debilidades de la web.
  • Deshacernos de abdera. Nada en contra del proyecto, pero dejaría swagenda unas diez veces más ligero.
  • Deshabilitar los filtros no aplicables: cuando seleccionas la localidad Alpedrete sólo permitir pinchar en las tags que hayas usado en sitios de Alpedrete.
Anuncios

Los accessors en java

Comencé a trabajar con java hace unos ocho años. Desde el principio aprendí que el uso de accessors era una buena práctica. Consiste en declarar las variables de instancia como privadas y definir unos métodos públicos, llamados getters y setters para acceder a esos atributos. Algo como esto:

private String foo;
public void setFoo(String foo) {
  this.foo = foo;
}
public String getFoo() {
  return foo;
}

Para acceder a foo entonces escribimos el siguiente código:

objeto.getFoo();
objeto.setFoo("mucho código, pocas nueces");

Nunca me acabaron de encajar demasiado, pero hasta ahora no había dedicado algo de tiempo a ello. Creo que los accessors son sencillamente una mala práctica y sería prudente dejarlos atrás. Una de las críticas más socorridas que se hace a java es su “verbosidad”, la crítica no carece de fundamento y los accessors son un ejemplo de ello.

La alternativa es simple. No utilizar accessors y hacer las variables públicas:

public String foo;

Para acceder a esta variable, entonces:

objeto.foo;
objeto.foo = "ahora sí";

La comparación es demoledora 🙂 aunque un poco simple, me recuerda a los argumentos que esgrimen muchas veces de forma poco fundamentada los enemigos de java, así que me esforzaré un poco más.

En realidad el problema (o más bien la ventaja) es que los accessors son una convención, de forma que si tu código está aislado bien puedes decidir tú cómo organizarlo, java no hace uso en ningún caso de los accessors. Pero multitud de frameworks y productos hacen uso de la convención y esperan que existan los accessors para acceder a las variables de instancia. Así ocurre con Spring, Hibernate y Expression Language, por poner tres ejemplos cotidianos para muchos programadores java en entornos internet.

La solución pasa por flexibilizar el estándar. Complicarlo, por desgracia, a cambio de simplificar mucho el código de los usuarios de esos frameworks. La lógica sería la de buscar el accessor para la variable que tratamos de acceder y si no lo encontramos atacar a la variable directamente. Sólo al no encontrar la variable en este segundo paso devolver un error. Esto proporcionaría compatibilidad hacia atrás de todo el código ya escrito para funcionar con accessors. Esta propuesta tiene el peligro de ser una sobrecarga en rendimiento. En todo caso lo que yo quiero es hacer ver que los accessors son una mala práctica, las soluciones pueden ser distintas de esta que propongo y que soy consciente que debería soportar con pruebas.

Algo de historia y una justificación

Si bien los accessors empezaron a utilizarse en C++, en java hicieron su aparición estelar como parte de la especificación de los JavaBeans. En ese contexto no sólo tienen sentido sino que son necesarios. Los JavaBeans como componentes nunca triunfaron por razones que desconozco, pero dejaron la percepción de que era una buena decisión de diseño fomentar el uso de los accessors. De hecho yo también creo que lo es, pero sólo en determinadas circunstancias. En Data Structures and Algorithms with Object-Oriented Design Patterns in Java Bruno Preiss es muy conciso respecto a las virtudes de los accessors:

“By defining suitable accessors, it is possible to hide the implementation of the class from the user of that class”

Esconder la implementación de la clase del cliente de la misma no me parece una ventaja per se, aunque sí puede serlo en el caso de que tu código vaya a ser distribuido y consumido por terceras partes como por ejemplo si haces un framework. Si eres un programador de Spring puede ser una buena idea ser estricto en el uso de los accessors, de esa manera aseguras la compatibilidad hacia atrás incluso aunque cambie la estructura de tus clases. Sin embargo, si es tu propio proyecto el consumidor de tu código, esa ventaja se diluye, dado que igual que cambias el código del productor puedes cambiar el de los consumidores. El hecho de que java sea estáticamente tipado y que existan los IDEs modernos hacen que esa tarea sea trivial. Eso en todo caso siempre que modifiques una clase estructuralmente sin que sus clientes deban modificarse, algo que la experiencia me dice que rara vez va a ocurrir.

Todas las refencias que he encontrado son muy antiguas. Parece que todos hemos dado por buena la necesidad de los accessors y ya no hay debate sobre ellos si alguna vez lo hubo. Scott Ambler escribe un artículo en defensa de los accessors en octubre de 2000.

Sólo 26 días después publica un segundo artículo abundando en el mismo tema. En un análisis más exhaustivo encuentra múltiples virtudes de los accessors y encuentra un solo defecto. Las virtudes se pueden resumir en una frase del primer artículo:

“Getters and setters are useful because they enable you to encapsulate important business rules, transformation logic, and validation logic that are applicable to your data fields”.

El defecto:

“The only time you might not want to use accessors is when execution time is of the utmost importance”

El defecto creo que sinceramente ha quedado superado con el tiempo, no sólo por el abaratamiento del hardware sino sobre todo por las mejoras en la máquina virtual de java, que creo que harán la diferencia de rendimiento entre usar o no accessors imperceptible.

En cuanto a las ventajas creo mete el dedo en la llaga mencionando la lógica de validación. Tiene mucho sentido que el setter valide si el valor que estamos tratando de setear es correcto. Creo que ésta es la gran virtud práctica de los setters, pero no veo necesario renunciar a ella si seguimos un modelo mixto: al escribir una variable de instancia primero busco su setter, si lo encuentro lo ataco, si no voy directamete contra la variable.

El siguiente artículo, escrito por Allen Holub, me pareció esperanzador al leer el título: Why getter and setter methods are evil, pero no podía estar más alejado de mis tesis:

“Getter and setter methods (also known as accessors) are dangerous for the same reason that public fields are dangerous: They provide external access to implementation details”.

Holub piensa que exponemos demasiado al utilizar accessors, aún propone esconder más el código. Considera que esconder el código es una virtud per se. Me parece una perspectiva interesante aunque quizás muy académica y que nos obligaría a repensar cómo estructuramos el código. No sólo el nuestro sino el de los frameworks que usamos.

Otros lenguajes hacen uso de los accessors no ya como convención sino como parte estructural del lenguaje. Así ruby no proporciona visibilidad fuera del propio objeto a las variables de instancia forzando así la existencia de accessors. De forma muy conveniente, eso sí, proporciona una keyword que implementa los accessors en runtime: attr_accessor.

JavaFX es un lenguaje que ha evolucionado a partir de java y prescinde de los accessors, a cambio implementa triggers. La única utilidad entonces que los diseñadores de JavaFX vieron a los accessors es lanzar operaciones sobre la escritura. Por cierto, ¿qué ha sido de JavaFX?.

Resumen

Los accessors proporcionan una serie de ventajas e inconvenientes que enumero a continuación:

Ventajas

  • Permite validar antes de alterar el estado de los objetos.
  • Proporciona una convención. Aunque no mucho mejor la convención setProp(valor) que prop = valor
  • Permite alterar el comportamiento sin modificar los clientes. En los tiempos de los IDEs cañeros y sus refactorizaciones, esto es difícilmente una ventaja.
  • Estándar de facto. Los frameworks confían en que exista y hasta el programador más bisoño entiende su mecanismo.

Inconveniente

  • Mucho más código. Más engorroso de manejar, más difícil de mantener.

Una sóla desventaja, pero de tanto peso que por mí merece la pena replantear la convención.

serialVersionUID

The serializable class Foo does not declare a static final serialVersionUID field of type long. Para deshacerte de este warning de eclipse: window > preferences > java > compiler > errors/warnings >  potential programming problems y allí marcas “Serializable class without SerialVersionUID” a “Ignore”. Prácticamente todo el mundo puede ignorar tranquilamente el serial version uid, pero si quieres saber de qué te está avisando el bueno de eclipse, sigue leyendo.

Que una clase sea serializable quiere decir que sus instancias pueden escribirse y leerse en, por ejemplo, un fichero. La clase puede cambiar con el tiempo, y algunos cambios pueden hacer que la serialización/deserialización de esa clase cambie. El atributo serialVersionUID indica con qué versión de una clase se ha serializado una instancia dada. De esa forma, el que vaya a deserializarla sabe de antemano si va a poder o no.

Una solución particularmente simple es poner como serial la fecha del cambio:

private static final long serialVersionUID = 20070901L;

Si alguna vez se cambia algo que afecte a la serialización del objeto, se cambia esa fecha.

Es bastante sencillo y tiene mucho sentido, pero yo llevaba un añito viendo el warning de marras y no tenía muy claro qué era ese mensaje. Comparto un vicio con la mayoría de mis colegas. Vicio que muchos de un tiempo a esta parte insisten en llamar virtud, y es que primero disparo y luego pregunto. A veces ni pregunto. El caso es que a menudo me olvido de recuperar los cadáveres que dejé en el camino: “esto es una ñapa pero cuando funcione todo lo dejaré bonito” o peor: “¡cómo mola! ¡no me explico que no pete!”.

Los warning son víctimas propiciatorias de esta política tan pragmática de aceptación de daños colaterales, y el serialVersionUID no iba a ser menos: “coño, qué warning más persistente”. He utilizado la palabra pragmático aposta, y es que lo que se considera oficialmente el programador pragmático diría exactamente lo contrario de lo que he dicho yo aquí. Hace muy poco me leí una especie de catecismo del programador ágil, y una de las pocas enseñanzas que saqué fue precisamente que considerase los warnings como errores. Que si eclipse los había puesto ahí sería por algo. Justo lo contrario de lo que yo he entendido siempre por pragmatismo. En fin, será cuestión de revisar mi vocabulario.