Haz que tu código fluya

Sin duda la expresividad, la facilidad para leerlo y tener clara su intención y efectos sobre el sistema, es una de las características más importantes del código. Si por algo son interesantes las interfaces fluentes son por que aumentan extraordinariamente.

Los primeros en describir formalmente esta técnica fueron Eric Evans y Martin Fowler, aunque el origen de la misma esta en el idiom, descrito para C++, method chaining. Quizás la primera librería que presenta un uso acusado de este idioma es la Iibrería iostream de C++ que permite construcciones de estilo de out << “hola” << “ “<< “mundo” << endl, aplicando method chaining al operador <<. Además en C++ se hace a menudo uso del named parameter idiom, que también está en la base de las fluent interfaces.

¿Cómo implementamos fluent interfaces?

La técnica es sumamente sencilla en cualquier lenguaje orientado a objetos. Se trata básicamente en crear métodos que además de realizar una labor, que generalmente es cambiar el estado del objeto sobre el que se invoca el método devolver como resultado de la función el propio objeto (this, en los lenguajes de la familia C) de manera que podamos encadenar la siguiente llamada.

Miremos el siguiente ejemplo:

File f = OpenFile("foo.txt")

        .ReadOnly()

        .CreateIfNotExist()

        .AppendWhenWriting()

        .BlockSize(1024)

        .Unbuffered()

        .ExclusiveAccess();

Si el método ReadOnly de la clase está implementado de esta manera:

OpenFile ReadOnly()

{

    _ReadOnly = true;

    return this;

}

…podemos encadenar la llamada a CreateIfNotExists sin problemas, dotando a nuestro código de una expresividad mayor que si simplemente hubiésemos hecho:

File f = OpenFile("foo.txt")

     f.ReadOnly = true;

     f.CreateIfNotExist = true;

     f.AppendWhenWriting = true;

     f.BlockSize = 1024;

     f.BufferMode = BufferMode.Unbuffered;

     f.AccessMode = AccessMode.ExclusiveAccess;

Vemos que implementar fluent interfaces es trivial en casi cualquier lenguaje orientado a objetos. Pero que sea fácil no quiere decir que sea adecuado siempre ¡ojo!. Ahora bien, cuando es adecuado, la potencia de esta técnica es clara y notoria. Esta técnica esta especialmente indicada cuando tenemos una serie de métodos y/o propiedades que tiene en la mayoría de las ocasiones tienen sentido invocar uno tras otro sobre el mismo objeto. Por ejemplo, una variación de esta técnica se usa para implementar las continuaciones en la Taks Parallel Library de .Net, permitiendo que podamos expresar de manera muy simple el encadenamiento de una serie de tareas:

new Task().ContinueWith(…)

          .ContinueWith(…)

          .ContinueWith(…)

          .ContinueWith(…)

          …

¿Cómo nos ayudan las fluen interfaces?

Hay dos librerías que son un claro ejemplo de la potencia de esta técnica y que son sumamente útiles.

La primera es una librería Fluent Validation que permite expresar validaciones de manera sumamente elegante:

using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(customer => customer.Company).NotNull();
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
    // custom postcode validating logic goes here
  }
}

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;

La otra, Fluent Assertions, es una librería que permite expresar aserciones en nuestras pruebas unitarias utilizando una fluent interface:

// Example

string actual = "ABCDEFGHI";

actual.Should().StartWith("AB").And.EndWith("HI").And.Contain("EF").And.HaveLength(9);

 

// Example

IEnumerable collection = new[] { 1, 2, 3 };

collection.Should().HaveCount(4, "because we thought we put three items in the collection"))

 

// Example

var recipe = new RecipeBuilder()

   .With(new IngredientBuilder().For("Milk").WithQuantity(200, Unit.Milliliters))

   .Build();

 

// Act

Action action = () => recipe.AddIngredient("Milk", 100, Unit.Spoon);

 

// Assert

action

   .ShouldThrow<RuleViolationException>()

   .WithMessage("Cannot change the unit of an existing ingredient")

   .And.Violations.Should().Contain(BusinessRule.CannotChangeIngredientQuanity);

Ambas librerías están disponibles a través de NuPack, así que no tienes disculpa para no probarlas.

¡Un saludo!

Leer antes de motivar… o lo que debe saber todo jefe de proyecto sobre la motivación

Lo más bonito de mi trabajo es que los clientes no dejan de sorprenderte nunca. Hace unos días llegue a un cliente, en el que recientemente hemos arrancado un piloto de un equipo. De las primeras cosas que llamaron mi atención fue ver tres líneas diferentes en su burndown chart. Tras preguntar, el jefe de desarrollo y el Scrum Master del equipo, me contaron, no sin cierto pudor, que las líneas representaban diferentes grados de cumplimiento de los objetivos del sprint, ¡cómo si fuese posible cumplir en diferentes medidas el trabajo comprometido para un sprint!.

Me reacción fue de clara contrariedad. Ellos sabían que la cosa no me iba a hacer gracia, pero se veían en la necesidad clara de ¡motivar al equipo!. Yo sabía que no era buena idea intentar ‘motivar’ al equipo prometiéndoles recompensas económicas por cumplir ‘más’ el sprint. Lo sabía porque ya había sufrido estos intentos de ‘motivarme’ durante mi carrera profesional y siempre habían tenido resultados dañinos. Lo sabía empíricamente, pero claro, cuanto te pagan por tu conocimiento, generalmente, no vale solo con decir, ‘tu idea no vale porque yo ya la he visto fallar’. Se espera una respuesta más analítica. Les apunté un artículo de Joel Spolky sobre el tema, titulado, Los pagos de incentivos considerados dañinos, pero me quede con la sensación de no haber respondido a su necesidad. La gente cuanto te paga por responder preguntas y ayudarles no quieren solo saber que puede pasar y como debe actuar sino los porqués…

La siguiente cuestión que se puso sobre la mesa fue: ¿tú qué haces para motivar a tu equipo? Mi respuesta es clara: tratar de no desmotivar. Hace tiempo leí o alguien me conto, que una buena forma de actuar es tratar de no hacer lo que a ti te han hecho y te ha desmotivado. Y a eso me suelo ceñir en lo que ha motivación se refiere.

Automáticamente me di cuenta de una realidad: ¡No sabía gran sobre la motivación! Y la motivación es el factor que más influye en el rendimiento de un equipo de desarrollo, eso sí que lo tengo muy claro, gracias al trabajo de Boehm que Steve McConnell refleja en sus libros que yo he leído con deleite. Si queremos equipos motivados no es para ser nominados a gestores del año, no, es simple egoísmo (léase sin connotaciones negativas) económico. Los desarrolladores motivados producen más.

En esta tesitura, tras dejar al cliente y llegar al aeropuerto, en una de esas casualidades que tiene la vida, mirando libros en el aeropuerto, tras el enésimo retraso del Vueling, encontré ‘La sorprendente verdad sobre qué nos motiva’ de Daniel H. Pink. Y ahora, unos días después de devorar el libro, puedo escribir este post.

¿Por qué mi intuición de que ofrecer dinero a un equipo de desarrollo por completar más historias que las comprometidas para un sprint no funciona es cierta?

Lo que debemos saber es que hay dos tipos de labores que los empleados pueden realizar. Hay tareas que son algorítmicas, que consisten en repetir una determinada receta para lograr un determinado objetivo productivo sin cabida para la creatividad o tareas heurísticas en las que el componente creativo es un factor relevante. ¿Alguien duda de que el desarrollo de software es una tarea de creación? Desarrollar software exige tomar continuamente decisiones de diseño. Cada línea es una decisión de diseño o varias. No es para nada una tarea repetitiva. Un desarrollador está continuamente solucionando problemas.

Hay un experimento esclarecedor descrito en el libro de Pink que demuestra científicamente que para tareas que requieren de creatividad y de dotes de resolución de problemas los incentivos económicos son dañinos. El experimento consistió en proponer a dos grupos de personas la resolución de un problema, el problema de la vela, cuyo planteamiento y solución podéis ver en la siguiente imagen, que exige cierta componente de pensamiento creativo. Se trata de sujetar la vela a la pared sin derramar una sola gota de cera. La solución una vez la conoces parece obvia, pero exige cierto pensamiento lateral para ver que es necesario sacar los clavos de la caja y que no es necesario usar las cerrillas.

Experimiento de la vela

A un grupo se le dijo que se le pagaría una cantidad si lograba resolver el problema, y a otro no. Sorprendentemente, el grupo remunerado obtuvo peores resultados a la hora de resolver el problema. El experimento demuestra que el hecho de establecer una recompensa económica automáticamente desvía nuestra atención de resolver el problema a obtener la recompensa.

El libro de Pink describe un motón de experimentos similares que llegan a una conclusión que es contraintutiva: tratar de motivar el trabajo mediante incentivos económicos solo funciona para tareas muy simples. Y desarrollar software no es una tarea simple. Además y de manera sorprendente, los incentivos económicos no solo no mejoran el rendimiento de los equipos de desarrollo, sino que además, a menudo ¡lo empeoran!. Es curioso ver en libro ejemplos de investigaciones que demuestran resultados muy ‘extraños’: incentivar económicamente la donación de sangre se traduce en una menor tasa de donaciones, los artistas realizan obras de peor calidad cuando están trabajando por encargo, los escolares que reciben un diploma por pintar pierden el interés por esta actividad… ¡cuando menos sorprendente!. Esto resultados ponen en evidencia la creencia general en gestión de que las personas respondemos al palo y la zanahoria, a un esquema de incentivos y castigos.

Para conocer el porqué hay que tener en cuenta que existen dos tipos fundamentales de motivación: la motivación extrínseca, es aquella que aparece cuando lo que atrae no es la acción que se realiza en sí, sino lo que se recibe a cambio de la actividad realizada (por ejemplo, dinero, comida o cualquier otra forma de recompensa) y la motivación extrínseca, que aparece cuando el individuo realiza una actividad por el simple placer de realizarla, sin que nadie de manera obvia le de algún incentivo externo. Cuando hablamos de trabajos en los que la creatividad juega un papel, la motivación intrínseca es sumamente importante, muchísimo más que la motivación extrínseca. Y lo que es más relevante, la motivación extrínseca forzada daña el rendimiento en este tipo de actividades.

No hay mejor manera de convertir un trabajo interesante y motivador en una pesada carga que tratar de incentivarlo. Si a un desarrollador le ofreces incentivos por realizar su trabajo, automáticamente le estas lanzando el mensaje de que el trabajo que realiza no debe despertar en él el interés suficiente por si mismo. Todos los desarrolladores odiamos los trabajos que no son interesantes, que no plantean un reto o una oportunidad de aprendizaje. Evidentemente en el desarrollo de software hay muchos trabajos que son repetitivos, pero por suerte, esto son susceptibles de ser automatizados, pedir a un desarrollador que automatice un trabajo repetitivo es mucho más productivo que remunerarle por realizar un trabajo que considera desagradable.

La psicología ha dado la explicación a algo que se sabía hace mucho tiempo. Fijaros en los factores que motivan a los desarrolladores, descubiertos por Barry Bohem hace décadas, tal y como aparecen en recomendable artículo Best Practices to Increase Productivity and Decrease Turnover de Janet Amirault:

image

El salario, en el caso de los desarrolladores de proyectos y los gestores aparece en el noveno lugar, tres más abajo que para la gente en general. Vamos que intentar motivar a desarrolladores con dinero, no da buenos resultado, hay factores mucho más influyentes y adecuados.

El corolario, expresado por Pink en su libro es que debemos recordar siempre que los incentivos basados en ‘si haces esto obtendrás aquello’ pueden eliminar la poderosa motivación intrínseca, reducir el rendimiento, dañar la creatividad, apartarnos de una conducta adecuada para lograr los objetivos volverse adictivos (necesitándose mayores y mayores incentivos cada vez) y potenciar el pensamiento cortoplacista.

Veamos qué escenario nos encontraríamos si cogemos un equipo y le ofrecemos dinero por terminar más historias de las comprometidas para un sprint. Para empezar, algo que es una meta loable, conseguir los objetivos marcados, algo a lo que nuestro ‘buenismo’ natural nos empuja, se convertiría en algo por lo que debemos ser sobre compensados. Implícitamente es admitir que el trabajo no es interesante, o no es motivador por si mismo o que los objetivos solo son factibles con una sobre motivación. Además la gente, como demuestra el experimento de la vela la gente se concentraría en fin, y olvidaría los medios. El fin de obtener el objetivo haría que fuésemos menos eficientes en el proceso de obtenerlo. Además seguro que algunos desarrolladores, sino todos, tomarían atajos de calidad, o no escribirían test unitarios o actualizarían la documentación solo para cerrar un historia más y obtener la recompensa, sutilmente estaríamos recompensando comportamientos anómalos. En el hipotético caso de que los incentivos funcionasen a corto, nunca funcionarían a largo plazo, pues cada vez serían necesarias mayores dosis para lograr los mismos resultados, algo insostenible económicamente.

Lo que si funciona, siempre administrándolo con juicio, son las recompensas no esperadas. Y sobre todo, aunque parezca mentira, lo que más funciona, es el reconocimiento al trabajo bien hecho. Un simple reconocimiento explícito es lo que mejor resultado da según muestran los estudios que Pink muestra en su libro.

Creo que después de todo, mi táctica de simplemente tratar de no desmotivar, es más que acertada. Y creo que la táctica de las metodologías ágiles de establecer metas claras, dar voz a los desarrolladores y permitir la excelencia son poderosos catalizadores de la motivación intrínseca.

Por si este post no ha despertado suficiente interés en vosotros sobre este tema, os dejo un video (en inglés) resumen brutal del libro de Pink, espero que lo disfrutéis:

¿A vosotros que os motiva?.

P.D.: Los videos con subtítulos en español (La soprendente verdad sobre los que nos motiva 1/2 y La sorprendente verdad sobre lo que nos motiva 2/2).

Experiencias en la implantación de metodologías ágiles con Visual Studio Team System

Cuando Microsoft lanzo Visual Studio Team System hace unos cuatro años, muchos desarrolladores vimos como se cumplían nuestras expectativas de lograr que Visual Studio se convirtiese en una herramienta al servicio de los equipos de trabajo y no solo al servicio de los desarrolladores. Además personalmente vi colmada otra expectativa, contar con una herramienta en entornos Microsoft que acercase las metodologías a los equipos de desarrollo, con independencia de la metodología elegida y del tamaño del equipo de desarrollo. En estos cuatro años he participado en multitud de proyectos de implantación de Team System, y Team System y las metodologías ágiles forman parte de mí día a día como desarrollador. En este artículo pretendo compartir lo aprendido sobre la implantación de metodologías ágiles con Team System, las dificultades encontradas, como las hemos abordado y que resultados hemos obtenido.

¿Por qué metodologías ágiles?

En Team System cuando creamos un nuevo proyecto en nuestro Team Foundation Server, la primera elección que debemos hacer y sin duda una de las más importante para el futuro de nuestros proyectos será la metodología que queremos usar. Las opciones son variadas y cada vez lo serán más, pues cada poco tiempo aparecen nuevas plantillas metodologías que podemos instalar en nuestro Team Foundation Server. No me voy a extender mucho en este punto, más siendo que en este mismo número podéis encontrar información sobre este tema. Simplemente me gustaría recalcar la importancia de que esta elección sea fundamentada y basada en el conocimiento de varias metodologías.

Dicho esto, ¿por qué elijo metodologías ágiles en la mayoría de las ocasiones? El motivo es uno solo: economía de recursos. En la mayoría de las ocasiones, lo equipos que implantan Team System tiene un conocimiento más o menos profundo de la herramienta y una fuerte predisposición para usarla, pero es raro que la motivación principal sea implantar una metodología. En esta situación es evidente que un enfoque de menos a más es el adecuado. Yo siempre digo que las metodologías se ganan como las contrarreloj en ciclismo: yendo de menos a más. Es muy difícil saber qué ‘cantidad de metodología’ necesita un proyecto, un equipo y una empresa. Poder ir de menos a más, añadir paulatinamente elementos hasta lograr el equilibrio justo entre tener un ciclo de vida gestionado y coste de mantenimiento del proceso y evitar que un exceso de burocracia asesine la adopción de la metodología es el vital. Las metodologías ágiles permite esto precisamente. Otras metodologías imponen ya de entrada unos costes de implantación y de mantenimiento que no todos los proyectos, equipos o empresas necesitan o pueden asumir. Mantenerse ágil es utilizar el mínimo de elementos metodológicos que eligiendo aquellos que más valor aportan al equipo de desarrollo.

Otro aspecto que me preocupa particularmente a la hora de elegir una metodología es que el desarrollador la perciba como algo familiar, que le puede ayudar en su trabajo diario. Los desarrolladores tienden a pensar en las metodologías ágiles de manera más amistosa mientras que ven otro tipo de metodologías como una imposición de más burocracia. No digo que esta percepción sea siempre correcta, pero sí que es cierto que contar con el apoyo y la comprensión de los desarrolladores es vital a la hora lograr implantar con éxito una metodología. El motivo es simple: ¡los desarrolladores son los más numerosos de todo los roles implicados en un proyecto!

Más adelante hablaré de las buenas prácticas, aspecto clave para tener un ciclo de vida sano. La metodología es el pegamento que une esas buenas prácticas y que permite gestionar el proceso de desarrollo de principio a fin, iteración tras iteración. Señalar que Scrum y MSF Agile son las opciones más frecuentemente elegidas en las implantaciones de Team System utilizando metodologías ágiles.

Las buenas prácticas: claves para el éxito

Durante el tiempo que llevo trabajando con Team System he visto equipos brillar con diferentes metodologías, ágiles y no. Pensando en esto he llegado a una conclusión clara. Todos esos equipos tenían algo en común: habían elegido una serie de buenas prácticas, no siempre las mismas, y las habían incorporado al día a día de su ciclo de vida en el marco de una metodología. Además, todos esos equipos habían utilizado inteligentemente las posibilidades que Team System nos brinda a la hora de adoptarlas. Si importante es adoptar buenas prácticas, igualmente importante es apoyar esta adopción en una herramienta que facilite la vida la vida del desarrollador. Toda práctica que queramos introducir en nuestro ciclo de vida va a encontrar una resistencia inicial por parte del equipo, utilizar una herramienta natural para el programador es vital. Team System permite a los desarrolladores realizar todas las actividades relacionadas con el seguimiento del proyecto y la puesta en marcha de buenas prácticas desde el entorno que más natural les resulta, su herramienta de desarrollo, Visual Studio.

Además de usar una herramienta que facilite la adopción de buenas prácticas, seleccionar qué buenas prácticas queremos incorporar a nuestro proceso de desarrollo es una cuestión que exige atención.

El difícil problema de la gestión de proyectos

Gestionar proyectos de software es una tarea difícil. Son muchos los aspectos relevantes y muchas las personas implicadas. Entre los aspectos relevantes podríamos citar una infinidad de ellos: las herramientas, los procesos, la gestión del riesgo, la involucración del cliente, la gestión de la configuración, la calidad, el retorno de la inversión, así, una larguísima relación de cuestiones relevantes. La dificultad está en elegir en cuales de estos aspectos vamos a centrar nuestros esfuerzos en primera instancia. Además, para más inri, ni siquiera serán los mismos de proyecto a proyecto. Evidentemente todos estos aspectos de la gestión de proyectos presentan dificultades, sobre las que podemos actuar para obtener ciertos resultados. Tras años de participar en la implantación de proyectos he llegado a valorar algunas de estos aspectos por encima de otros en base a su rango de aplicación en el espectro posible de tipos de proyectos, sus posibilidades de éxito y los resultados obtenidos una vez puestos en funcionamiento. Comentar las dificultades, las acciones realizadas en pos de su puesta en marcha y los resultados obtenidos es lo que viene a continuación.

El equipo multidisciplinar, auto-organizado y auto-gestionado

Las metodologías ágiles abogan por formar un equipo multidisciplinar, auto-organizado y auto-gestionado. Entender y formar este tipo de equipos es difícil, pero si logramos establecer un proceso de trabajo que promociones las relaciones entre iguales y el trabajo en pos de una meta compartida y con una visión común, las ventajas son muchas. Es evidente que cuando logramos trabajar en equipo la productividad se ve impulsada de manera importante. Un equipo de cuatro es mucho más productivo que la simple suma de cuatro individuos. Desde mi punto de vista hay varios puntos clave a la hora de lograr funcionar en equipo: establecer una visión común de proyecto, fomentar la participación de todos los miembros y la participación de compartida en los resultados y sobre todo permitir que sea el equipo quien en base a estimaciones establezca sus compromisos. Un equipo que establece compromisos claros, basados en un proceso formal de estimación, de manera consensuada y solidaria y los asume como suyos se deja la piel para cumplirlos. No aparece ningún dilema moral sin embargo cuando un equipo no logra cumplir compromisos que han sido establecidos por terceros en su nombre.

La estimación explicita como base de compromisos realistas

Evidentemente para poder establecer compromisos realistas es necesario realizar un proceso formal de estimación. Estimar la magnitud del proyecto y la magnitud de las porciones de proyecto que vamos a abordar en cada iteración es vital, puesto que solo así podremos establecer compromisos realistas, alineados con la capacidad del equipo. Un equipo de desarrollo solo va a tratar de cumplir aquellos objetivos que percibe que son realistas. Es necesario aprender a estimar y estimar en cada iteración. Un primer paso es comprender que las estimaciones solo son estimaciones. Esto que, a priori, es una perogrullada, se tiende a obviar. Los involucrados en los proyectos, especialmente los roles involucrados en la gestión del proyecto y la relación del cliente, tienden a olvidar esto. Tenemos que entender que cuando un desarrollador da una estimación no conoce muchos de los aspectos que con más fuerza influirán en la duración de la tarea, como, por ejemplo, la dificultad técnica. Además estos aspectos son mucho más difíciles de ver cuanto más lejano está el punto de inicio de la tarea. Las estimaciones con estimaciones, no contratos. Cuando alguien ajeno al equipo convierte las estimaciones en contratos está realizando un acto de adivinación no de ingeniería del software. Si una estimación no nos gusta o no casa con las necesidades del proyecto solo podemos añadir recursos o recortar características para que se ajuste a nuestras necesidades. Estimar y re-estimar con frecuencia, al inicio de cada iteración y tratar las estimaciones con responsabilidad y con respeto es el camino que nos lleva a poder gestionar nuestros proyectos en base a datos objetivos. ¿Pero qué técnicas podemos usar para estimar con frecuencia y con la participación de todo el equipo de manera ágil? Las técnicas que estimación que más adopción y mejores resultados presentan, usadas en combinación, en proyectos ágiles son Wideband Delphi y Planning Poker. No entro en detalles, pero si invito al lector a visitar la sección sobre estimación de mi blog donde encontrará información suficiente sobre estas técnicas.

Asumir el cambio como una oportunidad

Otro aspecto complicado en la adopción de metodologías ágiles es que estas asumen el cambio como algo positivo, inherente a todo proyecto de desarrollo de software. El cambio se debe percibir como una oportunidad más que como un problema. Mi experiencia es que este planteamiento choca de manera frontal con el estilo de gestión clásico al que muchos hemos estado acostumbrados. Cambiar esta mentalidad es un reto claro en toda implantación de metodologías ágiles. Es necesario comprender y explicar que si bien los cambios son bienvenidos para que estos nos asesinen el proceso de desarrollo es necesario arbitrar cuando se pueden producir. Que el cambio sea una realidad en todo proyecto, que lo gestionemos como una oportunidad y que bien gestionado el cambio nos ayude a cubrir las necesidades del cliente no quiere decir que el cambio constante sea bueno. Solo durante la planificación de una iteración es posible asumir cambios y estos deben estar fundamentados en necesidades reales surgidas de nuevas oportunidades o de cambios en el entorno. La manera en la que lidiamos con los cambios es simple: Iterar, iterar, iterar y volver a iterar… en iteraciones cortas durante las cuales los cambios están congelados y planificar, planificar, planificar y volver a planificar en base a estimaciones al comienzo de cada iteración. Evidentemente contar con una herramienta que nos permita gestionar de manera ágil y cómoda la información surgida del proceso es vital. Es aquí donde Team Foundation Server nos ayuda de manera clara.

Pruebas unitarias

En todo proyecto hay una frase que se oye a menudo: ‘si funciona, no lo toques’. Esta máxima es un exponente claro de la dificultad que los desarrolladores hemos padecido a la hora de mejorar, mantener y extender nuestro código. Todos sabemos que una función con mil líneas es una mala solución, pero solo si contamos con un mecanismo que nos permita saber que si mejorarnos esa situación no romperemos nada. Este mecanismo es son las pruebas unitarias. Si bien esta capacidad para integrar cambios con facilidad es a mi modo ver la principal ventaja de las pruebas unitarias no es la única:

  • El conjunto de test unitarios proporciona constante retroalimentación de que cada uno de los componentes sigue funcionando.
  • Los test unitarios actúan como documentación que no se queda obsoleta, al contrario que otros tipos de documentación.
  • Cuando el test pasa y el código de producción es refactorizado para eliminar duplicidades, es claro que el código está terminado, y el desarrollador se puede mover a la siguiente tarea.
  • El testeo unitario fuerza un análisis y diseño explicito porque el desarrollador no puede crear código de producción sin entender realmente cuales deberían ser los resultado deseados y como probarlos.
  • El software tiende a estar mejor diseñado, esto es, menos acoplado y más fácilmente mantenible, porque el desarrollador es libre de hacer decisiones de diseño y refactorizar en cualquier momento con la confianza de que el software todavía funciona.
  • El conjunto de pruebas actúa como una red de seguridad contra regresiones en los bugs: Si se encuentra un bug, el desarrollador debe crear un test que ponga de manifiesto el bug y después modificar el código de producción para eliminar el bug. En sucesivas ejecuciones de los test, todas las correcciones de bugs son verificadas.
  • El tiempo de depuración se reduce.

La principal dificultad a la hora de adoptar las pruebas de desarrollo en nuestro ciclo de vida es asumir que se trata de una inversión no de un coste. Es evidente que implementar las pruebas unitarias tiene un coste, y que este coste solo se rentabiliza cuando hay una base de código amplia. Es necesario hacer por tanto un acto de fe y creer que las pruebas unitarias nos ayudaran de manera cada vez más importante según la base de código vaya creciendo y el software se vaya complicando. Este acto de fe, muy sencillo para los equipos que han usado pruebas unitarias con anterioridad, es más difícil si ninguno de los miembros ha usado esta técnica antes. En estas situaciones, desde la dirección del proyecto se debe lanzar un mensaje claro: las pruebas unitarias no son opcionales.

El testeo unitario se debe implementar desde la primera línea de código del proyecto para que sea totalmente exitoso. Si lo hacemos, sin un gran, esfuerzo conseguiremos reunir un conjunto de pruebas que actuarán como una red de seguridad en nuestro proyecto. Otro aspecto importante en relación a las pruebas unitarias es contar con una herramienta de desarrollo que facilite al desarrollador la escritura y la ejecución de las pruebas. Visual Studio Team System cuenta con un poderosísimo framework de pruebas unitarias y con un motón de facilidades a la hora de ejecutarlas desde dentro del propio entorno. Personalmente, si tuviese que elegir la técnica que más ha impactado en como desarrollo software en los últimos años, sin dudarlo ni un segundo, diría que es el testeo unitario y su integración en el entorno de desarrollo.

1. Testeo unitario

Testeo unitario: Visual Studio Team System permite integrar con facilidad el testeo unitario en nuestra metodología de desarrollo.

Integración frecuente y construcciones automatizadas

Una de las grandes novedades de Visual Studio Team System y Team Foundation Server es la posibilidad de crear construcciones automatizadas. Pero el simple hecho de contar con una herramienta que nos ayude en la tarea no significa que vayamos a adoptar una buena práctica. De hecho antes de Team System ya existía NAnt como herramienta de automatización de la construcción, y se trata de una gran herramienta, pero aun así pocos son los equipos de desarrollo que cuentan con la posibilidad de construir todo su proyecto con la simple ejecución de un comando, son pocos los que usan construcciones automatizadas. Conocer las ventajas que aporta las construcciones automatizadas es el único camino para que estas se popularicen y más y más equipos de desarrollo disfruten de sus bondades.

El proceso de construir el software desde las fuentes es complejo. De hecho es cada vez más complejo: elegir la fuentes adecuadas, compilarlas con las versiones adecuadas de los componentes, asegurarnos que hemos compilado la configuración adecuada (debug o release), seleccionar de la salida del proceso de compilación aquellos archivos que debemos distribuir, no olvidar incluir aquellas librerías o componentes de los que depende nuestro software y asegurarnos de que su versión es la correcta, generar los archivos de ayuda, crear la estructura de directorios que espera como entrada nuestra herramienta de generación de instaladores, ejecutar el proceso de generación del instalador… y todo esto involucrando a un buen número de personas diferentes ¿de verdad alguien cree que es posible realizar este proceso manualmente sin cometer varios errores durante el mismo?. La cruda realidad es que no es posible. Y lo que es peor, a menudo los errores cometidos en alguno de los múltiples pasos que hay que dar se detectan solo al final del proceso. El resultado: ¡una enorme pérdida de tiempo!. Y lo peor del caso es que este es un proceso que se repite muchas veces a lo largo de la vida de un proyecto. Además, para agravar aún más la situación este problema ocurre cuando menos tiempo tenemos, ¡justo cuando alguien está esperando que le entreguemos el software!.

En todo proyecto de software existe un ciclo que ser repite infinitas veces: escribir código, compilarlo, integrarlo y realizar pruebas. Contar con un proceso de construcción del software automatizado hace que este ciclo se acelere enormemente.

El principal problema que plantean las construcciones automatizadas es que exigen una inversión de tiempo para ponerlas en marcha. Configurar un proceso de construcción completo que sea capaz de desde el código fuente de nuestro software construir el software completamente hasta el instalador y además desplegarlo en un sistema de prueba es complejo. De hecho es algo que solo es abordable y rentable si se realiza de forma incremental, haciendo que el proceso de construcción crezca de manera paralela a nuestro software. En cualquier caso, a menudo, en proyectos con problemas de integración, merece la pena invertir el tiempo necesario para configurar un proceso de construcción a posteriori. El esfuerzo es grande pero a menudo no hay otro camino para zanjar de raíz los problemas de integración en los proyectos de software. Resumiendo, más vale configurar pronto el proceso automatizado de construcción que hacerlo a posteriori cuando hay problemas.

Si bien el simple hecho de poder construir nuestro software de manera automática nos proporciona claras ventajas, yendo un paso más allá y construyendo nuestro software diariamente (gracias a nuestro proceso automatizado de construcción esto es algo posible) podemos obtener ventajas añadidas. Si diariamente construimos nuestro software detectáramos rápidamente problemas de integración y corregirlos cuando los cambios que pueden ser la causa aun están frescos en nuestra memoria y por tanto nos es más fácil corregirlos. Además como parte del proceso de construcción podemos ejecutar nuestros test unitarios lo que nos proporcionará la posibilidad de detectar errores no solo relacionados con la integración. Adicionalmente, como colofón a nuestro proceso de construcción y aprovechando que nuestro proceso de construcción despliega el software construido a un entrono de pruebas podemos realizar un test de humo que asegure que el software construido tiene la calidad suficiente como para ser probado en profundidad. Este paso asegura que cualquier error relativo a la configuración del software desplegado se detecta pronto.

A menudo se pone como escusa para no realizar construcciones diarias la magnitud del proyecto: ¿Cómo vamos a construir y desplegar un software tan complejo todos los días? Precisamente cuanto mayor es el proyecto mayores son las posibilidades de sufrir problemas de integración y de calidad pues más es el código que cada día se añade. Además el hecho de que grandes proyectos como por ejemplo Firefox lo haga, demuestra que es viable y rentable. Podéis ver el estado de las construcciones diarias de Firefox (http://tinderbox.mozilla.org/showbuilds.cgi?tree=Firefox).

Métricas

Las métricas son el camino hacia una gestión explicita de proyectos, basada en datos, no en intuiciones. La gran mayoría de los gestores de proyectos creen que las métricas son un instrumento poderoso, pero la gran mayoría de los proyectos no usan métricas. Este hueco se produce por la dificultad para recolectar los datos que fundamentan estas métricas. He visto implantaciones de metodologías fallar estrepitosamente por el hecho de que los desarrolladores tenían que pelear para abrir la hoja Excel en la que se realizaba el seguimiento del proyecto para alimentar los datos, con el resultado de que ese seguimiento se abandonaba.

Si en algo ha cambiado Team System la gestión de proyectos es en la facilidad que tenemos para recolectar métricas de lo más variado sin interferir en el día a día del desarrollador, sin imponerle burocracia adicional. El desarrollador trabaja desde el entorno de desarrolla, realizando sus actividades habituales y de forma casi transparente alimenta un completísimo datawarehouse que permite que todo el equipo y los gestores del proyecto accedan a las métricas más relevantes relacionadas con la metodologías elegida.

En las metodologías ágiles, la velocidad de desarrollo entendida como el trabajo realizado frente al trabajo que hemos estimado que nos queda por hacer es la principal métrica. Utilizar la velocidad como principal métrica está fundamentada en que incrementos en este aspecto del desarrollo son síntoma claro de mejora del proceso de desarrollo. Si desarrollamos más rápido, es que desarrollamos mejor. Además es una métrica difícilmente sesgable, si para mejorar la velocidad de desarrollo sacrificamos por ejemplo la calidad, olvidándola, o el equipo, forzándole por encima de su capacidad o cualquier otro aspecto, tarde o temprano esto se verá reflejado en la velocidad. Además la velocidad es una métrica que nos permite estimar con facilidad cuando el proyecto estará concluido o que magnitud de funcionalidad se debe quedar fuera para cumplir una fecha concreta.

Implantar métricas de progreso clara, nos permite informar a partes ajenas al desarrollo de cuál es el comportamiento del proyecto de manera analítica, explícita y difícilmente rebatible. Esto hace que el resto de los afectados por un proyecto puedan actuar en fase a datos. Los comerciales no comprometen fechas imposibles, los redactores técnicos pueden planificar cuando podrán comenzar a capturar pantallazos de la documentación, el departamento de calidad final sabrá cuando debe esperar carga de trabajo relacionada con nuestro proyecto, etc…

2. Metricas

Métricas: La velocidad es la métrica clave en las metodologías ágiles, Visual Studio Team System nos permite obtenerla sin imponer burocracia al desarrollador.

Facilitar la comunicación

La comunicación dentro de los proyectos y hacia afuera de los proyectos es un problema claro que todas las metodologías tratan de atajar. Algunas como RUP o CMMI ponen el peso en la documentación y en generara artefactos que actúen como repositorios de información que se mueven de un lado para otro. Otras como Scrum o XP y en general las metodologías ágiles asumen que las personas son el principal repositorio de conocimiento y tratan de habilitar mecanismos (como una serie de reuniones con propósito claro, asistentes determinados, duración preestablecida y entregables predefinidos) para promocionar que las personas compartan información. Sin duda en todo proceso de desarrollo ágil o no tendremos que mantener una magnitud mayor o menor de documentación.

Es vital lograr que todo el equipo esté informado. Es aquí donde una herramienta de gestión de proyectos juega un papel vital. Contar con un lugar único donde el desarrollador pueda consulta sus tareas, sus bugs o donde el gestor del proyecto pueda consultar si un requisito esta implementado o probado o no facilita de manera radical el acceso a la documentación. Pero no solo eso, exprimir al máximo las capacidades de notificaciones que Team Foundation Server pone a nuestro servicio nos va a permitir lograr un enfoque ‘push’ en nuestra gestión de proyectos. Ya no es necesario recordar mirar nuestras métricas, podemos recibirlas en nuestro correo cada día. Unamos esto a la capacidad que tiene el portal del proyecto de Team System para radiar información hacia el exterior del proyecto, para actuar como repositorio de la información y sobre todo, para informarnos de cuando hay cambios en documentos de nuestro interés y veremos que la labor de gestión de proyectos será mucho más efectiva, gracias a la utilización de herramientas como gestores documentales, wikis y listas de discusión.

3. Alertas

Alertas: La capacidad de subscribirnos a información relevante facilita enormemente la gestión del proyecto.

Calidad, calidad y… calidad

Unos de los principios de MSF dice que ‘La calidad es el negocio de todos todos los días’. No dejar la calidad para el final es vital. Si algo he aprendido implantando metodologías es que es imposible pensar en tener un proceso de desarrollo sano y sostenible sin incorporar testers a los proyectos. Podéis ahondar en las justificaciones leyendo un artículo publicado en mi blog, titulado ‘Pon un tester en tus proyectos’ (http://geeks.ms/blogs/rcorral/archive/2006/10/21/Pon-un-tester-en-tus-proyectos.aspx)

Es difícil asumir que añadir calidad a nuestro software, hasta cierto punto, al contrario de lo que puede parecer a primera vista, reduce los costes de desarrollo y acorta los plazos. La reducción de costes se produce porque con un adecuado proceso de desarrollo, que tenga la calidad del software como un factor central, se descubre antes los errores. Y los errores, de cualquier índole, son más costosos cuanto más tarde se descubren, además estos coste se incrementan siguiendo un función exponencial. Descubrir que nuestra arquitectura no es capaz de gestionar el número requerido de transacciones por segundo, es infinitamente más costoso de corregir si se descubre durante las pruebas de aceptación que durante la revisión de la arquitectura. La reducción del tiempo de desarrollo se produce porque es mucho más fácil construir software sobre software estable que sobre software que no es estable. Hoy en día todos los procesos de desarrollo de software son en mayor o menor medida iterativos e incrementales. Es imposible construir un incremento de funcionalidad si la base de ese incremento no es estable.

Debemos tener en cuenta que el nivel de calidad lo decide el cliente no nosotros. Ningún cliente aceptará de buen grado un software que no cumple sus estándares de calidad. Poner el esfuerzo en averiguar cuál es el nivel de calidad que nuestros clientes requieren y asegurar que durante todo el proceso de desarrollo estamos muy próximos a ese nivel. Pasarse es desperdiciar fuerzas y quedarse corto significa que en algún momento tendremos que hacer un esfuerzo añadido para alcanzar las expectivas de calidad de nuestro cliente. Si queremos poder actuar con agilidad, incorporar cambios de manera sencilla, y construir el software de manera iterativa e incremental es imprescindible lograr mantener el nivel de calidad a lo largo de todo el proceso.

Cuando apareció Visual Studio Team System, Microsoft puso a nuestra disposición una herramienta de pruebas completamente integrada en el ciclo de desarrollo de la aplicación. Los testers son uno más del equipo de desarrollo, utilizan las mismas herramientas que los desarrolladores y consolidan la información sobre los resultados de las pruebas en el mismo servidor de gestión de proyectos. Esto hace que el proceso de compartir la información entre desarrolladores y testers sea mucho más eficiente.

4. Calidad

Calidad: Visual Studio Team System proporciona las herramientas necesarias para hacer de la calidad un punto central de nuestro proceso de desarrollo.

Conclusiones

Visual Studio Team System y las metodologías ágiles son una excelente pareja que me ha permitido ayudar a numerosísimos equipos a mejorar su manera de desarrollar software. Usar metodologías ágiles me ha permitido optimizar la relación entre el esfuerzo de implantación y los resultados obtenidos. Utilizar Visual Studio Team System ha sido vital a la hora de impulsar y facilitar la adopción de buenas prácticas de gestión de proyectos e ingeniería del software.

Articulo publicado con anterioridad en DotNetMania.