Dec 27

Un pequeño puzzle de papel

Este es para los que les guste romperse la cabeza un rato.

Dispones de un trozo de papel cuadrado y de unas tijeras. Con ello y sin ningún tipo de pegamento, celo o similar, tienes que hacer la figura de las imágenes. La figura está hecha de una única pieza.

puzzle 1

Puzzle papel 2

La solución, por supuesto, para otro post….

Dec 22

Con la moral por los suelos

Llevo un par de semanas trabajando con XPlanner.  En él pones las tareas que vas a realizar y la estimación de tiempos de cada una de ellas. Día a día vas poniendo el tiempo que has trabajado en ellas y para ver cómo vas te saca unos gráficos. En el eje horizontal pone los días. En el eje vertical pone las horas estimadas de trabajo y las horas trabajadas.

En la situación ideal, las horas estimadas deberían ser una línea perfectamente horizontal, es decir, has sido capaz de estimar a priori todo lo que tienes que hacer y el tiempo que te va a llevar. El gráfico de horas trabajadas debería ser una línea que empiza en cero y día a día va subiendo hasta, al final del periodo estimado -una semana en mi caso- alcanza a la línea de horas estimadas. Justo en el momento de alcanzar a la de horas estimadas, el trabajo, si todo se ha planificado bien, debería estar terminado.

Pues bien, eso es la situación teórica. Ahí va mi gráfico de esta semana pasada

Grafico con Xplanner. Que mal planifico

Ante todo, se puede ver que no tengo ni repajolera idea de planificación. El Lunes no hice absolutamente nada de lo planificado, salvo quizás hacer la planificación, pero que no está planificada la tarea de hacer la planificación. El Martes, Miércoles y Jueves sí hice algo, pero casi todo lo que hacía eran tareas nuevas necesarias que no había previsto. Por eso la curva roja de tiempo previsto, en vez de ser horizontal, va subiendo. El Viernes fue el día que capture el gráfico y por eso no hay todavía datos -por cierto, se me olvidó apuntar el tiempo trabajado al final de la jornada-. Al final, dos conclusiones:

  • No he sido capaz de prever las tareas. Cada vez que me meto en ellas, me aparecen tareas previas que hay que hacer y no había previsto.
  • El tiempo de trabajo a la semana en lo planificado es más bien escaso. Tengo muchas interrupciones que me ocupan tiempo en cosas que no son de esta guerra. Como excusa, es la semana previa a navidades y tenemos muchos jolgorios asociados.

En fin, lo más importante es no desanimarse y persistir. Como propósito de año nuevo -junto con los consabidos hacer algo de deporte, ponerse a dieta y dejar de fumar-, me pondré el de aprender a planificar.

Por cierto, este es el típico gráfico de Scrum para ver como va el Sprint.

Dec 21

Constructores vs Setters

Lo que cuento aquí está extraido del artículo de Martin Fowler de Inversión de Control, pero como es interesante, pues eso, lo cuento aquí.

La cuestión, a la hora de inicializar una clase, es si lo hacemos pasándole todo lo necesario a través del constructor o bien por medio de métodos set().

En principio, es mucho más claro usar los constructores. En un constructor está claro qué debemos pasar a esa clase para que funcione correctamente y desde el mismo momento que la instanciamos, esa clase está en condiciones de funcionar, ya que  tiene todo lo necesario. Con los método set() no tenemos esa facilidad. Puede haber métodos set() que no sean necesarios para el correcto funcionamiento de la clase, por lo que no tendríamos necesidad de llamarlos. Y al revés, un método set() obligado se nos puede olvidar y la clase no funcionaría. Además, si no conocemos la clase, no podemos saber con los métodos set() cuales son obligatorio y cuales no, mientras que en el constructor está claro.

Por todo ello, en principio es mejor usar constructores. Pero hay una pega.

A veces hay muchas configuraciones posibles para la clase, según qué parámetros pasemos. Eso obligaría a hacer varios constructores. Si además, usamos herencia, es posible que en nuestra clase, además de nuestros constructores, tengamos que redefinir los de la clase padre, por lo que el número de constructores puede llegar a ser abrumador. Incluso a veces, al llamar al constructor de la clase padre, es posible que no podamos construir sobre la marcha uno de sus parámetros.

En ese caso, posiblemente sea mejor usar los métodos set(). Y como propone Martin Fowler, quizás sea buena idea llamar initParametro() a los que son obligatorios o a los que sólo se puede llamar una vez, aunque rompamos la regla de los beans de java.

Por mi parte, siempre había tenido esta duda y me había tropezado con los dos problemas -no saber que métodos set() son obligatorios o tener que hacer varios miles de constructores-. Todo esto me ha parecido buena idea, -usar constructores si es posible o métodos init() para los obligatorios- así que trataré de aplicarla a partir de ahora.

Dec 20

¿Se puede hacer realmente diseño antes de codificar?

Ando últimamente un poco preocupado. Supuestamente debo dedicarme a diseñar código y otros lo codificarán. El problema principal que veo es que hay mucha distancia desde el punto de vista teórico del diseño y "las trincheras" de la codificación.

Me explico.

Cuando haces diseño, sobre todo de grandes aplicaciones, no puedes meterte en los detalles del código. Puedes pensar una arquitectura, unos módulos, las responsabilidades de los modulos y las interfaces de los mismos. La implementación de dichas interfaces no puedes meterte en ellas, ya que ni eres capaz de prever a priori todo lo que hay que hacer, ni sabes los problemas de codificación que van a surgir.

Ahora llevo unos días codificando sobre código ya hecho y más o menos pensado por mi, pero codificado por otros. Estoy haciendo código nuevo aprovechando ese código ya existente. Y es complicado. A pesar de que más o menos había ideado yo la esctructura de todo eso, y más o menos la sigue, veo que los problemas que se encontraron al codificarlo los han ido resolviendo como han podido, unos mejor que otros. Veo que ese código, que teóricamente debería poder reutilizar tal cual, no me vale tal cual. Tengo que hacer cambios -no muy grandes, pero sí cambios-. La culpa es en parte mía, porque mi diseño inicial era válido para los proyectos que había en curso, pero no lo bastante como para estos nuevos. También es en parte culpa de los codificadores. Posiblemente movidos por la prisa que siempre les meten los jefes, muchas veces optaron por las soluciones rápidas en vez de las buenas.

Sobre todo veo código repetido, cosas que deberían ser comunes, que yo no había previsto como comunes y que los programadores, movidos por las prisas, acaban rápidamente con copy-paste. Y ahora me veo obligado a hacer yo también otro copy-paste de ese trozo para el nuevo proyecto -nuevamente movido por las prisas- o bien "refactorizar" -ignorando las prisas-. Tocar el código hecho, llevarme esas copias a un sitio común y probar que todo sigue funcionando -los test unitarios brillan por su ausencia-.

Todo esto me lleva a pensar que es muy difícil conseguir un diseño bueno a priori y que es realmente difícil conseguir que se siga. El diseñador debe estar muy metido en el día a día del código para ver lo que se está haciendo, lo cual hace imposible que pueda abarcar aplicaciones demasiado grandes. Metiéndose en el día a día, puede controlar el diseño de trozos relativamente pequeños.

Cada vez estoy más convencido de que las estructuras jerárquicas, en que uno hace arquitectura, otros hacen diseño detallado y otros codifican no llevan realmente a ningún sitio. Es mucho mejor un grupo de gente con mucha comunicación, que hagan un diseño previo y, sobre todo, que todos ellos sean programadores hábiles, a los que les guste programar y tengan muchísimo interés en hacer el código bien… ¡¡ y que no les metan prisa !!.

Dec 19

iBATIS

Al final creo que me he decidido por iBATIS. No he hecho más que unas pruebas sencillas con varios -Hibernate, iBATIS, JPOX, etc-, pero al final iBATIS me ha parecido el más "controlable".

Hibernate me ha fallado con la ingeniería inversa, no es capaz de tragarse el mismo los ficheros de configuración que él ha generado, aparte que los plugins y herramientas adicionales parecen bastante descuidadas.

JPOX ni siquiera he conseguido hacerlo funcionar -el plugin para eclipse, ni siquiera lo he probado a mano-. De todas formas, parece que toca los bytecodes después de compilar el código y eso me da "mal rollo".

iBATIS no me ha dado ninguna pega. El plugin para eclipse ha funcionado a la primera y el código generado funciona a la primera. Además, me gusta el tener los SQL visibles en un fichero, ya que siempre da la sensación de tener más control sobre lo que se está haciendo.

Un compañero mio probó cayenne, y aunque la ingeniería inversa se hace estupendamente con una interface gráfica de usuario, en los java beans mete cosas propias de él y no me convenció.

Por supuesto, y siguiendo mi costumbre, he puesto mis pruebas sobre iBATIS en la Chuwiki. Estoy deseando que me toque codificar algo contra una BD…

Dec 18

Ataque de Refactor

Buff, me ha dado un ataque de "refactoring" en una clase ClaseComun del paquete paquete_comun de la librería comun.jar … y llevo todo el día cambiando la misma tontería por todo el código de varios proyectos. Lo peor es que todavía no he acabado.

La verdad es que tenía ese cambio pendiente de hace lo menos un año y no lo hice en su día porque me daba pereza tocar todos los proyectos en marcha, pero esas cosas es peor dejarlas. A base de tropezarme una y otra vez con la misma pega, al final me he decidido a empezar a cambiarlo, y ahora hay más código que rehacer que hace un año.

Cuando haya que rehacer algo, aunque dé pereza tocar, es mejor hacerlo ya, que luego es peor.

Dec 17

Las cosas fáciles a veces son difíciles

En software, hay veces que en la teoría hay unas pequeñas ideas que son muy sencillas, pero que luego, a la hora de la realidad y del trabajo día a día son realmente complejas. Ya me he topado en varias ocasiones con ellas y he visto como caigo una y otra vez en los mismos problemas que teóricamente sé y no debería caer en ellos. Pongo unos cuantos ejemplos.

El primero y más tonto, es a la hora de  hacer componentes reutilizables. Tienes, por ejemplo, que hacer un gráfico que en el eje de las x pinte el tiempo y en el eje de las y el número de veces que te llega un mensaje por un socket. Cuando te pones a codificar ves que es un simple histograma, o un gráfico x/y en el que hay una función, y decides hacerlo general. Te haces un proyecto separado de gráfico-histograma, lo codificas y lo haces general. Es capaz de dibujar cualquier función por puntos o histograma. Curiosamente para pasarle las x has llamado al método setFechaHora() y setNumeroMesajes().

Sin embargo, hacer ese ejemplo bien, también es complejo. En cierta ocasión quise hacer una especie de traductor de palabras de inglés a español. Hice un fichero de propiedades con palabra_español=palabra_ingles. Me empece a hacer la clase que leía el fichero de propiedades y ponerle método getEnInglés(), getEnEspañol(), etc. Al final me doy cuenta que es más general que todo eso, puede servir para cualquier pareja de idiomas. Así que getEnIdioma1() y getEnIdioma2(). Pero claro, es más general todavía, sirve para cualquier pareja clave-valor. Vuelvo a cambiar los métodos… y al final tengo una copia hecha por mi mismo de la clase Properties de java.

Es difícil saber hasta dónde generalizar y hasta dónde dejar como específico.

Segundo ejemplo de cosa sencilla compleja. Actualmente estoy usando XPlanner, un poco para jugar, pero tratando de tomármelo un poco en serio. Tengo muy clara la idea que hay que pensar una historia de usuario -alguna funcionalidad concreta- y ponerle tareas concretas con tiempos y demás. El problema que tengo es que siempre acabo poniendo tareas generales que no son de una funcionalidad concreta. Por ejemplo, las historias deberían ser "dar de alta usuario nuevo", "borrar usuario existente", "modificar datos de usuario", etc. Las tareas deberían ser "hacer la gui de pedir usuario nuevo"; "hacer la inserción de usuario nuevo en bd", etc. Sin embargo, tiendo a poner "gestión de usuarios de la bd", en la que incluyo alta, baja y modificación de usuario con la base de datos. Supongo que el mal es excusable en el sentido de que tratas de hacer todo lo relativo a base de datos de una sola vez. Sin embargo, aunque quieras aprovechar a hacerlo todo de golpe, eso no quita que pongas TRES tareas separadas: alta, baja y modificación de usuario. Esto, además, debe ser así, porque obliga a pensar qué es exactamente eso de "gestión de usuarios en la bd". Independientemente de que se use o no XPlanner, este es un problema demasiado habitual en cualquier tipo de planificación: no definir claramente cual es la tarea exacta que se quiere hacer.

Es difícil concretar lo suficiente las tareas a hacer.

En cuanto al tercer ejemplo, el consabido Scrum que ya he comentado varias veces. Lees la teoría y es algo muy sencillo. Sin embargo, la práctica es bastante compleja. Requiere mucha, mucha disciplina, para hacer las reuniones diarias. Se junta con el problema que comenté antes de XPlanner/planificación: los sprint deberían ser concretos y no cosas como "gestionar usuarios en la bd". Y lo que yo veo más complejo, requiere gente que colabore y con buen rollo. Hace falta motivar a la gente, que vayan a priori convencidos de que el método es útil e intenten sacarlo adelante. De nada sirve que creas tú solo en él, andes todos los días tirando de la gente para las reuniones y el día que faltas nadie mueva un dedo por seguir con el tema.

Es dificil organizar a más de uno -incluso yo conmigo mismo tengo mis problemas-.

Dec 15

¿Se estarán pasando los de google?

Leo en google.dirson esta noticia que me deja un pelín preocupado. Aunque el principio de la noticia no cuenta nada del otro mundo, simplemente la evolución de la web y el rechazo de la wikipedia a poner anuncios google, los últimos párrafos sí son más chocantes.

Por lo visto, google tiene un marcha un proyecto llamado google knol, en el que google pretende que la gente escriba los artículos científicos, de historia, generales, etc. Por supuesto, piensa pagar a los que escriban por medio de los anuncios insertados en esos artículos.

Lo peor de todo esto es que posiblemente estos artículos empezarán a salir en el buscador de google, supongo que en igualdad de condiciones con el resto de la web. Pero, si google hace las cosas la mitad de bien de lo que suele hacerlas, lo más probable es que esos artículos salgan de los primeros en las búsquedas. Todo esto hará que la gente tienda a escribir sus artículos allí, ya que tendrán visitas y además cobrarán por ello, en vez de tratar de mantener sus propios sitios web, sin garantía de éxito y pagando por el hosting.

¿No llevará todo esto a un monopolio demasiado monopolio?. Google ya no sólo controlará las búsquedas, sino que con el tiempo quizás también la información. El tiempo lo dirá.

Dec 14

Camiseta chuidiang.com

Me he encontrado un sitio donde se pueden hacer de estas -me refiero a la camiseta-. De momento me he conformado con hacer la foto.

camistea chuidiang com

Dec 13

StringBuilder

Desde java 1.5 tenemos la clase StringBuilder. Esta clase es similar a StringBuffer, pero con la diferencia de que no es segura para su uso con varios hilos. Esto, si sólo usamos un hilo, la hace más eficiente que el uso de StringBuffer, ya que no tiene los métodos sincronizados.

La clase StringBuilder es ideal para esos String que construimos a base de concatenar trozos localmente dentro de un método, por ejemplo, para sacar una salida por pantalla o construir una sentencia SQL.

Hay sin embargo un curioso detalle más. El compilador de java es listo y si concatenamos cadenas con el típico +, como por ejemplo

String unaCadena = "hola, " + tuNombre + ". ¿Cómo estas?";

el compilador reemplaza todo esto por una construcción en condiciones usando StringBuilder. En tiempo de ejecución ese código es igual de eficiente que si usáramos StringBuilder y más eficiente que si usamos StringBuffer, contrariamente a lo que pasaba en las primeras versiones de java.

Ahora me alegro de no haberme acostumbrado nunca al uso de StringBuffer.

Tienes todo esto mucho más detallado en Manipulación de cadenas en java.