
L’édition 2025 du DevFest Nantes, qui a réuni plus de 3500 passionnés à la Cité des Congrès sur deux jours intenses, restera un millésime à part pour l’équipe Ippon. Cette année, nous étions une vingtaine de Nantais, mobilisés et enthousiastes, accompagnés de nos speakers bordelais Vivien Malèze et Sébastien Oddo, venus partager leur expertise sur Open Telemetry et de Thomas Boutin venu de Tours pour échanger sur les impacts sociaux et environnementaux de nos smartphones. Notre stand n’a pas désempli, suscitant de nombreux échanges et rencontres tout au long de l’événement, entre deux conférences.

Dans la suite de cet article, nous vous proposons un retour détaillé sur les talks qui ont particulièrement retenu notre attention lors de cette nouvelle édition du DevFest. Plongez avec nous dans ces éclairages techniques qui ont nourri nos échanges et permis d’enrichir notre savoir-faire collectif.
Présenté par Jérôme Tama – Onepoint Bordeaux

Jérôme débute en comparant le code à une maison : tout y est présent, mais pas toujours à sa place. Cette métaphore illustre parfaitement les difficultés de lecture et de maintenance rencontrées par les développeurs. Son objectif est clair : montrer comment réécrire le code de manière plus efficace, maîtrisée et automatisée.
Pour cela, il présente OpenRewrite, un framework open source conçu pour automatiser la réécriture de code. Testable, distribuable et multi-langage, il supporte Java, Kotlin, Groovy, YAML, et plus récemment TypeScript. Le cœur du framework repose sur le concept de “recipes”, de petites unités atomiques capables de parcourir et transformer le code. Ces recettes peuvent se composer entre elles pour réaliser des modifications plus complexes.
OpenRewrite s’appuie sur le Lossless Syntax Tree (LST), un arbre syntaxique préservant la mise en forme et les commentaires, garantissant ainsi que la structure du code reste intacte après transformation. Les recettes peuvent être exécutées de différentes façons, que ce soit via la CLI ou des plugins comme ceux de Maven.
Pour illustrer la puissance de l’outil, Jérôme montre la migration d’un projet de JUnit 4 vers JUnit 5 : une tâche habituellement longue de trois semaines, réalisée en quelques secondes grâce à une recette existante. Il précise qu’il existe des centaines de recettes gratuites, et qu’il est même possible d’en créer sans écrire de code, via une approche déclarative.
Cependant, Jérôme met en garde : un outil aussi puissant doit être utilisé avec discernement, notamment pour la maintenance de bibliothèques internes ou open source. En conclusion, OpenRewrite incarne une approche “refactor-as-code” à la fois pragmatique, testable et reproductible, offrant un véritable gain de temps et une amélioration durable de la qualité du code.
Par Benoit Martin et Damien Raude-Morvan
Cette Unconference, un des formats inédits pour l’édition 2025 du DevFest, était une réelle découverte. Et pour cause : il n’y a pas de sujet choisi au préalable. Après un rappel des règles de bonnes conduites pour les 2h que nous allions passer ensemble (écoute, empathie, bienveillance), Benoit et Damien nous ont invité à faire un brainstorming. Nous devions réfléchir aux sujets que nous souhaitions aborder avec les participants. Nous les avons noté sur des post-its, puis nous les avons mis sur un tableau. Ensuite, nous avons voté pour nos sujets préférés. Finalement, nous avons séparé la table en deux groupes en fonction des thématiques : une sur l’ubérisation des métiers du développement et la place des invisibles dans nos métiers. L’autre sur les problématiques liées au refactoring et à la gestion de la dette à grande échelle, avec ensuite un sujet sur l’avenir du TDD avec l’avènement de l’agentique. Sur toute la durée du créneau, il était possible de changer de table comme nous le voulions, voire de quitter l’assemblée pour retourner sur le salon. La loi des deux pieds était bien en place 🙂. De manière analogue, il n’y avait pas de temps imparti pour aborder un sujet : il pouvait aussi bien être traité en 10mn qu’en 1h30.
Comme nos deux animateurs le stipulaient en préambule, nous sommes aussi nombreux et nombreuses à venir en conférence pour les discussions qui se déroulent entre les présentations. Et c’est vrai que ce format présentait ce côté rafraîchissant, et comblait les manques que nous pouvons parfois ressentir en sortie d’une présentation : manque de retour concret du terrain, débat sur les limites d’une approche ou encore l’impossibilité de poser des questions parce que le temps imparti était dépassé.
Au final, on peut en ressortir avec des outils à tester comme vibe-flow et des certitudes qui se retrouvent infirmées ou confirmées.
En conclusion, merci ! Et si le format vous intéresse, les software crafters de Nantes ont l’habitude de fonctionner de cette manière. Jetez-y un oeil !
Présenté par Sébastien Ferrer – OVHCloud Nantes

Sébastien ouvre son talk en opposant les deux grandes phases du cycle de vie logiciel : le build (développement) et le run (exploitation).Fort de son expérience d’astreinte, il décrit la difficulté de gérer plusieurs projets sans toujours les connaître en profondeur.
Être “de run”, explique-t-il, signifie assurer le suivi des incidents, des tickets et des indicateurs clés comme le TTA et le TTR, tout en restant le principal point de contact en cas de problème.Pour diagnostiquer efficacement, il faut adopter une posture de détective, en s’appuyant sur la Root Cause Analysis (RCA).
Différentes méthodes existent : le drill down, rigoureux mais long, et le bottom up, plus adapté aux couches basses comme le réseau.
Dans tous les cas, la priorité reste de restaurer le service avant de chercher la cause profonde.Une fois la situation stabilisée, vient le temps du cadrage, de la reproduction et du post-mortem.La méthode des Five Whys aide alors à remonter à l’origine du problème.
Cette logique s’inscrit dans une philosophie claire : “Développe ton application comme si tu allais la maintenir.”
Sébastien insiste ensuite sur l’importance des logs : anticiper les informations utiles, structurer les niveaux, et surtout adopter un format standardisé pour faciliter leur exploitation.Le monitoring complète cette visibilité, en offrant des métriques, des alertes et une meilleure réactivité face aux incidents.
Enfin, il relie ces bonnes pratiques à une démarche LEAN : uniformiser les projets grâce à des librairies communes, utiliser un linter pour garantir la cohérence du code, et continuer à progresser, notamment via son blog blog.kimi.ovh.
Workshop (lab de 2h) présenté par Modeste Assiongbon et Camille Pillot
Le DevFest, ce n’est pas que des conférences, mais aussi des “labs” ! Il s’agit d’ateliers de 2h, avec une trentaine de participants, où l’animateur anime une sorte de TD au travers de slides et petits exercices que les participants réalisent sur leur ordinateur.
J’ai assisté à un lab autour des signal et rxResource Angular, fraîchement matures depuis Angular 19. Ces nouveaux outils permettent de gérer des Observable de manière bien plus concise, tant dans le code TS que HTML. Elles permettent un affichage de l’état d’erreur ou de chargement simplifié. Les exercices se poursuivent sur des notions similaires avec les httpResource (qui simplifient la syntaxe d’appels serveur simples) et les LinkedSignal (qui rendent une computed modifiable au lieu de lecture seule).
Pourtant fervent utilisateur d’Angular au quotidien, j’ai appris plein de choses au travers de cet atelier, que je pourrai désormais appliquer sur mes projets !
Les exercices étaient très bien décrits et les slides très claires. La présentation est disponible sur SlideShare. Le dépôt avec les exercices est disponible sur GitHub.
Présenté par Thomas Boutin (Ippon Technologies) et Robin Caroff (U Tech)
En 2007, le smartphone entrait dans nos vies. Depuis il est devenu notre réveil, notre appareil photo, notre carnet d’adresses, notre GPS, etc et les usages évoluent constamment au fur et à mesure des nouveautés proposées par les constructeurs et les éditeurs logiciels. Mais à quel prix ?

« Mobiles en Perspective », c’est une session un peu à part au DevFest Nantes 2025 : un format unconf, participatif, inspiré de la Fresque du Climat. Pas de slides ni de monologue : ici, on échange, on réfléchit ensemble et on explore les coulisses du numérique. On va donc essayer de ne pas tout dévoiler, parce que c’est avant-tout un format où le participant est acteur de l’atelier.
Thomas et Robin nous font redécouvrir le mobile étapes par étapes, avec une série de cartes prédéfinies : de sa fabrication à nos usages quotidiens, en passant par les infrastructures qui le font fonctionner. On parle beaucoup environnement aussi dans cet atelier. L’utilisation de ressources comme l’eau et les minerais lourds nécéssaires à la construction du matériel qu’il faut extraire (souvent dans des pays exploitant le travail des enfants.). La difficulté à recycler un smartphone, et son manque de rentabilité (moins de 5€ de matière première à récupérer) ainsi que le décyclage (perte de valeur des matériaux lors du recyclage) sont les sujets qui m’ont le plus choqués.
Enfin, les animateurs nous sensibilisent sur les impacts humains qui en découlent. Parfois positifs (accessibilité, changement des méthodes de travail), et trop souvent négatifs (santé mentale, isolement, fracture numérique), le smartphone a complètement changé nos modes de vie et nos habitudes.
Le tout, dans une ambiance conviviale, ouverte à toutes et tous, sans prérequis techniques. L’objectif n’est pas de culpabiliser, mais de comprendre ensemble et d’imaginer un numérique plus soutenable. Et pour celles et ceux qui voudraient prolonger la réflexion : tout le contenu de l’atelier est open source et libre d’accès sur GitHub.
Présenté par Simon Bernardin - Mobiapps
Il existe déjà un grand nombre de frameworks multiplateformes promettant le Saint Graal : pouvoir déployer nos applications sur toutes les plateformes disponibles (android/ios/web/desktop) à partir d’une seule codebase.
Simon Bernardin, vêtu de son adorable armure et son heaume de guerre, vient alors nous présenter LynxJS, un nouveau framework cross-platform développé par ByteDance (le studio derrière TikTok), sorti le 5 mars 2025, qui cible Android, iOS, HarmonyOS et prochainement le web. Malgré son jeune âge, il est apparemment déjà utilisé par ByteDance en interne.
L'atout principal de LynxJS est son architecture à double thread automatique : le thread principal gère uniquement l'affichage tandis qu'un thread secondaire traite tous les calculs et interactions par défaut. Le framework utilise un moteur JavaScript développé spécifiquement pour le framework (Prim.js), écrit en Rust, et qui serait nettement plus rapide que ses concurrents (environ 28% plus rapide que QuickJS).
Simon termine sa présentation en définissant ses axes d’amélioration et ses points forts. En premier lieu, l’expérience développeur reste quasi inexistante sur la partie mobile avec beaucoup de choses manquantes : absence de gestion automatisée de la publication (tout doit être configuré manuellement par plateforme) et impossibilité d'utiliser des modules natifs existants, obligeant les développeurs à coder eux-mêmes les fonctionnalités natives.
Néanmoins, Il tenait à souligner les performances fluides "out of the box", la documentation qui est de qualité, ainsi que la compatibilité avec l'écosystème React permettant l'utilisation d'assistants/agents IA pour faciliter le développement.
C’est un aperçu intéressant que nous offre Simon ici bien que LynxJS reste très jeune et immature avec un écosystème limité, il mérite d'être surveillé grâce à ses promesses de performances tenues et l'écoute active de ByteDance vis-à-vis de la communauté.
Présenté par Kevin Davin - Gradle
Dans son talk, Kevin a mis en avant des fonctionnalités utiles, pratiques et souvent méconnues de SQL et de Postgres. L’objectif était de nous faire connaître ces features pour nous éviter de tout recoder “from scratch”.
Voici une liste non exhaustive de ces fonctionnalités:
Leur usage améliore la lisibilité des requêtes en fragmentant les étapes. Dans certains cas, le plan d’exécution peut bénéficier d’une exécution parallèle et donc optimiser le temps d’exécution de la requête.
Les window functions sont un outil SQL standard, qui permettent d’effectuer des calculs sur un ensemble de lignes liées à la ligne courante, sans regrouper les données comme avec GROUP BY. Un exemple courant est la déduplication via ROW_NUMBER().
Le mot-clé LATERAL permet de faire référence à des colonnes de la requête “parente” dans une sous-requête du FROM, ce qui ouvre beaucoup de possibilités (agrégations, appels de fonctions, filtrages dépendants).
Cela peut améliorer les performances en évitant des sous-requêtes coûteuses ou des jointures redondantes
L’ancienne pratique du SERIAL (auto-increment) continue d’exister, mais l’usage de UUID est recommandé pour certaines tables (notamment dans des environnements distribués ou microservices) pour éviter les attaques par énumération (si les identifiants sont séquentiels, un attaquant pourrait “deviner” des IDs).
PostgreSQL supporte nativement le type uuid et peut en générer via des fonctions intégrées comme gen_random_uuid() ou uuidv4().
Les contraintes (clé primaire, clé étrangère, contraintes de CHECK, contraintes d’unicité) sont essentielles pour protéger la cohérence et éviter la corruption de données.
Il vaut mieux s’appuyer sur les contraintes déclaratives du SGBD que sur du code applicatif pour valider la logique métier.
La commande NOTIFY permet de notifier d’un événement survenu dans la base de données. Il peut être accompagné du contenu de cet événement (le contenu d’un item qui vient d’être inséré en base par exemple). Il envoie cet événement à l’application qui a exécuté un LISTEN sur ce channel.
Les Foreign Data Wrappers permettent à PostgreSQL de consulter des sources externes comme s’il s’agissait de tables locales. Une table externe est créée et pointe sur la source externe. Cela permet d’exécuter facilement des opérations depuis Postgresql.
D’autres fonctionnalités peuvent permettre d’optimiser l’utilisation de votre moteur Postgresql (ltree, les types, jsonb pour stocker des données non structurées, … )
Conférence présentée par Julien Wittouck
Julien utilise Factorio, un jeu d'automatisation industrielle, pour illustrer des concepts d'architecture logicielle. Dans ce jeu, le joueur doit construire des chaînes de production complexes pour transformer des ressources brutes en produits sophistiqués.
Au départ, le joueur crée rapidement des usines reliées entre elles pour obtenir un résultat fonctionnel. On obtient vite du "code spaghetti" : un enchevêtrement chaotique difficile à comprendre et à faire évoluer.
En regroupant les usines par type de transformation, on crée des modules spécialisés qui alimentent les autres. Cette approche fait émerger des "couches" de responsabilités, comparable à une architecture en lasagne. Julien présente également les microservices via des drones autonomes qui transportent les ressources : excellente scalabilité (copier-coller de modules), mais problèmes d'observabilité avec des flux difficiles à suivre.
Pour passer à l'échelle, on utilise des bus partagés auxquels se connectent les modules, permettant de déployer facilement des "quartiers" entiers (parallèle avec l'IaC). Julien illustre aussi les problématiques de sécurité (attaques aliens = cyberattaques) avec son "firewall" de tourelles lance-flammes, et l'importance de l'alerting via des sondes surveillant les débits et ressources.
On se rend bien compte dans cette conférence que le jeu vidéo permet d'expérimenter et visualiser des concepts architecturaux abstraits de manière ludique. Comme le dit Julien : "Je ne joue pas quand je fais du Factorio, je travaille" – les leçons tirées du jeu sont directement applicables à l'architecture logicielle.
Cette édition 2025 du DevFest Nantes aura été riche, inspirante et fédératrice pour nos Ippons. Ces deux jours nous ont permis d’explorer de nouvelles approches, de confronter nos pratiques et d’alimenter nos réflexions, autant sur les sujets techniques que sur l’impact de notre secteur. Nous repartons avec des idées concrètes à mettre en œuvre, des échanges qui continueront d’alimenter nos projets, et l’envie de faire grandir ces apprentissages au sein de nos équipes.Un grand merci à toutes celles et ceux rencontrés sur place pour leur énergie et leur curiosité. Nous avons déjà hâte de vivre la prochaine édition et de poursuivre ces discussions qui étaient, pour la plupart, légendaires !
 
		

Le Jeudi 16 Octobre 2025 avait lieu la très attendue première édition de la PlatformCon Live à Paris, premier événement organisé par l’Organisation Platform Engineering et nos collègues de chez WeScale, dédié au Platform Engineering en France. Ce sujet étant une de nos priorités depuis cette année, nous nous devions d’être de la partie, l’occasion de retrouver les amoureux du Platform Engineering. Chez Ippon Technologies, ce vaste sujet concerne tout nos corps de métier et ce faisant nous avions constitué une équipe de choc pour y participer, tous adeptes de la philosophie DevSecOps et une vision produit autour du Platform Engineering (Architecte Cloud & DevOps, ML Ops, Tech Lead Software Engineering, Coach Craftsmanship et notre Strategy Lead Platform Engineering). Le sujet de Platform Engineering ne se cantonne pas à nos collègues Ops (ou SRE, infra, DevOps Chapter, selon vos noms chez vous) mais bien à toute personne gravitant au sein d’une DSI pour construire les produits digitaux d'aujourd'hui et demain.

Le Platform Engineering, comme nous l’a présenté Luca Galante, contributeur principal de l’Organisation Platform Engineering, lors de la Keynote d’ouverture, a fortement progressé et s’est ancré de plus en plus dans la vie des entreprises tech, passant d’une composante dans les Hype Cycles (cycle des tendances) du Software Engineering d’après Gartner, à une évolution clefs de l’IT qui a son propre cycle de vie. Une statistique plus concrète: Gartner prévoyait une adoption du Platform Engineering chez 80% des entreprises tech d’ici 2026 et en fin de compte en 2025, 90% des entreprises ont entamé des démarches pour adopter ses pratiques d’après l’institut DORA (DevOps Research and Assessment).

Si le Platform Engineering était d’abord une notion dédiée au développement logiciel, son impact avait l’air de s’étendre à d’autres horizons et de s’appliquer dernièrement à l’infrastructure, la data et encore l’IA. Le sujet de l’IA a forcément été abordé lors de cette Keynote et Luca Galante n’a d’ailleurs pas manqué de rappeler l’importance du Platform Engineering et de ses principes pour adopter correctement l’IA. La deuxième partie de la Keynote était présentée par Kelsey Hightower, ingénieur logiciel et conférencier. À travers son intervention, il a précisé un point que beaucoup de personnes se posent: non, le Platform Engineering n’est pas une invention de ces dernières années, c’est un nom qui a été apposé à une tendance qui existe depuis longtemps, la Plateformisation, mais qui n’avait jamais été correctement définie avant.
Tout d’abord, ce n’est pas un rassemblement d’experts Unix, de mangeurs de hardware ou fanatiques de bare metal (même si une majorité en est passionnée). Il s’agit d’un rassemblement autour d’une vision partagée sur comment faire mieux dès demain en termes d’organisation de votre DSI.
Si vous attendiez d’avoir à PlatformCon la recette magique parfaite pour monter une Plateforme de développement interne ou de connaître la stack technique idéale pour la mettre en place alors vous serez déçu.
Une plateforme IT, la majorité des entreprises en possède une qui s’est construite au fil des 10 voir 20 dernières années avec ses évolutions majeures (l’arrivée de l’agilité, l’émergence de la virtualisation puis de la conteneurisation, l’avènement de la philosophie Cloud & DevOps qui s'orna du préfix Sec quelques années plus tard).
C’est avant tout une journée où nous pouvons échanger sur nos expériences (réussites comme échecs) autour de la mise en place d’une plateforme. Peut-on considérer que la PlatformCon est aux DevOps ce qu’est DDD Europe au craftsmanship ?
Bien sûr, on va parler solution technique sur table pour accélérer la Plateformisation. Vous n’aurez jamais autant entendu le terme Kubernetes à une conférence … ou alors peut-être à la KubeCon 😀! Mais toujours avec un énorme panneau “warning”, vous indiquant d’être vigilant sur les technologies présentées car bien souvent, elles sont amenées dans un contexte particulier pour des besoins propres à l’entreprise (ne faites pas de Kubernetes si vous êtes au début de votre chemin pour la Plateformisation, baby step first).
Cette année, le focus a été sur des retours d’expérience de mise en place de Platform Engineering pour diverses entreprises avec chacune leur modèle (de la société offrant des service numériques, en passant par la banque, la plateforme data mais aussi la startup boostée par des investisseurs, etc…). Grâce à ce panel d’entreprises avec chacune leur stratégie d’évolution, leur budget, leur philosophie organisationnelle, on peut arriver à trouver des idées / similarités à notre entreprise et s’en inspirer pour à son tour se challenger et grandir.
KISS: Keep it simple, stupid
Cet acronyme n’a jamais été aussi vrai. Tous les speakers qui sont intervenus sont alignés sur cette vision. Vouloir aller trop vite et trop complexe, dans le cadre de la mise en place d’une plateforme, est un échec assuré.
Tout d’abord, on commence par mettre à disposition des API Rest pour consommer les solutions et services. Même si pour certains cette étape est évidente, pour une majorité d’entre nous c’est un travail à mener (définir les bons contrats, identifier les services à exposer, prévoir de l’extension, adapter les outils aux usages des équipes, etc…). Si vous avez déjà un ensemble de services exposés par API au travers d’un point d’entrée unique (bien souvent une API Gateway), alors vous avez déjà acquis l’expérience pour avoir une vision produit de vos services, définir une organisation pour porter ces services et surtout acculturer et communiquer avec vos équipes pour l’usage et l’évolution de ce premier layer de votre plateforme.
Ensuite, on peut se poser la question de monter une IHM (Interface Homme Machine) pour améliorer la DevX (developer experience). Encore une étape pour faire grandir votre SI avec des questions comme:
De nombreux Design Systems existent en opensource et peuvent être des accélérateurs avant même de construire le vôtre.
Un product owner (celui de votre plateforme), 2 à 3 développeurs est un bon début pour monter ce produit.
On évite de se lancer à corps perdu dans les métriques DORA dès le début (de nombreux REX en parlent). On peut commencer KISS (Keep It Simple and Stupid) avec le Squad Health Check de Spotify. On rencontre les équipes une fois par mois par exemple (pas trop souvent) et on leur demande leurs pain points concernant la Plateforme, leurs besoins, etc…
Créer une plateforme sans jamais échanger avec les équipes qui l'utilisent, sans leur proposer d’y participer (contribution interne, ouverture des dépôts de code) est un échec assuré. Profitez de vos équipes d’expertise technique (DevEx team, enabler team, coach interne) pour évangéliser les équipes à l’usage de votre Plateforme.
Eat your own food
Encore merci Mirakl pour cette citation qui est forte en sens. Il est important que vos équipes en charge de la plateforme soient les premières à s’en servir. Ils sont les mieux placés pour critiquer les produits proposés. Et on en revient à l’idée de l’inner sourcing avec la facilitation des évolutions par la contribution interne sur les bases de vos standards à vous. Votre plateforme reflète vos standards techniques.
L’expérimentation ne s’arrête jamais
Il ne faut pas craindre les échecs car ils sont toujours instructifs et la courbe d’apprentissage de la Plateformisation n’est pas linéaire. La Plateformisation est un excellent moyen d'expérimenter au sein de votre SI de nouvelles méthodologies, pratiques (ex: mise en place de feature flipping, rollout gateway, fine-tuning kafka), outils etc …
Vigilance sur l’usage de l’IA
Mais alors, le big boss final de la plateforme, c’est la mise en place d’un chatbot sur notre plateforme ou d’un agent de Plateformisation ? La réponse est claire et concise: NON.
On en revient à notre KISS, mais il est impératif de savoir faire une Plateforme avec votre vision et qui apporte de la valeur à vos équipes avant de vouloir l’enrichir avec de l’IA. On n’investit pas sur un agent IA plateforme avant même d’avoir créé sa plateforme. La plateforme se veut être un accélérateur fournissant un ensemble de guidelines, golden path, documentation avant tout. Il ne doit en aucun cas être un enjeu pour faire de l’IA. L’IA peut enrichir votre produit si vous êtes mature sur le sujet et des speakers ont indiqué se lancer sur ce sujet avec des use cases identifiés chez eux.
Comme disait Kelsey Hightower lors de la Keynote, si c’est pour faire un agent IA qui reset votre mot de passe, alors qu’un simple clique sur un reset est possible et que derrière cela vous demande une usine à gaz pour rattraper l’aspect non déterministe de l’IA, alors vous allez dans le mur.
Un alignement existe tout de même sur l’idée d’utiliser l’IA afin d'accélérer l'accès à de la documentation et simplifier la rédaction de documentation. C’est là où est la force de l’IA (et surtout du NLP), grâce à elle, il est possible de répondre rapidement aux besoins d’un développeur concernant la plateforme sur la base d’un agent conversationnel. Mais soyez conscient qu’il faut garder un système de débrayage avec des équipes de supports accessibles par divers canaux (ticketing via Jira, thread via Slack ou Teams, etc…).
Pour ceux d’entre vous qui souhaiteraient avoir un petit résumé des conférences que nous sommes allés voir, nous y consacrons cette section.
Julien Briault est un des speakers ayant été présent sur de nombreuses conférences en France en cette année 2025, nous avions déjà pu le voir présenter son magnifique sujet à des conférences comme Touraine Tech en février de cette année.
Ce premier talk de la journée a été une leçon d’humilité pour nous face à l’implication de Julien Briault, SRE chez Deezer mais aussi bénévole chez les Restos du Coeur. Julien est venu présenter son projet Cloud du Coeur, le Cloud privé des Restos du Coeur qu’il met en place depuis 4 ans afin de permettre à l’association et ses 78 000 bénévoles d’accéder aux outils numériques indispensables pour assurer leur mission tout en permettant à l’association d’économiser de précieuses ressources financières afin de fournir plus de repas au plus démunis. Un très beau projet qui allie technologie et social, merci Julien pour ce talk et bravo à toute ton équipe.

Dans cette présentation, Romain Broussard, VP Platform Engineering (un intitulé de poste pas commun en France) chez Mirakl (éditeur de logiciel français) nous présente l’approche qu'il a eu lors de la mise en place de son équipe Plateforme et pose notamment l’accent sur l’approche produit qu'il faut avoir dans cette situation. En effet, de nombreuses entreprises font l’erreur de ne se concentrer que sur l’aspect technique du Platform Engineering sans aborder les vrais problèmes des structures. L’équipe Plateforme de Mirakl a mis en place une portail interne de développement mais Romain nous met en garde: nous pouvons avoir tendance à vouloir mettre en place un IdP(Internal Development Portal) directement en utilisant des projets comme Backstage de Spotify par exemple mais ceux-ci sont très complexes à mettre en place et il est préférable de d’abord exposer les services que l’on souhaite via des API par exemple, les mettre à disposition des développeurs avant de vouloir forcément une interface graphique. Si je devais retenir 2 leçons de cette conférence très intéressante : APIser d’abord et être soi même client de sa Plateforme pour pouvoir l’améliorer.
Chez Meilleurtaux, acteur du courtage en placement, assurance et crédit, l’hétérogénéité des équipes et l’absence de standards Dev, Sec et Ops freinaient l’innovation. Pour y remédier, l’entreprise a créé une équipe plateforme from scratch, combinant prestataires et recrutements internes, et impliquant l’ensemble des équipes infra, Ops, Sec et Dev.
Chaque squad dispose d’un champion DevSecOps, un Golden Path guide les développeurs, et l’architecture Hub & Spoke sécurise les environnements via des Landing Zones. L’objectif : réduire le Time to Cloud tout en garantissant sécurité et qualité.
Les bénéfices sont tangibles : autonomie accrue, déploiements plus rapides et sécurisés, meilleure visibilité sur les coûts et accès aux nouvelles fonctionnalités. Les défis restent la résistance au changement et la dette technique héritée.
Pour l’avenir, Meilleurtaux prévoit extension vers le cloud et la data, sandbox d’expérimentation, standardisation et suivi des métriques DORA et FinOps, tout en continuant l’onboarding de nouvelles squads.
Conçue au sein du ministère de l’Intérieur, Cloud Pi Native illustre la montée en puissance du Platform Engineering dans le secteur public. Née d’un simple besoin de simplifier le déploiement d’applications, la Plateforme est devenue un produit stratégique, capable d’héberger des projets critiques tels que le Système d’Immatriculation des Véhicules (SIV) ou des applications interministérielles (Intérieur, Armées, Justice).
Dans la continuité de la stratégie cloud de l’État (2021), Cloud Pi Native s’inscrit dans une logique de souveraineté numérique et de maîtrise des infrastructures. Elle repose uniquement sur des briques open source et s’intègre dans l’écosystème des clouds souverains internes (Cloud Pi, Nubo) et des clouds de confiance (S3NS, Scaleway).L’objectif : conjuguer agilité, sécurité et indépendance tout en respectant les exigences réglementaires et les niveaux de confidentialité (jusqu’au niveau Diffusion Restreinte).
Cloud Pi Native offre un ensemble de services pour accélérer le time-to-market, mutualiser les ressources et améliorer la satisfaction des utilisateurs. Selon le degré d’intégration, les équipes ministérielles peuvent déployer leurs applications plus rapidement et en toute autonomie, tout en conservant un haut niveau de gouvernance et de sécurité.
Les prochaines évolutions incluent :
Avec déjà 30 projets en production et plus de 100 agents formés, Cloud Pi Native s’impose comme un levier de modernisation et un vecteur de souveraineté numérique.Abstraction, standardisation, self-service, observabilité et sécurité by design : cette Plateforme open source incarne une nouvelle génération d’infrastructures publiques, pensées pour l’efficacité et la confiance.
Hela Ben Farhat, Product Manager chez BPIfrance, aborde un sujet incontournable lorsqu’on met en place une équipe plateforme, c’est sa rentabilité par rapport aux équipes métier. Chez Bpifrance Digital, le Platform Engineering est désormais perçu comme un levier économique majeur, surpassant le statut de simple centre de coût. S'inspirant de l'impact de la machine à laver sur l'économie du 20e siècle, qui a libéré du temps pour l'innovation, la plateforme a pour mission de libérer les développeurs pour l'accélération et la créativité. Architecturalement, la plateforme est le cœur numérique, positionné entre les fondations (infrastructure Cloud, services internes) et les Produits Digitaux Métiers (parcours clients, demandes de financement). Conçue pour être générique, réutilisable et exposée via API, elle remplit une double fonction: elle est une couche d'abstraction masquant la complexité des fondations, et une couche d'accélération pour les équipes de développement.
Pour prouver cette valeur stratégique et répondre aux doutes initiaux des décideurs, Bpifrance s'appuie sur le calcul du ROI. Actuellement, la Plateforme affiche une rentabilité de 300 %, soit 3 € gagnés pour chaque euro investi. L'ambition est d'atteindre 5 € pour 1 € d’ici deux ans. Ce gain se décompose en trois familles : les économies de réutilisation, les gains de productivité, et les gains business (réduisant le time-to-market pour certains produits d’un an à trois mois). Au-delà de ces métriques quantifiables, la démarche intègre l'impact des gains invisibles, tels que la fidélisation client et l'amélioration de l’expérience développeur, qui ne figurent pas dans les calculs mais renforcent la performance globale de l’entreprise.
La pérennisation de ces bénéfices repose sur trois piliers fondamentaux. Le premier est le maintien d'un modèle économique lisible ; le second est une approche produit proactive qui se concentre sur le consommateur (le développeur) via le continuous discovery, visant à abandonner la "feature factory" pour prioriser les sujets alignés sur les enjeux business. Le troisième pilier est l’excellence opérationnelle, essentielle pour garantir la robustesse, la performance et la sécurité de la Plateforme.
Malgré ces succès, des défis persistent, notamment la nécessité d'une transformation culturelle vers un état d’esprit "produit" au sein des équipes, et la fiabilisation des mesures (acceptant l'imprécision des gains de productivité). À l'avenir, Bpifrance mise sur l'intégration de l'IA et des Plateformes "Agentic" pour orchestrer des agents, automatiser des chaînes de valeur entières et démultiplier l'innovation.
Cette journée à la PlatformCon aura été riche en informations et retours d’expériences. Nous avons déjà hâte d'assister à la prochaine édition.
 
		
Mardi 16 septembre dernier, notre équipe Ippon était de retour pour les 10 ans du Salon de la Data et de L’IA de Nantes. Cet événement phare de la place nantaise nous permet de nous informer sur les dernières tendances et de renforcer nos liens avec la communauté tech.
Voici un résumé de quelques conférences auxquelles nous avons assisté.
Chose étonnante, Zazie Casimir-Favrot et Matthieu Chatry nous ont donné rendez-vous non pas dans une salle, mais sur l'esplanade de la Cité des Congrès. Au programme de cet atelier : une promenade dans le quartier.

La Datawalk, ou promenade de données, est un concept venu de Belgique. Il s'agit d'une visite guidée qui vise à nous faire (re)découvrir le mobilier urbain devenu invisible dans notre quotidien, mais dont la composante numérique améliore notre vie de tous les jours.
Le premier arrêt nous a conduits devant une station de vélos en libre-service Naolib. Un employé de JCDecaux, la société exploitante, nous a expliqué son fonctionnement et les données collectées. Ils sont capables de savoir si un vélo est amarré à une station ou s'il est en cours d'utilisation. Cela leur permet de connaître la fréquentation des stations pour optimiser la redistribution des vélos, améliorer le maillage des stations et rendre des comptes à la Métropole. Mais n'ayez crainte, les vélos ne sont pas géolocalisés et JCDecaux prend la RGPD au sérieux : les trajets non facturés (d'une durée inférieure à 30 minutes) sont anonymisés, et ceux qui sont facturés sont purgés au bout de 3 ans.
La balade nous a ensuite menés devant un guichet automatique de banque (GAB) du CIC, où une employée du groupe Société Générale nous a livré quelques anecdotes. Une employée de la Société Générale devant un CIC, n'y a-t-il pas là un problème ? Pas quand on sait que les GAB des banques BNP Paribas, Crédit Mutuel, CIC et Société Générale seront tous regroupés sous la marque Cash Services.
Prochain arrêt : une station d'autopartage Marguerite. Ces voitures sont truffées de capteurs et, à la différence des vélos, elles sont géolocalisées, mais pas en temps réel.
Le quatrième arrêt nous a conduits dans une pharmacie. La pharmacienne nous a fait une démonstration de son robot préparateur. En plus de préparer les commandes, cette énorme machine, constituée d'un grand couloir bordé de deux étagères, range et indexe automatiquement les médicaments. Ainsi, les médicaments souvent prescrits ensemble sont colocalisés pour optimiser les déplacements. De plus, il gère seul les dates de péremption afin de limiter les pertes.
Nous avons terminé cette DataWalk par une touche culturelle, devant le Grenier du Siècle. Ce lieu est une gigantesque capsule temporelle où les Nantais ont déposé des objets en 1999, à destination de leurs descendants de 2100.
Cet atelier était une bouffée d’air (pur ?) parmi toutes les conférences sur l’IA générative et ses agents.
Dans ce quickie Angéline Perennes et Mourad Bouallak nous parlent de l’utilisation de l’IA générative en entreprise.
Le «Shadow AI» désigne l’utilisation de l’intelligence artificielle en dehors du cadre autorisé ou défini par l’entreprise. Un phénomène de plus en plus fréquent, porté par la curiosité, le besoin de productivité et l’accessibilité des outils d’IA générative.
Ce constat fait écho au paradoxe de la Reine Rouge, tiré d’Alice au pays des merveilles : dans un monde où tout évolue très vite, rester immobile revient à reculer. Pour les entreprises, interdire purement et simplement l’usage de l’IA reviendrait à se mettre en retrait, au risque d’être dépassées par les concurrents.

Il devient donc essentiel de proposer un cadre clair, qui permette de profiter des avantages de l’IA (gain de temps, automatisation, assistance à la création, etc.) tout en limitant les risques. Ces risques sont bien réels : près d’un prompt sur douze contient des données sensibles, exposant les organisations à des violations du RGPD ou à des pertes de propriété intellectuelle.
Refuser l’usage de l’IA sans alternative crée souvent de la frustration chez les employés, qui chercheront à contourner les interdictions. La réponse n’est donc pas l’interdiction, mais la formation.
Des programmes comme Objectif IA (OpenClassrooms) permettent de sensibiliser les collaborateurs à un usage responsable et maîtrisé de ces outils, tout en accompagnant l’évolution rapide des pratiques professionnelles.
En début d’après-midi s’est tenue une table ronde d’une trentaine de minutes sur un sujet encore peu abordé lors du salon : la place des femmes dans le domaine de la data et de l’IA. Trois intervenantes aux parcours inspirants ont échangé sur leurs expériences, leurs visions du secteur et les défis, techniques comme moraux, auxquels elles ont fait et font toujours face en tant que femmes dans la tech.
Andrea Leylavergne, data scientist et directrice de l’association Women in Big Data, a ouvert le débat. Engagée depuis plusieurs années dans la promotion des carrières féminines dans la tech, elle milite pour une meilleure visibilité des femmes dans la data. Pour elle, la représentation est le premier levier de transformation pour que les choses évoluent dans le bon sens. Son action au sein de l’association vise justement à présenter des modèles auxquels les jeunes femmes peuvent s’identifier, en mettant en avant des parcours variés et ambitieux.
Parmi ces modèles, certaines femmes se montrent plutôt optimistes quant à l’avenir du féminin dans la tech, convaincues que les choses progressent. C’est le cas de Camille Marini, docteure en océanographie dynamique et aujourd’hui Director of Machine Learning chez Sonos. Pour elle, l’enjeu est avant tout d’encourager les étudiantes à se faire confiance et à oser les carrières techniques.
Plus tranchée dans ses propos, Fransceca Iannuzzi, Head of Data chez iAdvize, a évoqué sans détour les obstacles quotidiens rencontrés dans un milieu encore largement masculin. Elle raconte même, avec une pointe d’ironie, un épisode de mansplaining qu’elle a vécu à peine trente minutes avant le début de la table ronde. Il s’agit de ces situations dans lesquelles un homme explique à une femme quelque chose qu’elle sait déjà, voire dont elle est experte, souvent sur un ton paternaliste ou condescendant.

De ces échanges, un message clair ressort : les femmes ont toute leur place dans la data et l’IA, mais la bataille n’est pas que technique. La compétence n’a pas de genre, mais la confiance, elle, se construit. Comme le souligne Fransceca, il faut « redistribuer les cartes dès la crèche » : donner aux petites filles des modèles inspirants et apprendre aux petits garçons à écouter, à collaborer, à co-construire. Le débat s’est conclu sur une note d’espoir pour tous : quel que soit le genre ou le milieu social, l’essentiel est d’oser et d’y croire.
Lien vers les articles des années passées:
Une journée au salon de la data 2022
Une journée au salon de la data et de l'IA 2023
Une journée au salon de la data et de l'IA 2024
 
		
L’édition 2025 du Snowflake World Tour a placé l’intelligence artificielle au centre de toutes les discussions. Mais au-delà du simple buzzword, c’est une vision stratégique et opérationnelle qui s’est dessinée, une déclaration d'une ambition dévorante : transformer Snowflake d'une Data Cloud Platform en une "AI Data Cloud Platform". Cette refonte se concrétise par une plateforme unifiée, conçue pour simplifier radicalement l’accès à la data et à l’IA, tout en renforçant la confiance dans les résultats. La keynote, animée par des figures telles que Cecil Bove, Regional Vice President de Snowflake et Sridhar Ramaswamy, CEO de Snowflake, a posé les fondations d’un écosystème où la complexité technique s’efface au profit de la puissance et de l’accessibilité.
La simplicité a été érigée en différenciateur majeur face à la concurrence. Là où d’autres acteurs multiplient les fonctionnalités au risque de fragmenter l’expérience utilisateur, Snowflake mise sur une intégration native et fluide entre le cloud, la data et l’IA. Cette philosophie a été illustrée par un partenariat stratégique mis en scène avec le CEO d’Azure, Satya Nadella. Si les détails opérationnels de cette collaboration restent à préciser, elle symbolise une alliance forte dans un paysage cloud où les frontières, entre partenariat et concurrence, deviennent poreuses.
Une démonstration captivante est venue d’Hugo Barret, Solution Engineering Manager chez Snowflake, qui a présenté les nouvelles fonctionnalités avec un leitmotiv : faire de Snowflake une plateforme autonome et fiable. La gouvernance de l’IA a été placée au premier plan, comme un pilier essentiel pour garantir la transparence et la fiabilité des modèles génératifs. Pour soutenir cette ambition, la couche sémantique a été présentée comme le socle de l’IA générative, structurant les données de manière intelligible et ouvrant la voie à des outils comme Horizon Agent, dédiés aux Data Stewards. L’annonce d’un format généralisé, Open Semantic Interchange marque concrètement les intentions de Snowflake.
L’annonce la plus marquante restera sans doute Snowflake Intelligence : un chatbot métier capable d’interroger les bases de données en langage naturel, sans requête SQL. Une révolution pour les utilisateurs non techniques, qui pourront désormais exploiter la data via de simples prompts. Cette démonstration, enrichie par l’intervention d’Elizabeth den Dulk, Enterprise Solution Engineer chez Snowflake, a montré comment l’IA s’intègre désormais directement dans les pipelines, permettant de traiter aussi bien des données structurées que non structurées, comme des transcriptions audio ou des analyses d’images.
La keynote s'est conclue par un retour d'expérience concret de TF1, représenté par son Chief Data Officer, François-Xavier Pierrel. Il a détaillé le virage data du groupe pour soutenir sa transition vers le streaming (TF1+), gérant des volumes de données importants pour personnaliser l'expérience de millions d'utilisateurs. Son mot de la fin, à la fois drôle et décalé, a offert un moment de légèreté : « Ce n’est pas grave de rater, il faut juste que cela arrive une fois ». Une conclusion qui, à contre-courant du "fail fast" habituel, a rappelé avec humour que l'innovation, si elle comporte des risques, doit avant tout mener à un succès durable.
Au-delà de la keynote, plusieurs retours d’expérience ont illustré la maturité croissante de la plateforme.
L’intervention de Saint Jean, groupe agroalimentaire historique, a illustré comment une migration vers Snowflake, facilitée par l’outil Coalesce et son interface no-code, a permis de transformer une culture data encore émergente en une véritable capacité industrielle. En passant de plus de 30 rapports statiques à seulement deux rapports dynamiques, l’entreprise a non seulement regagné la confiance des métiers, mais aussi accéléré son time-to-value. Le choix de Coalesce, pour son interface visuelle et son intégration native, a été crucial pour une équipe initialement dépourvue de data engineers experts.
Le cas Stellantis a, quant à lui, impressionné par son ampleur. Face à un héritage technique complexe – 16 plateformes data distinctes – le constructeur automobile a su unifier son paysage autour de Snowflake, en s’appuyant sur une stack moderne intégrant dltHub et dbt. Leur framework open source, couplé à un monitoring maison basé sur Elastic, leur permet de gérer des milliers de pipelines et une centaine de développeurs avec une rigueur remarquable. L’utilisation des Data Metric Functions (DMF) de Snowflake pour piloter la qualité des données à grande échelle témoigne d’une vision résolument industrielle.
Enfin, la conférence dédiée à l’interopérabilité avec le format Apache Iceberg a confirmé la volonté d’ouverture de Snowflake et sa stratégie pour éviter le vendor lock-in. Grâce à des innovations comme l’intégration de catalogues externes (tel que Polaris, le catalogue open source de Snowflake) et la possibilité d’écrire directement dans des tables Iceberg, la plateforme permet de séparer le stockage des données du moteur de calcul, tout en conservant la scalabilité et la performance du compute Snowflake.
Cette édition du Snowflake World Tour a confirmé une ambition claire : faire de Snowflake une plateforme tout-en-un, où l’IA, la data et le cloud s’intègrent de manière fluide et accessible. Les annonces vont toutes dans le même sens : réduire la complexité pour les utilisateurs métiers, automatiser les tâches techniques et intégrer l’IA non comme une couche supplémentaire, mais comme un levier de productivité native.
Cette évolution interroge néanmoins les rôles traditionnels. L’émergence d’outils comme Snowflake Intelligence et la couche sémantique pourrait bien redistribuer les cartes, faisant évoluer le métier de Data Analyst vers des profils plus spécialisés, comme le Data Steward, garant de la qualité et de la cohérence sémantique.
Si la vision de Snowflake se concrétise, la plateforme pourrait bien s’imposer comme la référence incontournable pour les entreprises cherchant à unifier leur stack data, sans pour autant renoncer à la puissance et à l’expertise technique offerte par des écosystèmes ouverts et interopérables.
 
		
Cela fait plusieurs semaines que j’ai booké une session “lab / discovery” sur le sujet des RAG mais abordé par le prisme d’une technologie particulière : Neo4J.
Neo4J, c’est le leader de la base graphe. C'est un outil particulièrement adapté aux nouveaux enjeux technologiques dans lesquels on manipule des données pas forcément structurées. Ayant déjà utilisé Neo4J plusieurs années auparavant, je me souvenais d’un outil abouti et vraiment performant. Et c’est donc tout naturellement que j’ai voulu participer à ce Lab pour voir où se situait Neo4J dans la galaxie des outils qui gravitent dans l'écosystème LLM / IA.
En voici une synthèse.
Après la classique présentation de la société Neo4J, du principe des bases graphes, et pourquoi c’est bien de l’utiliser, on nous présente “Neo4j Aura Professionnal” qui est la solution SaaS de Neo4J et qui se décline en plusieurs briques :
Evidemment, Neo4j Aura Professionnal est indépendant du cloudProvider : on va donc pouvoir l’installer sur les grands fournisseurs de cloud, et ce, en quelques clics. Mais il est également possible de faire du self managed.
Le Lab (et tout ce qui est nécessaire) est accessible depuis le github de Neo4J :
https://github.com/neo4j-partners/hands-on-lab-neo4j-and-bedrock/tree/main
La formation se déroulant dans les locaux d’AWS, il était normal que le choix du cloudProvider soit AWS. Les premières étapes consistent à déployer sur un compte AWS de “bac à sable” une instance du moteur neo4j. Comme c’est une solution SaaS, complètement intégrée dans l’AWS Marketplace, cela se fait très facilement :

Notez qu’il faudra sélectionner à minima “Neo4J AuraDB Professionnal (pay as you go)” pour bénéficier des fonctionnalités IA.
Notez également que le système de Licensing Neo4J n’autorise pas à déployer en production la version communautaire, qui est de toute façon bridée.
Pour vos productions, il faudra sélectionner “Neo4J Enterprise Edition”.
Une fois déployée, nous nous connectons sur l’interface via la console d’administration :
Puis nous enchaînons sur une étape de création de la base graphe à l’intérieur de notre instance. Et enfin, nous la remplissons.
L’ensemble de ces étapes sont très bien décrites dans le repo github.
Un SA AWS nous présente le service AWS BedRock et les différents modèles qu’il supporte.
Ce n’est pas l’objet de ce billet mais voici quelques notes :
Amazon BedRock est une surcouche au-dessus des modèles que vous aurez sélectionnés. Je citerai juste ce que le SA AWS nous a conseillé : “Dans votre phase exploratoire, n’hésitez pas à tester les différents modèles : entre pertinence et coûts associés, trouvez le modèle qui correspond le plus à vos besoins.”
Ici, nous utilisons Anthropic et le modèle claude-sonnet-4-20250514-v1 comme LLM.
Pour terminer notre environnement, nous déployons, côté AWS, un domaine “SageMaker” pour dérouler les notebooks Jupyter fournis dans le repository git.
Voici les grandes lignes du notebook :
Objectif : Utiliser le LLM claude sonnet pour parser automatiquement des données semi-structurées (mélange de texte et XML) issues d’un fichier initial.
Le notebook permet de montrer comment générer des requêtes Cypher (langage natif neo4j pour interagir avec la base graphe) pour charger les données extraites dans notre base neo4J. Notez qu’à aucun moment on écrit un parser spécifique : c’est le LLM qui se charge de tout.
Le notebook utilise des prompts spécifiques pour guider le LLM dans l’extraction des informations. Dans notre cas particulier, nous manipulons des “managers” et des informations sur des “investments”. Voici les prompts (que vous pouvez retrouver directement dans le notebook).
mgr_info_tpl = """From the text below, extract the following as json. Do not miss any of these information.
* The tags mentioned below may or may not namespaced. So extract accordingly. Eg: <ns1:tag> is equal to <tag>
* "managerName" - The name from the <name> tag under <filingManager> tag
* "street1" - The manager's street1 address from the <com:street1> tag under <address> tag
* "street2" - The manager's street2 address from the <com:street2> tag under <address> tag
* "city" - The manager's city address from the <com:city> tag under <address> tag
* "stateOrCounty" - The manager's stateOrCounty address from the <com:stateOrCountry> tag under <address> tag
* "zipCode" - The manager's zipCode from the <com:zipCode> tag under <address> tag
* "reportCalendarOrQuarter" - The reportCalendarOrQuarter from the <reportCalendarOrQuarter> tag under <address> tag
* Just return me the JSON enclosed by 3 backticks. No other text in the response
Text:
$ctext
"""
filing_info_tpl = """The text below contains a list of investments. Each instance of <infoTable> tag represents a unique investment. 
For each investment, please extract the below variables into json then combine into a list enclosed by 3 backticks. Please use the quoted names below while doing this
* "cusip" - The cusip from the <cusip> tag under <infoTable> tag
* "companyName" - The name under the <nameOfIssuer> tag.
* "value" - The value from the <value> tag under <infoTable> tag. Return as a number. 
* "shares" - The sshPrnamt from the <sshPrnamt> tag under <infoTable> tag. Return as a number. 
* "sshPrnamtType" - The sshPrnamtType from the <sshPrnamtType> tag under <infoTable> tag
* "investmentDiscretion" - The investmentDiscretion from the <investmentDiscretion> tag under <infoTable> tag
* "votingSole" - The votingSole from the <votingSole> tag under <infoTable> tag
* "votingShared" - The votingShared from the <votingShared> tag under <infoTable> tag
* "votingNone" - The votingNone from the <votingNone> tag under <infoTable> tag
Output format:
* DO NOT output XML tags in the response. The output should be a valid JSON list enclosed by 3 backticks
Text:
$ctext
"""
La variable $ctext sera remplacée par chaque ligne récupérée du fichier initial.
Le notebook fournit des fonctions spécifiques permettant d’interagir avec le LLM, comme par exemple le moyen de découper (chunk) les données pour éviter de dépasser les limites de tokens du LLM.
Le LLM est utilisé pour générer des requêtes Cypher à partir des données extraites, afin de les charger dans Neo4j.
Même si ce n’est pas une révolution, on sent bien toute la puissance du LLM : à partir d’un fichier non structuré (le fichier de départ contient des données XML et des données en vrac), le LLM arrive à ne pas se perdre et à extraire les 2 listes d’informations relatives à des entités métier : le manager et le “investment”.
La session continue sur le lab 6 “ChatBot”. Il se base sur la librairie python “gradio” pour mettre en place cette fenêtre conversationnelle.
Le fonctionnement qui est proposé par ce nouveau notebook est le suivant :
Dans ce notebook, on nous présente l’avantage de l’utilisation de Neo4J. Sans précision particulière, une question du style : “Which managers own FAANG stocks?” ne permet pas d’avoir une réponse pertinente.
En effet, un modèle de langage (comme ceux utilisés dans les chatbots) peut reconnaître des termes courants comme FAANG (Facebook, Apple, Amazon, Netflix, Google ), mais il ne donnera que des réponses générales et limitées.
Or, dans un environnement professionnel, les questions portent souvent sur des données spécifiques : des noms de projets, des relations entre entités, ou des règles internes. Un LLM seul ne connaît pas ces détails. Neo4j résout ce problème en stockant ces informations dans un graphe de connaissances, où chaque élément est relié de manière structurée.
Grâce à LangChain, on peut alors :
C’est cette combinaison — LLM + Neo4j — qui permet de passer d’une réponse vague à quelquechose de beaucoup plus pertinent pour notre contexte.
Voici le schéma présenté dans le notebook :

Pour permettre au LLM de traduire la question de l’utilisateur en “Cypher Chain”, encore une fois, nous allons fournir un “prompt” qui va le guider. Il est disponible dans le notebook et est plutôt assez gros. Ci-joint un extrait de ce prompt :
CYPHER_GENERATION_TEMPLATE = """You are an expert Neo4j Cypher translator who understands the question in english and convert to Cypher strictly based on the Neo4j Schema provided and following the instructions below:
<instructions>
* Use aliases to refer the node or relationship in the generated Cypher query
* Generate Cypher query compatible ONLY for Neo4j Version 5
* Do not use EXISTS, SIZE keywords in the cypher. Use alias when using the WITH keyword
* Use only Nodes and relationships mentioned in the schema
* Always enclose the Cypher output inside 3 backticks (```)
* Always do a case-insensitive and fuzzy search for any properties related search. Eg: to search for a Company name use `toLower(c.name) contains 'neo4j'`
* Use the relationship variable `o` to access the `shares` and `value` properties of the `OWNS` relationship when calculating the sums.
* Cypher is NOT SQL. So, do not mix and match the syntaxes
* Use the elementId() function instead of id() to compare node identifiers
</instructions>
Strictly use this Schema for Cypher generation:
<schema>
{schema}
</schema>
The samples below follow the instructions and the schema mentioned above. So, please follow the same when you generate the cypher:
<samples>
Human: Which fund manager owns most shares? What is the total portfolio value?
Assistant: ```MATCH (m:Manager) -[o:OWNS]-> (c:Company) RETURN m.managerName as manager, sum(distinct o.shares) as ownedShares, sum(o.value) as portfolioValue ORDER BY ownedShares DESC LIMIT 10```
Human: Which fund manager owns most companies? How many shares?
Assistant: ```MATCH (m:Manager) -[o:OWNS]-> (c:Company) RETURN m.managerName as manager, count(distinct c) as ownedCompanies, sum(distinct o.shares) as ownedShares ORDER BY ownedCompanies DESC LIMIT 10```
Human: What are the top 10 investments for Vanguard?
Assistant: ```MATCH (m:Manager) -[o:OWNS]-> (c:Company) WHERE toLower(m.managerName) contains "vanguard" RETURN c.companyName as Investment, sum(DISTINCT o.shares) as totalShares, sum(DISTINCT o.value) as investmentValue order by investmentValue desc limit 10```
Human: What other fund managers are investing in same companies as Vanguard?
Assistant: ```MATCH (m1:Manager) -[o1:OWNS]-> (c1:Company) <-[o2:OWNS]- (m2:Manager) WHERE toLower(m1.managerName) contains "vanguard" AND elementId(m1) <> elementId(m2) RETURN m2.managerName as manager, sum(DISTINCT o2.shares) as investedShares, sum(DISTINCT o2.value) as investmentValue ORDER BY investmentValue LIMIT 10```
Human: What are the top 10 investments for rempart?
Assistant: ```MATCH (m:Manager) -[o:OWNS]-> (c:Company) WHERE toLower(m.managerName) contains "rempart" RETURN c.companyName as Investment, sum(DISTINCT o.shares) as totalShares, sum(DISTINCT o.value) as investmentValue order by investmentValue desc limit 10```
...
Human: {question}
Assistant:
"""
Maintenant qu’on a guidé notre LLM avec suffisamment de contexte dans notre prompt, il nous reste plus qu’à exploiter la puissance de Neo4J avec notre LLM.
Le notebook montre comment utiliser LangChain pour "ancrer" le LLM avec Neo4j, c’est-à-dire :
LangChain agit comme un pont entre le LLM (générique) et Neo4j (spécifique).
Il permet de structurer les interactions pour obtenir des réponses précises et contextualisées.
L’utilisation de GraphCypherQAChain automatise la conversion question → Cypher → réponse, pil poil ce dont on a besoin pour un “chatbot métier”.
Si maintenant on repose notre question “Which managers own FAANG stocks?”, la réponse devient complètement pertinente.
Pourquoi "Ancrer" un LLM avec Neo4j ?
"Ancrer" un LLM (Large Language Model) avec Neo4j signifie connecter le modèle à une base de données de graphes pour améliorer ses réponses. Voici 3 raisons :
Les questions complexes nécessitent souvent de relier plusieurs informations entre elles (ex : "Quels gestionnaires de fonds basés à New York détiennent des actions dans des entreprises technologiques cotées après 2020, et qui ont un rendement supérieur à 10% ?").
Dans une base de données relationnelle classique, cela implique des jointures multiples, qui peuvent être lentes et difficiles à optimiser.
Solution avec Neo4j :
Neo4j stocke les relations entre les données (ex : Gestionnaire → DÉTIENT → Action → COTÉE_DANS → Secteur). Ces relations sont pré-calculées et optimisées avant même que la question ne soit posée.
Pour une question nécessitant 4 "sauts" (hops) (ex : Gestionnaire → Action → Entreprise → Secteur), Neo4j traverse ces relations instantanément, sans calculs lourds.
Résultat : Nous obtenons des réponses rapides et précises, même pour des questions complexes.
Neo4j permet de limiter l’accès aux données en fonction des permissions de l’utilisateur (ex : un chatbot ne verra que les données autorisées pour le rôle de l’utilisateur). C’est une fonctionnalité qui n’est pas accessible dans la version communautaire.
Neo4j est optimisé pour les requêtes complexes sur des graphes, avec une latence faible même avec un grand nombre d’utilisateurs simultanés. C’est idéal pour des applications comme un chatbot utilisé par des centaines d’utilisateurs en parallèle.
À première vue, l’impact est indéniable : sans l’appui d’un LLM, l’extraction de données à partir de fichiers non structurés aurait été un défi de taille. L’envie d’ajouter une couche conversationnelle pour interroger ces données devient rapidement évidente. Le Lab, centré sur les atouts d’une base graphe comme Neo4j, met en lumière ces avantages. Une fois les données chargées dans Neo4j, la précision des réponses de l’agent s’en trouve décuplée.
Un aspect important qui n’est pas montré dans le Lab, est que Neo4j a intégré dès sa conception une approche pragmatique de la sécurité, notamment à travers la gestion de la visibilité des données. Par exemple, il est possible d’attribuer des niveaux de confidentialité (comme une échelle de C1 à C4, où C4 représente le niveau le plus restreint). Ainsi, selon les droits de l’utilisateur, la base graphe filtre automatiquement les informations accessibles : un profil autorisé uniquement pour le niveau C2 ignorera les nœuds classés C3 ou C4. Une fonctionnalité qui renforce la sécurité tout en restant transparente pour l’utilisateur.
Si les LLM sont impressionnants, ils ne remplacent pas l’expérience humaine. Leur efficacité dépend largement de la qualité des prompts qui les guident. Dans le cadre du Lab, ces prompts ont été soigneusement testés pour garantir des résultats pertinents. Cependant, en dehors de ce contexte, leur élaboration reste un exercice exploratoire, profondément lié au projet en cours, aux données et aux usecases. Impossible, donc, d’établir un guide universel pour rédiger des prompts efficaces.
Cette réalité rappelle les protocoles de recherche en laboratoire : en IT, comme en science, il est impératif de tester, d'ajuster et d'itérer, à la manière des laboratoires pharmaceutiques, jusqu'à obtenir la pertinence et l'efficacité souhaitées.
Durant cette semaine, j'ai pu rencontrer bon nombre de collègues et amis, jeunes étudiants et professionnels expérimentés, avec qui j'ai eu le plaisir d'échanger sur l'avenir de nos métiers dans l'IT, la place de l’IA qu’elle va prendre, et comment la “dompter”. Le temps que la frénésie autour de l’IA se stabilise, gageons que maîtriser le “prompt” soit le défi de demain, toute génération confondue.
Pour ceux qui sont dans le Sud de la France et qui souhaitent découvrir l'autre révolution en cours dans l'IA (i.e les MCP Servers), Venez nous rencontrer au meetup IA "Piloter votre infra AWS en langage naturel avec LangFuse le 23 Octobre pour une démonstration technique des capacités des MCP Servers.
 
		
Retour au Théâtre de Paris : pour sa nouvelle édition, la Swift Connection a de nouveau transformé la scène en point de rencontre privilégié pour les passionnés de l’écosystème Apple. Durant ces deux journées, développeurs, designers et acteurs du numériques ont échangé autour des tendances qui redessinent le développement iOS — de l’IA aux stratégies de tests, en passant par les interfaces expérimentales comme Liquid Glass et les premières explorations autour du Vision Pro.
Présente sur place, notre équipe a assisté à plusieurs conférences marquantes et en partage ici les principaux enseignements. Entre retours d’expérience, réflexions prospectives et bonnes pratiques, cette édition a confirmé que la scène iOS continue d’évoluer vite, et dans toutes les directions à la fois.

Comprendre la différence entre les mécanismes de manipulation (dark patterns) et les mécanismes d’engagement sain (Hook Model) dans la conception d’applications.
En tant que junior, j’ai beaucoup apprécié la clarté avec laquelle Tamia James a expliqué le concept de dark pattern c’était un bon rappel, utile pour ancrer les pratiques. En revanche, la découverte du Hook Model de Nir Eyal (auteur du livre Hooked) a été une vraie révélation. Ce modèle m’aidera à concevoir des expériences plus engageantes et respectueuses pour les utilisateurs.
Tamia a illustré le Hook Model avec des exemples très parlants :
1 - Le côté obscur de la force : Évitez les dark patterns. Ces pratiques qui piègent l’utilisateur, comme : le paiement obligatoire après installation, les abonnements qui se renouvellent automatiquement après la période d’essai ou encore les désabonnements volontairement compliqués (👀).
2 - “May the Force be with you” : Inspirez-vous du Hook Model de Nir Eyal, articulé autour de quatre étapes : Trigger (déclencheur), Action, Reward (récompense) et Investment (investissement). L’objectif : créer des habitudes positives et utiles, sans manipuler.
3 - Pensez avant tout à l’humain : La conception d’une application mobile doit servir les besoins réels des utilisateurs, pas exploiter leurs faiblesses.
Cette conférence m’a éclairé sur la manière dont se forment les habitudes chez les utilisateurs, un levier essentiel pour concevoir des expériences à la fois engageantes et responsables.
En intégrant ces notions, nous pouvons non seulement créer des parcours plus intuitifs, mais aussi mieux identifier les dérives du design persuasif, ces fameux dark patterns qu’il est si facile d’ignorer. D’ailleurs, Tamia n’en a qu'effleurer la surface : en dresser une typologie complète serait précieux pour affiner nos pratiques et affirmer nos choix éthiques en UX.
Ce que j’ai particulièrement apprécié, c’est la justesse du propos : un équilibre rare entre technologie et psychologie, servi avec clarté et pédagogie. Les exemples concrets d’applications mondialement connues ont rendu le sujet vivant et inspirant.
Une présentation qui donne envie d’aller plus loin, de questionner nos propres produits, nos réflexes de conception et la frontière parfois ténue entre influence et manipulation.
Alex Logan nous a présenté Foundation Models, le nouveau framework d’Apple dédié à l’IA générative intégrée à Apple Intelligence.
Ce framework permet d’ajouter dans vos apps iOS des capacités de :
En une vingtaine de minutes, Alex nous a guidés pas à pas à travers la mise en œuvre du framework, du concept à la première implémentation.
1 - Simplicité d’implémentation : En quelques lignes de code, vous pouvez interagir avec le modèle et obtenir des réponses générées en langage naturel. L’intégration se fait directement dans votre app via LanguageModelSession.
2 - Importance des instructions : Le modèle répond mieux et plus rapidement lorsqu’on lui fournit des instructions claires et des garde-fous. C’est ce qui permet d’orienter la génération et d’éviter des réponses imprécises ou trop longues.

3 - Annotation @Generable : En annotant vos structures ou enums avec @Generable, vous pouvez guider le modèle pour qu’il réponde dans un format Swift précis.
➤ Parfait pour les cas où vous voulez transformer la réponse en données structurées.
Tout était nouveau !
Foundation Models marque une vraie étape dans la façon d’intégrer l’IA générative directement sur l’appareil (on-device). Le framework ouvre des perspectives créatives sans dépendre d’API externes ou de serveurs distants.
Alex a montré comment ce modèle pouvait générer une structure logique autour d’un thème, par exemple :
Choisir une équipe de sport en fonction de critères donnés.
L’idée : montrer que Foundation Models peut servir à construire une réponse intelligente à partir d’une consigne naturelle, le tout dans un environnement Swift natif.

Cette conférence montre à quel point l’IA devient accessible aux développeurs iOS.
On peut désormais imaginer :
Le framework simplifie la création d’expériences interactives qui reposent sur des prompts, mais respectent les contraintes de performance et de confidentialité d’iOS.
Une présentation claire, vivante et accessible, d’environ 15–20 minutes, qui donne une très bonne première approche du framework.
Même si la démo restait simple, elle montrait bien le potentiel immense de Foundation Models pour l’écosystème iOS.
Seul petit bémol : j’aurais aimé voir un cas d’usage plus ancré dans le monde professionnel ou applicatif.
Mais dans l’ensemble, une session inspirante et concrète sur l’avenir de l’IA sur nos appareils Apple.

Thomas Ricouard fait une impressionnante démonstration de vibe coding avec Cursor et Claude Code. Il génère en live une application de comptage de clic en partant de zéro. Il commence par le setup du projet, puis il génère une première version très simple où il prompt son besoin. Le résultat est un simple texte et un bouton de clic sans aucun travail sur l’UI. Il demande une refactorisation du code. Il nous montre aussi la force de la suggestion de code de la part de Cursor. Il enchaîne les “Tab” pour produire du code. Puis il demande ensuite à Claude code de rajouter une couche d’ui pour rendre ça plus attirant. Le résultat est assez bluffant. Confettis et barre de progression. En relançant l’app, on constate que le compte de clic n’est pas conservé, il demande alors la correction du bug et le test de celui-ci pour vérifier qu’il a bien été réglé. Le code est généré l’app lancée et testée…
1 - Claude code est tout à capable de générer une app iOS en Swift
2 - Il est plus à l’aise avec les API ayant quelques années, ce qui est pratique pour le support des versions d’iOS précédentes.
3 - Claude code avec le MCP Xcode peut tester ses implémentations
Thomas a parfaitement illustré avec son talk qu’un développeur pouvant utiliser une telle génération va être nettement plus véloce que sans. Il apparaît clairement que le métier de développeur doit composer maintenant avec de tels outils et qu’ils doivent être pris en main au plus vite.
Une belle présentation, dynamique et risquée (live coding). Une belle démonstration de la puissance de ces outils.

Les Live Activities représentent une opportunité sous-exploitée pour enrichir l'expérience utilisateur iOS. Au-delà des cas d'usage évidents (VTC, livraison), toute fonctionnalité temporelle ou événementielle peut bénéficier de cette API pour offrir une visibilité permanente et contextuelle à l'utilisateur.
Le talk permet de mieux comprendre comment repenser l’interaction utilisateur autour des notifications :
Il a d’abord revisité les exemples classiques que nous connaissons tous, comme les applications de ride-sharing (Uber, Bolt) ou encore la livraison de nourriture en temps réel, où les Live Activities offrent une visualisation instantanée de la progression d’un trajet ou d’une commande directement depuis l’écran verrouillé. Mais il a surtout mis en avant des cas plus innovants et inspirants, qui vont bien au-delà de la simple information pratique. L’application Lumy, par exemple, propose une approche artistique en affichant les cycles solaires sous forme de visuels élégants et immersifs, transformant l’écran verrouillé en une expérience sensorielle. Flighty, de son côté, se distingue par des mises à jour de vol en temps réel. Maxime cite aussi Pixel Pals, un exemple original de gamification où un petit compagnon virtuel évolue directement dans la Dynamic Island, prouvant qu’il est possible de créer un lien émotionnel avec l’utilisateur à travers une simple animation. Enfin, il a mentionné Tinder, qui exploite les Live Activities pour afficher des comptes à rebours liés à des power-ups temporisés, une manière habile d’intégrer cette fonctionnalité dans une mécanique de jeu et d’engagement.
1 - L'implémentation est plus accessible qu'on ne le pense : Maxime a démontré que l'intégration des Live Activities ne nécessite que deux frameworks principaux (ActivityKit et WidgetKit) et suit un cycle de vie simple. La barrière à l'entrée technique est relativement basse pour un gain d'UX considérable.
2 - La créativité prime sur les conventions : Les exemples non-conventionnels (Lumy pour les levers/couchers de soleil, Pixel Pals avec son Tamagotchi dans Dynamic Island) prouvent qu'il faut sortir du cadre traditionnel "suivi de livraison" pour exploiter pleinement le potentiel de cette API.
3 - Facteur de différenciation stratégique : Peu d'apps implémentent encore les Live Activities. C'est une fenêtre d'opportunité pour se démarquer sur l'App Store et améliorer significativement la rétention utilisateur grâce à une présence continue sur l'écran verrouillé et Dynamic Island.
Une présentation technique solide, sans superflu, qui inspire à repenser nos apps existantes. Maxime a brillamment démontré que les Live Activities ne sont pas un "nice-to-have" gadget, mais un véritable levier d'engagement utilisateur qui mérite d'être intégré de manière réfléchie. Je recommande vivement de revoir ce talk et d'auditer vos apps pour identifier les opportunités d'implémentation.

Le talk de Zach et Josh explore la diversité des styles de présentation et la manière dont chacun peut trouver sa voix en conférence. Plutôt que de se focaliser sur le contenu technique (les reusable cells en Swift dans ce cas là), l’idée centrale est de montrer qu’il n’existe pas une seule “bonne” manière de présenter. En combinant deux approches radicalement différentes — l’over-préparation méthodique de Zach et la spontanéité de Josh — ils démontrent qu’un talk réussi repose autant sur la connaissance de son propre style que sur la capacité à s’adapter à son public.
Le véritable tour de force de cette conférence réside dans l’expérience qu’ils ont tentée : chacun a préparé les slides de l’autre et les a présentés selon le style opposé au sien. Ce renversement a révélé, avec humour et lucidité, à quel point la préparation et l’improvisation sont deux forces complémentaires, et non des approches concurrentes. En se glissant dans la méthode de l’autre, ils ont prouvé qu’un bon talk ne dépend pas du format, mais de la maîtrise du rythme, de l’intention et de la connexion avec le public.
Zach illustre sa méthode par une préparation minutieuse : chaque phrase est notée, chaque pause est planifiée après une blague ou un meme, et le talk est répété jusqu’à la mémorisation complète. Josh, au contraire, prépare ses slides à la dernière minute, les répète peu et improvise son discours, transformant son talk en une conversation vivante avec l’auditoire. Ensemble, ils créent un talk méta, où le contraste entre leurs styles devient lui-même un enseignement : comprendre son propre rapport à la préparation et à l’improvisation est une compétence clé pour tout intervenant.
1 - Connaître et jouer de son style : il est crucial de comprendre si l’on est plus à l’aise en préparant chaque mot ou en improvisant, et de tirer parti de ses forces naturelles pour captiver l’audience.
2 - Préparation vs spontanéité : chaque méthode a ses avantages : la préparation rigoureuse permet de maîtriser le rythme, les pauses et l’impact des blagues, tandis que la spontanéité offre de la fluidité et de l’authenticité.
3 - Collaboration et contraste : combiner deux styles différents peut créer un talk riche et dynamique, démontrant que la diversité d’approche peut renforcer l’expérience pour l’auditoire.

Même si le contenu Swift n’est pas central, le talk fournit des enseignements sur la communication et la transmission des idées. Dans le cadre de projets où il faut présenter des concepts techniques, qu’il s’agisse de démos internes ou d’articles destinés à un public plus large, comprendre l’impact de son style de présentation peut influencer la clarté et l’adhésion des interlocuteurs. Cela invite à réfléchir sur la manière de partager nos connaissances efficacement, que ce soit en réunion, en workshop ou lors d’un talk public.
Le talk de Zach et Josh était très clair et bien rythmé. La combinaison de deux styles contrastés a permis de maintenir l’attention et de rendre l’exposé captivant, tout en délivrant un message simple mais puissant : comprendre et exploiter son style personnel est essentiel pour communiquer efficacement. Leur complicité et le format méta ont rendu l’expérience instructive et agréable pour l’ensemble de l’audience.

Le talk de Maxim porte sur la notion de post-screen era, une ère où les interfaces ne se limitent plus à ce qui est visible à l’écran, mais savent quand se mettre en retrait pour laisser l’utilisateur interagir efficacement. Elle souligne que le véritable enjeu n’est pas la sophistication de la technologie mais la capacité à concevoir des systèmes centrés sur l’humain, compréhensibles et dignes de confiance.Pour Maxim, l’IA doit devenir un partenaire capable de s’adapter au contexte, de fournir un feedback clair et d’orchestrer les interactions selon les besoins de l’utilisateur, afin de transformer des outils puissants en expériences réellement utiles et accessibles.
Maxim cite l’ouvrage de Don Norman (The design of everyday things) pour appuyer ses idées : “Si une porte nécessite un panneau “Push”/“Pull”, c’est un échec du design.”. Cette illustration traduit un principe simple : le bon design doit guider sans instructions explicites. La compréhension intuitive est fondamentale, savoir non seulement où interagir, mais également comment, et sans manuel.
Un autre exemple mis en avant par Maxim est une expérience personnelle qui lui est arrivée lors d’un déplacement en vélo. L’iPhone détecte un ‘workout’ et demande à l’utilisateur de valider ou non l’activité avec les AirPods de l’utilisateur en hochant la tête. Ce design n’est absolument pas adapté lors d’un déplacement en vélo et met en danger l’utilisateur, et met en avant les limites actuelles des interfaces dites invisibles ou proactives.
1 - Chaque époque a ses angles morts : les designers d’hier ont su anticiper certaines révolutions (comme la personnalisation ou la biométrie) tout en se trompant complètement sur d’autres (la matérialité des supports, l’absence de cloud)
2 - Nos schémas d’interface actuels sont datés : nous perfectionnons les gestes tactiles (taps, swipes) alors que les systèmes intelligents apprennent déjà à anticiper nos besoins, sans interface visible.
3 - Penser au-delà de l’écran : il ne s’agit pas seulement de créer de nouveaux écrans ou formats, mais de questionner la nature même de l’interaction homme-machine dans un futur où l’IA sera omniprésente.

En tant que tech, j’ai souvent tendance à me concentrer sur le “comment”, la mise en œuvre, les tâches et les solutions, en laissant parfois de côté le “pourquoi” derrière les produits sur lesquels je travaille. Ce talk m’a poussé à envisager nos phases de conception avec une approche plus prospective, en intégrant davantage de veille technologique et en élargissant nos référentiels de réflexion au-delà du seul développement mobile. Il invite à expérimenter des interfaces allégées ou proactives, capables d’anticiper certaines interactions plutôt que d’attendre une action explicite de l’utilisateur.
Cela soulève naturellement de nouvelles questions : comment définir les critères d’une “bonne” expérience utilisateur dans un monde post-écran ? Quelles seront les implications éthiques et les enjeux de contrôle utilisateur dans des interfaces de plus en plus pilotées par l’IA ? Et, plus concrètement, quelle place accorder aux App Intents dans cette évolution des interactions ?
L’intervention de Maxim se distinguait par sa clarté, sa structure, et la richesse des exemples présentés. Au-delà de son contenu technique, elle a su fédérer des profils très variés autour d’une réflexion commune sur l’avenir du design, rappelant que la technologie n’a de sens que lorsqu’elle sert véritablement l’humain.
Vous pouvez suivre Maxim via linkedin ou sa newsletter.
On entend souvent parler d'« amélioration de l'accessibilité » pour les applications, mais dans bien des cas, la meilleure approche consiste à en faire moins, “Less is More”. Dans cette présentation, Ben explique que la prise en charge intégrée de l'accessibilité d'iOS fonctionne souvent mieux lorsqu'elle n'est pas modifiée ou contournée, et comment des ajustements manuels excessifs peuvent nuire à l'ergonomie pour les utilisateurs. Avec humour, Ben précise que bien avant cela, une app accessible c’est avant tout une app bien conçue et claire pour tout le monde. Il nous présente donc son application “Apple Store” … qui permet bien évidemment d’acheter des … pommes. Et au travers de quelques démonstrations puis exemples, nous montrer comment la rendre accessible de manière efficiente.

Cela commence par une réflexion produit/UX afin de rendre claire la navigation et les CTA ainsi qu’une utilisation pertinente des outils d'accessibilité mis à disposition par Apple :
Nous avons vu que s'appuyer sur les paramètres par défaut du système pour rendre notre application accessible avec un minimum d'efforts supplémentaires reste la méthode la plus efficace et également maintenable dans le temps. Quand il est réellement nécessaire de personnaliser le comportement d'accessibilité cela reste possible mais avec parcimonie. Et quoi de mieux que cette présentation au travers d’exemples concrets de paramètres par défaut efficaces et de personnalisations excessives ou contre-productives.
Considérant un premier exemple sur l’application, le voice over lit sans distinction tous les éléments de la page et l’utilisateur est rapidement perdu dans la navigation.
Le besoin : l'ajout de headers sur les différentes sections de la page. Et plutôt que d’ajouter la fonction .accessibilityaddtraits(.isHeader) dans le code existant (ici par exemple pour la section “visit us”) :

... On pourra facilement remplacer toutes ces parties par la fonction “GroupBox” prévue par Apple et qui permet avec une économie de moyens d’obtenir un résultat comparable.

1 - Le plus simple reste d’utiliser un composant “built-in” Apple
2 - On peut ensuite customiser un composant pour certaines fonctions
3 - Et enfin, selon les besoins on pourra construire un composant custom (avec plus de sueur)
Rendre son application accessible c’est avant tout faire des actions pour s’assurer que tout le monde peut l’utiliser pleinement indépendamment de sa situation individuelle. Accessibilité et usabilité vont main dans la main. Les boutons d’actions et interactions proposés à l’utilisateur sont clairement identifiés et repérables (”affordance” et “signifier”). Si l’utilisateur doit se demander comment accéder à l’action ou la page qui l’intéresse, c’est un échec et ce que l’on soit en situation de handicap ou pas.
Ben nous livre une présentation claire de ce qui fait qu’une application est lisible, pratique et utilisable pour tous et permet de réaliser que l’accessibilité est une extension de cette lisibilité et ne doit pas être vu comme un coût, un défi ou une difficulté supplémentaire.
Vous pouvez suivre Ben via linkedin ou sur son blog.
Cette édition 2025 de la Swift Connection a une nouvelle fois montré la richesse et la maturité de l’écosystème Apple dans son ensemble. Au fil des conférences, un même fil conducteur s’est dégagé : la volonté de remettre en question nos habitudes de conception, d’explorer de nouvelles approches et de partager ouvertement les apprentissages du terrain.
Entre vision produit et approche user-centric, les discussions ont aussi mis en lumière la place grandissante de l’intelligence artificielle dans nos pratiques — non pas comme un simple outil, mais comme un levier pour repenser l’expérience et redéfinir la frontière entre interface et usage.
Plus qu’un simple rendez-vous technique, la Swift Connection reste un espace d’échange et d’inspiration, où chacun repart avec des idées concrètes, mais aussi une dose bienvenue de motivation. Un grand bravo à l’ensemble des intervenants et à l’équipe d’organisation pour la qualité de cette édition — et rendez-vous l’an prochain pour continuer à faire évoluer, ensemble, notre manière de concevoir et de développer.
 
		
GitHub Copilot, lorsqu’il est utilisé dans Visual Studio Code, n’est pas seulement un outil d’autocomplétion : c’est un assistant capable de s’adapter à ton environnement, ton style et tes besoins.
Sans règles, Copilot agit comme un modèle générique : il propose du code standard, parfois en décalage avec tes conventions internes, tes contraintes techniques ou ta façon de rédiger. Avec des custom instructions, tu transformes Copilot en un collaborateur aligné avec ta façon de travailler.
Les custom instructions permettent de guider Copilot de manière précise : elles l’aident à produire du code conforme à ton style et à tes standards, à réaliser des revues de code ou des modifications en respectant les conventions de ton équipe, à adapter le ton et la structure des réponses selon ton public — qu’il soit technique ou non technique — et enfin à prioriser certains frameworks, bibliothèques ou patterns spécifiques à ton projet.
En définissant des règles, tu injectes ta voix et tes pratiques métiers dans les suggestions :
| Type | Portée | Emplacement | Cas d’usage | Limites / Notes | 
|---|---|---|---|---|
| Instructions personnelles | Globale (utilisateur) | Préambule Chat / Profil Copilot | Ton, style de réponse, niveau de détail | Non liées au dépôt, ne modifient pas les complétions inline | 
| Instructions par dépôt | Projet (dépôt) | .github/copilot-instructions.md (ou .github/instructions/*.instructions.md + applyTo) | Conventions de code, outils, archi spécifiques au repo | applyTo/multi-fichiers selon disponibilité; éviter secrets; résolution de conflits nécessaire | 
| Instructions organisationnelles | Organisation | Admin GitHub (Copilot Enterprise) | Standards transverses, sécurité/compliance | Réservé à Copilot Enterprise, géré par owners | 
| Prompt files | À la demande (par exécution) | *.prompt.md dans le projet | Actions récurrentes (review, refactor, audit) | N’applique rien en arrière-plan; doit être déclenché manuellement | 
Utilisons un prompt simple pour développer une roue de sélection de noms. Les utilisateurs pourraient y entrer des noms, et il y aurait un bouton "Choisir un gagnant". Quand on clique dessus, la roue tourne et affiche un nom gagnant.
Develop a name picker widget in the form of a wheel. This widget should allow users to input names and include a "Choose Winner" button that, when clicked, spins the wheel and displays a winning name.
Prompt pour générer widget test
La première version est très générique : elle se concentre sur la rotation de la roue et l'affichage du gagnant, sans trop se soucier de l'expérience utilisateur, du thème ou de la localisation. Les libellés sont en anglais, les commentaires s'affichent directement sous forme de texte brut et le style est minimaliste. Cela fonctionne, mais on a l'impression d'un code standard qui pourrait s'adapter à n'importe quel projet sans vraiment s'adapter à l'environnement.

Grâce à l’application créée pour un autre article sur les patrons de conception avec Flutter, je lui ai demandé de générer des instructions qui correspondent à mon style d’écriture. Mais vous verrez plus tard dans l’article que Copilot propose des solutions pour créer automatiquement ces règles.
You are an expert software assistant.  
I want you to analyze this codebase and generate a **custom instruction guide** for GitHub Copilot so that its suggestions match the project’s coding style and best practices.
### Steps:
1. **Analyze the codebase**:
   - Frameworks, libraries, architecture.
   - Naming conventions.
   - State management patterns.
   - File and folder structure.
   - Testing strategy.
   - Commenting/documentation style.
2. **Generate a structured Copilot instruction guide** with the following sections:
   - **Identity & Context** → who the developer is in this project context, what stack/framework is used.
   - **Goals & Expectations** → what to optimize for (readability, testability, performance, etc.).
   - **Style & Conventions** → naming rules, file structure, code style, widget/component design rules.
   - **Do’s & Don’ts** → explicit rules for what to prefer/avoid in code generation.
   - **Interaction Style** → how Copilot should explain or suggest code (minimal, detailed, alternatives, etc.).
3. **Output**:
   - Clear, concise, and copy-paste ready.
   - Written as if I will paste it directly into Copilot’s “Custom Instructions” section.
   
Prompt pour générer des customs instructions rapides

La deuxième version, cependant, montre une nette amélioration des pratiques. Le widget s'intègre mieux à Material Design en utilisant des Card, des Border, des Chip pour la gestion des participants et des AlertDialog pour les commentaires. Il respecte le thème de l'application en utilisant la palette de couleurs et adapte même les libellés au français. Le processus de sélection du gagnant est également plus abouti, avec une désactivation appropriée des boutons lorsque le nombre de participants ajoutés est insuffisant et une AlertDialog dédiée pour célébrer le résultat.
Au-delà de la simple fonctionnalité, des instructions claires transforment un extrait générique en composant prêt à s’intégrer à ton design system, ton langage et tes normes d’expérience utilisateur. C’est la différence entre du code standard e du code aligné sur les standards de ton équipe.
Dans Visual Studio Code, Copilot peut être guidé par différents types de règles, chacune ayant sa portée et son utilité.
Même si certaines sont spécifiques à GitHub Web ou à Copilot Enterprise, nous allons surtout nous concentrer sur celles qui influencent l’expérience dans VS Code.
C’est une phrase, un ordre que l’on met au début du chat, comme contexte, juste avant d’écrire ton prompt. Principalement utilisées dans GitHub Web, mais la logique est la même pour fixer un style global.
Adding personal custom instructions for GitHub Copilot - GitHub Enterprise Cloud Docs
Ces réglages s'appliquent à toutes tes conversations Copilot, peu importe le projet. Ils te permettent de personnaliser ton style de communication, tes préférences techniques et le format de sortie désiré.
Exemples :
Ces instructions servent de socle : elles assurent une cohérence dans toutes les interactions avec Copilot.
Le cœur de la personnalisation dans VS Code. Adding repository custom instructions for GitHub Copilot - GitHub Enterprise Cloud Docs
Les instructions pour GitHub Copilot sont limitées à un projet précis et sont implémentées via un fichier .github/copilot-instructions.md à la racine du dépôt. Ce fichier, rédigé en Markdown et en langage naturel, sert à définir des conventions de code, spécifier les outils à utiliser (frameworks, CI/CD, test runners), et imposer des règles d'architecture ou de performance.
.github/instructions/ contenant plusieurs fichiers .instructions.md avec un champ applyTo pour cibler des dossiers ou types de fichiers spécifiques.Note de disponibilité : la configuration multi-fichiers avec front matter applyTo peut dépendre de la version/du tenant et n’est pas toujours activée. Si elle n’est pas disponible, utilisez le fichier unique recommandé .github/copilot-instructions.md.
---
applyTo: "src/**/*.ts"
---
Always explicitly type all TypeScript functions.
Prohibit `any`.
Use ESLint according to `.eslintrc`.Exemple d'instructions par dépôt
Elles fonctionnent comme les instructions personnelles et sont réservées à Copilot Enterprise – non spécifiques à VS Code mais compatibles.
Adding organization custom instructions for GitHub Copilot - GitHub Enterprise Cloud Docs
Ces paramètres et règles s'appliquent à tous les dépôts et utilisateurs de l'organisation. Leur administration est gérée par les owners de l'organisation. Ils servent à uniformiser les conventions de code, les pratiques de développement, et à appliquer de manière cohérente les politiques de sécurité et les exigences de conformité sur l'ensemble des projets.
Si tu dois réécrire le même prompt, si tu as des usages redondants. C’est un outil puissant pour automatiser des prompts réutilisables.
Les fichiers *.prompt.md sont utilisés dans VS Code pour encapsuler et permettant de standardiser des actions récurrentes telles que les revues de code, les refactorings ou les audits. Leur contenu comprend un titre ou une description, des instructions claires et, si nécessaire, des variables dynamiques comme {{fileName}} ou {{selectedText}}.
# Title: Code review
Analyses the {{fileName}} file and identifies:
- Potential bugs
- Possible optimisations
- Style violationsExemple minimal de prompt files pour une revue de code
Le mode agent transforme Copilot en un assistant autonome capable de prendre en charge des tâches complètes, pas seulement des suggestions ligne par ligne. Use agent mode in VS Code
Dans ce mode, Copilot planifie, exécute et itère sur ses actions pour atteindre un objectif donné, à partir d’un simple prompt.
En mode Agent, Copilot peut :
Les custom instructions jouent ici un double rôle. Elles servent de garde-fou afin d’éviter des choix techniques incompatibles avec ton projet, tout en constituant un cadre stratégique qui oriente les décisions de l’agent vers tes propres standards.
Always document the functions you create with a Google-style docstring.
Custom instructions pour l'agent
Avec Agent Mode activé, cette consigne s’applique à chaque fonction générée, quel que soit le nombre de fichiers modifiés.
Implement a clear and intuitive checkbox option, labeled "Delete winning name," which, when selected, will automatically remove the name chosen as the winner from the list.Prompt minimal pour améliorer notre roue




Exemple du comportement agentique sur VSCode
En tant qu’agent, Copilot a lu les fichiers pertinents pour repérer le point d’intégration, et a implémenté la solution en ajoutant une option de suppression automatique du gagnant avec sa logique dédiée.
Il a ensuite vérifié le respect du style (libellés, widgets, gestion d’état) et des docstrings au format Google, a passé le lint et corrigé les ajustements nécessaires, et a contrôlé la conformité aux conventions du projet (structure, nommage, accessibilité).
Enfin, Copilot a conclu par un débrief indiquant que la fonctionnalité est isolée, contrôlable via la case à cocher, correctement documentée et sans régression observée.
Bonne nouvelle, il y a un bouton magique pour créer ton fichier de règles.
Tu peux générer ces fichiers depuis l’interface de VS Code, sans passer par un éditeur externe :

Cette commande crée un prompt qui active Copilot afin qu'il génère un fichier .github/copilot-instructions.md spécifiquement adapté aux besoins et à la structure de ton projet actuel. Ce fichier contiendra des instructions détaillées et personnalisées pour l'utilisation optimale de Copilot dans le contexte de ton environnement de développement. L'objectif est de maximiser l'efficacité de Copilot en lui fournissant les informations nécessaires pour qu'il puisse proposer des suggestions de code, des complétions et des refactorisations pertinentes, en accord avec les conventions et les spécifications de ton projet.

Une fois que tes fichiers d’instructions sont en place (.github/copilot-instructions.md ou .instructions.md dans .github/instructions/), VS Code les charge automatiquement dès que tu ouvres le projet.
.instructions.md ciblés par applyTo peut être soumis à disponibilité. À défaut, le fichier unique .github/copilot-instructions.md est pris en charge de manière générale.Ces instructions influencent directement le comportement de l’outil. D’une part, elles orientent les réponses du Chat, puisque Copilot adapte son ton, son style et respecte les contraintes définies.
D’autre part, elles guident également les Copilot Edits : lorsque tu sélectionnes du code et demandes une modification, Copilot applique les règles établies afin de produire un résultat conforme aux attentes.

La fonctionnalité Copilot peut être activée ou désactivée globalement dans les paramètres de VS Code. Il est également possible de désactiver temporairement la prise en compte des instructions pour tester un comportement "neutre" de Copilot ou en cas de changement de contexte de projet. Les modifications prennent effet immédiatement lors de la prochaine interaction avec le Chat ou le mode Edits.
Afin de maximiser la clarté et la maintenabilité, structure les fichiers par type de tâche : src.instructions.md pour les règles de génération et d'organisation du code, tests.instructions.md pour les règles spécifiques aux tests (framework, structure, conventions), et docs.instructions.md pour les règles de documentation (format, ton, sections obligatoires).
Les règles définies dans les fichiers d’instructions influencent Copilot Chat et Copilot Edits, mais n’ont aucun effet sur les complétions inline acceptées via Tab. Leur portée est limitée au dépôt ouvert : dès qu’une instruction est modifiée dans le fichier du projet, l’impact est visible à la prochaine interaction, que ce soit une nouvelle question ou une demande d’édition.
Il est important de garder à l’esprit que des instructions trop longues augmentent le nombre de tokens utilisés, ce qui peut ralentir les réponses ou diminuer la pertinence des suggestions ; il est donc préférable de rédiger des sections concises et ciblées.
Certaines fonctionnalités, comme le champ applyTo ou la configuration multi-fichiers via .github/instructions/*.instructions.md, dépendent de la version ou du tenant et peuvent être en preview : par défaut, il est recommandé d’utiliser le fichier unique .github/copilot-instructions.md.
Lorsque plusieurs fichiers d’instructions sont présents, Copilot fusionne les règles, mais celles ciblées via applyTo prennent le dessus sur les règles globales. Il est donc essentiel d’éviter toute contradiction entre les instructions personnelles, d’organisation et de dépôt. Par ailleurs, il ne faut jamais inclure de secrets (clés API, tokens, données sensibles) ni d’URL internes confidentielles dans les instructions, pour des raisons de sécurité.
Pour que Copilot suive efficacement tes standards, tes instructions doivent être rédigées avec soin. Elles doivent être claires et concises, sans jargon inutile ni formulations ambiguës, afin d’éviter toute interprétation erronée. Elles doivent aussi être impératives, en privilégiant l’infinitif ou l’impératif direct : par exemple, au lieu d’écrire “On pourrait utiliser des doubles quotes”, mieux vaut préciser “Utilise uniquement des doubles quotes”. Enfin, elles doivent être contextuelles, en mentionnant explicitement les éléments clés de ton environnement, comme la stack technique (“Projet React avec TypeScript”), l’outil de build (“Utilise Bazel”) ou encore les règles de style de code à respecter (“Respecte les règles ESLint standard + Prettier”).
Plus ces instructions sont précises et adaptées à ton contexte, plus Copilot pourra produire un code aligné sur tes conventions et directement exploitable.
Pour optimiser les règles de Copilot, vérifie les instructions actives, ajuste le niveau de rigueur (alléger ou renforcer), assure la cohérence entre les règles personnelles, de dépôt et d'organisation, et utilise applyTo pour cibler précisément certains fichiers ou répertoires (si disponible).
De nombreux contributeurs mettent à disposition leurs règles Copilot, souvent tirées de projets open source. N'hésite pas à explorer ces ressources publiques : elles constituent une mine d'or d'inspiration pour affiner tes propres configurations et découvrir des approches que tu n'aurais pas envisagées. Par exemple le site https://www.copilotcraft.dev/ qui te permet de générer un template de règles.
Optimiser GitHub Copilot avec des custom instructions transforme ton flux de travail en l'alignant sur tes standards et ta culture d'équipe. Copilot s'adapte à ton style de code, tes outils et le niveau de détail de tes livrables, améliorant la qualité et la cohérence de tes projets.
L'expérimentation est cruciale : commence simple, observe l'impact, puis affine, en utilisant des fonctionnalités comme "applyTo" et en t'inspirant des travaux de la communauté dev.
En intégrant ces pratiques, Copilot devient un prolongement de ton expertise, garantissant un code de meilleure qualité, une productivité accrue et une harmonie technique. C'est le passage d'un simple outil à un partenaire de code indispensable.
// .github/copilot-instructions.md
# Custom instructions for GitHub Copilot — flutter-design-pattern-configuration-builder
## Identity & context
- You are assisting a Flutter/Dart developer working on a small demo app that showcases a Builder + Director design pattern around “vehicle cards”.
- Tech stack: Flutter (Material 3), Dart null-safety, default flutter_lints.
- App uses simple state (setState in local StatefulWidgets). No Provider/Bloc/Riverpod.
- Project language is mixed FR/EN in UI strings; keep French labels in UI. The code intentionally uses the spelling “Vehicule” in many symbols and files—preserve it.
## Goals & expectations
- Optimize for clarity, immutability, and testability over micro-optimizations.
- Generate idiomatic Flutter widgets: prefer StatelessWidget, const constructors, final fields.
- Keep the design pattern separation: configuration objects, builders, and a director that sequences builder steps.
- Suggestions should compile with flutter_lints defaults and fit existing folder/barrel structure.
- When adding features, also propose/update minimal widget tests following the existing style.
## Style & conventions
Naming
- Classes, enums: PascalCase (e.g., `VehiculeCard`, `VehicleType`, `CarBuilder`).
- Methods, fields, variables: lowerCamelCase (e.g., `buildSpecsSection`, `isActionLoading`).
- Keep "Vehicule" spelling where already used (do not “correct” to Vehicle in identifiers or filenames).
Files & folders
- Widgets: `lib/widgets/` (icons, sections, card, header, button). New small reusable UI pieces go here.
- Views/pages: `lib/views/` (screens like bike demo pages).
- Models: `lib/models/` (simple data classes like `VehicleSpecsData`, `EngineData`, `VehicleType`).
- Config-only pattern: `lib/vehicule_with_configuration/` with `VehicleConfiguration` subclasses and a `VehicleWidget` factory.
- Builder pattern: `lib/vehicule_with_configuration_and_builder/` with `*CardConfiguration`, builders (e.g., `CarBuilder`, `BikeBuilder`), and `VehicleWidgetDirector`.
- Barrel exports: keep `lib/widgets/widgets.dart`, `lib/models/models.dart`, `lib/lib.dart` updated when adding public modules.
- Tests: `test/*.dart`, name with `_test.dart` and use `flutter_test`.
Widget & code style
- Prefer StatelessWidget. Use StatefulWidget + `setState` only for local UI state (e.g., loading toggles).
- Constructors: `const` when possible; mark parameters `required` and fields `final`.
- UI: Use Material widgets, simple layout, and consistent theming (`ColorScheme.fromSeed(seedColor: Colors.indigo)`).
- Card look: rounded corners (~18), subtle shadow, padding ~18, vertical spacing via SizedBox or Column spacing.
- Optional sections return null and are conditionally rendered with `if (widget != null) widget!`.
- Keep public APIs small and explicit; avoid global state/singletons.
Design pattern contracts
- Config-only flow (`vehicule_with_configuration`):
    - Create configuration subtype (`CarConfiguration`, `BicycleConfiguration`) implementing:
        - `buildIcon()`, `buildSpecsSection()`, `buildEngineSection()`, `buildButton()`.
    - Use `VehicleWidget.car(...)` / `.bicycle(...)` factories to wrap config and render `VehiculeCard`.
- Builder flow (`vehicule_with_configuration_and_builder`):
    - Define a `*CardConfiguration` with plain data.
    - Implement a `VehiculeCardBuilder` subclass with step methods: `withType`, `withTitle`, `withSubtitle`, `withIcon`, `withSpecs`, `withEngine`, `withButton`.
    - Use `VehicleWidgetDirector` to sequence steps into a recipe (may include/exclude sections).
    - Call `builder.build()` to get a `VehiculeCard`.
Strings & localization
- Keep UI strings in French where present (e.g., “Immatriculation”, “Mon garage”, button labels like “Réessayer”). No i18n framework is used.
Testing
- Wrap widgets in `MaterialApp(home: Scaffold(body: widget))` for tests.
- Use `flutter_test` finders: `find.text`, `find.textContaining`, `find.byIcon`, `find.byType`.
- For button taps, `await tester.tap(find.byType(ElevatedButton)); await tester.pump();` and assert side effects.
- Prefer focused tests that assert visible text, icons, and conditional sections.
## Do’s & Don’ts
Do
- Use `const` and `final` aggressively; keep constructors `const` when possible.
- Follow existing naming and file placement; update barrel files when adding exports.
- Keep “Vehicule” spelling in identifiers and paths to match the project.
- In builders, implement all step methods even if some are no-ops for a given type.
- Keep UI minimal and accessible; use standard Material components and theming.
- For new public behavior, add/adjust a small widget test mirroring the existing style.
Don’t
- Don’t introduce state management frameworks (Provider/Bloc/Riverpod) or navigation libraries.
- Don’t print to console for UX; use SnackBar in UI code when needed.
- Don’t refactor to English spelling or rename established APIs.
- Don’t mix platform-specific code or plugins; keep pure Flutter where possible.
- Don’t over-abstract; prefer simple data classes and small widgets over deep hierarchies.
## Interaction style
- Default to concise, single-solution suggestions that match the established patterns.
- When multiple patterns exist (config-only vs builder), pick the one already used in the touched file/folder; otherwise, suggest config-only for simple cases and builder+director when demonstrating recipes.
- Show minimal explanatory comments inline only where the pattern isn’t obvious; otherwise, keep code comment-light as in the repo.
- Prefer imports from barrel files (e.g., `widgets/widgets.dart`, `models/models.dart`) when adding sample code.
- If creating files, propose filenames and locations that fit the structure and add the necessary exports.
— End of Copilot custom instructions —Instructions générées pour la roue du début, suite à l'article sur les design pattern en Flutter
# Copilot instructions for this repo
Context: Flutter app with Material 3 theme and simple stateful widgets. UI text mixes French/English. Analyzer uses `flutter_lints`. Keep code concise, null-safe, and idiomatic Flutter.
Note on existing rules: `.github/instructions/best_practice.instructions.md` describes a “Vehicule builder” demo. That structure does not exist here. You can reuse general style points from it (Material 3, `const`/`final`, French labels), but follow the actual files and patterns below for this app.
## Big picture
- Entry: `lib/main.dart` → `MyStartApp` (MaterialApp with `ColorScheme.fromSeed(Colors.indigo)`), shows a top-end `Banner("Thomas D.")`, home is `StartPage`.
- Primary screen: `lib/start_page.dart` renders the wheel picker UI via `Generated2` (see below).
- Two wheel implementations exist:
  - `lib/generated_1.dart` (`Generated1`, `WheelPainter`) – earlier version.
  - `lib/widgets/generated2.dart` (`Generated2`, `_WheelPainter`) – current version used by `StartPage`.
- Custom painters draw the pie slices, labels, and a pointer; state is local (`setState`) with `AnimationController` for spin effects.
## Current patterns & conventions
- Keep UI strings in French where present (e.g., "Gagnant !", "Choisir le gagnant"). No i18n framework.
- Prefer `StatelessWidget`; use `StatefulWidget` + `setState` for local UI state only (text input, animation, selection).
- Constructors `const` when possible; fields `final`. Dispose controllers in `dispose()`.
- Small reusable UI pieces go in `lib/widgets/`. A barrel exists: `lib/widgets/widgets.dart`.
- Theming: use `Theme.of(context)` and Material 3 components; keep rounded corners (~18) and subtle elevation consistent with `Generated2`.
- Lints: follow `analysis_options.yaml` (inherits `flutter_lints`). Use `flutter analyze` to validate.
## Known quirks to mind
- `start_page.dart` imports `package:copitot_rules/widgets/name_picker_wheel.dart`, but that file is not present. The screen currently uses `Generated2`. Prefer importing from the barrel `widgets/widgets.dart` or the actual file `widgets/generated2.dart`. If you add `name_picker_wheel.dart`, export it from the barrel.
- There are two similar wheel implementations; avoid duplicating logic—prefer `Generated2` unless you are intentionally comparing versions.
## Typical workflows
- Install deps: `flutter pub get`
- Analyze: `flutter analyze`
- Run (hot reload): `flutter run` (select device; Android and web configs are present)
- Test: add widget tests under `test/*.dart` then `flutter test`
## Extension points and examples
- Adding a new widget:
  - Place in `lib/widgets/your_widget.dart`.
  - Export in `lib/widgets/widgets.dart` and import via `package:copitot_rules/widgets/widgets.dart`.
- Animation pattern (see `Generated2`):
  - Mixin `SingleTickerProviderStateMixin`.
  - Create/`dispose` `AnimationController` in `initState`/`dispose`.
  - Drive `Tween<double>(begin: _currentAngle, end: targetAngle)` with a curved animation; update `_currentAngle` in the listener and call `setState`.
  - On completion, compute winner index and show a dialog with the name.
- CustomPainter pattern:
  - Compute `anglePerName = 2*pi / names.length`.
  - Loop to draw arcs with `Colors.primaries[i % ...].withOpacity(0.8)`.
  - Use `TextPainter` to draw labels at `radius * 0.65` along the mid-angle; draw a triangle pointer above the circle.
## When adding features
- Keep labels French where the UI already uses FR.
- Maintain the Material 3 look and spacing similar to `Generated2` (padding ~18, rounded corners ~18).
- Validate with `flutter analyze` and ensure controllers are disposed.
- If you introduce new public widgets, add minimal widget tests (wrap with `MaterialApp(home: Scaffold(body: widget))` and assert visible text/icons).
## Key files
- `lib/main.dart` – app entry, theme, banner, home.
- `lib/start_page.dart` – home screen using `Generated2`.
- `lib/widgets/generated2.dart` – current wheel UI + painter.
- `lib/generated_1.dart` – earlier wheel variant for reference.
- `lib/widgets/widgets.dart` – barrel export for widgets.
Questions or gaps? If anything above is unclear (e.g., desired barrel usage or which wheel to standardize on), ask for confirmation before broad refactors.
Instructions générées par le bouton de Vscode
 
		
Qui n’a jamais ouvert un fichier et rencontré un fichier de 3000 lignes, un constructeur à rallonge, une logique métier mélangée à l’UI, et des if/else partout ? Et si on se posait une question simple : combien de temps perdez-vous à comprendre un widget « monstre » avant de le modifier sans crainte ?
Dans cet article, nous allons partir d’un cas concret transposé au domaine des véhicules (voiture, vélo, camion) pour montrer comment des design patterns classiques - Builder, Factory, Strategy, Template Method - transforment un code fragile en architecture claire, testable et extensible. Le code produit sera disponible sur un lien github à la fin de l’article ! Bonne lecture.


Écrans d'exemple des fiches de véhicules
Une fiche véhicule doit :
Problème réel : 15+ paramètres par constructeur, répétitions, et risques d’erreurs.
Exemple (simplifié) d’un widget de fiche véhicule :
// AVANT - constructeur « voiture » verbeux
const VehicleWidgetCar({
  required this.typeLabel,
  required this.brand,
  required this.model,
  required this.imageUrl,
  required this.onTap,
  required this.title,
  required this.subtitle,
  required this.wheelCount,
  required this.fuelType,
  required this.doorCount,
  required this.hasSunroof,
  required this.registration,
  required this.tryAgainButtonLabel,
  required this.isLoading,
  required this.isActionLoading,
  super.key,
}) : vehicleType = VehicleType.car,
     // … 8 autres champs initialisés à null pour d’autres types
     bikeSpecificData = null,
     truckSpecificData = null;Code verbeux de départ pour un widget fiche de voiture
Cette approche nuit gravement à la lisibilité du code, rendant la maintenance extrêmement complexe, et elle crée un couplage fort et indésirable entre les données, la logique métier et le rendu, ce qui complique les évolutions futures et l'ajout de nouvelles fonctionnalités. Ça devient un processus risqué, augmentant le risque d'oublis ou d'incohérences potentielles.
Le SRP (Single Responsibility Principle) dit qu’une classe ou un module doit avoir une seule raison de changer, c’est-à-dire une seule responsabilité.
Ce widget était responsable de la configuration des différents types (voiture, vélo, camion).
Il décidait également de l’affichage, intégrant la logique métier et il construisait l’UI en assemblant les différentes sections PUIS gérait l’état (chargement, erreurs).

L'ajout d'un nouveau type (par exemple, vélo électrique) nécessite de modifier les constructeurs, la méthode build(), l'énumération, et d'implémenter des conditions à de TOUS les endroits.
L'écriture de tests unitaires impliquait l'instanciation de widgets complexes avec des dizaines de paramètres à chacun des tests
Le widget présentait à lui-même plus de 3000 lignes indentées, on ne se retrouvait plus du tout.
// Pseudo code du widget
build() {
  return Column(
    if titre 
Text(titre)
    if vehicule.type == car 
Text(model)
    else if vehicule.type == bicycle 
Text('bicycle')
    if vehicule.showSpec && vehicule.spec != null 
Text(vehicule.spec)
    Bouton(
	onTap
	  if(vehicule.type == car and vehicule.type != camion)
           showVehiculeMoteur()
}Pseudo code pour la construction du widget de départ
On masque la complexité d’initialisation derrière une API simple. La fabrique est un patron de conception de création qui définit une interface pour créer des objets dans une classe mère, mais délègue le choix des types d’objets à créer aux sous-classes.

class VehicleWidget extends StatelessWidget {
  const VehicleWidget._({required this.configuration, super.key});
  final VehicleConfiguration configuration;
  factory VehicleWidget.car({
    required String typeLabel,
    required String title,
    required String subtitle,
    required VoidCallback onTap,
    required String buttonLabel,
    required bool isActionLoading,
    required VehicleSpecsData specs,
    required EngineData engine,
    Key? key,
  }) => VehicleWidget._(
    key: key,
    configuration: CarConfiguration(
      typeLabel: typeLabel,
      title: title,
      subtitle: subtitle,
      onTap: onTap,
      buttonLabel: buttonLabel,
      isActionLoading: isActionLoading,
      specs: specs,
      engine: engine,
    ),
  );
  factory VehicleWidget.bicycle({
    required String typeLabel,
    required String title,
    required String subtitle,
    required VoidCallback onTap,
    required String buttonLabel,
    required bool isActionLoading,
    required VehicleSpecsData specs,
    bool isElectric = false,
    Key? key,
  }) => VehicleWidget._(
    key: key,
    configuration: BicycleConfiguration(
      typeLabel: typeLabel,
      title: title,
      subtitle: subtitle,
      onTap: onTap,
      buttonLabel: buttonLabel,
      isActionLoading: isActionLoading,
      specs: specs,
      isElectric: isElectric,
    ),
  );
  @override
  Widget build(BuildContext context) => VehiculeCard(
    header: VehiculeCardHeader(
      vehicleType: configuration.typeLabel,
      title: configuration.title,
      subtitle: configuration.subtitle,
      icon: configuration.buildIcon(),
    ),
    specs: configuration.buildEngineSection(),
    engine: configuration.buildSpecsSection(),
    button: configuration.buildButton(),
  );
}Code principal pour la première version de résolution du widget de fiche de véhicule
Le design de l'API se veut propre, garantissant une initialisation centralisée et sécurisée, ce qui facilite grandement la consommation par le code appelant. On utilise aussi une nouvelle classe en plus de la Factory qui va centraliser les informations des différents véhicules.
Cette classe de configuration utilise aussi un patron de conception qui est la strategy. La stratégie est un patron de conception comportemental qui permet de définir une famille d’algorithmes, de les mettre dans des classes séparées et de rendre leurs objets interchangeables. On encapsule la logique spécifique à chaque type via une sealed class pour la sûreté et l’exhaustivité.
abstract class VehicleConfiguration {
  const VehicleConfiguration({
    required this.typeLabel,
    required this.title,
    required this.subtitle,
    required this.onTap,
    required this.buttonLabel,
    required this.isActionLoading,
  });
  final String typeLabel;
  final String title;
  final String subtitle;
  final VoidCallback? onTap;
  final String? buttonLabel;
  final bool isActionLoading;
  VehicleType get vehicleType;
  Widget buildIcon();
  Widget? buildSpecsSection();
  Widget? buildEngineSection();
  Widget? buildButton();
}
class CarConfiguration extends VehicleConfiguration {
  @override
  VehicleType get vehicleType => VehicleType.car;
}
class BicycleConfiguration extends VehicleConfiguration {
  @override
  VehicleType get vehicleType => VehicleType.bicycle;
}Code pour la création de classe Stratégie
Cependant, cette approche se limite à abstraire la modélisation du véhicule et de son contenu au sein d'une classe distincte. L'ajout de nouveaux véhicules demeure laborieux et la compréhension des mécanismes internes reste compliquée, malgré une simplification de la construction des widgets et une clarté augmentée des constructeurs.
Ici, VehicleConfiguration gère la distribution des données, l'interface utilisateur, la logique et l'état, ce qui ne résout pas le problème de base, mais le délègue simplement. On veut séparer les responsabilités pour pouvoir mieux les comprendre et mieux les tester. Alors allons-y !
On sépare les responsabilités en quatre rôles complémentaires, alignés avec le diagramme et le code :

Notre classe VehicleConfiguration, notre stratégie va devenir une template method car elle va servir uniquement à fournir les détails des véhicules. Le design pattern Patron de Méthode est un patron de conception comportemental qui permet de mettre le squelette d’un algorithme dans la classe mère, mais laisse les sous-classes redéfinir certaines étapes de l’algorithme sans changer sa structure.
abstract class VehicleCardConfiguration {
  const VehicleCardConfiguration({
    required this.typeLabel,
    required this.title,
    required this.subtitle,
    required this.onTap,
    required this.buttonLabel,
  });
  final String typeLabel;
  final String title;
  final String subtitle;
  final VoidCallback onTap;
  final String buttonLabel;
  VehicleType get vehicleType;
}
class CarCardConfiguration extends VehicleCardConfiguration {
  const CarCardConfiguration({
    required super.typeLabel,
    required super.title,
    required super.subtitle,
    required super.onTap,
    required super.buttonLabel,
    required this.specs,
    required this.engine,
  });
  final VehicleSpecsData specs;
  final EngineData engine;
  @override
  VehicleType get vehicleType => VehicleType.car;
}
class BicycleCardConfiguration extends VehicleCardConfiguration {
  const BicycleCardConfiguration({
    required super.typeLabel,
    required super.title,
    required super.subtitle,
    required super.onTap,
    required super.buttonLabel,
    required this.specs,
    this.isElectric = false,
  });
  final VehicleSpecsData specs;
  final bool isElectric;
  @override
  VehicleType get vehicleType => VehicleType.bicycle;
}Code de la template method la seconde version de résolution du widget de fiche de véhicule
Ce pattern améliore la clarté, une meilleure sécurité sur le type et une logique métier testable. Chaque implémentation de VehicleConfiguration agit comme un nouveau vehicule : le VehicleBuilder s’adapte au type sans conditions éparpillées. Ajouter TruckConfiguration n’implique pas de modifier le VehicleWidget : on respecte l’OCP (ouvert à l’extension, fermé à la modification).
On sépare la construction d’un widget complexe en méthodes modulaires qui s’appuient sur la configuration. Le Builder est un patron de conception de création qui permet de construire des objets complexes étape par étape. Il permet de produire différentes variations ou représentations d’un objet en utilisant le même code de construction. Lien pour la documentation pattern builder : Builder et de son Directeur
abstract class VehiculeCardBuilder {
  VehiculeCardBuilder();
  late String _vehicleType;
  late String _title;
  late String _subtitle;
  late Widget _icon;
  Widget? _specs;
  Widget? _engine;
  Widget? _button;
  void withType();
  void withTitle();
  void withSubtitle();
  void withIcon();
  void withSpecs();
  void withEngine();
  void withButton();
  Widget build() => VehiculeCard(
    header: VehiculeCardHeader(
      vehicleType: _vehicleType,
      title: _title,
      subtitle: _subtitle,
      icon: _icon,
    ),
    specs: _specs,
    engine: _engine,
    button: _button,
  );
}
class CarBuilder extends VehiculeCardBuilder {
  final CarCardConfiguration configuration;
  CarBuilder({required this.configuration});
  @override
  void withEngine() {
    _engine = CarEngineSection(engine: configuration.engine);
  }
  @override
  void withIcon() {
    _icon = CarIcon();
  }
  @override
  void withSpecs() {
    _specs = CarSpecSection(specs: configuration.specs);
  }
  @override
  void withSubtitle() {
    _subtitle = configuration.subtitle;
  }
  @override
  void withTitle() {
    _title = configuration.title;
  }
  @override
  void withType() {
    _vehicleType = configuration.vehicleType.name;
  }
  @override
  void withButton() {
    _button = VehiculeCardButton(
      onTap: configuration.onTap,
      buttonLabel: configuration.buttonLabel,
    );
  }
}
class BikeBuilder extends VehiculeCardBuilder {
  final BicycleCardConfiguration configuration;
  BikeBuilder({required this.configuration});
  @override
  void withEngine() {
    _engine = null;
  }
  @override
  void withIcon() {
    _icon = BikeIcon();
  }
  @override
  void withSpecs() {
    _specs = BicycleSpecSection(specs: configuration.specs);
  }
  @override
  void withSubtitle() {
    _subtitle = configuration.subtitle;
  }
  @override
  void withTitle() {
    _title = configuration.title;
  }
  @override
  void withType() {
    _vehicleType = configuration.vehicleType.name;
  }
  @override
  void withButton() {
    _button = VehiculeCardButton(
      onTap: configuration.onTap,
      buttonLabel: configuration.buttonLabel,
    );
  }
}
class BikeLoadingBuilder extends BikeBuilder {
  BikeLoadingBuilder({required super.configuration});
  @override
  void withIcon() {
    _icon = CircularProgressIndicator();
  }
  @override
  void withButton() {
    _button = VehiculeCardButton(onTap: () {}, buttonLabel: 'LOADING');
  }
}Code pour les Builders de la seconde version de résolution du widget de fiche de véhicule
Ce document offre une flexibilité appréciable, des sections réutilisables et une maintenance simplifiée. L’utilisation des mots clés late permettent d’avoir une erreur au runtime si les éléments obligatoires ont été oubliés par le directeur.

Pour notre exemple de fiche de véhicule, quelle que soit la méthode utilisée, nous avons besoin d’au moins un titre et un sous-titre, donc si il ne sont pas appelé par le Directeur au moment de la création, il y aura une late initialization error (documentation : https://www.dhiwise.com/post/understanding-the-late-initialization-error-in-flutter)
class VehicleWidgetDirector {
  const VehicleWidgetDirector();
  void buildCarCard(CarBuilder carBuilder) {
    carBuilder
      ..withType()
      ..withTitle()
      ..withSubtitle()
      ..withIcon()
      ..withButton()
      ..withSpecs()
      ..withEngine();
  }
  void buildCarCardWithoutSpecs(CarBuilder carBuilder) {
    carBuilder
      ..withType()
      ..withTitle()
      ..withSubtitle()
      ..withIcon()
      ..withButton();
  }
  void buildBikeCard(BikeBuilder bikeBuilder) {
    bikeBuilder
      ..withType()
      ..withTitle()
      ..withButton()
      ..withSubtitle()
      ..withIcon()
      ..withSpecs();
  }
  void buildBikeCardWithNoButton(BikeBuilder bikeBuilder) {
    bikeBuilder
      ..withType()
      ..withTitle()
      ..withSubtitle()
      ..withIcon()
      ..withSpecs();
  }	
}Directeur de la seconde version de résolution du widget de fiche de véhicule
Pour notre première version avec les design pattern Strategy et Factory, le VehicleWidget opère la sélection d'une configuration spécifique par les factories, telles que CarConfiguration ou BicycleConfiguration. Chaque configuration expose directement les composants prêts à être affichés (icône, spécifications, moteur, bouton). Le VehicleWidget procède ensuite à la composition du widget final en assemblant ces différents éléments.
Le flux de travail est simple; chaque configuration détermine les éléments à exposer (exemple: il n’y a pas de moteur sur un vélo, à part vos jambes).
Pour notre seconde version avec ses Builder et son Director, le VehicleWidget instancie un Director qui orchestre les étapes de construction (withType/Title/Subtitle/Icon/Specs/Engine/Button). Un Builder concret (CarBuilder/BikeBuilder) lit une configuration de données (CarCardConfiguration/BicycleCardConfiguration). Le Director impose une séquence uniforme et peut faire varier les "recettes" (inclure/exclure des sections).
Le produit final est construit étape par étape, de manière explicite, plus lisible par rapport à la première version.
L'implémentation de la première version est simple et rapide, nécessitant moins de classes et de formalités. Le code est très lisible, surtout lorsqu'il y a peu de variantes et d'options. Chaque configuration encapsule ses choix d'interface utilisateur, ce qui facilite la compréhension locale. Ce modèle est idéal pour des écrans plus simples.
Le système de la seconde version offre une forte cohérence du rendu grâce à un directeur centralisé qui permet d'appliquer facilement différentes recettes (par exemple, "fiche d’une voiture sans spécifications", "fiche d’un vélo sans bouton") sans dupliquer la logique d'assemblage. Il est évolutif lorsque le nombre de variantes (voiture, vélo, camion, etc..) ou de sections (section moteur, section nombre de pédales, etc..) augmente.
Le système améliore la testabilité en séparant les tests du directeur, des constructeurs et de la configuration.
void main() {
  testWidgets('BikeLoadingBuilder shows progress and overrides button', (tester) async {
    // caractéristiques du vélo
    final config = BicycleCardConfiguration(
	...
    );
    // builder pour une fiche qui affiche un loader
    final builder = BikeLoadingBuilder(configuration: config);
    const director = VehicleWidgetDirector();
    director.buildBikeCard(builder);
    final widget = builder.build();
    await tester.pumpWidget(MaterialApp(home: Scaffold(body: widget)));
    expect(find.byType(CircularProgressIndicator), findsOneWidget);
    expect(find.text('LOADING'), findsOneWidget);
    // on vérfie que malgré que nous sommes sur une fiche vélo
    // les comportements sont bien écrasés par notre builder
    expect(find.byIcon(Icons.directions_bike), findsNothing);
  });
}Exemple de code pour tester un cas de fiche de véhicule
De plus, il simplifie l'implémentation des feature flags et les tests A/B en permettant de changer de directeur ou de recette selon un flag.
| Pattern | Description | 
| Factory | Simplifie l’instanciation des bonnes variantes (configurations ou builders) sans exposer les détails au reste du code. Rend l’appelant plus propre et réduit le couplage. | 
| Strategy | Permute le comportement par type de véhicule sans if/switchpartout. Isole ce qui varie (données/présentation spécifique) de ce qui reste stable (structure de la carte). Simplifie l’ajout d’un nouveau véhicule : on ajoute une stratégie. | 
| Template method | Favorise la réutilisation du code en centralisant les parties communes de l’algorithme, réduit la duplication en évitant de réécrire les mêmes enchaînements de logique, et apporte de la flexibilité car chaque sous-classe peut redéfinir uniquement les étapes qui varient sans toucher au squelette général. Garantit aussi une meilleure lisibilité et maintenabilité en rendant explicite ce qui est fixe et ce qui peut changer dans un processus. | 
| Director | Centralise les recettes d’assemblage pour différents cas d’usage (ex : “car sans specs”). Sépare le “quoi/quand” (ordre, inclusion) du “comment” (Builder). Facilite l’expérimentation : on crée une nouvelle méthode du Director sans toucher aux Builders existants. | 
| Builder | Gère la construction d’un objet complexe par étapes, avec sections optionnelles (engine parfois absent). Réduit le risque d’incohérence visuelle : même squelette, étapes explicites. Permet la réutilisation d’étapes ( withHeader,withSpecs…) et favorise la DRYness. | 
Le choix entre l'utilisation d'un Configurateur simple et l'association Builder + Director dépend principalement de la complexité et des exigences de votre interface utilisateur.
Choisir la première version si vous avez:
Choisir la seconde version de notre système si vous avez:
L'over-engineering est un risque, mais les patrons de conception restent des outils précieux. Nous avons exploré ensemble quelques exemples pour illustrer leur existence et leur utilité.
Si vous avez seulement une ou deux variantes simples, il est préférable d'éviter une utilisation prématurée de Builder/Director.
Par contre, il y a des inconvénients au configurateur. À mesure que le nombre de variantes augmente, le Configurateur seul peut entraîner une duplication de l'assemblage et des incohérences visuelles.
Alors partons sur un compromis recommandé, il faudrait commencer par le Configurateur. Puis passer à Builder + Director lorsque les variantes ou les "recettes" deviennent trop nombreuses. Dans les deux cas, conservez la Strategy pour la configuration des données.
Cette approche, portée par les design patterns (Builder, Factory, Strategy, Template Method), transforme un widget « monstre » en architecture modulaire et élégante. On gagne en lisibilité, testabilité, et capacité d’évolution - exactement ce qu’on attend d’un code durable.
Investir dans la qualité du code n’est pas un luxe : c’est un accélérateur de livraison.
Comme promis, voilà le projet avec les différentes versions : https://github.com/thomasdhulst/flutter-design-pattern-configuration-builder
Essayez ces patterns sur vos propres widgets : partagez vos retours, posez vos questions, et comparez vos avant/après.
 
		
Vous passez des heures à traquer des bugs dans votre code, mais quand avez-vous débuggé votre emploi du temps pour la dernière fois ?
Pendant des années j’ai travaillé sans réelle stratégie d’organisation ou de planification. Cela me convenait très bien, je gardais les sujets importants dans ma tête. Mes mails, les dailys, les outils du projet me permettaient de rester à jour. Puis après quelques années je me suis heurté à un mur ! J’étais lead développeur d’une équipe de 10 développeurs et je n’arrivais plus à tout gérer.
Au fil de votre carrière vous allez certainement prendre de plus en plus de responsabilités, vous aurez peut-être plusieurs projets à la fois, vous serez peut-être responsables de certaines tâches en interne. Vous deviendrez peut-être lead ou manager. En tout cas, il est fort probable que la gestion de toutes ces activités en parallèle devienne bien plus complexe qu’au début de votre carrière.
Votre agenda est comme un programme mal optimisé : des fuites mémoires, des dépendances bloquantes, des exceptions non gérées, des boucles infinies ! Il est temps de le refactorer et de corriger tous ces bugs !
Aujourd’hui j’aimerais vous partager mon expérience afin de vous permettre d’identifier les bugs dans votre gestion du temps et les corriger, comme vous le feriez avec votre code.Cela vous permettra de réduire votre stress et votre charge mentale tout en vous donnant les moyens de vous investir dans les projets qui vous tiennent à cœur.
Disclaimer
Maîtriser son temps est très personnel. Je pense qu’il faut avant tout apprendre à se connaître et créer la méthode qui vous convient. Il existe de nombreuses méthodologies déjà existantes. Au cours de cet article je citerais celles dont j’ai emprunté des éléments et qui ont bien fonctionné pour moi, mais comme toujours je vous invite à faire des recherches et des tests par vous-même.

Tout comme il est parfois important d'arrêter de développer des nouvelles features pour corriger les problèmes présents dans la base de code, il faudra un peu de courage et d'honnêteté pour prendre du recul sur votre façon de travailler. Prenez le temps de vous arrêter au moins 1 heure pour vous auto-diagnostiquer.
Dans mon cas, il était urgent que je prenne le temps de ralentir mon activité pour faire ce diagnostic et comprendre quels étaient les bugs de ma gestion du temps. Pourquoi avais-je toujours cette impression de courir partout et de ne pas réussir à tout faire ?
Pour cette étape de diagnostic je vous propose d’établir votre liste de tâches et de les caractériser :
Avec cette comparaison vous devriez vous rendre compte de ce qui vous prend le plus de temps. Est-ce que ce sont vraiment les tâches principales ?
Sur 25 tâches différentes j’ai trouvé 11 tâches que je n’avais simplement pas le temps de faire. Dont certaines très importantes pour le projet et d’autres pour lesquelles j’étais triste de ne pas pouvoir y consacrer du temps. Suite à la montée en charge de l’équipe je n’avais plus vraiment le temps de développer, encore moins de faire de la veille techno ou d’animer des coding dojo. Mais en parallèle de ça je consacrais parfois ½ journée à des tâches peu importantes.
De plus, j'ai remarqué que je consacrais parfois la moitié de mon temps de travail à répondre aux sollicitations des autres membres de l’équipe au détriment des mes propres tâches.
Une fois ce constat fait, il faut maintenant changer vos habitudes. Pour cela il faudra faire preuve de 3 qualités : réalisme sur vos objectifs, indulgence sur vos résultats et ténacité face aux obstacles. Dans mon cas j’ai décidé de prendre 2 sprints de 3 semaines pour mettre en place certains conseils et une méthodologie de gestion du temps.

Suite à mon analyse, il était devenu évident que j’avais un problème avec le nombre de tâches dont je m’estimais responsable. Il me fallait donc apprendre à mieux les prioriser et ne pas me disperser.
Tout comme un code bien organisé permet de gagner en efficacité, une liste de tâches et un agenda “clean” seront vos meilleurs alliés dans votre gestion du temps.
Pour faire rentrer dans mon planning hebdomadaire les tâches les plus importantes, j’ai utilisé une variante de la matrice d’Eisenhower. Celle-ci permet de déterminer 6 niveaux de priorités en fonction de l’importance et de l’urgence de la tâche à accomplir.
L’urgence d’une tâche augmente au fur et à mesure que son échéance approche.
L’importance d’une tâche est proportionnelle aux risques liés à sa non-réalisation et aux gains de sa réalisation.
Vous pouvez utiliser le tableau de priorisation suivant pour déterminer la priorité de chaque tâche (de P1 à P6).

Les tâches P1 à P3 sont très importantes pour moi ou les autres.
Celles de P4 à P6 sont des tâches moins importantes.
Les P1 et P4 sont urgentes pour aujourd'hui
Les P2 et P5 sont urgentes pour cette semaine
Les P3 et P6 ne sont pas urgentes pour cette semaine
Selon le niveau de priorité la façon de traiter la tâche doit être différente :
En détectant et en supprimant les tâches P4 à P6 vous vous dégagerez le temps d’accomplir sereinement les tâches les plus importantes.
De plus, les P1 (et même les P2) devraient être exceptionnelles. En effet, il est rare de découvrir une tâche importante au dernier moment. Et même si c’est devant le mur qu’on voit le mieux… le mur, il est trop tard pour l’éviter.
Planifier vos tâches P3 à l’avance permet d’utiliser tout l’arsenal des solutions disponibles (analyser, déléguer, demander de l’aide, organiser une réunion… etc) plutôt que de traiter seul et dans le rush car la deadline approche. Avec de l’anticipation il est souhaitable de consacrer 60% de son temps aux tâches P3 (les plus importantes mais non urgentes).
Maintenant que vous avez les idées claires grâce à cette analyse et ce refacto, il devient beaucoup plus facile de corriger les bugs ! Une liste de tâches caractérisées et priorisées est bien plus facile à insérer dans un emploi du temps.
Voici ma méthode pour construire mon agenda. J’ai choisi de construire celui-ci sur 3 semaines car c’est la durée d’un sprint et que cela permet d’anticiper suffisamment à l’avance les tâches P3. J’utilise principalement la méthodologie “Time-blocking”. Cela consiste à réserver à l’avance des plages de travail pour vos activités.
L’agenda se compose de 2 types de créneaux
L’ensemble des éléments programmés ne doit pas dépasser 30% de votre temps. Ce sont les points fixes de votre agenda et permettent d’avancer en terrain connu. Si elles sont trop nombreuses vous perdrez en souplesse. Si c’est le cas pour vous, il est important de questionner ces créneaux et de se demander si cela concerne vraiment votre activité principale.
De mon côté j’avais 2 problèmes principaux. J’étais invité à beaucoup trop de réunions pour me laisser le temps de réaliser mes tâches personnelles, de plus j’étais souvent interrompu par des sollicitations extérieures du fait de la taille de mon équipe.
Le Time Blocking m’a beaucoup aidé à résoudre ces problèmes. Je sais d’avance que si j’accepte d’aider un collègue sur un des créneaux dédiés à un développement cela aura un impact sur le délai de réalisation de mon ticket. Je peux ainsi décider si j’ai le temps d’aider ce collègue ou si mon ticket est plus prioritaire. Lorsque je suis sur une tâche critique je peux signaler aux autres mon indisponibilité et quand je serai en mesure de les aider.
De la même manière, cette vision de mon agenda sur 3 semaines me permet de savoir quand je dois refuser une réunion ou envoyer un autre développeur à ma place.
Le fait de remplir son agenda à 100% est un autre bug très courant. Il est important de laisser des créneaux libres pour les imprévus dans l’emploi du temps. On estime qu’il faut entre 20 à 30% du temps libre pour gérer sereinement ces imprévus.
De plus, essayez au maximum de garder ces créneaux libres jusqu’au dernier moment. Cela vous permettra de gérer les urgences sereinement. On ne sait jamais quand un bug critique surgira en prod ou quand l’un de vos développement prendra du retard.
Dans le cas où tout va bien, ces créneaux me permettent souvent d’aller aider mes collègues et de répondre aux nombreuses sollicitations que j’ai mises de côté plus tôt dans la journée.

Une des choses les plus importantes à accepter pour bien gérer son temps est que cela prend du temps. Tout comme j’étais déjà convaincu du gain de temps apporté par les tests unitaires et les code review, ma dernière expérience m'a convaincu de l'intérêt de cette weekly review.
Il faut impérativement consacrer un peu de temps à la planification pour ne pas se laisser submerger par les tâches et ne pas se faire surprendre par des urgences.
Pour cela je vous conseille de réserver un créneau hebdomadaire d’1 heure pour faire le point. Cette pratique est souvent appelée la weekly review. C’est un moment que vous prenez toutes les semaines pour anticiper les 3 prochaines semaines à venir. C’est le moment d’appliquer la méthodologie expliquée dans le chapitre précédent.
Cette review est aussi le moment parfait pour faire le point avec vous-même sur les semaines précédentes. Tout comme une rétrospective en méthodologie agile c’est un temps consacré à l’amélioration continue. Cet aspect est particulièrement important lors des 6 premières semaines de changement dans votre façon de vous organiser.
Relancez-vous dans une phase de diagnostic et de debug ! Etes-vous satisfait de comment vous vivez vos semaines de travail ? Avez-vous eu le temps d’accomplir vos tâches importantes ?
Il sera souvent nécessaire d’actualiser votre agenda quotidiennement. Pour cela, réservez-vous 10 minutes pour faire le bilan de la journée. Personnellement j’aime bien le faire en fin de journée mais vous trouverez peut-être plus facile de faire ce bilan en arrivant le matin.Avez-vous terminé toutes les tâches importantes qui étaient prévues ? Si ce n’est pas le cas, il sera nécessaire de modifier votre plan pour la prochaine journée.
Est-ce que de nouvelles tâches importantes ou urgentes doivent être planifiées ?
Dans le cas échéant, il est important de bien prendre le temps de modifier votre liste de tâches et votre agenda pour les jours suivants. Dans le cas contraire, vous serez très content de réaliser que vous avez terminé tout ce que vous deviez faire aujourd’hui !
Afin de me libérer du temps dans la semaine j’ai eu besoin d’apprendre à mieux déléguer. Il y avait trop de tâches que je faisais seul et l’information ne circulait pas assez dans l’équipe. Finalement un lead dev qui ne délègue pas c’est comme une fonction qui fait tout : plus personne ne sait ce qu’elle fait vraiment…
La solution évidente à ce problème est de travailler en pair. Pour cela nous avons d’abord réalisé ces tâches ensemble puis quand les développeurs ont été autonomes j’ai pu complètement leur confier ces responsabilités.
Le fait de confier certaines tâches à d’autres membres de l’équipe était indispensable, au vu de la taille de l’équipe, et a permis à tout le monde de progresser et de mieux communiquer. En plus de cela j’y ai trouvé une satisfaction personnelle car j’ai réussi à retrouver le temps de développer. J’avais en effet moins de tâches différentes à accomplir et de réunions à suivre.
En tant que développeur.se, la gestion du temps est trop souvent survolée ou oubliée. Cependant il est très important de prendre soin de son emploi du temps, tout comme vous prenez soin de votre code.
Réserver des créneaux pour planifier mes semaines et accomplir mes tâches a vraiment été salvateur en tant que lead dev. Cela m’a pris plusieurs sprints pour reprendre le contrôle sur mon agenda mais je pense que le travail d’introspection accompli m’a énormément fait progresser. Je vous invite fortement à faire de même, avant de vous retrouver complètement sous l’eau !
Soyez courageux pour prendre du recul et détectez vos bugs.
Consacrez du temps à la gestion de votre agenda pour simplifier le reste de votre semaine et vous alléger l’esprit.
Anticipez et priorisez vos tâches pour créer de la confiance.
 
		
Lorsque votre application Android commence à grossir ou lorsque vous avez des portions que vous souhaitez isoler fortement les unes des autres, il y a de fortes chances que vous vous dirigiez vers une architecture multi-module. Si on se réfère à la documentation Android, on trouvera parmi les bénéfices recherchés :
| Bénéfice | Description | 
|---|---|
| Réutilisabilité | La modularisation ouvre des possibilités de partage de code et de création de plusieurs applications à partir de la même base. Par exemple, une bibliothèque d’authentification pourrait être réutilisée dans une autre application. | 
| Strict contrôle de la visibilité | Les modules, en particulier en kotlin avec le mot clé internal, vous permettent de contrôler facilement ce que vous souhaitez exposer. | 
| Livraison personnalisée | Play Feature Delivery est une fonctionnalité qui vient avec les app bundles. Elle permet de livrer certaines fonctionnalités de votre application de manière conditionnelle ou à la demande. Par exemple, un utilisateur téléchargera un niveau d’un jeu vidéo seulement une fois qu’il sera débloqué. L’avantage étant de réduire la taille de l’application lors du premier téléchargement. | 
Comme l’indique aussi la documentation officielle, modulariser est une manière d’atteindre ces autres bénéfices :
| Bénéfice | Description | 
|---|---|
| Découplage / Encapsulation | Modulariser pousse à séparer le code en fonction de ses responsabilités, réduisant le risque de code spaghetti. | 
| Facilitation de la gouvernance | Il est plus facile de faire travailler plusieurs équipes sur la même application en ayant des modules distincts. Un module A peut être affecté à une équipe X et un module B à une équipe Y. | 
| Testabilité | Puisque l’isolation des modules est censée être plus grande, c’est aussi censé être plus facile de tester en isolation ces mêmes modules. | 
| Temps de build | Gradle, qui est l’outil le plus utilisé pour construire des applications Android, se marie très bien avec la modularisation. Gradle utilise de la compilation incrémentale, du cache de build et de la parallélisation de build, ce qui est idéal avec des modules isolés. | 
| Passage à l’échelle | Tout cela contribue à aider le passage à l’échelle de votre application, là où sinon des problèmes organisationnels et / ou de temps de compilation peuvent survenir. | 
Voici un exemple d’app multi modules que je décrivais sur le blog Ippon dans cet article :

Chaque bloc est un module. Le découpage choisi à l’époque en 2020 est perfectible, mais l’idée étant de donner un exemple de ce que cela peut donner !
Un module Android se traduit donc par un module Gradle. Lorsque vous en créez un via Android Studio (clic droit sur le dossier parent du projet -> new -> Module), on découvre qu’il en existe plusieurs types :

Votre choix déterminera la structure des dossiers généré sera et le type de plugin gradle importé. Par exemple, si votre module est une application, com.android.application sera importé.
Ci-dessous un exemple pour le module app, dans le fichier build.gradle.kts, qui déclare dans ses plugins alias(libs.plugin.android.application).

C’est une instruction qui correspond à une entrée dans nos version catalogs :

Si votre module est une bibliothèque, alors ça sera le même principe mais avec en plugin com.android.library de déclaré.
Les version catalogs sont une fonctionnalité de gradle qui enrichit la manière de gérer les dépendances. Dans une manière plus classique, une dépendance est importée comme cela dans un fichier build.gradle.kts :
dependencies {
    implementation("<group>:<name>:<version>")
}
La problématique, c’est que si la dépendance doit être réutilisée ailleurs dans un autre module, il faut exactement écrire la même chose pour chaque module consommateur. On prend donc le risque d’avoir une version différente ou même un artefact différent. À la lecture, on ne peut pas déterminer que les dépendances doivent être les mêmes.
Les version catalogs apportent des réponses en externalisant ces déclarations dans un ou plusieurs fichiers .toml visibles de tous les modules du projet. Ce fichier se situe par défaut dans le répertoire gradle à la racine du projet :

Dans ce fichier on définit tout d’abord des versions, ensuite des libraries et enfin des plugins :
[versions]
activityComposeVersion = "1.10.1"
agpVersion = "8.12.0"
...
[libraries]
android-gradle-plugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agpVersion" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityComposeVersion" }
...
[plugins]
android-application = { id = "com.android.application", version.ref = "agpVersion" }
android-library = { id = "com.android.library", version.ref = "agpVersion" }
Des accesseurs sont générés automatiquement à la compilation. Il y a alors de l’autocomplétion lorsque les dépendances sont importées et la réutilisabilité est facile. Pour android-activity-compose on passerait alors de :
dependencies {
    implementation("android.activity:activity-compose:1.10.1")
}
À :
dependencies {
    implementation(libs.androix.activity.compose)
}
Note : libs est le préfixe utilisé par défaut comme répertoire de nommage pour tout ce qui est généré depuis le bloc libraries. Pour les plugins gradle, un suffixe plugins est ajouté à libs. On a alors pour un plugin android-library :
dependencies {
    alias(libs.plugins.android.library)
}
Depuis l’introduction de AndroidX, les dépendances d’une application Android sont bien plus atomiques. C’est bien pour alléger l’application. En revanche, cela augmente le nombre de dépendances à spécifier dans les fichiers de configuration. Pour donner un ordre de grandeur, j’ai plus de 60 entrées (versions + dépendances) dans le fichier TOML de mon application, alors qu’elle ne se compose que de 3 écrans.
Le constat, c’est qu’un module de notre application a souvent entre 80 et 100% de dépendances communes avec un autre module d’un même archétype. J’entends par là deux modules dédiés à la création d’écrans, ou deux modules plutôt orientés métier. Le challenge est alors d’aller un cran plus loin dans la gestion des dépendances pour factoriser leurs déclarations.
Notes :
Les version catalogs offrent une offre fonctionnalité intéressante : les bundles. Comme son nom laisse supposer, il s’agit là de regrouper des dépendances ensemble pour les importer ensemble en une seule fois. Si vous connaissez Maven, cela vous rappellera les BOM. Voici l’exemple de la documentation :
[versions]
groovy = "3.0.9"
[libraries]
groovy-core = { group = "org.codehaus.groovy", name = "groovy", version.ref = "groovy" }
groovy-json = { group = "org.codehaus.groovy", name = "groovy-json", version.ref = "groovy" }
groovy-nio = { group = "org.codehaus.groovy", name = "groovy-nio", version.ref = "groovy" }
[bundles]
groovy = ["groovy-core", "groovy-json", "groovy-nio"]
Le bundle groovy est ensuite importé dans les dépendances :
dependencies {
    implementation(libs.bundles.groovy)
}
Malheureusement, cela ne concerne pas les dépendances définies dans le bloc plugins. Impossible alors en une seule instruction de définir qu’un module importe x plugins et y dépendances.
Gradle fonctionne avec des plugins. Il en existe 4 grandes familles :
Une ancienne manière de faire était d’importer tout un fichier de configuration dans les modules où on souhaite le partager.
Prenons par exemple un fichier appelé configuration.gradle qui contient :
dependencies {
    implementation(libs.bundles.groovy)
}
Pour appliquer ces dépendances dans chaque build.gradle.kts de nos modules, il faut alors écrire en haut du fichier :
apply("$rootDir/configuration.gradle")
plugins {
/* ... */
Notez bien ici que configuration.gradle est un fichier gradle simple, pas en kotlin script. Avec un fichier gradle.kts on ne peut pas faire cette même “magie” simplement.
Il s’agit d’une manière legacy de faire. On perd en performance puisqu’il faut fusionner les instructions spécifiées dans notre nouveau fichier avec celles contenues dans chaque module. Le script n’est pas compilé mais réinterprété à chaque fois. Il n’y a enfin pas non plus de sécurité à la compilation puisqu’on importe le script via une chaîne de caractères.
La documentation de gradle propose aussi de définir un plugin comme ceci :
class CommonDependenciesPlugin : Plugin<Project> {
    override fun apply(project: Project) {
        val libs = the<LibrariesForLibs>()
        project.dependencies {
            add("implementation", platform(libs.androidx.compose.bom))
        }
    }
}
apply<CommonDependenciesPlugin>()
Malheureusement, malgré toutes mes tentatives, si le script kotlin est en dehors de certains dossiers spéciaux, la classe n’est pas reconnue correctement :
Caused by: java.lang.IllegalArgumentException: Class Common_gradle.CommonDependenciesPlugin is a non-static inner class
En fait, lors de la compilation kotlin, chaque script est relié à une classe kotlin. Dans notre exemple, gradle va créer une classe pour common-dependencies-plugin.gradle.kts, et va donc définir comme classe interne CommonDependenciesPlugin. Or, il semblerait que Gradle ait besoin de static pour travailler avec des plugins. Les classes internes ne sont pas static par défaut.
D’après la documentation, ce sont des scripts Groovy ou Gradle compilés et distribués au travers de bibliothèques. Ils sont appliqués via le bloc plugins d’un projet.
Par exemple, si un plugin contient dans un fichier plugin/src/main/kotlin/my-plugin.gradle.kts :
// This script is automatically exposed to downstream consumers as the `my-plugin` plugin
tasks {
    register("myCopyTask", Copy::class) {
        group = "sample"
        from("build.gradle.kts")
        into("build/copy")
    }
}
Alors la tâche myCopyTask sera accessible dans tous les projets qui intégreront my-plugin comme ceci :
plugins {
    id("my-plugin") version "1.0"
}
Gradle détermine automatiquement qu’il s’agit d’un plugin à partir du fichier .gradle.kts
Il s’agit d’un format intermédiaire entre les Binary Plugins et les Precompiled Script Plugins. buildSrc est un module spécial qui est automatiquement compilé et inclus au projet si votre répertoire source a cette structure :
root/
 ├─ build.gradle (or build.gradle.kts)
 ├─ settings.gradle (or settings.gradle.kts)
 ├─ buildSrc/
 │   ├─ src/main/kotlin (or java)
 │   │    └─ ... Kotlin/Java classes
 │   └─ build.gradle.kts
Le dossier buildSrc a besoin d’un fichier build.gradle.kts minimal comme celui-ci :
plugins {
    `kotlin-dsl`
}
repositories {
    google()
    mavenCentral()
}
Ensuite, l’idée est de définir ensuite une structure que l’on souhaite voir partagée. Prenons en exemple un fichier buildSrc/src/main/kotlin/common-dependencies.gradle.kts :
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
dependencies {
    add("implementation", libs.findLibrary("androidx-activity-compose").get())
}
Ici, on récupère dynamiquement les versions définies dans les versions catalogs. Il serait aussi envisageable de se passer des versions catalogs et de définir les versions et dépendances à ajouter directement en Kotlin. On ajoute aussi dynamiquement des entrées aux dépendances avec la méthode add. L’inconvénient c’est que l’on perd la sécurité à la compilation.
Pour factoriser aussi la déclaration de plugins, on les ajoute de manière programmatique :
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
project.pluginManager.apply(libs.findPlugin("android-application").get().get().pluginId)
dependencies {
    add("implementation", libs.findLibrary("androidx-activity-compose").get())
}
Par défaut, un bloc plugins sera chargé avant l’évaluation des version catalogs. buildSrc n’a pas la vue non plus sur les plugins définis ailleurs dans le projet. Si on veut alors plutôt que charger le plugin en déclaratif que de manière programmatique :
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
    
plugins {
    id("com.android.application")
}
    
dependencies {
    add("implementation", libs.findLibrary("androidx-activity-compose").get())
}
Ceci conduit à cette erreur :
* Exception is:
org.gradle.api.plugins.UnknownPluginException: Plugin [id: 'com.android.application'] was not found in any of the following sources:
- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Included Builds (No included builds contain this plugin)
- Plugin Repositories (plugin dependency must include a version number for this source)
À l’usage dans un module, il faut appliquer le plugin comme ceci :
plugins {
	id("common-dependencies")
}
Le plugin est automatiquement référencé en fonction du nom du fichier dans lequel il est déclaré.
Ce sont des plugins compilés et distribués en tant que JAR dans le projet. L’objectif ici est de publier en local des plugins qui contiennent toute la factorisation de dépendances. C’est la manière la plus performante de distribuer des plugins gradle en local. En effet, il s’agit de code compilé, mis donc en cache entre deux builds.
La déclaration de ce plugin va suivre à peu près ce qu’il se fait pour buildSrc. Il faut commencer par créer un répertoire build-logic (ou qui porte le nom que vous voulez) dans votre projet. Puisqu’un JAR sera distribué, il aura un nom de package. La structure des sources change alors aussi pour avoir le package : src/main/kotlin/my/package si le package est my.package.
root/
 ├─ build.gradle (or build.gradle.kts)
 ├─ settings.gradle (or settings.gradle.kts)
 ├─ build-logic/
 │   ├─ src/main/kotlin/my/package (or java)
 │   │    └─ ... Kotlin/Java classes
 │   └─ build.gradle.kts
 │   └─ settings.gradle.kts
Ce module n’est pas compilé automatiquement par gradle. Il faut alors l’enregistrer dans les settings.gradle.kts parent. Puisqu’on distribue des plugins, cela se fait au niveau du bloc pluginManagement :
pluginManagement {
    includeBuild("build-logic") // Inclusion du plugin
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
    }
}
Ce module doit aussi contenir un fichier settings.gradle.kts local pour activer les version catalogs et récupérer les dépendances du module :
dependencyResolutionManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
    }
    versionCatalogs {
        create("libs") {
            from(files("../gradle/libs.versions.toml"))
        }
    }
}
rootProject.name = "build-logic"
Le fichier build.gradle.kts de build-logic change aussi :
import org.gradle.initialization.DependenciesAccessors
import org.gradle.kotlin.dsl.support.serviceOf
plugins {
    `kotlin-dsl`
}
dependencies {    compileOnly(files(gradle.serviceOf<DependenciesAccessors>().classes.asFiles))
}
gradlePlugin {
    plugins {
        register("moduleAndroidPresentation") {
            id = "com.cheatshqip.module.android.presentation"
            implementationClass = "com.cheatshqip.build_logic.AndroidPresentationModulePlugin"
        }
    }
}
Il y a ici en dépendances les classes utilisées par DependenciesAccessor. C’est un service interne de gradle qui est utilisé avec les version catalogs. Il expose notamment la classe LibrariesForLibs. Elle représente le mapping Kotlin du contenu du fichier toml des versions catalogs.
Le bloc gradlePlugin sert à enregistrer le plugin que nous sommes en train de créer. On spécifie son identifiant (id) et la classe qui est le point d’entrée du plugin. Ici AndroidPresentationModulePlugin.
Enfin, justement cette classe contient le code suivant :
class AndroidPresentationModulePlugin : Plugin<Project> {
    override fun apply(target: Project) {
        with(target) {
            val libs = the<LibrariesForLibs>()
            
            with(pluginManager) {
                apply(libs.plugins.kotlin.compose.get().pluginId)
            }
            
            dependencies {
                implementation(libs.androidx.navigation.compose)
                implementation(libs.androidx.lifecycle.runtime.ktx)
                implementation(platform(libs.androidx.compose.bom))
                implementation(libs.androidx.compose.foundation)
                implementation(libs.androidx.activity.compose)
                implementation(libs.androidx.ui)
                implementation(libs.androidx.ui.graphics)
                implementation(libs.androidx.ui.material3)
                implementation(libs.androidx.ui.tooling.preview)
            }
        }
    }
}
private fun DependencyHandler.implementation(dependencyNotation: Any) {
    add("implementation", dependencyNotation)
}
private fun DependencyHandler.testImplementation(dependencyNotation: Any) {
    add("testImplementation", dependencyNotation)
}
private fun DependencyHandler.androidTestImplementation(dependencyNotation: Any) {
    add("androidTestImplementation", dependencyNotation)
}
Les fonctions privées implementation, testImplementation et androidTestImplementation servent à copier le DSL que nous utilisons habituellement dans un bloc dependencies pour déclarer nos dépendances.
Grâce à LibrariesForLibs nous avons accès aux dépendances utilisées lors de la compilation. C’est un vrai confort d’avoir de l’autocomplétion dans cette situation.
La classe AndroidPresentationModulePlugin implémente l’interface Plugin<Project>. En surchargeant la méthode apply, on a alors accès au Project sur lequel le plugin est appliqué. Via le pluginManager, on ajoute le plugin gradle jetpack compose et via le bloc dependencies on ajoute toutes les bibliothèques graphiques nécessaires pour travailler avec Jetpack Compose.
À l’usage, on importe le plugin par son id. On peut ajouter au préalable une entrée dans les version catalogs si on ne souhaite pas travailler avec des chaînes de caractères :
[plugins]
/* */
cheatshqip-module-android-presentation = { id = "com.cheatshqip.module.android.presentation" }
Puis, le plugin est ajouté dans le bloc dédié des modules, dans leurs fichiers build.gradle.kts :
plugins {
    /* */
    alias(libs.plugins.cheatshqip.module.android.presentation)
    /* */
}
buildSrc (convention plugins) et les binary plugins sont les moyens préconisés par gradle pour partager de la logique de configuration. Si les binary plugins sont un peu plus compliqués à mettre en place, ils offrent plus de possibilités et surtout de meilleures performances. buildSrc présente par exemple comme limite le fait que le moindre changement en son sein conduit à l’invalidation de l’ensemble du paramétrage du projet, et donc à sa recompilation. Amusez-vous bien !
 
		
iChaque exemple cité dans cet article a été réalisé avec succès grâce à Devstral, même s’il n’est pas toujours présenté visuellement.
Mistral AI a annoncé le lancement de Devstral, un nouveau modèle open source orienté ingénierie logicielle le 21 mai 2025.
Devstral est un modèle LLM agentique open source, conçu principalement pour les tâches de développement logiciel, c’est-à-dire la résolution de problèmes de programmation multi‑étapes dans de grands projets de code. Ce modèle est finement optimisé pour les agents de codage autonomes, capables de naviguer dans des bases de code complexes, modifier plusieurs fichiers, proposer des corrections tout en agissant de manière “agentique”.
Devstral a été développé en collaboration avec All Hands AI pour résoudre des problèmes complexes de développement (problèmes GitHub réelles) en se comportant comme un véritable agent : il analyse de larges bases de code, modifie plusieurs fichiers et exécute des tests pour valider ses changements.
Il obtient également un score de 46,8 % sur le benchmark SWE-Bench Verified* (500 problèmes réelles), surpassant les modèles open source plus volumineux (DeepSeek-V3-0324, Qwen3-232B-A22B) et certains modèles fermés comme GPT-4.1-mini.
*(SWE‑Bench Verified est un benchmark (jeu de tests) utilisé pour évaluer la capacité des modèles d'IA à résoudre de vrais bugs logiciels dans des projets open-source GitHub).

Comparaison des modèles IA sur SWE-Bench Verified
Avec seulement 24 milliards de paramètres et une fenêtre de contexte de 128 k tokens, issu de Mistral Small 3.1, Devstral peut tourner en local sur une RTX 4090 ou sur un Mac avec 32 Go de RAM, ce qui fait de lui un modèle léger et puissant.
Il possède également la licence Apache 2.0 complète ce qui signifie qu'il peut être aussi bien utilisé pour un usage personnel que commercial, la modification du modèle est également autorisée tout comme la redistribution de celui-ci qui est totalement libre.
Enfin il s’intègre de manière fluide aux frameworks d’agent comme OpenHands, SWE-Agent ou OpenDevin, qui orchestrent son interaction avec le code et l’environnement de développement. Il excelle pour inspecter et modifier plusieurs fichiers ainsi que dans la correction des bugs directement dans un dépôt.
Nous avons vu précédemment ce qu'était Devstral, nous allons à présent détailler les prérequis nécessaires à son utilisation en local, tant au niveau matériel que logiciel. Nous aborderons également trois méthodes d'utilisation : en ligne de commande, via un plugin, et en utilisant OpenHands.
Pour une utilisation fluide et optimale de Devstral, il est conseillé de disposer d’une machine avec les caractéristiques suivantes :
Il est toutefois possible d’utiliser Devstral avec une configuration plus modeste. Cependant, les performances seront fortement impactées, notamment en termes de temps de réponse. Voici une configuration minimale pour débuter :
Devstral est compatible avec Linux, macOS, et Windows (ce dernier étant recommandé avec WSL). Il nécessite au minimum Python 3.9. Si vous utilisez un GPU Nvidia il vous faudra une version supérieure à 11.8 pour CUDA (Outil qui permet de faire des calculs lourds sur le GPU plutôt que sur le CPU).
Les instructions d’installation et les exemples qui vont suivre ont été réalisés sur une machine Linux. Il se peut donc que certaines étapes diffèrent légèrement selon votre système d’exploitation.
Ollama est un outil open-source puissant permettant d’exécuter des LLM localement. J'ai choisi Ollama car il est très simple à installer et utiliser, qu'il peut tourner sur tous les systèmes d'exploitation et permet facilement le téléchargement et l'exécution d'énormément de modèles. Il existe également d'autres alternatives avec LM Studio, llama.cpp, GPT4All, etc..Pour des cas d'usages simples mais néanmoins robuste Ollama et LM Studio seront privilégiés.
Pour les machines Windows et Mac il suffit de se rendre sur https://ollama.com/download et télécharger le .exe et .dmg respectivement et de l’exécuter. Pour linux il faudra lancer la commande suivante dans un terminal :
curl -fsSL https://ollama.com/install.sh | shUne fois ollama installé il faudra lui demander de récupérer Devstral, pour ce faire il faudra lancer la commande :
ollama pull devstralSi vous exécutez la commande telle quelle, la dernière version de Devstral sera automatiquement téléchargée. Si vous souhaitez utiliser une version spécifique, vous pouvez le faire en remplaçant le mot-clé devstral dans la commande par le nom exact de la version désirée. (par exemple : ollama pull devstral:24b-small-2505-q8_0)
Le téléchargement pèse environ 15 Go, il faudra donc patienter quelques minutes selon la vitesse de votre connexion.
Une fois le téléchargement terminé, vous pouvez lancer Devstral avec la commande suivante :
ollama run devstralUne fois devstral lancé vous devriez obtenir un terminal similaire à celui-ci :

Exécution de la commande de lancement de Devstral par Ollama dans un terminal
Il existe plusieurs plugins pour IntelliJ permettant d'intégrer un agent de code préalablement téléchargé en local, afin d’utiliser l’assistant de votre choix. Dans mon cas, j’ai opté pour le plugin MyOllamaEnhancer. Pour les utilisateurs de VS Code, plusieurs extensions similaires sont également disponibles, telles que Ollama Dev Companion ou VSCode Ollama.
Ces plugins nécessitent que Devstral ait été installé au préalable via Ollama, comme décrit dans la section précédente.
En ce qui concerne l'installation et la configuration de MyOllamaEnhancer il suffit de le télécharger via le marketplace d'IntelliJ via le menu Settings > Plugin. Une fois celui-ci téléchargé il faudra le configurer comme tel :

Configuration de MyOllamaEnhancer dans IntelliJ
Attention à bien modifier le champ Ollama Model par le modèle spécifique que vous avez téléchargé via Ollama.
Il s'agit du cas d’usage le plus courant pour ce type de LLM agentique, car c’est dans ce contexte qu’il donne les meilleurs résultats. (Nous verrons d’ailleurs des exemples concrets dans le chapitre suivant)
Avant toute chose, vous devez générer une clé d’API Mistral. Cela peut se faire gratuitement en vous rendant à l’adresse suivante : https://console.mistral.ai/api-keys.
Une fois votre clé obtenue, ouvrez un terminal et exécutez les commandes suivantes :
# Store the API key securely as an environment variable (avoid hardcoding in scripts)
export MISTRAL_API_KEY=<MY_KEY>en remplaçant  <MY_KEY> par la clé API créée précédemment.
# Pull the runtime image for OpenHands
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.48-nikolaik# Create a configuration directory and settings file for OpenHands
mkdir -p ~/.openhands-state
cat << EOF > ~/.openhands-state/settings.json
{
  "language": "en",
  "agent": "CodeActAgent",
  "max_iterations": null,
  "security_analyzer": null,
  "confirmation_mode": false,
  "llm_model": "mistral/devstral-small-2505",
  "llm_api_key": "${MISTRAL_API_KEY}",
  "remote_runtime_resource_factor": null,
  "github_token": null,
  "enable_default_condenser": true
}
EOF# Run the OpenHands application in a Docker container with enhanced settings
docker run -it --rm --pull=always \
    -e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.48-nikolaik \
    -e LOG_ALL_EVENTS=true \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v ~/.openhands-state:/.openhands-state \
    -p 3000:3000 \
    --add-host host.docker.internal:host-gateway \
    --network=host \
    --name openhands-app \
    docker.all-hands.dev/all-hands-ai/openhands:0.48À la suite de l’exécution de cette dernière commande, l'application web va se lancer et sera disponible à l'adresse :
http://0.0.0.0:3000/
Vous devriez avoir une interface ressemblant à celle-ci :

Interface d'accueil d'OpenHands
Nous avons exploré plusieurs façons d’installer Devstral en local. Toutefois, toutes ne se valent pas en termes d’efficacité. À travers différents exemples, nous allons maintenant voir comment utiliser Devstral de manière optimale selon la méthode choisie.
Si on reprend notre terminal où nous l'avions laissé après avoir lancé Devstral via Ollama, celui-ci attend un prompt afin de pouvoir nous assister.
Nous commençons avec une demande assez basique d'écriture de javadoc pour une méthode écrite en Java :

Génération de documentation Java avec Devstral dans un terminal
Pour une action simple telle que celle-ci où l'environnement de développement n'a que peu de valeur, la réponse du prompt est plutôt efficace et peut être utilisée directement dans votre projet ou avec très peu d'ajustement.
En second exemple, on va lui passer une méthode assez complexe mais très mal structurée et difficile à maintenir inspirée du kata GildedRose. Voici le prompt ainsi que la méthode passé au prompt :
Refacto le code suivant pour une meilleur lisibilité et maintenabilitépublic void updateQuality() {
        for (int i = 0; i < items.length; i++) {
            if (!items[i].name.equals("Aged Brie")
                    && !items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                if (items[i].quality > 0) {
                    if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                        items[i].quality = items[i].quality - 1;
                    }
                }
            } else {
                if (items[i].quality < 50) {
                    items[i].quality = items[i].quality + 1;
                    if (items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                        if (items[i].sellIn < 11) {
                            if (items[i].quality < 50) {
                                items[i].quality = items[i].quality + 1;
                            }
                        }
                        if (items[i].sellIn < 6) {
                            if (items[i].quality < 50) {
                                items[i].quality = items[i].quality + 1;
                            }
                        }
                    }
                }
            }
            if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                items[i].sellIn = items[i].sellIn - 1;
            }
            if (items[i].sellIn < 0) {
                if (!items[i].name.equals("Aged Brie")) {
                    if (!items[i].name.equals("Backstage passes to a TAFKAL80ETC concert")) {
                        if (items[i].quality > 0) {
                            if (!items[i].name.equals("Sulfuras, Hand of Ragnaros")) {
                                items[i].quality = items[i].quality - 1;
                            }
                        }
                    } else {
                        items[i].quality = items[i].quality - items[i].quality;
                    }
                } else {
                    if (items[i].quality < 50) {
                        items[i].quality = items[i].quality + 1;
                    }
                }
            }
        }
    }Le résultat est le suivant :
public void updateQuality() {
        for (Item item : items) {
            updateItem(item);
        }
    }
    private void updateItem(Item item) {
        if (isSulfuras(item)) {
            return; // Sulfuras does not change
        }
        updateQualityBasedOnName(item);
        updateSellIn(item);
        if (item.sellIn < 0) {
            handleExpiredItem(item);
        }
    }
    private boolean isSulfuras(Item item) {
        return "Sulfuras, Hand of Ragnaros".equals(item.name);
    }
    private void updateQualityBasedOnName(Item item) {
        if ("Aged Brie".equals(item.name)) {
            increaseQuality(item, 1);
        } else if ("Backstage passes to a TAFKAL80ETC concert".equals(item.name)) {
            handleBackstagePasses(item);
        } else {
            decreaseQuality(item, 1);
        }
    }
    private void handleBackstagePasses(Item item) {
        int qualityIncrease = getBackstagePassesQualityIncrease(item.sellIn);
        increaseQuality(item, qualityIncrease);
    }
    private int getBackstagePassesQualityIncrease(int sellIn) {
        if (sellIn < 0) {
            return -item.quality; // Quality drops to 0
        } else if (sellIn < 6) {
            return 3;
        } else if (sellIn < 11) {
            return 2;
        } else {
            return 1;
        }
    }
    private void increaseQuality(Item item, int amount) {
        if (item.quality + amount <= 50) {
            item.quality += amount;
        } else {
            item.quality = 50;
        }
    }
    private void decreaseQuality(Item item, int amount) {
        if (item.quality - amount >= 0) {
            item.quality -= amount;
        } else {
            item.quality = 0;
        }
    }
    private void updateSellIn(Item item) {
        item.sellIn--;
    }
    private void handleExpiredItem(Item item) {
        if ("Aged Brie".equals(item.name)) {
            increaseQuality(item, 1);
        } else if ("Backstage passes to a TAFKAL80ETC concert".equals(item.name)) {
            item.quality = 0;
        } else {
            decreaseQuality(item, 1);
        }
    }
Pour ce second exemple, la réponse fournie est effectivement beaucoup plus lisible et maintenable que la méthode d'origine. En revanche on commence à apercevoir certaines erreurs et notamment sur cette méthode :
 
Erreur lors du refactoring du code GildedRose avec Devstral
Item n'est pas défini donc il y a une incohérence. Sans un vrai environnement à lui fournir, Devstral devient beaucoup moins performant et fait des erreurs qu'une autre IA ne ferait pas forcément en temps normal.
Devstral est avant tout conçu pour fonctionner dans un environnement complet et peut absorber une grande quantité de données afin de proposer la solution adéquate à l’environnement dans lequel il évolue.
Après avoir installé le plugin dans Intellij, lorsque vous effectuez un clic droit sur un texte sélectionné et que vous choisissez "Enhance this with options", plusieurs options seront proposées : meilleure lisibilité, ajout d'un commentaire, réparer un bug, créer un test unitaire, etc..
 
Fenêtre d'options du plugin MyOllamaEnhancer dans IntelliJ
La deuxième possibilité consiste à effectuer un clic droit sur un morceau de texte, puis à choisir l’option "Enhance this with prompt".
Contrairement aux suggestions automatiques, cette action vous permet de formuler manuellement une instruction sur ce que vous souhaitez que Devstral fasse du texte sélectionné.
Cependant, là encore, le potentiel de Devstral reste limité, car l’analyse se fait uniquement sur un fragment isolé de code. Il pourra donc répondre efficacement à des requêtes simples sur du code déjà clair et de complexité modérée, mais ne sera pas en mesure de contextualiser des éléments plus complexes.
C’est la méthode la plus adaptée pour exploiter pleinement les capacités d’un LLM agentique comme Devstral.
En effet, il peut ici scanner l’ensemble du contexte du projet avant d’agir, ce qui lui permet de proposer des réponses beaucoup plus pertinentes et ciblées.
Nous allons explorer cette approche à travers deux cas d’usage :
Dans l’exemple qui suit, j’ai choisi de créer un nouveau projet Java Spring Boot, structuré selon une architecture DDD (Domain-Driven Design), avec un cas concret pour illustrer son fonctionnement.

Création d’un projet Java Spring Boot structuré en DDD avec Devstral. Le volet gauche liste en temps réel les actions exécutées, et le volet droit présente les fichiers modifiés
Une fois votre prompt rédigé, Devstral détaille les différentes étapes qu’il s’apprête à exécuter pour atteindre le résultat attendu.
Vous obtenez ainsi un aperçu clair du processus dans le volet gauche de l’interface. C’est dans cet espace que toutes les actions seront listées en temps réel, ce qui vous permet de suivre précisément chaque étape.
Sur la droite, plusieurs onglets vous permettent d’interagir avec le projet :
Après quelques secondes toutes les actions ont été réalisées par Devstral.
 
Résumé des actions effectuées après une demande de création de projet Java Spring Boot structuré selon une architecture DDD
En examinant de plus près les actions réalisées, on constate que Devstral a automatiquement généré un projet Spring Boot structuré selon les principes du DDD (Domain-Driven Design), avec une arborescence cohérente respectant cette architecture.
Un exemple concret a été mis en place, incluant les entités Client, Order et Product. Pour chacune d'elles, Devstral a également créé les couches applicative, contrôleur et répertoire, permettant une séparation claire des responsabilités.
Par défaut, Devstral a choisi Gradle comme outil de build, mais il aurait tout aussi bien pu utiliser Maven si cela avait été précisé dans le prompt.
Le projet est configuré pour fonctionner avec la dernière version LTS de Java (Java 21).
Enfin, une configuration pour une base de données H2 a été ajoutée, ainsi qu’une suite complète de tests automatisés en Java.
Ces tests valident les interactions entre les différentes entités et simulent un processus d'achat complet. Tous les tests ont été exécutés avec succès, garantissant le bon fonctionnement de l’ensemble.
 
Résumé des différentes étapes d'actions en détail
Afin de pouvoir tester l'application en direct, celle-ci est directement lancée en local afin de tester son bon fonctionnement. Dans mon exemple, le projet est lancé sur le port 50020.
 
Mise à disposition des endpoints utiles de l'application nouvellement créée en local
Pour aller plus loin, nous aurions également pu demander à Devstral de rédiger les tests en Cucumber, afin de mieux refléter les concepts de domaine métier et de renforcer l’alignement avec notre approche orientée DDD.
Il aurait aussi été possible de lui faire :
C’est précisément dans ce type de scénarios que la qualité du prompt devient essentielle : plus votre demande est précise et détaillée, plus Devstral pourra fournir des résultats pertinents, complets et en phase avec vos attentes.
Nous allons maintenant observer comment Devstral se comporte avec un projet existant.
Dans cet exemple, le projet est récupéré depuis GitHub. Pour cela, plusieurs configurations sont disponibles et nécessaires dans OpenHands, accessibles via le bouton Paramètres.

Configuration de Git dans OpenHands
Une fois la configuration terminée, je peux sélectionner la branche que je souhaite récupérer pour effectuer mes actions.
Après sélection, l’interface que nous avons vue précédemment s’affiche, avec le projet entièrement chargé, conservant son fonctionnement habituel.
Dans cet exemple, nous avons choisi un projet complet comprenant :
Ces conditions offrent un cadre idéal pour exploiter pleinement les capacités de Devstral.
Nous avons commencé avec une action plutôt simple comme la génération d'une javadoc complète, sans grande surprise Devstral a été très efficace.
 
Volet d'actions en temps réel

Exemple de documentation générée par Devstral
Pour aller plus loin nous lui demandons de scanner toute la partie frontend du projet afin d'identifier les améliorations possibles.
1. Code Organization and Structure
Routing Module: Create a separate routing module instead of using inline routes in app.routes.ts.
Feature Modules: Consider organizing components into feature modules for better scalability.
2. Error Handling
Global Error Handling: Implement a global error handling mechanism using Angular's ErrorHandler.
User Notifications: Use Angular's MatSnackBar for displaying error messages to users.
3. Form Validation
Enhanced Validation: Add more specific validation rules (minlength, maxlength, pattern) for form fields.
Error Messages: Display validation error messages to users.
4. Styling and Accessibility
Improved Styling: Enhance the styling for better user experience, especially for forms and job lists.
Accessibility: Add ARIA attributes to improve accessibility.
Responsiveness: Ensure the application is responsive and works well on different screen sizes.
5. Performance
Lazy Loading: Implement lazy loading for feature modules.
Bundle Size: Optimize the application's bundle size.
Change Detection: Use onPush change detection strategy where appropriate.
6. Testing
Comprehensive Tests: Ensure all components and services have proper unit tests.
End-to-End Tests: Add end-to-end tests using a tool like Cypress.
Test Coverage: Implement test coverage reporting.
7. API Configuration
Environment Variables: Use environment variables for the API URL in the JobOfferService.
Environment Files: Create different environment files for development, staging, and production.
8. Internationalization (i18n)
i18n Support: Implement i18n support using Angular's i18n tools.
Translations: Extract translatable strings and provide translations for different languages.
9. Security
Input Validation: Implement proper input validation and sanitization to prevent XSS attacks.
HTTPS: Use HTTPS for API calls.
Authentication: Implement authentication and authorization if needed.
10. Documentation
Code Comments: Add comments to explain complex logic in the code.
Application Documentation: Create documentation for the application, including setup instructions, architecture overview, and usage guidelines.Le résumé est plutôt pertinent au vu du code actuel. On va s'attaquer au point numéro 1 car il faut avant tout que le code soit bien structuré et organisé pour la suite. Il est parfois mieux de découper les demandes que l'on va faire à notre IA pour éviter de se retrouver à faire des modifications partout en cas d'une erreur de sa part.
Nous lui demandons donc de restructurer et d'organiser au mieux le code de toute notre partie frontend via le prompt suivant :
Améliore la structure et l’organisation de toute la partie frontend du projet. Regroupe le code en commun et rend le code plus maintenable. 
Résumé des actions réalisées en détail dans le cadre d'une amélioration structurelle et organisationnelle de la partie frontend d'un projet complet

Interface VSCode intégrée à OpenHands listant les fichiers du projet ainsi que les modifications apportées
Le résultat est plus que satisfaisant puisque beaucoup de code a été centralisé et Devstral nous a également corrigé les erreurs qui interviennent à la suite de ces changements. Pour un total de 11 fichiers modifiés, aucune erreur de build à remonter et tous les tests validés, on peut dire que c'est un succès.
"Mais alors avons nous trouvé l'assistant de code parfait ?"
Aujourd'hui de nombreuses entreprises peinent encore à intégrer pleinement des outils d’IA dans leurs processus, c’est souvent en raison de préoccupations légitimes liées à la confidentialité et au partage de données sensibles. Dans ce contexte, Devstral se démarque en offrant la possibilité d’une utilisation entièrement locale, sans nécessité d’accès à Internet. Cette approche garantit que le traitement et l’analyse des données se font en interne, éliminant ainsi les risques liés à la transmission vers des serveurs externes, tout en conservant les avantages d’un modèle de langage puissant et spécialisé.
Celui-ci n’est pas exempt de défauts pour autant, il lui arrive fréquemment de générer du code inutile, ou parfois de produire des solutions trop complexes ou au contraire insuffisantes selon la taille et la nature du projet. Mais il n'est pas le seul responsable puisqu’aujourd'hui la qualité et la précision du prompt restent essentielles pour orienter au mieux l’IA.
Devstral ne se résume pas à une simple intelligence artificielle, il est conçu pour devenir un assistant de développement du quotidien. Cela passe par l'adoption d'une approche itérative de vos tâches mais également de l'utiliser dans un contexte complet et complexe pour en tirer le meilleur apport. Les projets bien fournis (architectures et concepts avancés, configuration CI, microservice, conteneurisation, etc..) sont le terrain de jeu idéal pour Devstral. Bien qu'il ne soit pas parfait, il peut vous permettre de gagner un temps considérable au quotidien.
Mistral a d'ores et déjà annoncé qu'il travaillait sur une version Devstral Large et qu'il serait prochainement disponible.
L’IA évoluant à une vitesse exponentielle, il est aujourd'hui impossible de prédire avec certitude comment les agents de code vont évoluer. Ce qui est certain, c’est qu’ils deviendront de plus en plus performants, et qu’il sera crucial de les intégrer dans des cas d’usage spécifiques pour maximiser les gains en termes de temps et de qualité.
Le futur du code est entre vos mains… et un peu entre celles de Devstral aussi !
 
		
Avec la généralisation de l'expression “Vibe Coding”, une nouvelle ère s’ouvre pour les entreprises pour donner à leurs utilisateurs l'opportunité de créer des applications afin de mieux tester leurs hypothèses avant de lancer des développements lourds et coûteux.
Chez Ippon Technologies, en tant que stagiaire, j’ai eu comme mission d'étudier comment des solutions alimentées par de l’IA peuvent permettre à un individu non-technique de créer ses applications pour résoudre ses problèmes quotidiens et lui permettre d’innover sans avoir recours à des équipes IT.
Dans le cadre de mon stage, je me suis attachée à tester différents outils et différents LLM afin de les comparer, d'identifier leurs limites communes et de déterminer quelles sont les connaissances de base indispensables au “Vibe coding”. Cet article résume mes conclusions et mes conseils.
Le Vibe Coding est avant tout un concept relativement nouveau inventé en 2025 qui s'appuie sur un programme piloté par l'IA afin de convertir les besoins exprimés verbalement par un utilisateur en application exploitable par la machine. Cela permet aux personnes n'ayant pas de compétences en code d'utiliser les solutions existantes pour développer leurs idées d'applications – idéalement, d'accroître l'efficacité et de réduire les coûts en automatisant les processus longs. Malheureusement, la réalité est bien plus complexe, compte tenu des nombreuses limites et de la maturité des outils disponibles. Cependant, au fil de mes expérimentations, avec une courbe d’apprentissage relativement rapide, j'ai pu identifier certaines pratiques qui permettent d'accélérer la création d’application. Les aspects les plus cruciaux à considérer sont :
Afin d’illustrer mes propos, nous allons mettre en place ces éléments en créant un jeu de pêche sous-marine, « Coral City Racers ». Cette application fut un fil rouge tout au long de mon stage. Le but d’un point de vue technique était de mettre en place des éléments d’interface, un système d'autorisation ainsi que la persistance du résultat des différentes courses pour pouvoir rejouer et améliorer son classement global.
Afin de se mettre dans la peau de personnes non techniques, je n’ai pas cherché à influencer les choix de langage de programmation ou le choix d’un framework particulier. Mon approche a été uniquement d’utiliser des termes issus de tous les jours.
Le but de l’application « Coral City Racers » est simple : une course en 2D, où il faut essayer de finir le plus rapidement possible en évitant les obstacles et ainsi participer au score global. Le fait d’utiliser un jeu pour illustrer mes propos permet de mieux illustrer les difficultés rencontrées.
Après plusieurs essais, je me suis très vite rendue compte d’un certain nombre de limitations.
Le "prompt engineering" est essentiel pour obtenir le produit souhaité à partir des IA génératives. Sans cette maîtrise, les résultats sont souvent imprécis, entraînant une perte de temps et d'argent. Des problèmes courants incluent le temps passé à combler les lacunes et la surconsommation de tokens.
Pour améliorer les prompts, suivez la structure :
Une fois votre sujet perfectionné, le facteur le plus important est le choix de la solution. Afin d'évaluer équitablement les résultats de mes expériences, j'ai toujours testé mes sujets avec plusieurs solutions et j’ai mis en place une grille de lecture pour les comparer (table 1). Afin de les évaluer de la façon la plus objective possible, j’ai utilisé les mêmes prompts à chaque fois en prenant compte de mes erreurs.
Table 1 :
| 1 - Non satisfaisant | 2 - Besoin d'amélioration | 3 - Satisfaisant | 4 - Bon | 5 - Excellent | |
|---|---|---|---|---|---|
| A - Utilisation | Le produit n'a pas pu être fabriqué par LLM | La production du produit s'est avérée complexe et a nécessité de nombreuses tentatives et modifications du modèle initial. Le LLM était difficile à manipuler et manquait d'instructions claires. | Le produit a été réalisé du premier coup, mais l'utilisation de LLM n'était pas intuitive, mais des instructions claires ont été fournies | Le produit a été réalisé du premier coup et LLM était assez simple à parcourir | Le produit a été réalisé du premier coup et l'utilisation de LLM était extrêmement claire | 
| B - Rapidité | Le LLM a souvent rencontré des pannes de système qui ont entravé la production des produits | Le LLM traitait les informations très lentement et la sortie était parfois obstruée par des pannes du système | Le LLM a traité les informations lentement, mais de rares pannes système se sont produites | Le LLM a traité les informations dans un délai acceptable et aucune panne du système ne s'est produite. | Le LLM a traité les informations rapidement et aucune panne du système n'a eu lieu | 
| C - Précision | Le produit différait/ne contenait pas beaucoup d'éléments essentiels par rapport à ce qui était demandé dans le prompt initial | Le produit différait/ne contenait pas un aspect crucial de l'invite | Le produit différait/ne contenait pas beaucoup d'aspects banals de l'invite | Le produit différait/ne contenait pas une petite quantité d'aspects banals de l'invite | Le produit contenait exactement ce qui était demandé par le client. | 
| D - Qualité visuelle | Le produit avait une qualité visuelle extrêmement faible et manquait de profondeur cruciale pour le contexte de l'application. | Le produit avait une faible qualité visuelle et le contexte est difficile à déduire | Le produit avait une qualité visuelle satisfaisante et le contexte du jeu restait évident | Le produit avait une bonne qualité visuelle et le contexte du jeu est évident | Le produit a une excellente qualité visuelle et le contexte du jeu est évident | 
| E - Jouabilité | Le produit n'était pas utilisable | Le produit était techniquement utilisable mais de nombreux aspects cruciaux manquaient ou manquaient de fluidité. | Le produit était utilisable mais des détails manquaient et la fluidité pourrait être améliorée | Le produit était utilisable et seuls quelques petits détails manquaient | Le produit était utilisable et aucun détail ne manquait | 
Table 2 : Résultat en prompt - solution pure LLM
| A - Utilisation | B - Rapidité | C - Précision | D - Qualité visuelle | E - Jouabilité | Score total | |
|---|---|---|---|---|---|---|
| Deep Seek R1 | 5 | 2 | 3 | 3 | 3 | 16 | 
| Gemini 2.5 | 5 | 5 | 4 | 3 | 4 | 21 | 
| Firebase Studios (emini Flash 2.0) | 5 | 4 | 2 | 2 | 2 | 15 | 
| Claude Sonnet 3.7 | 5 | 4 | 2 | 4 | 2 | 17 | 
| Résultat par Google AI Studios | Résultat en utilisant Claude | 
Table 3 : Résultat après ajustement en mode discussion
| A - Utilisation | B - Rapidité | C - Précision | D - Qualité visuelle | E - Jouabilité | Score total | |
|---|---|---|---|---|---|---|
| DeepSeek | 5 | 3 | 4 | 4 | 4 | 20 | 
| Google AI Studios* | 5 | 4 | 4 | 3 | 1 | 17 | 
| Firebase Studios | 5 | 4 | 2 | 4 | 2 | 17 | 
| Claude | 5 | 4 | 4 | 4 | 5 | 22 | 
J'ai découvert par exemple que Google AI Studios a eu la meilleure performance lorsqu'on lui a donné l'invite brute, mais une fois cette invite améliorée, Claude donne un rendu plus satisfaisant. Ces 2 outils ont obtenu d'excellentes notes car ils ont permis de maintenir un temps de traitement rapide tout en préservant un résultat qualitatif, plus respectueux des délais que les autres LLM.
J'ai ensuite approfondi mes recherches en testant des solutions spécialisées dans la création d'applications sur le web en utilisant la genIA. Je souhaitais élargir mon champ d'investigation, passant des outils courants, comme ceux créés par Google, à des outils indépendants, parfois même dotés de leurs propres LLM. À l'aide de Bolt.new et de version0, j'ai analysé et comparé leurs forces et leurs limites de telles solutions, ainsi que leurs versions gratuites et payantes par abonnements.
Table 4 : Comparaison des solutions gratuites vs payantes et des plateformes
| Aspect | Solution gratuite | Solution payante Bolt Pro (~20$) | Solution payante v0 Premium (~20$) | 
|---|---|---|---|
| Points forts | ✓ Accessible à tous ✓ Utile pour un travail quotidien limité ✓ Navigation simple et claire ✓ Instructions détaillées fournies | ✓ Capacité de tokens beaucoup plus grande ✓ Fonctionnalités externes avancées ✓ Configuration Firebase (classements, profils, authentification) ✓ Système d'amis (codes d'accès, demandes, classements) | ✓ ~20$ de crédits mensuels inclus ✓ Limite de taille de pièce jointe 5x plus élevée ✓ Import depuis Figma ✓ Accès à v0-1.5-lg ✓ Accès à l'API v0 | 
| Limites | ✗ Capacité d'entrée quotidienne limitée ✗ Consommation rapide des tokens ✗ Analyse superficielle des réponses | ✗ Plus de tokens n'impliquent pas nécessairement plus de possibilités ✗ Saturation serveur après ajout de fonctionnalités ✗ Problèmes récurrents (IA qui s'arrête, chronomètre défaillant, victoire non enregistrée) | ✗ Ne remplit pas certains aspects visuels automatiquement ✗ Difficile d'obtenir le résultat souhaité ✗ Bugs fréquents rendant le jeu injouable ✗ Produit uniquement des pistes carrées basiques | 
| Critiques sur l'accessibilité | ✓ Navigation simple et claire ✗ Bot n'effectue pas toutes les actions automatiquement ✗ Compétence technique requise mais étapes détaillées fournies ✗ Nécessité de version pro dépend du contexte | ✓ Configuration simple et réussie des fonctionnalités Firebase ✗ Problèmes de boucle de jeu et détection de collision ✗ Serveur saturé après modifications | ✓ Manque d'autonomie mais plus d'espace de personnalisation ✗ Fonction "conception" disponible mais résultats erronés ✗ Utilisation incorrecte des images téléchargées | 
| Recommandations | ✓ Planifier les entrées avec le moins d'ambiguïté possible ✓ Éviter les ajustements multiples pour réduire le gaspillage de tokens | ✓ Effacer et relancer le serveur après ajout de fonctionnalités ✓ Se concentrer sur le perfectionnement de la base avant d'ajouter des fonctionnalités ✓ Gérer la saturation serveur | ✓ Utiliser les crédits mensuels inclus efficacement ✓ Profiter des fonctionnalités premium (API, import Figma) ✓ Comprendre les limitations de l'outil | 
| Expérience personnelle | ✗ Utilisation rapide des tokens gratuits ✗ Manque d'analyse approfondie des réponses rapides ✗ Problèmes de sursaturation après ajout de fonctionnalités externes | ✗ Problèmes de sursaturation après modifications ✗ IA incapable de résoudre certains bugs techniques ✗ Fonctionnalités avancées mais instables | ✗ Résultats visuels limités et parfois incorrects ✗ Personnalisation possible mais complexe ✗ Accès premium étendu mais utilisation limitée pour non-programmeurs | 
| Conclusion | ✓ L'abonnement vaut son prix selon : ✓ Fréquence d'utilisation ✓ Nature du projet (personnel/professionnel) ✓ Complexité de l'application ✓ Contraintes de délai | ✓ Solution complète mais instable ✓ Idéal pour projets complexes avec intégrations externes ✓ Nécessite une gestion attentive des ressources serveur | ✓ Outil premium avec fonctionnalités étendues ✓ Plus adapté aux développeurs expérimentés ✓ Limites inhérentes à la plateforme | 
Captures d'écrans de la solution finale
Remarques importantes :
Comment optimiser ses tokens ?
Logique de développement de l’application :
Ce que j’ai appris en partageant avec mes collègues et que je conseillerais à mettre en oeuvre :
Une fois que vous avez choisi votre outil, une version payante sera nécessaire dans la plupart des cas (surtout si vous voulez partager votre application et pouvoir plus ou moins facilement faire des évolutions).
Quelle que soit l'attention portée par un concepteur d'applications aux bonnes pratiques à suivre pour optimiser l'utilisation d'une solution, certaines limites sont inévitables :
Au cours de cette mission, j’ai donc pu voir et creuser davantage comment fonctionne une solution de vibe coding ainsi que les limitations. Grâce aux conseils de mes collègues développeurs, j’ai pu mettre en place une méthodologie qui m’a permis de générer des applications plus rapidement tout en contrôlant davantage la consommation de token (plus on consomme, plus ça tourne en rond). Sans leur support ni leur approche structurelle, j’aurais perdu beaucoup de temps et d'énergie - voire je doute d'être arrivé à ce résultat final.
Si les solutions de marche aujourd’hui semblent magiques à première vue, je trouve que l’on se retrouve très vite coincés et qu’une aide un peu plus technique est nécessaire pour sortir de l’impasse. Les outils SAAS restent des boîtes noires qui certe facilitent pleins de choses - mais dont on contrôle très peu :
En guise de proof of concept, j'ai ensuite appliqué la même méthode pour la création d'une application web de scraping de documentation API - avec le résultat suivant :

En moins de 2 jours, j'ai pu mettre une application déployable sur internet qui savait télécharger la documentation technique, le remettre en forme pour être lisible par un utilisateur lambda et la rendre téléchargeable sous plusieurs formats. L'application permettait aussi de gérer les erreurs en informant l'utilisateur des possibles actions à mener.
"Game Design Document: Coral City RacersStudio: AquaPlay StudiosTarget Audience: Children, Ages 6-10Platform: Web Browser (PC/Mac)
Monetization: None (Premium, or Free with no ads/IAPs)
Logline : A vibrant and cheerful 2D underwater racing game where kids race as customizable fish through beautiful ocean landscapes, mastering precision control to stay on the path, out-swim a rival, and dodge grumpy sharks.
Core Pillars :
The player's journey is designed to be simple and seamless.
 
		
L'intelligence artificielle transforme la cybersécurité dans le cloud en 2025. Avec 44% des entreprises victimes de violations de données cloud et plus de 200 alertes quotidiennes à traiter, les équipes sécurité font face à un défi inédit. L'IA aide à répondre à cette équation en automatisant la détection comportementale et en réduisant jusqu’à 85% les faux positifs.
Les organisations migrant vers AWS découvrent rapidement un paradoxe troublant : plus elles adoptent de services cloud, plus le volume de données de sécurité explose, tandis que le temps pour réagir aux menaces se réduit.
Ce schéma représente l’organisation et l’interconnexion des principaux services AWS (EventBridge, SageMaker, Lambda) qui collaborent pour collecter, analyser et répondre automatiquement aux menaces via l’IA.

Dans un environnement AWS typique, CloudTrail génère des milliers d'événements par heure, CloudWatch collecte des centaines de métriques, et les VPC Flow Logs capturent chaque paquet réseau. Cette richesse d'informations devient rapidement ingérable avec les approches traditionnelles.
Les systèmes de règles statiques montrent leurs limites. Une règle comme "alerte après 5 tentatives de connexion échouées" ne distingue pas un développeur légitime qui a oublié son mot de passe d'un attaquant sophistiqué. Le résultat : une avalanche de faux positifs qui noient les vraies menaces.
Cette approche binaire ignore le contexte métier, les patterns comportementaux historiques et les corrélations entre événements. Elle traite chaque alerte isolément, sans comprendre qu'une tentative de connexion suspecte, un accès inhabituel à un bucket S3 et une modification IAM peuvent faire partie du même scénario d'attaque.
L'IA révolutionne cette approche en introduisant l'analyse comportementale contextuelle. Plutôt que des règles rigides, elle apprend continuellement des patterns normaux pour identifier les anomalies significatives.
Le processus débute par une phase d'apprentissage où l'IA analyse l'historique des activités légitimes. Elle identifie qui se connecte habituellement quand, d'où, avec quels patterns d'utilisation des services AWS. Elle comprend les cycles métier, les pics d'activité normaux, les corrélations entre systèmes.
Cette baseline devient la référence pour détecter les déviations. Quand un utilisateur accède depuis un pays inhabituel à 3h du matin, l'IA analyse le contexte : voyage-t-il fréquemment ? Son équipe travaille-t-elle sur un projet international ? Les services accédés correspondent-ils à ses responsabilités ?
Cette approche contextuelle calcule un score de risque nuancé (entre 0 et 1) plutôt qu'un simple "alerte/pas d'alerte". Un score de 0.3 indique une activité légèrement inhabituelle nécessitant une surveillance renforcée, tandis qu'un score de 0.9 déclenche une investigation immédiate.
Ce schéma détaille le flux opérationnel automatisé depuis la détection d’un événement critique jusqu’à la prise de décision et l’activation des actions de réponse adéquates, illustrant le processus métier que l’IA orchestre pour sécuriser l’environnement AWS.

L'implémentation s'articule autour de trois composants qui s'intègrent dans l'écosystème AWS existant.
Premier composant : Collecte intelligente Amazon EventBridge capture en temps réel les événements de CloudTrail, GuardDuty, Security Hub et VPC Flow Logs, en appliquant des filtres intelligents pour router différents types d'événements selon leur criticité.
resource "aws_cloudwatch_event_rule" "security_intelligence" {
  name = "ai-threat-detection"
  
  event_pattern = jsonencode({
    source = ["aws.guardduty", "aws.securityhub", "aws.cloudtrail"]
    detail-type = ["GuardDuty Finding", "Security Hub Findings"]
  })
}
Deuxième composant : Analyse IA Amazon SageMaker héberge des modèles de machine learning spécialisés dans la détection d'anomalies. L'algorithme Isolation Forest analyse les patterns d'utilisation pour identifier les comportements suspects.
class CloudSecurityAI:
    def __init__(self):
        self.isolation_forest = IsolationForest(contamination=0.1)
        
    def analyze_user_behavior(self, cloudtrail_events):
        features = self.extract_behavioral_features(cloudtrail_events)
        anomaly_scores = self.isolation_forest.decision_function(features)
        
        return {
            'threat_level': self.calculate_risk_score(anomaly_scores),
            'suspicious_patterns': self.identify_attack_vectors(features),
            'recommended_actions': self.generate_response_strategy(anomaly_scores)
        }
Troisième composant : Réponse automatisée AWS Lambda orchestre les actions selon le niveau de risque. Pour une menace critique (score > 0.8), isolation automatique de la ressource. Pour une menace modérée (0.5-0.8), monitoring renforcé et investigation. Pour une activité inhabituelle (<0.5), enrichissement des logs.
Amazon GuardDuty utilise déjà le machine learning pour identifier les activités malveillantes en analysant des téraoctets de données en temps réel. Sa nouveauté : l'analyse du trafic réseau des fonctions Lambda et la détection d'activités de cryptominage.
AWS Security Hub agit comme cerveau central, agrégeant et corrélant les findings multiples. Son IA excelle dans la réduction du bruit en regroupant automatiquement les alertes connexes et en calculant des scores de priorité contextuels.
Amazon Macie utilise l'IA pour découvrir et protéger automatiquement les données sensibles. Au-delà de la reconnaissance de formats, Macie comprend le contexte métier et détecte les fuites subtiles comme l'accès inhabituel à des documents confidentiels.
L'implémentation suit trois phases pour minimiser les risques de perturbation.
Phase 1 : Baseline (2-4 semaines) Établissement de la baseline comportementale sans actions automatiques. L'IA apprend les patterns normaux incluant différents cycles métier.
Phase 2 : Détection passive L'IA génère des scores de risque sans déclencher d'actions automatiques. Objectif : moins de 15% de faux positifs avant l'automatisation.
Phase 3 : Automatisation graduée Activation des réponses automatiques pour les scénarios critiques, supervision humaine maintenue pour les cas complexes.
Le succès se mesure par trois indicateurs clés :
Temps moyen de détection (MTTD) : réduction typique de 4 heures à 15 minutes pour les menaces critiques.
Réduction des faux positifs : passage de 85% à 12%, transformant l'expérience des équipes sécurité.
Automatisation des réponses : 80% des incidents de niveau 1 traités automatiquement.
def calculate_security_metrics():
    detection_metrics = {
        'mean_time_to_detection': calculate_mttd(),
          'false_positive_rate': calculate_false_positive_ratio(),
        'automated_response_rate': calculate_automation_percentage()
    }
    
    # Publication vers CloudWatch
    for metric_name, value in detection_metrics.items():
        cloudwatch.put_metric_data(
            Namespace='Security/AI',
            MetricData=[{'MetricName': metric_name, 'Value': value}]
        )
L'évolution ne s'arrête pas à la détection. L'IA générative transforme l'investigation d'incidents en automatisant la génération de rapports détaillés et de recommandations. La prédiction de menaces permet d'anticiper les vecteurs d'attaque probables et de suggérer des mesures préventives.
L'objectif : une sécurité autonome gérant les incidents de routine tout en apprenant continuellement, avec maintien de l'expertise humaine pour les cas complexes.
L'automatisation intelligente, optimisée par l'IA, renforce considérablement la sécurité cloud en agissant comme un multiplicateur d'expertise humaine. L'IA analyse des volumes massifs de données et détecte des modèles complexes, permettant aux experts de se concentrer sur des tâches critiques. Cette synergie entre l'IA et l'humain marque une nouvelle ère pour la sécurité, où la technologie décuple les capacités d'analyse sans compromettre la prise de décision. Investir dans l'IA pour la sécurité offre un avantage concurrentiel durable, protégeant les actifs numériques et favorisant l'agilité nécessaire à la transformation digitale.
Documentation AWS officielle :
 
		Si vous cherchez à construire une application de traduction ou de dictionnaire, votre principal souci sera d’avoir des données de qualité. Ajoutons en contraintes le fait que certaines langues sont à déclinaisons. Les personnes qui auront fait du latin ou de l’allemand reconnaîtront ce terme.
Dans une langue à déclinaisons, les mots changent de forme selon leur rôle grammatical dans la phrase. En albanais, il y a 5 cas grammaticaux : Nominatif (Sujet), Accusatif (COD), Datif (COI), Génitif (Indique la possession, souvent le complément du nom), Ablatif (Souvent utilisé avec des prépositions qui indiquent une origine).
Pourquoi l’albanais ? Parce que je développe justement une application mobile qui doit m’aider à déterminer les déclinaisons d’un mot albanais !
Autre particularité de cette langue : un mot se décline selon son rôle grammatical, mais aussi son nombre (singulier ou pluriel) et son caractère défini ou indéfini (le chien ou un chien). Un même mot a donc 20 déclinaisons possibles.
Pour illustrer, voici les déclinaisons du mot makinë (voiture) :
| singulier (numri njёjёs) | pluriel (numri shumёs) | |||
|---|---|---|---|---|
| forme indéfinie (trajta të pashquara) | forme définie (trajta të shquara) | forme indéfinie (trajta të pashquara) | forme définie (trajta të shquara) | |
| nominatif (emërore) | (një) makinë | makina | (disa) makina | makinat | 
| accusatif (kallëzore) | (një) makinë | makinën | (disa) makina | makinat | 
| génitif (gjinore)(i/e/të/së) | (një) makine | makinës | (disa) makinave | makinavet | 
| datif (dhanore) | (një) makine | makinës | (disa) makinave | makinavet | 
| ablatif (rrjedhore) (prej) | (një) makine | makinës | (disa) makinash | makinavet | 
Ce qui compte pour apprendre les déclinaisons en albanais, c’est de savoir la forme que prend le mot au nominatif pour chaque nombre et pour chaque caractère défini ou indéfini :
En effet, même si les déclinaisons sont en général régulières, il existe des mots qui sont irréguliers. Certains dictionnaires fournissent donc une description des formes au nominatif du mot recherché.
Par exemple, sur fjalorthi.com, voici le résultat obtenu en recherchant makinë :

Ici, makin est le radical du mot, avec successivement :
La complexité pour cette langue, qui est finalement assez peu parlée (environ 8 millions de locuteurs dans le monde), est d’avoir de la donnée libre de droit, gratuite et de qualité. C’est donc compliqué de savoir si un mot que vous écrivez est correct. D’ailleurs, comment les logiciels comme LibreOffice font-ils pour vérifier le format de ce qui est écrit ?
Hunspell est un spell checker. Littéralement, il vérifie comment un mot est épelé. C’est justement l’outil utilisé dans LibreOffice et dans nombre d'autres logiciels pour faire le spell checking (Firefox, Thunderbird, macOS, Opera…). Il s’agit de la troisième génération de spell checkers. Hunspell se base sur MySpell, lui-même basé sur ASpell et ISpell.
Hunspell s’installe facilement avec apt sur Linux ou avec brew pour MacOS. Vous pouvez aussi télécharger et compiler les sources si jamais ces méthodes ne vous conviennent pas. L’exemple sera sur MacOS.
brew install hunspell
Pour vérifier que l’installation s’est bien déroulée. Exécutez la commande suivante :
hunspell -v
Vous devriez avoir un résultat comme celui-ci (notez qu’Ispell et Myspell sont mis en avant) :
@(#) International Ispell Version 3.2.06 (but really Hunspell 1.7.2)
Copyright (C) 2002-2022 László Németh. License: MPL/GPL/LGPL.
Based on OpenOffice.org's Myspell library.
Myspell's copyright (C) Kevin Hendricks, 2001-2002, License: BSD.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, 
to the extent permitted by law.
Pour changer l’encodage de Hunspell, passez -i en argument. Par exemple :
hunspell -d sq_AL -i UTF-8
-d spécifie le dictionnaire à utiliser. Dans l’exemple ci-dessus, nous utilisons l’albanais. SQ est l’abréviation de Shqip, qui veut dire Albanais en Albanais.
Il y a de fortes chances que l’exécution de la commande ci-dessus produise cette erreur :
Can't open affix or dictionary files for dictionary named "sq_AL".
Cela signifie que Hunspell n’a pas le dictionnaire correspondant à l’entrée demandée (sq_AL). Dans ce cas, il faut en télécharger un. Hunspell travaille avec un couple de fichiers .dic et .aff qui ont des rôles bien définis.
Un fichier .dic liste ses mots un par un, avec un saut de ligne entre chaque :
ënjtur/LK
ënjtura/Z
ënjture
*ënjturëtet
Des caractères spéciaux sont aussi insérés. Le slash indique qu’une ou plusieurs règles sont définies dans le fichier .aff et s’appliquent à ce mot. Pour ënjtur, il s’agit de la règle L et de la règle K. Pour ënjtura, il s’agit de la règle Z. L’astérisque en préfixe indique un mot interdit dans le dictionnaire.
En regardant dans le fichier .aff pour chercher la règle Z, voici ce qu’on observe :
PFX Z Y 1
PFX Z   0    ç'           .
Cela signifie :
Transformation : 0 ç’.
Donc, /Z indique à Hunspell “Génère une forme supplémentaire du mot précédée de ç’”
Par exemple :
Les règles sont nombreuses et le manpage de hunspell bien fourni. Je vous invite à lire le reste ! Finalement, ce double format plutôt malin de sources permet à partir de fichiers relativement petits de générer beaucoup de mots.
Ces fichiers sont disponibles à plusieurs endroits en ligne. Dans mon cas, j’ai choisi de télécharger le dictionnaire MySpell mis à disposition par Shkenca ici :
https://www.shkenca.org/k6i/albanian_dictionary_for_myspell_en.html
C’est une organisation qui met en ligne de nombreuses ressources sur la langue albanaise, dont un dictionnaire en ligne et ce fichier. Hunspell est bien compatible avec MySpell.
C’est un zip. Décompressez-le dans un répertoire de travail. Commencez par faire attention à l’encodage des fichiers .dic et .aff. Par défaut, Hunspell travaille en UTF-8 mais les fichiers sont régulièrement dans un autre encodage. Dans ce cas, ou vous changez l’encodage des fichiers, ou vous spécifiez en option de Hunspell l’encodage à utiliser.
Attention cependant, le fichier .aff spécifie l’encodage à utiliser en début de fichier via l’instruction SET <encoding>.
Il faut que l’ensemble soit cohérent :
Lorsque c’est fait, spécifiez le chemin des dictionnaires .dic et .aff. Il faut que le nom du fichier soit le même et que seule l’extension change. Pour des fichiers nommés sq_AL.dic et sq_AL.aff, voici la commande correspondante :
hunspell -d <path>/sq_AL -i utf8
Si tout se passe bien, l’interpréteur se lance :
Hunspell 1.7.2
À partir de là, vous pouvez soumettre vos mots albanais et voir ce que Hunspell va vous répondre. Essayez avec makinë :
makinë
*
L’astérisque signifie que le mot est valide pour Hunspell.
Essayez maintenant une déclinaison du mot qui n’existe pas :
makino
& makino 3 0: makine, makina, makinë
Ici, Hunspell indique qu’il y a une erreur dans la saisie et suggère 3 mots comme correction (d’où le chiffre 3 dans 3 0). Le chiffre 0 spécifie l’index dans la ligne du premier caractère du mot en erreur.
Essayons avec plusieurs mots. Pour tridhjetë e pesë makino (35 voitures) :
tridhjetë e pesë makino
*
*
*
& makino 3 17: makine, makina, makinë
Nous avons trois astérisques. Ils valident les 3 premiers mots. Le dernier mot est en erreur.
Hunspell ne vérifie pas la bonne exécution des règles de grammaire. Il vérifie uniquement que les mots saisis existent en calculant un certain nombre de règles. Par exemple, si on lui soumet un équivalent albanais grammaticalement faux de “Ma voiture”...
makinë ime
*
*
…Hunspell considère que c’est valide, alors que makinë correspond au nominatif indéfini et ime au nominatif défini.
La version correcte serait makina ime :
makina ime
*
*
Attention alors à bien mesurer pour quel travail vous utilisez cet outil. Un correcteur orthographique mot à mot oui, mais il n’y aura pas de vérification de cohérence sur toute une phrase.
Dernier regret : il n’est pas possible de créer un dictionnaire “classique” à partir de dictionnaires construits pour Hunspell. L’open data sur l’albanais manquant un peu, ça aurait pu s’avérer très utile.
Connaître comment fonctionne Hunspell permet de comprendre comment fonctionnent certains correcteurs orthographiques, que ce soit pour leurs avantages et pour leurs limitations. Attention à bien le configurer et à maîtriser les objectifs recherchés. Malgré tout, c’est un super outil du monde opensource, dont le code et les dictionnaires sont maintenus de manière communautaire sur Weblate.
Il existe des implémentations dans beaucoup de langages de bibliothèques qui utilisent Hunspell. Pensez par exemple à Pyspell en Python !
 
		
Nous remercions Victor Barrau, notre collaborateur avec qui nous avons écrit cet article.
Dans un contexte où l'industrialisation des modèles de machine learning devient critique pour les entreprises, AWS SageMaker Batch Transform se présente comme une solution robuste pour le traitement par lots des inférences. Cet article explore comment adapter un modèle externe (BYOC - Bring Your Own Container) à SageMaker Batch Transform et pourquoi cette approche peut être pertinente pour votre cas d'usage.
Le choix du traitement par batch plutôt que du temps réel repose sur plusieurs considérations stratégiques :
Le traitement par batch est pertinent pour des tâches comme l’inférence sur un grand jeu de données en une seule exécution, l’analyse d’images ou de documents en masse, ou encore la classification de contenus. Ces cas d’usage ne nécessitent pas une réponse instantanée, car les résultats peuvent être exploités après coup sans impacter directement l’expérience utilisateur ou le processus métier en temps réel.
AWS SageMaker est une plateforme managée qui propose un ensemble de services pour le développement, l'entraînement et le déploiement de modèles de machine learning. Cette approche managée délègue la gestion des infrastructures à AWS, permettant aux équipes de se concentrer sur le développement des modèles plutôt que sur l'orchestration des ressources.
La plateforme offre une intégration native avec l'écosystème Python et les frameworks ML courants (TensorFlow, PyTorch, Scikit-Learn). SageMaker couvre différentes étapes du cycle de vie ML à travers des services modulaires : développement interactif (Studio, Data Wrangler), entraînement (Training distribué, AutoML) et déploiement (Batch Transform, Endpoints, Pipelines, Model Monitor).
Cette approche modulaire permet aux équipes d'adopter uniquement les services nécessaires à leur projet. L'intégration avec les autres services AWS (S3, IAM, CloudWatch, Lambda) facilite l'intégration dans un écosystème existant.
Cependant, cette approche présente certaines contraintes :
Le choix de SageMaker dépend donc du contexte : taille de l'équipe, expertise DevOps disponible, contraintes budgétaires et besoins de scalabilité.
Par exemple, les équipes disposant d'une forte expertise Kubernetes préféreront souvent Kubeflow pour sa portabilité multi-cloud et la maîtrise complète de l'orchestration.
De même, les projets nécessitant un contrôle fin de l'infrastructure, comme le debugging avancé des modèles ou l'implémentation d'optimisations système spécifiques, trouveront les abstractions de SageMaker limitantes. Dans ces cas, une approche custom sur EC2 ou Kubernetes offre la granularité nécessaire, même si elle implique une charge opérationnelle plus importante.
Enfin, les contraintes de souveraineté des données peuvent rendre SageMaker inadapté lorsque l'hébergement doit se faire dans des datacenters spécifiques ou sous certaines juridictions.
Bien que SageMaker Batch Transform soit une solution robuste, d'autres approches méritent considération selon le contexte et les contraintes spécifiques du projet.
AWS Batch avec Step Functions constitue une alternative pour les équipes recherchant un contrôle sur l'infrastructure tout en conservant les bénéfices d'un service managé. Cependant, elle demande une expertise plus poussée en configuration AWS et peut présenter des temps de démarrage à froid impactant les performances pour des tâches courtes.
ECS avec Step Functions s’adresse aux équipes techniques privilégiant la flexibilité maximale. Cette architecture permet un paramétrage fin des ressources et des stratégies d'auto-scaling. La contrepartie réside dans une complexité opérationnelle significative et des coûts potentiellement plus élevés sans un monitoring rigoureux.
Amazon EKS (Elastic Kubernetes Service) représente une option intéressante pour les équipes déjà familiarisées avec l'écosystème Kubernetes. Cette approche offre une portabilité multi-cloud et permet d'exploiter des outils spécialisés comme Kubeflow pour les workflows ML. EKS convient particulièrement aux organisations ayant une stratégie container-first ou souhaitant maintenir une cohérence technologique avec leurs autres applications. Cependant, cette solution nécessite une expertise Kubernetes solide et implique une charge opérationnelle plus importante que les services managés.
Le choix optimal dépend de plusieurs facteurs : la maturité de l'équipe, les contraintes budgétaires et la stratégie cloud de l'organisation. SageMaker reste pertinent pour les équipes privilégiant la rapidité de mise en œuvre et l'intégration native avec l'écosystème AWS, tandis que les alternatives offrent plus de contrôle au prix d'une complexité accrue.
Si SageMaker Batch Transform est principalement conçu pour l'inférence par lots, son utilisation peut être étendue à d'autres cas d'usages stratégiques dans le cycle de vie des modèles de machine learning. Cette section explore les applications pratiques de Batch Transform au-delà de son utilisation conventionnelle.
Même si l'entraînement classique se fait généralement via des jobs dédiés, Batch Transform offre des atouts significatifs pour la phase de validation et d'expérimentation. Cette approche permet de couvrir une multitude d'actions nécessaires pour la mise en production :
Un modèle Sagemaker est capable d’exécuter un ou plusieurs modèles de machine learning. Pour créer un modèle Sagemaker, il est nécessaire de fournir une image de conteneur qui sera utilisée pour effectuer les inférences. Cette image est appelée image primaire. Des images secondaires peuvent également être fournies au modèle si nécessaire.
Supposons que nous disposons d’un modèle de machine learning entraîné hors de Sagemaker (approche BYOC) et possédant des fichiers de poids (dans le cadre du transfert learning par exemple). Pour importer ce modèle dans Sagemaker afin de l’utiliser pour effectuer des inférences, il faut que ce modèle soit partie intégrante d’un modèle Sagemaker.
Pour ce faire, il faut procéder comme suit :

Sagemaker propose un large éventail d’instances pour la réalisation d’inférences. Le choix du type d’instance approprié à vos besoins dépend des performances que vous souhaitez atteindre et de votre budget. Optimiser les inférences nécessite d’effectuer des tests de charge sur différents types d’instances et avec différentes configurations telles que l’exécution de tâches sur une seule instance ou la parallélisation de tâches sur plusieurs instances.
Dans le cas d’une tâche Batch Transform, il est possible d’optimiser l’inférence en modifiant dans la configuration de lancement de la tâche les valeurs par défaut de certains paramètres tels que MaxConcurrentTransforms, BatchStrategy, et MaxPayloadInMB. Si aucune valeur n’a été renseignée pour ces paramètres, avant d’utiliser leurs valeurs par défaut, SageMaker enverra une requête HTTP GET à l'instance lorsqu’elle démarrera, sur le point de terminaison /execution-parameters (si vous l’avez implémenté dans le modèle).
| Paramètre | Description | Valeur par défaut | 
| MaxConcurrentTransforms | Nombre maximal de requêtes pouvant être envoyées en parallèle à chaque instance dans une tâche. Si la valeur n’est pas définie ou est égale à 0 et que le point de terminaison / execution-parameters n’a pas été implémenté dans le modèle, la valeur par défaut sera utilisée. | 1 | 
| BatchStrategy | Stratégie à utiliser pour les enregistrements. Un enregistrement correspond à une unité de données d'entrée (par exemple une ligne dans un fichier CSV) sur laquelle une inférence peut être réalisée. Pour n'utiliser qu'un seul enregistrement par requête d’inférence, spécifiez la configuration suivante : 
 Pour inclure dans chaque requête d’inférence autant d'enregistrements que la limite MaxPayloadInMB le permet, utilisez la configuration suivante : 
 | MULTI_RECORD | 
| MaxPayloadInMB | Taille maximale (en Mo) autorisée pour la charge utile. La charge utile correspond aux données d'un enregistrement, sans les métadonnées. La valeur de MaxPayloadInMB doit être supérieure ou égale à la taille d'un enregistrement. Pour estimer la taille d'un enregistrement en Mo, il suffit de diviser la taille de votre jeu de données par le nombre d'enregistrements. Afin de garantir que les enregistrements respectent la taille maximale de la charge utile, AWS recommande d'utiliser une valeur légèrement supérieure. La valeur maximale de MaxPayloadInMB est de 100 Mo. Si le paramètre MaxConcurrentTransforms est spécifié, la valeur de MaxConcurrentTransforms x MaxPayloadInMB ne peut pas non plus dépasser 100 Mo. | 6 | 
La première étape consiste à tester votre modèle sur une instance de base (ml.m5.large par exemple) avec les paramètres par défaut. Cette baseline vous permettra d'évaluer l'impact des optimisations suivantes.
Testez ensuite différentes configurations en ne modifiant qu'un paramètre à la fois. Par exemple, augmentez progressivement MaxConcurrentTransforms de 1 à 4, puis testez différentes valeurs de MaxPayloadInMB. Cette approche méthodique permet d'identifier l'impact de chaque paramètre indépendamment.
Les métriques clés à surveiller incluent :
Comme nous pouvons le constater, l’optimisation des inférences nécessite des compétences en machine learning, du temps et des efforts (qui peuvent parfois être conséquents) pour pouvoir effectuer les tests nécessaires. Afin de faciliter ce processus, Sagemaker dispose d’une fonctionnalité nommée SageMaker Inference Recommender : c’est un outil qui permet d’automatiser les tests de charge et d’effectuer des recommandations sur les instances susceptibles d’être les plus adaptées à la réalisation d’inférences avec votre modèle.
SageMaker Inference Recommender automatise ce processus d'optimisation en lançant des tests comparatifs sur différents types d'instances et configurations. L'outil évalue automatiquement diverses valeurs pour MaxConcurrentTransforms, BatchStrategy et MaxPayloadInMB, puis présente les résultats sous forme de métriques de performance et d'utilisation des ressources. Cette approche vous évite les tests manuels fastidieux et vous aide à identifier rapidement la configuration optimale pour vos besoins spécifiques.
Important à retenir : SageMaker Batch Transform ne propose pas d'autoscaling automatique. Le nombre d'instances est défini au lancement du job et reste fixe pendant toute sa durée. Cette approche diffère des endpoints en temps réel qui supportent l'autoscaling.
Choix entre CPU et GPU : Les instances CPU (séries ml.m5, ml.c5) sont généralement suffisantes pour :
Les instances GPU (séries ml.p3, ml.g4dn) sont nécessaires pour :
AWS SageMaker Batch Transform constitue une option viable pour l'industrialisation des modèles de machine learning lorsque l'inférence en temps réel n'est pas requise. Cette solution peut s'étendre au-delà du traitement par lots classique pour couvrir la validation de modèles, la détection de data drift, ou l'optimisation des pipelines MLOps.
L'approche BYOC (Bring Your Own Container) offre la flexibilité nécessaire pour adapter des modèles existants. Cette flexibilité implique cependant une responsabilité en termes d'optimisation : comprendre les paramètres de configuration et mettre en place une méthodologie de test appropriée reste essentiel pour obtenir des performances satisfaisantes.
Avant de choisir cette solution, il convient d'évaluer si les bénéfices (infrastructure managée, intégration AWS) compensent les contraintes (couplage, coûts, courbe d'apprentissage) par rapport aux alternatives disponibles.
