Implementando Feature Toggles en C# con Microsoft.FeatureManagement

Se conoce como Feature Toggles (o feature flags) a la capacidad/funcionalidad de disponibilizar (prender/apagar) una funcionalidad en base a un determinado criterio. En mi proyecto veníamos usando esta técnica casi desde que empezamos y en particular la usamos para habilitar funcionalidades gradualmente a distintos grupos de usuarios. De entrada hicimos nuestra propia implementación de feature toggles, la cual ofrecía ciertas capacidades acotadas pero que para nuestro escenario resultaban suficientes.

Nuestro Product Owner se entusiamó con esta capacidad de «togglear» funcionalidades y entonces decidimos analizar una solución de toggles más robusta y flexible. Es así que comenzamos a analizar las opciones listadas en el sitio FeatureFlags.io. Por otro lado nos encontramos con el componente Microsoft.FeatureManagement. A simple vista este componente nos resultó el más atractivo de los que habíamos visto y por ello decidimos probarlo.

El resultado fue contundente, nos llevó aproximadamente 1 hora reemplazar nuestro componente casero por el componente de Microsoft y lo que pensábamos que sería una prueba de concepto terminó completamente integrado en nuestra aplicación.

En forma resumida el uso de este componente requiere de los siguientes pasos.

1. Agregar el paquete

Agregar la referencia al paquete Microsoft.FeatureManagement.AspNetCore

2. Agregar la configuración

La configuración se puede poner en un archivo json o directamente se puede incluir en el archivo de configuración de la aplicación (appsettings.json).

"FeatureManagement": {
   "funcionalidad1":true,
   "funcionalidad2": false,
   "funcionalidad3": {
      "EnabledFor": [
         {
            "Name": "Targeting",
            "Parameters": {
            "Audience": {
              "Users": [
                "juan",
                "maria"
               ]
            }
          }
        }
  }

Este fragmento de configuración indica que la «funcionalidad1» está encendida, que la funcionalidad2 está apagada y que la funcionalidad3 está encendida solo para los usuarios juan y maria.

3. Agregar los toggle points

Los toggle points son los lugares en nuestro código donde se consultan los toggles para verificar si una funcionalidad está activa o no. Esto es: en el punto de entrada a la funcionalidad1 tengo que ver si la misma está disponible o no. Para esto utilizamos la clase featureManager

if(featureManager.IsEnabledAsync("funcionalidad1"))
{
   ....
}

Dependiendo de cómo esté definido el toogle puede que tengamos que adicionalmente darle al FeatureManager información contextual para que pueda consultarse la funcionalidad.
El componente de Microsoft ofrece también featureGates que pueden ser utilizados en los controllers/actions de una aplicación web y así evitar la ejecución en caso que la funcionalidad indicada no esté habilitada.

[FeatureGate("funcionalidad1)]
public class MyController : Controller
{
    …
}

Este componente ofrece out-the-box la capacidad para definir evaluación de toggles dependindo de rangos horarios, usuarios y grupos de usuarios. En caso que esto no sea suficiente también es posible crear extensiones para definir criterios propios de evaluación.

Generación de reportes de cobertura con ReportGenerator

Hace un tiempo escribí sobre medición de cobertura en Net Core utilizando Coverlet. Como indiqué en ese artículo Coverlet tiene la capacidad de medir la cobertura y generar reportes al respecto en distintos formatos. Pero hay una limitación: cuando nuestra cobertura no es del 100% querremos saber puntualmente que métodos/líneas no están cubiertos y si bien Coverlet genera reportes con esta información, los mismos no son en formatos «amistoso para humanos» sino que son en formatos particulares para ser procesados por otras herramientas. Es aquí donde entra en juego ReportGenerator.

ReportGenerator es una herramienta que a partir de un reporte de cobertura en formato «no amistoso para humano» (opencover, cobertura, jacoco, etc) genera reportes en formatos «amistoso para humanos» (csv, html, etc). Esta herramienta está construida en .Net y puede instalarse de varias formas diferentes dependiendo de la plataforma en la que uno pretenda utilizarla. Más aún, la propia herramienta provee una página donde a partir de completar un conjunto de opciones se generan las instrucción de instalación y ejecución correspondientes.

Ahora bien, para poder generar un reporte con ReportGenerator a partir de una medición de cobertura generada con Coverlet hay que indicarle a Coverlet que genere el resultado en un formato que sea compatible con ReportGenerator, por ejemplo formato OpenCover. A continuación comparto un ejemplo.

dotnet test Domain.Tests/Domain.Tests.csproj /p:CollectCoverage=true /p:CoverletOutput=../coverage.info /p:CoverletOutputFormat=opencover

reportgenerator -reports:coverage.info -targetdir:"coverage"

Preparando Ingeniería de Software UNTreF 2020

Ya está definido que este año tendremos que dictar la materia en modalidad completamente a distancia y por ello tendremos que hacer algunos ajustes en la dinámica de las clases y de la materia en general. Al mismo tiempo tenemos ciertas dudas sobre la cantidad de alumnos que cursarán.

Por esto es que hemos habilitado este formulario para llenen que los alumnos interesados en cursar Ingeniería de Software este segundo cuatrimestre de 2020 y de esta forma poder hacer una planificación con menos incertidumbre. Quisiéramos que llenen este formulario todos los alumnos que tengan intención de cursar la materia incluso cuando no reúnan todas las correlativas necesarias.

De paso compartimos aquí algunos detalles de la forma en que dictamos la materia:

  • Intentamos cubrir los temas de la materia con materiales de estudio actualizados y herramientas de uso de frecuente en la industria
  • Para las cuestiones de programación utilizamos Ruby
  • Como herramienta de soporte para las tareas de programación y el trabajo grupal utilizamos GitLab
  • La materia requiere una dedicación semanal de entre 4 y 6 horas adicionales al tiempo de clase
  • La dinámica de evaluación es continua, con tareas semanales que incluyen lecturas, videos, ejercicios de programación y cuestionarios.
  • Este artículo describe formalmente la dinámica de la materia
  • Aquí pueden encontrar varios sobre el dictado de la materia en cuatrimestres anteriores

Enseñanza de Métodos Ágiles en Argentina

Corté el título porque quedaba demasiado largo, pero para ser preciso debería haber puesto: Enseñanza de Métodos ágiles de Desarrollo de Software en Argentina. Estado del Arte. Este es el título formal del trabajo con el que completé mi carrera de Especialista en Tecnología Informática Aplicada en Educación (UNLP).

Este trabajo es un estudio formal y sistemático basado en métodos empíricos de investigación. El trabajo completo tuvo 3 fases.

La primera fase, a fines de 2018, fue incluso antes de comenzar formalmente con el trabajo de especialización. Hice una encuesta entre estudiantes en CONAIISI 2018. El resultado de esa encuesta fue un artículo titulado en «Initial Assessment of Agile Development in theUndergraduate Curricula» que fue publicado en el Workshop Brasilero de Métodos Agiles que se llevó a cabo en el contexto de Agile Brazil 2019.

La segunda fase, ya en el contexto de la especialización, consistió en un mapeo sistemático de literatura que fue publicado en el XXV Congreso Argentino de Ciencias de la Computación con el título «Introducing Agile Methods in Undergraduate Curricula, a Systematic Mapping Study«

Hasta este punto, toda la información recolectada no resultaba suficiente para tener un entendimiento lo suficientemente certero sobre el estado de la enseñanza de métodos ágiles en Argentina. Entonces ya en la fase 3 realicé una encuesta a docentes de Ingeniería de Software, que es el área donde típicamente se estudian métodos ágiles. Para esto contacte en forma personalizada a los docentes de Ingeniería de Software de la universidades pertenecientes a la Red de Universidades Nacionales con Carreras de Informática, un organismo que agrupa tanto a instituciones públicas como privadas.
Logré así recolectar respuestas de 69 cursos pertenecientes a 44 instituciones distintas. Según los datos provistos por de la Secretaría de Políticas Universitarias del Ministerio de Educación de la Nación , las instituciones relevadas en mi estudio «generaron» en ~77 % de los egresados de las carreras universitarias de informática en el país en el 2017. Esto da cuenta de la representatividad de la muestra analizada.

Entre los resultados encontrados, destacan:

  • Los métodos ágiles son enseñados en el 97.7 % de las carreras de grado relevadas. Más aún, en el 54,5 % de los casos, los métodos ágiles se estudian en el contexto de varias materias que también abordan otros temas.
  • La gran mayoría de los encuestados (83.8 %) dicta sus materias de forma completamente presencial. Este hecho puede estar influido por cuestiones de regulaciones ya que muchas instituciones no admiten alternativas de educación no presencial y exigen asistencia física a las clases. Sin embargo, el 70 % de los encuestados utiliza en sus materias un campus virtual, lo cual representa una extensión del aula y por ende cierto grado de hibridación en la modalidad de enseñanza.
  • El 77 % de los encuestados indicó enseñar Scrum, pero tan solo el 53 % indicó enseñar Retrospectivas, que sin duda es una de las prácticas más importantes de Scrum. Iteration Planning, Iteration Review y Daily Standup son todas prácticas centrales de Scrum y su porcentaje de enseñanza es bastante menor al de Scrum
  • Respecto de las prácticas ágiles; User Stories, Iteration Planning, Planning Pocker, Retrospectives e Iteration Review son las cinco prácticas más enseñadas, las cinco por encima del 50 %. Cabe destacar que estas cinco prácticas pertenecen todas a la categoría “Practicas de gestión”.

Los interesados en leer el trabajo completo lo pueden descargar desde este link.

El próximo lunes 17 a las 19.00 hs voy a hacer un sesión online para compartir los resultados de este estudio y debatir al respecto. Si estas interesado en participar, puedes registrarte aquí.

Y un día no separamos (una historia de crecimiento orgánico)

Hasta aquí…

Comenzamos el proyecto con un equipo completamente nuevo. Según pasaron las iteraciones nos fuimos consolidando como equipo a la vez que sumamos nuevos miembros. De esta forma llegamos a completar la iteración 12 siendo 14 personas. Suficiente, hora de separarnos.

Previamente, allá por la iteración 7, había contado de la previsibilidad de este equipo, un propiedad que el equipo logró mantener a pesar de seguir creciendo. En términos generales, analizando las 12 iteraciones, vemos que la diferencia de trabajo planificado vs trabajo completado no supera el 18%. Esto significado que si este equipo planifica entregar 10 ítems, hay altas probabilidades que al final de la iteración haya completado al menos 8 ítems. El siguiente gráfico muestra el trabajo planificado vs. el trabajo completado para las últimas 3 iteraciones.

Creo que esta característica de previsibilidad es en gran medida consecuencia de un trabajo disciplinado y un crecimiento orgánico.

Algunas métricas de lo realizado hasta aquí:

  • 45 releases a producción
  • 6 meses de trabajo iterativo
  • 382 casos de prueba automatizados que incluyen pruebas unitarias, de integración y aceptación
  • Una cobertura de código superior al 80%

De aquí en más…

Separamos el equipo y separamos el código para permitir que cada equipo sea lo más autónomo posible, pudiendo regular su velocidad delivery sin dependencias. Cada equipo trabajará enfocado en su (sub)producto con sus propios repositorios, infraestructura, microservicio y microfrontend.

Ahora el gran desafío es ver si podemos lograr que ambos equipos mantengan el nivel de efectividad y desempeño logrado hasta el momento.

En un par de meses les cuento.

Adaptación online del Kanban Pizza Game

El Kanban Pizza Game es una actividad tipo simulación, utilizada para enseñar los principios Kanban e implica el trabajo con materiales de librería (papel, tijeras, pegamento, etc). Usualmente utilizamos esta actividad en la clase Lean/Kanban en MeMo2.

Ayer dimos esta clase y ante la imposibilidad de hacerla en forma presencial, debido a la situación de pandemia, decidimos adaptarla para hacerla en forma online. Para ello utilizamos la herramienta Miro.

La actividad salió muy bien, los alumnos dieron feedback muy positivo. Para los interesados aquí publicamos una breve guía de como preparar y facilitar la actividad.

No más cursos de TDD

Estaba escribiendo una respuesta a un tweet en un hilo sobre developer testing y espontáneamente tuve esta revelación: no dictar más cursos de Test-Driven Development.
Si bien no lo tenía listado en mi catálogo de cursos, tenía un curso de TDD que venia dictando en forma privada a pedido de algunas empresas. Pero ya no más. La cuestión es simple: TDD es muy difícil de aplicar en proyectos de complejidad no trivial para gente que recién empieza con TDD y no creo que un curso de 1 o 2 días pueda bastar para que alguien aprenda la técnica y esté en condiciones de aplicarla en un proyecto no trivial apenas terminado el curso. Pero ojo, esto no significa que vaya a dejar de enseñar TDD. No, de ninguna manera. Simplemente voy a cambiar de estrategia: voy compartir gratuitamente un par de videos explicando la técnica (o incluso tal vez recomiende cursos de colegas) y luego ofreceré a los interesados trabajar conjuntamente en su proyecto para aplicar TDD.

Si bien yo uso TDD en mis proyectos, me llevó años y mucha perseverancia poder hacerlo una forma fluida y eficiente. Pero como he dicho más de una vez no considero TDD como una práctica de «efectividad universal», a mi me resulta eficiente programar haciendo TDD, pero no significa que vaya a resultarle igual a todo el mundo. A mis alumnos les exijo que hagan TDD cuando programan para la materia porque es parte del plan de estudio. A mis compañeros de trabajo les sugiero que hagan TDD si es lo que hemos acordado como equipo, pero dependiendo del contexto me parece completamente válido que agreguen los tests a posteriori si no gustan hacer TDD.

Dicho esto, si quieren aprender TDD conmigo, no me consulten por cursos, contáctenme en privado y coordinemos directamente para hacer un par de sesiones de TDD sobre su proyecto.

DevOops! tal vez igual sirve

Hace un tiempo escribí sobre algunos malentendidos de DevOps en la práctica, hoy quiero compartir algunas otras situaciones a la luz de una definición formal.

De acuerdo a Len Bass y sus colegas del SEI DevOps tiene 5 pilares fundamentales:

  1. Operaciones como ciudadano de primera categoría en el proceso de software delivery
  2. Involucramiento de los desarrolladores en los incidentes productivos
  3. Un proceso formal de deployment
  4. Continuous Delivery
  5. Infrastructure as Code

Pero en la práctica veo que muchas organizaciones que:

  • Pasan completamente por alto los dos primeros puntos, son cuestiones casi «culturales» que no son triviales de cambiar.
  • Van directo al punto 5, incorporan herramientas para la automatización de infraestructura para lo cual contratan algunas nuevas personas, típicamente bajo del rol de «Ingenieros DevOps». Hacer esto es muy más simple que pretender cambiar una estructura organizacional o un mindset.
  • El punto 4 lo toman solo parcialmente, invierten en la automatización de pipelines de despliegue (tarea que hacen los recientemente incorporados «Ingenieros DevOps») pero ni noticia de la automatización de pruebas (claro, los DevOps no automatizan pruebas)
  • El punto 3 lo logran como un efecto colateral de la automatización de los despliegues.

El resultado dista bastante de la idea de DevOps de Bass, pero no es tan malo porque a pesar de ello representa una mejora radical respecto de la situación previa.

Continuous Delivery como una cinta transportadora

Hace un par de semanas en un reunión de trabajo mi colega Mariano explicó la práctica de Continuous Delivery como una analogía con una cinta transportadora y me pareció simplemente excelente.

Siendo estrictos con las definiciones Continuous Delivery implica Continuous Integration y Trunk-Based Development. Entonces:

  • El equipo hace commits pequeños, si hace TDD, posiblemente un commit por cada nueva prueba en verde.
  • Un funcionalidad/story requiere de varios commits.
  • Si el equipo trabaja simultáneamente en más de una funcionalidad es común que una funcionalidad se complete mientras otra está aún en desarrollo.
  • Si efectivamente hacen continuous delivery es posible que a penas se complete una funcionalidad se la quiera poner producción. Esto a su vez implicaría llevar a producción también las funcionalidades aún no completas.

De esta forma el proceso de continuous delivery es una cinta transportadora donde cada commit es como un paquete que uno pone en la cinta y la cinta lo lleva a producción.

Esto tiene un impacto muy grande en la forma del trabajo del equipo que obliga a tomar precauciones adicionales como puede ser el uso de feature toggles, de manera que si una funcionalidad no completa llega a producción, la misma pueda ser «toggleada/apagada».

Medición de cobertura en .Net Core con Coverlet

Luego de cumplir con los primeros hitos de negocio y teniendo un equipo que empieza a estabilizarse me puse a hacer algunas pruebas para medir la cobertura de nuestro proyecto.

En primera instancia atiné a utilizar OpenCover, una herramienta que había utilizado en proyectos anteriores, pero me encontré que solo corre en Windows. Nuestra infraestructura de build corre en Linux y yo particularmente trabajo en MacOS. Con lo cual OpenCover quedó descartado.

Luego de Googlear un poco dí con Coverlet que según la documentación es multiplataforma. Investigando un poco más encontré este artículo de Scott Hanselman y con eso me bastó para hacer una prueba. A continuación voy a compartir algunos descubrimiento que hice aprendiendo a utilizar esta herramienta.

En primer lugar tenemos que saber que hay tres formas de utilizar esta Coverlet:

  1. Como una extensión de dotnet-cli
  2. Como un collector integrado al motor de ejecución de VSTest
  3. Como una tarea de MSBuild

Yo decidí ir por esta última estrategia. Para ello el primer paso es agregar el paquete coverlet.msbuild a cada uno de los proyectos de tests. Una vez agregado este paquete simplemente tenemos que agregar el parámetro de cobertura al momento de la ejecución de los tests

dotnet add package coverlet.msbuild
dotnet test /p:CollectCoverage=true

Si tenemos un solo proyecto de tests que cubre todos los proyectos/assemblies de nuestra solución, con esto ya habrá sido suficiente. Al ejecutar los comandos anteriores obtendremos una salida como la que se muestra en la siguiente figura.

Pero si nuestra solución, como es muy habitual, tiene varios proyectos de tests nos vamos a encontrar que la medición que hace Coverlet es «parcial»/»desagregada». Ocurre que cada proyecto de tests es ejecutado ejecutado independientemente haciendo que la medición de cobertura también sea independiente lo cual a su vez hace que tengamos varios reportes de cobertura. Esto se puede observar en la siguiente figura.

El primer reporte corresponde al proyecto de tests de Domain y nos indica que precisamente Domain tiene una cobertura de ~79%.
El segundo reporte corresponde al proyecto de tests de ApiServices y como ApiServices depende de Domain, la medición de cobertura considera ambos proyectos. Pero dado que los tests de ApiServices apenas tocan el código de Domain, la cobertura informada sobre Domain es mínima (~6%). Entonces lo que deberíamos hacer para obtener el valor correcto de cobertura es mezclar el reporte de cobertura generado por el proyecto de tests de Domain y el proyecto de tests de ApiServices. Aquí también coverlet nos da varias opciones. En mi caso, lo que hice fue ejecutar explícitamente cada proyecto de test por separado, escribiendo los resultados en un archivo y en la misma ejecución indicándole a Coverlet que realice el merge con el archivo de cobertura de la ejecución anterior.

dotnet test Domain.Tests/Domain.Tests.csproj /p:CollectCoverage=true /p:CoverletOutput=../coverage.json

dotnet test ApiServices.Tests/ApiServices.Tests.csproj /p:CollectCoverage=true /p:CoverletOutput=../coverage.json /p:MergeWith=../coverage.json

De esta forma el reporte se genera correctamente.

Una situación habitual cuando medimos la cobertura es no incluir en el cálculo algunas archivos. En nuestro caso ocurre que consumimos servicios SOAP, y utilizamos una herramienta que nos genera un conjunto de clases proxy para interactuar con SOAP. Dichas clases son almacenadas en un archivo Reference.cs que queremos excluir del análisis de cobertura. Para esto debemos incluir un parámetro adicional para Coverlet en la ejecución de los test /p:ExcludeByFile=»**/Reference.cs».

Bien, con todo lo descripto hasta el momento hemos logrado medir el % de cobertura de nuestro código. Lo siguiente que suele hacerse es ver cuales son las partes de código sin cobertura. Si bien coverlet tiene la capacidad de detectar esto, no provee un mecanismo cómodo para visualizarlo y por ello debemos utilizar otra herramienta complementaria. Pero eso será parte de otro post.