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.

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”.

Estructura de equipo para desarrollo de producto

Desde hace un tiempo estoy trabajando un equipo de producto de más de 20 personas y estamos organizados en una estructura que es nueva para mi pero que al mismo tiempo me parece viene resultando efectiva. La siguiente figura resume esta estructura.

Si bien todo el equipo de producto son más de 20 personas, en el día a día estamos divididos en 4 equipos: 3 feature teams y 1 equipo de toolsmiths (este nombre lo tomé del enfoque FDD, pero no es el nombre real del equipo)

Los 3 feature teams trabajan en funcionalidades del producto y están en el día a día con gente de negocio.

El equipo de toolsmiths es donde yo trabajo. Actuamos como proveedores/facilitadores de los features teams y nos encargamos de mantener/optimizar la infraestructura de desarrollo: repositorios, build server, ambientes, etc. Incluso en ocasiones agregamos código al producto, pero obviamente relacionado a cuestiones de soporte/infra como feature flags, health endpoints, etc. Como parte de nuestro trabajo tenemos que interactuar con otros grupos de soporte organizacional que se encargan de infraestructura de base y regulaciones (seguridad, red, etc). En el equipo somos 3 personas con skills mixtos: podemos codear, agregar tests, configurar servers, scriptear infraestructura pero sobre todo podemos hablar con otros grupos y generar concenso. Alguien podría tentarse de decir que somos DevOps, pero no lo vemos así, porque de entrada no creemos que DevOps sea ni un rol ni un área, sino un mindset con un conjunto de prácticas.

No se si este es el mejor enfoque para la estructura de un equipo de producto, pero consideramos que nos viene resultando bien: el negocio está contento, los distintos equipos están contentos, el producto está estable y tenemos la capacidad de ir a producción bajo demanda y de forma altamente automatizada.

Optimizando el pipeline de deployment – primeros resultados

A partir de la situación inicial previamente descripta, tuvimos que hacer algunos ajustes adicionales a lo esperado pero finalmente logramos paralelizar la pruebas de aceptación.

Logramos una mejora de ~30 % en el tiempo de ejecución del pipeline completo. La mejora es buena pero creemos que podemos mejorarlo aún más ya que en este momento los dos sets de pruebas automatizadas que hemos paralelizado se ejecutan dentro del mismo nodo de Jenkins compitiendo por recursos físicos.

Una mejora posible a esto es agregar un nuevo nodo Jenkins que permita que cada set de pruebas se ejecute con recursos físicos independientes.

Finalmente hay otra serie de posibles mejoras a experimentar pero que requieren trabajo ya a nivel código y por ello son más intrusivas en el día a día del equipo de desarrollo.

Optimizando el pipeline de deployment

Esta semana empezamos a trabajar con @CodeRaguet y Maxi Cruz en la tarea de optimizar el pipeline de deployment. Actualmente tenemos un pipeline de deployment que hace lo siguiente:

  1. Ante cada cambio en el repositorio obtiene el código
  2. Compila y corre las pruebas unitarias
  3. Despliega a un ambiente que “de integración”
  4. Corre las pruebas de aceptación
  5. Publica los artefactos
  6. Publica los pactos (pact)
  7. Despliega a un ambiente “de demo” donde la aplicación queda disponible para pruebas manuales

La ejecución de este pipeline insume actualmente ~45 minutos y el ~85 % de ese tiempo de ejecución lo consume el paso 4: la ejecución de los tests de aceptación.

Este pipeline representa la primera parte del camino hacia producción y se ejecuta varias veces al día ya que el equipo hace trunk-based development (todos trabajan en master). A continuación de este pipeline hay otro que se dispara manualmente que cubre los ambientes de tests y producción.

Un detalle no menor de esta situación es que si no hacemos nada esta situación va a empeorar gradualmente porque el producto está en constante evolución y todo el tiempo se van a agregando nuevos tests.

El desafió que enfrentamos es reducir el tiempo que insume este pipeline y por ende el tiempo que insume la ejecución de las pruebas aceptación. La estrategia que vamos a intentar implementar es: segmentar los tests de aceptación por grupos de funcionalidades y luego ejecutar cada grupo en paralelo.

En una semana les cuento como nos fue.

Manejo de parámetros de deployment en Jenkins

Al implementar un pipeline de deployment suele surgir la necesidad de usar algunos parámetros como ser credenciales para conexión a un server, alguna API Key para interactuar con un cloud provider, etc.

Hay varias formas de manejar esto cuando trabajamos con Jenkins. Hoy quiero compartir una forma que me parece elegante y simple a la vez.

La propuesta es utilizar el soporte de Credenciales que ofrece Jenkins. Para esto vamos a Credentials > Global > Add Credentials.

En la pantalla de agregado de Credenciales elegimos el tipo de credencial que queremos agregar. En este ejemplo voy a elegir una credencial del tipo Secret Text pues quiero guardar un simple API token.

Con esto ya hemos almacenado nuestra credencial en Jenkins. El campo ID es el que utilizaremos a posteriori para referenciar esta credencial.

La forma de usar esta credencial varia dependiendo del tipo de credencial (en este caso es Secret Text) y del “lugar” desde donde querramos accederla por ejemplo si es un FreeStyle job o un Pipeline job.

Para usar esta credencial desde un pipeline job se puede usar el siguiente snippet.

Para usar este credencial desde un FreeStyle job, primero bindeamos la credencial a una variable y luego utilizamos directamente la variable.

Un detalle no menor de esta estrategia es que cuando se ejecuta el job el valor de la credencial es enmascarado.

Servidores CI/CD: diferencias de modelos, Jenkins vs CircleCI

Servidores CI/CD: diferencias de modelos, Jenkins vs CircleCI

Jenkins es una de las herramientas de CI/CD más difundidas, posiblemente por su potencia y también por su larga historia (su primera versión es de 2005). Yo empecé a utilizarlo allá por 2008 cuando aún era Hudson. Inicialmente era un servidor de integración continua. Luego con el auge de la entrega continua se lo empezó a utilizar para hacer deployments. Esta última característica cobró más impulso a partir de la versión 2.

CircleCI es una herramienta de aparición mucho más reciente y viene a resolver el mismo problema que Jenkins pero con un modelo distinto.

En este post decidí hablar concretamente de Jenkins y Circle porque hoy en día estoy trabajando en dos proyectos, cada uno con una de estas herramientas. Pero en realidad es que en lugar de Circle podría referirme a Travis o a los Builders de Gitlab, pues conceptualmente representan el mismo modelo. Del mismo modo, en lugar de Jenkins podría hablar de Bamboo.

Veamos entonces algunas diferencias de estos dos modelos. CircleCI funciona atado a un repositorio Git (puede ser GitHub, BitBucket o algún otro). Al mismo tiempo, el funcionamiento de la herramienta está definido por un archivo (en formato yaml) donde uno define sus Jobs/Workflows. Si bien la herramienta provee una interface gráfica web, la misma es principalmente para visualización y solo permite ajustar algunos pocos settings, pero no permite la creación de Jobs. La situación es análoga al utilizar Travis o GitLab. Este modelo va muy bien con las estrategias del tipo GitOps, donde todo el pipeline de delivery se articula a partir de operaciones/eventos Git.

Por otro lado, Jenkins ofrece un modelo distinto, uno puede crear jobs asociados a distintos tipos de repositorios o incluso permite crear jobs sin asociación alguna a repositorios. Al mismo tiempo ofrece una interface de usuario web que permite manipular completamente la herramienta, de hecho, durante mucho tiempo esta era la única opción. Luego fueron apareciendo distintas opciones/plugins que posibilitaron tener un manejo similar al de Circle/Travis.

En otra dimensión de análisis podríamos decir que el modelo de Circle/Travis es en cierto modo “CI/CD as a Service”. Son herramientas muy enfocadas en CI/CD con toda una serie de cuestiones de diseño ya tomadas de antemano. De hecho en general el modelo de extensibilidad de estas herramientas es bastante limitado.

Por su parte Jenkins surgió inicialmente en modelo más On-Premises/Producto, contando desde su inicio con un modelo muy potente de extensibilidad y luego fue evolucionando incorporando características de los modelo más SaaS. La arquitectura extensible de Jenkins ha posibilitado la aparición de nuevos proyectos montados sobre Jenkins como ser JenkinsX.

Personalmente me siendo muy a gusto trabajando con Jenkins, creo que es un producto muy versátil y lo he utilizado para algunas cosillas más allá de CI/CD. Al mismo tiempo que creo en un contexto organizacional Jenkins ofrece varias características y posibilidades de extensibilidad no presentes en el otro modelo. Entre las bondades de Jenkins podría nombrar la integración con muchísimas herramientas, las capacidades de templating, slicing configuration y la posibilidad de generar plugins en caso que uno lo necesite (lo he hecho y no pareció complicado). Sin embargo y a pesar de mi gusto por Jenkins, creo que la característica de Pipeline as Code (jenkinsfile) no está lo suficientemente lograda. Perdón, creo que la funcionalidad está bien, pero personalmente me siento más a gusto utilizando un set de plugins tradicionales (como JobDSL, el JobBuilder y BuildPipeline) que usando los Jenkinsfile.

HOY: Patrones de Infraestructura para Continuous Delivery

Esta tarde a partir de las 18.50 estaré en la oficinas de RyanAir Madrid, exponiendo sobre esta temática.

De paso, voy a aprovechar el contacto con la comunidad ágil de Madrid para hacer difusión de algunos libros “Made in Argentina”. Voy a estar sorteando entre los participantes algunos ejemplares de “Construcción de Software, una mirada ágil” y “Experiencias ágiles, relatos de experiencias del uso de métodos ágiles en Argentina”.

Si están por Madrid y quieren sumarse, la entrada es gratis pero es necesario registrarse aquí.

Talleres segundo semestre 2017: DevOps, Continuous Delivery y Git

Para esta segunda mitad del año tengo planificado dictar los siguientes talleres:

  • Taller de Git, el martes 29 de Agosto, de 14 a 18 hs. en SADIO.
  • Taller de Continuous Delivery y Prácticas DevOps,  es un taller de 8 horas que dictaré el 15 de Septiembre en Kleer@Montevideo y el 3 de Octubre en Kleer@Argentina. El siguiente video explica brevemente el contenido del taller.

 

Notas del Meetup sobre Patrones de Infraestructura para Continuous Delivery

Si bien había más de 100 inscriptos la cantidad de participantes fue alrededor de 30, lo cual es está dentro de los parámetros esperados para los Meetup gratuitos de Agiles@Baires. La mayoría de los asistentes eran desarrolladores (~80%) y el resto se repartía entre gente de operaciones/sysadmins y gente de gestión. La audiencia estuvo muy participativa, hubo varias consultas e incluso algunos participantes hicieron aportes desde su propia experiencia.

A mi gusto la sesión fluyó muy bien, sobre todo considerando que fue la primera vez que la hice. Fueron alrededor de 80 minutos de exposición, con algunas preguntas intercaladas, y otros 20 minutos dedicados exclusivamente a consultas. De cara a la presentación en Agile, voy a tener que hacer varios ajustes y practicar un poco más, ya que el límite de tiempo que tengo es de 75 minutos y al mismo tiempo al ser una sesión en inglés es posible que no tenga tanta soltura en la oratoria.

Agradezco a todos los participantes por el feedback y les dejo aquí los slides utilizados.