Cos'è un feature flag: guida completa per ingegneri

Riassunto

Un feature flag è un'istruzione if il cui valore viene da configurazione o database, permettendo di attivare/disattivare comportamenti senza deploy. Essenziale per trunk-based development, rollout graduale e kill switch. Richiede disciplina: ogni flag è inventory con costo. Categorizzali per tipo (release, experiment, ops, permission), assegna owner e data di scadenza, rimuovili entro 90 giorni di inattività per evitare technical debt e bug silenzioso.

Scrivania di ingegnere con interruttori fisici a lato di un laptop

Cos'è un feature flag

Un feature flag è una condizione nel tuo codice che decide a runtime se attivare o disattivare un comportamento, senza un nuovo deploy. È tutto qui. Nella pratica, è un'istruzione if il cui valore proviene da una configurazione, una riga di database, o un servizio di flag invece di essere hardcoded. Il concetto è semplice. Convivere con 200 di questi in un repository no, e questa seconda parte è quello di cui parla davvero questa guida.

Cos'è un feature flag nel codice?

Ecco la versione più piccola e utile:

if (flags.isEnabled("new-checkout", { userId })) {
  return renderNewCheckout();
}
return renderOldCheckout();

Entrambi i percorsi di codice spediscono nella stessa build. Il valore del flag vive in qualcosa che puoi modificare senza fare il deploy: una variabile d'ambiente, un file JSON, una tabella, o un servizio. Cambi il valore, e il comportamento cambia al prossimo controllo.

Quella separazione è il punto. Fare il deploy è mettere il codice sui server. Il release è lasciare che gli utenti lo vedano. I flag dividono questi due eventi, quindi fare il merge su main non significa più "adesso tutti lo vedono".

Hand flipping a single toggle switch with a green indicator light

Perché i team usano i feature flag?

Tre motivi ricorrono ancora e ancora nei veri team di 5 a 50 ingegneri.

Niente di questo richiede un vendor. Un flag può essere un booleano in una tabella di config. Salta la piattaforma finché non hai bisogno di rollout percentuali, audit trail, o non-ingegneri che tolgano le spunte.

Quali sono i quattro tipi di feature flag?

L'articolo ampiamente citato di Pete Hodgson su feature toggles nel sito di Martin Fowler classifica i flag per quanto tempo vivono e quanto spesso la decisione cambia. Le categorie rimangono il modello mentale più chiaro.

La colonna del lifespan importa più di tutto. Un flag di release che outlive il suo release è un bug che non hai ancora trovato. Un flag di permission cancellato in uno sprint di cleanup è un outage che non hai ancora avuto.

Dai un nome e un'etichetta al tipo quando crei il flag. Tra sei mesi, nessuno ricorderà a quale categoria apparteneva "new-nav-v2".

Team planning grid of sticky notes grouped by category

Come fai il rollout di un flag senza fare male agli utenti?

La sequenza noiosa funziona meglio.

  1. Fai il ship del codice con il flag spento. Verifica che niente sia cambiato.

  2. Accendilo per il tuo team in produzione. Usalo per un giorno.

  3. Accendilo per l'1-5% degli utenti, sticky per user ID in modo che nessuno flippa tra varianti mid-session.

  4. Guarda il rate di errore, la latenza, e una metrica di business. Decidi la soglia prima di iniziare, non mentre guardi un dashboard.

  5. Scala al 100%, attendi un periodo definito, poi rimuovi il flag.

Il passo cinque è quello che i team saltano. Arriviamo a perché costa più di quanto pensi.

Una nota pratica sulla valutazione: rendi i flag reads economici e fail-safe. Se il flag service è down, il tuo codice ha bisogno di un default. Scegli il default per flag, di proposito. Un kill switch dovrebbe fallire a "safe", mentre una nuova feature dovrebbe fallire a "off".

Perché i feature flag diventano tech debt?

Ogni flag è un fork nel tuo codice. Due flag fanno quattro percorsi possibili, dieci flag fanno 1.024, e quasi certamente ne hai testato pochi. La guida di GrowthBook al flag debt cita ricerche che mostrano che circa il 75% dei toggle component erano ancora nelle codebase fino a 49 settimane dopo l'introduzione, anche se la maggior parte degli sviluppatori ha detto che pianificava di rimuoverli.

Hodgson la mette bene nello stesso articolo di Fowler: i team consapevoli trattano i toggle come inventory con un carrying cost, e lavorano per mantenere quell'inventory basso.

La storia di horror classica è Knight Capital nel 2012. Il flag di una feature ritirata fu riusato per un nuovo comportamento mentre il vecchio codice sedeva ancora su un server. Quel mismatch ha contribuito a circa 460 milioni di perdite in meno di un'ora. Il tuo flag stale probabilmente non farà così. Farà qualcosa di più silenzioso: un refactor che rompe un branch di cui nessuno sapeva che esistesse, o un nuovo hire che spende un pomeriggio a capire quale dei due checkout path è reale.

Dusty shelf of forgotten boxes and old switches

Come trovi ogni flag in una codebase esistente?

Questa è la domanda che i doc del vendor saltano, ed è dove la maggior parte dei team rimane bloccato. Il flag dashboard ti dice cosa è configurato. Non ti dice dove ogni flag è letto nel codice, o se il percorso di codice dietro un flag "off" è ancora raggiungibile.

Inizia con l'approccio economico:

# ogni literal flag key letto via il tuo wrapper
rg -n 'isEnabled\("' src/ | sort

# flag definiti ma mai referenziati
comm -23 <(jq -r 'keys[]' flags.json | sort) \
         <(rg -o 'isEnabled\("([^"]+)"' -r '$1' src/ | sort -u)

Questo crolla veloce. Flag key costruite da string concatenation non compaiono in grep. Flag passati attraverso helper function nascondono i loro call site. Monorepo e setup multi-repo moltiplicano il problema, perché la stessa key può essere letta da tre servizi.

È lì che leggere il codice con tooling aiuta. Code search tool che capiscono il tuo repo possono rispondere a "dov'è new-checkout valutato, e cosa dipende dal risultato?" in una query invece di un pomeriggio di grep. Cursor e GitHub Copilot se la cavano ragionevolmente dentro un repo. Attraverso vari repo, hai bisogno di un index che li spanni tutti, che è il caso per cui abbiamo costruito codebasechat.

Com'è un sano processo di pulizia dei flag?

Tratta la rimozione come parte del lavoro, non un compito per dopo.

L'analisi statica aiuta qui. Uno strumento come CodeScene può mostrare quali file portano il logic condizionale più aggrovigliato, che è di solito dove i vecchi flag si ammassano. SonarQube evidenzia il codice irraggiungibile e morto dopo che rimuovi un check.

Come testi il codice dietro un flag?

Il testing è la parte che nessuno budget. Con due percorsi per flag, la tua suite di test ha bisogno di coprire entrambi, almeno per i flag che proteggono il comportamento rischioso.

Mantienilo pratico. Testa gli stati on e off di ogni flag di release in unit test, iniettando il valore del flag invece di leggere un servizio live. Esegui una suite end-to-end contro la configurazione di produzione predefinita, perché è quello che gli utenti ottengono oggi. Poi esegui un secondo pass con il flag on per la feature che stai per rilasciare.

Non cercare di testare ogni combinazione. Con dieci flag non puoi. Invece, mantieni i flag indipendenti: un flag che cambia il comportamento solo quando un altro flag è anche on è un design smell, ed è la prima cosa da districare.

Quali errori fanno i nuovi ingegneri sui flag?

I junior tendono a fare gli stessi tre errori, e ciascuno è economico da prevenire in review.

Le prime due settimane di un nuovo hire sono esattamente quando incontra vecchi flag senza un owner. Un breve flag registry, con un tipo, un owner, e una data di rimozione per ogni entry, risparmi diverse ore di giro di domande.

Quando dovresti saltare i feature flag?

I flag non sono gratis, quindi saltali quando:

Usali senza esitazione quando un cambio è rischioso, rivolto all'utente, e difficile da invertire con il re-deploy. Payment flow, auth change, e tutto con una data migration dietro tutto si qualificherebbero.

Cosa faremmo davvero in un team di dieci

Inizia con un booleano in config e una funzione wrapper, quindi ogni lettura di flag passa attraverso un posto. Quel singolo choke point rende la lista di flag greppable, auditable, e facile da migrare a un servizio hosted più tardi.

Etichetta ogni flag per tipo, dagli un owner, e archiva il ticket di rimozione il primo giorno. Rivedi la lista mensilmente per dieci minuti. Cancella i flag che sono stati al 100% per due settimane.

Un feature flag è un prestito. Prendilo quando ti risparmia un rilascio rischioso, e pagalo indietro prima che l'interesse compaia nel tuo prossimo refactor.

Domande frequenti

Come si implementa un feature flag nel codice?
Un flag è un'istruzione if il cui valore proviene da configurazione, database o servizio. Entrambi i percorsi di codice spediscono nella stessa build, permettendo di cambiare il comportamento senza deploy.
Quali sono i 4 tipi di feature flag?
Release (giorni-settimane, ingegneri), Experiment (settimane, product/data), Ops (ore-sempre, on-call), Permission (mesi-anni, product/support). La categoria determina il lifespan e il processo di rimozione.
Perché i flag diventano technical debt?
Ogni flag è un fork nel codice. Con 10 flag hai 1.024 percorsi possibili, quasi impossibili da testare tutti. Il 75% dei toggle rimane in codebase fino a 49 settimane dopo l'introduzione.
Come evitare il flag debt?
Crea il ticket di rimozione con il flag. Assegna owner e data di scadenza (90 giorni di inattività = trigger di review). Rimuovi in due PR piccole. Aggiungi test time bomb. Metti un cap al totale.
Quando saltare i feature flag?
Quando il cambio è piccolo, reversibile, e un deploy lontano dal rollback. Usali invece per payment flow, auth change, data migration e qualunque release rischioso.