Nov 23

Herramientas frikis vs amigables

friki sheldom big bang theoryCuando busco herramientas para trabajar o aplicaciones para instalar, gratuitas, me he encontrado con frecuencia que hay dos herramientas con éxito, pero que difieren entre sí en un detalle, su facilidad de instalación/administración y sus posibilidades de extensión. Una de las herramientas es lo que yo llamo "para frikis", suele ser una herramienta muy potente y configurable, pero que requiere muchos conocimientos para administrarla. La otra es la herramienta "amigable", que un administrador sin profundos conocimientos informáticos puede instalar y poner en marcha sin demasiados problemas, pero que hace lo que hace y no es tan fácilmente salirse de eso. Veamos algunos ejemplos

Eclipse vs Netbeans . Ambas muy aceptadas en el mundo de desarrollo java. Eclipse es la herramienta de frikis. Puedes bajarte un eclipse "pelado" que apenas hace nada y luego liarte a instalarle plugins según el tipo de desarrollo que vayas a hacer (C++, java escritorio, java ee, plugins, etc, etc). Netbeans, por el contrario, es una herramienta más monolítica. Sí, también tiene plugins que puedes instalar/desinstalar, pero basta compara la página de descarga de eclipse y la de netbeans, para ver que eclipse requiere más conocimientos para saber qué quieres bajar. De hecho, hay más entornos de programación basados en eclipse, como el de Android o el de Spring, o el Aptana, que sobre netbeans. Suele ser normal también encontrarse que se usa eclipse en los entornos de desarrolladores profesionales, mientras que usan más netbeans los programadores que están empezando.

drupal vs joomla . Ambos para la construcción de sitios web. Drupal es la herramienta de frikis, aunque tiene una administración bastante intuitiva, es más espartana, muchos plugins desarrollados y posibilidades realmenten sorprendentes. Joomla, sin embargo, tiene una administración más vistosa (aunque a mi me resulta menos intuitiva) y tiene bastantes y más vistosos temas que drupal. De alguna forma, drupal es adecuada para administradores con conocimientos que en un momento dado requiran instalar o desarrollar plugins que hagan cosas que se salgan de lo normal en un sitio web, mientras que joomla es adecuado para obtener rápidamente un sitio web vistoso. Basta mirar el número de plugins de drupal (más de 14000) y el de joomla (más de 7000).

Geoserver vs mapserver Ambos servidores web de mapas. Mapserver es el de frikis, ejecutable nativo, mucho más eficiente sirviendo mapas, pero sin una interfaz web de administración (salvo instalando plugins) y un horror para configurar los mapas, a base de editar ficheros con sintaxis específicas. Geoserver, sin embargo, hecho en java, algo más lento sirviendo mapas, tiene una interfaz web de administración muy intuitiva y sin muchos conocimientos de geoserver, en pocos minutos se puede tener funcionando y sirviendo mapas. Mapserver es adecuado para un servidor de mapas que no vaya a tocarse mucho y que se requiera que sea eficiente, se configura una vez y listo. Geoserver más adecuado si se va a andar cambiando con frecuencia los mapas servidos o va a tener que administrarlo alguien sin muchos conocimientos.

redmine vs trac. Ambos gestores de tareas/incidencias. Redmine es el amigable, con una interfaz web de administración muy intuitiva, mientras que trac venía sin interfaz web de administración cuando lo estuve mirando, aunque ahora ya la lleva. La administración se hace por línea de comandos con un comando "trac-admin". Eso sí, al menos cuando los instalé, ninguno de los dos es fácil de instalar, aunque redmine me dio bastante menos guerra.

Git vs Mercurial. Ambos sistemas de control de versiones distribuidos. Git, diseñado por linus torvalds, cuenta aparentemente con más comandos avanzados y de bajo nivel, dándonos más posibilidades de hacer más cosas. Mercurial, sin embargo, tiene los comandos necesarios para hacer lo que se necesita en este tipo de herramientas. Sus características avanzadas están deshabilitadas por defecto. Git gusta a los frikis, Mercurial tiende a ser más la herramienta de los que necesitan un control de versiones distribuidos y no quieren pelearse con ella, sino dedicarse a desarrollar su propio proyecto. Es curiosa la comparativa en que se dice que Git es como Wesley Snipes y Mercurial como Denzel Washington. Denzel Washington es todo un actor, pero tiene una vida real normal, nada interesante. Mientras que Wesley Snipes, quizás no siendo tan buen actor, es mucho más divertido por tener una vida real más agitada. Por cierto, en el artículo dicen que Subversion sería Morgan Freeman.

Aunque una de ellas no es gratuita, por supuesto, Windows vs Linux. No hay mucho que comentar, creo que todos conocemos las virtudes y defectos de ambos sistemas operativos. Todos sabemos cual es el amigable y cual el de frikis. Y de la misma forma, Android vs iOS, que creo que tampoco es necesario comentar

Y seguramente hay más, aunque en este momento, con mi mujer al lado dándole a la ruidosa aspiradora, no se me ocurren más.

Sep 16

La leche con el spam

Tengo desde hace tiempo un pequeño blog en el que contaba mis andanzas con los deportes: correr y bicicleta. Hoy se me ha ocurrido mirar las estadísticas de uso de recursos en el hosting donde está alojado y me encuentro con burradas como que de los 4 Gigas de disco duro que tengo disponibles hay 2 Gigas ocupados y que en transferencia de datos, en lo que va de mes, llevo gastados 14 Gigas. ¡¡ Imposible !!. Ese blog lo miramos mi amiguete de bicicleteo y yo. Así que me pongo a investigar.

Lo primero que me llama la atención es que los 2 Gigas de disco los consume la base de datos, pero que el crecimiento en el tiempo ha sido casi contínuo y exagerado, y eso que llevo casi dos años sin escribir en ese blog

crecimiento de ocupacion en disco de base de datos

Y mirando más, lo segundo que me llama la atención es el país de procedencia de la mayoría de las visitas … ¡¡CHINA!!

 

 

Así que rápidamente se me abren los ojos. Es cosa del spam seguro, llevo tiempo peleándome en mis web con spam procedente de china. En este blog en concreto, recibía montones de comentarios de spam, así que primero puse que habría que registrase para poder comentar. Seguían llegando comentarios, así que puse que los comentarios requerían aprobación …. y me olvidé de aprobarlos y controlarlos. Seguro que esos comentarios en espera de aprobación son los que ocupan base de datos.

Y efectivamente, reviso la tabla de comentarios y nada más y nada menos que 500000 registros, 500K comentarios en espera de aprobación. Así que nada, borrados todos los usuarios excepto yo, borrados todos los comentarios excepto los aprobados y a ver qué pasa. Veo en el log del sitio que hay un "chino" que está intentando acceder (login) aproximadamente una vez por minuto.

Pues eso. ¡¡Malditos spammers!!

Jul 20

La leche, lo complicado que es programar en Android.

Hace ya unos meses que estoy leyendo un libro de programación en Android y haciendo algunas prácticas con mi tableta, bueno, más leyendo que haciendo prácticas, pero en ello ando. Y me llama la atención lo compleja que es la programación sobre Android.

No, el lenguaje java no es complejo, no más que cualquier otro lenguaje y menos para mí, que llevo años programando en java y no soy novato. Tampoco la API que ofrece Android es especialmente compleja. La documentación no es muy allá, hay partes de la API más claras y otras más oscuras, pero hay muchos ejemplos y tutoriales por internet, por lo que no hay demasiado problema en conseguir lo que quieres en un momento dado.

¿Cual es la complejidad entonces?

Android está pensado para móviles y tabletas, es decir, dispositivos escasos de recursos: poco procesador, poca memoria, poca batería y poco "disco duro" , por llamar de alguna forma a los pocos Gigas de almacenamiento interno que tiene, tarjeta micro SD aparte. Y como Android está especialmente pensado para sacar el máximo partido posible a esos pocos recursos, se siente con total libertad para quitar nuestro programa en ejecución de memoria en el momento que considere oportuno. Habitualmente, si el usuario está "jugando" con nuestro programa, no pasará eso, o sí. Pero si el usuario deja de atender la tableta un rato y entra en modo de ahorro de energía, si el usuario pone otra aplicación encima de la nuestra aunque sea momentáneamente o si símplemente, el usuario gira el dispositivo para que pase de vertical a apaisado o viceversa…. Android liquida nuestro programa de memoria y vuelve a cargarlo cuando lo considera necesario.

Pero como se espera que nuestro programa siga con lo que estaba haciendo cuando se vuelve a cargar en memoria, Android avisa a nuestro programa de que va a ser descargado de memoria, dándonos la oportunidad de salvar el estado del programa para que podamos restaurarlo luego. No quedaría bonito que el ususario esté con nuestro programa, se le ocurra momentánemente poner otra aplicación encima  y cuando vuelva a nuestro programa, haya perdido todo lo que estaba haciendo. Así que ante esos avisos de Android, debemos salvar todo lo que sea importante. Cuando nos vuelvan a llamar, Android nos pasará lo que habíamos salvado, y tenemos que restaurarlo. Si el usuario gira la pantalla, pasa lo mismo pero muy seguido, nos quitan de memoria dándonos oportunidad de salvar nuestros datos e inmediatamente después nos ponen en memoria para que recuperemos los datos… y podamos poner ventanas más acordes a la nueva orientación de pantalla. Y todo esto tiene como consecuencia, además de la pesadez de guardar y restaurar nuestro estado, que no nos podemos guardar en nuestras variables referencias a ventanas u otros objetos, ya que no sabemos en qué momento dejarán de estar disponibles.

El otro tema que complica la vida, también relacionado con la escasez de recursos, son las tareas que llevan tiempo. Android nos limita a unos pocos segundos ya que mientras nuestra tarea se realiza, la pantalla no responde. Si nuestra tarea no termna en unos pocos segundos, Android dará un aviso al usuario de si quiere abortar la tarea. Así que cualquier tarea que pueda tardar, como echar unas cuentas, consultar algo en internet, etc, debe hacerse en un hilo separado. Pero, aunque se puede, no es correcto hacer un hilo "vulgaris" de java,. ya que Android debe controlar también los hilos y debemos lanzarlos a través de API de Android. Así que debemos pedirle a Android que lance la tarea, debemos indicarle si esa tarea debe mantenerse aunque nuestra aplicación termine (un servicio), etc, etc y debemos indicarle a Android cómo avisar a nuestra aplicación cuando la tarea termine, para que muestre los resultados, siempre teniendo en cuenta que nuestra aplicación puede haberse ido de memoria y vuelto.

Total, que para programar cualquier cosa más allá de un "Hola Mundo" y hacerlo bien, es necesario hacer que nuestro programa tenga toda una "conversación" con Android y lo dicho, ¡la leche, lo complicado que es programar en Android!.

Jul 13

Seguir las reglas a ciegas

Veo esta duda en StackOverflow en la que preguntan si hay alguna forma de que los getter y setter en java se puedan generar automáticamente desde código, igual que muestra cómo se hace en Javascript. Mirando las respuestas, se llega por ejemplo a proyectos como Project Lombok, en el que poniendo anotaciones @Getter y @Setter en el atributo, los genera automáticamente.

Si vamos un poco más allá, también el lenguaje Groovy hace automáticamente estas cosas, pone en los bytecodes compilados métodos getter y setter para los atributos, de forma que podemos usarlos desde otros lenguajes como java.

Maravilloso, todos sabemos que hacer los atributos privados y poner setter y getter es una de las buenas costumbres de programación y es pecado no hacerlo, así que todas estas maravillosas herramientas lo hacen AUTOMATICAMENTE por nosotros, ahorrándonos escribir el tedioso código.

Pero creo que nos olvidamos del fondo. ¿Por qué es bueno hacer los atributos privados y poner getter y setter?. La respuesta todos la sabemos: encapsulación. Pero, ¿nos hemos parado a pensar realmente qué es eso?

Imagina un atributo privado "chisme" con su correspondiente getter y setter

private double chisme;
public void setChisme(double chisme) {
   this.chisme=chisme;
}
public double getChisme() {
   return this.chisme;
}

La ventaja de la encapsulación es que si más adelante decido que en vez "chismes" tengo "trvilorios" (todos sabemos que los "chismes" y los "trivilorios" son equivalentes y podemos obtener unos de otros) y que en vez de double, es un BigDecimal, podemos hacer esto

private BigDecimal trivilorio;
public void setChisme(double chisme) {
   this.trivilorio = getTrivilorioAPartirDeChisme(chisme);
}
public double getChisme() {
   return getChismeAPartirDeTrivilorio(this.trivilorio);
}

Y esta es la verdadera ventaja, hemos cambiado el atributo, pero mantenemos los setter y getter de chisme, haciendo las cuentas necesarias en esos métodos. De esta forma, todo el código que use nuestra clase seguirá usando setChisme() y getChisme() y seguirá trabajando con chismes y no con tirvilorios, no necesitamos cambiar nada, posiblemente ni siquiera recompilar ese otro código,  y todo seguirá funcionando.

Pero si usamos maravillosas herramientas que generan automáticamente los getter y setter, perdemos el encapsulamiento, que es precisamente el único motivo de la existencia de esos setter y getter. En el momento que cambie "chisme" por "trivilorio", aparecerán automáticamente getTrivilorio() y setTrivilorio(), pero desaparecerán, también automáticamente, getChisme() y setChisme(), por lo que todo el código que hay por ahí usando setChisme() y getChisme() se debe rehacer, recompilar…. y posiblemente hacer las conversiones de chisme a trivilorio y viceversa, o bien tocar el código que usaba chismes y ahora tiene que usar trivilorios.

Así que ojo con estas herramientas. Si queremos que el código que usa nuestra clase no tenga que cambiar y usamos estas herramientas, después de cambiar chisme  por trivilorio, debemos escribir manualmente los métodos getChisme() y setChisme() con su correspondiente conversión, manteniendo así la compatibilidad y la encapsulación. Por supuesto, setTrivilorio() y getTrivilorio() pueden y deben añadirse, automática o manualmente.

Jun 29

Primeras impresiones de Apache Cassandra

Apache CassandraEstán de moda las bases de datos BigData, bases de datos que son capaces de manejar cantidades ingentes de datos con multitud de clientes simulttáneos insertando, modificando y consultando datos. Al quedarse pequeñas las bases de datos tradicionales, las grandes compañías como google, facebook, … desarrollaron sus propios sistemas de base de datos : Google desarrolló BigTable y Facebook comenzó lo que ahora es Cassandra.

Así que me he puesto a jugar con Apache Cassandra y he aquí mis primeras impresiones.

Lo primero es que me ha parecido muy simple de instalar y poner en marcha. Un simple zip para desempaquetar y arrancar, o bien un instalador adecuado para el sistema operativo. Por ejemplo, el de Windows lo instala directamente como servicio si así lo deseamos.

Conectar varios servidores de Apache Cassandra entre sí para que formen un nodo multi-cluster también es relativamente sencillo. No he visto una documentación que diga correctamente todo lo que hay que tocar, pero no son más que cuatro o cinco propiedades en el fichero de configuración y no cuesta mucho encontrarlas tras revisar un poco la documentación para tenerlo funcionando.

Finalmente, desde java con el conector adecuado o bien desde la misma línea de comandos que ofrece Apache Cassandra, se pueden crear los primeros keyspaces, column families y datos. No he tenido demasiados problemas para hacer funcionar correctamente los ejemplos que encontré por ahí o mis propias pruebas.

Hablando de pruebas, me dio por comparar velocidad entre Apache Cassandra y PostgreSQL. No hice una prueba exahustiva, simplemente cree en ambas bases de datos una tabla igual, con las mismas columnas e índices, un solo servidor Cassandra, sin cluster ni nada, y partiendo de cero registros en cada tabla, lance dós hilos java, uno a hacer "update or insert" en una base de datos y otro lo mismo en la otra. Para Cassandra sólo insert, ya que si la fila existe, hace el update automáticamente. El resultado fue que PostgreSQL es más rápido inicialmente (unos 150 ms por cada 1000 insert/update frente a los 400 ms de Cassandra), pero tras estar funcionando el programa un rato largo y tener cerca de 2 millones de registros en la tabla, PostgreSQL tardaba unos 1700 ms por cada 1000 insert/update, mientras que Cassandra se mantenía firmemente en 400 ms.

Me ha parecido impresionante la facilidad de uso y su posibilidad de distribuir datos entre varios cluster, haciendo réplicas en varios discos o bien repartiendo los datos. Sin embargo, le he visto una gran pega a Apache Cassandra, precisamente su punto fuerte se convierte en su punto débil.

Cassandra está pensada para montar N servidores, cada uno con su ejecutable de Cassandra, trabajando en paralelo sobre M discos duros. Es capaz de manejar mogollón de datos eficientemente porque tiene a su disposición varios ordenadores entre los que repartir la carga y varios discos duros en los que repartir los datos. No es lo mismo que miles de clientes accedan simultáneamente a miles de datos dentro del mismo servidor y mismo disco, que Cassandra sea capaz de distribuir esos clientes en función de la carga de cada servidor y de lo ocupados de los discos. De hecho, los clientes puede conectarse a cualquiera de los ejecutables de Cassandra indistintamente. Pero justo esa distribución de datos en varios discos tiene una pega.

Si se hace una consulta de datos, Cassandra tendría que recorrer todos los discos para asegurarse que encuentra todos los datos solicitados. La busqueda de datos, pensada así, no es eficiente, así que Cassandra de alguna forma prohíbe hacer búsquedas que no estén planificadas previamente. Hablando lenguaje de programador, en la cláusula WHERE de una consulta no podemos poner lo que nos dé la gana. Hay que indicarle a Cassandra, en el diseño de las tablas, cómo vamos a consultar, de forma que Cassandra sea capaz de repartir los datos adecuadamente en los discos y sea luego capaz de saber en qué discos están los datos que estamos pidiendo.

Cassandra repartirá los datos en los discos de acuerdo a unos criterios, de forma que luego sea capaz de encontrarlos eficientemente. El primer criterio es la clave primaria de la tabla, en función de su valor, va a un disco u otro. Siempre se puede consutar por clave primeria, porque Cassandra sabe en qué disco estará ese dato.

Si queremos buscar por otros campos que no sean clave primaria, Cassandra nos obliga a crear índices secundarios para esos campos. Usando estos índices, Cassandra también sabrá en qué disco está cada dato, por lo que las búsquedas serán más eficientes. Pero la misma documentación de Cassandra nos advierte, no es adecuado crear un índice secundario de un campo que tenga valores distintos siempre. Por ejemplo, si nuestra tabla es de una flota de camiones, podemos crear un índice por marca de camión, ya que habrá varios camiones de la misma marca. Pero si estamos guardando las posiciones del camión obtenidas de sus gps, no podemos crear índices por la fecha/hora de la posición, ya que es muy probable que no haya dos fechas/horas iguales en todas las tablas, ni tampoco por latitud/longitud, por el mismo motivo.

¿Qué dice Cassandra que hagamos entonces para ese tipo de campo si queremos buscar por él?. Pues aprovechar que las columnas de las tablas son dinámicas. Cada fila dentro de una misma tabla puede tener columnas diferentes a otras filas y las columnas se ordenan por orden alfabético de nombre de columna. Por ejemplo, si se quieren guardar las posiciones históricas de un camión obtenidas de su GPS, se crearía una tabla en el que la clave sería el identificador de cada camión, es decir, habría una fila por cada camión. En cada fila, cada vez que se obtiene una nueva posición del camión que corresponde a esa fila, se crea una columna cuyo nombre es la fecha/hora y cuyo valor es la posición. Si más adelante queremos consultar las posiciones de un camión, Cassandra sabrá en qué disco está el camión por su id y cargará la fila completa con todas las fecha/hora y posición.

Y surge ahí otra pega. Una fila en Cassandra está limitada a unos 2Gigas, pero además, como se carga en memoria completa, conviente que la fila completa no ocupe más de la memoria que estemos dispuestos a gastar en ello (unos Megas, posiblemente). Así que debemos "partir" esa fila en filas más pequeñas haciendo ciertos "artificios" extraños. Por ejemplo, la clave de la fila, en vez de ser el camión, podria ser una cosa compuesta como <camion>.<dia>, así en cada fila sólo estarán las posiciones de ese camión en ese día.

Y esta tabla sólo para consultar posiciones de un camión en determinadas fechas. Habría que inventar tablas similares si se quieren consultar, por ejemplo, camiones que hayan estado en una zona  geográfica determinada en determinadas fechas, etc, etc. Y todas esas tablas tenemos que tenerlas actualizadas desde código.

Bueno, el detalle no importa, lo importante es hacerse idea del "artificio" que hay que montar para poder hacer consultas eficientes por una columna concreta con una posición geográcia o con una fecha/hora y que el diseño de tablas va a estar muy relacionado con las consultas que queramos hacer. En muchos sitios, a la hora de diseñar una base de datos Cassandra, aconsejan empezar pensando qué consultas va a hacer nuestra aplicación, y luego empezar a diseñar tablas, incluso repitiendo datos en varias tablas si es neceasario por eficiencia.

¿Y cual es la conclusión?. Si vas a tener "BigData" (cantidades ingentes de datos y conexiones simultáneas), adelante, usa Cassandra o una base de datos equivalente, no te queda más remedio ya que las bases de datos SQL no son capaces. Pero si no vas a tener "BigData", usar Cassandra no te va a aportar grandes beneficios, pero si montones de pegas si no tienes muy claro qué consultas vas a hacer exactamente en tus tablas, y tendrás más cosas que codificar en tu aplicación para facilitar consultas "extrañas", como consultar por fecha/hora, ya que tendrás que hacer los insert adecuados en las tablas de columnas variables con claves compuestas <camion>.<dia>.  Por cierto, ¿he comentado que Cassandra no tiene JOINs ni permite consultas mezclando tablas?. Sí, es otra cosa que tendrás que hacer desde tu código.

Hay otro posible caso en que puede ser útil una base de datos NoSQL (pienso quizás en alguna como MongoDB más que Cassandra) y es en pequeñas/medianas aplicaciones donde sólo se necesite una base de datos y no se requiera toda la complejidad de una base de datos SQL (tablas, restricciones, "foreing keys", etc). Bases de datos como MongoDB son muy dinámicas, podemos insertar datos variopintos sobre la marcha sin necesidad de echar unas horas diseñando tablas y modificándolas si luego no nos valen. Evidentemente, con MongoDB también hay que echar una "pensada" previa a lo que queremos, pero no tenemos la rigidez de una base de datos SQL.

Jun 22

Visita a Paradigma tecnológico

Hace ya casi un mes, me tocó una visita a Paradigma Tecnológico.

El tema es que un departamento de nuestra empresa, no el mío, tiene un proyecto en el que está como requisito el uso de algunas tecnologías modernas, entre otras, BigData. Puesto que en los departamentos de nuestros alrededores nadie tiene experiencia con estas tecnologías, se ha decidido subcontratar desarrollo y asesoría a alguien que sepa del tema, para sacar el proyecto adelante y para aprender nosotros sobre ello. La empresa elegida ha sido Paradigma Tecnológico.

Esta compañía ágil, como reza en su página web, hace nuestro proyecto con Scrum y finalizado el primer Sprint, llega el momento de hacer la "demo" al cliente, es decir, al departamento de mi empresa. Teniendo yo fama de friki, este departamento y  mi propia jefa, decidieron que yo debía acudir también a ese sprint, para enterarme lo más posible de este tipo de nuevas tecnologías y ver si son aplicables a otros proyectos. Así que allí fuí.

Lo que más me llamó la atención, en lo que se puede ver dando un paseo por las instalaciones de Paradigma, es que sí tiene toda la pinta de que usen Scrum realmente en todos los proyectos. Según se pasea, se ven tableros de Scrum y paquetes de postit de colores por todos lados. Según se podía ver y me contaba una de las personas que trabaja allí, los desarrolladores trabajan en una sala diáfana con mesas agrupadas de 6 en 6, creo recordar. Los programadores de un proyecto trabajan juntos en un grupo de mesas y en la pared al lado de su grupo de mesas tienen el tablero Scrum. Nos enseñaron también el product backlog de nuestro proyecto, un tablero enorme con miles de postit pegados con celo y nos enseañaron el gráfico "burn down" correspondiente a nuestro primer sprint.

En cuanto al Sprint que nos hicieron, era un poco extraño, posiblemente por ser el primer Sprint. Básicamente consistía en explicarnos la arquitectura decidida, una demo real sencilla viendo funcionar esa arquitectura y un "mono" de la interfaz de usuario para que nos hicieramos una idea de cómo iba a ser. Como es de rigor en un sprint, insistieron mucho en que hicieramos comentarios y diéramos nuestras opiniones, ahí creo que nos quedamos un poco "cojos", culpa nuestra.

Hay algunos detalles del Scrum que no me cuadran con lo que pensaba, por ejemplo, para el segundo Sprint se indicaron las tareas que se iban a hacer, imagino que previamente acordadas con el Product Manager que es una pesona de nuestra empresa. Lo que no me cuadra es que en ese segundo Sprint no se llegaba a una funcionalidad útil para el cliente, sino que las tareas eran pequeños (o grandes) trozos de código que evidentemente hay que hacer, pero que no constituyen en sí un producto, aunque sea muy básico, que se pueda entregar de alguna forma, salvo quizás, como un conjunto de liberías. Quizás yo soy demasiado teórico. Quizás un segundo sprint (de 3 semanas) sea también muy pronto para obtener ese primer producto básico. En cualquier caso, no le he dado demasiada importancia, ya que en mis intentos de hacer Scrum con mi grupo de trabajo, sé lo complejo que es entregar un pequeño producto en los primeros Sprint, donde hacer cualquier cosa completa que vaya desde un extremo del sistema (la interfaz de usuario) hasta el otro (el equipo hardware que se quiere controlar), pasando por todos los pasos intermedios (base de datos, lógica de negocio, …) requiere hacer mucho código de la arquitectura del sistema. Pero me deja ese mal regustillo de que quizás Scrum es demasiado teórico, excesivamente complejo, o no aplicable a cualquier proyecto …

Resumiendo, la impresión en general ha sido buena y me voy confirmando cada vez más en que hacer un Scrum que cumpla al 100% con la teoría de Scrum es muy complejo.

Mar 29

He leído “JavaScript, The Definitive Guide”

Hace un mes aproximadamente terminé de leer "JavaScript, The Definitive Guide". Un libro sobre JavaScript y alrededores que me ha encantado. Aparte de JavaScript, trata bastante bien temas como JavaScript en un navegador web, una introducción a node.js y rhino en el lado del servidor, AJAX, jQuery, almacenamiento local en el navegador, Canvas de HTML5, …

Son un montón de páginas, 1100 nada menos, pero aproximadamente la segunda mitad son una guía de referencia de las funciones de JavaScript, por lo que de lectura es aproximadamente la mitad.

Comienza con los principios de programación en JavaScript desde cero, el típica capítulo de introducción al lenguaje que no aporta demasiado a casi nadie, demasiado rápido para el que no sabe nada de programación, pero demasiado trivial para el que sabe programar en otros lenguajes. Aun así, dentro de esta parte, he encontrado una pequeña joya para alguien como yo acostumbrado a otros lenguajes y es todo el tema de cómo se hacen conversiones de tipos automáticas, sobre todo en los condicionales, es decir, cuándo una variable independientemente de su tipo (string, numérico, un objeto,…) se considera que es true o false.

Sin embargo, luego empieza a meterse en profundidad en montones de temas variados de JavaScript y aquí es donde algún programador experto en otro lenguaje pero sin demasiado conocimiento de JavaScript, empieza a disfrutar del libro. Por supuesto, hay temas demasiado farragosos como para que sea agradable leerlos, pero hay otros que me han parecido geniales, tanto por lo que supone aprender cosas que no sabes, como por la forma de exponerlas.

Entre los primeros, los farragosos, está la parte de orientación a objetos en JavaScript, clases, herencias, polimorfismo a base de tipado tipo pato, También la parte de eventos en los navegadores web es pesadita, más que nada porque cada navegador es de su padre y de su madre y no hay acuerdo en los eventos que se producen, cómo se llaman y cuándo se producen. El libro no puede hacer mucho más que dar una lista con una breve descricpción de cada uno de ellos.

Sin embargo, entre las partes geniales, me ha encantado la forma de explicar las expresiones regulares, tanto, que he hecho mi propio tutorial de expresiones regulares en JavaScript siguiendo esa forma de explicación, por supuesto, donde esté el libro que se quite cualquier tontería que haya podido hacer yo. También me ha encantado la forma de explicar jQuery, todos sus apartados, desde los selectores para buscar y modificar elementos de nuestro HTML, como la parte de AJAX, efectos especiales como fadeIn() y fadeOut(), …

En fin, totalmente recomendado para aquel que ya ha empezado a programar cosas en JavaScript pero necesita profundizar y comprender más el tema.

Mar 22

Móviles, “the hard way”

Esta mañana, como todas las mañanas de día laborable, estaba desayunando en mi cafetería habitual antes de ir a trabajar. La camarera estaba hablando con uno de los clientes y comentaban el precio de un móvil que libre costaba unos 300€, pero si hacías contrato costaba unos 80€. Por supuesto, sería un móvil de estos güay que ahora, imagino que con Android o similar.

Mi móvil es un "patatófono", el de la foto, con java JME, con teclas y todo, de tarjeta prepago porque soy muy rácano y encima lo uso como hucha, ya que cada 6 meses le meto dinero para que no se caduque la tarjeta y como pasa el 99% del tiempo apagado, tampoco lo gasto.

Sin embargo, la conversación de la camarera me ha hecho pensar que todos estamos "pillados" por los móviles de última generación. Ella con su cliente de la forma habitual, pendiente de los "wasaps" mientras pone cafés, y yo, raro de mí, de la forma "dura". Justo mientras ella hablaba con el cliente, yo estaba desayunando y leyendo "Programming Android: Java Programming for the new generation of Mobile Devices".

Aprovecho para comentar que el libro no me está gustando demasiado. Voy aproximadamente por la página 150 de sus 550 y todavía está explicándome que eclipse tiene autocompletar. Hasta ahora va explicando las cosas metiéndose en detalles sueltos muy profundos, pero explicándolos por encima y sin dar un "esquema general". Por ejemplo, primero explica java en un capítulo, pero evidentemente muy por encima. Luego cuenta el SDK de Android con todas sus herramientas en otro capítulo, describe un montón de herramientas que vienen con el SDK, pero metiéndose en detalles sin explicarlos claramente. Luego se mete con detalles que considera importantes de la programación Android, como liarse a explicar programación concurrente, tema un poco "farragoso" para empezar por él, y nuevamente se mete en detalles sin explicarlos claramente.

Sigo leyendo, enganchado como estoy al "hard way" de los móviles.

Mar 17

La parte olvidada de las metodologías ágiles

Cuando se habla de metodologías ágiles y quizás porque en el fondo somos programadores y no gestores, siempre se habla de cosas como la reunión diaria, las entregas frecuentes, los tableros Scrum, los test automáticos, etc, etc. Sin embargo, hay otro punto realmente importante y del que no se suele hablar, la intervención directa del cliente a lo largo de todo el proceso.

Afortunadamente, he tenido oportunidad de practicar con este último punto y ahí va la experiencia. Pongámonos primero en contexto

El proyecto es un proyecto pequeño para lo que estamos acostumbrados, un solo desarrollador, yo mismo, durante algo más de seis meses y con la suerte de poder dedicarme al 100% al proyecto (cosas de la crisis, no hay demasiado trabajo). Hay también un jefe de proyecto, pero su única gestión es básicamente el tema económico y alguna reunión o charla esporádica con los "jefes" del cliente. El proyecto es un proyecto Web, en el que sólo hay software implicado, el servidor está desde el principio en las instalaciones del cliente, con su dominio público en internet y al que tengo acceso de administración con una VPN (red privada virtual)

En este contexto, tengo contacto diario y directo, por teléfono y email, con los usuarios finales del proyecto, los que van a estar usando esa web día a día, así que pensé que es una situación ideal para metodologías ágiles. Al ser yo el único desarrollador y estar el cliente en otra ciudad a más de 400 km de distancia, todo eso de las "demos" y reuniones al estilo Scrum no me parecía adecuado, así que  opté por una opción más al estilo Kanban. Me di de alta en https://kanbanflow.com , hice un tablero con cuatro columnas : to-do, in-progress, verification y done, copié los requisitos iniciales en la columna to-do y le mostré el tablero a los clientes, así como una explicación del funcionamiento general de Kanban y metodologías ágiles, en lo que a ellos les afecta. Les pareció una idea estupenda y es lo que estamos usando.

Ellos ordenaron y matienen ordenada la columna de "to-do", además de añadir más tareas cuando les viene en gana, en el orden en que quieren que se desarrolle. Yo siempre saco la primera tarea de arriba del todo y la muevo a la columna "in-progress", teniendo como máximo 3 tareas simultáneas en desarrollo. Cuando termino de probarla en mi entorno de pruebas y la subo al servidor, la muevo a "en verficacion" y ellos, tras probarla, la mueven a "done" o la devuelven a la primera columna con más cosas que quieren o bugs que han encontrado. En fin, nada que no sepamos ya del funcionamiento de un tablero Kanban.

¿Y cuales son las consecuencias de todo esto?. Pues bien, como nada es blanco ni negro, hay cosas buenas y otras no tan buenas. Empecemos con las primeras.

Lo mejor de todo es que el cliente está encantado. No es solo que me lo digan cuando les pregunto, es también el "feedback" que me da nuestro jefe de proyecto cuando habla con ellos o lo que yo mismo oigo a los clientes hablar entre ellos cuando nos hemos reunido cara a cara.

Lo primero que les gusta, por supuesto, es que el producto, aparte de no tener grandes fallos, cumple exactamente lo que necesitan, como no puede ser de otra forma, puesto que los mismos usuarios finales lo ven evolucionar día a día y deciden sobre lo que se debe hacer y cómo. Y lo segundo que les encanta es la excelente gestión de sus peticiones (mérito de un mecanismo como Kanban), ellos tienen total control sobre lo que piden y cuándo se aborda, así como total visibilidad de lo que se está haciendo y lo que tarda en hacerse. Ninguna de sus tareas lleva un tiempo estimado de más de 3 ó 4 días, pero la mayoría son de 1 ó 2 días, por lo que ven progresos de forma continua. Si alguna tarea lleva mucho más, hablo con ellos y tratamos de partirla, creando una tarea más pequeña con lo que realmente es importante para ellos y otras con lo menos importante y que puedan poner más abajo en la lista.

Y ahora viene la parte no tan buena. Aunque se deja claro al principio que pueden añadir, modificar y ordenar tareas a su gusto, también se deja claro que el proyecto tiene una fecha de terminación y que toda modificación que hagan o tarea que añadan, no debería afectar a esa fecha, sino simplemente hacer más probable, si no seguro, que las tareas al final de la columna to-do se queden sin hacer. Esto, por supuesto es algo que no les gusta oir. Pero eso no es lo peor, porque la ventaja de controlar el desarrollo día a día les convence frente a la posibilidad de que alguna tarea poco importante para ellos se quede sin hacer y de alguna forma, lo aceptan. Lo peor es que en el día a día se "emocionan" con las tareas que se van realizando y tienden a no acabarse nunca. Cuando terminas una tarea y ellos la prueban, se les ocurren mejoras que inmediamente hacen que la tarea vuelva a la columna "to-do", con añadidos para hacer y, normalmente, al principio para que se aborde inmediatamente. Hay que estar continuamente pidiéndoles verificación, como sutil indirecta de que nos estamos eternizando en los detalles, de si están seguros que ese nuevo añadido es más prioritario que las siguientes tareas en la lista.

Hay otro detalle, no sé si bueno o malo, y es el "pequeño estrés" que causa este método al desarrollador (yo). Al ver ellos el progreso día a día y ser tareas de tan poco tiempo estimado (1, 2, 3 días), "canta" mucho si un día me distraigo con cualquier cosa. Si tengo alguna reunión ajena al proyecto, si acabo de volver de vacaciones y tengo el típico día perezoso que te pasas "güeveando" en internet o con el email … Se ve agravado por el hecho de que para tener mejor visibilidad de cómo va el proyecto, llevamos un pequeño excel compartido que se actualiza todos los Viernes, en él aparecen las tareas, el tiempo que yo estimo para cada una de ellas en días y sumando esos días, la fecha prevista de terminación de cada una de ellas … y por tanto la fecha prevista de terminación del proyecto si se hacen todas las tareas. Si una tarea se complica más de lo previsto, ya me causa un pequeño "estrés" actualizar el excel y ver cómo la fecha de finalización se va alargando a la vista de todos. Pero me causa mucho más "estrés" si encima ese retraso va causado por la típica pereza que todos tenemos algún día que otro.

Puedo asegurar que nunca he trabajado tanto y tan seguido como en este proyecto, en parte por el "estrés" que me causa perder el tiempo, en parte por tener en todo momento perfectamente claro qué es lo que tengo que hacer y cómo. Ojo, no he echado ni una sola hora de más, es simplemente que apenas pierdo el tiempo a lo largo del horario laboral tratando de que el flujo de tareas de "to-do" a "done" sea lo más fluído posible.

Ahora nos estamos acercando a la fecha prevista de finalización, por supuesto, con requisitos iniciales que el cliente no ha considerado importantes al final de la lista to-do y totalmente fuera de plazo, pero con otros requisitos que han añadido sobre la marcha y que han considerado más importantes hechos a su gusto, con el cliente bastante contento en general. Veremos qué tal va el cierre final ….

Jan 28

El vi, esa gran maravilla

Ando liado con menús y chorradas varias en el proyecto. El "rollo" es que a veces los menús son muy largo (fíjate en esta tabla de códigos ISO de paises). En base de datos va el código numérico o el de dos/tres letras, mientras que al usuario se le deben presntar los textos legibles con el nombre completo del país. A veces es símplemente mostrar un país resultado de una consulta, otras veces es mostrar un menú (unos select/option de HTML).

Pues bien, a partir de una de esas tablas hay que conseguir bien una tabla en base de datos con dos columnas: código – texto legible, bien el menú select/option de HTML, bien un fichero properties de java con muchas líneas codigo=país, etc. Y muchas veces la única entrada que tenemos es copiar de una página web como esa.

Habitualmente, un "truco" que hago es seleccionar con el ratón la tabla de la página web en cuestión, esto me copia en el portapapeles el código de la tabla HTML y afortunadamente, si se pega eso en un Excel lo hace de forma correcta (fíjate en la imagen)

excel importando paises

Ahora el proceso es más fácil, se puede exportar esto a un CSV, que no es más que un fichero de texto en el que cada fila corresponde a una línea y los valores de las columnas van separados por comas, encerrados en comillas o como queramos. Eliminamos antes las columnas que no nos interesen y obtenemos un fichero de texto como este (abierto ya con el editor vi)

CSV en el vi

 

Bien, pues con un fichero como este, lo habitual sería cogerle algún lenguaje de script, como phyton, perl, awk o cualquiera de nuestro gusto y hacer un pequeño programita que lea eso línea a línea y genere lo que  nosotros queramos, estilo

<option value="AF">Afganistán</option>

si queremos, por ejemplo, un select/option de HTML. Pero no es necesario uno de estos lenguajes, el mismo editor vi (gvim en mi caso) tiene un potente buscar y reemplazar con expresiones regulares similares a las de cualquiera de esos lenguajes. Si en el editor anterior ejecutamos el comando (lo explicamos al final)

:%s/^\(\S\+\); *\(.*\)$/<option value="\1">\2<\/option>/

nos da el resultado esperado

gvim modificado

El comando no es más que un comando de vi que permite sustituir unas cadenas por otras.

El : es para entrar en el modo que nos permite escribir comando de este tipo.

El %s indica la s un "sustituir" y el % que se haga en cada línea. El comando s lleva este formato s/cadena a buscar/cadena nueva/.

La cadena a buscar es una expresión regular, en la que ^ indica inicio de línea y $ fin de línea, como en cualquier lenguaje.

\S+ indica caracteres no espacios una o más veces, como en las expresiones regulares de cualquier otro lenguaje. La diferencia aquí es que el + hay que escaparlo, por eso \S\+. Esto ira casando con los códigos de dos letras. El .* indica cualquier cadena de caracteres, que iran casando con las descripciones de los paises.

Como nos interesa guardarnos ambas cosas (el código y la descripción), las encerramos entre paréntesis, pero a diferencia de otros lenguajes, aquí también hay que escaparlos, así que quedan cosas tan feas como \(\S\+\) y \(.*\). Entre ambas está el ; y el espacio que por lo que vemos es opcional, es decir <espacio>*

En la parte de la nueva cadena, tenemos disponibles en \1 y \2 lo que habíamos colocado entre paréntesis, es decir código de país y descripción. Así que la cadena nueva no es más que el <option> completo, poniendo \1 donde va el código de país y \2 donde va la descripción.

Nada que no se pueda hacer desde un script en otro lenguaje, como hemos dicho, pero .. ¿qué pasa en mi caso que posiblemente hiciera el script usando el vi? ¿para qué hacer el script, salvo que piense reutilizarlo más veces?