Apr 28

WeakHashMap y una posible solución de diseño

WeakHashMapHace poco descubrí la clase WeakHashMap de java y encontré un ejemplo de su uso con una idea interesante que no se me había ocurrido y que puede ser una alternativa buena de diseño para resolver determinados problemas. Me "explayo":

Imagina que en tu empresa haces proyectos de software en los que siempre hay listados de personas, pero la información que se guarda de cada persona varía de un proyecto a otro. Por ejemplo, en todos los proyectos las personas tienen DNI, nombre, apellidos, fecha de nacimiento, sexo, etc. Pero en un proyecto que hacéis de un taller de coches la persona tiene además asociado el coche que tiene, con su marca, modelo, etc. En otro proyecto que hacéis de nóminas la persona tiene también su cargo en la empresa, sueldo base, complementos, antigüedad, etc. Y así con cualquier tipo de proyecto que se os ocurra relacionado con personas.

Como somos una empresa espabilada y vemos que siempre tenemos personas en los proyectos y unos datos que siempre son comunes, decidimos hacernos una librería en la que tenemos la clase Persona con los atributos comunes, paneles para editar personas, JTable de personas, daos de persistencia en bd, tablas en bd, etc.

Cuando llega un proyecto concreto debemos ampliar los datos de esa Persona que tenemos en la librería. Y se nos presentan varias opciones.

La que rápidamente piensa cualquiera que haya estudiado orientación a objetos (y quizás sin mucha experiencia), es heredar de Persona y añadir en la clase hija los atributos adicionales. Así, en el ejemplo de nuestro taller, tendríamos PersonaConCoche extends Persona y le añadimos todo lo relativo al coche. Esta solución se puede hacer y funciona, pero al implementarla vemos que no acaba de convencer. El código que hagamos adicional para el taller va a tratar con una Persona a la que hay que hacer cast a PersonaConCoche, debemos rellenar los datos de un mismo objeto en dos consultas de bd e insertarlo en dos veces, unos campos primero y otros después, posiblemente en el orden adecuado, etc, etc.

La siguiente opción que se nos ocurre es poner un método en nuestra clase Persona que sea setDatosAdicionales(datosAdicionales). ¿Pero qué tipo ponemos a esos datosAdicionales en nuestra librería general para que nos sirva en cualquier proyecto?. Pues o bien ponemos Object, o bien hacemos que nuestra clase Persona sea un genérico. La primera opción no es especialmente clara, porque nunca sabremos que hay dentro de datosAdicionales y si somos varios programadores, alguno puede despistarse y meter ahí cualquier cosa. Lo del genérico es un rollo, ya que obliga a casi todas las clases de nuestra librería general (paneles, daos de bd) a ser a su vez genéricos.

Y finalmente está la solución del ejemplo de WeakHashMap que había comentado y que, aunque no he probado, tiene muy buena pinta. Consiste básicamente en meter esos datos adicionales directamente en un HashMap. La clave sería nuestra clase Persona tal cual la tenemos en la librería común y el valor los datos adicionales. Podemos concretar el HashMap genérico para nuestros datos concretos HashMap<Persona, Coche> y así todo queda claro sin posibilidad de confusión. No necesitamos tocar nada de nuestra librería y podemos hacer nuestros paneles y daos de Coche por separado. Por supuesto, este WeakHashMap se guarda fuera de la clase Persona (si no, no hemos mejorado nada respecto a las soluciones anteriores) y hay que hacerlo accesible al que lo necesite.

La ventaja para este tipo de solución de un WeakHashMap frente a un HashMap normal es que el primero no se guarda referencias reales a los objetos que tiene almacenados (ni de Persona ni de Coche), por lo que si en nuestra lista de personas (que tenemos aparte) eliminamos una persona y perdemos todas las referencias a ella, el recolector de basura reclamará también la Persona y sus datos guardados en el WeakHashMap. Si lo hubiéramos metido en un HashMap normal, las referencias a Persona y Coche ahí dentro son reales, por lo que el recolector de basura no los libera. por lo que después de borrar la persona de nuestra lista de personas, debemos además acordarnos de hacer y hacer una llamada al hashmap.remove(persona). Ya sabes que un un grupo de uno o más programadores, siempre hay al menos un despistado que se olvida de estas cosas.

No veo el momento de aplicar una solución de este estilo en algún sitio, a ver si me encuentro con pegas prácticas.

Apr 26

Verlo para creerlo

No tengo muy claro cómo comentar esto para que no sea muy rollo y se pueda apreciar en toda su magnitud, pero voy a intentarlo.

Hoy he estado revisando algo de código que me han pasado (de otra empresa, afortunadamente). Se supone que ese software debe hacer lo siguiente

El software tiene 16 puertos abiertos, todos ellos conectados a equipos iguales, por lo que su mensajería y comportamiento es igual en todos ellos. La idea del software es que el usuario pueda elegir uno de los puertos y hacerle un prueba apretando un botón. La prueba consiste en enviar un mensaje concreto (codificado en el código) y ver si la respuesta tarda menos de un minuto en llegar. Cuando el usuario ha elegido el puerto y pulsa el botón, se abre una ventana con un contador que comienza en 1:00 y va hacia atrás. Si la respuesta llega antes de que termine el contador, se oculta la ventana y se le dice al usuario que el puerto está bien. Si no llega, se cierra igualmente la ventana y se le dice al usuario que el puerto está mal.

¿Y cómo hace esto el software que me han pasado?

Pues se ponen 16 botones en 16 variables boton1, boton2, etc. Se guardan en otra clase 16 atributos estáticos boolean etiquetados testeandoPuerto1, testeandoPuerto2, testeandoPuerto3,…. para indicar qué puerto está bajo test. Por supuesto, los puertos también están guardados en 16 variables estáticas puerto1, puerto2, … Cada botón tiene su ActionListener (16 ActionListener) de forma que cada uno de ellos marca su atributo estático testeandoPuerto correspondiente y abre la ventana con la cuenta atrás.

Por si no fuera poco todo esto, lo bueno empieza ahora. Para la ventana con cuenta atrás se hacen 16 clases Ventana1, Ventana2, etc, una para cada botón. Estas ventanas, en su constructor, miran si se está testeando el puerto que les corresponde para arrancar la cuenta atrás. Y durante la cuenta atrás mira el puerto que le toca a ver si llega la respuesta. Por ejemplo, la Ventana7 en su constructor mirar si testeandoPuerto7 es true para arrancar o no la cuenta atrás. Y si la arranca, en la cuenta atrás se mira puerto7 para ver si llega la respuesta. Es decir, las 16 ventanas son exactamente iguales, salvo la variable testeandoPuerto y puerto, que cada ventana mira las suyas.

Y como todos sabemos que si quieres hacer algo bien es mejor hacerlo uno mismo, para la cuenta atrás no usaremos los Timer de java ni para pintar los minutos:segundos que quedan las clases Date, Calendar, SimpleDateFormat ni similares. Lo mejor es hacerse un hilo "vulgaris", guardándose previamente el currentTimeMillis(), haciendo sleeps de 1000 milisegundos, viendo el tiempo transcurrido respecto al currentTimeMillis() que guardamos al principio y multiplicar/dividir por 1000 milisegundos/segundo, 60 segundos/minuto, cogiendo los restos y las divisiones enteras para separar minutos de segundos.

Y claro, como el arrancar o no el Timer está en el constructor de la ventana y no hemos puesto métodos de arrancar/parar/resetear, pues cada vez que se pulse uno de los botones, se hace new de su ventana correspondiente, haya sido o no creada previamente, ya que si no se hace así no hay forma de rearrancar la cuenta atrás una segunda vez.

Resumiendo, 16 variables botón, con 16 ActionListener, 16 variables estáticas, 16 clases Ventanas exactamente iguales salvo por la variable que miran, y news por doquier.

Si soy bueno, puedo entender que quizás le encargaron esto a alguien que no sabe nada de java, quizás es alguien de perfil hardware que se dedica a testear los equipos con osciloscopios y voltímetros, que a su jefe se le ocurrió la brillante idea de hacer un software que ayude a testear, que a él le ha caído el marrón y que quizás incluso le han apretado en tiempo e hizo el copy-paste de las 16 clases Ventana un Domingo a las cuatro de la madrugada porque el Lunes tenía que estar todo a primera hora.

Pero hay que ver estas cosas para entender realmente lo que se dice en muchos posts y de lo que otros países más avanzados en software que España ya se han dado cuenta. Es mejor pagar el doble, el triple (o incluso 16 veces más) a un programador bueno y con experiencia, que pagar cuatro cuartos a dos o tres sin conocimientos ni experiencia ninguna. Imagino, con los conocimientos de java que demuestra, a la persona que ha hecho este código tardando dos o tres semanas en hacerlo, e imagino a algún programador bueno y con experiencia haciéndolo en una tarde, con 16 veces menos de líneas de código. La pena es que los jefes que contratan o encargan estos "marrones" al primero que pillan, no ven estas cosas, ni posiblemente quieren verlas.

Apr 22

Los técnicos, en el fondo, somos técnicos

 Tengo un par de compañeros de trabajo que son más o menos de mi edad y con los que llevo mucho tiempo trabajando, más de diez años. Sin embargo a mí me gusta mucho más la programación que a ellos y mucho menos los clientes que a ellos, así que más o menos en el mismo departamento, pero hemos evolucionado de forma distinta.

Yo tengo ciertas responsabilidades, pero me dedico sobre todo a hacer y revisar código con mi grupo de trabajo. Ellos han ido ascendiendo y son uno jefe "gordo" de proyecto y la otra jefa de departamento. Ambos dejaron de programar hace ya unos cuantos años y no ven el código ni de lejos.

Pero estos días surgió en un antiguo código C++ que todavía está funcionando la sospecha de un "bug" gordo y escondido, que ha sobrevivido sin ser detectado varios años.  Como no había demasiada gente disponible (ni con conocimientos de C++ ahora que todo es java), me pidieron que les pusiera un debugger y que ellos se encargaban de buscar ese "bug".

Pues el jefe "gordo" de proyecto confesó que la tarde que se pasó depurando el código es la mejor tarde que ha pasado en varios años de trabajo, harto de peleas con clientes, de controlar y ver cómo se le escapan "los dineros" más allá del presupuesto y ver cómo se le van los plazos. La jefa de departamento se la ve feliz y sonriente, ahí enfrascada con el debugger, tocando el código y viendo que va arreglando las cosas. Vino toda feliz a comentarme que había tocado el código y simplemente le había compilado.

Si es que los técnicos, en el fondo, somos técnicos y disfrutamos con las cosas técnicas, y no con las de gestión. Después de arreglar un bug, hacer un trozo de código que funciona y verlo funcionando (o simplemente que compila), nos vamos a casa felices con la sensación de que hemos hecho algo útil. Los gestores y jefe de proyecto me hace la impresión de que se van a casa con el problema en la cabeza y pocas ganas de volver al día siguiente. Eso sí, cobran bastante más.

Apr 16

Twitter, buzz, byt.ly y demás

 Hace ya bastante tiempo me apunté a twitter. Al principio lo usaba un poco para jugar y poner cualquier chorrada que se me ocurría, estilo "buenas noches", "acabo de desayunar" y "tengo sueño" (resumen de la vida de todo vago profesional: dormir, comer y dormir). Pero al final lo he acabado usando para poner enlaces a las cosas que voy publicando (es este blog, en la Chuwiki, etc).

Luego salió buzz, y para probarlo, también me apunté. A este, como tiene alguna posiblidad más de configuración, le añadí los sitios (blogs y twitter) en los que escribo algo y automáticamente los publica. También es más fácil seguir conversaciones o ver los comentarios de una entrada concreta, ya que van todos juntos. Aunque buzz es fácil de usar y con más posibilidades que twitter, es de momento menos usado, así que estuve dudando si quedarme con twitter o pasarme a buzz del todo.

Al final acabo de decidirme por una cosa intermedia. Seguiré publicando enlaces en twitter, pero pondré en buzz todo aquello que ocupe más de 140 caracteres (límite de twitter) y no tenga la envergadura suficiente como para publicarlo en este blog. O sea, si esto es un blog y twitter es un microblog, usaré buzz como miliblog (perdón por la estupidez).

Y urgando un poco más, veo que hay montones de sitios del estilo de buzz, como por ejemplo friendfeed. Y seguro que hay más a poco que busquemos. En este último me he apuntado también, pero no creo que ponga nada (entre milis y micros, no se me ocurren más divisores, como no sea centiblog o deciblog, y eso ya sería demasiado afinar).

Finalmente, otra estupidez. Viendo que los links de twitter se acortan, me fijo que lo hacen a través del dominio http://bit.ly/. Este es un dominio/utilidad curiosa. Sin necesidad de darse de alta, pones en él una URL y te la devuelve acortada. Puedes pegar esa URL acortada en cualquier sitio. Cuando alguien pincha esa URL acortada, está visitando el dominio http://bit.ly/ pero este te redirige "casi" inmediatamente a la URL original. Digo "casi" porque entre que te redirige y no, almacena estadísticas de quién ha pinchado el enlace, desde donde (país y web que contiene el enlace), a qué hora, etc, etc.

Si no te has dado de alta, puedes ver igualmente esas estadísticas. Todos los enlaces que has acortado desde tu navegador, aparecen cada vez que visitas la página, debe guardártelo en alguna cookie o por IP o algo.Y las estadísticas de cualquier enlace, sea tuyo o no, puedes verlas sin más que añadir un + detrás de la URL. Así, para ver las estadísticas de http://bit.ly/af2tgc sólo tienes que poner http://bit.ly/af2tgc+  . Y, por supuesto, si te das de alta, tienes todos tus enlaces y estadísticas accesibles en tu cuenta. Además, estando de alta, puedes crear una URL acortada y publicarla automáticamente en twitter.

En fin, una herramienta que puede tener su utilidad, aunque tiene su riesgo. Si algún día deja de funcionar o deja de prestar servicio, todos tus enlaces de ese estilo dejarán de funcionar. Sólo como curiosidad, los .ly son de Libia y bastante caros, pero muy apreciados porque en inglés pueden hacerse dominios como probab.ly, que en inglés significa "probablemente" y es fácil de recordar para un inglés.

Apr 10

Un par de herramientas para GTD

GTD es un método para que una persona pueda gestionar sus tareas eficientemente. Es un método sencillo y básicamente consiste en tener una lista de tareas para hacer. Cada vez que se nos ocurra algo para hacer, nos surja una nueva tarea o trabajo, símplemente la apuntamos en la lista y nos olvidamos de ella, así evitamos distracciones en nuestro trabajo actual. Con cierta frecuencia (una vez al día, por ejemplo), revisamos la lista y la ordenamos, de forma que decidimos en qué orden vamos a ir haciendo las tareas, si las dejamos aparcadas para mejor ocasión o si las borramos definitivamente de la lista. Luego, a lo largo del día, nos centramos en ir haciendo las tareas según el orden que hemos decidido al principio del día. Esto evita perder el tiempo pensando qué hacer a continuación o saltando de una tarea a otra. Hay más detalles sobre GTD, pero no voy a extenderme en el tema.

Este método de trabajo ha cobrado cierta fama y abundan las herramientas en internet para ayudarnos a llevar dicha lista. He estado buscando algunas para probar, mirando sobre todo que tengan interface sencilla y cómoda. Me he encontrado dos que me han gustado

La primera es Vitalist. Esta herramienta es en línea, te registras y pones tus tareas en la web. Tiene cuentas de pago, pero también tiene una gratuita en la que podemos poner ilimitadas tareas, pero restringidas a 5 proyectos y 5 contextos. La interface tiene lo que buscaba, por un lado, las tareas a hacer salen todas juntas en una lista en la página principal (no me gusta andar buscando las tareas por la herramienta) y se pueden ordenar simplemente arrastrándolas con el ratón. Aunque a cada tarea se le pueden poner muchas cosas (proyecto, contexto, persona de contacto, fecha límite), no es necesario rellenar todos los campos, por lo que añadir una nueva tarea es inmediato.

La segunda es What’s next. Esta está hecha en ruby y se puede descargar (ruby incluido). Basta descargarla, desempaquetarla y hacer doble click en el script adecuado para arrancar un pequeño servidor web. Se accede a ella a través del navegador. La interface muy sencilla y cómoda, con iconos y fuentes grandes. Las tareas se pueden ordenar arrastrándolas con el ratón y es muy fácil crear nuevas tareas o cambiarlas de estado. No tiene tantas posibilidades como Vitalist (tantos campos, posibilidades de filtrado, etc), pero yo creo que una metodología sencilla (GTD) requiere una herramienta sencilla.

Y son solo dos, a poco que se busque en internet, hay más de todo tipo, en linea, para instalar con ineterfaz web, de escritorio. He probado tres o cuatro más, pero me han parecido demasiado complejas o poco cómodas (muchos campos a rellenar obligatoriamente para que las tareas queden clasificadas, tareas escondidas entre los menús, difícil  de cambiar el estado de tareas o incluso demasiado lentas en el arranque y trabajo).

Apr 08

Thunderbird y los adjuntos

 Como cliente de correo suelo usar Thunderbird. Hace unos meses me actualicé a la última versión y me ha sorprendido con una pequeña característica que puede resultar útil.

Resulta que cuando en mis correos menciono un fichero .doc o escribo la palabra "adjunto" y luego doy a "enviar" el correo, Thunderbird me avisa que posiblemente se me ha olvidado añadir un fichero adjunto y me pregunta si quiero hacerlo antes de enviar el mensaje. Con curiosidad por el tema, he abierto la ventana de configuración y entre las pestañas me he encontrado esto

configuracion adjuntos thunderbird

Hay un sitio en el que puedes poner qué palabras pueden indicar que el correo debe llevar un fichero adjunto. En la ventana vemos las que tiene por defecto "adjunto", "adjuntado", ".doc", cosas de curriculum, etc.

La verdad es que es una idea bastante útil. ¿Quién no ha enviado un correo a alguien diciendo que le adjunta un fichero …. y se olvida de adjuntarlo?

pestana adjuntos en thunderbird