Mettre à jour une application mobile sans passer par les stores - #2 Remote config, Feature Flag & co

Et s’il suffisait de passer à non un paramètre pour désactiver une fonctionnalité qui pose problème en prod ? Ou de changer un chiffre pour modifier le nombre d’éléments de la page d’accueil d’une application mobile ? Sans avoir à modifier du code et sans passer par la case déploiement bien entendu, parce qu’on a envie d’agir rapidement. On pourrait simplement changer des valeurs sur une interface web par exemple.

Eh bien, c’est ce qui se cache derrière des concepts comme le Remote Config et le Feature Flagging. Ce sont des techniques de développement qui permettent de modifier des éléments d’une application sans avoir à déployer une nouvelle version. Les répercussions arrivent très peu de temps après (quelques minutes) et ne nécessitent aucune intervention de l’utilisateur. On peut changer le comportement d’une fonctionnalité, un algorithme, et même l’interface graphique.

On peut utiliser ces techniques sur un site web, une application mobile, un backend. Partout ! Le principe de base est très simple. D’un côté, il y a une configuration distante (sur un serveur par exemple). C’est un ensemble de paramètres avec des valeurs que l’application pourra interpréter - Activer le partage ? NON - et ça peut être un simple fichier JSON :

{
	"feature_share_enabled": false 
}

D’un autre côté, il y a une application qui récupère cette configuration régulièrement depuis le serveur et qui contient du code utilisant les différents paramètres reçus pour adapter son comportement. Par exemple, le nombre d’éléments de ma page d’accueil n’est pas un chiffre fixe dans mon code, mais correspond à celui indiqué dans ma configuration à distance.

let numberOfElements = remoteConfig.get("home_number_of_elements") 

J’insiste sur un point important. Du code doit être au préalable ajouté dans l’application en production pour réagir à chaque nouveau paramètre que l’on veut ajouter à la configuration. En d’autres termes, si je veux désactiver le partage, je dois écrire du code qui conditionne l’affichage ou non de mes boutons de partage. Et je dois aussi déployer cette version en production. Ce n’est pas magique, il faut prévoir ce travail.

Une fois que j’ai rendu configurable mes fonctionnalités, je n’ai qu’à modifier des valeurs dans ma configuration distante pour affecter mon application sans avoir ni à modifier son code ni à la déployer ! On décorrèle le déploiement du code de celui de la feature, ce qui nous ouvre de multiples possibilités.

Cas d’utilisations

Sans chercher à faire une liste précise et exhaustive, je vais parcourir plusieurs exemples afin de donner de la variété dans les cas d’utilisations - c’est bien plus qu’un bouton on/off.

  • Désactiver une fonctionnalité. J’ai soudainement un problème en production. La dernière fonctionnalité provoque un crash, une forte charge sur le serveur, se comporte anormalement. Ou un SDK tierce - qui se souvient du SDK de Facebook il y a quelques années ? Il a provoqué le crash au lancement d’innombrables apps, y compris les géants comme Spotify ou TikTok. Je peux réagir très vite en désactivant la fonctionnalité puis en analysant le pourquoi ensuite (Cynefin : on est dans le chaos, on cherche à agir tout de suite). On se met un filet de sécurité, un kill switch, on peut rollback. Ou peut-être qu’il n’y a aucun problème et que la fonctionnalité est simplement éphémère - on l’arrête sans nécessité de mise à jour.

  • Activer une fonctionnalité. J’ai le besoin inverse, activer plus tard une fonctionnalité. Peut-être qu’il faut attendre que la version de l’application soit assez déployée pour activer la fonctionnalité. Ou une date, un événement. Peut-être parce que le backend n’a pas encore terminé tout le travail requis. Ou parce qu’on veut intégrer et déployer continuellement (CI/CD) - on cache la fonctionnalité tant que le travail est inachevé.

  • Modifier l’expérience utilisateur. De manière plus générale, on peut modifier l’expérience utilisateur sous différents aspects. Ce n’est pas uniquement binaire “activé ou désactivé”. Je peux modifier l’agencement d’une page, un nombre d’éléments. Je peux créer une mécanique pour forcer la mise à jour de l’application (on indique un numéro de version minimal, et l’application aurait un écran incitant à mettre à jour au lancement).

  • Déployer progressivement une fonctionnalité. Apple et Google proposent tous les deux du déploiement progressif sur leurs stores. Ici, on pourrait très bien le faire au niveau d’une fonctionnalité. Je pourrais déployer ce nouveau tunnel à 10% des utilisateurs, et j’observe ce qu’il se passe. J’augmente le pourcentage quand et comme je le souhaite (ce que ne permet pas la solution sur l’App Store). On fait du Canary Release. Et je peux même réduire à 0% si j’ai un gros problème. Plus personne n’y aura accès. Un avantage par rapport aux déploiements progressifs via les stores : stopper le déploiement ne fait qu’empêcher de nouvelles installations, ceux qui ont déjà installé garderont la fonctionnalité active.

  • Expérimenter des variantes. J’ai envie de tester en production un affichage différent, un autre parcours, un placement, une couleur. Peut-être même deux solutions pour améliorer un problème. On va faire vivre ces deux variantes dans la nature en même temps et observer laquelle obtient le meilleur résultat. On fait de l'A/B Testing.

  • Bêta-tester. Je peux créer un groupe de bêta-testeurs ou d’early adopters pour donner accès en avance à des fonctionnalités. Ou je pourrais même avoir un opt-in dans l’application. Et j’active ou désactive plus largement dans le futur.

J’en profite pour rebondir sur cette dernière phrase. On peut combiner des cas d’utilisations. Parce que j’ai rendu configurable cette fonctionnalité, je peux commencer à l’ouvrir à mon groupe de bêta-tester, puis ouvrir à 10% de tous mes utilisateurs, puis désactiver la fonctionnalité quand un problème se présente. Et toujours sans avoir à déployer une nouvelle version.

Je veux ça !

Okkkayyyy je commence à être convaincu par l’idée, j’ai envie de l’intégrer sur mon projet, dans mon équipe. Quelle solution prendre ?

Première étape, j’opterais pour une autre question : quels sont mes besoins ? Plutôt que de foncer sur un outil parce qu’il a l’air cool ou parce qu’untel a dit qu’on a raté notre vie si on ne l’utilise pas, je préfère regarder mon contexte et mes besoins pour répondre de manière adaptée.

Ici, on peut se demander si on veut une configuration qui expose simplement des valeurs, ou si on veut pouvoir introduire des variantes pour faire de l’A/B Testing, du déploiement progressif, etc. Qui va modifier la configuration ? Un fichier versionné sous git pourrait suffire, mais une interface web serait plus adaptée si on veut que toute l’équipe puisse apporter des changements. Quel contrôle veut-on sur les données ? Une solution hébergée chez nous ou un SaaS clé en main ? Et le feature flagging au final, est-ce ce qui répond le mieux à notre besoin ?

À partir de ces réflexions, je peux aller dans plusieurs directions.

  • Je peux créer moi-même une solution. La mécanique de base est simple. Notre backend qui expose un fichier JSON ou une route avec la configuration et un appel HTTP classique côté app pourrait suffire. Un peu de gestion de cache. On a un contrôle total, c’est hébergé chez nous. Puis peut-être qu’on ajoute une interface web, de la variance, etc. Ce sont des ajouts qui prendront un peu plus de temps et qui pourraient diriger vers une solution open-source ou SaaS pour éviter de réinventer la roue.
  • Je peux héberger une solution open-source chez moi. J’ai rapidement accès à de multiples fonctionnalités et en même temps, je garde un assez bon contrôle. Je gère juste que ça tourne bien sur mes serveurs. Unleash et Featurehub sont deux possibilités.
  • Je peux utiliser une solution propriétaire dans le cloud. Je ne veux rien gérer, je délègue tout. Je peux très rapidement mettre en place une configuration à distance pour mon projet, mais j’ai moins de contrôle. Firebase Remote Config a démocratisé la technique pour les applications mobiles, et est très souvent utilisé. C’est Google derrière et aux USA, à avoir en tête pour les données :). Optimizely et ConfigCat sont deux alternatives intéressantes ; la dernière proposant une option pour un cloud privée.

Conclusion

J’aime bien les techniques de Feature Flag et Remote Config parce qu’elles sont simples et qu’elles apportent une réelle flexibilité en séparant le déploiement du code et de la fonctionnalité. On peut réagir à certains imprévus, on peut expérimenter en production, on peut modifier l’expérience utilisateur.

Vous avez pu voir que plusieurs autres pratiques et concepts gravitent autour des Feature Flags. L’A/B Testing, le kill switch, le Canary Release, par exemple. C’est aussi une brique que l’on peut retrouver quand on se plonge dans l’intégration continue (CI), le déploiement continu (CD), le trunk-based development - la configuration permettant d’intégrer et de livrer très régulièrement en cachant le travail non terminé.

Pour autant, les Feature Flags ne sont ni magiques ni parfaites. Il faut prendre soin d’en mettre aux endroits adaptés. Il faut une hygiène dans l’équipe pour les maintenir, les supprimer, éviter les chevauchements.

Elles permettent d’expérimenter en production, mais elles ne remplacent pas des entretiens et ateliers avec des utilisateurs, de la discovery, etc. C’est complémentaire.

Elles permettent d’ajouter un filet de sécurité. Elles ne remplacent pas une attention à la qualité de code, au design applicatif, aux tests, etc. Ajouter -> il est supplémentaire.

Et au fait, on dit Feature Flag, Feature Toggle, ou Feature Flip ? C’est la même chose. J’ai une préférence pour Feature Flag qui est moins binaire.


Série d’articles Mettre à jour une application mobile sans passer par les stores :

La suite est à venir et peut changer en fonction de mes réflexions et de discussions.