Feature flags en Go : quand chaque ligne de code est un risque
\n\nAvez-vous déjà été réveillé à 3 heures du matin parce qu'une nouvelle release a « tué » la production ? Ou avez-vous passé des heures à annuler des modifications parce qu'une nouvelle fonctionnalité a cassé la logique de l'ancienne ? Cela vous parle ? Alors les feature flags (drapeaux de fonctionnalités) sont ce qui va radicalement changer votre vie en tant que développeur Go.
\n\nLes feature flags ne sont pas simplement des « if-else » dans le code. C'est une philosophie de releases sécurisées. C'est la possibilité d'activer et de désactiver des fonctionnalités sans déploiement, de réaliser des tests A/B et de faire des canary releases. Dans le monde de Go, où la vitesse et la fiabilité sont les priorités absolues, les feature flags deviennent un outil incontournable.
\n\nQue sont les feature flags et pourquoi en avez-vous besoin en Go ?
\n\nUn feature flag (aussi appelé toggle, drapeau de fonctionnalité) est un mécanisme qui permet d'activer ou de désactiver une fonctionnalité spécifique d'une application sans modifier le code ni redéployer. En termes simples : vous écrivez du code, vous l'enveloppez dans une condition, et si le flag est actif, le code s'exécute ; sinon, il est ignoré.
\n\nEn Go, où la compilation en binaire statique et l'architecture minimaliste sont la norme, les feature flags résolvent plusieurs problèmes à la fois :
\n\n- \n
- Réduction du risque des releases — vous avez déployé une fonctionnalité, mais quelque chose s'est mal passé ? Il suffit de désactiver le flag. Sans annulation, sans nouveau déploiement. \n
- Tests A/B — montrez la nouvelle version à seulement 10 % des utilisateurs, comparez les métriques. \n
- Canary releases — activation progressive d'une fonctionnalité pour différents groupes d'utilisateurs. \n
- Dark launches — le code est déjà en production, mais caché. Permet de tester les intégrations sans impact sur les utilisateurs. \n
- Gestion des dépendances — activez une fonctionnalité uniquement lorsque l'infrastructure backend est prête. \n
Comment implémenter les feature flags en Go : du simple au complexe
\n\n1. La méthode la plus simple : constantes et variables d'environnement
\n\nCommençons par les bases. L'option la plus primitive, mais fonctionnelle, consiste à utiliser des constantes globales ou des variables d'environnement. Convient pour un MVP ou lorsque la dynamique n'est pas nécessaire.
\n\npackage main\n\nimport (\n "fmt"\n "os"\n)\n\nconst NewCheckoutFlowEnabled = false\n\nfunc main() {\n envFlag := os.Getenv("FEATURE_NEW_PAYMENT")\n isPaymentEnabled := envFlag == "true"\n\n if isPaymentEnabled {\n fmt.Println("Nouvelle passerelle de paiement active")\n processNewPayment()\n } else {\n fmt.Println("Ancienne passerelle de paiement utilisée")\n processOldPayment()\n }\n}\n\nfunc processNewPayment() {\n fmt.Println("Traitement via Stripe API v3")\n}\n\nfunc processOldPayment() {\n fmt.Println("Traitement via Stripe API v2")\n}\n\nLes inconvénients sont évidents : pas de gestion dynamique, nécessité de redémarrer l'application. Mais pour des scénarios simples, cela convient.
\n\n2. Approche structurée : votre propre gestionnaire de flags
\n\nLorsque le nombre de flags dépasse 5, il est temps d'extraire la logique dans un package séparé. Créons un gestionnaire de feature flags simple avec un stockage en mémoire.
\n\npackage feature\n\nimport (\n "sync"\n "time"\n)\n\ntype Flag struct {\n Name string\n Enabled bool\n UpdatedAt time.Time\n}\n\ntype Manager struct {\n mu sync.RWMutex\n flags map[string]Flag\n}\n\nfunc NewManager() *Manager {\n return &Manager{\n flags: make(map[string]Flag),\n }\n}\n\nfunc (m *Manager) IsEnabled(name string) bool {\n m.mu.RLock()\n defer m.mu.RUnlock()\n flag, exists := m.flags[name]\n return exists && flag.Enabled\n}\n\nfunc (m *Manager) Enable(name string) {\n m.mu.Lock()\n defer m.mu.Unlock()\n m.flags[name] = Flag{\n Name: name,\n Enabled: true,\n UpdatedAt: time.Now(),\n }\n}\n\nfunc (m *Manager) Disable(name string) {\n m.mu.Lock()\n defer m.mu.Unlock()\n m.flags[name] = Flag{\n Name: name,\n Enabled: false,\n UpdatedAt: