Feature Flag è una tecnica di sviluppo in cui la funzionalità dell'applicazione viene attivata o disattivata tramite interruttori condizionali in fase di esecuzione, senza distribuire nuovo codice. Invece dell'approccio tradizionale “commit — deploy”, i feature flags consentono di separare il momento della distribuzione dal momento dell'attivazione della funzionalità. Secondo LaunchDarkly (2024), i team che utilizzano feature flags riducono i tempi di lancio delle nuove funzionalità del 40%. I Feature flags sono diventati un elemento essenziale di CI/CD per le applicazioni mobili e web moderne.
Punti chiave
Feature Flag (feature toggle) è un meccanismo che consente di modificare il comportamento dell'applicazione senza modificare il codice. Nella sua forma più semplice, è una costruzione condizionale che verifica il valore del flag prima di eseguire una nuova funzionalità. Il flag può essere memorizzato in un file di configurazione, database o servizio esterno e modificato in tempo reale. Questo approccio offre ai team la possibilità di inviare codice non completato nel ramo principale senza il timore che raggiunga gli utenti prima del completamento dello sviluppo.
Lo scopo principale dei feature flags è separare la distribuzione dal rilascio. La distribuzione è il processo di posizionamento del codice su un server o in un app store. Il rilascio è il momento in cui la funzionalità diventa disponibile per l'utente. Senza feature flags, questi eventi coincidono: il codice va in produzione — gli utenti lo vedono. Con i feature flags, il codice può essere distribuito in produzione settimane prima del rilascio, attivato per test interni o implementato gradualmente al pubblico. Questo è fondamentale per il trunk-based development e il continuous delivery.
Considera un'implementazione base di feature flag in un'applicazione mobile Kotlin. Il flag è memorizzato in Firebase Remote Config e caricato all'avvio dell'app. A seconda del valore del flag, viene visualizzata la schermata del profilo vecchia o nuova. Questa implementazione consente di pubblicare una nuova versione del profilo senza pubblicare un aggiornamento sull'App Store — basta cambiare il valore nella console Firebase.
class ProfileFeature {
private val flags = FeatureFlagProvider()
private val profileFlag = FlagKey("new_profile_enabled")
fun getProfileScreen(): Screen {
return if (flags.isEnabled(profileFlag)) {
NewProfileScreen()
} else {
LegacyProfileScreen()
}
}
}
class FeatureFlagProvider {
fun isEnabled(key: FlagKey): Boolean {
val raw = Firebase.remoteConfig.getString(key.name)
return raw.toBoolean()
}
}
Non tutti i feature flags sono uguali. La classificazione di Martin Fowler identifica quattro tipi di flag, che differiscono per scopo d'uso, durata e requisiti di gestione. Una corretta classificazione dei flag aiuta a scegliere l'infrastruttura giusta ed evitare problemi comuni.
I Release toggles sono il tipo più comune di flag. Vengono utilizzati per nascondere funzionalità incomplete in produzione. Lo sviluppatore invia codice avvolto in un flag nel ramo principale e completa gradualmente la funzionalità. Dopo il completamento e i test, il flag viene attivato per tutti gli utenti. Il ciclo di vita di tale flag varia da alcuni giorni a due settimane. Dopo il rollout completo, il flag viene rimosso dal codice. I Release toggles sono la base del trunk-based development.
Gli Experiment toggles funzionano in combinazione con i test A/B. Non si limitano ad attivare o disattivare funzionalità, ma indirizzano l'utente a uno dei gruppi sperimentali. Questi flag spesso supportano regole di targeting complesse (per regione, versione del sistema operativo, abbonamento) e l'integrazione con sistemi di analisi. Gli Ops toggles vengono utilizzati per il controllo operativo — ad esempio, disattivare una funzione pesante sotto carico elevato o spegnere temporaneamente un modulo problematico senza distribuzione immediata. Gli Ops toggles devono essere il più veloci e affidabili possibile, poiché da essi dipende la stabilità del servizio.
| Tipo | Durata | Dinamica | Scopo |
|---|---|---|---|
| Release | Giorni-settimane | Statico | Nascondere codice incompleto |
| Experiment | Giorni-mesi | Dinamico | Test A/B e rollout |
| Ops | Ore-giorni | Dinamico | Controllo operativo |
| Permission | Mesi+ | Statico | Controllo accessi |
La gestione dei feature flags è una disciplina separata che include archiviazione, configurazione, monitoraggio e audit dei flag. Senza un sistema di gestione, i flag si trasformano in debito tecnico incontrollabile che rallenta lo sviluppo. Esaminiamo gli aspetti chiave della gestione utilizzando un sistema di produzione come esempio.
Ogni feature flag attraversa quattro fasi: creazione, utilizzo, stabilizzazione e rimozione. Nella fase di creazione vengono definiti la chiave del flag, il tipo e il valore predefinito. Durante l'utilizzo, il team monitora chi ha attivato il flag, per quale pubblico e con quale scopo. Dopo la stabilizzazione (funzionalità completamente pronta e testata), il flag deve essere rimosso dal codice. Il processo di rimozione viene automatizzato tramite la revisione del codice: il CI verifica che tutti i flag attivati al 100% per gli utenti abbiano un'attività di rimozione.
I feature flags dovrebbero essere archiviati centralmente, non sparsi nei file di configurazione di ciascun servizio. Idealmente — un servizio dedicato con interfaccia utente (LaunchDarkly, Unleash). Un'opzione minimamente accettabile è un file JSON di configurazione nel repository con revisione del codice per le modifiche. Un database per memorizzare i flag è meno preferibile perché richiede un'interfaccia di gestione separata. Ogni flag dovrebbe avere un proprietario (team o sviluppatore specifico), una descrizione e una durata (TTL). L'audit regolare dei flag obsoleti è una pratica obbligatoria, automatizzata tramite un'attività CI che verifica i flag invariati per più di N giorni.
Il mercato degli strumenti di gestione dei feature flags include sia piattaforme commerciali con ciclo di gestione completo, sia soluzioni open-source per l'auto-distribuzione. La scelta dello strumento dipende dalle dimensioni del team, dai requisiti di latenza e dalla conformità.
LaunchDarkly è il leader di mercato con SDK per tutti i linguaggi e le piattaforme più diffusi (iOS, Android, Web, Backend). Supporta multi-ambiente, targeting basato su regole, esperimenti A/B e rimozione automatica dei flag. Split è un'alternativa focalizzata su funzionalità enterprise: accesso basato sui ruoli, log di audit e conformità (SOC2, HIPAA). ConfigCat è una soluzione più leggera e accessibile, adatta a team piccoli. Tutte le piattaforme forniscono SDK con caching dei valori e impatto minimo sulla latenza dell'applicazione.
Unleash è la soluzione open-source più popolare con interfaccia utente, API e SDK per tutte le principali piattaforme. Supporta strategie di attivazione, contesti personalizzati e integrazione con Prometheus per il monitoraggio. Flagsmith è un'alternativa con test A/B integrati e gestione degli ambienti. Le soluzioni open-source richiedono distribuzione e manutenzione dell'infrastruttura, ma offrono il controllo completo sui dati e non hanno restrizioni di licenza. Per le applicazioni mobili, entrambe le soluzioni forniscono SDK nativi con caching offline dei valori dei flag.
I feature flags sono uno strumento potente, ma senza disciplina creano debito tecnico e complicano il codice. Martin Fowler e gli ingegneri di LaunchDarkly hanno formulato una serie di pratiche che aiutano a ottenere il massimo beneficio dai feature flags senza conseguenze negative. Esaminiamo le raccomandazioni principali per i sistemi di produzione.
Ogni feature flag che non è stato rimosso dopo il completamento del rollout diventa debito tecnico. Uno studio di LaunchDarkly (2024) ha mostrato che in media il 30–40% dei flag rimane nel codice dopo che non sono più necessari. Soluzione: implementare la regola “un flag — un'attività”. Quando si crea un flag, viene creata un'attività di rimozione con scadenza nel task tracker. Il CI verifica che non ci siano flag attivati al 100% per più di 30 giorni. La revisione del codice deve verificare non solo l'aggiunta ma anche la rimozione dei flag.
I feature flags creano complessità combinatoria per i test: ogni flag raddoppia il numero di possibili stati dell'applicazione. Per gestire questa complessità, vengono utilizzati test matriciali che verificano tutte le combinazioni di flag e test di integrazione di commutazione dei flag. Viene aggiunto un passo alla pipeline CI che esegue test con diverse combinazioni di valori dei flag. Per i flag critici (ops toggles), i test di carico sono obbligatori per verificare che la commutazione del flag non causi picchi di latenza o errori.
class FeatureFlagService:
def __init__(self, storage):
self.storage = storage
def is_enabled(self, flag_key, user_context):
flag = self.storage.get(flag_key)
if not flag:
return False
for rule in flag["rules"]:
if self._match_rule(rule, user_context):
return rule["value"]
return flag["default"]
def _match_rule(self, rule, context):
return (
rule["percentage"] > self._hash(context.user_id)
)
Domande frequenti
I termini sono spesso usati come sinonimi, ma c'è una sfumatura: feature flag di solito si riferisce a un sistema più maturo con gestione centralizzata, interfaccia utente e SDK, mentre feature toggle è un semplice interruttore binario nel codice. Martin Fowler usa feature toggle come termine generale, ma nel settore, feature flag è più spesso associato a piattaforme commerciali (LaunchDarkly, Split).
L'impatto sulle prestazioni è minimo con una corretta implementazione. Best practice: memorizzare nella cache i valori dei flag in memoria con un TTL di 30–60 secondi, evitare chiamate HTTP sincrone durante la verifica di un flag, utilizzare SDK con cache locale e sincronizzazione in background. Secondo LaunchDarkly, la latenza p99 del loro SDK è inferiore a 5 ms, il che è trascurabile per la maggior parte delle applicazioni.
I feature flags non sono raccomandati per modificare la logica di business in operazioni finanziarie critiche dove è importante sapere esattamente quale codice viene eseguito. Evitare anche i flag per funzioni di sicurezza (autorizzazione, crittografia) — la disattivazione di tale flag crea una vulnerabilità. Per i cambiamenti infrastrutturali (migrazione del database, migrazione a nuova architettura), i feature flags sono utili ma richiedono test particolarmente approfonditi.
L'approccio principale è il test matriciale: eseguire test con tutte le combinazioni di flag. Per CI/CD questo può essere troppo costoso (2^n combinazioni), quindi nella pratica tutti i flag vengono testati individualmente in entrambi gli stati (on/off) e vengono testate solo le combinazioni critiche. I test unitari dovrebbero simulare il valore del flag. I test di integrazione verificano scenari specifici con valori di flag noti. I test E2E coprono le combinazioni più probabili.
Il processo di rimozione: 1) assicurarsi che il flag sia attivato al 100% per tutti gli utenti e non sia utilizzato in modalità esperimento; 2) rimuovere tutti i controlli condizionali del flag dal codice, mantenendo solo il ramo “nuovo”; 3) rimuovere la definizione del flag dal sistema di gestione; 4) aggiornare i test rimuovendo i mock per il flag rimosso. Si consiglia di automatizzare questo processo tramite CI: i flag invariati per più di N giorni vengono contrassegnati come obsoleti e richiedono conferma di rimozione.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche