viernes, junio 04, 2010

Consejos y sugerencias para tu primer iteración

Empezar a trabajar por iteraciones puede ser un cambio muy grande (¡y que asusta!) cuando llevamos mucho tiempo desarrollando con otros métodos. Scrum dice cómo llevar adelante el proceso, pero a muy alto nivel. En este artículo, Jared Richardson comparte varios consejos para un equipo que recién comienza a formarse en Scrum, y está a punto de empezar su primera iteración.

No sobre-analicen todo. No importa si no saben exactamente cuánto les va a llevar hacer algo, o cómo van a escribir pruebas unitarias perfectas, o cómo van a manejar los datos para las pruebas X, Y, Z. Simplemente, empiecen a hacer. Tomen una serie de tareas pequeñas y empiecen. Lo mejor de tener iteraciones cortas es que tienen la próxima semana van a poder cambiar sus expectativas!

No se vuelvan locos pensando quién será el Scrum Master. De hecho, hagan que este rol rote en todo el equipo. Al principio, cada miembro del equipo tiene que ser Scrum Master por una iteración antes de volver a ser Scrum Master por segunda vez.

Aprendan la votación con cinco dedos. El equipo entero vota cualquier sugerencia que alguien hace. Un dedo significa que odio esa sugerencia y no puedo aceptarla. Cinco dedos significa que me encanta totalmente. Los dedos en medio reflejan distintos niveles de aceptación. Tres dedos muestran que nos resulta indiferente. Buscamos soluciones que junten respuesta de "Me encanta" o "Puedo aceptarlo". Ninguna de las sugerencias son permanentes; en cambio, usaremos experimentos de entre una y tres iteraciones. Siéntanse libres de probar cosas nuevas, y dejar que otros prueben cosas nuevas. No va a durar por siempre, y los buenos equipos eliminan las prácticas que no funcionan.

Tengan reuniones diarias cortas. El Scrum Master las lidera. Usen algún token sencilla (una lapicera, una pelotita) que se pasa entre los miembros. Si lo tienen, pueden hablar. Sino el resto del equipo puede callarnos por no hablar en nuestro turno (¡y hasta puede resultar divertido!). Debemos asegurarnos que cada persona responda las 3 preguntas: ¿Qué hiciste ayer? ¿Qué vas a hacer hoy? ¿Qué problemas tenés?

Usar integración continua para la compilación (¡como mínimo!). Si no tienen builds automáticos, o un servidor de integración continua, usen una "iteración cero" para configurar esta infraestructura. No dejen de hacerlo, los beneficios para el equipo son enormes y es una de los pasos más importantes.

Sólo trabajen en requerimientos estimados rápidamente entre uno y tres días. ¿Tienen una tarea de 6 semanas? Hay que dividirla en piezas más manejables.

Armen un equipo con desarrolladores y testers. Trabajen de a pares cuando escriban pruebas (¡ambos!). Los desarrolladores van a aprender a escribir mejores pruebas, y también los testers.

Tengan una reunión de planificación. El Dueño del Producto, el líder del producto (o quien cumpla con este rol) trae suficiente trabajo para una o dos iteraciones. Rechacen una tarjeta cuando no se pueden poner de acuerdo sobre qué significa la característica, o cómo se prueba que dicha característica. Hagan que el Dueño del Producto tenga la idea más en claro y traiga la tarjeta en una iteración futura.

Todo el trabajo se realiza tiene que realizarse con dos pares de ojos. Pueden lograrlo trabajando de a pares, o con revisiones de compañeros, pero nadie trabaja solo. Esto es tanto para la calidad de código como para compartir el conocimiento (por cierto, si piensan que sus compañeros no son lo suficientemente inteligentes para "entender" nuestro trabajo, el problema es nuestro. Siempre es nuestro. No sean ese tipo de desarrollador).

Agenden una demostración para mostrarle a los demás lo que hicieron durante la iteración. Es una oportunidad para mostrarnos, y dejar que otras partes de la empresa sepan lo que viene.

Por último, relájense. Los miembros del equipo que se viven preocupando con "¿Y qué pasaría si...? ¿Y qué pasa con...? ¿¿Y eso otro?? ¡¡¡Y que vamos a hacer si ocurre aquello!!!"... estos miembros son los que terminan haciendo menos. Simplemente empiecen a trabajar con equipo, y ajusten las iteraciones. Estoy seguro que no sólo lo van a encontrar muy productivo, sino sumamente divertido.

Fuente

lunes, mayo 17, 2010

Cumplir con la retrospectiva

Si alguna vez trataron de cambiar algún hábito personal (como comerse las uñas, por ejemplo) saben que es virtualmente imposible de lograrlo a menos que tengan algo para reemplazar el hábito viejo. Es más fácil adoptar un comportamiento nuevo que extinguir uno viejo. Lo mismo ocurre para los equipos en las organizaciones.

En su retrospectiva, el equipo de Lynn decidió dejar de empezar a codificar sin tener un plan. Pero en la siguiente reunión de planificación de la iteración, dos miembros del equipo abrieron sus notebooks para compartir código en el que habían trabajado durante el fin de semana. Creían que le estaban dando una ventaja al equipo.

Lynn les recordó a todos el acuerdo y compartió varias ideas para planificar que había leído en grupos de discusión Ágiles. El equipo acordó actuar de acuerdo a lo decidido y probar las ideas de Lynn para la planificación. A medida que el equipo empezó a hablar sobre el trabajo que debía hacerse, el equipo se dió cuenta que el código escrito durante el fin de semana no contribuía al objetivo de la iteración - fue un esfuerzo en vano.

Sin un reemplazo (como estas ideas para planificar), el equipo no tuvo más alternativa que caer en su comportamiento anterior.

Todos los comportamientos nuevos resultan extraños al principio. Las personas desarrollan tranquilidad con la práctica - sea tanto al aprender un nuevo saque de tenis como aprender a escribir código en un nuevo lenguaje. Debemos brindar apoyo y recordar que está bien cometer errores mientras se aprenden nuevas habilidades.

Brindar apoyo

El trabajo de provocar un cambio no termina con el cierre de la retrospectiva. Incluso los cambios más pequeños necesitan ser cuidados y apoyados. El apoyo proviene de diferentes formas: refuerzos, empatía, oportunidades de aprendizaje, oportunidades de práctica, y recordatorios. Algunos tipos de apoyo provienen del equipo (como la empatía y los recordatorios). Otros requieren de recursos y presupuesto externos. Los líderes de equipos, coaches y gerentes tienen la responsabilidad de obtener el apoyo que requiera de gastos.

Refuerzos

El cambio es difícil. Debemos apoyar al equipo (y a nosotros mismos) haciendo notar el avance. Demos frases de aliento sobre lo que estamos haciendo bien.

Debemos brindar información sobre lo que va bien para que el equipo pueda ver que están avanzando. Demos feedback que describa el comportamiento y destaque el impacto: "Noté que ayer no nos fuimos de tema en la reunión diaria. Acordamos sólo responder las preguntas del scrum diario, y eso hicimos. Nos ayudó a ver cuáles eran los obstáculos".

Empatía

Es válido que las personas sientan frustración o pérdida por el cambio. Veamos como Fred manejó mal la situación cuando un miembro del equipo le habló sobre los cambios. Fred escuchó a Katie explicar cómo se sentía sobre tener que dejar su cubículo personal cuando el equipo se ubicó en un espacio abierto. "Estuve pensando lo que me contaste", le dijo Fred, "y no hay ningún motivo para que te sientas así". ¡Eso no es empatía! Debemos respetar los puntos de vista de las otras personas, aunque no los compartamos. A veces un simple "Te escucho" es suficiente.

Oportunidades de aprendizaje

Debemos apoyar la exploración y el aprendizaje, y demostrarlo. Es posible que el equipo necesite aprender nuevas habilidades para tener éxito en los experimentos que eligieron para su plan de acción. Se pueden organizar almuerzos y sesiones para que los miembros aprendan entre ellos. Se pueden dar listas de recursos web y artículos para que el equipo investigue ideas nuevas. La programación de a pares ayuda a aprender nuevos lenguajes y técnicas. Y se puede hacer todo esto sin un presupuesto.

También debemos estar dispuestos en gastar dinero para apoyar un cambio. No todas las habilidades se pueden aprender desde un sitio web o leyendo un artículo. Invirtamos en capacitación para construir las bases de nuevas habilidades. Armemos una biblioteca de referencia para que el equipo pueda consultarla.

Oportunidades de práctica

Las personas necesitan practicar para ganar experiencia. Una forma es dejar al equipo con el proyecto para que prueben algo nuevo. Otra opción es crear un espacio formal de práctica usando algún proyecto pequeño, un área de práctica, o un programa tipo Hola Mundo.

Los proyectos cortos -uno que dure dos días, o incluso menos- sirven para explorar posibles soluciones y probar métodos nuevos. El límite de tiempo en los proyectos cortos crea un punto de verificación explícito en donde el equipo puede comprobar su aprendizaje y las decisiones en el experimento.

Las áreas de práctica son un lugar donde el equipo puede cosas nuevas sin afectar al producto real. Un área de práctica puede ser un área especial de desarrollo o prueba que no se utiliza para el desarrollo actual del producto.

Alentemos a que el equipo prueba programas del tipo Hola Mundo. Los programas Hola Mundo son muy simples (en general sólo muestran el mensaje "Hola, Mundo"), pero sirven para probar entornos de desarrollo, configuraciones y encontrar problemas rápido (o confirmar que algún concepto básico funciona).

Recordatorios

Los tableros grandes y visibles y los check-in son recordatorios que ayudan a que el equipo se enfoque en los cambios. Por ejemplo, el equipo de Terry decidió que necesitaban realizar refactors más seguido. Crearon un tablero grande donde cada miembro agregaba un punto verde cuando terminaban una tarea de refactor. Al final de cada día, revisaban el gráfico y discutían los resultados.

Un check-in le permite al equipo informar lo que están haciendo con un cambio en particular. Debemos mantener preguntas y respuestas cortas: "En una o dos palabras, ¿cómo estamos con las estimaciones?". Las respuestas nos pueden ayudar a saber cómo está avanzando el cambio.

Fuente

viernes, mayo 07, 2010

¿Inteligente o Tonto?

¿Cuál es la diferencia entre ser inteligente o ser tonto? Creo que podría resumirse en dos cosas: qué tan lejos en el futuro podés pensar, y qué tan rápido podés generar este pensamiento. Cuando alguien juega ajedrez, o poker, sus habilidades están determinadas por cuántas movidas puede pensar por adelantado. Cuánta historia pueden recordar, y así planificar el siguiente movimiento.

En el desarrollo de software, ¿qué tan lejos podés mirar? ¿Estás usando prácticas destructivas porque estás muy ocupado "terminando el trabajo"? ¿Estás ignorando buenas prácticas que podrían ahorrarte tiempo?

Podemos relacionarlo con armar un camino que atraviese un bosque. Estás trabajando muy, muy duro. Todos en el equipo están transpirando, astillándose las manos, todo el tiempo. No se puede cuestionar la lealtad ni dedicación de nadie.

Pero...

¿Cuándo fue la última vez que detuviste esta tala de árboles metafórica, te subiste a un árbol... o miraste el mapa... o afilaste el hacha? El problema con la mayoría de los equipos de software que talan árboles en el bosque es que no comprueban si el camino que están armando está dirigido hacia la ciudad correspondiente. No comprueban si es un camino recto. No analizan si podrían comprar algunas sierras eléctricas para reemplazar a las hachas obsoletas que vienen usando.

Por supuesto que esto también puede abusarse. No queremos pasar todo el día en el negocio buscando herramientas nuevas, pero de vez en cuando necesitamos mirar los alrededores, ver si seguimos en línea recta. Debemos asegurarnos de estar usando las herramientas correctas para el trabajo. Comprobar si siguen afiladas las hojas.

Les dejo algunas sugerencias como herramientas para asegurarnos que seguimos en el camino correcto.

  • Integración Continua. Hay muchas herramientas de Integración Continua que ayudan muchísimo al equipo. Hace que el equipo siga escribiendo código en vez de arreglar compilaciones, mantiene limpio al producto, y encuentra problemas rápido.
  • Demos frecuentes. Tanto si son internas o para el cliente, estas demostraciones públicas ayudan a entender lo que estamos haciendo, y nos sugiere correciones al curso. Si estamos cortando el camino en la dirección incorrecta, ¿cuánto tiempo queremos seguir perdiendo? Debemos mostrar lo que hacemos, y averiguar lo que piensan lo antes posible.
  • Iteraciones de duración fija. Las iteraciones acotadas brindan una forma más efectiva de enfocar los esfuerzos y asegurarse de estar construyendo el software adecuado.
  • Pruebas automatizadas. Cuando codificamos nuestro conocimiento del producto en una prueba automatizada (que se ejecuta en un servidor de integración continua), se hace imposible que alguien del equipo rompa el código sin que se descubra rápidamente.
  • Pruebas guiadas por los defectos. ¿Encontraste un bug? Agregá una prueba. Siempre. Esta perspectiva extreme a la automatización de pruebas nos brinda cobertura justo en donde era necesaria. También, no agregues una sola prueba... buscá armar escenarios derivados de la situación.
  • Desarrollo guiado por pruebas. Escribir una prueba antes de escribir el código productivo hace que surja un código completamente diferente. Es más pequeño, más enfocado y (¡sorpresa!) está probado. TDD es un camino de ida... ¡probalo!
  • Reuniones diarias de parado. Estas reuniones diarias y breves hacen que todos hablen y se vean la cara, todos los días. Se responden 3 preguntas que ayudan a compartir información. ¿Cuántos equipos conocen que no se hablan a diario?
Fuente

jueves, abril 22, 2010

Integración Continua para mantener el proyecto en rumbo

Hoy en día tenemos muchas herramientas que dicen limpiar de forma mágica nuestro código. Mueven, modifican, emprolijan y mágicamente resuelven todos nuestros problemas. Lamentablemente, como la mayoría ya sabe, escribir buen código lleva trabajo. No existen herramientas mágicas que puedan salvarnos (y no importa lo que nos digan los vendedores), pero si hay una herramienta que funciona muy bien para ayudarnos a mantenernos en forma.

La Integración Continua es una idea bien simple. Configuramos un programa que mire el código fuente. Cuando alguien hace algún cambio, el sistema de Integración Continua lo compila de inmediato. Si la compilación pasa, se ejecutan las pruebas automatizadas. Por último, se publican los resultados.

Simple, ¿no? ¿Por qué es tan poderoso?

La Integración Continua es como una tarjeta de crédito al revés. Una tarjeta de crédito nos permite comprar algo grande hoy, y pagarlo de a poquito más adelante. Sin embargo, las tarjetas de crédito tienen un pequeño secretito oscuro... el interés compuesto. Terminamos pagando mucho, mucho más de lo que tomamos prestado. Siempre resulta más barato pagar en efectivo si podemos.

Cuando usamos un sistema de Integración Continua, ocurre lo opuesto. Podemos hacer pequeños pagos todos los días, o podemos esperar hasta el final y hacer un único gran pago. ¡Desafortunadamente este último gran pago tiene todo el interés compuesto agregado! Si esperamos al final, terminamos pagando más... mucho más!

Esto ocurre por el "tiempo a oscuras" entre que un desarrollador escribe el código y lo combina con el código que escribió el resto del equipo. Si combinamos el código todos los días, o incluso un par de veces a la semana, los cambios son menores y relativamente indoloros. Pero si esperamos...

Si esperamos, los cambios crecen. Mientras más esperamos, más código escribimos. Y más código escribe el resto del equipo. Al terminar el mes, cuando nos vemos forzados a combinar y unir todos esos cambios, las colisiones son gigantes. Los desarrolladores trabajan en los mismos archivos, a veces en las mismas líneas... otras veces hay funcionalidad en la que un desarrallador dependía y ahora hay otro desarrollador que la cambió (quiero decir, "mejoró"). Y los cambios mutuamente excluyentes generan caos.

Durante este tiempo entre escribir el código y hacer la combinación, compilación y testeo con el código de los demás, es cuando no podemos ver lo que está pasando. ¿Nuestros cambios entran en conflicto con los de alguien más? ¿Alguien cambió algo que necesitamos? No podemos verlo todavía... estamos a oscuras. Y vamos a seguir a oscuras hasta que unamos el código.

Una herramienta de Integración Continua ayuda los desarrolladores a aprender el ritmo de "escribir una cosa, subirla al repositorio". Esto funciona mucho mejor que "escribir una cosa... y otra... y otra... y otra...", y después "dedicar horas y días a combinar el código". ¡Y ni siquiera empezamos a ahblar de los beneficios de ejecutar las pruebas automatizadas después de subir cada cambio!

Tenemos que encontrar los problemas lo más rápido posible, cuando todavía los arreglos son menores. ¡Es el mejor momento para arreglar los problemas!

Algunos productos de Integración Continua para empezar

Fuente: DosIdeas

miércoles, abril 21, 2010

Crear amor, no dinero

Algunas personas de negocios siguen una estrategia que no se enseña en las escuelas de negocios: la mejor forma de maximizar las ganancias es dejar de pensar en maximizar las ganancias y, en cambio, enfocarse en tratar bien a las personas. Es decir, la mejor forma de hacer dinero es enfocarse en amar a las personas.

Joel Spolsky ya lo dijo: "Las mejores condiciones de trabajo -> Los mejores programadores -> El mejor software -> ¡Ganancia!".

Tony Hsieh lo dice de esta forma: "La Cultura es nuestra prioridad número uno... Creemos que si generamos la cultura correcta, entonces muchas otras cosas como construir una marca van a ocurrir de forma natural por si mismas".

Quisiera distinguir esta visión de dos perspectivas similares: la primera es el estilo del colectivismo hippie de los '60, en el cual el capitalismo es malvado porque es inherentemente manipulativo, que el trabajo y el capital deberían beneficiar a todos los miembros de la organización, y que, en realidad, el dinero es una molestia y lo que importa es el amor. En contraste, la perspectiva de Crear amor, no dinero no dice que el dinero sea una molestia o cómo debería organizarse el capital. Tampoco quiere decir que sea inconsistente con el punto de vista hippie.

La segunda perspectiva proviene del mantra tradicional de Scrum: "El objetivo del equipo es maximizar el valor de negocio entregando software que funciona". Bajo la mirada de Crear amor, no dinero se podría re-escribir: "El objetivo de un equipo es optimizar su entorno de trabajo y, como efecto secundario beneficioso, va a incremental radicalmente el valor de negocio que se entrega". Es un hallazgo empírico que optimizar el entorno de trabajo suele llevar a incrementos significativos en los resultados financieros. Resulta consistente con el sentido común pero no necesarimante deriva de la premisa "optimizar el entorno de trabajo".

Una buena pregunta: ¿Por qué no hacen esto quienes maximizar las ganancias? El gerente típico medio, cuando se le pide que aumente las ganancias, responde despidiendo trabajadores o ahorrando en material de la oficina - no creando un gran entorno de trabajo. No sé porqué. Sospecho que tiene que ver con las limitaciones cognitivas de las personas. Nos resulta muy dificil comprender el enésimo efecto de nuestras acciones. Es mucho más simple comprar sillas baratas para lograrlo - cualquier otra cosa es más complicada.

Si se adoptara, quienes maximizan los beneficios podrían ver a la perspectiva de Crear amor, no dinero como una herramienta cognitiva que ayuda a tomar mejores decisiones, al igual que un coach de ajedrez enseña a desarrollar las piezas (en vez de pedirle que haga mate al rey).

En resumen: enfocarse en crear grandes ambientes de trabajo, y obtendremos gratis las ganancias extraordinarias.

Fuente: DosIdeas

lunes, abril 05, 2010

Lista de comprobación para hacer TDD

El Desarrollo Guiado por Pruebas (o TDD) se suele describir como un ciclo de rojo-verde-refactor, que se repite continuamente, para ir agregando nuevas características o arreglar bugs. La siguiente lista de comprobación que comparte Giorgio Sironi contiene un grupo de preguntas que deberíamos hacernos a nosotros mismos mientras avanzamos por las fases de TDD, para no olvidarnos de la esencia de esta técnica.

Rojo

El desarrollo de cualquier característica nueva tiene que empezar con una prueba que falla.

  • ¿Subiste el código al repositorio remoto o local? Si el código se rompe, es más fácil revertir los cambios que re-escribir.
  • ¿Ya escribiste código productivo? Si lo hiciste, comentalo o, mejor todavía, eliminalo para no estar atado implícitamente a un API mientras escribís la prueba.
  • ¿Elegiste la unidad apropiada para expandir? La clase modificada debería ser una que siga teniendo cohesión luego del cambio, y a menudo se deberían agregar claes nuevas en vez de acomodar la funcionalidad en las existentes.
  • ¿Falla la prueba? Si no, re-escribila para exponer la falta de funcionalidad.
  • ¿Una parte de la prueba ya falla? Si es así, eliminá el restante de la prueba; el resto lo podés agregar en métodos diferentes.
  • ¿El nombre del método de prueba describe su propósito? Asegurate de no atarte a detalles de implementación.
  • ¿Los mensajes de fallas son descriptivos sobre el problema? Asegurate que describan en dónde está fallando la funcionalidad, destacando la ubicación si se rompiera en el futuro.
  • ¿Los números y strings mágicos están expresados dentro de constantes? ¿Hay código repetido? El refactor del código de pruebas es más fácil cuando se hace tempranamente y mientras aún falla, ya que en este paradigma es más importante hacer que siga fallando que hacer que pase.

Verde

Se debe escribir el código productivo necesario para que la prueba pase.

  • ¿El código productivo hace pasar a la prueba? (así de simple)
  • ¿Hay un subconjunto del código productivo que hace pasar a la prueba? Si es así, comentá, o mejor todavía, eliminá el código productivo innecesario. Cualquier otra línea de código que escribas no tendrá cobertura, y serán líneas sin pruebas que deberemos leer y mantener en el futuro.
  • Cualquier otra acción específica será llevada a cabo en la fase de Refactor.

Refactor

Mejorar la estructura del código para facilitar los cambios futuros y el mantenimiento.

  • ¿Existe código repetido en la clase actual?
  • ¿El nombre de la clase es el apropiado?
  • ¿Los métodos públicos y protegidos tienen un nombre descriptivo? ¿Son legibles? El refactor de renombrado es uno de los más poderosos.
  • ¿Hay código repetido en diferentes clases? ¿Existe un concepto de dominio que está faltando? Podemos extraer hacia clases abstractas o hacer un refactor de composición. Este alto nivel de refactor también debería aplicarse a las clases de pruebas unitarias.
Fuente: DosIdeas

jueves, marzo 18, 2010

NoSQL y varias alternativas a las bases de datos

Hace un tiempo cubrimos la inauguración de la comunidad NoSQL, un movimiento para pensar alternativas a las bases de datos relacionales que tan acostumbrados nos tienen. En este artículo, Debasish Ghosh reflexiona sobre el futuro del movimiento y las diferentes alternativas que tenemos hoy en día.

Hoy en día somos testigos de muchas noticias alrededor de NoSQL. Llámese NoSQL (~SQL) o NOSQL (Not Only SQL - No solo SQL), el movimiento tiene una misión. No todas las aplicaciones necesitan almacenar y procesar datos de la misma manera, y por lo tanto la arquitectura de almacenamiento debería pensarse de forma acorde. Hasta hoy estuvimos forzados a usar el mismo martillo para pegarle a todos los clavos. Sin importar cómo procesáramos los datos de nuestra aplicación, los solemos almacenar como filas y columnas en bases de datos relacionales.

Cuando estamos tratando con grandes aplicaciones de escritura escalables, las bases relacionales apestan. La normalización de datos, los joins, y las transacciones ACID son anti-patrones para la escritura escalable. Quizás piensen que el sharding solucione los problemas, dividiendo los datos en porciones más pequeñas. En realidad, el mayor problema del sharding es que las bases de datos relacionales nunca fueron diseñadas para eso. El sharding quita muchos de los beneficios de las bases relacionales. El sharding no puede ser "algo para pensar después", ya que se entromete en la lógica del negocio de la aplicación, y hacer joins de múltiples shards puede resultar un esfuerzo no trivial. Mientras podamos escalar de forma vertical nuestro modelo de datos aumentando la capacidad del hardware, seguramente sea la opción más sana para adoptar. Pero según Moore... incluso aunque podamos escalar verticalmente, traten de migrar una base MySQL realmente grande. Les va a llevar horas, quizás días. Este es uno de los motivos por los cuales algunas empresas están migrando a bases de datos sin esquemas, cuando las aplicaciones así lo permiten.

Y si para escalar horizontalmente sacrificamos la normalización, los joins y las transacciones ACID, ¿por qué usar motores de bases de datos relacionales? No se necesitan... Digg está migrando de MySQL hacia Cassandra. Todo depende de la aplicación y del tipo de escalabilidad de escrituras que necesitemos lograr para procesar los datos. Para escalar la lectura, podemos usar esclavos de sólo-lectura que replican todo lo que llega a la base de datos maestra en tiempo real, y configurar un proxy inteligente entre los clientes y la base de datos.

El mayor entusiasmo que creó el movimiento NoSQL es por los enfoques divergentes que prometen cada uno de sus productos. Y esto es muy diferente al movimiento de motores de bases de datos relacionales, que comenzó como un único martillo llamado SQL que es capaz de manipular filas y columnas de tipos de datos sobre la teoría matemática de un conjunto de operaciones. Y cada aplicación adoptó la misma arquitectura de almacenamiento sin portar de cómo procesara los datos dentro de la aplicación. Una cosa llevó a la otra, las personas creyeron poder resolver el problema con otra capa de indirección... y así apareció esa cosa extraña llamada Mapeador Objeto-Relacional (ORM).

Finalmente, con el boom del procesamiento de datos en la Web, nos dimos cuenta que no todos los datos se procesan igual. El almacenamiento que funcionó tan bien para las aplicaciones de escritorio tradicionales, fracasa estrepitosamente con las aplicaciones sociales donde se necesitan procesar datos enlazados, que tienen la forma de grafos. La comunidad NoSQL respondió con Neo4J, una base de datos de grafos que brinda almacenamiento sencillo y recorrido de estructuras de grafos.

Si quieren escalar a lo grande la escritura, la única forma es la descentralización y la consistencia eventual. Aparece el teorema de CAP, en donde necesitamos comprometer la consistencia, la disponibilidad o la tolerancia a la partición de la red (elijan uno). Riak y Cassandra ofrecen almacenamiento descentralizado de datos que pueden escalar indefinidamente en la teoría. Si tu aplicación necesita más estructura que una base de datos clave-valor, pueden optar por Cassandra, el sistema de almacenamiento orientado a columnas, distribuido y peer-to-peer. Pueden mirar este artículo de Digg donde se compara su casos de uso entre el almacenamiento relacional y el almacenamiento por columnas que ofrece Cassandra. Si quieren una base de datos orientada a documentos con todos los beneficios de REST y JSON, prueben Riak. Riak también ofrece Map/Reduce enlazado con la opción de almacenar elementos enlazados de datos, muy parecido a la forma en que funciona la web. Riak realmente es un sistema de almacenamiento con la forma de la web.

CouchDB ofrece otra interesante propuesta para el ecosistema de NoSQL. La mayoría de las aplicaciones son básicamente offline y necesitan facilidades de replicación transparentes. CouchDB usa una estructura de almacenamiento de Árbol-B, operaciones de sólo agregado con un control de concurrencia basado en el modelo MVCC, operaciones sin bloqueos, API REST y operaciones incrementales Map/Reduce. Chris Anderson, uno de los desarrolladores líderes de CouchDB, resume el valor de CouchDB en el mundo web de hoy:

Las aplicaciones CouchApps son el producto de un navegador HTML5 y una instancia CouchDB. La ventaja clave es la portabilidad, basada en la plataforma HTML5. Las características como los Web Workers y el XHR cross-domain hacen una diferencia enorme en la arquitectura de la web. La disponibilidad en todas las plataformas es clave para el futuro de la web.

Al igual que CouchDB, MongoDB también ofrece almacenamiento de documentos. No brinda soporte REST, pero se basa en un almacenamiento JSON. También tiene Map/Reduce, y ofrece un poderoso conjunto de APIs de consulta muy parecido a SQL. Este es un punto clave de MongoDB, que le resulta muy cómodo a personas que tienen conocimientos de SQL. MongoDB también ofrece replicación maestro-esclavo, y están trabajando en escalabilidad basada en autosharding y en tolerancia a fallos.

Hay varios más sistemas de almacenamientos que ofrecen soluciones a problemas de todos los días. Caché, consumidores de colas que requieren operaciones push/pop atómicas, procesamiento de flujos de actividad, log de datos, etc. Redis y Tokyo Cabinet funcionan bien para estos casos. Redis es como caché en memoria con una base de datos persistente de clave-valor. Es un único hilo, utiliza IO no-bloqueante y es súper rápido. Redis, además de ofrece almacenamiento de clave-valor, también ofrece la posibilidad de almacenar listas y colecciones con operaciones atómicas.

Otro aspecto interesante es la interoperabilidad entre los sistemas de almacenamiento. Riak, por ejemplo, ofrece la posibilidad de usar distintos backends para los datos - podríamos usar CouchDB como backend para Riak. Posiblemente también veamos un backend Cassandra para Neo4J. Sin dudas es interesante ver como estas comunidades tienen este sentido de cooperaciones para hacer que todo el ecosistema sea más útil y crezca más.

Original: DosIdeas

jueves, febrero 25, 2010

Reportar Errores o Escribir Puebas Unitarias

Los sistemas de gestión de errores (o "bug trackers") son cuellos de botella, y perpetúan el continuo idea y vuelta entre testers y desarrolladores, además de requerir de mucha documentación para mantenerlos.

Alberto Gutierrez comparte una interesante reflexión sobre cómo crear el mejor sistema de gestión de errores: ¡dejar de reportar errores y empezar a escribir pruebas automatizadas!

El ciclo de vida estándar de un bug es más o menos así: un tester de QA encuentra un error en la aplicación, crea un nuevo reporte de bug en el bug tracker y se lo envia al desarrollador, quien a su vez, ni bien soluciona el bug, lo envia de vuelta al tester, quien a su vez notifica al dueño del producto y luego cierra el bug.

En la teoría este proceso suena bien, pero tiene varias desventajas:

  • Problemas de comunicación. A veces la descripción del bug es pobre, o el desarrollador malinterpreta el problema.
  • Pruebas de regresión. El proceso requiere de idas y vueltas de código entre desarrollo y QA, lo que ocasiona problemas de versionado y duplica el esfuerzo de testing.
  • No es robusto. El proceso no garantiza que el error no vuelva a aparecer en el futuro.
  • Burocracia. Los sistemas de bug tracking tradicionales cambian el foco de la calidad a la burocracia.

La solución a estos problemas es bastante simple. Cuando alguien encuentra un bug, inmediatamente escribe una prueba automatizada que falla sobre el bug descubierto. Este mecanismo tiene varias ventajas:

  • Desaparecen los problemas de versionado, todos trabajan en el head del código.
  • Se garantiza que el bug no vuelva a aparecer sin ser detectado.
  • Se elimina la ambigüedad sobre cuál es el bug exactamente.
  • Se elimina burocracia.
  • Consolida las actividades de desarrollo en un único lugar, el código.

Obviamente también hay desafíos a superar para cambiar a este proceso en donde no se necesita de un bug tracker:

  • Se necesita un sistema de construcción automatizado. La construcción del proyecto tiene que estar corriendo todas las pruebas automatizadas, de manera que cuando se agregue una nueva prueba por un bug, la construcción falle y el equipo de desarrollo pueda decidir corregir el error en el momento, o ignorarlo por un tiempo (de esta manera sabremos que todas las pruebas ignoradas son bugs sin arreglar).
  • Se necesita cooperación. Los desarrolladores y los testers tienen que trabajar juntos para crear las nuevas pruebas ni bien aparezca un bug. Se necesita tener testers con habilidades de programación.
  • Se necesita disciplina. Los equipos tienen que entender que se debe crear una prueba por cada bug encontrado, sin excepción. Y cada vez que se rompe la construcción, la prioridad es solucionarlo.
  • Se necesita organización. Las prueban tienen que crearse con criterio y usando alguna nomenclatura en común.

En resumen, en mi opinión el futuro de la gestión de errores es eliminar los bugs trackers tradicionales y toda la burocracia. Para lograr esto hay varios desafíos; si tienen las habilidades, las herramientas y el equipo para superar estos desafíos, podrían pensar seriamente en deshacerse del viejo sistema de gestión de errores.

Fuente: DosIdeas

viernes, enero 22, 2010

10 motivos para amar el test ágil

Recientemente, Kay Johansen hizo la pregunta "¿Por qué te gusta probar ágil?". Las respuestas varian desde desde las más serias a las más relajadas.
  • Tener la oportunidad realmente de impactar en la calidad y no sólo documentarla! (Juan Overbaugh) - cuando los defectos son corregidos de inmediato en lugar de ponerlos en una pila de defectos.
  • No más pruebas manuales de los scripts! En cambio, los scripts serán ejecutados automáticamente, proporcionando más tiempo para que el tester realice las pruebas de exploración.
  • Los desarrolladores realmente gustan de esto! - Localizar los problemas antes de la final de la interacción cuando el código está fresco en la mente de los desarrolladores, les ayuda a encontrar el problema.
  • Ahora puede comprobar los recursos antes de que sean escritos! (Kay y Philip) - El tester puede evitar problemas al iniciar la prueba antes que los recursos se definan.
  • Los resultados de las pruebas automatizadas se pueden ver muchas veces al día, proporcionando una rápida retroalimentación después de cualquier cambio.
  • El ambiente está muy orientado al equipo (Juan Overbaugh) - Cada miembro del equipo se preocupa de terminar las pruebas y no sólo el código (Lisa Crispin).
  • El tester puede ocasionalmente ajustar el defecto (Lisa Crispin) - Cada miembro del equipo se siente más cómodo ya que la prueba está automatizada.
  • Ofrece la oportunidad de revisar constantemente las prácticas de pruebas (Adam Knight) - En lugar de simplemente repetir lo que se ha hecho anteriormente, las prácticas son constante revisadas. En el caso de Adam las pruebas que acostumbraban tomar 5 días para ejecutarse manualmente se han reducido ahora a 30 minutos.
  • He pasado mucho menos tiempo en depuración (Adrian Howard) - tengo el feedback prácticamente al mismo tiempo que se ha cometido un error, por lo tanto, suele ser trivial localizar y corregir.
  • Siempre existe tiempo para probar porque la prueba se realiza primero - Josué Barbosa dos Santos contó la historia de trabajar en una oficina del gobierno en Brasil, donde la práctica era probar al final del proyecto. El desarrollo siempre estaba atrasado en el calendario del proyecto y terminaba siendo liberado a los usuarios sin pruebas. Con la introducción de TDD y ATDD las pruebas se ejecutaban mientras que el software era desarrollado.

El número uno para Kay de los motivos de amar la prueba ágil: es que puedo escuchar gente diciendo "este es el mejor proyecto que he trabajado en mi vida!"

Fuente: DosIdeas

5 consejos para construir software sin defectos

Lamentablemente, en algunas organizaciones todavía se considera al testing como la última etapa del proceso de desarrollo. Los desarrolladores entonces cruzan los dedos para programar todo lo más perfecto posible, de manera que la etapa de testing sea una formalidad donde a lo sumo se encuentren errores menores. Por suerte ya hace un tiempo que nos estamos alejando de esta utopía ridícula y vamos avanzando hacia un concepto en donde el testing es una parte integrada al proceso de desarrollo.

El artículo How to write good tests nos deja 5 consejos para aprovechar al máximo este nuevo enfoque.

  1. El código de test es tan importante como el código productivo. Uno de los problemas más comunes al empezar con TDD es que el código de test no es limpio ni tan prolijo como el productivo, de manera que eventualmente cuesta mucho mantenerlo. Para evitar este escenario es importante que el código de test sea tan prolijo como el productivo.
  2. Probar lo más posible, lo antes posible, lo más seguido posible. Es importante no avanzar en el código productivo hasta tener una prueba que verifique que el código escrito funcione como esperamos. Este enfoque logrará que nuestro sistema tenga menos defectos, y además nos dará mayor seguridad a futuro para implementar cambios.
  3. Probar en distintos niveles. No hay que ahogarnos con pruebas de integración que son muy dificil de escribir y lentas para ejecutar (y que, de última, no llegan a cubrir todos los elementos de la aplicación). El mejor enfoque es usar pruebas en distintos niveles. Por ejemplo:
    • Pruebas unitarias, que comprueban los componentes de forma aislada al resto.
    • Pruebas de aceptación, que son creadas por el Dueño del Producto y representan la funcionalidad mínima que tiene que tener la aplicación para poder aceptarse desde la perspectiva del negocio.
    • Pruebas de integración, que no son identificadas por el Dueño del Producto pero las desarrolla QA o el equipo de desarrollo como complemento.
    • Pruebas de interfaz de usuario. Son lentas y además cambian mucho, por lo que hay que mantenerlas separadas del resto de las pruebas.
  4. Integración continua. Las pruebas tienen que ser una parte fundamental e integral del proceso de desarrollo, que ocurren en cada instante del proceso. Todos son responsables por las pruebas, desde el desarrollador hasta QA y el Dueño del Producto. Las herramientas de integración continua nos ayudan enormemente a llevar adelante este desafio.
  5. Usar herramientas y frameworks de testing. No hay que reinventar la rueda, ni trabajar como en la edad de piedra. Tenemos muchas herramientas y frameworks de software libre que nos permiten implementar una estrategia seria de testing.
    • Fitnesse, una herramienta para crear pruebas de aceptación, de forma que personas no-técnicas puedan escribir sus propios escenarios.
    • xUnit, un framework para desarrollar pruebas unitarias, que se integra con todos los IDE de desarrollo en distintos lenguajes de programación.
    • Bugzilla, una herramienta para reportar bugs y hacer su seguimiento.
    • Selenium, una herramienta para crear pruebas automatizadas de interfaces de usuario web.
    • Hudson, una herramienta de integración continua que se usa para asegurar que el código siempre esté funcionando correctamente y pase todas las pruebas.
Fuente: DosIdeas