Developing Frogtek

El blog del Departamento de Tecnología

Categoría: herramientas (página 2 de 3)

Robolectric: TDD en Android

Llevábamos ya desde nuestros inicios buscando herramientas que nos permitieran practicar TDD para desarrollar las clases de nuestro proyectos en Android. El problema era que las Activity (clase fundamental de las aplicaciones Android) solo podían ser testeadas a través del propio entorno Android, nunca como clase independiente. Por lo tanto, los únicos tests que habíamos realizado sobre esas clases eran tests de integración, que podían tardar del orden de 4 minutos en ejecutarse por completo, lo que nos imposibilitaba el realizar un diseño guiado por tests.

Robolectric (http://pivotal.github.com/robolectric) es una herramienta que nos va a permitir lanzar tests unitarios en Android.

Su uso nos aporta varias ventajas:

  • Ejecuta tests en Android que duran segundos y no minutos, como en el caso de un Android jUnit test.
  • Su velocidad nos permite practicar TDD al crear clases en Android.
  • Podemos usar Mockito o PowerMock en conjunción con los tests de Robolectric.
  • Nos permite utilizar clases de librerías Android, como JSONObjects o JSONArrays, que en otros entornos no podríamos usar.

Como algunas clases de Android no tienen métodos para acceder al estado o las variables que contienen, la gente de Robolectric se ha sacado de la manga los Shadows (ShadowImageView, ShadowRelativeLayout, ShadowActivity, etc.), los cuales nos van a permitir realizar pruebas como esta:

@Test
public void testImagenEsCorrecta() throws Exception {
    ImageView imagenBanner = (ImageView) activity.findViewById(R.id.banner);
    ShadowImageView shadowBanner = Robolectric.shadowOf(imagenBanner);
    assertThat(shadowBanner.resourceId, equalTo(R.drawable.img_banner_grande));
}

Cómo configurar Robolectric para Eclipse:

Estos son los pasos básicos para configurar Robolectric en Eclipse. Recomiendo seguir el quick-start de la web oficial para más detalles:

  1. Crear una nueva carpeta en la raíz de nuestro proyecto que vamos a testear, llamada test.
  2. Crear un nuevo proyecto (u obtenerlo del SVN) llamada MyProjectTest.
  3. Queremos meter el código dentro de la carpeta test antes creada, así que en MyProjectTest haremos clic en propiedades y en Build Path/Source/Link Source seleccionaremos la carpeta test.
  4. Añadir al proyecto el .jar de Android.
  5. Añadir al proyecto el .jar de Robolectric (¡con dependencias!).
  6. Añadir una nueva run configuration en Run/Run configurations, de forma que elijamos Eclipse JUnit launcher y en la pestaña Arguments seleccionaremos Other/Workspace y elegiremos la carpeta raíz del proyecto que queremos testear.

Ejemplo de uso para testear una Activity:

@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {
    private Activity activity;
    private Button pressMeButton;
    private TextView results;

    @Before
    public void setUp() throws Exception {
        activity = new MyActivity();
        activity.onCreate(null);
        pressMeButton = (Button) activity.findViewById(R.id.press_me_button);
        results = (TextView) activity.findViewById(R.id.results_text_view);
    }

    @Test
    public void shouldUpdateResultsWhenButtonIsClicked() throws Exception {
        pressMeButton.performClick();
        String resultsText = results.getText().toString();
        assertEquals("Testing Android Rocks!", resultsText);
    }
}

De momento, Robolectric es un proyecto joven (surgió en noviembre de 2010). Esperamos que esta herramienta mantenga una cierta continuidad, para que podamos obtener el máximo rendimiento a las prestaciones que nos ofrece.

Por ahora estamos experimentando las posibilidades que nos otorga, todavía nos queda por descubrir como crear nuestros propios objetos Cursor dentro de este entorno. Seguiremos informando…

Google App Engine: Lanzar un MapReduce desde un cron

Con las antiguas limitaciones del GAE, la ejecución de un proceso batch (generación de informes, actualización de una columna en todas las entidades de un tipo…) requería montar complejos sistemas diviendo nuestro proceso en pequeñas partes que serían procesadas por tareas enlazadas.

Desde hace poco (SDK 1.4.0.) el límite de tiempo para las peticiones en segundo plano (tareas y cron) aumentó:  ¡de 30 segundos a 10 minutos! , por lo que,  la mayoría de los procesos antes mencionados podrían ejecutarse sin mayor problema.

Sin embargo, cuando lo que necesitamos es recorrer todas las entidades de un modelo y actualizarlas/operar con ellas, mapreduce nos aporta algunas ventajas:

  • Comodidad a la hora de definir un nuevo script (mapreduce handler).
  • Eficiencia: mapreduce se ejecuta atutomáticamente con un número configurable de shards.
  • Escalabilidad infinita (aquí no tenemos la limitación de 10 minutos en caso de tener millones de entidades).

El problema es que los mapreduce están pensados para lanzarse manualmente desde la consola de administración de mapreduce (url_de_mi_aplicacion/mapreduce) pero en ocasiones nos gustaría poder lanzarlos programáticamente. Estudiando un poco el funcionamiento de esta consola y el código de mapreduce es sencillo modificarlo para conseguir nuestro propósito. Por ejemplo, lanzar un mapreduce desde un cron que se ejecute todos los lunes a la misma hora.

Lo primero es definir la entrada en nuestro cron.yaml, por ejemplo:

cron:
- description: purge tokens
 url: /admin/cron/execute_mapreduce
 schedule: every monday 00:00
 timezone: Europe/Madrid

Nosotros usamos Django, así que definiríamos una entrada en urls.py para mapear la url definida en el cron con nuestro método python encargado de llamar al mapreduce:

(r'^admin/cron/execute_mapreduce$', 'ruta_del_modulo.run_map_reduce'),

Y ahora viene la duda. ¿Cómo llamamos al mapreduce desde dicho método si sólo se puede a través de la consola? Esstudiando el comportamiento de la consola con una herramienta tipo firebug, vemos que cuando se pulsa en el botón “run” se ejecuta una llamada AJAX con una serie de parámetros. Si replicamos dicha llamada en nuestro código ya tenemos el mismo comportamiento.

Si  la definición de nuestro mapreduce (en el mapreduce.yaml) es ésta:

- name: execute_something_from_cron
 mapper:
 input_reader: mapreduce.input_readers.DatastoreInputReader
 handler: map_reduce_handlers.executed_from_cron.execute_something_from_cron
 params:
 - name: entity_kind
 default: points_of_sale.models.pos_model.PointOfSale

Entonces la llamada por código (en localhost) sería esta:

 form_fields = {
 "mapper_handler": "map_reduce_handlers.executed_from_cron.execute_something_from_cron",
 "mapper_input_reader": "mapreduce.input_readers.DatastoreInputReader",
 "mapper_params.entity_kind": "points_of_sale.models.pos_model.PointOfSale",
 "name": "calculate_aggregates_of_aggregates"
 }

 form_data = urllib.urlencode(form_fields)
 result = urlfetch.fetch(url="http://localhost:8080/mapreduce/command/start_job",
 payload=form_data,
 method=urlfetch.POST,
 headers={'Content-Type': 'application/x-www-form-urlencoded'},
 deadline=10)

Por último, para probar que todo funciona ya sólo queda ejecutar el cron. En local se puede hacer a través de la url:

http://localhost:8080/_ah/admin/cron

Pero cuidado, para poder ejecutarlo en local necesitamos un pequeño cambio. Lo normal es que mapreduce requiera permisos de administrador, lo cual, se indica en app.yaml:

- url: /mapreduce(/.*)?
 script: mapreduce/main.py
 login: admin  

Si ejecutamos el cron en la nube no hay problema porque tiene permisos de admin, sin embargo, el test local se ejecuta con permisos de usuario y, por ello, es necesario comentar la línea “login: admin” para las pruebas locales.

Ya parece que tenemos todos lo necesario, así que, lanzamos el test del cron desde el nagegador…obteniendo el siguiente resultado:

ApplicationError: 2 timed out

¿Por qué ocurre esto? La explicación se encuentra en el fichero base_handler.py de la libería mapreduce. Concretamente en el método _handle_wrapper:

def _handle_wrapper(self):
 if self.request.headers.get("X-Requested-With") != "XMLHttpRequest":
 logging.error(self.request.headers)
 logging.error("Got JSON request with no X-Requested-With header")
 self.response.set_status(
 403, message="Got JSON request with no X-Requested-With header")
 return

Como vemos, se están vetando explícitamente aquellas peticiones que no sean AJAX.

Afortunadamente, existe una solución muy fácil que evita cambiar el código de la librería mapreduce (sería peligroso porque en cualquier momento puede cambiar de versión o incorporarse por defecto sin necesidad de incluirla en el despliegue): se trata de añadir la cabecera XMLHttpRequest a nuestra petición:

headers={'Content-Type': 'application/x-www-form-urlencoded',
 'X-Requested-With': "XMLHttpRequest"},

Y ahora ya podemos ejecutar el mapreduce desde el cron y consultar la consola/logs cuando queramos ver su resultado. También se podrían lanzar peticiones (al igual que lo hace la consola) para comprobar que todo ha ido bien por código, pero eso ya es otra historia…

Segunda frogtek code kata

Como ya sabréis en Frogtek solemos realizar un TPV cada dos semana. En esta ocasión hemos decidido realizar nuestra segunda code kata con un ejercicio llamado Backwards Talk y que consiste en invertir un string. Por cambiar un poco con respecto a la primera sesión, hemos optado por realizarla en Python, salvo Guillermo que se ha atrevido con Javascript.

La solución de Javi Martínez nos ha parecido una de las más acertadas, haciendo uso de recursividad. En Frogtek solemos decir que los programadores que utilizan recursividad deberían llevar pajarita, ¿veremos mañana a Martínez con una?

def reverseString(str):
    if len(str) <= 0:
        return ''
    else:
        return reverseString(str[1:]) + str[0]

¿Comentarios? ¿Mejoras?

Herramientas: Resource filtering en Maven

Nuestro querido servidor de desarrollo es el encargado de generar las versiones de nuestros productos, los publica en la web, nos avisa por e-mail de que se han generado nuevas versiones, etc. Además se encarga de que desde el mismo código salgan dos versiones diferentes de la aplicación. La versión de producción, sólo para clientes finales, y la de pre-producción donde se prueban todas las funcionalidades antes de ser pasadas a producción.

Las diferencias entre ambas versiones son mínimas pero delicadas, así que hace tiempo programamos una serie de bash scripts que hacían los cambios automáticamente en Hudson. Nada elegante pero muy útil para evitar errores al subir archivos de configuración a nuestro sistema de control de versiones.

Hace unos días, a raíz de este post de Francho, Pedro pensó que igual podíamos mejorar dichos scripts para incluir ese proceso de definición en la propia aplicación. Nosotros no usamos Ant a nivel del servidor de integración continua, sino Maven. Me tocó desempolvar el recomendable libro que me dio a conocer Maven y me puse manos a la obra.

Así descubrí el Resource filtering, plugin de Maven que permite filtrar archivos y sustituir variables definidas en el pom.xml (archivo de configuración de Maven). A continuación os muestro lo sencillo que fue deshacerme de tres o cuatro scripts y pasar a definir dicho proceso desde el propio archivo de configuración de Maven.

Para ello en primer lugar se definen las variables.

...

   false
   UA-********
   http://*******/tiendatek/prebuilds/latest.apk
   frogtek

...

Seguir leyendo

Primera code kata en frogtek

Hoy hemos tenido la primera code kata. Jose ha preparado una magnifica sesión en la que hemos puesto el pomodoro a 25 minutos para elaborar una solución al problema del Fizz Buzz.

Hemos tenido soluciones muy elegantes, os paso esta por ejemplo de Alberto:

public class FizzBuzz {

	final static String FIZZ = "Fizz";
	final static String BUZZ = "Buzz";
	final static String FIZZBUZZ = "FizzBuzz";
	public static void main(String[] args) {
		for (int i=1; i<=100; i++) {
			System.out.println(getFizzBuzz(i));
			
		}
	}
	
	public static String getFizzBuzz (int number) {
		if (number % 15 ==0){
			return FIZZBUZZ;
		} else if (number % 3 ==0){
			return FIZZ;
		} else if (number % 5 ==0){
			return BUZZ;
		} else {
			return Integer.toString(number);
		}
	}

}

¿Algún comentario? ¿Mejora?

Hemos decidido hacerla en Java, la próxima irá en python y alguien por ahí ha dicho que en LISP.

¿Qué IDE usas?

Hoy en frogtek vamos a tener nuestra primera kata organizada por Jose. Ayer mientras nos enviaba información acerca de las webs que había visitado para prepararla, pensé en el IDE y de qué manera un developer se siente cómodo al usarlo.

Yo desde hace un tiempo llevo usando NetBeans para desarrollar en Android y GAE, me cansé de la inestabilidad y lentitud de Eclipse cuando tratas con varios proyectos grandes.

Esto también me hizo pensar acerca de la ayudas que un IDE proporciona a un programador, como por ejemplo:

  • Completar métodos.
  • Compilación inmediata.
  • Sugerencias de corrección de errores.

Todas estas ayudas que en principio están diseñadas para hacernos la vida más fácil y aumentar la rapidez de desarrollo, pueden convertirse en un lastre en cuanto a eficiencia se refiere y una frustración diaria. Todo esto relacionado con que debemos tender a “Go Mouseless”, para aumentar nuestra productividad, me hace pensar que cada día deberíamos bajar un escalón en la abstracción e intentar obviar las ayudas en busca de más rendimiento. También creo que estas ayudas a la larga hacen perder un poco la visión global de proyectos grandes.

Me gustaría saber cuáles son vuestros IDE’s mas usados y vuestras configuraciones.

Frogtek Kanban Boards

En Frogtek tenemos dos tablas de kanban distintas en paralelo, una para los Product Owners y otra para el equipo de Tecnología. Primero nació la de Tecnología, como una manera fácil y visual de controlar el trabajo, lo que queda pendiente, lo que está ya acabado o lo que está siendo programado en este momento. El proceso de desarrollo es lo suficientemente “complicado” (tampoco mucho) como para que sean necesarias varias columnas, pero ¿por qué necesitamos también una tabla de kanban para el proceso de diseño de una user story por parte de los Product Owners?. Principalmente, y esto es lo único que voy a contar al respecto antes de centrarme en la tabla de Tecnología, porque el proceso de definición de user stories se ha ido complicando conforme añadíamos técnicas como el Usability Testing y demás y ahora requiere de varias iteraciones antes de que una user story quede archivada y por lo tanto disponible para ir al Backlog de Tecnología, es decir, a la fase de producción.

La tabla virtual de los Product Owners.

Moraleja: las tablas de Kanban son muy útiles incluso si lo que quieres organizar son las tareas del hogar, no es algo reservado a programadores o ingenieros.

La tabla virtual de tecnología.

Nuestra tabla real de tecnología (ver foto abajo) tiene una fila por proyecto y 6 columnas de las cuales forman parte del proceso estrictamente 4, las dos de los extremos no son más que los recipientes de donde salen las user stories y en donde acaban al final.

La tabla real de Tecnología

Son las siguientes:

  1. Backlog: aquí el Product Owner almacena las user stories que ya han pasado por todo el proceso de diseño (en la otra tabla) y están listas para ser empezadas cuando lo considere necesario, es una especie de almacén (los programadores no miran mucho dentro). También almacenamos bugs que cualquiera detecta y que no son muy urgentes, de esta forma el Product Owner puede evaluarlos, descartarlos o priorizarlos según su criterio.
  2. Development – User Interface: de alimentar esta columna se encargan tanto el Product Owner como la diseñadora gráfica. La idea es la siguiente, cuando una user story del backlog está lista (es decir, tiene una descripción exhaustiva y una lista de tests de aceptación) si requiere antes de su programación de la creación de recursos gráficos (iconos, imágenes…) entonces es la diseñadora gráfica la que la arrastra a esta columna (a la parte izquierda) y no la coloca en la derecha (que indica que la user story está lista para pasar a la siguiente fase) hasta que no ha creado todos los recursos y los ha adjuntado para que los usen los programadores. Si la user story, por el contrario, no necesita nada gráfico el Product Owner la mueve directamente a la parte derecha de la columna en espera de que un desarrollador la escoja. Sea como fuere, en este punto todas las user stories tendrán una descripción detallada, una lista de test de aceptación y si lo requiere ciertos archivos adjuntos con los recursos gráficos necesarios. En esta columna también aparecen de vez en cuando bugs urgentes (aquellos que alguien detecta y que hay que resolver enseguida).
  3. Development – Code: Esta columna es responsabilidad de los programadores, cuando uno de ellos se libera acude a la columna Development – User Interface y toma la user story que esté más arriba de entre las de la parte de la derecha. La user story (el post-it en realidad) se mueve a la parte izquierda de esta tercera columna y quedará allí hasta que el programador considere que ha terminado su trabajo. ¿Y eso que quiere decir?. Pues hasta que ha probado, en un entorno lo más real posible, que lo que ha programado cumple todos y cada uno de los test de aceptación diseñados por el Product Owner (amén de los tests unitarios propios y ajenos entre otras cosas). Entonces hace “commit” (o comitea en castellano antiguo) y cruza los dedos para que todo funcione y no haya “momento cerdito” (en ese momento la build se compila en el servidor y los test unitarios se ejecutan, así como los funcionales y los aleatorios… así que es como para echarse a temblar, lo del cerdito lo explicaremos en otro post dentro de poco). Si todo va bien es momento de mover la user story a la parte derecha de la columna donde esperará a que otro desarrollador inicie el proceso de revisión. Por cierto, IMPORTANTE,  esta columna es la única a la que aplicamos WIP (limitación del Work In Progress) y normalmente lo limitamos al número de programadores en el proyecto menos uno. De esta forma no podemos tener dentro de la columna más user stories que programadores en el proyecto menos uno. Lo que hace que, a veces, cuando alguien acaba su tarea se vea obligado a revisar alguna de las user stories que otros hayan acabado para vaciar la columna o a hacer pair programming.
  4. Quality – Review: el proceso de revisión es doble, primero por parte de un desarrollador, que no haya participado en la programación de la user story, y luego por parte de nuestro responsable de QA, Julio. Consiste en utilizando la herramienta Review Board revisar que todo el código y ver que el código es consistente en estilo y con un diseño eficiente. Si hay algún tipo de comentario, el programador original deberá modificar el código y volver a pasar pruebas manuales y automáticas. Al final del proceso y si todo va bien la user story acaba en la parte derecha de la columna esperando a que el responsable de calidad la testee.
  5. Quality – Test: ya estamos llegando al final del proceso. Aquí es donde las cosas se ponen más interesantes ya que Julio se dedica a comprobar que todos y cada uno de los test de aceptación definidos por los Product Owners se han satisfecho. Si encuentra algún error, la user story vuelve directamente a la columna 3 (Development – Code) y el momento cerdito es acogido con regocijo por toda la oficina (menos aquel a quien se le aplica). Esto es un poco como esas casillas del juego de la oca que te mandaban 20 casillas atrás… hay que volver a empezar y arreglar lo que no funciona. Cuando los tests se pasan correctamente la user story se deja en la parte derecha de la columna esperando a que el Product Owner que es quien debe dar al final el visto bueno la archive definitivamente.
  6. Archive: cuando una user story está en la parte derecha de la columna Quality Test es señal de que el trabajo está listo para que el Product Owner lo pruebe. Si comprueba que todos los tests de aceptación se pasan directamente puede mover la tarea a esta sexta columna donde quedará para siempre. Si hay algún error entonces la tarea vuelve a la tercera columna, todo vuelve a comenzar y el “momento cerdito” planea sobre nuestro querido Tester.

Algunos comentarios:

No diferenciamos entre user stories y bugs, salvo por el color del post-its, eso es importante. Los tratamos igual. Un bug normalmente no tendrá test de aceptación, archivos gráficos adjuntos pero si una descripción detallada. Cuando los errores se identifican durante la fase de testeo, no se genera un bug, sino que se rechaza la user story. Si se detectan después, sí y, en ese caso, su destino será: el backlog si no son urgentes, la parte derecha de la columna de Dev – User Interface si lo son o la parte izquierda de la columna de Dev – Code si son críticos. El triaje lo realiza normalmente o el responsable de QA, el Kanban Master o el Product Owner si está disponible (nótese la diferencia horaria, 6-7 horas, entre POs y programadores).

¿Cómo es posible que el tester pueda testear “instantáneamente” cada una de las user stories tras el commit?. Gracias al sistema de integración continua del que ya hemos hablado en varios posts. Cada commit genera una nueva versión de pre-producción que nos sirve para testear lo último que se ha terminado. No hay más que seleccionar buscar actualizaciones en nuestra aplicación y el “upgrade” es automático.

En los pantallazos correspondientes a nuestra tabla virtual (que en el fondo es la oficial, porque es la única que compartimos toda la empresa) no hay lado derecho o izquierdo de las columnas. Simplemente cuando una user story está lista le ponemos un reborde verde.

Si os fijáis en las imágenes que hemos adjuntado la tabla real no tiene columna “Archive” esto es así porque realmente hemos encontrado una utilidad mucho mejor para las user stories (los post-its) terminadas que coger polvo o ir a la caja de reciclar. Lo contaremos en nuestro próximo capítulo junto con lo del “momento cerdito”.

Automatización

Gracias a la costumbre en Frogtek de fomentar la formación a través de la compra libros, he podido leer “The Pragmatic Programmer” magnífico libro recomendable para cualquier programdor con ganas de mejorar.

En el mismo dan un par de consejos que me han parecido muy interesantes y que aparte de estar muy ligados, creo que seguimos bastante aquí en Frogtek. El primero:

Use the power of command shells

Indica que debemos usar los comandos shell como herramientas para facilitar nuestro trabajo. Por ejemplo en mi caso utilizo scripts shell para eliminar nuestro software del emulador y cargar la última versión de nuestro servidor, consiguiendo con un solo comando algo que si hiciera a través de la interfaz me llevaría el doble o el triple de tiempo. El segundo:

Don’t use manual procedures

Nos dice que no hagamos de forma manual nada que pueda hacer un script o programa. Será más propenso a errores y dará más quebraderos de cabeza a la hora de ser repetido en diferentes entornos. En este caso el ejemplo es nuestro proceso de paso a producción a través de Hudson, la compilación de todos los proyectos y paso de test, etc.

En resumidas cuentas automatización, todo lo que sea susceptible de ser automático debería serlo. Será más rápido, más confiable y menos propenso a errores. No tengas miedo al coste de configuración, si lo vas ha hacer más de dos veces, vale la pena automatizar. Vamos o eso nos dice la experiencia en Frogtek …

Waterfall vs SCRUM vs Kanban (II)

[Leer Waterfall vs SCRUM vs Kanban (I)]

Fue así como descubrimos SCRUM, una metodología ágil que implementa de una u otra manera los 4 principios fundamentales del Agile Manifesto, a saber:

  1. Que aunque los procesos y las herramientas son importantes, lo son más los individuos y sus interacciones.
  2. Que aunque la documentación exhaustiva está muy bien, es mucho mejor tener prototipos que funcionan.
  3. Que aunque negociar un contrato con el cliente es vital, es mejor aún que el cliente se involucre contigo en el proyecto.
  4. Y que aunque saber seguir un plan es una estupenda habilidad, más importante es saber cambiar dicho plan a tiempo.

SCRUM define distintos roles para las distintas personas que participan en un proyecto, no voy a entrar en detalles ya que existe multitud de literatura al respecto. Simplemente saber que existe el rol de Product Owner (en adelante PO) que es la persona que, en estrecho contacto con el cliente, define las pequeñas piezas de funcionalidad que se le van añadiendo poco a poco al producto. También se define el rol del Team (equipo de desarrolladores) que son los programadores de la cosa y el del SCRUM Master, que viene a ser el encargado de que todo el proceso que define SCRUM, el ritual periódico por el que hay que pasar inexorablemente, se lleve a la práctica como Dios manda. ¿Ritual?, ¿qué ritual?. Pues principalmente uno muy sencillo, el que sigue:

  • Como nos resulta imposible saber con antelación qué es lo que quiere el cliente dividimos el tiempo en pequeños periodos (Sprints, típicamente de entre 2 y 4 semanas) sobre los que creemos tener suficiente visibilidad. Es decir, “no tengo ni idea de cómo va a evolucionar mi producto dentro de 6 meses pero sí creo saber que mi cliente quiere ver tales características funcionando dentro de 2 semanas”… Esto tiene que ver con los puntos 3 y 4 del Manifiesto Ágil (involucrar al cliente y gestionar el cambio).
  • El PO, por lo tanto, estudia con el cliente la funcionalidad que les gustaría tener disponible en la próxima versión de la aplicación. Y luego participa en la reunión de planificación de principio de Sprint en la que, junto con el Equipo de Desarrollo, se clarifica qué hay que hacer y se decide quién hará qué y cuánto tiempo costará. Punto 1, sobre las personas y las interacciones.
  • Durante todo el Sprint el Equipo de Desarrollo lleva a cabo reuniones diarias para intercambiar información. De nuevo reforzando el punto 1 del Manifiesto.
  • Cuando se acaba el Sprint se hace una reunión de Revisión y Demo en la que el PO muestra al cliente, o los desarrolladores al PO (depende) la nueva versión del producto con las mejoras de las últimas dos semanas ya listas. Punto 2, mejor un prototipo que un infumable tocho de documentación obsoleta.
  • El ritual termina con la reunión de Retrospectiva, donde el Equipo de Desarrollo junto con SCRUM Master y POs revisan el proceso y proponen mejoras para el siguiente Sprint.

Y vuelta a empezar. Hay normas extras, peculiaridades, cosas divertidas y complicaciones sobre las que se podría profundizar mucho, pero básicamente esto es SCRUM.

En nuestro caso la cosa empezó bastante “de andar por casa”. El PO era PO y SCRUM Master a la vez, los programadores no hacían Stand-ups… Cowboy-SCRUM como bien dice Pablo. Pero bueno, la intención es lo que cuenta, durante un tiempo al menos.

Con la nueva oficina la cosa mejoró, al menos el equipo técnico ya se veía las caras. Stand-ups, Sprint Plannings, Sprint Reviews, Sprint Retrospectives… toda una plétora de reuniones salpicaba nuestro calendario. Mucha diversión mientras a la vez tratábamos de montar un entorno de desarrollo decente con pre-producción, producción, repositorios de código, branches… la juerga padre vamos. El típico momento en el que a los novatos emprendedores les empiezan a crecer los enanos y se dan cuenta de que ser profesional es difícil, muy difícil y complejo, muy complejo.

Lo que veis más arriba era nuestro día a día por aquellos tiempos. Habíamos conseguido ya tener un proceso automático que compilaba todos los días a las 15:00 CET (a primera hora de la mañana de nuestros POs en USA y Colombia) una versión de preproducción. Al final del Sprint sacábamos dos versiones de producción, una el viernes después del Review del jueves y otra el domingo con las US (User Stories, pequeños fragmentos de funcionalidad) que nuestro programador exiliado en Santiago de Compostela hacía los fines de semana. Resultado: habíamos dado nuestro primer paso hacia un concepto que desconocíamos, la Integración Continua… y nos salían bugs por todos lados. Fue por eso que empezamos también a interesarnos por cosas como el TDD y las pruebas unitarias automáticas y nos empezáramos a preocupar de que la frase “pues en mi emulador funciona” se oyera cada vez menos.

En lo que respecta a SCRUM dimos un paso de adelante contratando el servicio AgileBuddy una página web que te permite gestionar distintos proyectos con sus respectivos Backlogs (el conjunto de funcionalidades a programar), los Sprint Backlogs (cosas a programar durante el Sprint), etc, etc. Se trata de una útil herramienta para gestionar tus proyectos usando esta metodología. Lo mejor, que te dota de un marco de trabajo donde tienes todo mucho más controlado y que te calcula automáticamente las métricas de tus proyectos (Burndown chart y demás). Lo peor, que a veces no es fácil entender la forma que tienen estas herramientas de calcular sus métricas y también que quizá entraba en demasiado detalle y era necesario desglosar tareas, imputar horas de forma no siempre tan fácil o intuitiva como nos gustaría.

No fue AgileBuddy, no obstante, la razón por la apenas 4 meses después decidimos cambiar al Kanban. ¿Cambiamos por las razones adecuadas?, ¿fue un cambio precipitado?, ¿estábamos haciendo suficientemente bien SCRUM?… Todo eso y mucho más, en el próximo capítulo.

Eficiencia en Google App Engine: Appstats

Nuestra elección a la hora de subir datos a la nube fue Google App Engine, el servicio que permite ejecutar aplicaciones web en la infraestructura de Google. El desarrollo  en esta plataforma presenta ciertas características que obligan a cambiar el chip desde un primer momento y que nos fuerzan implícitamente a tener en cuenta la eficiencia y, sobretodo, la escalabilidad. Dicho esto, siempre hay momentos a lo largo del camino en los que uno se plantea revisar la eficiencia global de la aplicación para mejorar su tiempo de respuesta, reducir los consumos de cpu y, de paso, reducir la factura cobrada por Google.

La primera vez que nos enfrentamos a esta situación decidimos usar cProfile y pstats para estudiar los tiempos de nuestro código Python centrándonos en aspectos clásicos como optimización de búsquedas, mejora de la eficiencia en la manera de concatenar cadenas, reducción del número de iteraciones en un bucle…la verdad es que de poco nos sirvió, ya que, veíamos que la mayor parte del tiempo de proceso se gastaba en algo que en el profile se indicaba con líneas como esta:

_apphosting_runtime___python__apiproxy.Wait

Es decir, que la mayor parte del tiempo nuestra aplicación estaba esperando a que se completase el proceso realizado por una llamada a alguna API de Google.

Estudiando en detalle el lugar del código en el que aparecen estas líneas, se puede averiguar a qué API se están refiriendo pero, por suerte, todo ese trabajo dejó de ser necesario gracias al descubrimiento de Appstats:

Appstats es una herramienta creada por  Guido van Rossum (creador de Python y actual empleado de Google) que forma parte del SDK y nos permite ver en detalle en qué emplea realmente el tiempo nuestra aplicación mediante el estudio de las RPC, es decir, las llamadas remotas que nuestra aplicación hace a las distintas API’s de Google. Su instalación es muy sencilla y podemos instalarla incluso en producción porque consume muy pocos recursos.

En  el siguiente video, el propio Guido, nos explica las bondades de esta herramienta indispensable:

En el video se muestra cómo instalar y usar la herramienta, una breve explicación de su funcionamiento y consumo, posibilidades de configuración y algunos ejemplos de uso como, por ejemplo, detección de ciertos patrones de ineficiencia comunes a muchas aplicaciones : Patterns of Doom!

Antiguas entradas Recientes entradas