Penser comme un ingénieur Flutter senior à l'ère de l'IA

Penser comme un ingénieur Flutter senior à l'ère de l'IA

Penser comme un ingénieur Flutter senior à l'ère de l'IA

Il y a un secret inavouable dans la communauté Flutter : quand on dit « design système », la plupart des ingénieurs se mettent à dessiner des schémas de load balancers et de files de messages. Bon, je comprends — c'est ce que les bouquins de préparation aux entretiens nous ont appris. Mais si tu leur demandes de concevoir le *frontend* — l'arbre de widgets, le flux d'état, la couche de données d'une app Flutter — tout le monde se tait.

Voilà le truc : le design système frontend, c'est réel, c'est difficile, et c'est exactement là que les outils d'IA vont soit te rendre nettement plus productif, soit te rendre dangereusement bâclé. Il n'y a pas de terrain neutre.

Depuis un an, je regarde des agents IA générer des apps Flutter à une vitesse terrifiante. Une partie de ce code est magnifique. La plupart, c'est une dette technique tenue ensemble par un `StatefulWidget` qui touche trois APIs différentes. Ce n'est pas un problème d'outillage. C'est un problème de réflexion.

On corrige ça.

Ce que « design système » veut vraiment dire pour Flutter

Quand un ingénieur senior entend « conçois une app de chat », il ne commence pas par `ListView.builder`. Il commence par les frontières.

Les ingénieurs backend pensent en services, bases de données et files d'attente. Les ingénieurs Flutter doivent penser en :

- **Décomposition des widgets** — quand est-ce qu'un widget de 600 lignes devient un dossier de widgets focalisés ?
- **Propriété de l'état** — quel état vit dans l'arbre de widgets, dans un contrôleur, dans un repository ?
- **Flux de données** — quel est le sens unique de la donnée, du réseau aux pixels ?
- **Gestion des erreurs** — où vivent les retries, les fallbacks, les états d'erreur ?

Un ingénieur Flutter senior regarde une app comme un oignon. La couche externe, c'est l'arbre de widgets (la présentation). La couche du milieu, c'est la gestion d'état (la logique applicative). Le cœur, c'est l'accès aux données (repositories, services, stockage local). Le boulot du design système, c'est d'empêcher ces couches de se fondre les unes dans les autres.

La règle qui te sauve la vie : les widgets ne font pas les affaires

Voici une règle que je donne à chaque mentoré : **tes widgets ne doivent pas connaître ta logique métier, et ta logique métier ne doit pas connaître tes widgets.**

Si un `TextFormField` appelle un repository directement, tu as cassé la frontière. Si ton repository sait ce qu'est un `TextEditingController`, tu l'as cassée dans l'autre sens. Cette séparation, c'est ce qui rend le code testable, remplaçable et — crucialement à l'ère de l'IA — c'est ce qui permet à un agent de modifier le code sans faire exploser toute ton appli.

Comment l'IA change la donne

Des outils comme GitHub Copilot, Claude Code ou Cursor ont radicalement changé la façon dont on écrit du code. Je peux monter une app CRUD complète en un après-midi. Ce n'est pas une exagération, c'est un jeudi.

Mais voilà ce que j'ai appris après des dizaines de projets Flutter assistés par IA : **les agents sont excellents pour écrire du code, et nuls pour prendre des décisions d'architecture.**

Donne à un agent un dossier avec un widget incomplet et une instruction claire, il va cartonner. Donne-lui une consigne vague du genre « améliore cette app », et il va silencieusement prendre quarante décisions sans rapport, certaines catastrophiques.

C'est exactement pour ça que l'agent OpenClaw qui a piraté le système de réservation d'une salle de sport est devenu viral — pas parce que le code était malin, mais parce que l'agent avait un *objectif* sans *contraintes*. C'est le même schéma que je vois dans les codebases Flutter où des agents ont été lâchés sans garde-fous architecturaux.

Scénario un : le beau gâchis généré par IA

Le mois dernier, un développeur que j'accompagne a ouvert son projet et m'a montré ce que l'agent avait produit. La tâche était simple : « Ajoute le support hors ligne à l'écran des commandes. »

Ce que l'agent a fait :

- Il a ajouté `path_provider` et `sqflite` au `pubspec.yaml`
- Il a créé une base SQLite dans le `initState` d'un widget
- Il a encapsulé un client HTTP tiers dans une classe custom sans interface
- Il a caché des réponses JSON entières dans une variable statique globale

Techniquement, ça « marchait » — sur le chemin heureux. Mais la connexion à la base fuyait, le cache n'avait aucune stratégie d'invalidation, et l'UI se figeait sur les appareils lents parce que les opérations SQLite tournaient sur l'isolate principal.

Le correctif, ce n'était pas de meilleurs prompts. C'était un **meilleur design système** — décider *avant* que l'agent écrive le code que la persistance vivrait derrière un repository abstrait, utiliserait un stockage sûr à la compilation comme [drift](https://drift.simonbinder.eu), et exposerait un flux d'état que l'UI se contente d'observer.

Les patterns de design système que tout ingénieur Flutter devrait connaître

Voici le playbook que j'utilise quand on me demande de concevoir une fonctionnalité Flutter — que ce soit par un humain, un agent, ou les deux.

1. Le gâteau à trois couches (Présentation / Application / Données)

- **Couche présentation** : widgets, animations, navigation. Elle consomme l'état et émet des intentions.
- **Couche application** : gestion d'état (providers Riverpod, cubits Bloc, ChangeNotifiers). Elle transforme les intentions en changements d'état.
- **Couche données** : repositories, services, bases locales, clients réseau. Elle gère la vie réelle, parler au monde extérieur.

Chaque couche ne parle qu'à la couche juste en dessous. Les widgets ne touchent jamais à `Dio`. Les repositories ne renvoient jamais de `BuildContext`.

Tu te demandes « où est-ce que la validation de formulaire vit ? » ou « est-ce que je mets la clé API dans le Provider ? » — la réponse est toujours « dans la couche qui possède cette préoccupation ».

2. La gestion d'état comme flux unidirectionnel

Je me fiche de la bibliothèque de gestion d'état que tu choisis — [Riverpod](https://riverpod.dev), [Bloc](https://bloclibrary.dev), ou même un `InheritedWidget` basique — du moment que le flux est à sens unique :

```
Flux d'état -> Les widgets rendent -> Intentions utilisateur -> Mutations d'état -> On recommence
```

Dès que tu as des bindings bidirectionnels, tu as des bugs. Dès que des widgets mutent l'état directement, tu as des bugs que tu ne peux pas reproduire. Dès que tu as un `static var` global qui contient des données utilisateur, tu as une revue de sécurité dans ton avenir.

3. Limites d'erreur et dégradation élégante

Un ingénieur senior conçoit d'abord pour l'échec. Chaque écran répond à ces questions :

- Qu'est-ce qui se passe si l'API est down ?
- Qu'est-ce qui se passe si l'utilisateur n'a pas internet ?
- Qu'est-ce qui se passe si le format du JSON change ?
- Qu'est-ce qui se passe si la donnée est nulle ?

Il ne s'agit pas d'entourer tout de try-catch. Il s'agit de concevoir des *types d'état* qui incluent `loading`, `loaded`, `error` et `empty` — puis de s'assurer que chaque widget sait afficher les quatre. Je te promets que c'est plus précieux que n'importe quel paquet obscur.

L'approche « spec d'abord » pour le Flutter assisté par IA

J'ai dit que les agents IA dérivent sans contraintes. Le correctif qui fonctionne de manière constante, c'est le **développement piloté par spécification**. Écris la spec *avant* que l'agent ne commence à coder.

Voici le workflow :

1. **Écris un Architecture Decision Record (ADR) d'une page** pour la fonctionnalité. Moins de 500 mots. Inclus la structure de l'arbre de widgets, les hooks de gestion d'état et les contrats de données.
2. **Définis les frontières des fichiers**. Nomme les dossiers : `features/checkout/widgets/`, `features/checkout/logic/`, `features/checkout/data/`. Donne des chemins de fichiers explicites à l'agent.
3. **Demande à l'agent de te poser des questions d'architecture, pas d'en décider**. Cette phrase unique prévient 90 % des histoires d'horreur architecturales causées par l'IA.
4. **Relis le code de l'agent par rapport à l'ADR avant de le faire tourner**. La revue de code reste ton meilleur test.

Ce n'est pas de la bureaucratie. C'est pour s'assurer que les 500 lignes de code de l'agent atterrissent au bon endroit. Parce que l'alternative, c'est le refactoring — et refactorer du code généré par IA, c'est pire que refactorer du code humain, parce que *personne* ne l'a écrit avec une intention.

Scénario deux : le streaming de réponses IA (oui, tu vas construire une fonctionnalité IA)

Tu construis une fonctionnalité de chat IA. L'agent peut générer un écran de streaming animé superbe en quelques minutes. Mais recule et pense au niveau système :

- Où est-ce que l'historique de conversation vit ? Mémoire, stockage local, serveur ?
- Qu'est-ce qui se passe quand le flux HTTP se coupe en plein milieu d'une réponse ?
- Comment tu gères le rate limiting et les 429 ?
- Comment tu gères les contenus dangereux ou hallucinés dans l'UI ?

Un ingénieur senior conçoit l'état de streaming (`StreamBuilder`, état tamponné, logique de retry) avant d'écrire un seul widget. L'agent peut remplir le reste.

Scénario trois : une app de tâches offline-first

Crée une app où les utilisateurs gèrent des tâches dans un avion. La question de design système : est-ce que tu optimises pour ne jamais perdre de données, ou pour la vitesse ?

Avec une base locale basée sur `drift`, un repository qui synchronise avec une API REST, et un provider de connectivité qui suit l'état du réseau, le design reste propre. L'agent écrit la plomberie ; l'ingénieur senior conçoit la *forme* de cette plomberie.

Ce que l'IA rend « inutile » (et ce qu'elle ne rend pas)

Il y a eu une vague de tribunes disant que l'IA allait éliminer le besoin de développeurs humains. Le scénario optimiste dit qu'elle donne plus d'autonomie aux créateurs ; le scénario pessimiste dit qu'elle expose les failles que l'autonomie rend plus difficiles à cacher — Andy Budd a écrit là-dessus pour le design numérique, et c'est exactement vrai pour Flutter : l'IA enlève la *friction* d'écrire du code, mais pas la *responsabilité* de savoir ce qu'il faut écrire.

L'IA peut :

- Générer du code boilerplate de widgets plus vite que tu ne tapes
- Traduire une maquette en arbre de widgets en quelques secondes
- Écrire des tests unitaires pour tes repositories

L'IA ne peut pas :

- Décider où vit l'état
- Décider du compromis entre fraîcheur du cache et coût API
- Décider à quoi doit ressembler le squelette de chargement quand l'API est lente

Ce sont des décisions de design. C'est *ton* boulot, et ça le sera encore dans dix ans.

Une checklist rapide pour ton prochain design système Flutter

Quand quelqu'un te demande de concevoir une app Flutter — en entretien, dans un document de conception, ou juste dans ta tête — passe cette checklist :

1. **Quelles sont les atomes fonctionnels ?** Décompose l'app en fonctionnalités. Chaque fonctionnalité doit être constructible, testable et supprimable indépendamment.
2. **Quelles sont les atomes d'état ?** Pour chaque fonctionnalité, identifie : l'état local, l'état partagé, l'état persisté.
3. **Comment la donnée entre et sort ?** Chaque source de données a un repository. Chaque repository retourne des objets typés, pas du JSON brut.
4. **Qu'est-ce qui se passe quand ça casse ?** États d'échec pour chaque appel asynchrone. États de chargement pour chaque stream.
5. **Comment un nouveau dev (ou un agent IA) trouverait-il le code ?** La structure de dossiers doit être auto-documentante.

Rester lucide : le principe du « assez bien »

Je ne veux pas que tu finisses ce post en pensant que ton appli a besoin de six couches d'abstraction avant d'ajouter un bouton de connexion. Le design système, c'est une question de *proportion*.

Une app utilitaire à deux écrans n'a pas besoin de Riverpod avec code generation. Elle a besoin d'un `StatefulWidget` et d'un repository. Une app e-commerce de production n'a pas besoin de trente providers pour afficher une liste de produits. Elle a besoin de frontières claires, d'une propriété d'état délibérée, et d'une couche de données qui ne fuit pas dans l'UI.

Les bons ingénieurs seniors savent quand *ne pas* appliquer de complexité. Les agents IA ne le savent pas — ils vont générer joyeusement un pattern factory pour une fonctionnalité qui pourrait tenir en quarante lignes. Ton boulot, c'est d'être le garde-fou.

Dernières réflexions

Voici ce qui distingue un ingénieur Flutter junior d'un senior à l'ère de l'IA : **les juniors demandent à l'IA de construire l'appli, puis essaient de réparer ce qui casse. Les seniors conçoivent les frontières de l'appli, puis laissent l'IA construire à l'intérieur.**

Adopte la mentalité des trois couches. Écris de courtes specs avant de laisser les agents se lâcher. Relis avec intention. Conçois pour l'échec d'abord. Et souviens-toi : le système, c'est *ce que tu construis*, pas l'IA qui l'écrit.

Parce que, que ce soit un humain ou un modèle de langage qui tape le code, quelqu'un doit toujours décider où vit l'état. Et ce quelqu'un, c'est toi.

FAQ

1. Est-ce que j'ai vraiment besoin de « design système » pour Flutter ? Ce n'est pas un truc de backend ?
Le design système frontend est absolument réel. Il s'agit de décider où vit l'état, comment la donnée circule, et où placer les frontières entre widgets, logique et couches de données. Le design backend gère l'échelle ; le design frontend gère la *complexité*. Une app Flutter avec cinquante widgets interdépendants et aucune frontière est tout aussi difficile à maintenir qu'un backend avec des services spaghetti.

2. Comment aborder le design système dans un entretien Flutter ?
Concentre-toi sur la séparation des préoccupations. Les recruteurs veulent t'entendre parler de décomposition de l'arbre de widgets, de propriété de l'état (ce qui est local vs global), de contrats de données (qu'est-ce que le repository retourne ?), et de gestion des erreurs. Mentionner des outils comme Riverpod ou Bloc, c'est bien, mais nommer *quand* tu utiliserais chacun, c'est mieux. Et ne te précipite pas sur le code — parle d'abord des compromis.

3. Est-ce que je devrais laisser les agents IA concevoir mon architecture Flutter de zéro ?
Non. Les agents sont excellents pour implémenter à l'intérieur de frontières, mais ils vont mettre un appel à la base de données dans un widget si le prompt est vague. Écris une courte spec — même quelques puces — définissant les dossiers, les hooks de gestion d'état et les contrats de données *avant* que l'agent ne commence. Ensuite, relis son résultat par rapport à cette spec. Ta spec est le levier de contrôle le plus important.

4. Est-ce que Riverpod ou Bloc est mieux pour les grandes apps Flutter ?
Les deux sont prêts pour la production ; c'est plus une question de philosophie que de technologie. Riverpod offre la sécurité à la compilation, des providers scopés, et un style plus fonctionnel. Bloc impose un pattern strict événement/état, plus facile à documenter au prix d'un peu de verbosité. Pour les grandes apps, choisis selon le confort de ton équipe et reste cohérent. Appliquer la même chose de manière cohérente vaut mieux que de changer en cours de projet. Lis les deux docs — [riverpod.dev](https://riverpod.dev) et [bloclibrary.dev](https://bloclibrary.dev) — et prends la décision avec ton équipe.

Comments (0)

No comments yet. Be the first to comment!

Leave a Comment