Si sos de los que quieren mover rápido sin romper producción, las feature flags te van a encantar. La idea es simple: separás el despliegue del “encendido” de una funcionalidad. Subís el código hoy, pero lo activás mañana (o a un grupo pequeño) con un interruptor desde Azure App Configuration. En este post te cuento, en tono bien humano, cómo funciona todo y cómo armar una demo con Flask + Jinja + Bootstrap que vas a poder mostrar en minutos.

Repositorio del proyecto:


FeatureFlagRepo

 

¿Qué es una feature flag y por qué te conviene?

  • Pensalo como un interruptor remoto. La app consulta a Azure: “¿Esta función va ON u OFF?”. Con eso podés:
  • Lanzar gradualmente (canary): encendés para un 10%, luego 50%, y así.
  • Tener un kill-switch: si algo falla, apagás la función sin redeploy.
  • Hacer A/B testing sin complicarte con ramas o despliegues paralelos.
  • Para vos, como Dev o DevOps, esto significa menos riesgo y más velocidad. No esperás ciclos de deploy para mostrar (o esconder) algo.

 

¿Qué vamos a construir?

como dirian en mi tierra ... vamos me suena a manada ajjaaj

Una app mínima en Flask con una única plantilla index.html. Cuando la feature flag SurveyON está OFF, se ve una pantalla elegante que explica que la encuesta no está disponible. Cuando está ON, aparece un formulario de encuesta (demo) hecho con Bootstrap. Nada se envía, pero alcanza perfecto para demostrar el concepto y la experiencia de usuario.

¿Cómo conversa tu app con Azure?

  • Vos guardás las flags en Azure App Configuration. En tu app, usás el provider de Azure para traer esa info y un FeatureManager para preguntar si una flag está activa. El flujo es más o menos así:
  • Llega una request a /.
  • Tu app hace un chequeo rápido con config.refresh().
  • Si corresponde, el provider trae los cambios desde Azure; si no, usa caché.
  • Le preguntás al FeatureManager si SurveyON está encendida.
  • Renderizás index.html con una variable (survey_on=True/False) y Jinja decide qué mostrar.



“Contámelo fácil”: ¿qué hace config.refresh()?

Mirá: tu app guarda una copiecita local de las flags. Cada vez que llamás a config.refresh(), la app pregunta: “¿cambió algo en Azure?”.

  • Si pasaron al menos 10 segundos desde el último chequeo (porque configuraste refresh_interval=10) o si usás una clave sentinel que cambiaste, actualiza esos valores.
  • Si no pasaron esos 10 s y no tocaste la sentinel, no hace nada y sigue con la caché.
  • Traducción: es un ping rápido, no es un “esperar 10 s”. Decide si ir a buscar cambios o no, y listo.

 

¿Cómo se ve por dentro? (visión rápida de código)
Estructura mínima

your-app/
 app.py
 --> templates/
   ----> index.html


Backend (Flask)

  1. Pasos para probarlo ya
  2. Creá un recurso de App Configuration en Azure.
  3. En Feature Manager, creá la flag SurveyON (dejala OFF).
  4. Corré la app: python app.py y abrí http://localhost:5000.
  5. Vas a ver la pantalla OFF.
  6. En Azure, poné SurveyON en ON.
  7. Recargá el navegador: si ya pasaron 10 s desde el último chequeo, vas a ver la encuesta.

 

Acá creás el provider, el FeatureManager y la ruta principal. Leés el connection string desde una variable de entorno (en demo podés dejarlo inline, pero no lo subas al repo), recuerda usar la misma template que usamos en el video:

# app.py
import os
from flask import Flask, render_template
from featuremanagement import FeatureManager
from azure.appconfiguration.provider import load

APP_CONFIG_CONNECTION_STRING =APP_CONFIG_CONNECTION_STRING", "Endpoint=...;Id=...;Secret=..."

app = Flask(__name__)

config = load(
    connection_string=APP_CONFIG_CONNECTION_STRING,
    refresh_interval=10,                 # usa caché por 10s entre chequeos
    feature_flag_enabled=True,
    feature_flag_refresh_enabled=True
)

feature_manager = FeatureManager(config)

@app.route("/")
def index():
    # Chequeo rápido: si corresponde, refresca desde Azure; si no, usa caché
    try:
        config.refresh()
    except Exception:
        pass

    survey_on = feature_manager.is_enabled("SurveyON")
    return render_template("index.html", survey_on=survey_on)

if __name__ == "__main__":
    app.run(debug=True, port=5000)