Skip to content

13. Conclusion

Nous avons écrit le client [Flutter] de l'application [RdvMedecins]. Pour l'utilisateur, il offre les mêmes écrans que l'application HTML du cours [NestJS] et que les clients [Vue.js], [Angular] et [React] des cours précédents ; mais c'est une application mobile, installée sur le téléphone, et le même code produit aussi une application web.

Le serveur, lui, n'a pas changé. Son API JSON, dont le contrat (routes, corps, codes et clés d'erreur) a suffi pour écrire le client sans jamais lire son code, sert indifféremment un navigateur et un téléphone. Une seule différence : sur le téléphone, il n'y a pas de navigateur pour garder le cookie du jeton, et c'est l'application qui a joué ce rôle, en quelques lignes ([ClientAvecCookies]). La sécurité n'a pas bougé : c'est toujours le serveur qui authentifie, qui vérifie les rôles et les règles de gestion, et qui décide de ce qu'un patient a le droit de voir.

Le lecteur qui a suivi le cours [React] peut comparer :

  • les deux reposent sur la même idée : l'interface est une fonction de l'état. Un composant [React] est une fonction qui renvoie du JSX ; un widget [Flutter] a une méthode [build()] qui renvoie un arbre de widgets. Quand l'état change ([useState] / [setState]), l'interface est reconstruite, puis comparée à la précédente ;
  • [React] fabrique du HTML, que le navigateur dessine ; [Flutter] dessine lui-même chaque pixel, avec son propre moteur, sur le téléphone comme dans le navigateur. D'où des écrans identiques sur toutes les plates-formes, mais une application web plus lourde à charger ;
  • [Flutter] fournit beaucoup plus que [React] : les widgets de [Material], les formulaires, les listes, les fenêtres, les animations, le thème, les tests. Il a fallu moins de bibliothèques : [go_router] pour les adresses, [provider] pour l'état partagé, [http] pour les requêtes. Pas de CSS : la mise en page est faite de widgets ([Column], [Row], [Padding], [Expanded]...) ;
  • [Dart] est un langage typé, compilé, aux types non nullables : beaucoup d'erreurs que [TypeScript] laisse passer (une valeur [null] oubliée, un JSON mal lu) sont détectées à la compilation, ou dès la réception de la réponse grâce au filtrage de [Dart] 3 ;
  • la contrepartie : des écrans plus verbeux (l'arbre des widgets est profond), et un cycle de vie à connaître ([initState], [didUpdateWidget], [dispose], [mounted]).

Les notions de [Flutter] rencontrées dans ce cours (widgets sans état et avec état, cycle de vie, clés, [InheritedWidget] et [provider], [ChangeNotifier], [Future] et [Stream], routeur et gardes, formulaires, internationalisation) sont celles de toute application [Flutter]. Pour aller plus loin :

  • la documentation officielle, docs.flutter.dev, ses tutoriels, et son guide d'architecture (« App architecture ») ;
  • les tests : les tests de widgets ([flutter_test]), qui manipulent un écran sans téléphone (c'est avec eux qu'ont été faites les copies d'écran de ce document), et les tests d'intégration ([integration_test]), qui pilotent la vraie application sur un émulateur ;
  • d'autres gestionnaires d'état, très utilisés : [Riverpod] (le successeur de [provider], par le même auteur), [Bloc] ;
  • la génération de code : [json_serializable] et [freezed] écrivent les méthodes [depuisJson], [copyWith], [==]... à partir de simples déclarations ;
  • le stockage sécurisé du jeton ([flutter_secure_storage]), les notifications, l'appareil photo, la géolocalisation : un paquet par besoin, sur pub.dev ;
  • l'iPhone : le même code produit une application [iOS], à construire sur un [Mac] avec [Xcode].