Comment choisir sa solution de state management en Flutter ?

le 10/04/2024 par Rémi Dormoy
Tags: Software Engineering, Mobile

Au moment de commencer son application, un des premiers choix qui se posent à tout développeur•euse Flutter est aussi un des plus importants : le choix de la solution de state management. Dans la documentation de Flutter, c’est la première rubrique que l’on trouve après dans la partie “Au delà de la UI”. Le principe est résumé de la façon suivante : Le rendu sur l'écran est égal à une fonction, de l'état de l'application, cette fonction étant les méthodes buildsLe rendu sur l'écran est égal à une fonction de l'état de l'application, cette fonction étant les méthodes builds. En d’autres termes, notre affichage dépend directement d’un état (ou state) qu’il nous faudra matérialiser et gérer : bref, on devra faire du state management. Si le principe est relativement simple, sa mise en pratique peut se révéler plus complexe. Le framework Flutter nous met à disposition quelques outils :

  • Les StatefullWidget et leur méthode setState : utile principalement pour des états dits “éphémères” qui ne dépassent pas la couche de présentation.
  • Les ChangeNotifier, ChangeNotifierProvider et Consumer qui permettent un state management basique.

Il est fort probable que vous connaissiez les premiers, peut-être est-ce moins sûr pour les seconds. Quoi qu’il arrive, pour un projet qui n’est pas “basique”, Flutter recommande directement de passer par un framework développé par la communauté dont il fait une liste non exhaustive. Et c’est ici que tout se complique : aucun framework n’est LE framework officiel (ni même recommandé), et chacun a ses avantages, ses inconvénients et ses implications propres. Votre chance, c’est que nous allons pouvoir, dans la suite de cet article, vous donner toutes les clés pour choisir la solution qui conviendra le mieux à votre équipe, votre projet et votre application !

Quels impacts aura mon choix ?

Selon le choix que vous ferez, votre solution de state management sera plus ou moins au cœur de votre application et aura un impact plus ou moins important sur votre développement. Ce qui est sûr néanmoins, c’est que même une solution “légère” aura malgré tout des impacts tout au long du cycle de développement de votre application.

Je vais impacter la structure de mon code

Chaque librairie, même les plus légères, nous amènera de nouveaux rôles spécifiques à leur fonctionnement, sous forme de méthodes ou de classe. De la même manière que nous ajoutons le suffixe Repository aux classes qui nous servent à récupérer des données, nous appliqueront le même principe pour les classes remplissant ces différents rôles. Notre code sera donc plein de multiples classes et/ou fichiers sur le format suivant FeatureRoledanslalibrairie. Bien sûr, la quantité de classes qui suivra ce format (et les responsabilités associées) sera plus ou moins importante en fonction de la librairie choisie et nous aurons ainsi un impact sur :

  • La rigidité de notre structure de code
  • La liberté de notre manière de développer
  • La verbosité de notre code

Je vais impacter la maintenabilité de mon code

Tout d’abord précisons que si notre solution de state management va impacter la maintenabilité, cela ne veut en aucun cas dire qu’elle en sera le seul facteur, ni même le principal. Il est tout à fait possible de produire une application tout à fait maintenable avec n’importe quelle solution, de la même manière qu’il est possible de produire du code endetté dès le premier jour avec n’importe quelle solution. Cela dit, comme on en a parlé plus haut, chaque solution va nous pousser à implémenter un certain nombre de classes ayant un rôle spécifique, ce qui crée d’emblée un premier découpage. La rigidité plus ou moins grande de chaque solution peut également restreindre la liberté dont dispose chaque développeur•e, mais aussi renforcer naturellement la cohérence de chaque fonctionnalité.
Pour résumer, certaines solutions vont nous forcer à respecter un cadre clair et donc favoriser une application maintenable à travers son cycle de développement. Au contraire, des solutions moins rigides laissent la porte ouverte à plus de différences d’implémentation entre les fonctionnalités et donc si on n’y fait pas attention, une base de code plus difficile à maintenir.

Je vais impacter la complexité de mon code

Ce qui découle des deux parties vues au-dessus, c’est que suivant la solution de state management que je choisis, je vais complexifier ou non certaines parties de mon code. Certaines libraires viennent également avec une vision associée de comment on doit les utiliser, voir un pattern d’architecture à part entière qu’il nous faudra respecter. Le premier impact visible de la complexité sera probablement la durée de montée en compétences nécessaires avant que chacun des développeur•e•s de notre projet maîtrise les différents concepts associés à la librairie choisie. Il est également à prévoir que lorsque vous aurez des départs ou des arrivées dans l’équipe de développement, la passation de connaissance et/ou la documentation de votre projet soit impactée.

Bien comprendre le contexte de son application

Maintenant que nous connaissons les différents impacts qui vont découler de notre choix, quels éléments doivent être pris en compte ? Nous avons vu qu’il n’existe pas de solution universellement meilleure que les autres. Comment choisir laquelle sera la meilleure pour notre application ? Pour cela, commençons par lister ce qui fait la différence entre les applications que nous pouvons être amenés à développer.

La taille de l’équipe et des fonctionnalités

La différence la plus évidente, d’un projet à l’autre, est la taille. Que ce soit la taille des équipes, qui varie d’un développeur•euse à plusieurs dizaines sur les plus gros projets. Mais aussi la taille de l’application, en termes d’écrans et de fonctionnalités. Quel impact cela peut-il avoir sur le choix de la solution de state-management ?

Plus une équipe de développement est grande, plus le besoin est fort d’avoir des standards et des conventions de code partagées et appliquées. Dans ce cas, la rigidité imposée par une librairie peut donc devenir un avantage au lieu d’une contrainte.

Au niveau de la taille de l’application en elle-même, en nombre d’écrans ou de fonctionnalités, on retrouve un questionnement similaire. D’autant plus si l’application elle-même doit gérer des règles métier qui n’ont pas pu être déplacées dans un back-end. Un nombre conséquent de fonctionnalités ou de code métier nous poussera donc vers des solutions plus “lourdes” de state management. 💡Certaines solutions ont également été créées pour répondre à des problématiques précises et peuvent apporter de la simplicité pour répondre à certains types de fonctionnalités, notamment celles nécessitant du partage d’informations d’un écran à l’autre.

La durée du développement et de vie de l’application

Au-delà de la taille, nous devons aussi considérer la durée de vie de notre application. D’abord sur la phase de développement (phase de “build”) mais aussi sa longévité prévue sur les stores (phase de “run”).

Il y a encore quelques années, les fronts en général, dont le mobile, étaient souvent considérés comme “jetables”. Ils ne devaient durer que quelques mois, au maximum deux-trois ans. Et ensuite, une fois qu’ils étaient devenus trop vieux, on se lançait dans une refonte et un nouveau cycle de développement. Aujourd’hui, il est fréquent de démarrer un projet mobile en se disant que notre application est là pour de nombreuses années, et cela a des implications sur le choix de notre solution de state management.

Tout d’abord, si la durée prévue est longue, il est important de choisir une solution abondamment soutenue par une communauté dynamique. Et pour cela, rien de plus simple : regardons le nombre de likes sur pub.dev ou la présence d’un logo Flutter favourite.

Pour réduire les probabilités de dépréciation de notre librairie, nous pouvons aussi prendre en compte l’ancienneté de notre solution.

Pour les projets longs, il faudra également prévoir les rotations dans l’équipe de développement. Au-delà d’une ou deux années, il est fort probable qu’une partie (voire la totalité) de votre équipe ait changé. Ce qui peut compliquer la cohérence des standards de code.

💡Pour des applications à durée de vie très longue, nous pouvons aussi prendre en compte le coût éventuel d’une migration de cette solution vers une nouvelle. Quelle que soit votre solution de state management, ce coût sera probablement élevé, mais il ne sera pas le même entre une librairie présente au cœur de votre code métier et une autre qui toucherait simplement aux couches de présentation et à votre injection de dépendances.

La maturité de l’équipe de développement

Enfin, évidemment, les développeur•euse•s que vous aurez sous la main pour construire cette application influenceront aussi le choix de la solution de state management que vous choisirez. Tout d’abord, si vous avez dans votre équipe des développeur•euse•s ayant déjà un avis sur telle ou telle solution (des développeur•euse•s séniors par exemple), il vous faudra soit choisir une solution qu’ils recommandent, soit avoir les arguments pour les convaincre d’en prendre une autre.

Pour des solutions plus complexes, le fait que votre équipe maîtrise déjà une partie des concepts et/ou de l’implémentation d’une solution peut fortement faire pencher la balance vers cette solution.

Dans certains cas, si votre équipe a une séniorité hétérogène (par exemple un seul développeur•euse sénior, avec quelques juniors), une solution un peu plus lourde, mais donnant un cadre clair et rigide peut être indiquée. À l’inverse, si votre équipe est plus homogène, une solution plus libre permettra à chacun•e d’apporter sa pierre à l’édifice pour construire les standards de l’équipe.

💡Même si personnellement je ne recommanderais pas d’y accorder trop d’importance, un phénomène de hype accompagnant telle ou telle solution de state management peut aussi entrer en compte. Notamment pour des projets à durée de vie courte, un peu de hype peut vous permettre de motiver votre équipe de développement, de recruter plus facilement des développeur•euse et peut-être même de pouvoir communiquer sur votre projet en montrant que vous êtes au top du top de ce que si fait de nouveau !

Cas concret : je choisis BLoC ou REDUX ?

Essayons maintenant d’expliciter ce que nous venons de voir avec deux exemples fictifs d’application, et en réduisant notre choix de solution à BLoC et REDUX.

Pour la suite de cet article, je considérerais que vous connaissez déjà ces deux solutions. Si ce n’est pas le cas, je vous invite à consulter cet article vous présentant BLoC et cet article vous présentant REDUX.

Comme nous avons envie d’être le mieux éclairé possible pour le choix de notre solution, nous avons pris le temps de bien cerner le contexte de chacun des projets :

Projet A :

  • Notre client, qui vend des produits de maquillage, veut mettre en avant sa gamme de produits à destination des adolescent•e•s en créant une application avec une charte graphique dédiée et ne contenant que ces produits.
  • Notre client a à sa disposition un back-for-front (BFF) nous permettant, pour chaque page, de récupérer les données dont nous avons besoin, déjà ordonnées voire formatées.
  • La prévision pour le projet est une équipe de 2 développeur•euse•s expérimenté•e•s (par exemple avec 2-3 ans de développement Flutter) pour une durée de 5 mois.

Dans ce contexte, la durée de mission et la taille de l’équipe réduisent l’importance d’avoir un cadre rigide. Le fait d’avoir un back-for-front va également limiter la présence de code métier ou de règles de gestion à l’intérieur de l’application. Nous aurons également peu d’informations à faire transiter d’un écran à l’autre. La durée relativement courte de ce projet peut également nous pousser vers une solution plus légère, qui permettra de réduire le temps nécessaire à l’équipe pour atteindre sa pleine vitesse de développement.

Pour ce projet, je vous recommanderais donc de partir sur BLoC, qui sera plus léger, et dont le temps de montée en compétence est en général plus court. Vous aurez également moins de code “passe-plat” à écrire que sur REDUX.

Projet B :

  • Notre client, une banque ayant des centaines de milliers de clients, veut refondre ses applications natives en Flutter pour moderniser son apparence et diminuer ses futurs coûts de maintenance.
  • L’application devra utiliser les web-services actuels, divisés par domaine fonctionnel.
  • La prévision pour le projet est une équipe de 8 développeur•euse•s, dont 2 séniors, avec une durée d’un an avant la première mise en production, et sans date de fin pour la durée de vie sur les stores et les futures fonctionnalités.

Ici, pour que notre projet reste maintenable à travers les années, malgré les nombreux ajouts de feature, il sera important de fixer des standards précis voire rigides pour ne pas multiplier les différences d’implémentation. Il est fort probable que notre application contienne une quantité non négligeable de règles de gestion, et il nous faudra donc avoir un découpage efficace pour ne pas polluer le code métier avec des règles de présentation, ou des classes liées à l’infrastructure, comme les appels réseaux.

Pour ce projet, je vous recommanderais donc de partir sur REDUX, qui vous donnera une architecture clef en main, une structure claire et facile à reproduire sur toutes vos fonctionnalités, et dont il sera plus difficile de s’écarter au fur et à mesure que le projet avancera. Vous aurez également une grande facilité à partager des données ou des règles de gestion entre vos différents écrans grâce au store unique. La différence initiale de complexité par rapport à BLoC sera rapidement amortie par le découpage plus précis des responsabilités de chaque classe dans REDUX.

Conclusion

J’espère ne pas vous avoir déçu ceux qui auraient espéré une réponse toute faite s’appliquant à chaque projet. Quelle que soit l’application sur laquelle vous travaillez, la meilleure solution de state management ne pourra être que “sur mesure” pour s’adapter le mieux possible à votre équipe. Sachant cela, certaines solutions seront tout de même mieux adaptées que d’autres à votre projet. Bien cerner votre contexte et ce qui le rend particulier vous aidera à maximiser les impacts positifs de votre choix et à anticiper les futures difficultés. Mon conseil de fin, si vous hésitez entre plusieurs solutions sans arriver à trancher : essayez celui que vous connaissez le moins ! Au-delà de ce que ce choix apportera à votre projet, il sera plus intéressant pour vous personnellement de partir sur une solution ou vous avez tout à apprendre.