Developing Frogtek

El blog del Departamento de Tecnología

Etiqueta: optimizar

Scrum, Kanban y la matriz de Eisenhower

Érase una vez un Scrum Master que controlaba el proceso Scrumban que un equipo seguía. ¿Le pitan a alguien los oídos?. Dicho de otro modo, para que no se diga que aquí sólo escribimos para los “talibanes agilistas” ;P.

Erase una vez un gestor de un equipo encargado de llevar a cabo tareas planificadas y no planificadas en un periodo de tiempo determinado y cíclico. No sé cual de las dos introducciones es peor.

Érase, también, una vez un Product Owner malvado que no hacía más que meter Kanban en el sprint, haciendo sufrir al Scrum Master y poniendo a prueba la velocidad del equipo. El Scrum Master le insistía al equipo para que no dejara abandonadas las tareas de Scrum, mantuviera una velocidad de Scrum aceptable y consiguiera los objetivos del sprint. Y en estas llegó la retrospectiva y el equipo le afeó al Scrum Master que priorizara el Scrum frente al Kanban, ya que todos son hijos de Dios (del Product Owner en este caso). Así que el Scrum Master se puso a pensar y sacó las siguientes moralejas además de escribir este post.

  • El equipo tiene razón, en teoría, el Kanban es tan válido como el Scrum. La suma de todo nos da la velocidad total del equipo y si los puntos totales al final del sprint son iguales o mayores que los planificados el equipo habrá cumplido con su papel.
  • El Scrum Master también tiene razón, en la práctica, el Product Owner siempre, salvo cambios grandes de requerimientos, espera que todo el Scrum esté acabado en la fecha final de sprint. Si el Scrum se termina, el Scrum Master habrá cumplido con su papel.
  • El hecho de no tener definidos claramente las prioridades del Kanban (FIRE, PRIO, ASAP) puede fomentar estos problemas. El Kanban en Frogtek entra directamente en la pila de producto del sprint y se empieza antes o después en función de lo arriba que entre en la columna. Es decir, es priorizado junto con lo demás (hasta ahí bien), pero luego cuando entra y navega por las diferentes fases no tiene ni más, ni menos prioridad que el resto de lo que está en desarrollo. De ahí que el Scrum Master en algún caso acabe defendiendo lo planificado y el programador quiera que todo se valore por igual, ambos defendiendo su trabajo. Pero ¿debe hacerse?.

Aquí es cuando entra en juego la relación entre las tareas de Scrum, Kanban y la matriz de Eisenhower. Eisenhower se ve que era un tío muy organizado y las malas lenguas dicen que inventó el típico plano cartesiano con cuatro cuadrantes, con un eje señalando la importancia y otro la urgencia. Así tras analizar una tarea en un momento dado podía decidir qué hacer con ella:

  • Urgente e importante. Consejo de Eisenhower: ¡Hazla ya!. Consejo ágil: Normalmente esto es Scrum (en el peor de los casos esto entrará como Kanban de alta prioridad a mitad de sprint pero en ese caso es bastante fácil poner al Scrum Master y al equipo de acuerdo en lo importante que es sacarla la tarea cuanto antes adelante).
  • No urgente pero importante. Consejo de Eisenhower: Planifícala. Consejo ágil: Vuelve a analizarla en la siguiente ronda de planificación y métela como Scrum en el siguiente sprint cuando ya sea urgente e importante.
  • Urgente pero no importante. Consejo de Eisenhower: Delega. Consejo ágil: Normalmente esto es Kanban, ya que su urgencia suele salir a relucir a mitad de sprint y nunca tendrá la importancia suficiente para entrar como Scrum. Este tipo de tareas son las que crean conflicto a veces y las que acaban retrasando los sprints.
  • Ni urgente, ni importante. Consejo de Eisenhower: ¡A la basura!. Consejo ágil: si ves muchas de estas en tu tabla, cambia de Product Owner.

Simplificando un poco se podría asimilar Importante con Scrum y Urgente con Kanban. Es por eso que como Scrum Master creo que Scrum casi siempre debe ir por delante que Kanban. Siendo flexibles, claro. 🙂

Tabla de kanban para las retrospectivas

Al principio nuestras reuniones de retrospectiva eran de lo más… cómo decirlo sin ofender a nadie… anárquico. Tanto en contenido como en periodicidad, es decir, las hacíamos cuando queríamos y como queríamos. Podían pasar meses entre una y otra, y cuando por fin hacíamos una nos dábamos cuenta de lo útiles que eran y la cantidad de cosas interesantes que surgían. Las ha habido incluso que han supuesto un punto de inflexión en nuestra manera de trabajar, como aquella que hicimos con la excusa de que algunos habían acudido a un evento llamado AOS en una ciudad llamada Barcelona.

Con el tiempo, y conforme te haces con todos los procesos y ellos dejan de dominarte a ti, hemos sido siendo más constantes y periódicos con estas reuniones. Incluso nos compramos un libro, Agile Retrospectives (del cual he de reconocer que sólo he leído los primeros capítulos) e investigamos por internet sobre la mejor manera de hacerlas. Hay infinidad de técnicas que se pueden aplicar. Nosotros optamos por una de lo más sencillo. Básicamente cada miembro del equipo escribe en uno o varios post-its las cosas que han ido bien y las cosas que han ido mal en el último mes. Se ponen en común y se agrupan por temas, de forma que podemos identificar cuales son las principales virtudes que debemos fortalecer y cuales los principales problemas que hay que paliar. Sigue una discusión sobre estos temas de la cual obtenemos una lista de puntos de acción que se revisan de retrospectiva en retrospectiva. Además de puntos de acción también salen sugerencias y recomendaciones (o lo que podríamos llamar puntos de acción “vagos“… del estilo de “sed todos buenos“). Estas recomendaciones son un problema porque no es fácil hacer un seguimiento de su cumplimiento ya que no son objetivos SMART. En la última parte de la reunión debatimos también sobre las ideas que cualquiera haya incluido en la excel que tenemos para “ideas a discutir durante la retrospectiva”.

Llevamos ya varios meses siendo muy regulares con este tema y ahora hemos decidido dar un paso más y crear una tabla de kanban para ilustrar el proceso. Nos gustan los post-its y ayudan a decorar la oficina… qué se le va a hacer!!.

En la foto podéis ver cómo en verde y rojo apuntamos las cosas buenas y las malas, para que a nadie se le olviden. Más importante aún son los puntos de acción cuyo seguimiento realizamos con una tabla que no puede ser más simple. Adicionalmente tenemos nuestro apartado de sugerencias del mes… a ver si teniéndolas en la sala de reuniones a la vista, las tenemos más presentes. Si esto no funciona optaremos por recitarlas todas la mañanas en plan mantra antes del stand-up. Algo del estilo de:

  • Ser QA no me da derecho a hacer cowboy committing
  • Me flagelaré de forma inmisericorde si el stand-up dura más de 25 minutos

Muchas veces hemos oído que la reunión de retrospectiva es la más importante de todas las reuniones que conforman el espíritu ágil. Encarna la esencia del Kaizen y da la oportunidad de debatir, aportar y enriquecerse (espiritualmente, claro). He de reconocer que, personalmente, veo como muchas de estas reuniones suponen un soplo de aire fresco en Frogtek. Y veo, no sin orgullo, como nuestro equipo se autogestiona y mejora de forma imparable, día tras día y mes tras mes. Supongo que son los pequeños placeres del Scrum Master que no programa, dado que no puedo hacer el baile de la victoria tras compilar por última vez la loser story de turno.

 

El post-mortem del Ranatón

Volvimos de Morillo. Sanos y salvos y ahora estamos disfrutando todos de unas merecidas Navidades. Aunque, bueno, siempre tiene que haber alguien al pie del cañón, también es cierto que se trabaja muy tranquilo cuando todo el resto del mundo está de vacaciones. Es como un pomodoro continuo.

El Ranatón fue una gran experiencia. El sitio resultó muy apropiado (estábamos solos y aislados), la relación calidad precio fue lo más ajustado que pudimos encontrar y la conexión WiFi, el gran miedo que teníamos, funcionó más que aceptablemente para 9 personas que estábamos continuamente conectados.

El acabar el tercer día hicimos una especie de Stand-up retrospectivo. Sirvió para que cada uno presentara los avances conseguidos; notorios fueron los del equipo “Portal” que nos presentaron toda una serie de páginas web con unas gráficas más que jugosas, menos obvios pero tan o más importantes fueron los conseguidos por el equipo “Inframundo” (de infraestructura) que se dedicó a la no muy agradecida tarea de optimizar nuestra querida TiendaTek. Enhorabuena a los dos equipos.

Las conclusiones del Ranatón fueron las siguientes:

  • A todo el mundo le gustó, sobre todo porque rompe la rutina y es una buena manera de hacer equipo y de que todos nos conozcamos un poco más.
  • Es muy muy útil hacer una sesión intensiva en la que PO y programador tengan conexión directa y puedan trabajar juntos codo con codo. Esta vez sólo teníamos a David, pero ójala en nuestro siguiente Ranatón podamos traer también a Yael, Mark y Kristel. Puede parecer una obviedad pero es que nosotros tenemos a POs y programadores separados por miles de kilómetros en nuestro día a día.
  • Aunque durante un Ranatón se puede llevar a cabo cualquier tipo de tarea es mucho mejor aprovechar para implementar US que necesiten de mucho feed-back por parte del PO y de los compañeros. También es mejor no hacer US que sean supercomplicadas, son preferibles las tareas cortas y también aquellas que tengan un reflejo rápido y grande en el producto. Anima mucho ver que se avanza rápido y que los avances son muy visibles. Esto lo conseguimos con el equipo Portal, con el equipo Inframundo fue más complicado (el pobre Pablo se pegó tres días optimizando listas), lo haremos mejor la próxima vez.

  • Es muy útil tener una pizarra donde apuntar las US y tareas y poder registrar los avances. Nosotros además utilizábamos un timbre (de estos hotel) para dar cuenta de los US terminadas y de los cerditos que iban cayendo.
  • No fue el típico kick-off para hacer team-building ya que fuimos a Morillo a currar y no hubo las típicas excursiones o actividades lúdicas oficiales. Tres días fue la duración adecuada, acabamos todo bastante cansados.
  • Sí que hubo actividades lúdicas oficiosas como hacer alguna pausa para ir a arreglar el mundo al salón de al lado (el hotel entero estaba a nuestra disposición ya que estábamos solos), echar una o dos cervezas mientras se programa (nada de drunk-programming) o jugar un partido de tenis a dobles en la Wii.

  • La comida fue muy buena pero demasiado abundante, costaba un poco reenganchar después de un típica comida montañesa o de las deliciosas pizzas que tomamos las dos noches en Aínsa. Restaurante con loro incluido, por cierto… muy apropiado para el señor Stallman.
  • Trasnochar trabajando es un arma de doble filo. Por un lado es divertido y todo un reto estar programando hasta las 3:30 de la mañana. Cuando a partir de cierta hora el ambiente se relaja y se pone música de fondo para todos o se comparten unas cervezas uno tiene la impresión de estar una start-up al más puro estilo americano (los que hayan visto “La red social” que no se lleven a engaño, lo nuestro fue mucho más tranquilo… ni sexo, ni drogas). Por otro lado el oficio de programador tiene mucho de artesano y cirujano y, por lo tanto, la falta de sueño no es buena compañera y los grandes alardes se pagan de un día para otro… aquí como en muchas otras facetas de la vida lo importante es la regularidad y la constancia.
  • Concentrar a todos los “roncadores” en la misma habitación hizo que el resto del equipo descansara a pierna suelta… pero condenó al insomnio a buena parte de los primeros en la “habitación del pánico“.

Y esto es todo. Felices Navidades a todo el mundo.

Crear nuestros propios adapters para listados, y no morir en el scroll

Si no vienes del post introductorio, quizás te gustaría leerlo.

Tercera entrega de la optimización a la que fue sometida nuestra aplicación. Esta vez, tiene que ver con los listados de elementos; de muchos elementos, como puede ser el inventario de una tienda. Sirva como ejemplo práctico que solíamos crear nuestros propios adapters (extend BaseAdapter, todo sea dicho) muy alegremente, pero sólo al principio. Como buenos desarrolladores, copiábamos código del primer sitio que encontrábamos, sin fijarnos en lo óptimo que era. Y como buenos desarrolladores, repito, hacíamos las pruebas de nuestros propios adapters con 5 o 6 elementos para simular el inventario de una tienda.
¿Qué pasó? Cuando tuvimos nuestro primer tendero con ganas de inventariar toda su tienda, enseguida se nos vio el plumero. Una lista de 1200 (mil doscientos) elementos, con código copi-pegado y poco probado, tiene un 99% de posibilidades de ir más lenta, al hacer scroll, que el stand-up meeting de un lunes de resaca.

Como bien apuntó Francho en un comentario, una manera de ganar velocidad haciendo scroll es omitiendo los reiterados findViewById cada vez que hay que cambiar los valores del famoso convertView. En su lugar, debemos hacer uso de los tag que podemos asignar a las filas (rows) de nuestro listado. ¿A quién no le suenan las funciones setTag() y getTag()? Pues hace tiempo, a nosotros ni se nos pasaban por la cabeza. Luego de ver el magnífico video de la Google I/O 2009, Making your Android UI Fast and Efficient, hicimos una capillita en la oficina a Romain Guy. Merece la pena cada año ver los videos de la Google I/O…

Muy bien. Con esto que he nombrado arriba, tenemos solucionado una parte de nuestro problema; es decir: que cada vez que se haga scroll y haya que buscar los widgets cuyas propiedades han de cambiar, no se haga siempre mediante el findViewById(), si no que utilicemos los tags.
La otra parte del problema, venía al experimentar que aún habiendo mejorado la velocidad de scroll un poquito, no conseguíamos ese efecto de fluidez que una lista ha de tener. ¿Por qué? Muy sencillo: cada nueva fila que aparecía en el listado al hacer scroll contenía uno, o a veces más, widgets cuyo contenido era calculado en el mismo momento del getView(). A veces eran cálculos de sumas, fáciles. Otras veces eran consultas a la Base de Datos, lo cual nos estaba robando mili-segundos de muy alto precio al hacer que el scroll de tu aplicación sea fluido.

Por lo tanto, otro mandamiento que nos grabamos a fuego en la mente: No harás consultas a la Base de Datos en el getView() de tus propios adapters. Las consultas, se hacen antes del setAdapter() del ListView. Si no, arderás en el infierno de los developers.

Y ya, para rizar el rizo de la optimización de un listado y hacerlo más rápido que Usain Bolt: Dime cuál es la fuente de datos que alimenta tu Adapter, y te diré cuántos mili-segundos perderás en cada getView().
¿Por qué digo esto? Por que, como bien dijo Pedro en un post: hay que evitar a toda costa el trabajar con ArrayList de objetos propios en android. Reflection lo llaman, ¿no? Android y reflection no son buenos amigos.
Así que en lugar de acceder a los datos que poblarán nuestros ListView de manera limpia y con código legible, como puede ser un ArrayList, os recomendamos que uséis directamente el objeto Cursor devuelto por la Base de Datos. Sí: mucho más sucio el código, pero no veas lo rápido que va todo.

En resumen, hoy hemos visto:

  1. El ViewHolder para evitar millones de findViewById()
  2. No hacer consultas a la Base de Datos dentro de un getView()
  3. La fuente de datos de un Adapter, a ser posible, que sea un Cursor

¿Me olvido algo?

Diseño de layouts XML, sucios pero eficientes, en android

Si no vienes del post introductorio, quizás te gustaría leerlo.

Bien, pues a medida que añadíamos nueva funcionalidad a la aplicación en la tablet, experimentábamos una lentitud tremenda en alguna de las actividades que abríamos. No era normal que si en el teléfono, el mismo layout funcionaba perfectamente, ¿por qué al unir dos layouts en uno sólo, pero más grande, vaya tan lento? Respuesta: no hay nada que el traceview no solucione. Nada.

Rápidamente, Julio comenzó a ver que había miles de llamadas a una función nativa de android que se llama onMeasure(). La misma, se encarga de que cada vez que hay que posicionar un widget dentro del layout, hacer las medidas necesarias de lo ya presente en el mismo para así determinar dónde debe de ir colocado. ¿Y qué problema hay con esto? Pues que si tu layout tiene muchos widgets, y estos widgets tienen algunas de sus propiedades (como el layout_width, o layout_height) con valores wrap_content o fill_parent, todo resultará en un festival de onMeasure(). Creo recordar, que el 90% del tiempo de carga de una pantalla ineficiente nuestra, se lo llevaba esta función. Obviamente, pasamos de medio segundo para cargar una pantalla determinada en el teléfono, a 2 ó 3 (incluso más) en la tablet.
Por lo tanto, uno de los nuevos mandamientos que hay que grabarse a fuego es que: siempre darás medidas a tus widgets (Button, TextView, Layouts, EditText, etc), en lugar de que las decida android. Siempre, a no ser que sea estrictamente necesario; que alguna vez lo es.
Este es el primer paso para que la aplicación fluya un poquito más rápido que antes. Pero sólo un poquito.

¿Qué, que aún no hemos ensuciado el layout? Bien, pues este punto tiene que ver con el nivel en que un widget se encuentra anidado. Podemos tener un layout muy sencillo, con un RelativeLayout y dos Button dentro, o podemos tener algo como esto (o peor). Es por esto lo que un día dije en la oficina. Somos unos barrocos.
Por lo tanto, desde frogtek recomendamos encarecidamente que, a poder ser, se tenga un RelativeLayout padre con todos sus hijos al mismo nivel. Si se tienen 4 o 5 widgets en el layout, serás afortunado; si tienes 30 o 40 como en alguno de nuestra tablet, puedes volverte loco buscando uno en concreto en el Outline de eclipse. Cierto es que queda todo mucho más ordenado si vamos anidando widgets dentro de Layouts, pero se pierde rapidez al cargar, ya que también hay muchos más onMeasures() que si estuviesen todos al mismo nivel. Y traceview no miente.

Por lo tanto, el primer paso para agilizar la carga (o recarga) de una pantalla, pasa por dar medidas a todo widget al que podamos dar medidas absolutas, e intentar que nuestros layouts sean lo menos barrocos posibles en cuanto a ordenación jerárquica se refiere.

Consejo extra que se me ocurre mientras escribo: si utilizas el LayoutInflater para cargar layouts dentro de otros, tener un layout con uno o dos niveles de anidación ayudará mucho. Nosotros, que tenemos layouts dentro de layouts, y de nuevo dentro de layouts (por necesidad), lo hemos notado.

Optimizar una aplicación android (Introducción)

Hacía como mes y medio que quería escribir sobre este tema, pero me habría precipitado ya que desde esa fecha hasta ahora hemos aprendido mucho más sobre la optimización de una aplicación para android; aunque aún no quedan muchos conocimientos por adquirir.

Como ya hemos contado alguna vez, desde hace casi dos años, desarrollamos nuestro producto para teléfonos; teléfonos con una resolución fija. Y durante este verano, hemos dado el salto a una tablet. Suerte que todo el núcleo de la aplicación lo teníamos bien separado en un .jar. Por lo que el 2% del tiempo lo hemos invertido en retocar un poquito el núcleo, y el 95% restante ha sido armar una interfaz de usuario muy bonita, pero que nos ha dado bastantes quebraderos de cabeza, y que voy a intentar plasmar en una serie de posts.

Tras unas cuantas iteraciones y un empujón espectacular, teníamos muy avanzada la versión para la tablet. Pero el cambio de una pantalla de 320 x 480, a una de 800 x 480 conlleva problemas de memoria y de rendimiento (con un hardware superior al del teléfono, todo iba mucho más lento). Por que no es oro todo lo que reluce. Con un buen procesador, y bastante memoria no todo va a funcionar como pensabas. Por lo menos, en android. Nos hemos rascado mucho la cabeza, hemos sufrido, pero finalmente hemos aprendido muchas cosas; sobretodo de nuestros errores.

Es por ello, que nos gustaría compartir con vosotros los siguientes temas:

A medida que vayamos redactando la serie de posts, se actualizarán los puntos con enlaces a las URLs.