[{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/blog/","section":"Blog","summary":"","title":"Blog","type":"blog"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":" À propos # Ingénieur de données avec plus de 10 ans d\u0026rsquo;expérience en développement logiciel, maintenant spécialisé dans l\u0026rsquo;architecture de pipelines ETL, la modernisation de plateformes d\u0026rsquo;analytique et le MLOps. Expertise dans la transformation de processus manuels en solutions de données automatisées et prêtes pour la production, avec une solide base technique en systèmes distribués.\n","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/","section":"Damien GOEHRIG","summary":"\u003ch1 class=\"relative group\"\u003eÀ propos\n    \u003cdiv id=\"à-propos\" class=\"anchor\"\u003e\u003c/div\u003e\n    \n    \u003cspan\n        class=\"absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none\"\u003e\n        \u003ca class=\"text-primary-300 dark:text-neutral-700 !no-underline\" href=\"#%c3%a0-propos\" aria-label=\"Ancre\"\u003e#\u003c/a\u003e\n    \u003c/span\u003e\n    \n\u003c/h1\u003e\n\u003cp\u003eIngénieur de données avec plus de 10 ans d\u0026rsquo;expérience en développement logiciel, maintenant spécialisé dans l\u0026rsquo;architecture de pipelines ETL, la modernisation de plateformes d\u0026rsquo;analytique et le MLOps. Expertise dans la transformation de processus manuels en solutions de données automatisées et prêtes pour la production, avec une solide base technique en systèmes distribués.\u003c/p\u003e","title":"Damien GOEHRIG","type":"page"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/categories/data-engineering/","section":"Categories","summary":"","title":"Data Engineering","type":"categories"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/tags/data-engineering/","section":"Tags","summary":"","title":"Data Engineering","type":"tags"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/tags/dbt/","section":"Tags","summary":"","title":"Dbt","type":"tags"},{"content":"Publier un package sur PyPI. C\u0026rsquo;est un de ces trucs qui a l\u0026rsquo;air intimidant de l\u0026rsquo;extérieur, mais qui, finalement, s\u0026rsquo;avère être une question de bon timing et d\u0026rsquo;un problème assez précis à résoudre.\nLe problème # Quand tu travailles avec dbt, tu finis par avoir un DAG (directed acyclic graph) avec des dizaines, voire des centaines de modèles qui dépendent les uns des autres. Le truc, c\u0026rsquo;est que dbt ne te dit pas quand tu casses quelque chose en aval. Tu renommes une colonne dans un modèle silver, tu pushes ta PR, les tests passent\u0026hellip; et trois jours plus tard, quelqu\u0026rsquo;un se rend compte qu\u0026rsquo;un dashboard gold est cassé parce qu\u0026rsquo;il référençait cette colonne.\nC\u0026rsquo;est le genre de problème silencieux. Pas d\u0026rsquo;erreur à la compilation. Pas de test qui fail. Juste un consommateur en aval qui se retrouve avec des données manquantes.\nMais ça existe sûrement déjà ? # Avant de me lancer, j\u0026rsquo;ai fait ce que tout le monde fait : chercher si quelqu\u0026rsquo;un avait déjà résolu le problème.\nIl y a quelques outils dans l\u0026rsquo;écosystème qui s\u0026rsquo;en approchent :\ndbt Core 1.5+ avec model contracts : si tu déclares contract: enforced: true sur un modèle, dbt détecte les breaking changes au moment du run. Mais ça exige une configuration explicite modèle par modèle. Sur un projet existant, c\u0026rsquo;est pas réaliste de tout rétroférer. Ok un LLM peut refactorer ton projet pour ajouter les contrats, mais j\u0026rsquo;aime pas vraiment cette utilisation des contracts. Je les vois plutot comme une spec OpenAPI (vision de developpeur) que comme un outil de validation de breaking changes (vision d\u0026rsquo;ops). Recce : l\u0026rsquo;outil open source le plus complet pour la validation de changements dbt. Il utilise SQLGlot pour analyser les breaking changes, il est sérieux et actif. Mais son workflow est pensé pour comparer deux environnements connectés (dev et prod) avec accès à la base de données. dbt-manifest-differ : compare deux manifests, mais pour déboguer pourquoi dbt a marqué un nœud comme state:modified. Pas pour détecter des breaking changes de colonnes. Aucun ne répondait exactement à mon besoin : comparer deux manifests en offline, sans connexion à Snowflake, sans configuration préalable des modèles.\nLa raison pour laquelle ce gap existe, je pense, c\u0026rsquo;est une combinaison de facteurs. Les équipes qui ont des DAGs assez grands pour souffrir de ce problème sont souvent sur dbt Cloud, qui a la détection de breaking changes derrière son offre payante. Et dans la culture data engineering, l\u0026rsquo;outillage se connecte au warehouse par réflexe. L\u0026rsquo;idée d\u0026rsquo;analyse statique sur des fichiers JSON locaux est contre-intuitive dans cet écosystème.\nIl y a aussi un prérequis implicite : pour que l\u0026rsquo;analyse statique sur le manifest fonctionne, il faut que les colonnes soient documentées dans les fichiers YAML. Ce qui n\u0026rsquo;est peut-être pas le cas dans beaucoup de projets dbt.\nL\u0026rsquo;autre motivation, c\u0026rsquo;est le coût. Une pipeline CI dbt classique, ça fait un dbt build complet. Ça veut dire du compute Snowflake, des warehouses qui tournent, des credits qui brûlent. Chaque PR, chaque push. Quand t\u0026rsquo;as une stack data de taille respectable, ça chiffre vite. Et pour quoi ? Pour valider un renommage de colonne qui aurait pu être détecté sans jamais toucher à Snowflake.\nL\u0026rsquo;idée # Je voulais quelque chose de simple : un outil qui compare deux versions d\u0026rsquo;un manifest dbt (la branche base vs la PR) et qui te dit \u0026ldquo;attention, tu as retiré/renommé la colonne X dans le modèle Y, et les modèles Z1, Z2, Z3 en dépendent.\u0026rdquo;\nPas de connexion à la base de données requise. Zéro compute Snowflake. 100% offline. Juste de l\u0026rsquo;analyse statique sur les fichiers manifest.json que dbt génère déjà. Tu roules dbt parse (qui est quasi instantané et ne touche pas à ta base), tu compares les manifests, et c\u0026rsquo;est réglé.\nComment ça marche # Le principe est assez direct :\nTu lui donnes deux dossiers : un avec le manifest de la branche principale, l\u0026rsquo;autre avec celui de ta PR Il parse les deux manifests et extrait les colonnes de chaque modèle Il compare et identifie les changements : colonnes supprimées, renommées, changements de type Pour les changements cassants, il traverse le DAG en BFS (breadth-first search) pour trouver tous les modèles en aval impactés En option, il trace le lignage au niveau des colonnes pour éliminer les faux positifs : si un modèle downstream ne référence pas la colonne modifiée, pas d\u0026rsquo;alerte La distinction entre cassant et non-cassant est simple :\nCassant : colonne supprimée, renommée, changement de type Non-cassant : nouvelle colonne, nouveau modèle dbt-guard diff --base target/base --current target/current --dialect snowflake Et ça sort un rapport en texte, JSON, ou en annotations GitHub Actions. Ce dernier format est pratique, les alertes apparaissent directement sur les lignes de code dans la PR.\nLe lignage au niveau des colonnes # C\u0026rsquo;est la feature qui m\u0026rsquo;a le plus donné de fil à retordre, et c\u0026rsquo;est aussi celle qui rend l\u0026rsquo;outil vraiment utile.\nSans lignage de colonnes, si tu modifies une colonne dans un modèle upstream, tous les modèles downstream sont flaggés comme potentiellement impactés. Avec des centaines de modèles, ça génère beaucoup de bruit.\nAvec le lignage, dbt-guard trace quelles colonnes downstream référencent réellement la colonne modifiée. Si un modèle downstream fait un SELECT col_a, col_b et que tu as modifié col_c, pas d\u0026rsquo;alerte. C\u0026rsquo;est SQLGlot qui fait cette magie en parsant le SQL et en construisant l\u0026rsquo;arbre de dépendances.\nÉvidemment, ça a ses limites. SELECT * est le cas classique qui complique les choses. Quand un modèle fait un SELECT *, on ne peut pas savoir statiquement quelles colonnes il consomme réellement. Et certains patterns SQL complexes peuvent tromper le parser. Mais pour la majorité des cas, ça fonctionne et ça réduit significativement le bruit.\nPublier sur PyPI # Premier package Python publié. Le processus en soi n\u0026rsquo;est pas sorcier : pyproject.toml bien configuré, quelques métadonnées, et pip install build \u0026amp;\u0026amp; python -m build \u0026amp;\u0026amp; twine upload dist/*. Mais c\u0026rsquo;est quand même satisfaisant de voir son package apparaître sur pypi.org et de pouvoir faire pip install dbt-guard.\nJ\u0026rsquo;ai mis en place les standards de base : pytest pour les tests, mypy pour le typage, ruff pour le linting, un seuil de couverture à 80%. Les tests utilisent des fixtures synthétiques plutôt que des bases de données réelles, cohérent avec la philosophie \u0026ldquo;pas de connexion requise\u0026rdquo; de l\u0026rsquo;outil.\nCe que j\u0026rsquo;ai appris # Quelques leçons en vrac :\nLa dégradation gracieuse, c\u0026rsquo;est important. SQLGlot ne peut pas parser tous les patterns SQL imaginables. Plutôt que de crasher, dbt-guard retombe sur les colonnes documentées dans le manifest quand le parsing SQL échoue. C\u0026rsquo;est pas parfait, mais c\u0026rsquo;est mieux qu\u0026rsquo;une erreur bloquante.\nGarder les dépendances minimales. Chaque dépendance que tu ajoutes est une source potentielle de conflits de version dans l\u0026rsquo;environnement de quelqu\u0026rsquo;un d\u0026rsquo;autre. Avec juste SQLGlot et Click, les chances de conflits sont faibles.\nLes fixtures synthétiques pour les tests. Pas besoin d\u0026rsquo;une vraie base Snowflake pour tester un outil d\u0026rsquo;analyse statique. Des manifests JSON fabriqués à la main font l\u0026rsquo;affaire et les tests roulent en quelques secondes.\nPourquoi la documentation comme prérequis n\u0026rsquo;est pas un problème # Un prérequis de dbt-guard, c\u0026rsquo;est que tes colonnes soient documentées dans les fichiers YAML. Pour quelqu\u0026rsquo;un qui vient du développement logiciel, ça semble évident : la documentation fait partie du contrat d\u0026rsquo;une API, pas d\u0026rsquo;un nice-to-have. Mais en data engineering, c\u0026rsquo;est loin d\u0026rsquo;être la norme.\nMon point de vue : avec les LLMs, il n\u0026rsquo;y a plus d\u0026rsquo;excuse. Documenter des centaines de colonnes manuellement était pénible. Aujourd\u0026rsquo;hui, un agent peut lire ton SQL, inférer le contexte métier et générer un premier jet de documentation YAML en quelques secondes. J\u0026rsquo;en parle plus en détail dans l\u0026rsquo;article sur la documentation dbt comme gouvernance.\nEt puis dans un CI, l\u0026rsquo;enforcement est automatique via dbt_meta_testing : si une PR ajoute un modèle ou une colonne sans description, elle ne passe pas. La documentation n\u0026rsquo;est pas optionnelle, elle est vérifiée au même titre que les tests.\nUn projet dbt, c\u0026rsquo;est de l\u0026rsquo;infrastructure testable offline # Ce qui m\u0026rsquo;a convaincu de l\u0026rsquo;approche statique, c\u0026rsquo;est une analogie simple : un projet dbt est une représentation de l\u0026rsquo;infrastructure de ta stack data. Le DAG, les colonnes, les dépendances, tout ça vit dans des fichiers JSON et YAML. Comme du Terraform pour ta donnée.\nEt l\u0026rsquo;infrastructure, on peut la valider offline. terraform plan ne touche pas à ton cloud. dbt parse ne touche pas à Snowflake. Le manifest qui en résulte est une description complète de ce que le projet est censé faire.\nTester ce manifest, c\u0026rsquo;est tester l\u0026rsquo;infrastructure avant de la déployer. Ça ne remplace pas les tests sur les données réelles (les contraintes d\u0026rsquo;unicité, les valeurs nulles, la fraîcheur), mais ça permet d\u0026rsquo;être strict sur la structure des pipelines sans aucun coût de compute. C\u0026rsquo;est un filtre en amont, rapide et gratuit, avant même de toucher à la base.\nL\u0026rsquo;argument du coût # Je reviens là-dessus parce que c\u0026rsquo;est un point sous-estimé. Une CI dbt \u0026ldquo;standard\u0026rdquo; qui fait dbt build --target ci, c\u0026rsquo;est :\nUn warehouse Snowflake qui se réveille Des modèles qui se matérialisent (même en mode CI) Des tests qui roulent sur des données réelles Des credits qui partent à chaque PR Avec dbt-guard, la détection de breaking changes coûte exactement zéro credit Snowflake. Ça tourne sur le runner CI lui-même, en quelques secondes, avec des fichiers JSON locaux. Ça ne remplace pas ta CI dbt (tu en as toujours besoin pour valider la logique), mais ça attrape une catégorie entière de problèmes avant même de toucher à ta base. C\u0026rsquo;est un filtre rapide et gratuit en amont.\nEt la suite ? # L\u0026rsquo;outil fait ce qu\u0026rsquo;il doit faire. C\u0026rsquo;est un garde-fou qui s\u0026rsquo;intègre dans ta CI, et qui bloque (ou avertit) quand une PR risque de casser des consommateurs en aval. Pas plus, pas moins.\nC\u0026rsquo;est mon premier package Python publié. C\u0026rsquo;est pas révolutionnaire, c\u0026rsquo;est pas un framework qui va changer le monde. C\u0026rsquo;est un outil qui résout un problème spécifique que j\u0026rsquo;avais, que personne d\u0026rsquo;autre n\u0026rsquo;avait encore résolu en open source, et qui pourrait être utile à d\u0026rsquo;autres.\nLe code est sur GitHub, sous licence Apache 2.0. Si vous travaillez avec dbt et que vous avez déjà eu le plaisir de découvrir un breaking change en production un vendredi soir, ça vaut peut-être le coup d\u0026rsquo;y jeter un oeil.\n","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/blog/dbt-guard-package-python/","section":"Blog","summary":"\u003cp\u003ePublier un package sur PyPI. C\u0026rsquo;est un de ces trucs qui a l\u0026rsquo;air intimidant de l\u0026rsquo;extérieur, mais qui, finalement, s\u0026rsquo;avère être une question de bon timing et d\u0026rsquo;un problème assez précis à résoudre.\u003c/p\u003e","title":"dbt-guard : Mon premier package Python (et pourquoi j'en avais besoin)","type":"blog"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/categories/open-source/","section":"Categories","summary":"","title":"Open Source","type":"categories"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/tags/open-source/","section":"Tags","summary":"","title":"Open Source","type":"tags"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/tags/python/","section":"Tags","summary":"","title":"Python","type":"tags"},{"content":"","date":"5 avril 2026","externalUrl":null,"permalink":"/fr/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"27 février 2026","externalUrl":null,"permalink":"/fr/categories/data-quality/","section":"Categories","summary":"","title":"Data Quality","type":"categories"},{"content":"","date":"27 février 2026","externalUrl":null,"permalink":"/fr/tags/data-quality/","section":"Tags","summary":"","title":"Data Quality","type":"tags"},{"content":"Tu connais cette sensation : un rapport qui sort des chiffres bizarres, un analyste qui te dit \u0026ldquo;les totaux matchent pas\u0026rdquo;, et tu passes ta journée à remonter la chaîne pour trouver où les données ont dérapé. Souvent, le problème aurait pu être détecté automatiquement si quelqu\u0026rsquo;un avait mis un test quelque part.\nLes tests déclaratifs dans dbt # dbt a un système de tests intégré directement dans les YAML de documentation. C\u0026rsquo;est le même fichier qui documente tes colonnes et qui déclare tes tests. L\u0026rsquo;idée est simple : tu décris tes attentes sur les données, et dbt les vérifie à chaque exécution.\nLes quatre tests natifs :\nnot_null : cette colonne ne devrait jamais être vide unique : pas de doublons sur cette colonne accepted_values : les seules valeurs possibles sont cette liste relationships : cette colonne référence une autre table (intégrité référentielle) C\u0026rsquo;est déclaratif. Tu n\u0026rsquo;écris pas de SQL de test, tu déclares des contraintes.\nAu-delà des tests de base # Les quatre tests de base couvrent une bonne partie des besoins, mais pas tout. Pour le reste, il y a les packages de tests et les tests custom.\nLes tests de combinaison. \u0026ldquo;Cette combinaison de colonnes doit être unique.\u0026rdquo; Par exemple, une commande ne devrait apparaître qu\u0026rsquo;une seule fois par date et par client. C\u0026rsquo;est pas un simple unique sur une colonne, c\u0026rsquo;est une contrainte composite. dbt-utils fournit unique_combination_of_columns pour ça.\nLes tests de distribution. \u0026ldquo;Cette colonne ne devrait pas avoir plus de X% de valeurs nulles.\u0026rdquo; Utile pour les colonnes qui peuvent être nulles mais ne devraient pas l\u0026rsquo;être trop souvent.\nLes tests de fraîcheur. \u0026ldquo;La donnée la plus récente dans cette source ne devrait pas avoir plus de 24 heures.\u0026rdquo; Techniquement c\u0026rsquo;est un mécanisme séparé dans dbt (dbt source freshness), mais ça se déclare au même endroit dans les YAML. Si ta source arrête d\u0026rsquo;envoyer des données et que personne ne le remarque pendant une semaine, t\u0026rsquo;as un problème.\nLes tests de cohérence. \u0026ldquo;Le sous-total + taxes + livraison devrait être égal au total de commande.\u0026rdquo; C\u0026rsquo;est le genre de test qui attrape les bugs d\u0026rsquo;arrondi et les incohérences de calcul avant qu\u0026rsquo;un client ou fournisseur te le signale.\nTests sur les sources : la première ligne de défense # Un pattern que j\u0026rsquo;apprécie particulièrement : tester les données source, pas juste les modèles transformés.\nQuand tes données arrivent dans Snowflake via un outil de réplication (genre Fivetran, Airbyte), tu n\u0026rsquo;as aucune garantie sur leur qualité. Le système source peut avoir des bugs. La réplication peut avoir des problèmes. Les types peuvent changer sans prévenir.\nEn mettant des tests directement sur les définitions de sources dans dbt, tu crées une première ligne de défense :\nEst-ce que les colonnes que tu attends sont toujours là ? Est-ce que les types sont corrects ? Est-ce que les IDs sont bien uniques ? Est-ce qu\u0026rsquo;il y a des données récentes ? Quand un test source fail, ça te dit \u0026ldquo;le problème vient d\u0026rsquo;en amont, pas de ta transformation.\u0026rdquo; C\u0026rsquo;est de l\u0026rsquo;information précieuse pour le debug.\nEn pratique, c\u0026rsquo;est souvent le meilleur moyen de découvrir qu\u0026rsquo;un collègue du côté dev a fait un changement sur l\u0026rsquo;un de ses services sans passer par la case \u0026ldquo;prévenir l\u0026rsquo;équipe data\u0026rdquo;. Une colonne renommée, un nouveau statut ajouté, un type qui change silencieusement en prod. Sans tests sur les sources, tu le découvres quand un dashboard est cassé. Avec, tu catches rapidement pourquoi la dynamic table et tout le lineage fail. Tu roules tes tests, ça te donne une première piste, et tu peux aller poser la bonne question à la bonne équipe avant de partir débugger dans le mauvais sens.\nLa CI comme filet de sécurité # Les tests ne servent à rien si personne ne les roule. La pipeline CI est là pour ça.\nChaque PR qui touche aux modèles dbt déclenche un cycle complet :\nBuild des modèles en environnement CI Exécution de tous les tests Validation de la documentation (complétude) Si tout passe, la PR peut être mergée Le point clé : la CI fail si un test fail. Pas de warning ignoré, pas de \u0026ldquo;on corrigera plus tard.\u0026rdquo; Si tes données ne passent pas les contraintes que tu as déclarées, le code ne va pas en production.\nCI sur Snowflake : quelques réglages pour ne pas saigner des crédits # Si ta CI build une stack éphémère complète à chaque PR, il y a quelques réglages qui font une vraie différence sur la facture.\nDimensionner les warehouses selon le volume de CI. Un XS suffit pour la plupart des builds CI, inutile de sur-dimensionner. Le vrai paramètre à ajuster, c\u0026rsquo;est combien de runs parallèles tu peux avoir en simultané sur une journée chargée.\nUtiliser des databases transient pour la CI. Une database transient dans Snowflake ne conserve pas de Fail-Safe (la rétention de données en cas de corruption ou suppression accidentelle qui est activée par défaut sur les tables standard). Pour de la donnée CI qui est de toute façon recréée à chaque run, payer pour le Fail-Safe n\u0026rsquo;a aucun sens. Déclarer la database cible de la CI comme transient coupe ce coût sans aucun impact fonctionnel.\nNettoyer proprement à la fin. Le step de cleanup de ta CI doit dropper la database entière, pas juste les tables créées pendant le run. Un pipeline qui plante à mi-chemin sans cleanup laisse des objets orphelins qui tournent, notamment les Dynamic Tables, qui continuent à se rafraîchir et à consommer des crédits jusqu\u0026rsquo;à ce que quelqu\u0026rsquo;un les supprime manuellement. Vérifier de temps en temps que des vieilles CI databases ne traînent pas est une bonne hygiène.\nOverrider le lag des Dynamic Tables en CI. Par défaut, une Dynamic Table déployée en CI va essayer de se rafraîchir selon son lag cible : toutes les heures, toutes les 5 minutes, selon ce qui est déclaré en prod. En CI, tu veux exactement le contraire : qu\u0026rsquo;elles ne se rafraîchissent jamais toutes seules. La solution est d\u0026rsquo;overrider le target_lag à une valeur longue (genre 8760 hours, soit un an) dans ton profil CI. La table est créée, les tests tournent sur le contenu initial, et aucun refresh automatique ne vient perturber ou prolonger l\u0026rsquo;exécution.\nUtiliser --defer avec un manifest de prod. C\u0026rsquo;est probablement l\u0026rsquo;optimisation la plus impactante. dbt a une option --defer qui, combinée avec le manifest de la branche principale, permet de ne builder que les modèles modifiés dans la PR. Pour les modèles non touchés, dbt les \u0026ldquo;proxie\u0026rdquo; vers la version prod existante plutôt que de les recréer from scratch. Une PR qui modifie 3 modèles dans un DAG de 200 ne build que ces 3 modèles et leurs dépendants directs, pas la stack entière. Le gain en temps et en crédits est considérable sur les projets de taille respectable.\nLes tests comme documentation vivante # Ce qui est élégant avec les tests déclaratifs dans les YAML, c\u0026rsquo;est qu\u0026rsquo;ils servent aussi de documentation. Quand tu vois :\n- name: status description: \u0026#34;Statut de la commande\u0026#34; tests: - not_null - accepted_values: values: [\u0026#39;PENDING\u0026#39;, \u0026#39;PROCESSING\u0026#39;, \u0026#39;SHIPPED\u0026#39;, \u0026#39;DELIVERED\u0026#39;, \u0026#39;CANCELLED\u0026#39;] Tu sais immédiatement trois choses :\nCe que la colonne contient (description) Qu\u0026rsquo;elle ne peut pas être vide (not_null) Quelles sont ses valeurs possibles (accepted_values) C\u0026rsquo;est de la documentation qui se vérifie automatiquement. Quand un nouveau statut de commande apparaît dans les données, le test fail, la documentation est mise à jour, et tout le monde est au courant.\nLes erreurs qui m\u0026rsquo;ont convaincu # Quelques exemples concrets de problèmes attrapés par des tests :\nLe type boolean fantôme. Une colonne qui devrait être boolean mais qui contient des NULL en plus de true/false. Le code source traite NULL comme false, mais ta transformation dbt ne fait pas forcément pareil. Un test accepted_values: [true, false] combiné à not_null clarifie l\u0026rsquo;intention.\nL\u0026rsquo;ID en double. Un système source qui, suite à un bug de migration, a dupliqué quelques milliers d\u0026rsquo;enregistrements. Sans test unique, ces doublons se propagent silencieusement dans toute la chaîne de transformation.\nCe que j\u0026rsquo;en retiens # L\u0026rsquo;approche qui a marché pour moi part d\u0026rsquo;une hiérarchie simple.\nEn premier : les contraintes YAML. not_null, unique, accepted_values, relationships. Ces tests ne sont pas séparables de la documentation : ils sont la documentation. Déclarer qu\u0026rsquo;une colonne status accepte ['PENDING', 'SHIPPED', 'DELIVERED'], c\u0026rsquo;est à la fois documenter le contrat et le vérifier à chaque run. Le coût est quasi nul (une ligne de YAML), et ça donne une couverture de base sur toutes les colonnes sans effort particulier. C\u0026rsquo;est le minimum non négociable.\nEnsuite seulement : les tests complexes. Tests de cohérence, de distribution, de mapping : ceux qui nécessitent du SQL custom ou des packages comme dbt-utils. Ceux-là sont précieux, mais ils ont un coût : il faut les relire.\nC\u0026rsquo;est là où j\u0026rsquo;ai appris à ma dépens : déléguer la génération de tests à un LLM sans passer par une relecture sérieuse, c\u0026rsquo;est se retrouver avec de la fausse couverture. Des tests qui s\u0026rsquo;exécutent, qui passent, et qui ne testent pas vraiment ce qu\u0026rsquo;ils prétendent tester. C\u0026rsquo;est pire que pas de tests du tout, parce que ça donne une confiance non méritée. J\u0026rsquo;ai relu des tests générés par LLM que je n\u0026rsquo;avais pas vérifiés au moment du merge, et certains étaient tout simplement à côté de la plaque : logique inversée, mauvaise table référencée, seuil arbitraire sans sens métier. Ça passe mais ça ne sert à rien.\nLa règle que j\u0026rsquo;applique maintenant : les contraintes YAML, toujours, systématiquement, vérifiées en CI. Les tests complexes, seulement quand j\u0026rsquo;ai le temps de les relire ligne par ligne avant de les merger. Une couverture de 30% de tests bien compris vaut mieux qu\u0026rsquo;une couverture de 80% de tests dont personne ne sait vraiment ce qu\u0026rsquo;ils vérifient.\n","date":"27 février 2026","externalUrl":null,"permalink":"/fr/blog/dbt-tests-contraintes-yml/","section":"Blog","summary":"\u003cp\u003eTu connais cette sensation : un rapport qui sort des chiffres bizarres, un analyste qui te dit \u0026ldquo;les totaux matchent pas\u0026rdquo;, et tu passes ta journée à remonter la chaîne pour trouver où les données ont dérapé. Souvent, le problème aurait pu être détecté automatiquement si quelqu\u0026rsquo;un avait mis un test quelque part.\u003c/p\u003e","title":"dbt : Les tests dans les YAML, ou comment arrêter de prier pour que les données soient correctes","type":"blog"},{"content":"You know the feeling: a report spitting out weird numbers, an analyst telling you \u0026ldquo;the totals don\u0026rsquo;t match,\u0026rdquo; and you spend your day tracing back up the chain to find where the data went wrong. Often, the problem could have been detected automatically if someone had put a test somewhere.\nDeclarative Tests in dbt # dbt has a testing system built directly into the documentation YAMLs. It\u0026rsquo;s the same file that documents your columns and declares your tests. The idea is simple: you describe your expectations about the data, and dbt verifies them at every execution.\nThe four native tests:\nnot_null: this column should never be empty unique: no duplicates on this column accepted_values: the only possible values are this list relationships: this column references another table (referential integrity) It\u0026rsquo;s declarative. You don\u0026rsquo;t write test SQL, you declare constraints.\nBeyond Basic Tests # The four basic tests cover a good portion of needs, but not everything. For the rest, there are test packages and custom tests.\nCombination tests. \u0026ldquo;This combination of columns must be unique.\u0026rdquo; For example, an order should only appear once per date and per customer. It\u0026rsquo;s not a simple unique on one column, it\u0026rsquo;s a composite constraint. dbt-utils provides unique_combination_of_columns for this.\nDistribution tests. \u0026ldquo;This column should not have more than X% null values.\u0026rdquo; Useful for columns that can be null but shouldn\u0026rsquo;t be null too often.\nFreshness tests. \u0026ldquo;The most recent data in this source should not be more than 24 hours old.\u0026rdquo; Technically this is a separate mechanism in dbt (dbt source freshness), but it\u0026rsquo;s declared in the same place in the YAMLs. If your source stops sending data and nobody notices for a week, you have a problem.\nConsistency tests. \u0026ldquo;Subtotal + taxes + shipping should equal the order total.\u0026rdquo; This is the kind of test that catches rounding bugs and calculation inconsistencies before a customer or supplier reports them to you.\nTests on Sources: The First Line of Defense # A pattern I particularly appreciate: testing source data, not just transformed models.\nWhen your data arrives in Snowflake via a replication tool (like Fivetran, Airbyte), you have no guarantee about its quality. The source system can have bugs. Replication can have issues. Types can change without warning.\nBy putting tests directly on source definitions in dbt, you create a first line of defense:\nAre the columns you expect still there? Are the types correct? Are IDs properly unique? Is there recent data? When a source test fails, it tells you \u0026ldquo;the problem comes from upstream, not from your transformation.\u0026rdquo; That\u0026rsquo;s valuable information for debugging.\nIn practice, this is often the best way to discover that a colleague on the dev side made a change to one of their services without going through the \u0026ldquo;notify the data team\u0026rdquo; step. A renamed column, a new status added, a type that silently changes in production. Without source tests, you discover it when a dashboard is broken. With them, you catch quickly why the dynamic table and the whole lineage are failing. You run your tests, they give you a first lead, and you can go ask the right question to the right team before debugging in the wrong direction.\nCI as a Safety Net # Tests are useless if nobody runs them. The CI pipeline is there for that.\nEvery PR touching dbt models triggers a complete cycle:\nBuild models in CI environment Execute all tests Validate documentation completeness If everything passes, the PR can be merged The key point: CI fails if a test fails. No ignored warnings, no \u0026ldquo;we\u0026rsquo;ll fix it later.\u0026rdquo; If your data doesn\u0026rsquo;t pass the constraints you declared, the code doesn\u0026rsquo;t go to production.\nCI on Snowflake: A Few Settings to Stop Bleeding Credits # If your CI builds a complete ephemeral stack on every PR, a few settings make a real difference on the bill.\nSize warehouses to CI volume. An XS is enough for most CI builds, no need to oversize. The real parameter to tune is how many parallel runs you can have simultaneously on a busy day.\nUse transient databases for CI. A transient database in Snowflake doesn\u0026rsquo;t retain Fail-Safe (the data retention in case of corruption or accidental deletion that\u0026rsquo;s enabled by default on standard tables). For CI data that gets recreated on every run anyway, paying for Fail-Safe makes no sense. Declaring the CI target database as transient cuts this cost with no functional impact.\nClean up properly at the end. Your CI cleanup step must drop the entire database, not just the tables created during the run. A pipeline that crashes midway without cleanup leaves orphaned objects running, especially Dynamic Tables which keep refreshing and consuming credits until someone manually deletes them. Periodically checking that old CI databases aren\u0026rsquo;t hanging around is good hygiene.\nOverride Dynamic Table lag in CI. By default, a Dynamic Table deployed in CI will try to refresh according to its target lag: every hour, every 5 minutes, whatever is declared for production. In CI, you want the exact opposite: for them to never refresh automatically. The solution is to override target_lag to a long value (like 8760 hours, meaning one year) in your CI profile. The table is created, tests run on the initial content, and no automatic refresh comes to disrupt or extend execution.\nUse --defer with a production manifest. This is probably the most impactful optimization. dbt has a --defer option that, combined with the main branch manifest, lets you only build the models modified in the PR. For unmodified models, dbt \u0026ldquo;proxies\u0026rdquo; them to the existing production version instead of recreating them from scratch. A PR that modifies 3 models in a 200-model DAG builds only those 3 models and their direct dependents, not the entire stack. The time and credit savings are considerable on larger projects.\nTests as Living Documentation # What\u0026rsquo;s elegant about declarative tests in YAMLs is that they also serve as documentation. When you see:\n- name: status description: \u0026#34;Order status\u0026#34; tests: - not_null - accepted_values: values: [\u0026#39;PENDING\u0026#39;, \u0026#39;PROCESSING\u0026#39;, \u0026#39;SHIPPED\u0026#39;, \u0026#39;DELIVERED\u0026#39;, \u0026#39;CANCELLED\u0026#39;] You immediately know three things:\nWhat the column contains (description) That it can\u0026rsquo;t be empty (not_null) What its possible values are (accepted_values) It\u0026rsquo;s documentation that verifies itself automatically. When a new order status appears in the data, the test fails, the documentation gets updated, and everyone knows about it.\nThe Errors That Convinced Me # A few concrete examples of problems caught by tests:\nThe phantom boolean type. A column that should be boolean but contains NULL in addition to true/false. The source code treats NULL as false, but your dbt transformation doesn\u0026rsquo;t necessarily do the same. An accepted_values: [true, false] test combined with not_null clarifies the intent.\nThe duplicate ID. A source system that, following a migration bug, duplicated a few thousand records. Without a unique test, these duplicates silently propagate through the entire transformation chain.\nWhat I Take Away # The approach that worked for me starts with a simple hierarchy.\nFirst: YAML constraints. not_null, unique, accepted_values, relationships. These tests aren\u0026rsquo;t separable from documentation: they are the documentation. Declaring that a status column accepts ['PENDING', 'SHIPPED', 'DELIVERED'] is both documenting the contract and verifying it at every run. The cost is near zero (one line of YAML), and it gives basic coverage across all columns with no particular effort. This is the non-negotiable minimum.\nThen and only then: complex tests. Consistency tests, distribution tests, mapping tests: those requiring custom SQL or packages like dbt-utils. These are valuable, but they have a cost: you have to re-read them.\nThat\u0026rsquo;s where I learned the hard way: delegating test generation to an LLM without serious review means ending up with false coverage. Tests that execute, that pass, and that don\u0026rsquo;t actually test what they claim to test. That\u0026rsquo;s worse than no tests at all, because it gives unearned confidence. I reviewed LLM-generated tests I hadn\u0026rsquo;t checked at merge time, and some were simply off the mark: inverted logic, wrong table referenced, arbitrary threshold with no business meaning. They pass but serve no purpose.\nThe rule I apply now: YAML constraints, always, systematically, enforced in CI. Complex tests, only when I have time to read them line by line before merging. 30% coverage of well-understood tests is worth more than 80% coverage of tests nobody really knows what they\u0026rsquo;re checking.\n","date":"27 février 2026","externalUrl":null,"permalink":"/blog/dbt-tests-constraints-yml/","section":"Blog","summary":"\u003cp\u003eYou know the feeling: a report spitting out weird numbers, an analyst telling you \u0026ldquo;the totals don\u0026rsquo;t match,\u0026rdquo; and you spend your day tracing back up the chain to find where the data went wrong. Often, the problem could have been detected automatically if someone had put a test somewhere.\u003c/p\u003e","title":"dbt: Tests in YAML, or How to Stop Praying Your Data Is Correct","type":"blog"},{"content":"","date":"27 février 2026","externalUrl":null,"permalink":"/fr/tags/testing/","section":"Tags","summary":"","title":"Testing","type":"tags"},{"content":"","date":"6 février 2026","externalUrl":null,"permalink":"/fr/categories/ai/","section":"Categories","summary":"","title":"AI","type":"categories"},{"content":"","date":"6 février 2026","externalUrl":null,"permalink":"/fr/tags/ai/","section":"Tags","summary":"","title":"AI","type":"tags"},{"content":"Documenter les colonnes d\u0026rsquo;une base source, c\u0026rsquo;est le genre de tâche que personne ne veut faire. T\u0026rsquo;as un système opérationnel avec des centaines de tables, des milliers de colonnes, et une documentation qui va de \u0026ldquo;inexistante\u0026rdquo; à \u0026ldquo;un commentaire de 2017 qui dit TODO: document this.\u0026rdquo;\nLe contexte # Quand tu travailles avec dbt et que tu définis tes sources, tu veux idéalement documenter chaque colonne. Pas juste son nom et son type, mais ce qu\u0026rsquo;elle représente réellement, ses particularités, ses valeurs possibles, ses relations avec d\u0026rsquo;autres tables.\nC\u0026rsquo;est la couche bronze (les données brutes telles qu\u0026rsquo;elles arrivent des systèmes sources) qui est la plus difficile à documenter. Contrairement aux couches silver et gold, où la transformation elle-même est une forme de documentation (le SQL dit ce que la donnée est censée être), la couche bronze hérite des conventions, des bugs et des décisions de design du système qui l\u0026rsquo;alimente. La connaissance ne vit pas dans dbt, elle vit dans la codebase applicative.\nC\u0026rsquo;est là aussi que tout repose. Si tu ne sais pas ce que signifie une colonne en bronze, tu ne peux pas documenter correctement sa transformation en silver, ni la métrique business qu\u0026rsquo;elle alimente en gold. La documentation se construit de bas en haut, et le bas, c\u0026rsquo;est le plus dur.\nLe problème, c\u0026rsquo;est que cette connaissance est souvent dispersée. Elle est dans le code applicatif qui écrit dans ces tables. Elle est dans la tête des développeurs backend. Elle est parfois dans un wiki que personne n\u0026rsquo;a mis à jour depuis 2019.\nEt personne n\u0026rsquo;a envie de passer 3 semaines à éplucher du code legacy pour comprendre ce que legacy_field_42 veut dire.\nL\u0026rsquo;idée : des agents LLM spécialisés # L\u0026rsquo;approche que j\u0026rsquo;ai expérimentée, c\u0026rsquo;est d\u0026rsquo;utiliser des agents LLM pour faire le gros du travail d\u0026rsquo;investigation. Pas un seul prompt géant qui essaie de tout comprendre d\u0026rsquo;un coup, mais une approche multi-agent où chaque agent a un rôle spécifique.\nLe principe :\nAgent explorateur : parcourt le schéma de la base source, identifie les tables et les colonnes, note les types, les FK apparentes, les patterns de nommage Agent analyste de code : prend le code applicatif qui interagit avec chaque table et analyse comment chaque colonne est utilisée : en lecture, en écriture, les validations appliquées, les transformations Agent documentaliste : synthétise les informations des deux premiers agents et produit une documentation structurée au format YAML de dbt Chaque agent travaille table par table, colonne par colonne. C\u0026rsquo;est méthodique et systématique.\nCe que les agents découvrent # Le plus intéressant, c\u0026rsquo;est ce que les agents trouvent que personne ne savait (ou avait oublié) :\nLes colonnes détournées. Une colonne notes qui en théorie contient du texte libre, mais qui en pratique stocke du JSON sérialisé avec une structure spécifique que le frontend parse.\nLes valeurs magiques. Un status qui vaut 0, 1, 2, 3, 4. Mais personne ne sait que 3 veut dire \u0026ldquo;en attente de validation manuelle\u0026rdquo; et 4 c\u0026rsquo;est \u0026ldquo;annulé automatiquement par le système.\u0026rdquo; L\u0026rsquo;agent qui analyse le code trouve les constantes et les conditions.\nLes contraintes implicites. Une colonne qui n\u0026rsquo;a pas de contrainte NOT NULL en base, mais que le code applicatif ne laisse jamais vide. Ou une colonne qui devrait être unique mais qui a des doublons à cause d\u0026rsquo;un bug corrigé il y a 3 ans.\nLes données sérialisées. Du JSON, du XML, des formats propriétaires dans un champ texte. L\u0026rsquo;agent identifie le format et documente la structure interne.\nLes relations non documentées. Des FK qui n\u0026rsquo;existent pas en base mais que le code utilise systématiquement. Des colonnes qui référencent d\u0026rsquo;autres tables via une convention de nommage que personne n\u0026rsquo;a formalisée.\nL\u0026rsquo;intégration dans dbt # Une fois les YAML générés et validés, ils s\u0026rsquo;intègrent directement dans le projet dbt comme définitions de sources. Avec persist_docs activé, les descriptions remontent dans Snowflake et les métadonnées de classification alimentent les politiques de gouvernance. Ce mécanisme est couvert en détail dans l\u0026rsquo;article sur les YAML comme gouvernance.\nCe qui compte ici : les agents transforment un exercice de documentation fastidieux en base concrète pour une gouvernance active, sans que ça soit un projet séparé.\nDu bronze aux couches supérieures # Une fois la couche bronze documentée, quelque chose change dans la façon dont on documente le reste.\nEn silver, chaque modèle dbt est une transformation explicite depuis des sources connues. Le SQL lui-même dit beaucoup : une colonne total_amount calculée par unit_price * quantity n\u0026rsquo;a pas besoin d\u0026rsquo;une longue description. Ce qui compte, c\u0026rsquo;est de documenter les décisions de nettoyage, les règles de déduplication, les cas limites. Et ça, un LLM peut l\u0026rsquo;inférer en lisant le SQL et la documentation bronze en parallèle.\nEn gold, les modèles sont souvent des agrégations business. Les colonnes correspondent à des métriques dont le sens est dans la logique métier, pas dans le code. C\u0026rsquo;est là que la documentation devient plus manuelle, mais au moins tu pars d\u0026rsquo;une base solide. Tu sais exactement ce que chaque champ upstream représente, ce qui rend la documentation des métriques dérivées beaucoup plus précise.\nL\u0026rsquo;effet de levier est réel : la couche bronze est la plus longue à documenter et la plus difficile à automatiser partiellement. Les couches supérieures bénéficient directement de ce travail de fondation. Chaque colonne bronze correctement décrite se propage dans le lignage et réduit le travail de documentation des couches qui en dépendent.\nC\u0026rsquo;est aussi ce qui rend la documentation bronze si rentable à faire en premier, malgré l\u0026rsquo;effort : c\u0026rsquo;est le seul endroit où la connaissance est enfouie dans une codebase externe, et donc le seul endroit où les agents LLM ont un vrai avantage sur un data engineer qui ne connaît pas ce code.\nLes limites # Soyons honnêtes sur ce qui marche moins bien :\nLe contexte métier. Un LLM peut comprendre que creation_date est une date de création. Il ne peut pas savoir que dans votre contexte, cette date a une signification contractuelle précise qui affecte d\u0026rsquo;autres calculs en aval. Le contexte métier fin, ça reste humain.\nLe code legacy illisible. Quand le code qui interagit avec une table est un fichier de 3000 lignes sans structure claire, même un LLM a du mal à en extraire une documentation cohérente.\nLa validation. Tout ce que produit un LLM doit être validé par quelqu\u0026rsquo;un qui connaît le domaine. Les agents font le gros du boulot, mais la validation, la correction et l\u0026rsquo;ajout de contexte métier restent essentiels et irremplaçables. Pis comme je le dis souvent, on est responsable de notre utilisation de l\u0026rsquo;IA, et ça inclut la validation de ce qu\u0026rsquo;elle produit.\nLe workflow complet # En pratique :\nTu donnes à tes agents le dump du schéma de la base source et le code applicatif Les agents produisent des fichiers YAML documentés, table par table Un humain review, corrige les erreurs, ajoute le contexte métier manquant Les YAML corrigés deviennent les définitions de sources dans dbt Les métadonnées sont poussées vers Snowflake via persist_docs Les classifications alimentent les politiques de gouvernance Le temps total ? Pour une base de quelques centaines de tables : quelques jours d\u0026rsquo;agents + quelques jours de review humaine. Sans les agents, c\u0026rsquo;est des semaines, voire des mois, de travail manuel que personne ne veut faire.\nUn dernier conseil pratique : quitte à faire ça, autant y aller franchement. Prompt de reverse engineering complet, mode deep thinking activé, review systématique table par table. Ça veut dire brûler quelques millions de tokens chez nos amis d\u0026rsquo;OpenAI, Anthropic ou Google, mais c\u0026rsquo;est un investissement ponctuel pour un actif qui dure. Lance ça de nuit. Le matin, t\u0026rsquo;as une première version de doc sur toute ta couche bronze, et tu n\u0026rsquo;as pas eu à te taper une seule ligne de legacy_field_42 à la main.\nLa leçon # La documentation de source, c\u0026rsquo;est un des meilleurs use cases pour les LLM dans le data engineering. C\u0026rsquo;est pas glamour, c\u0026rsquo;est pas du machine learning, c\u0026rsquo;est pas de la data science. C\u0026rsquo;est du travail de fond, fastidieux mais essentiel, que les LLM font bien parce que c\u0026rsquo;est systématique, que le contexte est dans le code, et que la sortie est structurée.\nEt contrairement à d\u0026rsquo;autres applications de LLM, ici la validation est simple : un data engineer ou un développeur backend peut vérifier la documentation produite en quelques minutes par table. Les erreurs sont faciles à repérer et à corriger.\nC\u0026rsquo;est pas magique. C\u0026rsquo;est juste un bon outil appliqué au bon problème.\n","date":"6 février 2026","externalUrl":null,"permalink":"/fr/blog/dbt-documenter-source-llm-multi-agent/","section":"Blog","summary":"\u003cp\u003eDocumenter les colonnes d\u0026rsquo;une base source, c\u0026rsquo;est le genre de tâche que personne ne veut faire. T\u0026rsquo;as un système opérationnel avec des centaines de tables, des milliers de colonnes, et une documentation qui va de \u0026ldquo;inexistante\u0026rdquo; à \u0026ldquo;un commentaire de 2017 qui dit \u003ccode\u003eTODO: document this\u003c/code\u003e.\u0026rdquo;\u003c/p\u003e","title":"Documenter une base de données source avec des LLM multi-agents","type":"blog"},{"content":"Documenting columns in a source database is the kind of task nobody wants to do. You have an operational system with hundreds of tables, thousands of columns, and documentation ranging from \u0026ldquo;nonexistent\u0026rdquo; to \u0026ldquo;a 2017 comment that says TODO: document this.\u0026rdquo;\nThe Context # When you work with dbt and define your sources, you ideally want to document every column. Not just its name and type, but what it actually represents, its quirks, its possible values, its relationships with other tables.\nThe bronze layer (raw data as it arrives from source systems) is the hardest to document. Unlike silver and gold layers, where the transformation itself is a form of documentation (the SQL says what the data is supposed to be), the bronze layer inherits the conventions, bugs and design decisions of the system that feeds it. The knowledge doesn\u0026rsquo;t live in dbt, it lives in the application codebase.\nThis is also where everything rests. If you don\u0026rsquo;t know what a bronze column means, you can\u0026rsquo;t correctly document its silver transformation, or the business metric it feeds at the gold layer. Documentation builds from the bottom up, and the bottom is the hardest part.\nThe problem is that this knowledge is often scattered. It\u0026rsquo;s in the application code that writes to these tables. It\u0026rsquo;s in the heads of backend developers. Sometimes it\u0026rsquo;s in a wiki nobody has updated since 2019.\nAnd nobody wants to spend 3 weeks sifting through legacy code to understand what legacy_field_42 means.\nThe Idea: Specialized LLM Agents # The approach I experimented with is using LLM agents to do the heavy lifting of investigation. Not a single giant prompt trying to understand everything at once, but a multi-agent approach where each agent has a specific role.\nThe principle:\nExplorer agent: traverses the source database schema, identifies tables and columns, notes types, apparent FKs, naming patterns Code analyst agent: takes the application code that interacts with each table and analyzes how each column is used: reads, writes, validations applied, transformations Documentarian agent: synthesizes information from the two previous agents and produces structured documentation in dbt YAML format Each agent works table by table, column by column. Methodical and systematic.\nWhat the Agents Discover # The most interesting part is what the agents find that nobody knew (or had forgotten):\nRepurposed columns. A notes column that theoretically contains free text, but in practice stores serialized JSON with a specific structure that the frontend parses.\nMagic values. A status that takes values 0, 1, 2, 3, 4. But nobody remembers that 3 means \u0026ldquo;pending manual validation\u0026rdquo; and 4 means \u0026ldquo;automatically cancelled by the system.\u0026rdquo; The agent analyzing the code finds the constants and conditions.\nImplicit constraints. A column with no NOT NULL constraint in the database, but which the application code never leaves empty. Or a column that should be unique but has duplicates due to a bug fixed 3 years ago.\nSerialized data. JSON, XML, proprietary formats inside a text field. The agent identifies the format and documents the internal structure.\nUndocumented relationships. FKs that don\u0026rsquo;t exist in the database but the code uses systematically. Columns referencing other tables via a naming convention nobody formalized.\nIntegration into dbt # Once the YAMLs are generated and validated, they integrate directly into the dbt project as source definitions. With persist_docs enabled, descriptions surface in Snowflake and classification metadata feeds governance policies. This mechanism is covered in detail in the article on YAMLs as governance.\nWhat matters here: the agents transform a tedious documentation exercise into a concrete foundation for active governance, without it being a separate project.\nFrom Bronze to Upper Layers # Once the bronze layer is documented, something changes in how you document the rest.\nIn silver, each dbt model is an explicit transformation from known sources. The SQL itself says a lot: a total_amount column calculated from unit_price * quantity doesn\u0026rsquo;t need a long description. What matters is documenting cleaning decisions, deduplication rules, edge cases. And an LLM can infer those by reading the SQL and the bronze documentation in parallel.\nIn gold, models are often business aggregations. Columns correspond to metrics whose meaning is in business logic, not in code. That\u0026rsquo;s where documentation becomes more manual, but at least you start from a solid foundation. You know exactly what each upstream field represents, which makes documenting derived metrics much more precise.\nThe leverage effect is real: the bronze layer is the longest to document and the hardest to partially automate. Upper layers benefit directly from this foundation work. Every correctly described bronze column propagates through the lineage and reduces documentation work for the layers that depend on it.\nThis is also what makes bronze documentation so worthwhile to do first, despite the effort: it\u0026rsquo;s the only place where knowledge is buried in an external codebase, and therefore the only place where LLM agents have a real advantage over a data engineer who doesn\u0026rsquo;t know that code.\nThe Limits # Let\u0026rsquo;s be honest about what works less well:\nBusiness context. An LLM can understand that creation_date is a creation date. It can\u0026rsquo;t know that in your context, this date has a precise contractual meaning that affects downstream calculations. Fine-grained business context remains human.\nUnreadable legacy code. When the code interacting with a table is a 3000-line file with no clear structure, even an LLM struggles to extract coherent documentation from it.\nValidation. Everything an LLM produces must be validated by someone who knows the domain. Agents do the heavy lifting, but validation, correction and adding business context remain essential and irreplaceable. And as I often say, we\u0026rsquo;re responsible for how we use AI, and that includes validating what it produces.\nThe Complete Workflow # In practice:\nYou give your agents the source database schema dump and the application code The agents produce documented YAML files, table by table A human reviews, corrects errors, adds missing business context The corrected YAMLs become the source definitions in dbt Metadata is pushed to Snowflake via persist_docs Classifications feed governance policies Total time? For a database with a few hundred tables: a few days of agents plus a few days of human review. Without agents, that\u0026rsquo;s weeks or months of manual work that nobody wants to do.\nOne last practical tip: if you\u0026rsquo;re going to do this, go all in. Full reverse-engineering prompt, deep thinking mode enabled, systematic table-by-table review. This means burning a few million tokens with our friends at OpenAI, Anthropic or Google, but it\u0026rsquo;s a one-time investment for a long-lasting asset. Run it overnight. In the morning, you have a first version of documentation for your entire bronze layer, and you didn\u0026rsquo;t have to manually work through a single legacy_field_42 yourself.\nThe Lesson # Source documentation is one of the best use cases for LLMs in data engineering. It\u0026rsquo;s not glamorous, it\u0026rsquo;s not machine learning, it\u0026rsquo;s not data science. It\u0026rsquo;s foundational work, tedious but essential, that LLMs do well because it\u0026rsquo;s systematic, the context is in the code, and the output is structured.\nAnd unlike other LLM applications, here validation is straightforward: a data engineer or backend developer can verify the produced documentation in a few minutes per table. Errors are easy to spot and correct.\nIt\u0026rsquo;s not magic. It\u0026rsquo;s just a good tool applied to the right problem.\n","date":"6 février 2026","externalUrl":null,"permalink":"/blog/dbt-document-sources-llm-multi-agent/","section":"Blog","summary":"\u003cp\u003eDocumenting columns in a source database is the kind of task nobody wants to do. You have an operational system with hundreds of tables, thousands of columns, and documentation ranging from \u0026ldquo;nonexistent\u0026rdquo; to \u0026ldquo;a 2017 comment that says \u003ccode\u003eTODO: document this\u003c/code\u003e.\u0026rdquo;\u003c/p\u003e","title":"Documenting a Source Database with Multi-Agent LLMs","type":"blog"},{"content":"","date":"6 février 2026","externalUrl":null,"permalink":"/fr/tags/llm/","section":"Tags","summary":"","title":"LLM","type":"tags"},{"content":"","date":"16 janvier 2026","externalUrl":null,"permalink":"/fr/categories/data-governance/","section":"Categories","summary":"","title":"Data Governance","type":"categories"},{"content":"","date":"16 janvier 2026","externalUrl":null,"permalink":"/fr/tags/data-governance/","section":"Tags","summary":"","title":"Data Governance","type":"tags"},{"content":"La documentation, c\u0026rsquo;est le truc que personne ne veut faire. Surtout en data. T\u0026rsquo;as des centaines de colonnes dans des dizaines de tables, et quelqu\u0026rsquo;un te demande \u0026ldquo;c\u0026rsquo;est quoi le champ status dans la table orders ?\u0026rdquo; Et la réponse honnête, c\u0026rsquo;est souvent \u0026ldquo;euh\u0026hellip; un enum je pense qui veut probablement dire X.\u0026rdquo;\nLe problème de la documentation data # Dans un projet dbt classique, la documentation est optionnelle. Tu peux écrire tes modèles SQL, les déployer, et ne jamais documenter une seule colonne. dbt ne t\u0026rsquo;oblige à rien.\nLe résultat, c\u0026rsquo;est prévisible : des schémas Snowflake avec des centaines de colonnes dont personne ne connaît la signification exacte. Des noms de colonnes hérités d\u0026rsquo;un système source vieux de 10 ans. Des colonnes qui s\u0026rsquo;appellent type ou status sans aucune indication de ce que ça veut dire.\nEt quand un analyste marketing veut comprendre les données, il doit soit déranger quelqu\u0026rsquo;un qui a la connaissance tribale, soit deviner. Les deux sont problématiques.\nLes YAML de dbt : plus qu\u0026rsquo;une formalité # dbt a un mécanisme de documentation intégré : les fichiers schema.yml (ou peu importe comment tu les nommes). Tu peux y décrire chaque modèle, chaque colonne, avec du texte libre. La plupart des équipes s\u0026rsquo;en servent peu ou pas.\nMais si tu prends le temps de bien structurer ces fichiers, ils deviennent bien plus qu\u0026rsquo;une documentation passive. Ils deviennent la source de vérité pour la gouvernance de tes données.\nL\u0026rsquo;idée, c\u0026rsquo;est d\u0026rsquo;utiliser le champ meta de chaque colonne pour stocker des métadonnées structurées :\nClassification : est-ce que cette colonne contient de l\u0026rsquo;information personnelle (PII), financière, confidentielle ? Catégorie sémantique : est-ce un email, un montant, une adresse, un identifiant ? Sensibilité : haute, moyenne, basse ? Obligations réglementaires : LPRPDE, GDPR, données consommateurs, e-commerce ? Rétention : combien de temps garder ces données ? Quand chaque colonne a ses métadonnées, tu passes d\u0026rsquo;une documentation passive à une gouvernance active.\npersist_docs : du YAML à Snowflake # Le truc qui fait la différence, c\u0026rsquo;est persist_docs. C\u0026rsquo;est une option dbt qui prend tes descriptions YAML et les pousse comme commentaires sur les objets Snowflake. Quand tu actives ça :\nmodels: mon_projet: +persist_docs: relation: true columns: true Chaque description de modèle et de colonne dans tes YAML devient un commentaire visible dans Snowflake. Pas besoin d\u0026rsquo;un outil externe. Quelqu\u0026rsquo;un qui navigue les données dans Snowsight voit directement les descriptions que t\u0026rsquo;as écrites dans dbt.\nEt si tu utilises Snowflake Horizon (leur plateforme de gouvernance), ces descriptions alimentent directement le catalogue de données. Ta documentation dbt EST ta documentation Snowflake. Une seule source de vérité.\nForcer la documentation en CI # Mon point de vue là-dessus est assez tranché : la documentation, c\u0026rsquo;est aussi obligatoire que le code lui-même. Pas un nice-to-have, pas quelque chose qu\u0026rsquo;on fera \u0026ldquo;quand on aura le temps\u0026rdquo;. Si tu déploies du code non testé en production, c\u0026rsquo;est un problème. Déployer un modèle non documenté devrait l\u0026rsquo;être tout autant.\nEt si tu automatises tout le reste (déploiements, tests, validations), pourquoi la documentation échapperait-elle à cette logique ? La CI est la réponse évidente. C\u0026rsquo;est le premier check que j\u0026rsquo;y mets : avant même de valider la logique des transformations, on vérifie que la documentation est là.\nConcrètement, ça donne une étape qui valide la complétude :\nChaque modèle Silver et Gold doit avoir une description Chaque colonne dans le SQL doit être présente dans le YAML Chaque colonne documentée doit avoir une description non vide Si une PR ajoute un modèle sans documentation, la CI fail. Point final. C\u0026rsquo;est la seule façon de maintenir la discipline sur le long terme. Le package dbt-meta-testing fait exactement ça : il expose des macros required_docs et required_tests que tu branches dans ta pipeline.\nLes tags de gouvernance : du YAML au masquage # Là où ça devient puissant, c\u0026rsquo;est quand tu combines les métadonnées YAML avec les fonctionnalités de gouvernance de Snowflake.\nTu déclares dans ton YAML qu\u0026rsquo;une colonne contient du PII. dbt peut appliquer un tag Snowflake correspondant quand il crée le modèle, via un post-hook qu\u0026rsquo;on écrit nous-mêmes, c\u0026rsquo;est pas du built-in. Et Snowflake, grâce à des politiques de masquage liées aux tags, masque automatiquement la valeur pour les utilisateurs qui n\u0026rsquo;ont pas le bon rôle.\nLe résultat : tu documentes tes colonnes dans le YAML, et le masquage de données se fait tout seul. Pas de logique de masquage dans le SQL, pas de vues spéciales, pas de maintenance. La gouvernance découle directement de la documentation.\nLes tests : la documentation qui se vérifie # Les YAML de dbt ne servent pas qu\u0026rsquo;à la documentation, ils servent aussi aux tests. Et c\u0026rsquo;est là que ça boucle : ta documentation devient vérifiable.\nTu documentes qu\u0026rsquo;un order_id est une clé primaire ? Mets un test unique et not_null. Tu documentes qu\u0026rsquo;un statut ne peut avoir que certaines valeurs ? Mets un test accepted_values. Tu documentes qu\u0026rsquo;une colonne référence une autre table ? Mets un test de relation.\nLes tests sont déclarés au même endroit que la documentation. Un seul fichier YAML qui dit : \u0026ldquo;cette colonne s\u0026rsquo;appelle X, elle contient Y, elle ne peut pas être nulle, et ses valeurs possibles sont Z.\u0026rdquo; La documentation et les tests sont la même chose. On revient là-dessus en détail dans l\u0026rsquo;article sur les tests dbt.\nQuand les tests passent, ta documentation est prouvée correcte. Quand un test fail, ta documentation ou tes données sont fausses. Dans les deux cas, tu dois investiguer.\nLes contacts de gouvernance # Un aspect souvent négligé : qui est responsable de quoi ? Dans les métadonnées de chaque modèle, tu peux déclarer un propriétaire, un steward, un approbateur. Ces métadonnées sont poussées vers Snowflake via un post-hook custom (encore une fois, c\u0026rsquo;est du bricolage maison, pas du dbt natif).\nQuand quelqu\u0026rsquo;un trouve un problème de données, il sait exactement qui contacter. Pas besoin de chercher dans un wiki ou de demander à la cantonade. L\u0026rsquo;information est attachée directement aux données elles-mêmes.\nLe coût réel : c\u0026rsquo;est moins que tu penses # Le reproche classique : \u0026ldquo;ça prend du temps de documenter chaque colonne.\u0026rdquo; C\u0026rsquo;est vrai. Mais compare avec l\u0026rsquo;alternative :\nDes heures perdues par les analystes à deviner ce que les colonnes veulent dire Des erreurs dans les rapports parce que quelqu\u0026rsquo;un a interprété un champ de travers Des audits qui prennent des semaines parce que personne sait quelles données sont sensibles Des incidents de sécurité parce qu\u0026rsquo;une colonne PII n\u0026rsquo;était pas identifiée comme telle Documenter une colonne prend 30 secondes. Ne pas la documenter peut coûter des heures, des jours, ou pire. Et avec les LLMs, le coût de départ a encore baissé : documenter une base source entière en quelques jours n\u0026rsquo;est plus une utopie.\nLe bonus : la documentation comme clé du talk to my data # La documentation sert deux audiences : tes collègues humains, et les LLMs. Et c\u0026rsquo;est là que ça devient intéressant.\nSnowflake Cortex Analyst est la réponse de Snowflake au \u0026ldquo;talk to my data\u0026rdquo; : poser une question en langage naturel et obtenir la requête SQL correcte en retour. Demander une KPI précise, la filtrer selon des critères, la comparer avec une autre métrique, sans écrire une ligne de SQL. Ça paraît magique. Et les gens pensent spontanément que c\u0026rsquo;est des mois de travail d\u0026rsquo;ingénierie pour y arriver.\nCe n\u0026rsquo;est pas le cas, si la documentation est propre.\nCortex Analyst fonctionne à partir d\u0026rsquo;un modèle sémantique : un fichier YAML qui décrit les tables, les colonnes, les métriques, les relations entre entités, et le vocabulaire métier associé. La structure de ce fichier est très proche de ce que dbt produit déjà dans ses fichiers de documentation. L\u0026rsquo;infrastructure existe. Les modèles existent. Si les descriptions de colonnes sont là, si les relations sont documentées, si les métriques clés sont définies, le gap pour Cortex Analyst est faible.\nSnowflake Labs a même publié dbt_semantic_view, un package qui génère des Semantic Views Snowflake directement depuis le modèle sémantique dbt. Ces Semantic Views sont nativement exploitables par Cortex Analyst. Le pipeline devient : dbt documente → dbt_semantic_view publie les vues sémantiques → Cortex Analyst répond aux questions en langage naturel.\nUn projet dbt bien documenté est à 2-4 semaines d\u0026rsquo;un talk to my data fonctionnel, pas à 6 mois. Le travail restant (formaliser quelques métriques, distinguer dimensions et mesures, ajouter des synonymes métier) est marginal comparé à ce qui est déjà en place. C\u0026rsquo;est un quick win qui ne se débloque qu\u0026rsquo;avec une condition : avoir traité la documentation comme une contrainte dès le début, pas comme une tâche à faire plus tard.\nCe que j\u0026rsquo;en retiens # Au final, ce qui a marché pour moi, c\u0026rsquo;est de traiter la documentation des données avec le même sérieux que le code de transformation. Pas comme un nice-to-have qu\u0026rsquo;on fera \u0026ldquo;quand on aura le temps.\u0026rdquo; Comme une partie intégrante du pipeline, vérifiée en CI, propagée automatiquement.\nLes YAML de dbt sont l\u0026rsquo;endroit idéal pour ça. Un seul fichier qui sert à la documentation humaine, aux tests automatisés, et à la gouvernance de données. Ça sonne fancy dit comme ça, mais en pratique c\u0026rsquo;est juste des fichiers YAML qui font leur job.\n","date":"16 janvier 2026","externalUrl":null,"permalink":"/fr/blog/dbt-documentation-gouvernance-yml/","section":"Blog","summary":"\u003cp\u003eLa documentation, c\u0026rsquo;est le truc que personne ne veut faire. Surtout en data. T\u0026rsquo;as des centaines de colonnes dans des dizaines de tables, et quelqu\u0026rsquo;un te demande \u0026ldquo;c\u0026rsquo;est quoi le champ \u003ccode\u003estatus\u003c/code\u003e dans la table \u003ccode\u003eorders\u003c/code\u003e ?\u0026rdquo; Et la réponse honnête, c\u0026rsquo;est souvent \u0026ldquo;euh\u0026hellip; un enum je pense qui veut probablement dire X.\u0026rdquo;\u003c/p\u003e","title":"dbt : Quand tes fichiers YAML deviennent ta gouvernance de données","type":"blog"},{"content":"Documentation is the thing nobody wants to do. Especially in data. You have hundreds of columns across dozens of tables, and someone asks \u0026ldquo;what\u0026rsquo;s the status field in the orders table?\u0026rdquo; And the honest answer is often \u0026ldquo;uh\u0026hellip; an enum I think that probably means X.\u0026rdquo;\nThe Data Documentation Problem # In a typical dbt project, documentation is optional. You can write your SQL models, deploy them, and never document a single column. dbt doesn\u0026rsquo;t force you to do anything.\nThe result is predictable: Snowflake schemas with hundreds of columns that nobody knows the exact meaning of. Column names inherited from a 10-year-old source system. Columns called type or status with no indication of what they mean.\nAnd when a marketing analyst wants to understand the data, they either have to bother someone who has the tribal knowledge, or guess. Both are problematic.\ndbt YAMLs: More Than a Formality # dbt has a built-in documentation mechanism: schema.yml files (or whatever you call them). You can describe each model, each column, with free text. Most teams use them little or not at all.\nBut if you take the time to structure these files properly, they become much more than passive documentation. They become the source of truth for your data governance.\nThe idea is to use the meta field of each column to store structured metadata:\nClassification: does this column contain personal (PII), financial, or confidential information? Semantic category: is it an email, an amount, an address, an identifier? Sensitivity: high, medium, low? Regulatory obligations: PIPEDA, GDPR, consumer data, e-commerce? Retention: how long to keep this data? When every column has its metadata, you move from passive documentation to active governance.\npersist_docs: From YAML to Snowflake # The thing that makes the difference is persist_docs. It\u0026rsquo;s a dbt option that takes your YAML descriptions and pushes them as comments on Snowflake objects. When you enable it:\nmodels: my_project: +persist_docs: relation: true columns: true Every model and column description in your YAMLs becomes a comment visible in Snowflake. No external tool needed. Someone browsing data in Snowsight sees the descriptions you wrote in dbt directly.\nAnd if you use Snowflake Horizon (their governance platform), these descriptions feed directly into the data catalog. Your dbt documentation IS your Snowflake documentation. A single source of truth.\nEnforcing Documentation in CI # My view on this is pretty firm: documentation is as mandatory as the code itself. Not a nice-to-have, not something we\u0026rsquo;ll do \u0026ldquo;when we have time.\u0026rdquo; If you deploy untested code to production, that\u0026rsquo;s a problem. Deploying an undocumented model should be just as much of one.\nAnd if you automate everything else (deployments, tests, validations), why would documentation escape this logic? CI is the obvious answer. It\u0026rsquo;s the first check I put there: before even validating the transformation logic, we verify that the documentation exists.\nIn practice, this means a step that validates completeness:\nEvery Silver and Gold model must have a description Every column in the SQL must be present in the YAML Every documented column must have a non-empty description If a PR adds a model without documentation, CI fails. Full stop. It\u0026rsquo;s the only way to maintain discipline over the long term. The dbt-meta-testing package does exactly this: it exposes required_docs and required_tests macros that you wire into your pipeline.\nGovernance Tags: From YAML to Masking # This is where it gets powerful: combining YAML metadata with Snowflake\u0026rsquo;s governance features.\nYou declare in your YAML that a column contains PII. dbt can apply a corresponding Snowflake tag when it creates the model, via a post-hook you write yourself (not built-in, this is custom work). And Snowflake, through masking policies tied to tags, automatically masks the value for users who don\u0026rsquo;t have the right role.\nThe result: you document your columns in YAML, and data masking happens on its own. No masking logic in SQL, no special views, no maintenance. Governance flows directly from documentation.\nTests: The Documentation That Verifies Itself # dbt YAMLs aren\u0026rsquo;t just for documentation, they\u0026rsquo;re for tests too. And that\u0026rsquo;s where it loops back: your documentation becomes verifiable.\nYou document that an order_id is a primary key? Add a unique and not_null test. You document that a status can only have certain values? Add an accepted_values test. You document that a column references another table? Add a relationship test.\nTests are declared in the same place as documentation. A single YAML file that says: \u0026ldquo;this column is called X, it contains Y, it can\u0026rsquo;t be null, and its possible values are Z.\u0026rdquo; Documentation and tests are the same thing. We go into this in detail in the article on dbt tests.\nWhen tests pass, your documentation is proven correct. When a test fails, your documentation or your data is wrong. Either way, you need to investigate.\nGovernance Contacts # An often overlooked aspect: who is responsible for what? In each model\u0026rsquo;s metadata, you can declare an owner, a steward, an approver. These metadata are pushed to Snowflake via a custom post-hook (again, this is handcrafted, not native dbt).\nWhen someone finds a data problem, they know exactly who to contact. No need to search a wiki or ask around. The information is attached directly to the data itself.\nThe Real Cost: Less Than You Think # The classic objection: \u0026ldquo;it takes time to document every column.\u0026rdquo; True. But compare it to the alternative:\nHours lost by analysts guessing what columns mean Errors in reports because someone misinterpreted a field Audits that take weeks because nobody knows which data is sensitive Security incidents because a PII column wasn\u0026rsquo;t identified as such Documenting a column takes 30 seconds. Not documenting it can cost hours, days, or worse. And with LLMs, the startup cost has dropped further: documenting an entire source database in a few days is no longer a pipe dream.\nThe Bonus: Documentation as the Key to Talking to Your Data # Documentation serves two audiences: your human colleagues, and LLMs. And that\u0026rsquo;s where it gets interesting.\nSnowflake Cortex Analyst is Snowflake\u0026rsquo;s answer to \u0026ldquo;talk to my data\u0026rdquo;: ask a question in natural language and get back the correct SQL query. Ask for a specific KPI, filter by criteria, compare with another metric, without writing a line of SQL. It sounds like magic. And people instinctively think it takes months of engineering work to get there.\nIt doesn\u0026rsquo;t, if the documentation is clean.\nCortex Analyst works from a semantic model: a YAML file describing tables, columns, metrics, relationships between entities, and associated business vocabulary. The structure of this file is very close to what dbt already produces in its documentation files. The infrastructure exists. The models exist. If column descriptions are there, if relationships are documented, if key metrics are defined, the gap to Cortex Analyst is small.\nSnowflake Labs has even published dbt_semantic_view, a package that generates Snowflake Semantic Views directly from the dbt semantic model. These Semantic Views are natively usable by Cortex Analyst. The pipeline becomes: dbt documents, dbt_semantic_view publishes the semantic views, Cortex Analyst answers questions in natural language.\nA well-documented dbt project is 2 to 4 weeks away from a working talk-to-your-data experience, not 6 months. The remaining work (formalizing a few metrics, distinguishing dimensions from measures, adding business synonyms) is marginal compared to what\u0026rsquo;s already in place. It\u0026rsquo;s a quick win that only unlocks under one condition: treating documentation as a constraint from the start, not a task to do later.\nWhat I Take Away # In the end, what worked for me is treating data documentation with the same seriousness as transformation code. Not as a nice-to-have we\u0026rsquo;ll do \u0026ldquo;when we have time.\u0026rdquo; As an integral part of the pipeline, verified in CI, propagated automatically.\ndbt YAMLs are the ideal place for this. A single file serving human documentation, automated tests, and data governance. That sounds fancy when you say it that way, but in practice it\u0026rsquo;s just YAML files doing their job.\n","date":"16 janvier 2026","externalUrl":null,"permalink":"/blog/dbt-documentation-governance-yml/","section":"Blog","summary":"\u003cp\u003eDocumentation is the thing nobody wants to do. Especially in data. You have hundreds of columns across dozens of tables, and someone asks \u0026ldquo;what\u0026rsquo;s the \u003ccode\u003estatus\u003c/code\u003e field in the \u003ccode\u003eorders\u003c/code\u003e table?\u0026rdquo; And the honest answer is often \u0026ldquo;uh\u0026hellip; an enum I think that probably means X.\u0026rdquo;\u003c/p\u003e","title":"dbt: When Your YAML Files Become Your Data Governance","type":"blog"},{"content":"","date":"16 janvier 2026","externalUrl":null,"permalink":"/fr/tags/snowflake/","section":"Tags","summary":"","title":"Snowflake","type":"tags"},{"content":"Snowflake est fondamentalement SQL-first. C\u0026rsquo;est sa force : tout se pilote en SQL, des grants à la création d\u0026rsquo;objets en passant par les transformations. L\u0026rsquo;infrastructure, on a vu comment la dompter avec Terraform dans l\u0026rsquo;article précédent. Mais les transformations de données, elles, tombent dans un angle mort. Des scripts SQL éparpillés, pas de tests, pas de versioning sérieux, un seul collègue qui sait dans quel ordre tout lancer.\nC\u0026rsquo;est là que dbt entre en jeu. Et ce n\u0026rsquo;est pas un hasard si les deux outils fonctionnent si naturellement ensemble : Snowflake abstrait l\u0026rsquo;infrastructure physique, dbt abstrait l\u0026rsquo;orchestration des transformations. Les deux sont déclaratifs, SQL-first, conçus pour que le code soit la source de vérité. dbt n\u0026rsquo;est pas un framework générique de transformation de données, c\u0026rsquo;est l\u0026rsquo;outil qui complète Snowflake là où Snowflake ne complète pas lui-même : l\u0026rsquo;organisation, les tests, la documentation et le déploiement reproductible de tout ce SQL.\nLe problème avec les scripts SQL de transformation # Avant dbt, le pipeline de données classique ressemblait à ça : des scripts SQL numérotés, un scheduler quelconque, et un README qui expliquait dans quel ordre lancer quoi. Ou pire, des procédures stockées dans Snowflake avec une logique métier enfouie dedans.\nLe problème, c\u0026rsquo;est le même qu\u0026rsquo;avec les scripts SQL d\u0026rsquo;infrastructure : les DDL s\u0026rsquo;accumulent. Tu as create_orders_table.sql, puis add_status_column.sql, puis alter_orders_add_shipping_address.sql. Au bout d\u0026rsquo;un moment, personne ne sait ce que la table est censée être. Tu dois exécuter tous les scripts dans l\u0026rsquo;ordre pour reconstituer l\u0026rsquo;état réel, et tu espères qu\u0026rsquo;il n\u0026rsquo;y en a pas un qui manque.\nEt quand tu veux ajouter une colonne dans un pipeline en 5 phases (staging, enrichissement, agrégation, export, rapport), tu dois ouvrir 5 fichiers, ajouter la colonne dans chacun, puis coordonner le déploiement dans le bon ordre en prod. Sans framework, tu gères ça à la main. Et tu oublies presque toujours un modèle quelque part.\nQuant aux tests : écrire un test de non-nullité sur une colonne sans framework, c\u0026rsquo;est écrire un SELECT COUNT(*) WHERE col IS NULL et vérifier que le résultat est 0. Faisable une fois. Pénible à maintenir sur 200 colonnes.\nCe que dbt change fondamentalement # dbt (data build tool) prend une idée simple : les transformations de données, c\u0026rsquo;est du code. Et le code, ça se gère avec les mêmes pratiques que le reste : version control, tests, documentation, CI/CD.\nConcrètement, tu écris des modèles : des fichiers .sql qui définissent chacun une table ou une vue. Un modèle référence d\u0026rsquo;autres modèles avec une syntaxe {{ ref('nom_du_modele') }}. dbt résout automatiquement les dépendances et construit un DAG (graphe acyclique dirigé) de tes transformations.\n-- models/silver/orders_enriched.sql select o.order_id, o.created_at, o.status, c.email as customer_email, p.name as product_name from {{ ref(\u0026#39;stg_orders\u0026#39;) }} o left join {{ ref(\u0026#39;stg_customers\u0026#39;) }} c on o.customer_id = c.customer_id left join {{ ref(\u0026#39;stg_products\u0026#39;) }} p on o.product_id = p.product_id dbt sait que orders_enriched dépend de stg_orders, stg_customers et stg_products. Il les construit dans le bon ordre, automatiquement. Quand tu ajoutes une colonne à stg_orders, elle est disponible dans tous les modèles en aval sans que tu aies à coordonner quoi que ce soit.\nL\u0026rsquo;analogie avec Terraform # Le parallèle avec Terraform n\u0026rsquo;est pas superficiel. Les deux outils partagent la même philosophie fondamentale :\nÉtat souhaité, pas étapes. Tu ne dis pas \u0026ldquo;exécute cette transformation après celle-là\u0026rdquo;. Tu décris ce que chaque table doit contenir, et dbt figure comment y arriver.\nDéclaratif. Ton code décrit le résultat, pas le processus. SELECT ... FROM ref('source') dit \u0026ldquo;cette table contient ces colonnes calculées depuis cette source\u0026rdquo;, pas \u0026ldquo;prends cette table, jointure-la avec ça, filtre ça\u0026rdquo;.\nReproductible. dbt build reconstruit tout depuis zéro, dans le bon ordre, à chaque fois. Comme terraform apply reconstruit ton infra depuis les fichiers HCL.\nVersionné. Chaque changement dans une transformation est un commit. Tu peux voir qui a modifié quoi, pourquoi, et revenir en arrière.\nL\u0026rsquo;analogie a quand même une limite importante : dbt n\u0026rsquo;a pas de state distant. Si quelqu\u0026rsquo;un supprime une table dans Snowflake à la main, dbt n\u0026rsquo;en sait rien. Le prochain dbt run va simplement la recréer sans te signaler le drift. Terraform, lui, detecterait l\u0026rsquo;écart entre l\u0026rsquo;état réel et l\u0026rsquo;état souhaité et te proposerait de le corriger. Ce n\u0026rsquo;est pas un défaut critique, mais c\u0026rsquo;est à garder en tête : dbt est déclaratif sur ce qu\u0026rsquo;il crée, pas sur ce qui existe.\nL\u0026rsquo;extensibilité : ce qui compense largement # Ce manque de state distant, c\u0026rsquo;est un des rares points où Terraform fait mieux. Mais dbt compense avec quelque chose de différent : une extensibilité remarquable.\nLe dbt Hub regroupe des centaines de packages communautaires. Des tests additionnels, des macros utilitaires, des intégrations avec des sources spécifiques. dbt-utils est probablement dans tous les projets dbt sérieux : il ajoute des dizaines de macros et de tests que tu n\u0026rsquo;aurais pas envie d\u0026rsquo;écrire toi-même.\nMais la vraie puissance, c\u0026rsquo;est le système de macros Jinja. Tout ce que dbt fait en interne, tu peux le faire aussi. Ce qui veut dire que les fonctionnalités réservées à dbt Cloud sont souvent reproductibles en dbt Core avec quelques macros.\nLa détection de breaking changes dans les schémas ? On en parle dans un prochain article, et c\u0026rsquo;est exactement ce genre de feature qu\u0026rsquo;on peut implémenter soi-même. L\u0026rsquo;alerting sur la fraîcheur des sources ? Des macros. La génération automatique de documentation ? Des macros. dbt Core n\u0026rsquo;est pas une version appauvrie de dbt Cloud, c\u0026rsquo;est une fondation sur laquelle tu construis ce dont tu as besoin.\ndbt comme infrastructure, pas juste comme ETL runner # Beaucoup d\u0026rsquo;équipes utilisent dbt comme un runner ETL : elles matérialisent des tables, et font tourner dbt run toutes les heures dans Airflow ou Prefect. C\u0026rsquo;est une utilisation valide. Mais c\u0026rsquo;est loin d\u0026rsquo;épuiser ce que dbt peut faire.\nSnowflake a un concept qui change l\u0026rsquo;équation : les Dynamic Tables. Au lieu de matérialiser une table et la rafraîchir manuellement, tu déclares une Dynamic Table avec un lag cible (\u0026ldquo;cette table doit être à jour à moins de 1 heure\u0026rdquo;). Snowflake gère le rafraîchissement automatiquement, en propageant les changements dans le DAG.\nCombiné avec dbt, ça veut dire que tu n\u0026rsquo;as plus besoin d\u0026rsquo;un orchestrateur externe pour gérer les rafraîchissements. Tu déclares tes modèles comme des Dynamic Tables dans dbt, tu déploies, et Snowflake s\u0026rsquo;occupe du reste. dbt devient ce qu\u0026rsquo;il est vraiment : un outil de déclaration d\u0026rsquo;infrastructure de données, pas un scheduler.\n# dbt_project.yml models: mon_projet: silver: +materialized: dynamic_table +target_lag: \u0026#39;1 hour\u0026#39; +snowflake_warehouse: TRANSFORMING_L Les targets : un environnement par contexte # Un des concepts les plus pratiques de dbt, c\u0026rsquo;est le système de targets. Un target, c\u0026rsquo;est une configuration de déploiement : quelle database, quel schéma, quel warehouse utiliser.\nEn pratique, chaque développeur a un target dev par défaut qui pointe vers sa propre database isolée, avec un petit warehouse pour ne pas bruler des crédits inutilement :\n# profiles.yml mon_projet: target: dev outputs: dev: database: DEV_JEAN schema: silver warehouse: DEV_XS prod: database: PROD schema: silver warehouse: TRANSFORMING_L Quand Jean lance dbt run, il déploie dans DEV_JEAN.silver. Il ne peut pas accidentellement écraser la production. Pour déployer en prod, il faut être explicite : dbt run --target prod. C\u0026rsquo;est un opt-in volontaire, pas le comportement par défaut.\nCe qui est élégant, c\u0026rsquo;est que dbt permet d\u0026rsquo;overrider la database, le schéma, et même le warehouse à plusieurs niveaux : au niveau du projet, du dossier, du modèle individuel. Tu peux avoir un modèle spécifique qui tourne toujours sur un warehouse dédié, indépendamment du target. La configuration se compose.\nSélectionner avec précision dans le DAG # Une fois que tu as un DAG de 200 modèles, tu ne veux pas systématiquement tout rebuilder. dbt a un système de sélection expressif pour cibler exactement ce dont tu as besoin.\nLa syntaxe + contrôle la direction dans le DAG :\n# Juste le modèle dbt run --select orders_enriched # Le modèle et tout ce qui est en amont (ses dépendances) dbt run --select +orders_enriched # Le modèle et tout ce qui est en aval (ce qui en dépend) dbt run --select orders_enriched+ # Le modèle, ses dépendances ET ses dépendants dbt run --select +orders_enriched+ Tu peux aussi sélectionner par tag. Si tu tagges tes modèles retail :\n-- models/silver/orders_enriched.sql {{ config(tags=[\u0026#39;retail\u0026#39;, \u0026#39;orders\u0026#39;]) }} Tu peux alors cibler tout le domaine retail en une commande :\ndbt run --select tag:retail Combiné avec state:modified, ça donne un contrôle très précis sur ce qui tourne en CI : seulement les modèles modifiés et leurs dépendants directs.\nSources et exposures : les deux bouts du DAG # dbt gère non seulement les transformations intermédiaires, mais aussi les deux extrémités du pipeline.\nLes sources sont les tables que tu ne contrôles pas : tes données brutes qui arrivent via Fivetran, Airbyte, ou un autre outil de réplication. Tu les déclares dans les YAML :\nsources: - name: shopify database: RAW schema: shopify tables: - name: orders - name: customers - name: products Ça te permet de les référencer avec {{ source('shopify', 'orders') }} dans tes modèles, de leur associer des tests, et de monitorer leur fraîcheur. Si les données Shopify n\u0026rsquo;ont pas été mises à jour depuis 6 heures, dbt peut te l\u0026rsquo;alerter avant que tes rapports soient périmés.\nCes descriptions de sources s\u0026rsquo;intègrent aussi avec Snowflake Horizon : les métadonnées que tu déclares dans dbt remontent dans le catalogue de données Snowflake, visible par tous ceux qui ont accès à l\u0026rsquo;instance.\nLes exposures sont l\u0026rsquo;autre bout : les consommateurs de tes données que dbt ne gère pas. Un dashboard Tableau, une API, un fichier exporté vers un partenaire. Tu les déclares aussi :\nexposures: - name: tableau_revenue_dashboard type: dashboard owner: name: Équipe BI depends_on: - ref(\u0026#39;daily_revenue\u0026#39;) - ref(\u0026#39;top_products\u0026#39;) Ça complète le lignage : tu peux voir dans le DAG non seulement comment les données se transforment, mais aussi où elles finissent. Quand tu modifies daily_revenue, dbt sait que le dashboard Tableau en dépend et peut t\u0026rsquo;alerter.\nLes assets complémentaires : seeds et UDFs # Deux éléments méritent d\u0026rsquo;être mentionnés pour compléter le tableau.\nLes seeds sont des fichiers CSV que dbt gère comme des tables. Des tables de référence, des mappings, des configurations statiques. Au lieu d\u0026rsquo;avoir un fichier CSV quelque part sur un serveur ou dans un Google Sheet, tu le versiones dans le repo dbt et dbt crée la table correspondante dans Snowflake.\nseeds/ product_categories.csv country_codes.csv shipping_carriers.csv Les UDFs (User Defined Functions) Snowflake ne sont pas gérées nativement par dbt, mais tu peux les déployer via des pre-hooks ou des macros. C\u0026rsquo;est la limite de la métaphore infrastructure-as-code : certains objets Snowflake restent dans le territoire Terraform.\nLe manifest : le plan compilé de ta stack # Quand tu lances dbt parse, dbt compile tout ton projet et produit un manifest.json. C\u0026rsquo;est l\u0026rsquo;artifact central : une représentation complète et lisible par machine de tout ce que ton projet sait faire.\nLe manifest contient les modèles, leurs colonnes déclarées, leurs dépendances, les tests, les sources, les exposures. Tout.\nC\u0026rsquo;est l\u0026rsquo;équivalent du state Terraform pour tes données. Et comme le state Terraform, il peut être utilisé pour faire des comparaisons : qu\u0026rsquo;est-ce qui a changé entre la version précédente et la version actuelle ? C\u0026rsquo;est exactement ce qu\u0026rsquo;on exploitera dans un prochain article pour détecter les breaking changes avant qu\u0026rsquo;ils arrivent en production.\nPourquoi ça change la dynamique d\u0026rsquo;équipe # Avant dbt, les transformations étaient souvent la propriété d\u0026rsquo;une personne. Quelqu\u0026rsquo;un savait dans quel ordre lancer les scripts, quelles tables dépendaient de quoi, où était la logique de déduplication. La connaissance était tribale.\nAvec dbt, n\u0026rsquo;importe quel data engineer peut ouvrir le repo, voir le DAG, comprendre les dépendances, modifier un modèle, et déployer dans son environnement dev sans risque. La connaissance est dans le code.\nC\u0026rsquo;est le même gain qu\u0026rsquo;on a eu avec Terraform pour l\u0026rsquo;infra. On passe de \u0026ldquo;demande à la personne qui sait\u0026rdquo; à \u0026ldquo;lis le code\u0026rdquo;.\nPourquoi dbt et pas SQLMesh ? # Quand j\u0026rsquo;ai commencé à évaluer des outils pour gérer mes transformations de façon déclarative, SQLMesh était sur ma liste. C\u0026rsquo;est un outil sérieux : open source, Apache 2.0, rétrocompatible avec les projets dbt existants, avec des concepts intéressants comme la détection automatique des breaking changes et l\u0026rsquo;évaluation incrémentale native.\nSur le papier, SQLMesh est techniquement plus rigoureux que dbt sur plusieurs points. Mais j\u0026rsquo;ai choisi dbt pour une raison simple : l\u0026rsquo;effet de masse.\ndbt est de loin l\u0026rsquo;outil le plus utilisé dans l\u0026rsquo;écosystème data. Ce qui veut dire :\nDes centaines de packages dans le dbt Hub - des tests, des macros, des utilitaires déjà écrits Une communauté active avec des réponses à presque tous les problèmes que tu vas rencontrer Des intégrations natives dans tous les outils de la stack : Fivetran, Hightouch, Metabase, Tableau, et l\u0026rsquo;essentiel des data catalogues Des data engineers qui connaissent déjà dbt quand ils arrivent dans une équipe Et depuis 2024, Snowflake a formalisé ce partenariat avec une intégration encore plus profonde : la dbt Snowflake Native App. Tu peux désormais orchestrer et monitorer tes jobs dbt directement depuis Snowflake, sans infrastructure externe. dbt tourne dans ton instance Snowflake, pas à côté.\nSQLMesh aurait probablement aussi bien fait le job. Mais quand tu choisis une infrastructure, tu choisis aussi un écosystème. Et l\u0026rsquo;écosystème dbt est imbattable pour l\u0026rsquo;instant.\ndbt + Snowflake : le duo pour un data engineer qui vient du dev # Ce qui rend cette combinaison particulièrement solide, c\u0026rsquo;est que les deux outils partagent la même philosophie et qu\u0026rsquo;ils se complètent sans se chevaucher.\nTerraform déclare l\u0026rsquo;infrastructure : les databases, les schémas, les rôles, les permissions, les politiques de masquage. dbt déclare les transformations : les modèles, les tests, la documentation, le lignage. Les deux sont du code, versionnés dans git, déployés via des pipelines CI, avec des environnements isolés par développeur.\nMais au-delà de la philosophie partagée, l\u0026rsquo;intégration est concrète. Les Dynamic Tables Snowflake se matérialisent nativement dans dbt. Les descriptions de colonnes dans tes YAML remontent dans Snowflake Horizon via persist_docs. Et depuis 2024, dbt peut tourner directement dans ton instance Snowflake via la dbt Snowflake Native App, sans infrastructure externe à gérer.\nLa stack complète ressemble à ça : Terraform gère ce qui est au-dessus des données, dbt gère ce qui est dedans, et Snowflake est le socle sur lequel les deux s\u0026rsquo;appuient. Chaque couche a sa responsabilité, chaque couche est du code. Pour quelqu\u0026rsquo;un qui vient du dev, c\u0026rsquo;est exactement ce à quoi une stack data devrait ressembler. Pas des scripts SQL dans un dossier partagé, pas de connaissances tribales, pas de déploiement manuel un vendredi soir.\nLa rigueur qu\u0026rsquo;on applique au code applicatif n\u0026rsquo;a aucune raison de ne pas s\u0026rsquo;appliquer aux données. dbt est l\u0026rsquo;outil qui rend ça possible, et Snowflake est la plateforme sur laquelle cette rigueur prend tout son sens.\n","date":"26 décembre 2025","externalUrl":null,"permalink":"/fr/blog/dbt-data-infrastructure-as-code/","section":"Blog","summary":"\u003cp\u003eSnowflake est fondamentalement SQL-first. C\u0026rsquo;est sa force : tout se pilote en SQL, des grants à la création d\u0026rsquo;objets en passant par les transformations. L\u0026rsquo;infrastructure, on a vu comment la dompter avec Terraform dans \u003ca\n  href=\"https://damiengoehrig.ca/fr/blog/snowflake-terraform-infrastructure-as-code/\"\u003el\u0026rsquo;article précédent\u003c/a\u003e. Mais les transformations de données, elles, tombent dans un angle mort. Des scripts SQL éparpillés, pas de tests, pas de versioning sérieux, un seul collègue qui sait dans quel ordre tout lancer.\u003c/p\u003e","title":"dbt : tes transformations de données comme de l'infrastructure","type":"blog"},{"content":"","date":"26 décembre 2025","externalUrl":null,"permalink":"/fr/tags/sql/","section":"Tags","summary":"","title":"SQL","type":"tags"},{"content":"","date":"5 décembre 2025","externalUrl":null,"permalink":"/fr/categories/infrastructure/","section":"Categories","summary":"","title":"Infrastructure","type":"categories"},{"content":"","date":"5 décembre 2025","externalUrl":null,"permalink":"/fr/tags/infrastructure-as-code/","section":"Tags","summary":"","title":"Infrastructure as Code","type":"tags"},{"content":"Il y a un moment, dans la vie d\u0026rsquo;un data engineer, où tu te retrouves avec un fichier SQL de 300 lignes qui crée des rôles, des grants, des warehouses, et tu te demandes comment t\u0026rsquo;en es arrivé là. C\u0026rsquo;est mon histoire.\nSnowflake : tout en SQL, pour le meilleur et pour le pire # Snowflake a réussi quelque chose que peu de plateformes accomplissent : abstraire complètement l\u0026rsquo;infrastructure physique tout en conservant un contrôle granulaire sur tout ce qui compte. Pas de serveurs à maintenir, pas de clusters à dimensionner. Juste des bases de données, des schémas, des warehouses, des rôles, et des commandes SQL pour tout piloter.\nSnowsight, son interface graphique, est capable. Tu peux y créer des objets, gérer des accès, visualiser tes données. Mais comme tout outil qui existe à la fois en version UI et en version programmatique, la vraie puissance est côté code. L\u0026rsquo;UI te donne accès aux fonctionnalités. Le SQL te donne le contrôle. La manipulation programmatique te donne la reproductibilité.\nC\u0026rsquo;est l\u0026rsquo;analogie classique avec les outils en ligne de commande : ils paraissent moins accessibles qu\u0026rsquo;une interface graphique, mais ils se scriptent, se versionnent, s\u0026rsquo;automatisent. Chaque action devient reproductible, auditable, intégrable dans un pipeline. Un GRANT exécuté dans Snowsight disparaît dans le néant dès que tu fermes l\u0026rsquo;onglet. Le même GRANT déclaré dans du code Terraform est tracé, reviewable, réversible.\nLe problème, c\u0026rsquo;est que Snowflake est tellement accessible en SQL ad hoc qu\u0026rsquo;on finit par tout faire comme ça. Un GRANT par-ci, un nouveau rôle via la console, un warehouse créé en urgence un mardi soir. Chacun de ces gestes est anodin. Ensemble, ils deviennent une infrastructure impossible à auditer.\nL\u0026rsquo;ère des scripts SQL # Au départ, quand j\u0026rsquo;ai commencé à monter une infrastructure Snowflake, j\u0026rsquo;ai fait ce que tout le monde fait : des fichiers .sql. Un script pour créer les databases, un autre pour les schémas, un autre pour les rôles. Simple, direct, ça marche.\nSauf que ça marche jusqu\u0026rsquo;à un certain point.\nPremière semaine : 5 fichiers SQL, bien organisés. Premier mois : 15 fichiers, quelques IF NOT EXISTS pour l\u0026rsquo;idempotence. Troisième semaine : tu te rends compte que tu dois modifier un rôle et tu parcours 4 fichiers pour être sûr de pas oublier un grant quelque part. Et tu finis par te demander si le état actuel de Snowflake correspond vraiment à ce qui est dans tes scripts, ou si quelqu\u0026rsquo;un a fait un GRANT à la main dans la console un mardi soir.\nL\u0026rsquo;épisode des migrations # Ensuite j\u0026rsquo;ai essayé les migrations. Comme en développement applicatif : des fichiers numérotés, chacun avec un changement incrémental. 001_create_databases.sql, 002_add_marketing_role.sql, 003_fix_grant_on_silver.sql\u0026hellip;\nSur le papier, c\u0026rsquo;est mieux. T\u0026rsquo;as un historique. Tu peux retracer l\u0026rsquo;évolution. Mais en pratique :\nSi quelqu\u0026rsquo;un fait un changement manuel, les migrations et la réalité divergent silencieusement Faire un rollback d\u0026rsquo;un REVOKE ou d\u0026rsquo;un DROP ROLE, c\u0026rsquo;est pas comme un ALTER TABLE, les effets en cascade sont imprévisibles T\u0026rsquo;as aucune idée de l\u0026rsquo;état actuel sans exécuter un audit complet Et surtout, tu te retrouves avec 50 fichiers de migrations et plus personne sait ce que l\u0026rsquo;infrastructure est censée être, juste ce qu\u0026rsquo;elle est devenue L\u0026rsquo;évidence : Terraform # Et puis un jour, je me suis demandé s\u0026rsquo;il existait un provider Terraform pour Snowflake. La réponse : oui, et il est maintenu par Snowflake directement.\nÇa m\u0026rsquo;a paru comme une évidence. Terraform, c\u0026rsquo;est exactement le bon outil pour ce problème :\nDéclaratif : tu décris l\u0026rsquo;état souhaité, pas les étapes pour y arriver Plan avant apply : terraform plan te montre exactement ce qui va changer avant que ça change Source de vérité unique : le code Terraform décrit l\u0026rsquo;état souhaité de l\u0026rsquo;infrastructure, pas une approximation, pas un historique de migrations Historique via git : chaque changement est un commit, reviewable, réversible Idempotent : tu peux l\u0026rsquo;exécuter 10 fois, ça donne le même résultat En comparaison avec les scripts SQL : si quelqu\u0026rsquo;un fait un changement manuel dans la console Snowflake, le prochain terraform plan te le montre comme un drift. Tu vois la différence entre l\u0026rsquo;état réel et l\u0026rsquo;état souhaité. Avec des scripts SQL, tu ne vois rien.\n(En vrai, Terraform a ses propres irritants : le state qui se corrompt, les import pénibles, les changements breaking du provider entre deux versions. Mais ces problèmes sont gérables, et le gain en visibilité compense largement.)\nLes rôles : penser en couches # Le concept qui m\u0026rsquo;a le plus aidé, c\u0026rsquo;est de structurer les rôles en trois niveaux. C\u0026rsquo;est une pratique recommandée par Snowflake dans leur documentation sur le contrôle d\u0026rsquo;accès, et documentée par plusieurs architectes Snowflake (exemple sur le blog officiel).\nNiveau 1 : Les rôles système Snowflake. ACCOUNTADMIN, SYSADMIN, SECURITYADMIN. Tu ne les crées pas, ils existent déjà. Mais tu configures Terraform pour utiliser le bon rôle au bon endroit, SYSADMIN pour créer des databases et des warehouses, SECURITYADMIN pour les rôles et les grants. Principe du moindre privilège.\nNiveau 2 : Les rôles d\u0026rsquo;accès (access roles). Ce sont des rôles techniques, granulaires, qui donnent accès à un schéma spécifique à un niveau spécifique. Genre SILVER_RO (lecture seule sur le schéma Silver), GOLD_RW (lecture-écriture sur Gold), STAGING_FULL (accès complet au schéma de staging). La convention de nommage est importante : en lisant le nom du rôle, tu sais exactement ce qu\u0026rsquo;il fait.\nNiveau 3 : Les rôles fonctionnels (functional roles). Ce sont les rôles business, ceux que tu assignes aux humains. Un rôle ANALYST, un rôle ENGINEER, un rôle REPORTING. Chaque rôle fonctionnel agrège plusieurs rôles d\u0026rsquo;accès. Le rôle Analyst obtient SILVER_RO + GOLD_RO. L\u0026rsquo;engineer obtient un accès plus large.\nLe flux est simple : Utilisateur → Rôle fonctionnel → Rôles d\u0026rsquo;accès → Permissions sur les schémas.\nL\u0026rsquo;avantage de cette approche, c\u0026rsquo;est que quand un nouvel analyste arrive, tu l\u0026rsquo;assignes au rôle fonctionnel ANALYST et il a automatiquement accès à tout ce dont il a besoin. Pas de liste de grants à maintenir manuellement.\nLes grants en cascade # Un des aspects les plus satisfaisants de cette approche, c\u0026rsquo;est la cascade des grants. Dans Snowflake, tu peux créer une hiérarchie de rôles : un rôle peut \u0026ldquo;contenir\u0026rdquo; un autre rôle.\nConcrètement, si tu as trois niveaux d\u0026rsquo;accès pour un schéma (lecture, écriture, création), tu structures ça en cascade :\nLe rôle Create hérite du rôle Read-Write Le rôle Read-Write hérite du rôle Read-Only Tu n\u0026rsquo;as besoin d\u0026rsquo;accorder les privilèges qu\u0026rsquo;une seule fois à chaque niveau Quand tu assignes le rôle Create à quelqu\u0026rsquo;un, il obtient automatiquement les permissions d\u0026rsquo;écriture et de lecture par héritage. Pas de duplication de grants, pas de maintenance supplémentaire.\nLes future grants : anticiper l\u0026rsquo;avenir # Un pattern critique dans Snowflake : les future grants. Quand tu crées un rôle avec SELECT sur un schéma, ça s\u0026rsquo;applique aux tables qui existent maintenant. Mais quand dbt crée un nouveau modèle demain ? Sans future grants, personne n\u0026rsquo;y a accès.\nTerraform permet de déclarer des future grants : \u0026ldquo;tous les objets futurs dans ce schéma hériteront automatiquement de ces permissions.\u0026rdquo; C\u0026rsquo;est le genre de détail qui fait la différence entre une infra qui fonctionne le jour 1 et une infra qui fonctionne encore 6 mois plus tard quand l\u0026rsquo;équipe data a ajouté 50 modèles.\nLes utilisateurs : configuration, pas code # L\u0026rsquo;ajout d\u0026rsquo;un utilisateur, dans cette approche, ne nécessite pas d\u0026rsquo;écrire du code Terraform. Tu remplis une configuration :\nSon identité (nom, email) Son équipe (marketing, finance, data engineering\u0026hellip;) Est-ce un admin ? A-t-il besoin d\u0026rsquo;un sandbox de développement ? À partir de cette configuration, Terraform calcule et génère automatiquement :\nLe compte utilisateur L\u0026rsquo;assignation au rôle fonctionnel de son équipe Le warehouse par défaut L\u0026rsquo;accès sandbox si applicable Ajouter un nouveau membre, c\u0026rsquo;est modifier quelques lignes de configuration, faire un terraform plan pour vérifier, et terraform apply. Pas de SQL à écrire, pas de grants à chercher.\nLa frontière Terraform / dbt # Un point important : où s\u0026rsquo;arrête Terraform et où commence dbt ?\nMa vision : Terraform gère tout ce qui est au-dessus du schéma. dbt gère tout ce qui est en dessous.\nTerraform s\u0026rsquo;occupe de :\nCréer les databases et les schémas Créer les warehouses Gérer les rôles et les permissions Définir les politiques de masquage Configurer le monitoring dbt s\u0026rsquo;occupe de :\nCréer les tables et les vues dans les schémas Transformer les données Appliquer les tags de gouvernance aux colonnes Documenter les modèles Tester la qualité des données L\u0026rsquo;infrastructure (Terraform) évolue lentement, un nouveau schéma par mois, un nouveau rôle par trimestre. Les transformations (dbt) évoluent tous les jours : nouveaux modèles, logique métier, corrections.\nCette séparation fait que deux équipes peuvent travailler en parallèle sans se marcher dessus. L\u0026rsquo;ingénieur plateforme gère le Terraform, le data engineer gère le dbt. Chacun dans son repo, avec son propre cycle de déploiement.\nLe masquage de données : un bon exemple d\u0026rsquo;intégration # Un exemple concret de comment Terraform et dbt collaborent : le masquage de données.\nTerraform crée les politiques de masquage par tag : \u0026ldquo;si une colonne est taguée PII, masquer la valeur sauf pour les rôles qui ont le droit de la voir.\u0026rdquo; Il crée aussi les tags et les rôles de démasquage.\ndbt, de son côté, applique les tags aux colonnes quand il crée les modèles : \u0026ldquo;cette colonne email est PII, cette colonne montant est FINANCIAL.\u0026rdquo;\nLe résultat : quand un utilisateur marketing fait un SELECT * FROM clients, les emails sont masqués automatiquement. L\u0026rsquo;utilisateur avec le bon rôle voit les valeurs réelles. Personne n\u0026rsquo;a eu à écrire de logique de masquage dans le SQL, c\u0026rsquo;est géré par la combinaison infrastructure + metadata.\nAuditer et itérer # Un des bénéfices les plus sous-estimés de cette approche : l\u0026rsquo;auditabilité.\nQuand un audit de sécurité demande \u0026ldquo;qui a accès à quoi ?\u0026rdquo;, la réponse est dans le code. Pas dans une console Snowflake où il faut naviguer 15 pages. Pas dans un document Excel maintenu à la main. Dans le code, versionné, avec l\u0026rsquo;historique complet de qui a changé quoi et quand.\nEt quand tu veux ajouter une nouvelle équipe, un nouveau schéma, ou modifier des permissions, c\u0026rsquo;est un processus standard : modifier la config, ouvrir une PR, reviewer, merger, appliquer. Le même workflow que pour du code applicatif.\nAssisté par un LLM # Un dernier point qui vaut la peine d\u0026rsquo;être mentionné : une fois que ton infrastructure est déclarée sous forme de code structuré, un LLM devient un assistant redoutablement efficace. Tu peux lui demander de créer un nouveau rôle fonctionnel, d\u0026rsquo;ajouter un utilisateur, de modifier des permissions, et il produit du Terraform valide qui suit tes conventions existantes.\nAvec des scripts SQL ad hoc, c\u0026rsquo;est beaucoup plus risqué. L\u0026rsquo;IA ne sait pas quel est l\u0026rsquo;état actuel de l\u0026rsquo;infra. Avec Terraform, l\u0026rsquo;état souhaité est dans le code, et le plan valide que le résultat est correct avant toute application. L\u0026rsquo;IA propose, Terraform vérifie.\nLe vrai gain # Au final, ce qui a changé, c\u0026rsquo;est pas la technologie, c\u0026rsquo;est la confiance. Tu sais que l\u0026rsquo;état de ton infrastructure correspond au code. Tu sais que les permissions sont correctes. Tu sais que personne n\u0026rsquo;a fait un changement non documenté. Et quand quelqu\u0026rsquo;un te demande d\u0026rsquo;ajouter un accès ou de créer un nouveau schéma, c\u0026rsquo;est 5 minutes de configuration au lieu d\u0026rsquo;une demi-heure de scripts SQL avec la peur de casser quelque chose.\nLes scripts SQL, c\u0026rsquo;est de l\u0026rsquo;artisanat. Les migrations, c\u0026rsquo;est de l\u0026rsquo;artisanat mieux organisé. Terraform, c\u0026rsquo;est pas parfait non plus : le state peut être fragile, les erreurs de plan sont parfois cryptiques, et le provider Snowflake a ses propres bugs. Mais au moins, tu sais où t\u0026rsquo;en es. Et quand quelque chose casse, tu sais pourquoi.\n","date":"5 décembre 2025","externalUrl":null,"permalink":"/fr/blog/snowflake-terraform-infrastructure-as-code/","section":"Blog","summary":"\u003cp\u003eIl y a un moment, dans la vie d\u0026rsquo;un data engineer, où tu te retrouves avec un fichier SQL de 300 lignes qui crée des rôles, des grants, des warehouses, et tu te demandes comment t\u0026rsquo;en es arrivé là. C\u0026rsquo;est mon histoire.\u003c/p\u003e","title":"Snowflake + Terraform : Arrêter de gérer son infra data en SQL","type":"blog"},{"content":"","date":"5 décembre 2025","externalUrl":null,"permalink":"/fr/tags/terraform/","section":"Tags","summary":"","title":"Terraform","type":"tags"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/tags/aws/","section":"Tags","summary":"","title":"AWS","type":"tags"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/categories/backend/","section":"Categories","summary":"","title":"Backend","type":"categories"},{"content":"Fait que j\u0026rsquo;ai construit cette app de Planning Poker. Tu sais, le truc agile d\u0026rsquo;estimation où l\u0026rsquo;équipe se rassemble pour voter sur les story points ? Ouais, j\u0026rsquo;ai décidé de la faire web et temps réel pokerplanning.net. Et puis\u0026hellip; disons juste que je suis devenu un peu ambitieux avec le déploiement.\nL\u0026rsquo;idée # Les sessions de Planning Poker c\u0026rsquo;est généralement le chaos dans une salle de conférence - quelqu\u0026rsquo;un écrit sur un tableau, quelqu\u0026rsquo;un d\u0026rsquo;autre crie son estimation, pis la moitié de l\u0026rsquo;équipe est dans la lune. Le problème est simple : t\u0026rsquo;as besoin de quelque chose qui marche instantanément, qui demande pas d\u0026rsquo;inscription, pis qui juste\u0026hellip; marche.\nFait que j\u0026rsquo;ai pris Go pour le backend (rapide, compilé, un bon modèle de concurrence), PocketBase comme couche tout-en-un pour la base de données et l\u0026rsquo;authentification, pis j\u0026rsquo;ai ajouté htmx + Alpine.js sur le frontend pour cette sensation réactive sans bâtir une app React complète. WebSockets pour les mises à jour temps réel. Simple.\nPourquoi PocketBase ? (Le point de vue du gars WordPress) # Voici l\u0026rsquo;affaire - j\u0026rsquo;ai passé des années à faire du développement WordPress. Je l\u0026rsquo;ai aimé, détesté, la routine habituelle. Quand j\u0026rsquo;ai transitionné vers du vrai développement logiciel, j\u0026rsquo;ai commencé à faire toute la danse : choisir un ORM, configurer les migrations, brancher l\u0026rsquo;authentification, bâtir ton routeur, gérer les changements de schéma de base de données\u0026hellip; c\u0026rsquo;est épuisant.\nPocketBase m\u0026rsquo;a fait penser à l\u0026rsquo;équivalent Go de ce que WordPress était pour moi - une base de référence sensée tout-en-un. T\u0026rsquo;as une couche de base de données, l\u0026rsquo;authentification, une interface d\u0026rsquo;admin, des migrations qui marchent pour vrai, pis un routeur HTTP. C\u0026rsquo;est assez structuré pour avancer vite, mais assez flexible pour étendre.\nJe voulais pas passer la prochaine semaine à gosser avec Gorm, écrire des fichiers de migration, bâtir un middleware d\u0026rsquo;authentification pis configurer un routeur. Je voulais livrer quelque chose en quelques jours. PocketBase m\u0026rsquo;a permis de me concentrer sur le vrai problème : faire marcher Planning Poker en temps réel.\nPis si ça se transforme un jour en quelque chose que je veux monétiser comme SaaS, je peux bâtir par-dessus cette fondation. La nature headless de PocketBase veut dire que je peux éventuellement changer le frontend, ajouter une couche de tarification, peu importe. C\u0026rsquo;est une base solide.\nSQLite : Le héros méconnu des bases de données # Pour vrai : j\u0026rsquo;adore Postgres. Sérieusement. Mais pour ce projet-là ? SQLite c\u0026rsquo;était le bon choix.\nLa plupart du monde réalise pas ça, mais SQLite c\u0026rsquo;est le moteur de base de données le plus déployé au monde. Ton téléphone a probablement une douzaine de bases SQLite qui roulent en ce moment. Android, iOS, Firefox, Chrome - tout SQLite. C\u0026rsquo;est plate, fiable, pis vraiment sous-estimé.\nPour une app Planning Poker qui a pas besoin de mise à l\u0026rsquo;échelle horizontale ou de transactions multi-utilisateurs complexes à grande échelle, SQLite c\u0026rsquo;est exactement ce qu\u0026rsquo;il te faut. Pas de serveur de base de données séparé à gérer, pas de maux de tête de pooling de connexions, pas d\u0026rsquo;appels de crise \u0026ldquo;est-ce que la DB est down ?\u0026rdquo; à 3h du matin. Ça vit dans un fichier. Tu peux le sauvegarder, le versionner, le déplacer.\nJ\u0026rsquo;ai fait un choix délibéré cette fois : pas trop complexifier la base de données. L\u0026rsquo;app a pas besoin de la complexité de Postgres. SQLite gère 20 000 connexions WebSocket concurrentes sur un t3.micro sans broncher. C\u0026rsquo;est en masse.\nCe que ça fait # La boucle principale est pas mal directe :\nCréer une salle, pas besoin de connexion Le monde rejoint avec un nom Tu configures un tour de vote avec Fibonacci ou des valeurs personnalisées Tout le monde vote en même temps Révélation et discussion On recommence Y\u0026rsquo;a aussi des affaires basées sur les rôles - tu peux être un voteur ou juste spectateur. Les créateurs de salle peuvent verrouiller les choses comme ils veulent. Tout se synchronise en temps réel via WebSocket, fait que quand quelqu\u0026rsquo;un vote, tout le monde le voit instantanément (ou voit qu\u0026rsquo;il a voté, du moins - les votes sont cachés jusqu\u0026rsquo;à la révélation).\nLa gestion d\u0026rsquo;état est propre. Les tours ont des états : vote, révélé, terminé. Les participants suivent qui est où. Les votes vivent dans la base de données. Les salles expirent automatiquement après 24 heures fait que tu stockes pas de données mortes pour toujours.\nPerformance ? Ouais, j\u0026rsquo;ai vérifié # C\u0026rsquo;est ici que ça devient un peu absurde. Sur un t3.micro (1 vCPU, 1GB RAM), ce truc-là peut gérer :\n2 000-3 000 salles concurrentes 20 000-30 000 connexions WebSocket C\u0026rsquo;est\u0026hellip; pas mal plus que ce dont t\u0026rsquo;aurais jamais besoin pour du Planning Poker. Mais j\u0026rsquo;allais pas livrer quelque chose qui pourrait pas gérer son propre succès, non ?\nJ\u0026rsquo;ai intégré de la diffusion asynchrone avec livraison de messages non-bloquante, des canaux d\u0026rsquo;envoi par client avec mise en mémoire tampon, du verrouillage fin. Y\u0026rsquo;a des endpoints de surveillance pour que tu puisses jeter un œil aux métriques en temps réel. Les clients lents se font détecter pis nettoyer automatiquement. C\u0026rsquo;est beaucoup trop complexe pour ce que ça fait, mais ça marche.\nLe rabbit hole du déploiement # Pis là j\u0026rsquo;suis arrivé au déploiement.\nAu lieu de juste le lancer sur un serveur avec SSH, j\u0026rsquo;ai décidé d\u0026rsquo;aller en mode entreprise. Voici la configuration :\nGitHub Actions surveille les tags git Construit une image Docker multi-architecture Pousse vers GitHub Container Registry Déclenche une commande AWS Systems Manager Run Command L\u0026rsquo;instance EC2 tire l\u0026rsquo;image Docker Compose démarre les conteneurs Les vérifications de santé valident que tout est en ligne Zéro clé SSH exposée. Aucun port ouvert sauf HTTP/HTTPS. Tout est audité dans CloudTrail. Pis ouais, j\u0026rsquo;suis allé full Terraform sur l\u0026rsquo;infrastructure - EC2, groupes de sécurité, rôles IAM, toute la patente.\nEst-ce excessif pour une app Planning Poker ? 100%. Est-ce que j\u0026rsquo;aurais pu juste SSH dans une machine pis la rouler ? Ouais. Mais de cette façon-là, déployer c\u0026rsquo;est littéralement juste git tag v1.0.0 \u0026amp;\u0026amp; git push origin v1.0.0. Deux minutes plus tard c\u0026rsquo;est en ligne. Pis t\u0026rsquo;as une piste d\u0026rsquo;audit, des capacités de rollback automatique, pis de l\u0026rsquo;infrastructure-as-code. Fait que vraiment, je suis juste minutieux.\nStack technique (la vraie) # Backend : Go 1.25, PocketBase 0.30 (qui est essentiellement Echo + SQLite + interface d\u0026rsquo;admin dans un seul binaire) Frontend : htmx 2.0 pour AJAX/WebSocket, Alpine.js 3.14 pour l\u0026rsquo;interactivité, Templ pour le templating Base de données : SQLite (inclus dans PocketBase) Déploiement : Docker, Docker Compose, Terraform, GitHub Actions, AWS SSM Surveillance : Endpoint de métriques intégré, vérifications de santé Pourquoi cette stack ? # PocketBase c\u0026rsquo;était la vraie découverte. Tout le monde veut bâtir un backend, mais PocketBase t\u0026rsquo;en donne juste un. Base de données, migrations, interface d\u0026rsquo;admin, authentification, tout. J\u0026rsquo;ai juste eu à brancher le hub WebSocket pis la logique métier. C\u0026rsquo;est du temps pas passé à gosser sur du boilerplate.\nhtmx + Alpine c\u0026rsquo;est sous-estimé pour ce genre de projets. Pas de maux de tête de pipeline de build, pas de fatigue de framework JavaScript, juste des attributs HTML déclaratifs qui font ce que t\u0026rsquo;attends. Amélioration progressive, hypermédia, toutes ces bonnes affaires-là. T\u0026rsquo;écris moins de code, c\u0026rsquo;est plus facile à suivre, pis ton frontend devient pas un cauchemar de maintenance dans six mois.\nPis les goroutines de Go ont rendu le hub WebSocket trivial. Diffuser des messages à des milliers de connexions ? Goroutines avec channels. Fait. C\u0026rsquo;est le vrai avantage de Go pour ce cas d\u0026rsquo;utilisation - de la concurrence qui te rend pas fou.\nLe vrai défi # Honnêtement ? Réussir la machine d\u0026rsquo;état. Les tours doivent s\u0026rsquo;enchaîner proprement : vote → révélé → terminé → nouveau tour. Les participants doivent rester synchronisés. Les connexions tombent pis se reconnectent - tu peux pas perdre le vote de quelqu\u0026rsquo;un parce que son WiFi a flanché.\nÇa m\u0026rsquo;a pris plus de réflexion que le déploiement. L\u0026rsquo;infrastructure faisait juste\u0026hellip; ce que l\u0026rsquo;infrastructure fait. La partie difficile c\u0026rsquo;était de s\u0026rsquo;assurer que la logique de vote était solide.\nFait que c\u0026rsquo;est fini ? # Ouais, ça marche. Tu peux rouler make dev pis ça démarre localement avec rechargement en direct. Y\u0026rsquo;a des tests d\u0026rsquo;intégration. Ça a des métriques, des vérifications de santé, de la gestion d\u0026rsquo;erreurs correcte. Tu pourrais vraiment utiliser ça pour rouler des sessions Planning Poker maintenant.\nEst-ce que le déploiement est beaucoup trop complexe pour une app Planning Poker qui va probablement jamais suer à grande échelle ? Absolument. Mais bon, c\u0026rsquo;est là, ça marche, pis maintenant j\u0026rsquo;ai un template pour déployer des apps Go sur AWS sans toucher à SSH. Ça vaut quelque chose, non ?\nLa vraie leçon par contre ? Complexifie pas trop la base de données. SQLite a fait la job. PocketBase m\u0026rsquo;a sauvé de passer trois jours sur du boilerplate. Les primitives de concurrence de Go ont rendu les parties difficiles faciles. Pis des fois, la meilleure infrastructure c\u0026rsquo;est celle qui se tasse de ton chemin pis qui marche juste.\nTu pourrais vraiment l\u0026rsquo;utiliser pour tes sessions de Planning Poker maintenant sur pokerplanning.net.\n","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/blog/planning-poker-app/","section":"Blog","summary":"\u003cp\u003eFait que j\u0026rsquo;ai construit cette app de Planning Poker. Tu sais, le truc agile d\u0026rsquo;estimation où l\u0026rsquo;équipe se rassemble pour voter sur les story points ? Ouais, j\u0026rsquo;ai décidé de la faire web et temps réel \u003ca\n  href=\"https://pokerplanning.net/\"\n    target=\"_blank\"\n  \u003epokerplanning.net\u003c/a\u003e. Et puis\u0026hellip; disons juste que je suis devenu un peu ambitieux avec le déploiement.\u003c/p\u003e","title":"Construire Planning Poker : Une app de collaboration temps réel (que j'ai peut-être trop complexifiée)","type":"blog"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/categories/development/","section":"Categories","summary":"","title":"Development","type":"categories"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/categories/d%C3%A9veloppement/","section":"Categories","summary":"","title":"Développement","type":"categories"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/tags/devops/","section":"Tags","summary":"","title":"DevOps","type":"tags"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/tags/go/","section":"Tags","summary":"","title":"Go","type":"tags"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/tags/htmx/","section":"Tags","summary":"","title":"Htmx","type":"tags"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/tags/pocketbase/","section":"Tags","summary":"","title":"PocketBase","type":"tags"},{"content":"","date":"15 novembre 2025","externalUrl":null,"permalink":"/fr/tags/websockets/","section":"Tags","summary":"","title":"WebSockets","type":"tags"},{"content":" Expérience professionnelle # Groupe Alesco # Ingénieur principal données \u0026amp; IA | Pipelines ETL · MLOps | Plateforme analytique # Octobre 2025 - Présent | Saint-Hubert, Québec\nModernisation et industrialisation de l\u0026rsquo;infrastructure de données pour supporter les initiatives d\u0026rsquo;analytique et d\u0026rsquo;intelligence artificielle. Transformation des processus manuels en pipelines automatisés et implémentation d\u0026rsquo;une plateforme analytique accessible et performante.\nExpertise technique :\nArchitecture et automatisation de pipelines de données (ETL/ELT) Implémentation et optimisation de plateforme analytique (Snowflake) Opérationnalisation de modèles de machine learning et d\u0026rsquo;IA générative Démocratisation de l\u0026rsquo;accès aux données pour les équipes d\u0026rsquo;affaires et d\u0026rsquo;analytique Développeur logiciel Full Stack | PHP/Symfony · AWS | Solutions financières # Février 2024 - Octobre 2025 | Saint-Hubert, Québec\nConception et développement d\u0026rsquo;applications web hautement performantes au sein d\u0026rsquo;une équipe agile dans le secteur du financement alternatif. Participation active à l\u0026rsquo;architecture, au développement et à l\u0026rsquo;optimisation de plateformes critiques pour l\u0026rsquo;expérience client.\nExpertise technique :\nStack LAMP (Symfony, MySQL, Redis, Nginx) et écosystème AWS Développement frontend avec React/Next.js Architecture de solutions évolutives et sécurisées Intégration d\u0026rsquo;APIs tierces et optimisation de performance Mentorat et partage de connaissances au sein de l\u0026rsquo;équipe Optable # Développeur logiciel Backend | Go · gRPC · GCP | Plateforme de collaboration de données Septembre 2022 - Janvier 2024 | Montréal, Québec, Canada\nDéveloppement et optimisation du backend d\u0026rsquo;une plateforme innovante de collaboration de données axée sur la confidentialité. Contribution à une solution qui répond aux plus hauts standards de l\u0026rsquo;industrie en matière de qualité, sécurité et performance.\nExpertise technique :\nDéveloppement backend en Go avec architecture gRPC Infrastructure cloud (GCP) et Infrastructure as Code (Terraform) Bases de données relationnelles et analytiques (Postgres, BigQuery) Développement frontend avec React.js Tests automatisés et revues de code rigoureuses Architecture microservices et APIs haute performance Vortex Solution # Développeur logiciel Backend | PHP · WordPress · Vue.js | Applications web sur mesure Mai 2020 - Août 2022 | Montréal, Québec, Canada\nDéveloppement d\u0026rsquo;applications web sur mesure pour des sites institutionnels modernes au sein d\u0026rsquo;une agence web renommée. Spécialisation dans la création de solutions complexes adaptées aux besoins spécifiques des clients, avec un focus sur la performance et l\u0026rsquo;expérience utilisateur.\nExpertise technique :\nDéveloppement de moteurs de recherche avancés et systèmes SSO Intégration d\u0026rsquo;APIs externes et systèmes d\u0026rsquo;authentification Optimisation de performance et gestion de données à grande échelle Développement de modules interactifs avec Vue.js Architecture de solutions WordPress personnalisées Stack PHP/JavaScript pour applications web évolutives Ekkip boutique sport # Développeur logiciel Full Stack \u0026amp; Gestionnaire TI | Développement web · Infrastructure · Marketing numérique Juillet 2017 - Mai 2020 | Montréal, Canada\nGestion complète de l\u0026rsquo;écosystème technologique pour une entreprise dynamique de vente au détail d\u0026rsquo;articles de sport. Responsable du développement web, de l\u0026rsquo;infrastructure TI et des stratégies de marketing numérique, combinant expertise technique et vision créative pour supporter la croissance de l\u0026rsquo;entreprise.\nExpertise technique et stratégique :\nDéveloppement et maintenance du site web principal Création de logiciels internes sur mesure pour optimiser les opérations Gestion du réseau informatique et sécurité Design web et design graphique (web, imprimé, publicité) Développement et exécution de stratégies de marketing numérique Production de contenu vidéo et création multimédia Support technique et infrastructure TI Début de carrière en France # Développeur web \u0026amp; Spécialiste marketing numérique Août 2012 - Juillet 2017 | Diverses locations en France\nMandats en freelance et en agence dans le développement web, le SEO et le marketing numérique. Construction d\u0026rsquo;une expertise fondamentale en développement PHP/JavaScript, WordPress, intégration frontend, e-commerce, webmarketing et production multimédia à travers de multiples projets clients et entreprises.\nFormation # Université de Montréal # D.E.S.S Beaux-Arts et technologies créatives 2016 - 2017\nDéveloppement VR/AR, médias interactifs et technologies créatives avec focus sur Unity, vidéomapping et intégration Arduino/Raspberry Pi.\nUniversité de Toulon, France # Licence Ingémedia (Baccalauréat) - Information \u0026amp; Communication 2014 - 2015\nDesign et communication multimédia.\nDUT SRC (Services et Réseaux de Communication) 2011 - 2014\nArchitecture des systèmes distribués, développement logiciel et gestion de projet.\n","externalUrl":null,"permalink":"/fr/resume/","section":"Damien GOEHRIG","summary":"Ingénieur de données avec plus de 10 ans d\u0026rsquo;expérience en développement logiciel en Go et PHP, spécialisé maintenant dans l\u0026rsquo;architecture de pipelines ETL, la modernisation de plateformes analytiques et le MLOps. Solide expertise technique dans la construction d\u0026rsquo;infrastructures de données évolutives et de systèmes distribués. Expert dans la transformation de processus manuels en solutions de données automatisées et prêtes pour la production.","title":"Damien GOEHRIG","type":"resume"},{"content":"","externalUrl":null,"permalink":"/fr/stack/","section":"Stack","summary":"","title":"Stack","type":"stack"}]