Feature flags : livrer plus vite sans fabriquer une dette technique
Une feature est prête dans le code. Mais cela ne veut pas forcément dire qu'elle doit être visible par tous les utilisateurs.
C'est tout l'intérêt des feature flags, aussi appelés feature toggles : contrôler le comportement d'une application au moment de l'exécution, sans redéployer le code. On peut livrer une fonctionnalité à l'équipe interne, à un groupe de clients, puis à tout le monde, en observant ce qui se passe à chaque étape.
Le mécanisme est simple. Sa gestion ne l'est pas.
Un feature flag bien conçu réduit le risque d'une mise en production. Un flag laissé dans le code pendant des mois devient une branche conditionnelle de plus à tester, à comprendre et à maintenir. Le problème n'est donc pas de savoir s'il faut utiliser des feature flags, mais de savoir pourquoi chaque flag existe, qui le contrôle, et quand il doit disparaître.
Déploiement et mise en ligne sont deux décisions différentes
Sans feature flag, le chemin est généralement direct : on fusionne le code, on déploie, la fonctionnalité devient accessible. Le déploiement technique et la mise à disposition pour les utilisateurs arrivent au même moment.
Avec un flag, ces décisions sont séparées :
- le code est déployé avec la fonctionnalité désactivée ;
- l'équipe vérifie que l'application démarre et que le nouveau chemin reste isolé ;
- la fonctionnalité est activée pour une cible définie ;
- les métriques, les erreurs et les retours sont observés ;
- l'exposition est élargie, ou le flag est désactivé si le comportement pose problème.
Cette séparation est particulièrement utile pour une startup ou une PME qui ne dispose pas d'une grande marge d'erreur opérationnelle. Elle évite de faire du déploiement un moment irréversible et permet de revenir à un comportement connu sans reconstruire toute la release.
Mais un feature flag n'est pas un rollback. Il ne remet pas la base de données dans son état précédent, ne supprime pas les données déjà écrites et ne corrige pas automatiquement un changement incompatible. C'est un contrôle de comportement, pas une machine à remonter le temps.
Quatre usages, quatre règles de gestion
Traiter tous les flags comme de simples interrupteurs on/off finit par créer de la confusion. La première discipline consiste à les classer selon leur objectif.
Le flag de release
Il sert à terminer ou vérifier une fonctionnalité sans la rendre visible à tout le monde. Sa durée de vie doit être courte. Une fois la fonctionnalité validée et exposée, le flag doit être supprimé, ainsi que l'ancien chemin de code si celui-ci n'est plus nécessaire.
C'est le flag le plus souvent oublié. Il est créé au début du développement et personne ne prend explicitement la responsabilité de son retrait.
Le flag d'expérimentation
Il sert à comparer des variantes auprès de groupes d'utilisateurs. Dans ce cas, il faut définir à l'avance l'hypothèse testée, la population concernée, la durée de l'observation et le critère de décision.
Une expérimentation sans métrique de sortie n'est pas une expérimentation. C'est une fonctionnalité permanente avec un nom plus élégant.
Le flag opérationnel
Il permet de désactiver temporairement une partie coûteuse ou fragile du système, par exemple une intégration externe non essentielle. Il se rapproche d'un coupe-circuit et peut avoir une durée de vie longue, à condition d'être documenté dans les procédures d'exploitation.
Ce type de flag doit être accessible quand le service est dégradé. S'il dépend du même composant que la fonctionnalité qu'il est censé protéger, il ne remplira pas son rôle pendant un incident.
Le flag de permission
Il contrôle l'accès à une capacité selon un plan, une organisation, un rôle ou une phase de lancement. Il peut être durable, mais il ne doit pas remplacer l'autorisation métier.
Un utilisateur ne doit jamais obtenir un droit sensible uniquement parce qu'une valeur de feature flag est vraie côté navigateur. Les contrôles d'accès doivent être vérifiés côté serveur, au plus près de l'opération protégée. Un flag peut décider si une fonctionnalité est proposée, il ne doit pas devenir l'unique barrière devant une action critique.
Le vrai danger : la combinaison des flags
Un flag isolé est facile à comprendre. Plusieurs flags qui se combinent créent rapidement un système difficile à tester.
Imaginez une page dont le comportement dépend de la nouvelle navigation, du nouveau moteur de recherche et d'une règle de permission. Chaque flag double potentiellement le nombre de chemins à vérifier. Avec trois flags, l'équipe ne teste déjà plus seulement l'ancien et le nouveau comportement, mais plusieurs combinaisons possibles.
Il ne faut pas en déduire qu'il faut supprimer tous les flags. Il faut réserver les flags aux décisions qui justifient cette complexité et limiter leur portée :
- donnez à chaque flag un nom explicite, lié à une capacité et non à une version vague comme
next-version; - centralisez la logique de décision plutôt que de répéter le même nom dans toute l'application ;
- injectez la décision dans les composants métier, afin qu'ils ne dépendent pas directement du fournisseur de feature flags ;
- testez au minimum le chemin activé, le chemin désactivé et le comportement de repli si le service de configuration est indisponible ;
- évitez qu'un flag traverse toute l'application quand il peut être évalué à sa frontière, dans un contrôleur, un composant d'interface ou un adaptateur.
Le principe est simple : le code métier doit savoir quelle capacité il doit fournir, pas quel tableau de bord a décidé de l'activer.
Le fallback doit être décidé avant l'incident
Que se passe-t-il si le fournisseur de flags ne répond plus ? La réponse ne peut pas être laissée à une valeur par défaut choisie au hasard.
Pour chaque flag, il faut décider du comportement sûr :
- une interface non essentielle peut rester désactivée ;
- un traitement critique peut conserver le chemin stable ;
- une fonction qui écrit des données ne doit pas basculer silencieusement vers un comportement destructif ;
- une règle de permission doit échouer fermée, puis être contrôlée par le système d'autorisation habituel.
Les systèmes de feature flags sérieux exposent généralement un état d'évaluation et des erreurs possibles. La spécification OpenFeature prévoit notamment des valeurs par défaut typées, un contexte d'évaluation et des statuts comme ERROR ou STALE. Ce sont des signaux à traiter, pas des détails à cacher derrière une valeur booléenne.
Le fallback doit aussi être observable. Si la moitié des requêtes utilise la valeur de secours, l'équipe doit le savoir. Sinon, elle croit contrôler un déploiement alors que l'application a cessé de recevoir la configuration attendue.
Un flag sans date de sortie est une dette annoncée
Au moment de créer un flag, ajoutez les informations qui permettront de le supprimer :
- son objectif précis ;
- son type, release, expérimentation, opérationnel ou permission ;
- son propriétaire ;
- sa valeur par défaut et son comportement de secours ;
- les métriques à surveiller ;
- la condition qui autorise son retrait ;
- l'issue ou la tâche de nettoyage associée.
Le retrait doit faire partie du travail initial, pas d'une bonne intention future. Pour un flag de release, la demande de suppression peut être préparée dès la création. Lorsque l'équipe termine la mise en ligne, elle n'a plus qu'à confirmer que le nettoyage est justifié.
Cette discipline rejoint celle que j'applique pour le code mort : ce qui n'a plus de raison d'exister doit être retiré avant de devenir une partie invisible de l'architecture.
Une revue régulière des flags permet de repérer les symptômes classiques : flag activé partout, flag désactivé partout, propriétaire parti, métrique inexistante ou condition de retrait oubliée. Un flag dans l'un de ces états est souvent prêt à être supprimé.
Feature flags et CI/CD, une chaîne complète
Un flag ne compense pas un mauvais pipeline. Il s'insère dans une chaîne de livraison qui doit rester lisible :
- les tests vérifient les deux comportements nécessaires ;
- le pipeline construit et déploie un artefact identifié ;
- la fonctionnalité reste désactivée ou limitée à une cible connue ;
- le monitoring mesure les erreurs, la latence et les indicateurs produit pertinents ;
- l'équipe élargit progressivement l'exposition ;
- le flag, puis le code devenu inutile, sont supprimés.
Les tests E2E sont utiles pour vérifier les parcours visibles, mais ils ne doivent pas devenir l'unique filet de sécurité. Un test par combinaison de flags est rarement tenable. Les décisions de ciblage doivent être testées séparément, les composants métier doivent pouvoir être testés avec une configuration explicite, et les parcours critiques doivent être couverts par quelques scénarios représentatifs.
Le monitoring doit distinguer les variantes. Si l'ancien et le nouveau comportement partagent les mêmes métriques, une dégradation peut rester invisible. Au minimum, les logs et les traces doivent permettre de savoir quel chemin a été exécuté, sans exposer de données personnelles ni transformer le flag en outil de traçage disproportionné.
Mon filtre avant d'ajouter un feature flag
Je pose quatre questions avant d'accepter un nouveau flag :
- Quel risque réduit-il ? Si la réponse est seulement « c'est la méthode habituelle », il n'y a probablement pas de justification.
- Qui prendra la décision ? L'application, l'équipe technique, le support ou le produit ne pilotent pas les mêmes types de flags.
- Quelle est sa durée de vie prévue ? Un flag temporaire et un coupe-circuit permanent ne doivent pas être conçus ni documentés de la même façon.
- Comment saura-t-on qu'il peut disparaître ? Sans critère de sortie, la dette est créée au moment même où le flag est ajouté.
Pour une petite fonctionnalité à faible risque, un déploiement classique accompagné de tests peut être plus simple. Pour une migration, une nouvelle intégration, un changement de parcours critique ou une expérimentation, le flag peut réduire fortement le risque, à condition d'être borné dans le temps et visible dans l'exploitation.
FAQ : feature flags et feature toggles
Quelle est la différence entre un feature flag et un feature toggle ?
Dans la pratique, les deux expressions désignent le même mécanisme : une décision contrôlée à l'exécution qui modifie le comportement d'une application sans redéployer le code. « Feature flag » est l'expression la plus courante dans les outils et la documentation récente.
Un feature flag remplace-t-il une branche Git ?
Non. Une branche Git isole du code pendant le développement. Un feature flag contrôle l'exposition d'un code déjà déployé. Les deux répondent à des risques différents et peuvent être utilisés ensemble, sans laisser une branche longue durée devenir le seul mécanisme de release.
Peut-on utiliser un feature flag pour gérer les droits utilisateurs ?
Un flag peut aider à gérer l'exposition d'une capacité, mais il ne doit pas remplacer l'autorisation côté serveur. Les droits et les règles métier doivent être vérifiés indépendamment, sur chaque opération sensible.
Faut-il toujours utiliser un outil SaaS de feature flags ?
Non. Un fichier de configuration, une table dédiée ou un composant interne peuvent suffire pour un besoin simple. Le choix dépend de la fréquence des changements, du ciblage nécessaire, de la disponibilité attendue et du niveau d'audit requis. L'outil ne remplace pas la gouvernance des flags.
Comment supprimer un feature flag proprement ?
Commencez par confirmer que la variante conservée est bien celle à garder. Supprimez ensuite le flag, la branche conditionnelle devenue inutile, sa configuration, ses tests spécifiques et sa documentation obsolète. Exécutez les tests et vérifiez le diff, comme pour tout refactoring de production.
Un feature flag est une décision d'architecture, pas une case à cocher dans un outil de déploiement. Bien utilisé, il permet de réduire le rayon d'explosion d'une release et d'apprendre avec de vrais utilisateurs. Mal géré, il transforme chaque fonctionnalité en labyrinthe de conditions.
La règle que je retiens est volontairement pragmatique : un flag doit avoir un objectif, un propriétaire, un comportement de secours et une sortie. S'il n'a pas ces quatre éléments, il ne sécurise pas votre livraison. Il ajoute simplement une nouvelle forme de dette technique.
Sources
Benjamin Raimond
CTO hands-on : j'architecture, je code, je structure l'équipe technique. Je transforme des objectifs business en solutions robustes et durables pour les startups et PME.
En savoir plus →