Mar 29

Más sobre pom_version

 

Hace tiempo comenté que me había hecho un plugin de maven, pom_version, para ayudarme a cambiar los números de versión en los pom.xml de los proyectos maven. El problema era que en proyectos grandes, con muchos subproyectos, muchos pom.xml y muchas dependencias, era un pequeño infierno cambiar la versión de uno de los jar, ya que requería ir buscando y editando todos los pom.xml uno a  uno. El plugin hacía esto de forma más o menos automática en un proyecto maven.

El otro día me tocó hacer una rama de CVS para un hito con el cliente. Por un lado, eché casi un día entero haciendo sólo la rama de CVS. Los proyectos son grandes y los cvs tag recorren todos los ficheros uno a uno, por lo que sólo hacer los "cvs tag" en todos los proyectos implicados me llevó todo el día.

Al día siguiente me dediqué al cambio de números de versione en los pom.xml. Al crear una rama para un hito de cliente, todos los jar deben pasar a un número de versión nuevo, el del entregable y la rama en cuestión. Pensé que con el plugin el tema iba a ser rápido, pero no lo fue. Eché toda la mañana y no terminé.

El primer problema es que el plugin sólo maneja un proyecto maven con todos sus subproyectos. Pero nuestros proyectos tiran de librerías propias que a su vez tiran de librerías propias y muchas de ellas son grandes, con subproyectos y más subproyectos. La ejecución del plugin es inmediata en un proyecto maven, pero tengo que ir pasando manualmente por todos los proyectos, empezando por los más básicos hasta el de más alto nivel, revisando que no se quedan dependencias sin cambiar, que todo compila como debe, etc, etc.

El segundo problema, menor, es que el plugin no me soporta las propiedades en los números de versión. Si un pom.xml se define una propiedad "numeroVersion=1.2.3" y luego en las dependencias unos usas ${numeroVersion} y otros 1.2.3, el plugin sólo cambia los que usan variable o los que usan número, según se le diga.

Así que me he replanteado el tema, no puedo echar dos días cada vez que quiera hacer una rama general de todo el proyecto.

  1. Sólo para entretenerme, porque quizás deje de usarlo, en el plugin le he hecho un arreglo para que soporte bien las propiedades. Ahora está en versión pom_version 1.1.0. He aprovechado además para quitarle la dependencia que tenía con Xerces y hacer algo más de test junit (he intentado aplicar TDD para estas mejoras).
  2. La primera medida seria va a ser pasar de CVS a Subversion. En Subversion la creación de un tag o rama tarda entre dos o tres segundos, independientemente del tamaño del proyecto. A veces me gusta darle un comando al ordenador y luego estar un rato rascándome la barriga (por no decir otra cosa) mientras el ordenador trabaja, pero estar rascándome un día entero, acaba escociendo.
  3. La segunda medida seria y es sólo una idea, es hacerme una pequeña aplicación a la que se le configure diciéndole dónde están todos los proyectos maven que usa un determinado proyecto de cliente, decirle qué número de versión quiero para cada proyecto y que él se encarge de hacer todos los cambios en todos los proyectos. Por supuesto, esa pequeña configuración por proyecto, debe guardarse en algún sitio para no tener que indicar todos los directorios cada vez. No creo que una herramienta así me lleve mucho hacerla, ya que es simplemente buscar ficheros xml de nombre pom y hacer cambios en ellos. En el punto 1 comenté que quizás dejaría de usar el plugin y lo dejare si hago esta herramienta.

La duda que tengo respecto a la herramienta, es si hacerla yo mismo en mis ratos libres (y así disfrutar de un rato de codificación) o pasársela a uno de los FP que van a venir a hacer tres meses de prácticas…

Mar 25

Y la luz se hizo

 

He leído en dosideas un artículo sobre cómo trabajar en paralelo de verdad. En él menciona dos posibles formas de trabajo. Una, que llamaré de ahora en adelante "trabajo en paralelo", consiste en dar a cada desarrollador una de las funcionalidades del sistema. Cada desarrollador trabaja en su funcionalidad. La otra, que llamaré "trabajo conjunto", consiste en que todos los desarrolladores trabajan conjuntamente en la misma funcionalidad hasta que se considera acabada. Luego, todos juntos, pasan a la siguiente.

En el trabajo en paralelo, aparentemente se va avanzando mas. Cada desarrollador hace una funcionalidad y cuando llega el hito de entrega, todas las funcionalidades están acabadas o casi. La pega que menciona en el artículo es que los desarrolladores, según se acercan al hito, empezarán a correr y hacer chapuzas en su código para llegar a tiempo. Nos podemos encontrar con que ninguna funcionalidad llega al hito totalmente acabada y posiblemente todas con muchos errores.

En el trabajo conjunto, al trabajar todos los desarrolladores en la misma funcionalidad, posiblemente esa primera funcionalidad se acabe mucho antes del hito y se acabe bien. La segunda también y así sucesivamente. Es posible que la última funcionalidad que se haga justo antes del hito sea un poco chapucera y también es posible que haya funcionalidades enteras que no estén.

Es interesante ver las imágenes del enlace anterior para ver ambas formas de trabajo.

Aparte del artículo en sí, yo tenía muchas dudas sobre la utilidad de algunas de las prácticas de las metodologías ágiles, sobre todo las de los desarrolladores comunicándose entre sí con mucha frecuencia. Comento a modo de ejemplo algunas de las dudas que tenía y cómo la lectura de este artículo me ha hecho ver la luz o, al menos, replantearme mis puntos de vista.

Por un lado, tenía mis dudas sobre las reuniones diarias de desarrolladores en Scrum. Si seguimos un "trabajo en paralelo" que, desgraciadamente, suele ser lo habitual en los desarrollos tradicionales, estos quince minutos de reunión diaria no son más que una cosa totalmente informativa. Si yo estoy con mi funcionalidad A, puedo tener curiosidad por ver cómo va Fulanito con su funcionalidad B, pero desde luego, no me va la vida en ello. Si hacemos "trabajo conjunto", estas reuniones cobran todo su sentido. Las tareas que tenemos dependen estrechamente unas de otras y Fulanito puede tener interés en ver cómo va mi tarea y yo puedo querer saber cuándo voy a poder usar la suya.

También con Scrum, había otro problema con las entregas cada quince días. Si cada desarrollador hace su funcionalidad, ¿qué hacemos con el desarrollador que acaba antes de tiempo la suya?. Puede ponerse a ayudar a otro, pero ya sabemos que en las cercanías de un hito poner más desarrolladores entorpece más que ayuda. Tendría que perder parte de mi escaso tiempo explicándole a Fulanito de qué va mi funcionalidad, por dónde voy y cómo puede ayudarme. Con el "trabajo conjunto", siempre puede quedar una tarea que todavía no se ha abordado, se puede echar una mano a otro desarrollador en una tarea cercana a la tarea que yo he hecho, ya que están relacionadas, se puede ir probando la integración de todas esas tareas, etc.

Con la programación extrema y en concreto, la programación en parejas, pasa algo parecido. En un "trabajo en paralelo" implica dos desarrolladores por funcionalidad. Si las parejas deben cambiar con frecuencia, quiere decir que uno de ellos tiene un cambio de contexto muy grande, ya que cambia de funcionalidad además de compañero. Si además, dentro de una funcionalidad no mantenemos a uno de los desarrolladores todo el tiempo, la siguiente pareja se encontrará una funcionalidad a medias que además les resulta nueva y no saben qué estaban haciendo los anteriores. Si usamos el "trabajo conjunto", nuevamente la programación en parejas empieza a tener sentido. Las parejas pueden cambiar con frecuencia, ya que las tareas se suponen son de más corto tiempo y están todas relacionadas. Al cambiar la pareja, al menos la funcionalidad les suena a todos, aunque empiecen a trabajar en trozos de código distinto.

En conclusión, el artículo me ha despejado muchas de las dudas (por no decir pegas) que tenía sobre las metodologías ágiles y me parece imprescindible el "trabajo conjunto" para llevar a buen puerto una metodología ágil. El "trabajo conjunto" tiene además la ventaja de que hace que realmente la gente se vea cómo un equipo, ya que trabajan codo con codo en lo mismo. El "trabajo paralelo" sí, todos los desarrolladores trabajan en el mismo proyecto, pero todos pueden ir a su bola aislados de los demás, salvo en pequeños puntos concretos. No hay con ello sensación de equipo de trabajo.

Y ya para finalizar, una pequeña pega que veo al "trabajo conjunto" basada en mi experiencia. Cuando varios desarrolladores trabajan en una misma funcionalidad, lo más posible es que acabada esa funcionalidad se quede huérfana. Si una vez acabada y los desarrolladores han pasado a otra cosa (los no fracasados ya ni siquiera codifican: son jefes de algo), salen algunas incidencias, es muy posible que ningún desarrollador de los que quede y que está liado en otra cosa quiera hacerse responsable de esa incidencia, o empiecen a pasársela unos a otros. En un "trabajo en paralelo", esto no es tan fácil. Si una funcionalidad tiene una incidencia, está claro quien es el responsable. Como digo, lo digo por experiencia. En nuestros proyectos de larga duración tenemos muchas incidencias huérfanas, que en bugzilla van cambiando de dueño todos los días de propietario, ya que unos se la pasan a otros.

Mar 21

Jugando con TDD, MVP, PF, EasyMock y Mockito

 

Normalmente no codifico, lo he dejado por imposible. Un día de trabajo mio normal consiste en atender una cola de gente que viene a preguntarme cosas, algunos pocos sobre java, algunos más sobre las herramientas que usamos (maven, archiva, redmine, etc) y muchos (jefes sobre todo) sobre incidencias de los proyectos, cómo va el trabajo, etc. En esas condiciones, es muy difícil concentrarse cinco minutos seguidos y mucho menos diez, por lo que hace tiempo que decidí no meterme en serio a codificar.

Sin embargo, el viernes de la semana pasada fue un día excepcionalmente tranquilo. Todo el mundo sentado en su sitio, a sus cosas y sin que nadie viniera a decirme nada. Cuando pasan estas cosas, suelo aburrirme un poco, no empiezo a hacer nada en serio por temor a las interrupciones que seguro que están al caer. Pero ese viernes la tranquilidad se estaba prolongando demasiado, había un módulo nuevo para hacer desde cero y yo acababa de leerme algo sobre TDD, así que hablé con la persona que tenía asignada ese módulo y no le molestó que lo empezara yo (aun a sabiendas de que lo dejaré a medias y le tocará seguir a él). Así que así me he tirado casi una semana, codificando y jugando al TDD.

Las primeras historias fueron más o menos sencillas. Hice mis test, luego mi código, refactoricé un poco y vuelta a empezar. Pero llegó un momento en que el tema se me complicó más de la cuenta. Llegó una historia de usuario en la que había involucrada una parte de interface de usuario con Swing que no era trivial de probar con un test automático. Y me puse a investigar en internet.

Primero encontré la posibilidad de ponerse con los métodos de java getComponents() y similares para tratar de buscar el componente java (el JTextField, el JButton o lo que sea) que necesitas para tu test y a partir de ahí usar el método setText(), getText() o doClick() para simular la interacción con el usurio. Aunque eso sí te puede sacar del apuro en un caso puntual, no parece que sea la mejor forma de hacerlo por sistema. El test se llena de código rebuscado con bucles y recursiones hasta localizar el componente que te interesa y que por supuesto, tienes que haber dado previamente un nombre con el método setName() para distinguirlo de otros componentes del mismo tipo.

Seguí buscando y encontré que todo ese proceso se facilita con librerías como FEST-Swing, que de alguna forma facilitan y eliminan todo el código raro que mencioné en el apartado anterior. No llegué a probarlo porque no encontré un repositorio maven que me permitiera bajarme la librería fácilmente.

Y seguí buscando y encontré una cosa interesante: El patrón MVP (Model-View-Presenter) y el PF (Presenter First). La idea de estos patrones es que una interface gráfica de usuario es muy compleja de testear automáticamente, por lo que debemos hacerla lo más tonta posible, para no tener que testearla. Es decir, un panel de nuestra interface gráfica de usuario únicamente debe tener métodos set y get para mostrar datos y recogerlos. No debe tener actionListeners para los botones ni ningún tipo de inteligencia. Toda la inteligencia de esa interface se hace en otra clase, llamada Presenter. Esta clase debe recibir dos interfaces en el constructor, una de la interface gráfica de usuario y otra correspondiente al modelo de datos. La clase Presenter debe hacer ella misma de listener de los botones y encargarse de interactuar con el modelo y la interface de usuario. Haciéndolo así, es fácil testear toda esta lógica, ya que podemos instanciar en nuestro test el Presenter y pasarle dos mock-objects, el del modelo y el de la interface del usuario.

Me gustó la idea, así que rápidamente me puse a modificar mi código para usar un Presenter y quitarle el máximo posible de código (todo) a los componentes swing. Por supuesto, siguiendo TDD, primero comencé a hacer test y modificar los ya hechos.

Pero lleguó el momento de usar los mock-objects. Por un lado, podía hacérmelos a mano, pero por otro lado hace tiempo que conozco y nunca he usado la librería EasyMock. Supuestamente (y en la realidad) facilita la creación de los mock-objects, haciéndolo automáticamente. Viendo la documentación me pareció fácil de usar y encontré además la librería en los repositorios maven, así que me puse con ello. Sin embargo, me ha decepcionado un poco. Los EasyMock están bien para determinadas cosas, pero les veo dos pegas que no los hacen ideales en todas las circunstancias:

  • La filosofía de un EasyMock en el test es crear el mock-object, decirle a qué métodos se van a llamar durante el test y con qué parámetros, luego llamar a su método replay() para indicarle que empieza el test de verdad y hacer el test. Si durante el test no se sigue la secuencia de llamadas indicada anteriormente, el test falla. ¿Cual es la pega que le veo a esto?. Pues sobre todo para cosas como TDD, en que las clases se refactorizan y van evolucionando según se van desarrollando nuevas historias. Es muy fácil que sin modificar el funcionamiento de la clase, la secuencia de llamadas cambie, porque se hagan más llamadas, o se reemplacen algunas por otras o lo que sea. Esto obliga a ir rehaciendo los test, aunque la funcionalidad no cambie, simplemente porque cambia el orden o el número de llamadas que se hacen.
  • Los EasyMock, aunque no lo puedo asegurar porque no lo he mirado en profundidad, no permiten que un mock-object genere algún tipo de eventos. En el caso concreto del patrón MVP y PF mencionados antes, un Presenter añade un ActionListener a un botón de la interface de usuario. Si estoy testeando el Presenter y le paso un mock de la interface de usuario, no puedo simular un click en el botón o hacer la llamada al actionListener. Unicamente puedo ver que el Presenter efectivamente se suscribe llamando al addActionListener() correspondiente.

Tratando de solucionar algunas de estas pegas (la primera sobre todo), hay otra librería, Mockito, que se basa en EasyMock, pero trata de darle una API más sencilla y versátil. Tengo pendiente echarle un ojo, pero creo que la segunda pega no me la va a solucionar. Supongo que para cosas como los listener, no me quedará más remedio que hacerme los mock-object a medida … y a mano.

Lo que me da realmente pena de todo esto, es la persona que va a seguir con este código, cuando a mí empiecen a agobiarme con otros temas. Veamos que cara pone cuando empiece a ver Presenters y Mockitos. O lo tira todo a la basura, o aprovecha para aprender una nueva forma de hacer las cosas y así, al menos, tendré alguna opinión más sobre el tema, aparte de la mía propia. Esto es, nuevamente, una sopa de piedras o un capitán araña. Ya veremos en qué acaba.

Mar 19

Google analytics y Google Adsense

 

Una cosa que se llevaba mucho tiempo deseando, era integrar las estadísticas de google analytics con los ingresos obtenidos con google adsense. El primero da estadísticas de visitas de nuestro sitio web: número de visitas, qué páginas se visitan, si las visitas vienen de un buscador o de algún enlace en otra página, qué palabras han usado en el buscador, etc. El segundo, google adsense, nos da los ingresos por los anuncios en nuestro sitio web, pero los análisis que permite hacer sobre estos ingresos siempre han estado cojos: No nos permite saber qué páginas son las que más ingresos producen (es decir, en qué páginas salen anuncios sobre los que hace click la gente).

Desde hace mucho el integrar estas dos herramientas era algo que la gente le pedía a google y ya, por fin, se ha hecho realidad. Hace unos días en mi página de google adsense encontré un enlace que indicaba algo como "integrar google adsense con google analytics", así que rápidamente le di y me puse a ello.

Al pulsar el enlace, pide el usuario y contraseña de google analytics. Te muestra los distintos sitios que tienes allí dados de alta y pregunta cuales quieres integrar con tu cuenta de google adsense. Marcas unos cuantos y te da unos scripts para poner en cada uno de los sitios. Aquí es importante fijarse y leer bien: dichos scripts deben ponerse en la parte superior de las páginas web. Yo no hice demasiado caso y no me funcionaron hasta que los cambié de sitio.

Listo, después de unas horas, en la página de google analytics aparece un informe sobre google adsense, indicando cuales de tus páginas han dado más ingresos, como han evolucionado los ingresos en función del tiempo, qué páginas producen más clicks, etc. En la foto, una imagen del panel principal del informe:

Informe de google adsense en google analytics

Mar 17

Yo sí soy tonto

 

Recuerdo cuando empecé a trabajar, picando código y aprendiendo a programar, tenía unos "jefes" realmente curiosos. Para que quedara claro que eran jefes, se solían quedar ellos lo mejor, dejándonos a nosostros, los nuevos, las sobras. ¿Que llegaba material nuevo?, rápidamente se lo agenciaban ellos, se agenciaban los nuevos monitores, o se agenciaban los pen-drives, o las libretas más "molonas", o los "pilot" y a nosotros nos llegaban sus sobras, sus ordenadores viejos, sus monitores viejos, nos quedábamos sin pen-drives y nos tocaban los "bic".

Ahora he "ascendido" un poquito, pero aun recuerdo aquellos tiempos. Hace unas semanas pedí pen-drives para repartir y efectivamente, los repartí: ¡¡ todos para la gente más nueva !!. Yo sigo con mi viejo pen-drive de 2 Gigas y no me he quedado ninguno de los nuevos. Es más, a los que son "jefecillos" como yo, tampoco les he dado pen-drives, aunque algunos me lo reclamaro. Les dije algo así como "a los jefes, ni agua" y se quedaron sin ellos.

Total, que toda la gente nueva anda con pen-drives nuevos y yo ando con la sensación de ser tonto …

Mar 12

Personalizando MediaWiki

 

Hace tiempo comenté que tenía un problema con la página aleatoria de la Wiki y el amigo google. Buscando una palabra en google, este me mostraba un enlace a la Chuwiki. Casualmente, este enlace, en vez de ser al artículo original, era la página aleatoria de la Chuwiki, por lo que pulsando el enlace mostrado por google, me iba a una página aleatoria y no a la buscada.

Hace un par de días volví a tropezarme con el problema. Busqué no sé qué en google, apareció un artículo de la Chuwiki, pinché el enlace y acabé en una página aleatoria. Así que me he decidido a arreglarlo. Por supuesto, para variar y por culpa mía, el cambio ha sido una pequeña odisea.

Lo primero de todo, por supuesto, ponerme a urgar en los ficheros php de MediaWiki, a ver dónde demonios está ese enlace de página aleatoria para quitarlo. Después de un par de horas de revisar el código, ir de un lado a otro, dar mil vueltas y no llegar a ningún sitio (está oculto el dichoso enlace), me decidí a hacer lo que debería haber hecho desde el principio: consultar la ayuda de la MediaWiki.

Las cajas de menú de la izquierda de la MediaWiki son bastante fáciles de modificar. Con permisos de administrador basta desde la misma web, editar la página MediaWiki:Sidebar. En esa página aparece el menú y se puede modificar a gusto. Para editar esa página, que no está fácilmente accesible, hay que poner la url directamente en el navegador:

http://www.tuwiki.com/index.php?title=MediaWiki:Sidebar&action=edit

y listo, ahí ponemos lo que queramos, incluso más cajas de menús. Tienes los detalles en Manual:Interface/Sidebar de la MediaWiki.

De todas formas y como siempre tiene que haber algo que incordie, después de hacer los cambios no veia en absoluto modificado el menú. El dichoso firefox tenía guardada la página en memoria y no me cambiaba el menú. Me dí cuenta al visitar otra página de la Chuwiki y ver que ahí si estaban cambiados los menús. Así que cada vez que hacía un cambio, no me quedaba más remedio que vaciar la caché del firefox ("herramientas"->"limpiar datos privados").

Mar 08

Nuevo foro de programación

 

Nace un nuevo foro de programación, del blog línea de código. Desde aquí darle ánimos y suerte con la iniciativa.

Mar 04

Dos Ideas

 

Un sitio que me ha gustado Dos Ideas : La visión de Sistemas desde el Desarrollo. Contiene una serie de artículos interesantes y amenos de leer sobre desarrollo de software, metodologías ágiles, etc. Y lo mejor de todo, en perfecto argentino. Creo que ya tengo entretenimiento para unos días.

Mar 02

Incordiando al personal

 

Una de las cosillas que conviene hacer en un programa serio es usar un sistema de logging en condiciones en vez de usar un System.out o un System.err. Sin embargo, aunque se lo dices a la gente, es bastante habitual que muchos se "despisten" o pasen olímpicamente del tema, llenando el código de System.out.println("Voy por aquí") y System.out.println("Entro en el bucle"). Por supuesto, dicen que es temporal, sólo para probar, pero la realidad es que luego eso nunca se quita y queda por los siglos de los siglos.

Aprovechando que la clase System tiene un método setOut() que permite cambiar el System.out por otra cosa, si veo que proliferan los System.out.println(), lo que hago es cambiarlo en el main() de la aplicación (o en algún sitio menos evidente). Una "colleja" amistosa se puede dar con un código como este

package chuidiang.ejemplos;

import java.io.PrintStream;

public class CambiaSystemOut {

    public static void main(String[] args) {
        System.setOut(new PrintStream(System.out) {
            @Override
            public void print(String text) {
                super.print("No seas capullo y usa log4j");
            }

        });

        System.out.println("Hola mundo");
    }
}
 

con lo que cuando alguien pone su System.out.println("salgo del if") y hace la prueba, verá un "No seas capullo y usa el log4j".

Y si quiero dar la "colleja" de forma más vistosa (y tenemos tiempo para permitirnoslo), se puede poner el mismo mensaje pero usando un JOptionPane.showMessage(), que "canta" más. O ya para una "colleja" nada amistosa, un System.setOut(null), que hará que salte una NullPointerException cada vez que hagan un System.out.println().

El que no se divierte, es porque no quiere y yo, a veces, me lo paso como los indios.