RSS

¿Y si jugamos a que hacemos software?

lunes 30 de noviembre de 2009

 

Desde hace un tiempo, estoy dando una mirada de vez en cuando a una revista online sobre metodologías ágiles en portugués. Visão Ágil, como tarea hogareña del curso portugués que estoy haciendo, y con la intención de leer un poco sobre este tema (como dice la poco ecológica metáfora: matar dos pájaros de un tiro).

 

La técnica del Tomate

En el blog de esta revista encontré recientemente un artículo sobre la “Técnica Pomodoro” de Manoel Pimentel. La Técnica Pomodoro se utiliza para la administración personal del tiempo, y está inspirada en ideas de las metodologías ágiles, como TimeBoxing y el uso de herramientas de “baja tecnología”, puntualmente: papel, lápiz y un timer de cocina.

 

 

tomato_timer1 paper-pencil

Estos timers con forma de tomate (pomodoro en italiano) son los que dan nombre a la técnica

 

Si bien ese artículo tiene un mindmap que resume muy bien los puntos clave, lo que más destacaría es la simplicidad, el énfasis en mantener el foco, y la asignación rígida de tiempos (véase TimeBoxing) tanto a las tareas como a los intervalos de descanso entre éstas.

 

Con respecto a este último punto, el libro oficial que puede descargarse de http://www.pomodorotechnique.com destaca la importancia de estos intervalos para “asimilar lo aprendido y hacer algo bueno por tu salud”, como caminar, ejercicios de respiración o contar un chiste. Interrumpir este período de descanso con cualquier tarea que implique un esfuerzo mental, “bloqueara el constructivo proceso mental de integración necesario para estar alerta y listo para el proximo ciclo”. Una especie de build de integración que se ejecuta periódicamente en background en nuestro cerebro.

 

El último que se escondió arma el release!

Sin embargo lo que quería mencionar en este artículo (y por eso el título), es algo que me parece muy valioso y puede pasar desapercibido a primera vista. Es el espíritu lúdico que hay detrás de esta técnica (vi este punto escrito en el mindmap del artículo de Pimentel).

Una idea que tambien está implícita en varias técnicas utilizadas en metodologías ágiles.

 

Creo que en esta manera de encarar el trabajo (y cualquier otra cosa) hay mucho más jugo de lo que se cree habitualmente. Especialmente en ambientes que promueven la productividad y la creatividad.

No hay que confundirlo con una forma de hacer apología de la competencia (que casi nunca es sana), o de esquivar el bulto a las tareas tediosas. Se trata más bien de evitar que nuestro trabajo sea una letárgica marcha atrás de la recompensa monetaria de fin de mes (Dispositivo del burro y la zanahoria),

 

burro_zanahoria

 

para empezar a disfrutar del día a día, transformándolo en un juego constructivo, hasta casi “sentir que no trabajamos”.

burrojugando 

Sin duda el tema, da para mucho más que este artículo (y para autores más calificados!) pero la intención era traer a colación el tema, y tratar de poner en evidencia, o preguntar, ¿Cuántas cosas hacemos (o podemos hacer) en este sentido?

"La columna del medio"

viernes 13 de noviembre de 2009

Aportando dinámica a la pizarra

En nuestro equipo de trabajo contamos con los ambientes de desarrollo (pruebas de unidad) y de QA (pruebas de integración).

Desde hace tiempo venimos aplicando prácticas de SCRUM. Con el uso de la pizarra notamos la necesidad de diferenciar las tareas cuyo desarrollo se encontraba en progreso de aquellas terminadas y a la espera de un pasaje al ambiente de QA.

Esto era debido a que cada vez que terminábamos una tarea la pasábamos a la columna de “Test”, ocasionando muchas veces confusiones ya que no teníamos manera de saber si las tareas que se encontraban en esta columna estaban contempladas dentro del último build.

Durante un tiempo intentamos hacer el pasaje de papelitos solamente cuando hacíamos el build al ambiente QA, pero para eso contábamos con nuestra memoria para saber que tareas estaban completas, lo que no siempre resultaba con éxito por que… seamos sinceros… esta no siempre nos era fiel =)

Entonces un día, durante la retrospectiva de uno de nuestros proyectos tuvimos la siguiente maravillosa idea para arribar a una solución:

Agregar una columna intermedia entre DESA (In progress) y QA (Test) que nos permitiera saber, de forma inmediata, cuáles eran las tareas que estaban listas pero que todavía no estaban disponibles para ser probadas en QA…

¿Como funciona?

Cada vez que el desarrollador termina alguna tarea, mueve el papelito correspondiente de “In Progress” a la columna “DESA/TEST”(la columna del medio) indicando de esta manera que el desarrollo ha finalizado y estará disponible en el próximo build para su prueba.

Si bien debo reconocer que en un principio tuve mis dudas acerca de si la nueva columna iba a servir de algo, el uso de la misma nos demostró gran efectividad.

Su implementación acarreó las siguientes mejoras:

  • Nos permitió tener una noción más precisa del avance del sprint, rompiendo con la sensación de un “avance estático” generado por la acumulación de tareas en la columna de desarrollo.
  • Da una idea más clara al desarrollador de qué tareas le falta completar y cuáles completó.
  • Brinda al tester la certeza de saber qué estará para probar.
  • Es mucho más fácil decidir en qué momento hacer un pasaje de ambiente.

Resultado final

La pizarra 

Conclusiones

Por nuestra experiencia, la incorporación de esta nueva columna trae grandes beneficios a la dinámica del equipo, agilizando la comunicación. Los invitamos a probar esta alternativa y que compartan con nosotros sus experiencias.

Sobre Ratas, Elefantes y TimeBoxing

miércoles 8 de julio de 2009

La semana pasada nos dispusimos a realizar un cronograma de entregas para las próximas semanas de uno de nuestros proyectos, así que me reuní con el resto del grupo involucrado, y empezamos una planificación, haciendo una revisión rápida de las historias de usuario prioritarias en nuestro backlog.

Acto seguido, ubicaríamos estas historias de usuario según sus “tamaños” , prioridades y dependencias, en hipotéticos sprints, manteniendo presente el concepto de TimeBoxing.

La bolsa de Gatos

La lista resultó ser bastante extensa, y estimar el esfuerzo requerido por cada ítem, se volvía un poco confuso. Eran demasiado heterogéneas (lo que comúnmente llamamos bolsa de gatos).

Era necesario dividir un poco las aguas y separar cosas como “cambiar el color de fondo del campo X” de “diseñar un generador de fusión en frío”.

Creo que lo más peligroso de esto es que camufladas en medio de la estampida de historias de usuario más pequeñas, podían pasar desapercibidas las más pesadas o de más difícil estimación.

Una metodología de planificación para toda la familia

Normalmente utilizamos para estimar el esfuerzo requerido de cada historia de usuario, cartas de Planning Poker (gracias a Mountain Goat) al comienzo de cada sprint, sin embargo esta planificación prolongada requería de una primera clasificación grosera.

Fue así que con el ánimo de innovar un poco y de hacer la reunión un poco más divertida inventamos (y ofrecemos sin patente alguna) un método de planificación que podría llamarse “El Arca de Noé”.

Es importante que participen todos los miembros del equipo (funcionales, desarrolladores, líder de proyecto, etc. con sus diferentes visiones) y consiste básicamente en 2 etapas:

1. Clasificación

En esta etapa se toma cada una de las historias de usuario, y luego de una breve descripción, y discusión sobre sus implicancias (aquí típicamente es el momento de que un desarrollador advierta sobre dificultades posibles, o calle para siempre :)). se procede a su clasificación.

Las tareas se ubicarán en 3 grandes categorías de acuerdo al esfuerzo que representa la tarea, para hacerlo más entretenido decidimos identificar estas categorías con especies animales:

  1. Rata: Con este nombre identificamos historias de usuario más rápidas de resolver y que no requieren casi ningún análisis sobre la forma de implementarlas. Típicamente cambios estéticos, cambios de configuración, pseudo-duplicar un componente ya existente, etc.
  2. Perro: En esta categoría van tareas que implican un cierto análisis y/o un trabajo más cuidadoso o extenso que las anteriores.
  3. Elefante: Finalmente elefantes son las historias de usuario más pesadas, generalmente requieren un esfuerzo de diseño, o hay muchas dudas sobre la forma implementarlo, o implica un riesgo díficil de estimar.

MouseElephant


Finalmente es importante entender que tanto el número de categorías (3), como los criterios para ubicar un historia de usuario en cada categoría, son parámetros que deben ajustarse con el tiempo a las particularidades de cada equipo.

2. Planificación

En esta etapa al igual que Noé con su Arca, es dónde tenemos que acomodar estos animales (o historias de usuario) en compartimientos finitos (o sprints).

Advertencia: Si la cantidad de sprints es limitada, es posible que algunas historias de usuario se pierdan en el diluvio universal.

Para esto tenemos que sopesar diferentes criterios:

  • Historias prioritarias para el cliente
  • Dependencias entre éstas
  • Recursos disponibles
  • Imprevisibilidad o riesgo de una tarea (generalmente es preferible comenzar estas tareas lo antes posible para en caso de necesidad ajustar el rumbo a tiempo)

y otros que puedan ser particulares del proyecto.

Aquí es dónde se aplican todas las metodologías de planificación que normalmente utilizamos.

Por supuesto que la medida de cuántos “elefantes” entran en cada sprint, además de depender de los recursos disponibles en ese sprint, es algo que los miembros del equipo irán refinando con el paso del tiempo.

El Resultado:

DSC01439_rr

Conclusiones

Antes de empezar a dibujar Gantts, Cronogramas o un Análisis de Riesgo, se hace necesario hacer una primera pasada que identifique las historias de usuario clave. Esta variante simple resulta bastante divertida, lo cual en una larga planificación nunca está demás.

Eso sí, una consecuencia inmediata y un poco vergonzosa, son expresiones del tipo; “Yo 2 elefantes en esta semana no me puedo comer, mejor empiezo agarro un elefante y voy intercalando con algunas ratitas” o “Me parece que nos estás vendiendo perro por rata”

Quién se anima a compartir otras variantes de este tipo?

Como excluir archivos de configuración de Source Control

lunes 16 de febrero de 2009

Una pregunta que alguien se podría hacer al leer este artículo, es ¿porque voy a querer quitar los archivos de configuración del repositorio de código fuente?

El objetivo de los Repositorios de Código es justamente ese, resguardar el código, los archivos de configuración son necesarios al ejecutar la aplicación, y muchas veces al compilarla, tal es el caso del web.config, por este motivo necesitamos que sean parte del proyecto, pero tenerlos en el repositorio de código fuente nos puede traer algunos problemas.

Uno de los inconvenientes ocurre en los procesos de Deployment, ya que los archivos de configuración, ente otras cosas, almacenan información referida al ambiente donde corre la aplicación:

  • Desarrollo
  • Qa
  • Producción
  • etc
y el repositorio almacena versiones del código, independientemente de los ambientes en donde se instale.

En este sentido excluirlos, nos obliga a hacer un manejo especial con ellos en los diferentes pasajes de ambiente, que nos puede evitar errores. Por otro lado mientras estamos desarrollando, es bastante común hacer pruebas modificando los archivos de configuración, pruebas que nunca vamos a querer subir al repositorio de código (Ej.: apuntar la configuración a una Base de Datos local), si tenemos los archivos en el repositorio, es necesario hacer CECK OUT, para luego hacer UNDO PENDING CHANGES al finalizar la prueba. Esto, mas allá de ser una tarea tediosa para el desarrollador, es problemática si son muchos los que están trabajando al mismo tiempo.

Veamos cómo hacerlo

En este caso vamos a hacer un ejemplo utilizando como Repositorio de Código Fuente a Team Fundation Server.

En este ejemplo, voy a abrir la solución correspondiente al Sitio corporativo de Tercer Planeta http://www.tercerplaneta.com/
, para excluir al web.config, cabe aclarar que esto se puede aplicar también, en una aplicación WinForms, excluyendo el app.config.

Al abrir la solución vemos la siguiente estructura de carpetas y archivos desde Solution Explorer de Visual Studio 2008.

El primer paso consta de hacer una copia del web.config, para luego renombrarlo como web.config.template. Este témplate nos sirve para almacenar la configuración que requiere la aplicación, en el también podríamos identificar de alguna manera, que cosas vamos a tener que modificar, cada vez que la aplicación se encuentre en un ambiente diferente.

Para esto nos paramos sobre el archivo web.config en el Solution Explorer, hacemos una copia del mismo y lo renombramos como lo dijimos anteriormente.


Luego de subir los cambios, pasamos a excluir el web.config de Source Control.

Para ello, seleccionando el web.config desde el Solution Explorer, debemos ir al punto de menú File / Source Control /Exclude web.config from Source Control como se ve a continuación.

Este último paso hace CHECK OUT del proyecto para marcar al web.config como archivo excluido.

Luego de guardar los cambios debemos eliminar definitivamente al web.config de Source Control, para esto en la solapa Source Control Explorer de Visual Studio 2008, debemos pararnos sobre el archivo web.config y hacer Click Derecho / Delete.

Si en este punto miramos la columna Pending Change, de la solapa Source Control Explorer vamos a ver que marca el archivo web.config como Delete y además hace cambios sobre los archivos del proyecto.

Como solo queremos quitarlo de Source Control y no del proyecto, lo que tenemos que hacer es desde el Source Control Explorer, deshacer los cambios sobre los archivos del proyecto.

Para eso los seleccionamos y hacemos UNDO PENDING CHANGES como se muestra a continuación.

Luego hacemos CHECK IN sobre el web.config , para podes borrarlo definitivamente.

Estos últimos dos pasos, hacen que el web.config desaparezca del árbol de Source Control, pero no lo excluye del proyecto web.

Si ahora observamos nuevamente el Solution Explorer vamos a ver que el web.config sigue apareciendo en la lista de archivos, pero ahora con dos iconos.

El icono rojo indica que el archivo está excluido de Source Control, mientras que el icono amarillo nos dice que no lo tenemos actualmente en el disco local.

El último paso consta de ir a nuestro disco local, hacer una copia del témplate que generamos en los pasos anteriores, y renombrarla como web.config, de esta manera en el Solution Explorer solo veríamos el icono rojo.

A partir de este momento el web.config, está localmente y nunca se va a pisar cuando hagamos Get Latest Version. Es importante aplicar los cambios al Témplate cuando se necesite hacer un cambio en el web.config, y avisar de esto al resto del equipo, para que lo actualice localmente.

De esta manera, cada puesto de trabajo pasa a tener su copia del web.config, que el desarrollador puede modificar cuando quiera, evitando hacer CHECK-OUT cada vez. Por otro lado, cada ambiente donde se instale la aplicación va a tener que tener su propio web.config, la forma de obtenerlo en este caso dependerá del mecanismo que utilicemos como publicación.

Drag and Drop en WinForms

viernes 5 de septiembre de 2008

Hace unos días durante un curso de capacitación un cliente nos comentó que necesitaban implementar una grilla cuyas filas fueran reordenables mediante "drag and drop" (es decir arrastrando y soltando) y vergonzosamente tuvimos que reconocer que apenas teníamos una (muy vaga) idea teórica de como implementarlo.

A la semana siguiente con la intención de dar un respuesta un poco más sólida, dediqué unos minutos a leer un poco y dado que resultaba fácil, armé una pequeña demo para probar el uso de Drag and Drop en WinForms.

Demo

El código puede descargarse de aquí.

En el ejemplo hay un simple DataGridView al cual se puede arrastrar un archivo Xml, cuyo formato sea "convertible" a DataSet, con lo cual la tabla (la primera si hay más de una) se muestra en la grilla (en el ejemplo incluí un Items.xml que sirve a tal fin).

Una vez que tengo filas en la grilla, puedo arrastrar filas con el mouse para modificando el orden.

Esto muestra como realizar Drag n Drop, desde una aplicación externa (Explorador de Windows por ejemplo) hacia un control WinForms propio, y como hacerlo desde y hacia la misma aplicación.

Paso a Paso
  • Lo primero que necesitamos es iniciar el "arrastre", y una forma posible es en el evento MouseMove del control de origen, para esto agregue en el código de este evento una llamada al método "DoDragDrop" (cuando el botón izquierdo está presionado, etc.), al cual se le debe pasar como argumentos el objeto a arrastrar (en mi caso el DataGridViewRow que se esta arrastrando), que simplemente sirve como información para el control de destino, y la acción deseada, por ej. "Move".
  • Con esto ya podemos tomar una fila y llevarla por toda la pantalla, sin embargo todavía nadie acepta nuestro "DataGridViewRow", con la cual el cursor muestra el conocido símbolo de prohibido.
  • Lo que necesitamos ahora es que nuestra grilla diga "Vienes con un DataGridViewRow? Puedes soltarlo aquí!", lo que hace que el cursor se transforme en uno más amigable indicando la acción permitida.
  • Para esto hay que agregar código en el evento "DragOver", en este una vez que me aseguro que el objeto arrastrado es una DataGridViewRow, perteneciente a mi misma grilla, informo mediante un argumento del evento "DragOver" que la acción permitida es (como fue solicitado) "Move".
  • Finalmente tengo que hacerlo cuando el objeto es soltado, esto ocurre en el evento "DragDrop", en el cual verifico nuevamente que estoy recibiendo una DataGridViewRow de mi propia grilla, y realizo finalmente el movimiento de filas (lo cual dependerá de la fuente de datos de la grilla (DataTable, DataView, List, etc.).

De forma similar en DragOver y DragDrop espero un objeto con formato "FileName" (el cual nos envía el Windows Explorer) para aceptar archivos .xml sobre la grilla. Lo cual muestra que el origen y destino pueden estar en aplicaciones separadas, y tecnologías diferentes, ya que Drag and Drop es una funcionalidad propia del Sistema Operativo.

Esto por supuesto no abarca todas las posibilidades como por ejemplo mostrar un icono personalizado durante el arrastre, arrastrar información en diferentes formatos, etc. Pero es un buen ejemplito introductorio.

Operadores de conversión (Implícitos y Explícitos)

miércoles 4 de junio de 2008

Es muy habitual realizar conversiones entre tipos de datos diferentes, por defecto muchos tipos de datos permiten la conversión implícita, esto se da en los casos en los cuales el tipo de dato de origen puede expresarse en su totalidad, como el Tipo de dato de destino, acá podemos ver un ejemplo:

byte valByte = 123;
int valInt = valByte;
double valDouble = valInt;
Como se ve en este caso no es necesario hacer ningún CAST, en cambio para el siguiente caso:
int valInt = 0;
byte valByte = valInt;
Tendriamos un error de compilación “Cannot implicitly convert type 'int' to 'byte'. An explicit conversion exists (are you missing a cast?)”, que nos indica que podemos hacer una conversión explícita, quedando resuelto de esta forma:
int valInt = 0;
byte valByte = (byte)valInt;
"Claro está que de esta manera, el Desarrollador está asumiendo los riesgos de obtener en la variable destino “valByte” información no esperada, si el valor origen “valInt” es superior al soportado por el tipo de dato Byte."

Conversión para clases definidas por el usuario

Desde la versión del .NET 2.0 podemos definir operadores de conversión para los tipos definidos por el usuario, como se puede ver en el siguiente ejemplo:
public class MyClase
{
public double valor;

/// <summary>
/// Permite la conversion implicita
/// desde Double hacia MyClase
/// </summary>
/// <param name="arg">Desde
/// <returns>Hacia</returns>
public static implicit operator MyClase(double arg)
{
MyClase res = new MyClase();
res.valor = arg;
return res;
}

/// <summary>
/// Permite la conversion implicita
/// desde MyClase hacia Double
/// </summary>
/// <param name="arg">Desde
/// <returns>Hacia</returns>
public static implicit operator double(MyClase arg)
{
return arg.valor;
}
}

public class MyClase2
{
public double valor;

/// <summary>
/// Permite la conversion explicita
/// desde Double hacia MyClase
/// </summary>
/// <param name="arg">Desde
/// <returns>Hacia</returns>
public static explicit operator MyClase2(double arg)
{
MyClase2 res = new MyClase2();
res.valor = arg;
return res;
}

/// <summary>
/// Permite la conversion explicita
/// desde MyClase hacia Double
/// </summary>
/// <param name="arg">Desde
/// <returns>Hacia</returns>
public static explicit operator double(MyClase2 arg)
{
return arg.valor;
}
}


En este caso la clase MyClase permite la conversión implícita con double, mientras que en la clase MyClase2 la conversión es explícita, la utilización de estas clases podría ser la siguiente:

double valDouble = 22;

MyClase myClase = new MyClase();
// Conversión implicita en ambos casos
valDouble = myClase;
myClase = valDouble;


MyClase2 myClase2 = new MyClase2();
// En este caso se requiere del CAST
valDouble = (double)myClase2;
myClase2 = (MyClase2)valDouble;

En resumen

Vimos un modo sencillo de implementar mecanismos de conversión entre tipos definidos por nosotros, generalmente entre tipos numéricos.
Otro modo de hacerlo es implementar System.IConvertible para utilizar la conversión a través de System.Convert, lo cual nos permite especificar la conversión por cultura.

Conferencia online - IIS 7 para desarrolladores

lunes 19 de mayo de 2008

En esta presentación online de MSDN (20/mayo/08) que realizamos con Carlos Walzer, destacamos algunos de los aspectos de la nueva plataforma de hosting en Windows Server 2008 y Windows Vista, enfocados desde la óptica de los desarrolladores.

Puede descargar aquí la presentación (.PPTX) y el ejemplo de código DemoWebsite con la extensión de consola para el administrador de IIS7. Los ejemplos están desarrollados con Visual Studio 2008.

NOTA: al abrir en Visual Studio la solucion de la consola administrativa, puede pedir una contraseña para el archivo de claves encriptadas. La misma es 123456