[{"data":1,"prerenderedAt":25808},["ShallowReactive",2],{"author-anais-cousin-articles":3},[4,911,1594,1881,3528,5011,5657,5806,6273,6610,7075,7243,7824,8046,8193,17864,18450,18870,20029,20247,21158,21432,21875,23228,23410,23732,23810,24125,25217,25418,25539],{"id":5,"title":6,"alt":7,"authors":8,"body":15,"date":888,"description":889,"extension":890,"image":891,"meta":892,"navigation":893,"ogImage":891,"path":894,"published":893,"reviewers":895,"seo":902,"stem":903,"tags":904,"__hash__":910},"blogs\u002Fblogs\u002F2026-05-04-mainframe-aws-reconcilier-deux-mondes-grace-a-levent-driven\u002Findex.md","Mainframe & AWS : Réconcilier deux mondes grâce à l'Event-Driven","Comparaison visuelle entre un mainframe vintage des années 70 et un centre de données cloud moderne, reliés par un flux de données numérique bidirectionnel symbolisant la transformation numérique.",[9],{"id":10,"name":11,"image":12,"linkedin":13,"x":14},"838dec96-f9fc-404f-a302-07719225d785","Maxime Deroullers",".\u002Fassets\u002Fauthor-maxime-deroullers.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fmaxime-deroullers-1b5791137\u002F","https:\u002F\u002Fx.com\u002Fmderoullers",{"type":16,"value":17,"toc":859},"minimark",[18,22,27,30,38,45,60,63,67,73,76,83,88,120,124,148,152,173,180,186,290,300,304,308,314,317,336,340,343,386,390,393,422,429,433,439,442,466,469,473,480,484,529,533,556,560,563,577,580,584,590,593,618,629,633,636,646,649,669,672,676,679,683,731,735,755,759,766,770,802,806,813,817,820,823,826,852,855],[19,20,21],"p",{},"Comment réconcilier 80 à 90 % des données métier coincées dans un Mainframe IBM avec des applications cloud-native qui exigent l'instantané ? Retour d'expérience sur la construction d'un pont event-driven entre le Mainframe et AWS sans toucher à une seule ligne de COBOL.",[23,24,26],"h2",{"id":25},"_1-lexpérience-utilisateur-dabord-le-conseiller-aveugle","1. L’expérience utilisateur d’abord : le conseiller \"aveugle\"",[19,28,29],{},"Imaginez un conseiller en banque privée, censé offrir un service d'excellence à des clients exigeants. Pourtant, chaque matin, il commence sa journée avec un handicap majeur : il est \"aveugle\" sur les dernières 24 heures.",[19,31,32,33,37],{},"Si son client a effectué un virement important, soldé une assurance-vie ou reçu des fonds hier après-midi, le conseiller ne le voit pas.\nPourquoi ?\nParce que le système d'information repose sur des ",[34,35,36],"strong",{},"batchs de nuit",". Les données sont traitées en masse, une fois par jour. Pire, si le batch \"plante\" la nuit (ce qui arrive), le retard s'accumule, et l'aveuglement dure 48 heures.",[19,39,40,41,44],{},"Prenons un exemple concret. Un client demande un arbitrage sur son assurance-vie via le portail web. L'opération est traitée par le système de gestion des contrats, mais l'intégration automatique échoue (dans notre contexte, 5 à 20% des cas selon les opérations). Résultat : le dossier reste \"en sommeil\" dans l'application documentaire, invisible pour le gestionnaire. Le client attend, relance, s'impatiente. Le problème n'est pas un bug, c'est un ",[34,42,43],{},"défaut d'architecture",".",[19,46,47,48,51,52,55,56,59],{},"C'est le choc des cultures. D'un côté, un ",[34,49,50],{},"Mainframe IBM"," (le \"Vieux Monde\"), robuste, sécurisé, mais rigide et rythmé par ses batchs quotidiens. Dans notre contexte, il concentre ",[34,53,54],{},"80 à 90% des données métier"," de l'entreprise, un poids incontournable. De l'autre, des applications modernes sur ",[34,57,58],{},"AWS"," (le \"Nouveau Monde\"), conçues pour l'instantanéité et l'expérience utilisateur fluide.",[19,61,62],{},"Notre mission ? Réconcilier ces deux mondes.",[23,64,66],{"id":65},"_2-le-défi-technique-faire-parler-un-dinosaure","2. Le défi technique : faire parler un dinosaure",[19,68,69,70,44],{},"Le problème fondamental est architectural : ",[34,71,72],{},"le COBOL n'est pas conçu pour l'événementiel",[19,74,75],{},"Les programmes Legacy sont procéduraux. Ils traitent des fichiers, pas des flux. Leur demander d'émettre un événement HTTP ou d'appeler une API à chaque transaction est risqué (latence, couplage fort) et complexe (réécriture de code critique vieux de 30 ans).",[19,77,78,79,82],{},"Nous avons évalué plusieurs architectures candidates, regroupées en ",[34,80,81],{},"trois grandes familles",", récapitulées dans le schéma plus bas :",[84,85,87],"h3",{"id":86},"solution-a-rabbitmq-via-lambda-bridge","Solution A : RabbitMQ via Lambda Bridge",[19,89,90,97,98,103,104,109,115,116,119],{},[91,92,96],"a",{"href":93,"rel":94},"https:\u002F\u002Fwww.rabbitmq.com\u002F",[95],"nofollow","RabbitMQ"," (via ",[91,99,102],{"href":100,"rel":101},"https:\u002F\u002Faws.amazon.com\u002Famazon-mq\u002F",[95],"Amazon MQ",") offre un routage intelligent natif et, depuis la v3.9, un ",[91,105,108],{"href":106,"rel":107},"https:\u002F\u002Fwww.rabbitmq.com\u002Fstreams.html",[95],"mode ",[91,110,112],{"href":106,"rel":111},[95],[34,113,114],{},"Stream"," combinant messaging classique et event-streaming. L'option la plus économique serait une connexion AMQP directe depuis le COBOL, mais elle exigeait de réécrire les programmes Mainframe. Les variantes plus sûres reposent sur un ",[34,117,118],{},"bridge Lambda"," entre IBM MQ et Amazon MQ, au prix de code custom à écrire et maintenir.",[84,121,123],{"id":122},"solution-b-kafka-connect-la-gagnante","Solution B : Kafka Connect, la gagnante",[19,125,126,131,132,137,138,143,144,147],{},[91,127,130],{"href":128,"rel":129},"https:\u002F\u002Fkafka.apache.org\u002Fdocumentation\u002F#connect",[95],"Kafka Connect"," (associé à ",[91,133,136],{"href":134,"rel":135},"https:\u002F\u002Faws.amazon.com\u002Fmsk\u002F",[95],"Amazon MSK",") consomme directement IBM MQ via un ",[91,139,142],{"href":140,"rel":141},"https:\u002F\u002Fgithub.com\u002Fibm-messaging\u002Fkafka-connect-mq-source",[95],"connecteur officiel IBM Event Streams",". Le Mainframe continue de déposer ses messages dans ses files MQ comme il l'a toujours fait ; le connecteur les réplique en topics Kafka et inversement. Aucune ligne de code custom : tout se pilote par configuration. C'est l'approche ",[34,145,146],{},"\"Configuration over Code\""," qui a tranché.",[84,149,151],{"id":150},"solution-c-zos-connect-rest-hybride","Solution C : z\u002FOS Connect (REST hybride)",[19,153,154,155,162,163,168,169,172],{},"Utiliser ",[91,156,159],{"href":157,"rel":158},"https:\u002F\u002Fwww.ibm.com\u002Fproducts\u002Fzos-connect",[95],[34,160,161],{},"z\u002FOS Connect"," pour exposer des API REST depuis le Mainframe vers le broker AWS. Avantage : supprime la dépendance à ",[91,164,167],{"href":165,"rel":166},"https:\u002F\u002Fwww.ibm.com\u002Fproducts\u002Fmq",[95],"IBM MQ",". Inconvénient majeur : on perd la ",[34,170,171],{},"transactionnalité native",", il faut recréer la gestion de transactions côté applicatif.",[19,174,175],{},[176,177],"img",{"alt":178,"src":179},"Comparatif des trois solutions techniques évaluées : RabbitMQ via Lambda Bridge, Kafka Connect (retenu) et z\u002FOS Connect en REST hybride.","\u002Fcontent-assets\u002F2026-05-04-mainframe-aws-reconcilier-deux-mondes-grace-a-levent-driven\u002Fassets\u002Fimg1.webp",[19,181,182,183,44],{},"Elle a gagné sur un critère décisif : ",[34,184,185],{},"zéro modification du code COBOL",[187,188,189,207],"table",{},[190,191,192],"thead",{},[193,194,195,199,201,204],"tr",{},[196,197,198],"th",{},"Critère",[196,200,96],{},[196,202,203],{},"Kafka (MSK)",[196,205,206],{},"ActiveMQ",[208,209,210,225,239,252,266,279],"tbody",{},[193,211,212,216,219,222],{},[213,214,215],"td",{},"Débit",[213,217,218],{},"20-50K msg\u002Fs",[213,220,221],{},"50-100K msg\u002Fs par partition (millions sur un cluster)",[213,223,224],{},"10-20K msg\u002Fs",[193,226,227,230,233,236],{},[213,228,229],{},"Replay natif",[213,231,232],{},"Via extension Stream",[213,234,235],{},"Excellent (log persistant)",[213,237,238],{},"Limité",[193,240,241,244,247,250],{},[213,242,243],{},"Scalabilité",[213,245,246],{},"Bonne",[213,248,249],{},"Excellente",[213,251,246],{},[193,253,254,257,260,263],{},[213,255,256],{},"Routage intelligent",[213,258,259],{},"Oui (exchanges)",[213,261,262],{},"Non (côté client)",[213,264,265],{},"Oui",[193,267,268,271,274,277],{},[213,269,270],{},"Intégration MQ native",[213,272,273],{},"Code custom nécessaire",[213,275,276],{},"Kafka Connect (config only)",[213,278,273],{},[193,280,281,284,286,288],{},[213,282,283],{},"Service managé AWS",[213,285,102],{},[213,287,136],{},[213,289,102],{},[19,291,292,293,296,297,299],{},"L'argument décisif n'était pas seulement la performance, mais ",[34,294,295],{},"la simplicité d'intégration",". Avec Kafka Connect et les connecteurs IBM Event Streams, nous pouvions adopter une approche ",[34,298,146],{}," : le Mainframe continue de déposer ses messages dans IBM MQ comme il l'a toujours fait, et le connecteur se charge du reste.",[23,301,303],{"id":302},"_3-la-solution-kafka-connect-comme-pont-bidirectionnel","3. La solution : Kafka Connect comme pont bidirectionnel",[84,305,307],{"id":306},"avant-après-vue-densemble","Avant \u002F après : vue d'ensemble",[19,309,310],{},[176,311],{"alt":312,"src":313},"Avant \u002F après : du batch de nuit (12 à 24 h de latence) au pipeline event-driven Mainframe → IBM MQ → Kafka Connect → Amazon MSK (quelques secondes).","\u002Fcontent-assets\u002F2026-05-04-mainframe-aws-reconcilier-deux-mondes-grace-a-levent-driven\u002Fassets\u002Fimg2.webp",[19,315,316],{},"Le contraste est radical : le batch de nuit, linéaire et bloquant, cède la place à un pipeline d'événements continu où chaque mouvement remonte en quelques secondes.",[19,318,319,320,322,323,326,327,332,333,44],{},"La solution retenue est d'utiliser ",[34,321,130],{}," pour faire le pont entre le monde IBM MQ (la messagerie native du Mainframe) et ",[91,324,136],{"href":134,"rel":325},[95]," (Managed Streaming pour ",[91,328,331],{"href":329,"rel":330},"https:\u002F\u002Fkafka.apache.org\u002F",[95],"Apache Kafka",") et ce pont fonctionne ",[34,334,335],{},"dans les deux sens",[84,337,339],{"id":338},"sens-mainframe-aws-source","Sens Mainframe → AWS (source)",[19,341,342],{},"Le Mainframe dépose un événement dans une file MQ. Le connecteur l'ingère et le transforme en topic Kafka.",[344,345,351],"pre",{"className":346,"code":347,"language":348,"meta":349,"style":350},"language-plain shiki shiki-themes github-dark-default","# CONFIGURATION 1 : Ingestion (MQ -> Kafka)\nconnector.class=com.ibm.eventstreams.connect.mqsource.MQSourceConnector\nmq.queue=MQ_KAFKA\ntopic=msk-serverless-tutorial\nmq.record.builder=com.ibm.eventstreams.connect.mqsource.builders.DefaultRecordBuilder\n","plain","text","",[352,353,354,362,368,374,380],"code",{"__ignoreMap":350},[355,356,359],"span",{"class":357,"line":358},"line",1,[355,360,361],{},"# CONFIGURATION 1 : Ingestion (MQ -> Kafka)\n",[355,363,365],{"class":357,"line":364},2,[355,366,367],{},"connector.class=com.ibm.eventstreams.connect.mqsource.MQSourceConnector\n",[355,369,371],{"class":357,"line":370},3,[355,372,373],{},"mq.queue=MQ_KAFKA\n",[355,375,377],{"class":357,"line":376},4,[355,378,379],{},"topic=msk-serverless-tutorial\n",[355,381,383],{"class":357,"line":382},5,[355,384,385],{},"mq.record.builder=com.ibm.eventstreams.connect.mqsource.builders.DefaultRecordBuilder\n",[84,387,389],{"id":388},"sens-aws-mainframe-sink","Sens AWS → Mainframe (sink)",[19,391,392],{},"Les applications modernes sur AWS peuvent aussi renvoyer de l'information (ex: validation d'opération) au Mainframe. Kafka Connect lit le topic et écrit dans la file MQ.",[344,394,396],{"className":346,"code":395,"language":348,"meta":349,"style":350},"# CONFIGURATION 2 : Restitution (Kafka -> MQ)\nconnector.class=com.ibm.eventstreams.connect.mqsink.MQSinkConnector\nmq.queue=KAFKA_MQ\ntopic=msk-serverless-tutorial\nmq.connection.mode=client\n",[352,397,398,403,408,413,417],{"__ignoreMap":350},[355,399,400],{"class":357,"line":358},[355,401,402],{},"# CONFIGURATION 2 : Restitution (Kafka -> MQ)\n",[355,404,405],{"class":357,"line":364},[355,406,407],{},"connector.class=com.ibm.eventstreams.connect.mqsink.MQSinkConnector\n",[355,409,410],{"class":357,"line":370},[355,411,412],{},"mq.queue=KAFKA_MQ\n",[355,414,415],{"class":357,"line":376},[355,416,379],{},[355,418,419],{"class":357,"line":382},[355,420,421],{},"mq.connection.mode=client\n",[19,423,424,425,428],{},"L'avantage de cette solution, c'est qu'il n'y a ",[34,426,427],{},"aucune ligne de code à écrire pour l'ingestion",". Tout se passe par configuration.",[84,430,432],{"id":431},"un-exemple-concret-le-flux-darbitrage","Un exemple concret : le flux d'arbitrage",[19,434,435],{},[176,436],{"alt":437,"src":438},"Flux d'arbitrage assurance-vie : événement Arbitrage publié dans le Hub, consommé en parallèle par l'application documentaire et le Mainframe ; retour Personne du Mainframe vers les applications aval.","\u002Fcontent-assets\u002F2026-05-04-mainframe-aws-reconcilier-deux-mondes-grace-a-levent-driven\u002Fassets\u002Fimg3.webp",[19,440,441],{},"Pour illustrer ce bidirectionnel, prenons notre cas d'arbitrage assurance-vie :",[443,444,445,453,456,459],"ul",{},[446,447,448,449,452],"li",{},"Le système de gestion des contrats détecte un échec d'intégration → il publie un ",[34,450,451],{},"événement \"Arbitrage\""," dans le Hub",[446,454,455],{},"Le pipeline (filtrage + contrôle qualité) valide l'événement et le route vers les topics de sortie",[446,457,458],{},"Deux consommateurs reçoivent l'événement en parallèle :",[446,460,461,462,465],{},"Kafka Connect (côté Source) reprend cet événement, le republie dans le Hub, qui le distribue aux ",[34,463,464],{},"applications aval"," (Référentiel Personne et apps consommatrices)",[19,467,468],{},"Un seul événement métier, deux consommateurs, un aller-retour complet entre les deux mondes.",[23,470,472],{"id":471},"_4-standards-et-interopérabilité","4. Standards et interopérabilité",[19,474,475,476,479],{},"Pour que ce pont fonctionne à l'échelle (des dizaines de flux, pas un seul POC), il faut ",[34,477,478],{},"standardiser le contrat d'interface"," entre producteurs et consommateurs.",[84,481,483],{"id":482},"cloudevents-un-format-universel","CloudEvents : un format universel",[19,485,486,487,494,495,500,501,504,505,508,509,512,513,516,517,520,521,524,525,528],{},"Nous avons adopté ",[91,488,491],{"href":489,"rel":490},"https:\u002F\u002Fcloudevents.io\u002F",[95],[34,492,493],{},"CloudEvents"," (",[91,496,499],{"href":497,"rel":498},"https:\u002F\u002Fgithub.com\u002Fcloudevents\u002Fspec",[95],"spécification CNCF",") comme format d'événement. Chaque message transitant par le hub porte des métadonnées standardisées : ",[352,502,503],{},"source",", ",[352,506,507],{},"type"," et ",[352,510,511],{},"id"," (identifiant unique) sont ",[34,514,515],{},"requis"," par la spec, tandis que ",[352,518,519],{},"time"," (timestamp) et ",[352,522,523],{},"dataschema"," sont recommandés. Cela garantit la ",[34,526,527],{},"traçabilité de bout en bout"," et l'interopérabilité, quel que soit le transport (HTTP, AMQP, Kafka).",[84,530,532],{"id":531},"asyncapi-documenter-larchitecture-événementielle","AsyncAPI : documenter l'architecture événementielle",[19,534,535,536,543,544,551,552,555],{},"Comme ",[91,537,540],{"href":538,"rel":539},"https:\u002F\u002Fwww.openapis.org\u002F",[95],[34,541,542],{},"OpenAPI"," documente les API REST, ",[91,545,548],{"href":546,"rel":547},"https:\u002F\u002Fwww.asyncapi.com\u002F",[95],[34,549,550],{},"AsyncAPI"," décrit nos canaux événementiels en YAML : quels événements, quels formats, quels serveurs, quels protocoles. Un ",[34,553,554],{},"SDK est généré"," à partir de ces spécifications et distribué aux équipes productrices et consommatrices, garantissant un contrat d'interface cohérent sans effort manuel.",[84,557,559],{"id":558},"deux-types-dévénements","Deux types d'événements",[19,561,562],{},"Nous avons distingué deux catégories fondamentales :",[443,564,565,571],{},[446,566,567,570],{},[34,568,569],{},"Événement Métier"," (notification) : \"un arbitrage a échoué\", il signale qu'un fait s'est produit, sans embarquer toutes les données.",[446,572,573,576],{},[34,574,575],{},"Événement Data"," (propagation d'état) : réplication complète d'un jeu de données depuis le système maître vers N systèmes esclaves.",[19,578,579],{},"Cette distinction évite de surcharger le bus avec des payloads inutiles tout en garantissant la fraîcheur des données là où c'est nécessaire.",[23,581,583],{"id":582},"_5-le-pipeline-de-traitement","5. Le pipeline de traitement",[19,585,586],{},[176,587],{"alt":588,"src":589},"Workflow d'un événement dans le hub : filtrage, contrôle qualité, distribution vers les consommateurs ; les événements en échec partent en Dead Letter Queue.","\u002Fcontent-assets\u002F2026-05-04-mainframe-aws-reconcilier-deux-mondes-grace-a-levent-driven\u002Fassets\u002Fimg4.webp",[19,591,592],{},"Les événements ne transitent pas \"bruts\" dans le hub. Un pipeline en trois étapes assure la qualité et l'aiguillage des données :",[443,594,595,606,612],{},[446,596,597,494,600,605],{},[34,598,599],{},"Filtrage",[91,601,604],{"href":602,"rel":603},"https:\u002F\u002Faws.amazon.com\u002Flambda\u002F",[95],"AWS Lambda",") : vérifie que l'événement est attendu, correspond à un schéma connu, et n'est pas un doublon technique.",[446,607,608,611],{},[34,609,610],{},"Contrôle Qualité"," (AWS Lambda) : valide le contenu métier, champs obligatoires, cohérence des données, conformité au schéma CloudEvents.",[446,613,614,617],{},[34,615,616],{},"Distribution"," : routing intelligent vers les topics de sortie par domaine, consommés par N applications.",[19,619,620,621,628],{},"Si un événement échoue à l'une des deux étapes de validation, il est redirigé vers une ",[91,622,625],{"href":623,"rel":624},"https:\u002F\u002Fdocs.aws.amazon.com\u002FAWSSimpleQueueService\u002Flatest\u002FSQSDeveloperGuide\u002Fsqs-dead-letter-queues.html",[95],[34,626,627],{},"Dead Letter Queue (DLQ)",". Rien n'est perdu : l'événement est conservé pour analyse et rejeu éventuel, mais il ne \"pollue\" pas les consommateurs en aval.",[23,630,632],{"id":631},"_6-sécurité-et-fiabilité-zero-message-loss","6. Sécurité et fiabilité : zero message loss",[19,634,635],{},"Dans la banque, perdre un message signifie potentiellement perdre de l'argent ou une instruction client. C'est inacceptable.",[19,637,638,639,44],{},"Kafka Connect offre ici une garantie technique majeure : le ",[91,640,643],{"href":641,"rel":642},"https:\u002F\u002Fkafka.apache.org\u002Fdocumentation\u002F#semantics",[95],[34,644,645],{},"\"at-least-once delivery\"",[19,647,648],{},"Comment cela fonctionne-t-il concrètement ?",[443,650,651,657,663],{},[446,652,653,656],{},[34,654,655],{},"Transactions et Offsets"," : Le connecteur ne valide la lecture (\"commit via offset\") qu'une fois le message bien arrivé à destination.",[446,658,659,662],{},[34,660,661],{},"Résilience Réseau"," : Si le lien entre AWS et le Mainframe coupe :",[446,664,665,668],{},[34,666,667],{},"Garantie de bout en bout"," : De la file MQ source jusqu'au topic Kafka répliqué sur 3 Availability Zones (AZ), la donnée est toujours persistée avant d'être acquittée.",[19,670,671],{},"Nous passons d'un couplage temporel fort (le batch de nuit) à un couplage lâche mais ultra-robuste.",[23,673,675],{"id":674},"_7-retours-dexpérience-difficultés-et-prérequis","7. Retours d'expérience : difficultés et prérequis",[19,677,678],{},"La mise en place de ce pont n'a pas été sans embûches. Voici les principaux enseignements.",[84,680,682],{"id":681},"intégration-réseau-et-infrastructure","Intégration réseau et infrastructure",[443,684,685,691,697,709],{},[446,686,687,690],{},[34,688,689],{},"Proxy d'entreprise"," : L'environnement AWS tourne derrière un proxy corporate. Chaque composant (EC2, connecteurs) doit être configuré avec les bonnes exclusions (métadonnées AWS, endpoints MSK). Un oubli = un connecteur muet sans message d'erreur explicite.",[446,692,693,696],{},[34,694,695],{},"Résolution DNS"," : Les endpoints MSK Serverless nécessitent parfois une résolution DNS manuelle (fichier hosts) dans les sous-réseaux privés, car les VPC endpoints ne sont pas toujours immédiatement résolus.",[446,698,699,702,703,708],{},[34,700,701],{},"Accès restreint"," : Pas de SSH en environnement de pré-production, tout passe par ",[91,704,707],{"href":705,"rel":706},"https:\u002F\u002Faws.amazon.com\u002Fsystems-manager\u002F",[95],"AWS SSM (Systems Manager)",". Le debug d'un connecteur Kafka en panne devient un exercice de patience.",[446,710,711,714,715,720,721,724,725,730],{},[34,712,713],{},"Port spécifique"," : ",[91,716,719],{"href":717,"rel":718},"https:\u002F\u002Faws.amazon.com\u002Fmsk\u002Ffeatures\u002Fmsk-serverless\u002F",[95],"MSK Serverless"," utilise le port ",[34,722,723],{},"9098"," pour l'",[91,726,729],{"href":727,"rel":728},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fmsk\u002Flatest\u002Fdeveloperguide\u002Fiam-access-control.html",[95],"authentification IAM"," (différent du 9094 TLS classique). Une source de confusion récurrente.",[84,732,734],{"id":733},"compatibilité-et-formats","Compatibilité et formats",[443,736,737,749],{},[446,738,739,742,743,748],{},[34,740,741],{},"EBCDIC et formats fixes"," : Les messages MQ du Mainframe sont souvent dans des formats historiques (COPYBOOK). Il faut prévoir une transformation (",[91,744,747],{"href":745,"rel":746},"https:\u002F\u002Fdocs.confluent.io\u002Fplatform\u002Fcurrent\u002Fconnect\u002Ftransforms\u002Foverview.html",[95],"Single Message Transform"," dans Kafka Connect) pour produire du JSON exploitable.",[446,750,751,754],{},[34,752,753],{},"Rétrocompatibilité applicative"," : Certaines applications consommatrices tournent sur des frameworks anciens. Les librairies IAM et CloudEvents n'étant pas disponibles sur toutes les versions, des compromis de version ont été nécessaires.",[84,756,758],{"id":757},"gestion-des-doublons","Gestion des doublons",[19,760,761,762,765],{},"Le \"at-least-once\" implique des doublons possibles. Chaque consommateur doit être ",[34,763,764],{},"idempotent",", typiquement via une clé de déduplication sur l'identifiant métier (numéro de contrat + identifiant d'opération).",[84,767,769],{"id":768},"gouvernance-et-observabilité","Gouvernance et observabilité",[443,771,772,778,790],{},[446,773,774,777],{},[34,775,776],{},"Dictionnaire d'événements"," : Sans catalogue formalisé des événements (qui produit quoi, quel schéma, quelle fréquence), le hub devient rapidement une boîte noire. Nous avons mis en place une gouvernance dédiée avec un RACI clair.",[446,779,780,783,784,789],{},[34,781,782],{},"Monitoring unifié"," : Le Mainframe et AWS ont des outils très différents. Les métriques JMX des connecteurs sont remontées dans ",[91,785,788],{"href":786,"rel":787},"https:\u002F\u002Faws.amazon.com\u002Fcloudwatch\u002F",[95],"CloudWatch"," pour unifier la supervision. Le hub doit pouvoir émettre à tout moment une synthèse d'activité (qui a publié, qui a consommé).",[446,791,792,795,796,798,799,801],{},[34,793,794],{},"FinOps"," : Le coût se joue à deux endroits. Côté AWS, ",[34,797,719],{}," (facturation à l'usage, pas de cluster à dimensionner en amont) limite l'investissement initial et s'adapte aux montées en charge réelles. Côté Mainframe, le licensing ",[34,800,167],{}," pèse lourd, mais Kafka Connect, qui consomme MQ de manière native, permet de le maintenir comme couche transitoire. Les équipes Mainframe planifient ainsi son décommissionnement à leur rythme, sans bloquer le déploiement du hub côté AWS.",[84,803,805],{"id":804},"conduite-du-changement","Conduite du changement",[19,807,808,809,812],{},"Les équipes Mainframe ne connaissent pas Kafka, et les équipes Cloud ne connaissent pas MQ. Un effort de ",[34,810,811],{},"montée en compétence croisée"," est indispensable, c'est peut-être le prérequis le plus sous-estimé.",[23,814,816],{"id":815},"_8-conclusion","8. Conclusion",[19,818,819],{},"Le résultat ? Le conseiller bancaire voit désormais les mouvements de son client quelques secondes après qu'ils aient eu lieu, et non le lendemain.",[19,821,822],{},"Nous avons \"réveillé le dinosaure\" sans le brusquer. Moderniser le Legacy ne signifie pas nécessairement tout réécrire (\"Big Bang\"). Parfois, il suffit de construire les bons ponts pour exposer la valeur existante aux nouveaux usages.",[19,824,825],{},"Les clés de cette réussite :",[443,827,828,834,840,846],{},[446,829,830,833],{},[34,831,832],{},"Configuration over Code"," : Kafka Connect évite de toucher au COBOL",[446,835,836,839],{},[34,837,838],{},"Standards ouverts"," : CloudEvents + AsyncAPI comme contrat d'interface universel",[446,841,842,845],{},[34,843,844],{},"Pipeline de qualité"," : Filtrage et validation avant distribution, avec DLQ pour le rejeu",[446,847,848,851],{},[34,849,850],{},"Gouvernance dès le jour 1"," : Dictionnaire d'événements, monitoring unifié, FinOps",[19,853,854],{},"Le Mainframe n'est pas mort. Il a juste besoin qu'on lui construise les bonnes passerelles.",[856,857,858],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":350,"searchDepth":364,"depth":364,"links":860},[861,862,867,873,878,879,880,887],{"id":25,"depth":364,"text":26},{"id":65,"depth":364,"text":66,"children":863},[864,865,866],{"id":86,"depth":370,"text":87},{"id":122,"depth":370,"text":123},{"id":150,"depth":370,"text":151},{"id":302,"depth":364,"text":303,"children":868},[869,870,871,872],{"id":306,"depth":370,"text":307},{"id":338,"depth":370,"text":339},{"id":388,"depth":370,"text":389},{"id":431,"depth":370,"text":432},{"id":471,"depth":364,"text":472,"children":874},[875,876,877],{"id":482,"depth":370,"text":483},{"id":531,"depth":370,"text":532},{"id":558,"depth":370,"text":559},{"id":582,"depth":364,"text":583},{"id":631,"depth":364,"text":632},{"id":674,"depth":364,"text":675,"children":881},[882,883,884,885,886],{"id":681,"depth":370,"text":682},{"id":733,"depth":370,"text":734},{"id":757,"depth":370,"text":758},{"id":768,"depth":370,"text":769},{"id":804,"depth":370,"text":805},{"id":815,"depth":364,"text":816},"2026-05-04T12:28:37.016Z","Comment réconcilier 80 à 90 % des données métier coincées dans un Mainframe IBM avec des applications cloud-native qui exigent l'instantané ? Retour d'expérience sur la construction d'un pont event-dr","md",".\u002Fassets\u002Fcover-image.webp",{},true,"\u002Fblogs\u002F2026-05-04-mainframe-aws-reconcilier-deux-mondes-grace-a-levent-driven",[896],{"id":897,"name":898,"image":899,"linkedin":900,"x":901},"e8163b24-7e01-41c5-adbf-0dc655f929d0","Nicolas Zago",".\u002Fassets\u002Freviewer-nicolas-zago.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fnicolaszago\u002F",null,{"title":6,"description":889},"blogs\u002F2026-05-04-mainframe-aws-reconcilier-deux-mondes-grace-a-levent-driven\u002Findex",[905,906,907,908,909],"architecture","cloud-platform","cloud","kafka","event driven architecture","33nLawacWxzcOggJs-mxD-uYhrQLmljKKAj6WV-dk5Q",{"id":912,"title":913,"alt":914,"authors":915,"body":921,"date":1571,"description":1572,"extension":890,"image":891,"meta":1573,"navigation":893,"ogImage":891,"path":1574,"published":893,"reviewers":1575,"seo":1586,"stem":1587,"tags":1588,"__hash__":1593},"blogs\u002Fblogs\u002F2026-04-20-docker-volumes-et-perte-de-donnees-pourquoi-vos-donnees-disparaissent\u002Findex.md","Docker, volumes et perte de données : pourquoi vos données “disparaissent”","Image d’illustration: un conteneur cassé avec le texte “data lost” et un conteneur sécurisé avec une porte blindée",[916],{"id":917,"name":918,"image":919,"linkedin":920,"x":901},"33bf4462-cd38-80da-845c-c63b2fd024bf","Florian Hirson",".\u002Fassets\u002Fauthor-florian-hirson.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fflorian-hirson\u002F",{"type":16,"value":922,"toc":1558},[923,929,933,945,948,951,954,958,961,965,976,979,999,1002,1008,1014,1016,1020,1023,1037,1043,1046,1054,1056,1060,1063,1066,1069,1073,1076,1079,1085,1095,1097,1101,1104,1463,1466,1468,1472,1475,1492,1495,1497,1501,1507,1514,1522,1525,1529,1532,1535,1552,1555],[19,924,925,926],{},"Récemment, j’ai vécu ma première “vraie” perte de données dans mon homelab.\nRien de critique… mais suffisamment frustrant pour me rappeler une règle essentielle avec Docker : 👉 ",[34,927,928],{},"Les données ne disparaissent presque jamais. On ne regarde juste pas au bon endroit.",[23,930,932],{"id":931},"le-contexte-calibre-web-dans-mon-cluster-docker-swarm","Le contexte : Calibre-Web dans mon cluster Docker Swarm",[19,934,935,936,939,940,44],{},"Pour gérer ma bibliothèque d'ebooks, j'ai déployé ",[34,937,938],{},"Calibre-Web"," sur mon cluster ",[91,941,944],{"href":942,"rel":943},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Fswarm\u002F",[95],"Docker Swarm",[19,946,947],{},"Tout fonctionnait parfaitement : j'uploadais des livres, je les lisais depuis n'importe quel appareil… bref, tout roulait. Quelques jours plus tard, je modifié ma stack et… catastrophe : plus aucun livre. Tout a disparu. 😱",[19,949,950],{},"Le plus étrange ? La configuration de Calibre-Web était toujours là. Comment était-ce possible ?",[952,953],"hr",{},[23,955,957],{"id":956},"comprendre-comment-docker-gère-les-données","Comprendre comment Docker gère les données",[19,959,960],{},"Avant de comprendre le problème, il faut rappeler un point fondamental :",[84,962,964],{"id":963},"par-défaut-un-conteneur-docker-est-éphémère","Par défaut, un conteneur Docker est éphémère",[443,966,967,973],{},[446,968,969,970],{},"Les fichiers sont stockés ",[34,971,972],{},"dans le conteneur",[446,974,975],{},"Si le conteneur est supprimé → les données disparaissent",[19,977,978],{},"Pour éviter ça, on utilise :",[443,980,981,987,996],{},[446,982,983,984],{},"des ",[34,985,986],{},"volumes Docker",[446,988,983,989],{},[91,990,993],{"href":991,"rel":992},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Fstorage\u002Fbind-mounts\u002F",[95],[34,994,995],{},"bind mounts",[446,997,998],{},"ou des stockages distants (NFS, etc.)",[19,1000,1001],{},"👉 Mais Docker ne fait aucune magie :",[1003,1004,1005],"blockquote",{},[19,1006,1007],{},"Il ne sait pas quels fichiers sont importants.",[19,1009,1010],{},[176,1011],{"alt":1012,"src":1013},"Schéma illustrant l’emplacement des données dans Docker. À gauche, la machine hôte est divisée en deux zones : le disque (avec un volume Docker stocké dans \u002Fvar\u002Flib\u002Fdocker\u002Fvolumes\u002F... et un répertoire local lié \u002Fhome\u002Fuser\u002Fprojects\u002F...) et la RAM (tmpfs, stockage temporaire comme \u002Ftmp ou \u002Frun\u002Fsecrets, perdu à l’arrêt du conteneur). En bas, un conteneur contient trois points de montage : \u002Fdata (volume), \u002Fapp\u002Fsrc (bind mount vers le disque hôte) et \u002Ftmp (tmpfs en mémoire), utilisés par l’application. À droite, un réseau permet de connecter ces stockages à des systèmes externes comme NFS (Linux), SMB (Windows) ou des services cloud (EBS, EFS).","\u002Fcontent-assets\u002F2026-04-20-docker-volumes-et-perte-de-donnees-pourquoi-vos-donnees-disparaissent\u002Fassets\u002Fimg1.webp",[952,1015],{},[23,1017,1019],{"id":1018},"lorigine-du-problème","L'origine du problème",[19,1021,1022],{},"Après investigation, j'ai identifié la cause :",[443,1024,1025,1028,1031],{},[446,1026,1027],{},"J'avais mal lu la documentation du conteneur",[446,1029,1030],{},"J’avais monté un volume sur un mauvais chemin",[446,1032,1033,1034],{},"Et surtout : ce chemin ",[34,1035,1036],{},"n’était pas utilisé par l’application",[19,1038,1039,1040],{},"Lors de la recréation du conteneur, Docker a fait exactement ce qu’il est censé faire :\n👉 ",[34,1041,1042],{},"Créer automatiquement un nouveau volume vide",[19,1044,1045],{},"Résultat :",[443,1047,1048,1051],{},[446,1049,1050],{},"mon application lisait un dossier vide",[446,1052,1053],{},"mes données existaient toujours… mais dans un autre volume",[952,1055],{},[23,1057,1059],{"id":1058},"une-erreur-très-courante-avec-docker","Une erreur très courante avec Docker",[19,1061,1062],{},"L’erreur que j’ai commise est en réalité assez fréquente avec Docker : monter un volume sur un mauvais chemin, ou sur un répertoire qui n’est tout simplement pas utilisé par l’application.",[19,1064,1065],{},"Dans ce type de situation, le comportement de Docker peut être trompeur. Le conteneur démarre sans problème, aucune erreur n’est remontée, et tout semble fonctionner normalement. Pourtant, les données ne sont pas écrites à l’endroit attendu.",[19,1067,1068],{},"En pratique, cela signifie que la persistance est silencieusement cassée : les fichiers sont stockés ailleurs, voire dans un volume éphémère, sans que cela ne soit immédiatement visible.",[23,1070,1072],{"id":1071},"schéma-ce-quil-sest-vraiment-passé","Schéma : ce qu’il s’est vraiment passé",[19,1074,1075],{},"Pour comprendre visuellement :",[19,1077,1078],{},"👉 C’est exactement ce qui rend ce problème piégeux.",[19,1080,1081],{},[176,1082],{"alt":1083,"src":1084},"Schéma montrant un conteneur Calibre-Web connecté à un NAS via des volumes Docker montés en NFS. Trois répertoires du conteneur (\u002Fconfig, \u002Flibrary, \u002Fcwa-book-ingest) sont reliés par des flèches vertes à des volumes stockés sur le NAS, indiquant un montage correct et fonctionnel. Un quatrième répertoire (\u002Fbooks) est représenté avec une ligne rouge en pointillés, signalant un volume mal monté ou non fonctionnel. Le NAS est illustré comme un stockage central recevant et fournissant les données au conteneur.","\u002Fcontent-assets\u002F2026-04-20-docker-volumes-et-perte-de-donnees-pourquoi-vos-donnees-disparaissent\u002Fassets\u002Fimg2.webp",[19,1086,1087,1088,1091,1092,44],{},"👉 ",[34,1089,1090],{},"La clé à comprendre :"," Docker ne “perd” pas les données. Il les écrit simplement ",[34,1093,1094],{},"ailleurs que là où l’application les lit",[952,1096],{},[23,1098,1100],{"id":1099},"la-configuration-corrigée","La configuration corrigée",[19,1102,1103],{},"Voici la stack Compose fonctionnelle :",[344,1105,1109],{"className":1106,"code":1107,"language":1108,"meta":350,"style":350},"language-yaml shiki shiki-themes github-dark-default","services:\n  calibre-web-automated:\n    image: crocodilestick\u002Fcalibre-web-automated:v4.0.6\n    networks:\n      - proxy\n    volumes:\n      - calibre-web-config:\u002Fconfig\n      - calibre-web-library:\u002Fcalibre-library\n      - calibre-web-ingest:\u002Fcwa-book-ingest\n      - \u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro\n    environment:\n      - PUID=1000\n      - PGID=1000\n      - TZ=Europe\u002FParis\n      - DOCKER_MODS=linuxserver\u002Fmods:universal-calibre\n    deploy:\n      mode: replicated\n      replicas: 1\n\nnetworks:\n  proxy:\n    external: true\n\nvolumes:\n  calibre-web-config:\n    driver: local\n    driver_opts:\n      type: nfs\n      o: addr=192.168.0.174,nolock,soft,rw\n      device:\":\u002Fvolume1\u002Fdocker-swarm-nfs\u002Fcalibre-web\u002Fconfig\"\n  calibre-web-library:\n    driver: local\n    driver_opts:\n      type: nfs\n      o: addr=192.168.0.174,nolock,soft,rw\n      device:\":\u002Fvolume1\u002Fdocker-swarm-nfs\u002Fcalibre-web\u002Flibrary\"\n  calibre-web-ingest:\n    driver: local\n    driver_opts:\n      type: nfs\n      o: addr=192.168.0.174,nolock,soft,rw\n      device:\":\u002Fvolume1\u002Fdocker-swarm-nfs\u002Fcalibre-web\u002Fingest\"\n","yaml",[352,1110,1111,1121,1128,1140,1147,1155,1163,1171,1179,1187,1195,1203,1211,1219,1227,1235,1243,1254,1266,1272,1280,1288,1299,1304,1312,1320,1331,1339,1350,1361,1367,1375,1384,1391,1400,1409,1415,1423,1432,1439,1448,1457],{"__ignoreMap":350},[355,1112,1113,1117],{"class":357,"line":358},[355,1114,1116],{"class":1115},"sPWt5","services",[355,1118,1120],{"class":1119},"sZEs4",":\n",[355,1122,1123,1126],{"class":357,"line":364},[355,1124,1125],{"class":1115},"  calibre-web-automated",[355,1127,1120],{"class":1119},[355,1129,1130,1133,1136],{"class":357,"line":370},[355,1131,1132],{"class":1115},"    image",[355,1134,1135],{"class":1119},": ",[355,1137,1139],{"class":1138},"s9uIt","crocodilestick\u002Fcalibre-web-automated:v4.0.6\n",[355,1141,1142,1145],{"class":357,"line":376},[355,1143,1144],{"class":1115},"    networks",[355,1146,1120],{"class":1119},[355,1148,1149,1152],{"class":357,"line":382},[355,1150,1151],{"class":1119},"      - ",[355,1153,1154],{"class":1138},"proxy\n",[355,1156,1158,1161],{"class":357,"line":1157},6,[355,1159,1160],{"class":1115},"    volumes",[355,1162,1120],{"class":1119},[355,1164,1166,1168],{"class":357,"line":1165},7,[355,1167,1151],{"class":1119},[355,1169,1170],{"class":1138},"calibre-web-config:\u002Fconfig\n",[355,1172,1174,1176],{"class":357,"line":1173},8,[355,1175,1151],{"class":1119},[355,1177,1178],{"class":1138},"calibre-web-library:\u002Fcalibre-library\n",[355,1180,1182,1184],{"class":357,"line":1181},9,[355,1183,1151],{"class":1119},[355,1185,1186],{"class":1138},"calibre-web-ingest:\u002Fcwa-book-ingest\n",[355,1188,1190,1192],{"class":357,"line":1189},10,[355,1191,1151],{"class":1119},[355,1193,1194],{"class":1138},"\u002Fetc\u002Flocaltime:\u002Fetc\u002Flocaltime:ro\n",[355,1196,1198,1201],{"class":357,"line":1197},11,[355,1199,1200],{"class":1115},"    environment",[355,1202,1120],{"class":1119},[355,1204,1206,1208],{"class":357,"line":1205},12,[355,1207,1151],{"class":1119},[355,1209,1210],{"class":1138},"PUID=1000\n",[355,1212,1214,1216],{"class":357,"line":1213},13,[355,1215,1151],{"class":1119},[355,1217,1218],{"class":1138},"PGID=1000\n",[355,1220,1222,1224],{"class":357,"line":1221},14,[355,1223,1151],{"class":1119},[355,1225,1226],{"class":1138},"TZ=Europe\u002FParis\n",[355,1228,1230,1232],{"class":357,"line":1229},15,[355,1231,1151],{"class":1119},[355,1233,1234],{"class":1138},"DOCKER_MODS=linuxserver\u002Fmods:universal-calibre\n",[355,1236,1238,1241],{"class":357,"line":1237},16,[355,1239,1240],{"class":1115},"    deploy",[355,1242,1120],{"class":1119},[355,1244,1246,1249,1251],{"class":357,"line":1245},17,[355,1247,1248],{"class":1115},"      mode",[355,1250,1135],{"class":1119},[355,1252,1253],{"class":1138},"replicated\n",[355,1255,1257,1260,1262],{"class":357,"line":1256},18,[355,1258,1259],{"class":1115},"      replicas",[355,1261,1135],{"class":1119},[355,1263,1265],{"class":1264},"sFSAA","1\n",[355,1267,1269],{"class":357,"line":1268},19,[355,1270,1271],{"emptyLinePlaceholder":893},"\n",[355,1273,1275,1278],{"class":357,"line":1274},20,[355,1276,1277],{"class":1115},"networks",[355,1279,1120],{"class":1119},[355,1281,1283,1286],{"class":357,"line":1282},21,[355,1284,1285],{"class":1115},"  proxy",[355,1287,1120],{"class":1119},[355,1289,1291,1294,1296],{"class":357,"line":1290},22,[355,1292,1293],{"class":1115},"    external",[355,1295,1135],{"class":1119},[355,1297,1298],{"class":1264},"true\n",[355,1300,1302],{"class":357,"line":1301},23,[355,1303,1271],{"emptyLinePlaceholder":893},[355,1305,1307,1310],{"class":357,"line":1306},24,[355,1308,1309],{"class":1115},"volumes",[355,1311,1120],{"class":1119},[355,1313,1315,1318],{"class":357,"line":1314},25,[355,1316,1317],{"class":1115},"  calibre-web-config",[355,1319,1120],{"class":1119},[355,1321,1323,1326,1328],{"class":357,"line":1322},26,[355,1324,1325],{"class":1115},"    driver",[355,1327,1135],{"class":1119},[355,1329,1330],{"class":1138},"local\n",[355,1332,1334,1337],{"class":357,"line":1333},27,[355,1335,1336],{"class":1115},"    driver_opts",[355,1338,1120],{"class":1119},[355,1340,1342,1345,1347],{"class":357,"line":1341},28,[355,1343,1344],{"class":1115},"      type",[355,1346,1135],{"class":1119},[355,1348,1349],{"class":1138},"nfs\n",[355,1351,1353,1356,1358],{"class":357,"line":1352},29,[355,1354,1355],{"class":1115},"      o",[355,1357,1135],{"class":1119},[355,1359,1360],{"class":1138},"addr=192.168.0.174,nolock,soft,rw\n",[355,1362,1364],{"class":357,"line":1363},30,[355,1365,1366],{"class":1138},"      device:\":\u002Fvolume1\u002Fdocker-swarm-nfs\u002Fcalibre-web\u002Fconfig\"\n",[355,1368,1370,1373],{"class":357,"line":1369},31,[355,1371,1372],{"class":1115},"  calibre-web-library",[355,1374,1120],{"class":1119},[355,1376,1378,1380,1382],{"class":357,"line":1377},32,[355,1379,1325],{"class":1115},[355,1381,1135],{"class":1119},[355,1383,1330],{"class":1138},[355,1385,1387,1389],{"class":357,"line":1386},33,[355,1388,1336],{"class":1115},[355,1390,1120],{"class":1119},[355,1392,1394,1396,1398],{"class":357,"line":1393},34,[355,1395,1344],{"class":1115},[355,1397,1135],{"class":1119},[355,1399,1349],{"class":1138},[355,1401,1403,1405,1407],{"class":357,"line":1402},35,[355,1404,1355],{"class":1115},[355,1406,1135],{"class":1119},[355,1408,1360],{"class":1138},[355,1410,1412],{"class":357,"line":1411},36,[355,1413,1414],{"class":1138},"      device:\":\u002Fvolume1\u002Fdocker-swarm-nfs\u002Fcalibre-web\u002Flibrary\"\n",[355,1416,1418,1421],{"class":357,"line":1417},37,[355,1419,1420],{"class":1115},"  calibre-web-ingest",[355,1422,1120],{"class":1119},[355,1424,1426,1428,1430],{"class":357,"line":1425},38,[355,1427,1325],{"class":1115},[355,1429,1135],{"class":1119},[355,1431,1330],{"class":1138},[355,1433,1435,1437],{"class":357,"line":1434},39,[355,1436,1336],{"class":1115},[355,1438,1120],{"class":1119},[355,1440,1442,1444,1446],{"class":357,"line":1441},40,[355,1443,1344],{"class":1115},[355,1445,1135],{"class":1119},[355,1447,1349],{"class":1138},[355,1449,1451,1453,1455],{"class":357,"line":1450},41,[355,1452,1355],{"class":1115},[355,1454,1135],{"class":1119},[355,1456,1360],{"class":1138},[355,1458,1460],{"class":357,"line":1459},42,[355,1461,1462],{"class":1138},"      device:\":\u002Fvolume1\u002Fdocker-swarm-nfs\u002Fcalibre-web\u002Fingest\"\n",[19,1464,1465],{},"Cette fois, tous les répertoires utilisés par l’application sont correctement persistés.",[952,1467],{},[23,1469,1471],{"id":1470},"comment-tester-la-persistance-dun-service","Comment tester la persistance d’un service",[19,1473,1474],{},"Une bonne pratique simple (et souvent oubliée) :",[443,1476,1477,1480,1483,1486,1489],{},[446,1478,1479],{},"Démarrer le service",[446,1481,1482],{},"Ajouter une donnée (ex : un fichier ou un livre en l'occurrence)",[446,1484,1485],{},"Supprimer le conteneur",[446,1487,1488],{},"Le recréer",[446,1490,1491],{},"Vérifier que la donnée est toujours présente et accessible",[19,1493,1494],{},"👉 Si ce test échoue, votre persistance est cassée.",[952,1496],{},[23,1498,1500],{"id":1499},"ce-que-jai-appris","Ce que j'ai appris",[19,1502,1503,1504],{},"Cette expérience m’a appris une chose essentielle :\n👉 ",[34,1505,1506],{},"Avec Docker, une donnée n’est persistante que si vous savez exactement où elle est écrite.",[19,1508,1509,1510,1513],{},"Les volumes ne sont pas compliqués… mais ils sont ",[34,1511,1512],{},"implicites"," :",[443,1515,1516,1519],{},[446,1517,1518],{},"Docker ne valide pas votre intention",[446,1520,1521],{},"Il exécute simplement votre configuration",[19,1523,1524],{},"Résultat : une simple erreur de mapping peut donner l’impression que les données ont disparu, alors qu’elles sont juste… ailleurs.",[23,1526,1528],{"id":1527},"conclusion","Conclusion",[19,1530,1531],{},"Docker est un outil extrêmement puissant, mais aussi très permissif. Et c’est justement ça le danger.",[19,1533,1534],{},"En pratique, ce qu’il faut retenir :",[443,1536,1537,1540,1543,1546],{},[446,1538,1539],{},"Identifiez toujours les dossiers critiques d’une application",[446,1541,1542],{},"Vérifiez où les données sont réellement écrites",[446,1544,1545],{},"Testez systématiquement vos déploiements",[446,1547,1548,1549],{},"Et surtout : ",[34,1550,1551],{},"ne faites jamais confiance à une configuration non testée",[19,1553,1554],{},"Parce qu’en production, ce type d’erreur ne pardonne pas.",[856,1556,1557],{},"html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":350,"searchDepth":364,"depth":364,"links":1559},[1560,1561,1564,1565,1566,1567,1568,1569,1570],{"id":931,"depth":364,"text":932},{"id":956,"depth":364,"text":957,"children":1562},[1563],{"id":963,"depth":370,"text":964},{"id":1018,"depth":364,"text":1019},{"id":1058,"depth":364,"text":1059},{"id":1071,"depth":364,"text":1072},{"id":1099,"depth":364,"text":1100},{"id":1470,"depth":364,"text":1471},{"id":1499,"depth":364,"text":1500},{"id":1527,"depth":364,"text":1528},"2026-04-20T12:21:10.137Z","Récemment, j’ai vécu ma première “vraie” perte de données dans mon homelab. Rien de critique… mais suffisamment frustrant pour me rappeler une règle essentielle avec Docker : 👉 Les données ne dispara",{},"\u002Fblogs\u002F2026-04-20-docker-volumes-et-perte-de-donnees-pourquoi-vos-donnees-disparaissent",[1576,1581],{"id":1577,"name":1578,"image":1579,"linkedin":1580,"x":901},"67adfd77-4b84-4496-b55d-3391541f59c5","Michaël Bernasinski",".\u002Fassets\u002Freviewer-michael-bernasinski.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fmichael-bernasinski",{"id":1582,"name":1583,"image":1584,"linkedin":1585,"x":901},"0bb914a6-f882-4951-bee6-53e8e8abb807","Emmanuelle Gouvart",".\u002Fassets\u002Freviewer-emmanuelle-gouvart.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Femmanuellegouvart-182b6ab2\u002F",{"title":913,"description":1572},"blogs\u002F2026-04-20-docker-volumes-et-perte-de-donnees-pourquoi-vos-donnees-disparaissent\u002Findex",[1589,1590,1591,1592,906],"docker","cloud native","devops","rex","28WRAVFXqaUTiw3o7NHSK5vZQp6mJXnKU4-y08gCTwg",{"id":1595,"title":1596,"alt":1597,"authors":1598,"body":1601,"date":1864,"description":1865,"extension":890,"image":891,"meta":1866,"navigation":893,"ogImage":891,"path":1867,"published":893,"reviewers":1868,"seo":1876,"stem":1877,"tags":1878,"__hash__":1880},"blogs\u002Fblogs\u002F2026-04-14-rex-environnements-phmres\u002Findex.md","REX: Environnements éphémères","Image d’illustration, une usine à environnements éphémères qui sont créés, validés puis détruits",[1599],{"id":1577,"name":1578,"image":1600,"linkedin":1580,"x":901},".\u002Fassets\u002Fauthor-michal-bernasinski.webp",{"type":16,"value":1602,"toc":1854},[1603,1606,1624,1631,1638,1648,1652,1659,1662,1680,1684,1690,1694,1716,1732,1735,1741,1750,1755,1764,1768,1775,1782,1788,1792,1814,1818,1829,1837,1839,1848,1851],[19,1604,1605],{},"Tout au long de ma carrière de développeur web, une question s’est toujours posée : comment tester une nouvelle fonctionnalité développée ? Une anomalie corrigée ?",[19,1607,1608,1609,1614,1615,1618,1619,1623],{},"Certes les tests automatisés répondent en partie à la problématique, par exemple grâce au ",[91,1610,1613],{"href":1611,"rel":1612},"https:\u002F\u002Fhoppr-tech.notion.site\u002FFormation-TDD-HoppR-19ff4462cd388034b74eecb49e31630d",[95],"TDD",", mais ",[34,1616,1617],{},"quid de la validation humaine",", par un ",[1620,1621,1622],"em",{},"product owner",", un testeur, voire un utilisateur final ?",[19,1625,1626,1627,1630],{},"Beaucoup de projets utilisent des environnements de recette. Mais ceux-ci finissent rapidement avec des données bancales\u002Fobsolètes, des configurations bricolées, et où plusieurs fonctionnalités mergées récemment s’entremêlent. Et qui n’a jamais entendu une phrase du type “",[1620,1628,1629],{},"N’utilisez pas la recette, je fais des tests dessus","”, bloquant ainsi l’ensemble de l’équipe et réduisant la productivité de celle-ci.",[19,1632,1633,1634,1637],{},"De plus, si le développement mergé ne répond pas au besoin, cela entraîne deux choses : soit un commit “parasite” a été introduit sur la branche ",[352,1635,1636],{},"main"," testée, soit l’évitement de ce problème nécessite un travail sur plusieurs branches Git parallèles et autant de complexité ajoutée.",[19,1639,1640,1641,1644,1645,1647],{},"Dès lors, comment tester manuellement une fonctionnalité de manière isolée ? Sur un environnement propre ? Ou des tests end-to-end peuvent être joués sans difficultés pour chaque ",[1620,1642,1643],{},"merge request"," ? Sur une MR qui sera validée avant de partir sur une branche ",[352,1646,1636],{}," ?",[23,1649,1651],{"id":1650},"quest-ce-quun-environnement-éphémère","Qu’est-ce qu’un environnement éphémère ?",[19,1653,1654,1655,1658],{},"Comme son nom l’indique, ",[34,1656,1657],{},"un environnement éphémère est une instance qui a une durée de vie limitée",", par exemple à la MR à laquelle il est rattaché. Il est construit dans une configuration au plus proche de celle de production, avec des données de test préchargées si nécessaire, pour faciliter les tests automatisés (end-to-end par exemple) et manuels.",[19,1660,1661],{},"Une fois que l’on sait créer un environnement éphémère facilement, plusieurs cas d’usage se présentent :",[443,1663,1664,1674,1677],{},[446,1665,1666,1667,1669,1670,1673],{},"Celui que j’ai le plus utilisé, une ",[1620,1668,1643],{}," = un environnement éphémère. Ainsi, n’importe qui dans l’équipe peut visualiser et valider les modifications avant ",[1620,1671,1672],{},"merge"," de la branche",[446,1675,1676],{},"Création d’un environnement dédié propre pour des démonstrations, qu’elles soient internes ou aux utilisateurs",[446,1678,1679],{},"Un environnement créé pour des tests end-to-end, détruit ensuite",[23,1681,1683],{"id":1682},"retour-dexpérience","Retour d’expérience",[19,1685,1686,1687,44],{},"Je vais vous faire mon retour d’expérience de l’utilisation de ces environnements éphémères, lors de mon projet actuel chez mon client. Ces environnements sont systématiquement utilisés, pour chaque MR ",[34,1688,1689],{},"sans exception",[84,1691,1693],{"id":1692},"la-mise-en-place","La mise en place",[19,1695,1696,1697,504,1701,508,1706,1711,1712,1715],{},"Sur le projet, nous utilisons les outils suivants : ",[91,1698,58],{"href":1699,"rel":1700},"https:\u002F\u002Faws.amazon.com\u002Ffr\u002F",[95],[91,1702,1705],{"href":1703,"rel":1704},"https:\u002F\u002Fdeveloper.hashicorp.com\u002Fterraform",[95],"Terraform",[91,1707,1710],{"href":1708,"rel":1709},"https:\u002F\u002Fabout.gitlab.com\u002F",[95],"Gitlab",". Cela nous permet de facilement automatiser la construction des environnements avec l’",[34,1713,1714],{},"infrastructure-as-code"," (IaC).",[19,1717,1718,1719,1721,1722,1727,1728,1731],{},"Pour avoir un environnement disponible à la création de la ",[1620,1720,1643],{},", nous utilisons une ",[91,1723,1726],{"href":1724,"rel":1725},"https:\u002F\u002Fdocs.gitlab.com\u002Fci\u002Fvariables\u002Fpredefined_variables\u002F",[95],"variable prédéfinie de GitLab"," nommée ",[352,1729,1730],{},"CI_MERGE_REQUEST_IID"," , un identifiant de la MR spécifique au projet. Cela nous permet d’intégrer la construction de l’environnement à la pipeline de CI\u002FCD.",[19,1733,1734],{},"Bien entendu, hors de question d’installer un environnement inutilement pour un développement qui ne passe pas les tests unitaires. La pipeline ressemble donc  grossièrement à ceci :",[19,1736,1737],{},[176,1738],{"alt":1739,"src":1740},"Exemple de pipeline : build ⇒ TU ⇒ environnement éphémère","\u002Fcontent-assets\u002F2026-04-14-rex-environnements-phmres\u002Fassets\u002Fimg1.webp",[19,1742,1743,1744,1749],{},"A noter que l’environnement éphémère créé à la volée possède ses propres ressources AWS, (dans notre cas, des buckets S3, des queues SQS, etc.). Un jeu de données spécifique à ces environnements est mis en place via un script ",[91,1745,1748],{"href":1746,"rel":1747},"https:\u002F\u002Fwww.liquibase.com\u002Fhow-liquibase-works",[95],"liquibase"," pour un référentiel de données nécessaire aux tests. Ainsi naît un environnement avec une URL du type",[19,1751,1752],{},[352,1753,1754],{},"https:\u002F\u002Fenv-${CI_MERGE_REQUEST_IID}.client.fr",[19,1756,1757,1758,1763],{},"Bien évidemment, il faut faire attention à ne pas oublier de détruire automatiquement l’environnement à la fermeture de la MR, qu’elle soit mergée ou non (avec l’aide de ",[91,1759,1762],{"href":1760,"rel":1761},"https:\u002F\u002Fdocs.gitlab.com\u002Fuser\u002Fproject\u002Fintegrations\u002Fwebhook_events\u002F#merge-request-events",[95],"webhooks Gitlab","). On pourra également donner une durée de vie maximum à l’environnement. Cela nécessite également une bonne observabilité pour ne pas garder d’environnements “fantômes” coûteux.",[84,1765,1767],{"id":1766},"la-mise-en-situation","La mise en situation",[19,1769,1770,1771,1774],{},"Maintenant que nous avons des environnements éphémères pour chaque ",[1620,1772,1773],{},"merge request,","  comment allons-nous les utiliser ?",[19,1776,1777,1778,1781],{},"Notre principale idée ici est d’intégrer les ",[1620,1779,1780],{},"product owners"," dans la construction de chaque feature. Ainsi, là où la majorité des projets ne demande qu’une validation technique par un pair technique, nous demandons également une validation fonctionnelle par un PO ou un UX, suivant le sujet.",[19,1783,1784],{},[176,1785],{"alt":1786,"src":1787},"Exemple sur une MR sur GitLab : le PO ET un autre dev ont validé la MR, qui a ensuite pu être mergée","\u002Fcontent-assets\u002F2026-04-14-rex-environnements-phmres\u002Fassets\u002Fimg2.webp",[84,1789,1791],{"id":1790},"les-avantages","Les avantages",[443,1793,1794,1797,1800,1803,1806],{},[446,1795,1796],{},"Chaque MR dispose d’un environnement dédié, évitant les interférences entre les fonctionnalités en développement",[446,1798,1799],{},"Terraform garantit que chaque environnement est identique (mêmes configurations, versions, dépendances), et permet de provisionner\u002Fdétruire l’infrastructure à la demande.",[446,1801,1802],{},"D’ailleurs, cela permet la génération de multiples environnements avec la même config, plus besoin de maintenir chaque environnement de recette\u002Fformation\u002Fdémo séparément",[446,1804,1805],{},"Facilite le développement, l’intégration et le déploiement continu",[446,1807,1808,1809],{},"Permet une amélioration de vos ",[91,1810,1813],{"href":1811,"rel":1812},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-10-31-dora-metrics-valuer-la-performance-de-livraison-logicielle#quest-ce-que-les-m%C3%A9triques-dora",[95],"DORA Metrics",[84,1815,1817],{"id":1816},"les-inconvénients","Les inconvénients",[443,1819,1820,1823,1826],{},[446,1821,1822],{},"La mise en place du fonctionnement est complexe, et nécessite un investissement initial important en début de projet. De plus, cela nécessite une bonne maîtrise des outils utilisés",[446,1824,1825],{},"La construction automatique d’un environnement complet peut prendre du temps, et rallonger la pipeline",[446,1827,1828],{},"Avoir un métier (PO\u002FUX) pleinement impliqué et disponible pour faire des revues fonctionnelles.",[19,1830,1831,1832,44],{},"Pour ce dernier point, c’est le cas sur ce produit, donc pas d’inquiétude là-dessus. Il faut de toute façon toujours impliquer le métier dans le développement et inversement, c’est la clé de la réussite de tous vos projets, et c’est cela que l’on pousse systématiquement chez ",[91,1833,1836],{"href":1834,"rel":1835},"https:\u002F\u002Fwww.hoppr.tech\u002F",[95],"HoppR",[23,1838,1528],{"id":1527},[19,1840,1841,1842,1844,1845,1847],{},"Toute l’équipe est ravie de ce système de double validation technique\u002Fmétier sur chaque ",[1620,1843,1643],{}," fonctionnelle. Les ",[1620,1846,1780],{}," et les développeurs travaillent en symbiose sur le produit, ce qui est nécessaire dans une équipe pluri-disciplinaire soudée.",[19,1849,1850],{},"L’investissement initial à la mise en place des environnements éphémères est largement rentabilisé, fluidifiant le processus de développement. Ce système est d’ailleurs petit à petit propagé à d’autres produits chez le même client, suite à nos retours d’expérience positifs.",[19,1852,1853],{},"Alors, qu’attendez-vous pour employer les environnements éphémères, et mieux impliquer le métier dans vos développements ?",{"title":350,"searchDepth":364,"depth":364,"links":1855},[1856,1857,1863],{"id":1650,"depth":364,"text":1651},{"id":1682,"depth":364,"text":1683,"children":1858},[1859,1860,1861,1862],{"id":1692,"depth":370,"text":1693},{"id":1766,"depth":370,"text":1767},{"id":1790,"depth":370,"text":1791},{"id":1816,"depth":370,"text":1817},{"id":1527,"depth":364,"text":1528},"2026-04-14T07:29:50.497Z","Tout au long de ma carrière de développeur web, une question s’est toujours posée : comment tester une nouvelle fonctionnalité développée ? Une anomalie corrigée ?  Certes les tests automatisés répond",{},"\u002Fblogs\u002F2026-04-14-rex-environnements-phmres",[1869,1871,1874],{"id":1582,"name":1583,"image":1870,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4663EVYACVJ%2F20260414%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260414T072949Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEL7%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJHMEUCIGZtaRbA4cSdTwdKuo6iJWkH8%2F7Mf4%2F7P2W6PXte3kjGAiEAok6aw4VityW2XGt3RF9AGdcuCRas9ZE5wwRFKdD8whcqiAQIh%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDJYMPZlPCPZ%2B%2BEq4XyrcA0HVbqp5SrmxfwBpOmpGhgMIg2gTLjV3M6tzdLTdz1DY3m5Zswt94ObBgZT2zhyiePmuVZBd1Yg1lc3W5l4Plvp1OTzIp4BRtM5hZrAXZfoBHQWnigkX1G6zQbPZUIgWCLbbCRfsX0MMT0k49aDA2T2%2B8kuBS8gWNYR1P1hwkZtrA02V4rtsmCfaFrkZZB7EItp9LNTxhmjx9Z7YNBJx9n%2F5ZNY2MIIwLM%2BoEhgaCs4ReNV608nFYY8f0%2F9QzMZye3PM5WlCN9Sgf1O%2FfCO31or9a0z%2FCfxAL37zIa6parPGRxTaGuGT1V2q%2Ftn%2FD%2FVaFbFq0tsFOU5vDyhrQRTjHVOC9i0Bxr%2Bu3Ak9jtAgSZk5gcMpBe1Gwvsu0G8ZWVcPFk0gio%2BfOHd%2BPPJaDoGo5eGVGw5gyBGbovOThBvyvMT6eXcrDWWntNs4IA8iJgFkhRDOI0WPwf3Z%2BASr9UFvNBIGFwOJWG6nRfqJ1c2e7z9yFAhtmFO%2FIAu3p0QMoZ7diWXeFiPcptFAary1LxEwUC9ajIIaF92J%2FIcsZzX%2BUujpZZXDCM7clyCayH%2BgBBdk5ZCXXtuxzLHQG9CWt%2F4HOmafqFTCwhwO3l1BU8fjUNzofspm0KV4sf8cP4yrMKq0984GOqUB4D0QZc81PuEfU5nOGA8R6pZbugM8G6tdhcqL%2BDIjVIXKvGD7pUh8JrnWiiJttpmlBsSRPNT712UTe6nfpUsgIoYecV5eladz3QX4lKzPcT6DFOK1QyILpjC%2BYfO4yoLETTJ0kMmTpOEZMJDhT%2B1qbyLmH3tunIsjs5KTzObbxMOPWCum76IZMm%2Ft7V53%2BjfXdBwkLQRu7hgyITrMqz2603DNgwUd&X-Amz-Signature=52a40968af7f41c867e910c4f5f34edb18ae5a028da26372aaa8b48db773f820&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":1872,"name":1873,"image":901,"linkedin":901,"x":901},"320f4462-cd38-8071-8eb7-f90621a068a3","Marjorie Dieusart",{"id":917,"name":918,"image":1875,"linkedin":920,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F2b6052d3-047d-4e1d-9256-fea2c2adc9e6\u002FPhoto_Profil_CV_1200px_%289%29.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4663SBXKDNX%2F20260414%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260414T072949Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEL7%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJHMEUCIQDoQ2zeta%2FyHTI540wsMH0HxSAY%2BATUU8y1DXJo49%2FR3QIgfgYpE8rnxVjQjdXQSdfSs4FkbukBGNmM4mYPxzHzNsoqiAQIh%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDH%2FXA22vPQpx%2FkhClCrcA479MmEEV6I9eigvXgytlLjiNUm7v9pTEdM6CFlyZps94bpHWFfG1VfrFw5wOqXSNRFgPrU%2BgGOGKxBi49qeUtd1KdV%2FAPniG8hILB88TLq0EP1yYuBzeSzZmQ%2FqW2T8t92AsCFIedtwHr2DEc%2BKS9q4BREb75QOIKQukTD4iyXiMTaQOHGbu1wYT7I0NUnIHCYv6MyctXcxvPMrjVuxcHmU9EqjvvBHhzpZSzZWHdoR7NhEiNn3ia5TEEurHsuCHtwJP33t86%2FWvgmpv3eqDKI1h8U84OHcINLxPkHCjNytazhXEsDQii%2FC1ejswGUQajdRdLTT6orMRQ1jiUqWYYLtHUUluWzswhoWbBQF2Gd0DaN5AlEh4LjA92uMSg7Ooz6EkIEX2IfuKc6P%2B6v2BVD3wrrJwaCJUJK38ponmF03%2B5WYj0BOvHc6QpkSqO3ptcz2m2NTsHSJJQIdXInRtGGkcfIpLKPeRVr%2F4ueugg%2BTdv05AwuLXcwhOiBDx%2FiSPKxu8DzESmpt1KL7097NPp33PkgeOi%2BoMuGjNn0mJQCL6aTfQHl%2FGwVCu8fC04fqlmgDI4bGR9uT0VWcLEtS93V%2FWCVctavIuyFfTjm3bW3YnQqmDWvoTF5bglFAMMi1984GOqUBpwexbiOU10bG1oXGEC8pAoGR1qleIYaJFatZ3Hn2l02%2ByqIleJqpNHHJunG9BF04s4vtqS4IOIhpUc6y63prUVltgzFyGsM7q46WZwKClOYQ%2BHR9DQTSdAv7ujF3tdq%2BezDPIBWNstYKoWlRBL7cGoqdzL9Rs0SnZtD4ZSEFTkSEXVLeb8klio4AlBqqsVoslyJMFnZurcUaJ0HQyVxlldG%2FFXzY&X-Amz-Signature=760c14d682562a02818ac9dd16ece58d593677ef6cde7d10ff42bcb67502a42e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":1596,"description":1865},"blogs\u002F2026-04-14-rex-environnements-phmres\u002Findex",[1879,1592],"craft","l4AE9RbTPfGFFrIE5a0c5Yvcj9eYR9PrSGRNYuMi4qg",{"id":1882,"title":1883,"alt":1884,"authors":1885,"body":1896,"date":3513,"description":3514,"extension":890,"image":891,"meta":3515,"navigation":893,"ogImage":891,"path":3516,"published":893,"reviewers":3517,"seo":3524,"stem":3525,"tags":3526,"__hash__":3527},"blogs\u002Fblogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit\u002Findex.md","Architecture hexagonale en programmation fonctionnelle, mythe ou réalité ?","Quand l’architecture hexagonale rencontre la programmation fonctionnelle",[1886,1892],{"id":1887,"name":1888,"image":1889,"linkedin":1890,"x":1891},"02c620f8-3576-4943-b5cf-6117f99220a2","Edouard Cattez",".\u002Fassets\u002Fauthor-edouard-cattez.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fedouard-cattez-865794133\u002F","https:\u002F\u002Fx.com\u002Fecattez",{"id":1893,"name":1894,"image":1895,"linkedin":901,"x":901},"188f4462-cd38-80d5-b9e6-ec28a94d11e5","Bastien Dufour","\u002Fdefault-author-image.webp",{"type":16,"value":1897,"toc":3504},[1898,1901,1908,1911,1914,1918,1926,2582,2585,2588,2605,2624,2642,2645,2750,2761,2768,2771,2775,2787,2790,2910,2913,2917,2920,3003,3006,3010,3013,3486,3489,3492,3494,3501],[19,1899,1900],{},"À mesure que les systèmes logiciels gagnent en complexité, les approches traditionnelles de conception montrent leurs limites. Couplage excessif, difficulté à tester, rigidité face au changement : autant de symptômes qui ralentissent l’évolution des applications modernes. Dans ce contexte, deux courants se distinguent par leur capacité à apporter clarté, robustesse et maintenabilité : l’architecture hexagonale et la programmation fonctionnelle.",[19,1902,1903,1904,1907],{},"L’architecture hexagonale, aussi appelée ",[1620,1905,1906],{},"Ports and Adapters",", propose de recentrer le cœur métier en le protégeant des dépendances techniques. Elle favorise une séparation nette entre la logique métier et les interactions externes, rendant les systèmes plus modulaires et testables.\nDe son côté, la programmation fonctionnelle introduit des principes comme l’immuabilité, les fonctions pures et la composition, permettant de construire des logiciels plus prévisibles et plus faciles à raisonner.",[19,1909,1910],{},"Bien que ces deux approches soient issues de contextes différents, elles partagent une même ambition : réduire la complexité accidentelle pour laisser place à l’essentiel. Leur combinaison ouvre la voie à des architectures élégantes, où le code devient non seulement plus fiable, mais aussi plus expressif.",[19,1912,1913],{},"Dans cet article, nous explorerons comment ces deux paradigmes peuvent se compléter, et en quoi leur adoption conjointe peut transformer en profondeur la manière de concevoir et de faire évoluer nos applications.",[23,1915,1917],{"id":1916},"le-langage-ubiquitaire-au-centre-de-larchitecture","Le langage ubiquitaire au centre de l'architecture",[19,1919,1920,1921,44],{},"Nous allons illustrer tout ça avec le calcul de package de ",[91,1922,1925],{"href":1923,"rel":1924},"http:\u002F\u002Fhoppr.tech\u002F",[95],"Hoppr",[355,1927,1930],{"className":1928},[1929],"katex-display",[355,1931,1934],{"className":1932},[1933],"katex",[355,1935,1939,2046,2158,2263,2337,2428,2518],{"className":1936,"ariaHidden":1938},[1937],"katex-html","true",[355,1940,1943,1948,1955,1959,1963,1967,2033,2038,2043],{"className":1941},[1942],"base",[355,1944],{"className":1945,"style":1947},[1946],"strut","height:0.9694em;vertical-align:-0.2861em;",[355,1949,1954],{"className":1950,"style":1953},[1951,1952],"mord","mathnormal","margin-right:0.05017em;","B",[355,1956,1958],{"className":1957},[1951,1952],"o",[355,1960,1962],{"className":1961},[1951,1952],"n",[355,1964,1966],{"className":1965},[1951,1952],"u",[355,1968,1970,1974],{"className":1969},[1951],[355,1971,1973],{"className":1972},[1951,1952],"s",[355,1975,1978],{"className":1976},[1977],"msupsub",[355,1979,1983,2024],{"className":1980},[1981,1982],"vlist-t","vlist-t2",[355,1984,1987,2019],{"className":1985},[1986],"vlist-r",[355,1988,1992],{"className":1989,"style":1991},[1990],"vlist","height:0.3283em;",[355,1993,1995,2000],{"style":1994},"top:-2.55em;margin-left:0em;margin-right:0.05em;",[355,1996],{"className":1997,"style":1999},[1998],"pstrut","height:2.7em;",[355,2001,2007],{"className":2002},[2003,2004,2005,2006],"sizing","reset-size6","size3","mtight",[355,2008,2010,2014],{"className":2009},[1951,2006],[355,2011,2013],{"className":2012},[1951,1952,2006],"Ho",[355,2015,2018],{"className":2016,"style":2017},[1951,1952,2006],"margin-right:0.00773em;","ppR",[355,2020,2023],{"className":2021},[2022],"vlist-s","​",[355,2025,2027],{"className":2026},[1986],[355,2028,2031],{"className":2029,"style":2030},[1990],"height:0.2861em;",[355,2032],{},[355,2034],{"className":2035,"style":2037},[2036],"mspace","margin-right:0.2778em;",[355,2039,2042],{"className":2040},[2041],"mrel","=",[355,2044],{"className":2045,"style":2037},[2036],[355,2047,2049,2053,2061,2065,2069,2072,2075,2079,2083,2146,2150,2155],{"className":2048},[1942],[355,2050],{"className":2051,"style":2052},[1946],"height:1.6em;vertical-align:-0.55em;",[355,2054,2060],{"className":2055,"style":2059},[2056,2057,2058],"mop","op-symbol","large-op","position:relative;top:0em;","∑",[355,2062],{"className":2063,"style":2064},[2036],"margin-right:0.1667em;",[355,2066,2068],{"className":2067},[1951,1952],"m",[355,2070,1958],{"className":2071},[1951,1952],[355,2073,1962],{"className":2074},[1951,1952],[355,2076,2078],{"className":2077},[1951,1952],"t",[355,2080,2082],{"className":2081},[1951,1952],"an",[355,2084,2086,2089],{"className":2085},[1951],[355,2087,2078],{"className":2088},[1951,1952],[355,2090,2092],{"className":2091},[1977],[355,2093,2095,2138],{"className":2094},[1981,1982],[355,2096,2098,2135],{"className":2097},[1986],[355,2099,2102],{"className":2100,"style":2101},[1990],"height:0.3361em;",[355,2103,2104,2107],{"style":1994},[355,2105],{"className":2106,"style":1999},[1998],[355,2108,2110],{"className":2109},[2003,2004,2005,2006],[355,2111,2113,2118,2121,2125,2128,2131],{"className":2112},[1951,2006],[355,2114,2117],{"className":2115,"style":2116},[1951,1952,2006],"margin-right:0.10764em;","f",[355,2119,91],{"className":2120},[1951,1952,2006],[355,2122,2124],{"className":2123},[1951,1952,2006],"c",[355,2126,2078],{"className":2127},[1951,1952,2006],[355,2129,1966],{"className":2130},[1951,1952,2006],[355,2132,2134],{"className":2133},[1951,1952,2006],"re",[355,2136,2023],{"className":2137},[2022],[355,2139,2141],{"className":2140},[1986],[355,2142,2144],{"className":2143,"style":2030},[1990],[355,2145],{},[355,2147],{"className":2148,"style":2149},[2036],"margin-right:0.2222em;",[355,2151,2154],{"className":2152},[2153],"mbin","−",[355,2156],{"className":2157,"style":2149},[2036],[355,2159,2161,2165,2170,2173,2176,2181,2185,2190,2253,2256,2260],{"className":2160},[1942],[355,2162],{"className":2163,"style":2164},[1946],"height:1em;vertical-align:-0.25em;",[355,2166,2169],{"className":2167},[2168],"mopen","(",[355,2171,1973],{"className":2172},[1951,1952],[355,2174,91],{"className":2175},[1951,1952],[355,2177,2180],{"className":2178,"style":2179},[1951,1952],"margin-right:0.01968em;","l",[355,2182,2184],{"className":2183},[1951,1952],"ai",[355,2186,2189],{"className":2187,"style":2188},[1951,1952],"margin-right:0.02778em;","r",[355,2191,2193,2197],{"className":2192},[1951],[355,2194,2196],{"className":2195},[1951,1952],"e",[355,2198,2200],{"className":2199},[1977],[355,2201,2203,2244],{"className":2202},[1981,1982],[355,2204,2206,2241],{"className":2205},[1986],[355,2207,2209],{"className":2208,"style":2101},[1990],[355,2210,2211,2214],{"style":1994},[355,2212],{"className":2213,"style":1999},[1998],[355,2215,2217],{"className":2216},[2003,2004,2005,2006],[355,2218,2220,2223,2226,2229,2232,2235,2238],{"className":2219},[1951,2006],[355,2221,2068],{"className":2222},[1951,1952,2006],[355,2224,2196],{"className":2225},[1951,1952,2006],[355,2227,1962],{"className":2228},[1951,1952,2006],[355,2230,1973],{"className":2231},[1951,1952,2006],[355,2233,1966],{"className":2234},[1951,1952,2006],[355,2236,2196],{"className":2237},[1951,1952,2006],[355,2239,2180],{"className":2240,"style":2179},[1951,1952,2006],[355,2242,2023],{"className":2243},[2022],[355,2245,2247],{"className":2246},[1986],[355,2248,2251],{"className":2249,"style":2250},[1990],"height:0.15em;",[355,2252],{},[355,2254],{"className":2255,"style":2149},[2036],[355,2257,2259],{"className":2258},[2153],"×",[355,2261],{"className":2262,"style":2149},[2036],[355,2264,2266,2270,2273,2328,2331,2334],{"className":2265},[1942],[355,2267],{"className":2268,"style":2269},[1946],"height:0.8444em;vertical-align:-0.15em;",[355,2271,1962],{"className":2272},[1951,1952],[355,2274,2276,2280],{"className":2275},[1951],[355,2277,2279],{"className":2278},[1951,1952],"b",[355,2281,2283],{"className":2282},[1977],[355,2284,2286,2320],{"className":2285},[1981,1982],[355,2287,2289,2317],{"className":2288},[1986],[355,2290,2293],{"className":2291,"style":2292},[1990],"height:0.3117em;",[355,2294,2295,2298],{"style":1994},[355,2296],{"className":2297,"style":1999},[1998],[355,2299,2301],{"className":2300},[2003,2004,2005,2006],[355,2302,2304,2307,2310,2314],{"className":2303},[1951,2006],[355,2305,2068],{"className":2306},[1951,1952,2006],[355,2308,1958],{"className":2309},[1951,1952,2006],[355,2311,2313],{"className":2312},[1951,1952,2006],"i",[355,2315,1973],{"className":2316},[1951,1952,2006],[355,2318,2023],{"className":2319},[2022],[355,2321,2323],{"className":2322},[1986],[355,2324,2326],{"className":2325,"style":2250},[1990],[355,2327],{},[355,2329],{"className":2330,"style":2149},[2036],[355,2332,2259],{"className":2333},[2153],[355,2335],{"className":2336,"style":2149},[2036],[355,2338,2340,2344,2347,2350,2353,2414,2419,2422,2425],{"className":2339},[1942],[355,2341],{"className":2342,"style":2343},[1946],"height:1.0361em;vertical-align:-0.2861em;",[355,2345,2078],{"className":2346},[1951,1952],[355,2348,91],{"className":2349},[1951,1952],[355,2351,1966],{"className":2352},[1951,1952],[355,2354,2356,2360],{"className":2355},[1951],[355,2357,2359],{"className":2358},[1951,1952],"x",[355,2361,2363],{"className":2362},[1977],[355,2364,2366,2406],{"className":2365},[1981,1982],[355,2367,2369,2403],{"className":2368},[1986],[355,2370,2372],{"className":2371,"style":2101},[1990],[355,2373,2374,2377],{"style":1994},[355,2375],{"className":2376,"style":1999},[1998],[355,2378,2380],{"className":2379},[2003,2004,2005,2006],[355,2381,2383,2386,2389,2393,2397,2400],{"className":2382},[1951,2006],[355,2384,2196],{"className":2385},[1951,1952,2006],[355,2387,2068],{"className":2388},[1951,1952,2006],[355,2390,2392],{"className":2391,"style":2179},[1951,1952,2006],"pl",[355,2394,2396],{"className":2395},[1951,1952,2006],"oye",[355,2398,1966],{"className":2399},[1951,1952,2006],[355,2401,2189],{"className":2402,"style":2188},[1951,1952,2006],[355,2404,2023],{"className":2405},[2022],[355,2407,2409],{"className":2408},[1986],[355,2410,2412],{"className":2411,"style":2030},[1990],[355,2413],{},[355,2415,2418],{"className":2416},[2417],"mclose",")",[355,2420],{"className":2421,"style":2149},[2036],[355,2423,2154],{"className":2424},[2153],[355,2426],{"className":2427,"style":2149},[2036],[355,2429,2431,2434,2437,2440,2443,2446,2449,2452,2509,2512,2515],{"className":2430},[1942],[355,2432],{"className":2433,"style":2343},[1946],[355,2435,2169],{"className":2436},[2168],[355,2438,2392],{"className":2439,"style":2179},[1951,1952],[355,2441,91],{"className":2442},[1951,1952],[355,2444,2117],{"className":2445,"style":2116},[1951,1952],[355,2447,1958],{"className":2448},[1951,1952],[355,2450,1962],{"className":2451},[1951,1952],[355,2453,2455,2459],{"className":2454},[1951],[355,2456,2458],{"className":2457},[1951,1952],"d",[355,2460,2462],{"className":2461},[1977],[355,2463,2465,2501],{"className":2464},[1981,1982],[355,2466,2468,2498],{"className":2467},[1986],[355,2469,2472],{"className":2470,"style":2471},[1990],"height:0.1514em;",[355,2473,2474,2477],{"style":1994},[355,2475],{"className":2476,"style":1999},[1998],[355,2478,2480],{"className":2479},[2003,2004,2005,2006],[355,2481,2483,2487,2490,2495],{"className":2482},[1951,2006],[355,2484,2486],{"className":2485},[1951,1952,2006],"ma",[355,2488,2189],{"className":2489,"style":2188},[1951,1952,2006],[355,2491,2494],{"className":2492,"style":2493},[1951,1952,2006],"margin-right:0.03588em;","g",[355,2496,2196],{"className":2497},[1951,1952,2006],[355,2499,2023],{"className":2500},[2022],[355,2502,2504],{"className":2503},[1986],[355,2505,2507],{"className":2506,"style":2030},[1990],[355,2508],{},[355,2510],{"className":2511,"style":2149},[2036],[355,2513,2259],{"className":2514},[2153],[355,2516],{"className":2517,"style":2149},[2036],[355,2519,2521,2524,2527,2579],{"className":2520},[1942],[355,2522],{"className":2523,"style":2164},[1946],[355,2525,1962],{"className":2526},[1951,1952],[355,2528,2530,2533],{"className":2529},[1951],[355,2531,2279],{"className":2532},[1951,1952],[355,2534,2536],{"className":2535},[1977],[355,2537,2539,2571],{"className":2538},[1981,1982],[355,2540,2542,2568],{"className":2541},[1986],[355,2543,2545],{"className":2544,"style":2292},[1990],[355,2546,2547,2550],{"style":1994},[355,2548],{"className":2549,"style":1999},[1998],[355,2551,2553],{"className":2552},[2003,2004,2005,2006],[355,2554,2556,2559,2562,2565],{"className":2555},[1951,2006],[355,2557,2068],{"className":2558},[1951,1952,2006],[355,2560,1958],{"className":2561},[1951,1952,2006],[355,2563,2313],{"className":2564},[1951,1952,2006],[355,2566,1973],{"className":2567},[1951,1952,2006],[355,2569,2023],{"className":2570},[2022],[355,2572,2574],{"className":2573},[1986],[355,2575,2577],{"className":2576,"style":2250},[1990],[355,2578],{},[355,2580,2418],{"className":2581},[2417],[19,2583,2584],{},"Vous y avez compris quelque chose ? Ne vous en faites pas, on va expliciter tout ça.",[19,2586,2587],{},"Gardons en tête que:",[443,2589,2590,2593,2596,2599,2602],{},[446,2591,2592],{},"Le plafond de la marge HoppR par mois est fixe.",[446,2594,2595],{},"Le chiffre d'affaire est la somme du montant des factures, une facture peut être négative (note de frais par exemple).",[446,2597,2598],{},"Le coût employeur est un taux fixe.",[446,2600,2601],{},"Le package est l'addition du salaire et du bonus HoppR.",[446,2603,2604],{},"Si le bonus HoppR est négatif, il est considéré comme nul, autrement dit, le package sera le salaire brut.",[19,2606,2607,2608,2613,2614,2619,2620,2623],{},"Nous avons décidé de partir sur ",[91,2609,2612],{"href":2610,"rel":2611},"https:\u002F\u002Fgleam.run\u002F",[95],"Gleam",", un langage fonctionnel, strictement typé, basé sur ",[91,2615,2618],{"href":2616,"rel":2617},"https:\u002F\u002Felixir-lang.org\u002F",[95],"Elixir",". Ce langage offre la possibilité de créer des alias de type, par exemple ",[352,2621,2622],{},"type MaString = string",". Cette mécanique est une vraie force car elle permet de mettre en évidence les mots clés du métier (ici celui du Package chez HoppR).",[19,2625,2626,2627,504,2630,504,2633,504,2636,504,2639,44],{},"On retrouve ainsi des types comme ",[352,2628,2629],{},"ConsultantId",[352,2631,2632],{},"Revenue",[352,2634,2635],{},"GrossSalary",[352,2637,2638],{},"EmployerRate",[352,2640,2641],{},"GrossMargin",[19,2643,2644],{},"Notre service métier de calcul de package va quant à lui s'exprimer sous la forme d'une fonction.",[344,2646,2650],{"className":2647,"code":2648,"language":2649,"meta":350,"style":350},"language-elixir shiki shiki-themes github-dark-default","pub fn calculate_annual_packaging(\n  revenues: List(Revenue),\n  gross_salary: GrossSalary,\n  employer_rate: EmployerRate,\n  max_margin: GrossMargin,\n) -> Package {\n  let employer_cost = gross_salary |> to_employer_cost(employer_rate)\n\n  revenues\n  |> cumulate\n  |> to_gross_margin(employer_cost)\n  |> cap_at(max_margin)\n  |> to_bonus(employer_rate)\n  |> to_package(gross_salary)\n}\n\n\u002F\u002F Quelques exemples de ce à quoi peuvent ressembler les tests du domaine\npub fn only_one_mission_full_time_test() {...}\npub fn three_missions_during_the_year_test() {...}\npub fn package_is_the_gross_salary_when_the_company_loses_money_test() {...}\n","elixir",[352,2651,2652,2657,2662,2667,2672,2677,2682,2687,2691,2696,2701,2706,2711,2716,2721,2726,2730,2735,2740,2745],{"__ignoreMap":350},[355,2653,2654],{"class":357,"line":358},[355,2655,2656],{},"pub fn calculate_annual_packaging(\n",[355,2658,2659],{"class":357,"line":364},[355,2660,2661],{},"  revenues: List(Revenue),\n",[355,2663,2664],{"class":357,"line":370},[355,2665,2666],{},"  gross_salary: GrossSalary,\n",[355,2668,2669],{"class":357,"line":376},[355,2670,2671],{},"  employer_rate: EmployerRate,\n",[355,2673,2674],{"class":357,"line":382},[355,2675,2676],{},"  max_margin: GrossMargin,\n",[355,2678,2679],{"class":357,"line":1157},[355,2680,2681],{},") -> Package {\n",[355,2683,2684],{"class":357,"line":1165},[355,2685,2686],{},"  let employer_cost = gross_salary |> to_employer_cost(employer_rate)\n",[355,2688,2689],{"class":357,"line":1173},[355,2690,1271],{"emptyLinePlaceholder":893},[355,2692,2693],{"class":357,"line":1181},[355,2694,2695],{},"  revenues\n",[355,2697,2698],{"class":357,"line":1189},[355,2699,2700],{},"  |> cumulate\n",[355,2702,2703],{"class":357,"line":1197},[355,2704,2705],{},"  |> to_gross_margin(employer_cost)\n",[355,2707,2708],{"class":357,"line":1205},[355,2709,2710],{},"  |> cap_at(max_margin)\n",[355,2712,2713],{"class":357,"line":1213},[355,2714,2715],{},"  |> to_bonus(employer_rate)\n",[355,2717,2718],{"class":357,"line":1221},[355,2719,2720],{},"  |> to_package(gross_salary)\n",[355,2722,2723],{"class":357,"line":1229},[355,2724,2725],{},"}\n",[355,2727,2728],{"class":357,"line":1237},[355,2729,1271],{"emptyLinePlaceholder":893},[355,2731,2732],{"class":357,"line":1245},[355,2733,2734],{},"\u002F\u002F Quelques exemples de ce à quoi peuvent ressembler les tests du domaine\n",[355,2736,2737],{"class":357,"line":1256},[355,2738,2739],{},"pub fn only_one_mission_full_time_test() {...}\n",[355,2741,2742],{"class":357,"line":1268},[355,2743,2744],{},"pub fn three_missions_during_the_year_test() {...}\n",[355,2746,2747],{"class":357,"line":1274},[355,2748,2749],{},"pub fn package_is_the_gross_salary_when_the_company_loses_money_test() {...}\n",[19,2751,2752,2753,2756,2757,2760],{},"Ici la lecture de la règle de calcul se voit facilitée par l'usage du ",[1620,2754,2755],{},"pipe operator"," ",[352,2758,2759],{},"|>"," qui envoie dans le premier argument de la fonction du dessous le résultat de la fonction du dessus.",[19,2762,2763,2764,2767],{},"On peut donc lire le code comme on le ferait en langage naturel: on cumule les ",[352,2765,2766],{},"revenues"," auquel on applique une marge brute capée à la marge max. On applique le bonus si bonus il y a et on transforme le tout en package final.",[19,2769,2770],{},"La logique métier est explicite, pure et déterministe.",[84,2772,2774],{"id":2773},"aparté-sur-les-value-objects-et-le-pipe-operator","Aparté sur les value objects et le pipe operator",[19,2776,2777,2778,2783,2784,44],{},"Pour éviter le ",[91,2779,2782],{"href":2780,"rel":2781},"https:\u002F\u002Frefactoring.guru\u002Ffr\u002Fsmells\u002Fprimitive-obsession",[95],"primitive obsession"," et mettre en évidence les concepts du vocabulaire métier, nous créons ce que l'on appelle des ",[34,2785,2786],{},"value objects",[19,2788,2789],{},"Dans la programmation orientée objet, nous aurions quelque chose comme:",[344,2791,2795],{"className":2792,"code":2793,"language":2794,"meta":350,"style":350},"language-java shiki shiki-themes github-dark-default","record Revenue(BigDecimal amount) {}\n\nrecord Revenues(List\u003CRevenue> revenues) {\n    public Revenue cumulate() {\n        return new Revenue(revenues.stream()\n                .map(Revenue::amount)\n                .reduce(BigDecimal.ZERO, BigDecimal::add));\n    }\n}\n","java",[352,2796,2797,2810,2814,2835,2850,2869,2886,2901,2906],{"__ignoreMap":350},[355,2798,2799,2803,2807],{"class":357,"line":358},[355,2800,2802],{"class":2801},"suJrU","record",[355,2804,2806],{"class":2805},"sQhOw"," Revenue",[355,2808,2809],{"class":1119},"(BigDecimal amount) {}\n",[355,2811,2812],{"class":357,"line":364},[355,2813,1271],{"emptyLinePlaceholder":893},[355,2815,2816,2818,2821,2824,2827,2829,2832],{"class":357,"line":370},[355,2817,2802],{"class":2801},[355,2819,2820],{"class":2805}," Revenues",[355,2822,2823],{"class":1119},"(List",[355,2825,2826],{"class":2801},"\u003C",[355,2828,2632],{"class":1119},[355,2830,2831],{"class":2801},">",[355,2833,2834],{"class":1119}," revenues) {\n",[355,2836,2837,2840,2843,2847],{"class":357,"line":376},[355,2838,2839],{"class":2801},"    public",[355,2841,2842],{"class":1119}," Revenue ",[355,2844,2846],{"class":2845},"sc3cj","cumulate",[355,2848,2849],{"class":1119},"() {\n",[355,2851,2852,2855,2858,2860,2863,2866],{"class":357,"line":382},[355,2853,2854],{"class":2801},"        return",[355,2856,2857],{"class":2801}," new",[355,2859,2806],{"class":2845},[355,2861,2862],{"class":1119},"(revenues.",[355,2864,2865],{"class":2845},"stream",[355,2867,2868],{"class":1119},"()\n",[355,2870,2871,2874,2877,2880,2883],{"class":357,"line":1157},[355,2872,2873],{"class":1119},"                .",[355,2875,2876],{"class":2845},"map",[355,2878,2879],{"class":1119},"(Revenue",[355,2881,2882],{"class":2801},"::",[355,2884,2885],{"class":1119},"amount)\n",[355,2887,2888,2890,2893,2896,2898],{"class":357,"line":1165},[355,2889,2873],{"class":1119},[355,2891,2892],{"class":2845},"reduce",[355,2894,2895],{"class":1119},"(BigDecimal.ZERO, BigDecimal",[355,2897,2882],{"class":2801},[355,2899,2900],{"class":1119},"add));\n",[355,2902,2903],{"class":357,"line":1173},[355,2904,2905],{"class":1119},"    }\n",[355,2907,2908],{"class":357,"line":1181},[355,2909,2725],{"class":1119},[19,2911,2912],{},"L'objet expose ses propres méthodes pour pouvoir faire des opérations métiers. Cela impose que toute nouvelle opération soit portée par le dit value object. Le pipe operator permet d'étendre les possibilités du concept sans modifier le concept lui-même.\nCeci offre une vraie flexibilité, de la lisibilité. C'est la composition fonctionnelle !",[23,2914,2916],{"id":2915},"services-purs-et-dépendances-explicites","Services purs et dépendances explicites",[19,2918,2919],{},"Le use case principal dépend de données externes (financier + paie). En programmation fonctionnelle, ces dépendances sont injectées via des fonctions :",[344,2921,2923],{"className":2647,"code":2922,"language":2649,"meta":350,"style":350},"pub type GetFinancialDataPort =\n  fn(ConsultantId) -> FinancialData\npub type GetCompanyPayrollDataPort =\n  fn() -> CompanyPayrollData\n\npub fn calculate_consultant_annual_packaging(\n  consultant_id: ConsultantId,\n  get_financial_data: GetFinancialDataPort,\n  get_company_payroll_data: GetCompanyPayrollDataPort,\n) {\n  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une api externe\n  let CompanyPayrollDataPort(employer_rate, max_margin) = get_company_payroll_data()\n  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une base de données\n  let FinancialDataPort(revenues, gross_salary) = get_financial_data(consultant_id)\n  calculate_annual_packaging(revenues, gross_salary, employer_rate, max_margin)\n}\n",[352,2924,2925,2930,2935,2940,2945,2949,2954,2959,2964,2969,2974,2979,2984,2989,2994,2999],{"__ignoreMap":350},[355,2926,2927],{"class":357,"line":358},[355,2928,2929],{},"pub type GetFinancialDataPort =\n",[355,2931,2932],{"class":357,"line":364},[355,2933,2934],{},"  fn(ConsultantId) -> FinancialData\n",[355,2936,2937],{"class":357,"line":370},[355,2938,2939],{},"pub type GetCompanyPayrollDataPort =\n",[355,2941,2942],{"class":357,"line":376},[355,2943,2944],{},"  fn() -> CompanyPayrollData\n",[355,2946,2947],{"class":357,"line":382},[355,2948,1271],{"emptyLinePlaceholder":893},[355,2950,2951],{"class":357,"line":1157},[355,2952,2953],{},"pub fn calculate_consultant_annual_packaging(\n",[355,2955,2956],{"class":357,"line":1165},[355,2957,2958],{},"  consultant_id: ConsultantId,\n",[355,2960,2961],{"class":357,"line":1173},[355,2962,2963],{},"  get_financial_data: GetFinancialDataPort,\n",[355,2965,2966],{"class":357,"line":1181},[355,2967,2968],{},"  get_company_payroll_data: GetCompanyPayrollDataPort,\n",[355,2970,2971],{"class":357,"line":1189},[355,2972,2973],{},") {\n",[355,2975,2976],{"class":357,"line":1197},[355,2977,2978],{},"  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une api externe\n",[355,2980,2981],{"class":357,"line":1205},[355,2982,2983],{},"  let CompanyPayrollDataPort(employer_rate, max_margin) = get_company_payroll_data()\n",[355,2985,2986],{"class":357,"line":1213},[355,2987,2988],{},"  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une base de données\n",[355,2990,2991],{"class":357,"line":1221},[355,2992,2993],{},"  let FinancialDataPort(revenues, gross_salary) = get_financial_data(consultant_id)\n",[355,2995,2996],{"class":357,"line":1229},[355,2997,2998],{},"  calculate_annual_packaging(revenues, gross_salary, employer_rate, max_margin)\n",[355,3000,3001],{"class":357,"line":1237},[355,3002,2725],{},[19,3004,3005],{},"Les ports sont des types de fonctions, et la composition des règles reste locale au domaine. Le métier ne dépend d'aucune techno (HTTP, DB, etc.).",[84,3007,3009],{"id":3008},"et-en-programmation-orientée-objet","Et en programmation orientée objet",[19,3011,3012],{},"En Java, on représente les mêmes concepts via des records, classes et interfaces. Le vocabulaire métier est identique, mais l'encapsulation se fait par objets plutôt que par des fonctions.",[344,3014,3016],{"className":2792,"code":3015,"language":2794,"meta":350,"style":350},"public interface FinancialDataPort {\n  FinancialData forConsultant(ConsultantId consultantId);\n}\n\npublic interface CompanyPayrollPort {\n  CompanyPayrollData get();\n}\n\npublic final class PackageCalculator {\n  private final FinancialDataPort financialDataPort;\n  private final CompanyPayrollPort payrollDataPort;\n\n  public PackageCalculator(FinancialDataPort financialDataPort,\n                           CompanyPayrollPort payrollDataPort) {\n    this.financialDataPort = financialDataPort;\n    this.payrollDataPort = payrollDataPort;\n  }\n\n  public Package calculateFor(ConsultantId consultantId) {\n    var payroll = payrollDataPort.get();\n    var financial = financialDataPort.forConsultant(consultantId);\n    return calculateAnnualPackaging(\n      financial.revenues(),\n      financial.grossSalary(),\n      payroll.employerRate(),\n      payroll.maxMargin()\n    );\n  }\n\n  private Package calculateAnnualPackaging(\n    Revenues revenues,\n    GrossSalary grossSalary,\n    EmployerRate employerRate,\n    GrossMargin maxMargin\n  ) {\n    var employerCost = grossSalary.multiply(employerRate);\n    var grossMargin = revenues.subtract(employerCost);\n    var cappedMargin = grossMargin.subtract(maxMargin);\n    var bonus = cappedMargin.apply(employerRate);\n    var total = grossSalary.add(bonus);\n\n    return new Package(\n      bonus,\n      grossSalary,\n      total\n    );\n  }\n}\n",[352,3017,3018,3032,3049,3053,3057,3068,3079,3083,3087,3102,3114,3125,3129,3145,3155,3167,3178,3183,3187,3203,3221,3238,3249,3259,3268,3278,3287,3292,3296,3300,3311,3320,3329,3338,3346,3351,3369,3387,3404,3421,3438,3442,3453,3459,3465,3471,3476,3481],{"__ignoreMap":350},[355,3019,3020,3023,3026,3029],{"class":357,"line":358},[355,3021,3022],{"class":2801},"public",[355,3024,3025],{"class":2801}," interface",[355,3027,3028],{"class":2805}," FinancialDataPort",[355,3030,3031],{"class":1119}," {\n",[355,3033,3034,3037,3040,3043,3046],{"class":357,"line":364},[355,3035,3036],{"class":1119},"  FinancialData ",[355,3038,3039],{"class":2845},"forConsultant",[355,3041,3042],{"class":1119},"(ConsultantId ",[355,3044,3045],{"class":2805},"consultantId",[355,3047,3048],{"class":1119},");\n",[355,3050,3051],{"class":357,"line":370},[355,3052,2725],{"class":1119},[355,3054,3055],{"class":357,"line":376},[355,3056,1271],{"emptyLinePlaceholder":893},[355,3058,3059,3061,3063,3066],{"class":357,"line":382},[355,3060,3022],{"class":2801},[355,3062,3025],{"class":2801},[355,3064,3065],{"class":2805}," CompanyPayrollPort",[355,3067,3031],{"class":1119},[355,3069,3070,3073,3076],{"class":357,"line":1157},[355,3071,3072],{"class":1119},"  CompanyPayrollData ",[355,3074,3075],{"class":2845},"get",[355,3077,3078],{"class":1119},"();\n",[355,3080,3081],{"class":357,"line":1165},[355,3082,2725],{"class":1119},[355,3084,3085],{"class":357,"line":1173},[355,3086,1271],{"emptyLinePlaceholder":893},[355,3088,3089,3091,3094,3097,3100],{"class":357,"line":1181},[355,3090,3022],{"class":2801},[355,3092,3093],{"class":2801}," final",[355,3095,3096],{"class":2801}," class",[355,3098,3099],{"class":2805}," PackageCalculator",[355,3101,3031],{"class":1119},[355,3103,3104,3107,3109,3111],{"class":357,"line":1189},[355,3105,3106],{"class":2801},"  private",[355,3108,3093],{"class":2801},[355,3110,3028],{"class":1119},[355,3112,3113],{"class":1119}," financialDataPort;\n",[355,3115,3116,3118,3120,3122],{"class":357,"line":1197},[355,3117,3106],{"class":2801},[355,3119,3093],{"class":2801},[355,3121,3065],{"class":1119},[355,3123,3124],{"class":1119}," payrollDataPort;\n",[355,3126,3127],{"class":357,"line":1205},[355,3128,1271],{"emptyLinePlaceholder":893},[355,3130,3131,3134,3136,3139,3142],{"class":357,"line":1213},[355,3132,3133],{"class":2801},"  public",[355,3135,3099],{"class":2845},[355,3137,3138],{"class":1119},"(FinancialDataPort ",[355,3140,3141],{"class":2805},"financialDataPort",[355,3143,3144],{"class":1119},",\n",[355,3146,3147,3150,3153],{"class":357,"line":1221},[355,3148,3149],{"class":1119},"                           CompanyPayrollPort ",[355,3151,3152],{"class":2805},"payrollDataPort",[355,3154,2973],{"class":1119},[355,3156,3157,3160,3163,3165],{"class":357,"line":1229},[355,3158,3159],{"class":1264},"    this",[355,3161,3162],{"class":1119},".financialDataPort ",[355,3164,2042],{"class":2801},[355,3166,3113],{"class":1119},[355,3168,3169,3171,3174,3176],{"class":357,"line":1237},[355,3170,3159],{"class":1264},[355,3172,3173],{"class":1119},".payrollDataPort ",[355,3175,2042],{"class":2801},[355,3177,3124],{"class":1119},[355,3179,3180],{"class":357,"line":1245},[355,3181,3182],{"class":1119},"  }\n",[355,3184,3185],{"class":357,"line":1256},[355,3186,1271],{"emptyLinePlaceholder":893},[355,3188,3189,3191,3194,3197,3199,3201],{"class":357,"line":1268},[355,3190,3133],{"class":2801},[355,3192,3193],{"class":1119}," Package ",[355,3195,3196],{"class":2845},"calculateFor",[355,3198,3042],{"class":1119},[355,3200,3045],{"class":2805},[355,3202,2973],{"class":1119},[355,3204,3205,3208,3211,3214,3217,3219],{"class":357,"line":1274},[355,3206,3207],{"class":2801},"    var",[355,3209,3210],{"class":1119}," payroll",[355,3212,3213],{"class":2801}," =",[355,3215,3216],{"class":1119}," payrollDataPort.",[355,3218,3075],{"class":2845},[355,3220,3078],{"class":1119},[355,3222,3223,3225,3228,3230,3233,3235],{"class":357,"line":1282},[355,3224,3207],{"class":2801},[355,3226,3227],{"class":1119}," financial",[355,3229,3213],{"class":2801},[355,3231,3232],{"class":1119}," financialDataPort.",[355,3234,3039],{"class":2845},[355,3236,3237],{"class":1119},"(consultantId);\n",[355,3239,3240,3243,3246],{"class":357,"line":1290},[355,3241,3242],{"class":2801},"    return",[355,3244,3245],{"class":2845}," calculateAnnualPackaging",[355,3247,3248],{"class":1119},"(\n",[355,3250,3251,3254,3256],{"class":357,"line":1301},[355,3252,3253],{"class":1119},"      financial.",[355,3255,2766],{"class":2845},[355,3257,3258],{"class":1119},"(),\n",[355,3260,3261,3263,3266],{"class":357,"line":1306},[355,3262,3253],{"class":1119},[355,3264,3265],{"class":2845},"grossSalary",[355,3267,3258],{"class":1119},[355,3269,3270,3273,3276],{"class":357,"line":1314},[355,3271,3272],{"class":1119},"      payroll.",[355,3274,3275],{"class":2845},"employerRate",[355,3277,3258],{"class":1119},[355,3279,3280,3282,3285],{"class":357,"line":1322},[355,3281,3272],{"class":1119},[355,3283,3284],{"class":2845},"maxMargin",[355,3286,2868],{"class":1119},[355,3288,3289],{"class":357,"line":1333},[355,3290,3291],{"class":1119},"    );\n",[355,3293,3294],{"class":357,"line":1341},[355,3295,3182],{"class":1119},[355,3297,3298],{"class":357,"line":1352},[355,3299,1271],{"emptyLinePlaceholder":893},[355,3301,3302,3304,3306,3309],{"class":357,"line":1363},[355,3303,3106],{"class":2801},[355,3305,3193],{"class":1119},[355,3307,3308],{"class":2845},"calculateAnnualPackaging",[355,3310,3248],{"class":1119},[355,3312,3313,3316,3318],{"class":357,"line":1369},[355,3314,3315],{"class":1119},"    Revenues ",[355,3317,2766],{"class":2805},[355,3319,3144],{"class":1119},[355,3321,3322,3325,3327],{"class":357,"line":1377},[355,3323,3324],{"class":1119},"    GrossSalary ",[355,3326,3265],{"class":2805},[355,3328,3144],{"class":1119},[355,3330,3331,3334,3336],{"class":357,"line":1386},[355,3332,3333],{"class":1119},"    EmployerRate ",[355,3335,3275],{"class":2805},[355,3337,3144],{"class":1119},[355,3339,3340,3343],{"class":357,"line":1393},[355,3341,3342],{"class":1119},"    GrossMargin ",[355,3344,3345],{"class":2805},"maxMargin\n",[355,3347,3348],{"class":357,"line":1402},[355,3349,3350],{"class":1119},"  ) {\n",[355,3352,3353,3355,3358,3360,3363,3366],{"class":357,"line":1411},[355,3354,3207],{"class":2801},[355,3356,3357],{"class":1119}," employerCost",[355,3359,3213],{"class":2801},[355,3361,3362],{"class":1119}," grossSalary.",[355,3364,3365],{"class":2845},"multiply",[355,3367,3368],{"class":1119},"(employerRate);\n",[355,3370,3371,3373,3376,3378,3381,3384],{"class":357,"line":1417},[355,3372,3207],{"class":2801},[355,3374,3375],{"class":1119}," grossMargin",[355,3377,3213],{"class":2801},[355,3379,3380],{"class":1119}," revenues.",[355,3382,3383],{"class":2845},"subtract",[355,3385,3386],{"class":1119},"(employerCost);\n",[355,3388,3389,3391,3394,3396,3399,3401],{"class":357,"line":1425},[355,3390,3207],{"class":2801},[355,3392,3393],{"class":1119}," cappedMargin",[355,3395,3213],{"class":2801},[355,3397,3398],{"class":1119}," grossMargin.",[355,3400,3383],{"class":2845},[355,3402,3403],{"class":1119},"(maxMargin);\n",[355,3405,3406,3408,3411,3413,3416,3419],{"class":357,"line":1434},[355,3407,3207],{"class":2801},[355,3409,3410],{"class":1119}," bonus",[355,3412,3213],{"class":2801},[355,3414,3415],{"class":1119}," cappedMargin.",[355,3417,3418],{"class":2845},"apply",[355,3420,3368],{"class":1119},[355,3422,3423,3425,3428,3430,3432,3435],{"class":357,"line":1441},[355,3424,3207],{"class":2801},[355,3426,3427],{"class":1119}," total",[355,3429,3213],{"class":2801},[355,3431,3362],{"class":1119},[355,3433,3434],{"class":2845},"add",[355,3436,3437],{"class":1119},"(bonus);\n",[355,3439,3440],{"class":357,"line":1450},[355,3441,1271],{"emptyLinePlaceholder":893},[355,3443,3444,3446,3448,3451],{"class":357,"line":1459},[355,3445,3242],{"class":2801},[355,3447,2857],{"class":2801},[355,3449,3450],{"class":2845}," Package",[355,3452,3248],{"class":1119},[355,3454,3456],{"class":357,"line":3455},43,[355,3457,3458],{"class":1119},"      bonus,\n",[355,3460,3462],{"class":357,"line":3461},44,[355,3463,3464],{"class":1119},"      grossSalary,\n",[355,3466,3468],{"class":357,"line":3467},45,[355,3469,3470],{"class":1119},"      total\n",[355,3472,3474],{"class":357,"line":3473},46,[355,3475,3291],{"class":1119},[355,3477,3479],{"class":357,"line":3478},47,[355,3480,3182],{"class":1119},[355,3482,3484],{"class":357,"line":3483},48,[355,3485,2725],{"class":1119},[19,3487,3488],{},"Le cœur métier reste le même : règles, vocabulaire, invariants. Les dépendances sont injectées depuis l'extérieur du domaine.",[19,3490,3491],{},"Finalement, seule la forme change.",[23,3493,1528],{"id":1527},[19,3495,3496,3497,3500],{},"En programmation fonctionnelle, les règles sont pures et les dépendances explicites.En programmation objet, elles sont encapsulées dans des objets et des interfaces.  Dans l’un comme dans l’autre, l’architecture hexagonale s’y applique de manière égale: le métier et son vocabulaire au centre de l’application. Autrement dit, c",[34,3498,3499],{},"e n'est pas parce qu'on ne fait que des fonctions qu'il n'y a pas d'architecture en couches: on peut clairement distinguer le domaine métier de l'infrastructure."," La programmation fonctionnelle n'est donc pas un obstacle à la valorisation du métier dans le code. Elle peut au contraire rendre le vocabulaire plus lisible et les règles plus testables.",[856,3502,3503],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .sc3cj, html code.shiki .sc3cj{--shiki-default:#D2A8FF}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}",{"title":350,"searchDepth":364,"depth":364,"links":3505},[3506,3509,3512],{"id":1916,"depth":364,"text":1917,"children":3507},[3508],{"id":2773,"depth":370,"text":2774},{"id":2915,"depth":364,"text":2916,"children":3510},[3511],{"id":3008,"depth":370,"text":3009},{"id":1527,"depth":364,"text":1528},"2026-04-08T07:34:28.327Z","À mesure que les systèmes logiciels gagnent en complexité, les approches traditionnelles de conception montrent leurs limites. Couplage excessif, difficulté à tester, rigidité face au changement : aut",{},"\u002Fblogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit",[3518,3520,3522],{"id":1582,"name":1583,"image":3519,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466YZGE5L65%2F20260408%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260408T073428Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEC4aCXVzLXdlc3QtMiJHMEUCIQC89XiI4LV2nPeP5GwelaGxITa1i8vxE7nDPN%2FCOOIGPAIgIMuadU2XMtNuvRqanOfvVI6kHru%2B2YCLP1W9z9BRL6UqiAQI9%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDMWjV%2FO1zt1H6KDcMCrcA7q8rYPD7JArUtRE2XmtlGFi0Gb1u2jY%2B9Y3SPAbwzgUQRWQ1LEqXfyjuHcnYUj6O%2BiWWlqVuXmzWt1l7lG5Y7arPfzt6AjsXPmIzlmAvYMctlE1uESBOaThTr8QcjJR42skKrqwlIVe%2FFOfTIaN80P8yI23zbwYPGbrre3Q34lTWnE77vQ1FHlDAEnF4q6vCNLknS7i4J4vDz%2FPhtjrQMHSV1BSwg4czuhoUylgbdW1CL8HRfEeFraXH3AJ4wGhuMoxGCakNRvrw7KrF0jpzkULBEC4PwztMJcaWUnD6T2miI%2FUuL5g7ASMT7NtTPiiRFtg3beSatik6dY6JMEdSVElz5yspss5kTYq8YsIQlT8tLRejU4zgp78leO47JOHzmJnro2wd9YdGm%2BEqqiHPsku1HbLTV3oHwYEtPB9FBFqSC9V8AbocksXRXhfmXn8WnZbebEXMu7XiIp%2BiZjIcQC9Brq%2BicBi7iHaUQoAljN8RHny0jm%2FGsm4PRQNiCYbWJnmahrKNRWNkP5RiXqGZnjsXHInBSqkupWnekY9Bd9Vd11JiKSuGkj2ebN%2BuuF4KEtNARclVCjiTEQDt6jwpswqxeH4fTDflh5XXLwZvxU6RIJ1tjcQWwAxRLGRMObb184GOqUB6QApw17fi31uRcyevbEhsIVcF7cbhz5DT9rK2wxOH0%2FJF55Z%2BYpWz%2FPU%2B5b2R7H0t6SkCITFdxrerbjTKeo3ANn6Maeo3qDIWvnyFCzBZT4MaZW3wqjClgUj7X3KTeNPimG82xZWapTks839ysnOLg36HeDcQuWXHFJ73l4hJVzt84hWxgfsDVAj2LWIvdLzbEUnbJwlOUNalA4bSFXi3%2B%2BZSVGf&X-Amz-Signature=b23db6b30ffaf694e97c7283799bfd5930ff0c8de4e984d08997a4e68c32080e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":10,"name":11,"image":3521,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466XRONKPNZ%2F20260408%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260408T073428Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEDAaCXVzLXdlc3QtMiJIMEYCIQDm83y7rflR2VODU5aP5Qz692idMY%2BBAiAN%2BSxy%2BIDx8QIhAOa4gMORM%2FaT6TWEmlAYAB1EFUTqVOd8ObAa36VRLn1ZKogECPn%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQABoMNjM3NDIzMTgzODA1Igx2JIBqc1%2BH7MVdyPMq3AMwmiKyWYDt3nYnDnPmTWKFpHTuLOkgcCjGctfi8lEGyGwb8HnDFp3AGSj883xVmpSFG3ov9Gr0jbfhSvKTLITWxqJygrQWcaGjzsOJf2a%2BCJ1YrRQsGcOq9WQmDm%2BZhHrG5pNgk31O2f2hxAQP8kGkOC8Jxgz5i%2ByBwCv2fghEPKWCxHIu%2FnLv%2FhXKVET9jUK6L6WptG48fnveHprIygQH86y8dPYXMgAN9T0vx6kBoo%2B08NKPdTqNPAVqVyc9pqmixVE5%2FYYWUF9bJj3TbgGOM7nD84%2FvSBbwXZ6tNimPrdF1CmwsAID4sHly9nv3xvml6AWX09lwlYBpvChHrg88DKCJyzlX3fQoIJuUFMssgpP06IgkjTu%2Fnr3Xn5uGFTrIfL5rQ%2BzaYK%2FZEydEOzHikjrCo7K6xcZ52KaSP60Vn9BeslZ59%2BgDLrczqnXYc%2BKmYDxA%2BOsXObXQid1ODmY8uyRcVIogTAZZXhZ0A%2Bi4Jab9uw4tYXRJe%2BrKHn2xyU6qVUV8Yk%2BfK6ZiFWDz2V%2BwgHyegcnDoE%2BS2x1ckw6xTTeoJTZLnLrQOfKKsfbUnZhS%2Bz9vc1iZ%2BvyfWl4WCQPtFwu3AbDHGveoR2wvwgkrm1njJEU%2BkGJmdJJuszC5iNjOBjqkAYLjzrk9PZ61PMzHm%2FL6BGmd9EAJ05SyolUKGsI0gCLqm4I0mFF9BvGTn7y679fSfLS7vBM%2FDT1t2h5TD0H1yXt66PKQIFXPPMIFEQkFoMF4JwsmgNsAwbBRkURagTfGs50qrviYMBbEFKlnmiB4x%2FWI0IOonbk9v0ZBs7OlLZJHOwHgH5nN9Z1KuBEUGhdP9V%2B4zpiZTAlCThrQxBqa1eSxr%2FZb&X-Amz-Signature=ebff0fd05509337077f565c3ea9b944db6f15a3995bdd1bdfb7c90fa020e82fb&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":1577,"name":1578,"image":3523,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F1f0a6cf7-edf2-44dc-babb-f1624e4f52b0\u002FPhoto_profil.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466WIK4JRTG%2F20260408%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260408T073428Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEC4aCXVzLXdlc3QtMiJHMEUCICuqELPi893QSyfwnyFTnMqcLUW8j4oiAxjFNZ3gFDtCAiEAgcg%2BHl1dGG5cM0uNfUCb0JlwgkzZ9eZmwtsFG5AyCuMqiAQI9%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDGHa9MlsDbZfN%2FYCKircA5gcGnNJ%2FBjl5mcv6g1TMFzbf7dYZESahFgAifbuK%2BBonIuiW%2FfR%2BTBODtvfbiNDgpbOjHteJv7%2FLOgZgpSP1epkw0qahEvYFogVnIgmzLd1roYHs626IPYVOS0RunsFyTGcQwSmc6hVyS4pfODT4OKwUE7EiGUqaQWg%2Fj7j12kZ2vv1FnXda7kxpzNDmLuLzlZp70ozboHb6%2FOUf3BhqdOVAAb1Y%2BK2xHnkdYAr%2BPVJ0v5qUPazBQAtUzMVwAgYxG2JugfVSn2sofk97v9b5pcJIhED4A4Cob%2F21PV2d9RiMTHjuKP2GoO6t96A%2BwpXcyFgb4GLlGugrJ%2B40w0Joq8w3Pfd0SayKfc72LE3%2B0NgPDdD3%2BPBxX8e6RYAxjGHSwwxoqXn0rwbRoa5e94lavTTwWEGXmlhJK6vyL7oMNAh76VCuiKU8zQR9iO4PwyYCOeyYXmwY9uSsjv1Xhnl5Jm6VsP%2BKqUR%2Bm8WmG3%2FSIxpZt0kkz2aF82DYYtBr0odjMLSWzxkezG0APvFa%2F%2FG%2B05zRflCS2EHTC7c3KyVP%2FO0Oz7QkF5vuXU%2F2fPrV4W1%2FSaX6M1s4y8UbTneRMlxLoqt5JSLJAsGyo6eo50VIh%2FeKCkQymrPWjIEIkaIMO7a184GOqUBK3sKSMU%2BE8%2FdgcSKNfCHNWUjsc3Q4%2FwCLEpB3gKjjU2rM9gS1cUnM9ROHr0wmcL3WKMsNhQ0m48hnO45ibaQ7AuaY9YmTTVOucTGGtqI6%2BQ%2FzksdZtEIgKbuMSFIR4TAp0QnGLKg%2B38rtJH3GS%2FB41z21vB74NsTbOLmVnnRN7b%2BUxPfPhInd7VMo9OVUSCVgqOXPGht2WN3qTzRkojiBxAGb%2FIq&X-Amz-Signature=03e3a75c38948c108cfd727f230ff460bccfea1ad49530d77d843f9e4556e253&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":1883,"description":3514},"blogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit\u002Findex",[1879],"5kjyA9V_-oP7-hiszOmgMcw7zYpEN_O9T0BmQwPEiJQ",{"id":3529,"title":3530,"alt":3531,"authors":3532,"body":3534,"date":4996,"description":4997,"extension":890,"image":891,"meta":4998,"navigation":893,"ogImage":891,"path":4999,"published":893,"reviewers":5000,"seo":5005,"stem":5006,"tags":5007,"__hash__":5010},"blogs\u002Fblogs\u002F2026-03-31-connecter-datadog-un-rseau-100-hors-ligne-retour-dexprience-avec-vector\u002Findex.md","Connecter Datadog à un réseau 100% hors-ligne : retour d'expérience avec Vector","Cover de l'article : Diagramme d'architecture illustrant la collecte, l'anonymisation par Vector et l'envoi de logs serveurs vers Datadog.",[3533],{"id":10,"name":11,"image":12,"linkedin":13,"x":14},{"type":16,"value":3535,"toc":4973},[3536,3561,3563,3567,3570,3577,3584,3587,3608,3611,3613,3617,3620,3626,3649,3652,3681,3684,3687,3696,3702,3704,3708,3711,3722,3728,3730,3738,3745,3749,3764,3774,3787,3794,3800,3804,3807,3860,3870,3877,3879,3883,3886,3889,3958,3965,3991,3998,4021,4023,4027,4036,4042,4046,4061,4203,4207,4210,4357,4360,4363,4365,4369,4372,4375,4475,4478,4499,4506,4510,4517,4543,4545,4549,4552,4563,4601,4604,4607,4633,4635,4639,4642,4656,4686,4705,4711,4720,4722,4726,4729,4735,4751,4757,4773,4775,4779,4782,4933,4935,4939,4946,4952,4963,4965,4970],[19,3537,3538,2756,3541,2756,3548,2756,3551,2756,3558],{},[1620,3539,3540],{},"Comment faire fonctionner",[91,3542,3545],{"href":3543,"rel":3544},"https:\u002F\u002Fwww.datadoghq.com\u002F",[95],[1620,3546,3547],{},"Datadog",[1620,3549,3550],{},"sur des serveurs Windows isolés, sans internet et avec une anonymisation stricte des données ? Retour d'expérience sur la mise en place de",[91,3552,3555],{"href":3553,"rel":3554},"https:\u002F\u002Fvector.dev\u002F",[95],[1620,3556,3557],{},"Vector",[1620,3559,3560],{},"pour connecter un cluster hors-ligne à Datadog.",[952,3562],{},[23,3564,3566],{"id":3565},"le-contexte-des-serveurs-aveugles","Le contexte : des serveurs aveugles",[19,3568,3569],{},"Dans les environnements réglementés, la sécurité réseau n'est pas négociable. Mais ça ne devrait pas condamner une équipe à piloter ses applications à l'aveugle.",[19,3571,3572,3573,3576],{},"Un client du secteur de l'assurance a contacté ",[91,3574,1836],{"href":1923,"rel":3575},[95]," pour mettre en place du monitoring sur son parc applicatif. Le setup : une dizaine de serveurs Windows sous IIS hébergeant des applications .NET, répartis entre une DMZ et un réseau interne, générant plusieurs Go de logs par jour. Jusque-là, rien d'exotique.",[19,3578,3579,3580,3583],{},"La contrainte principale : ",[34,3581,3582],{},"aucun de ces serveurs n'a accès à internet."," Politique de sécurité réseau stricte, pas de dérogation possible. Tolérance zéro pour la perte de données. Et le client veut Datadog, pas un ELK maison, pas un Prometheus à manager.",[19,3585,3586],{},"Le cahier des charges :",[443,3588,3589,3592,3595,3598,3605],{},[446,3590,3591],{},"Centraliser les logs applicatifs IIS dans Datadog",[446,3593,3594],{},"Collecter les métriques de performance (HTTP, runtime .NET, SQL)",[446,3596,3597],{},"Activer le tracing distribué (APM) sur les applications cibles",[446,3599,3600,3601,3604],{},"Anonymiser les données sensibles ",[34,3602,3603],{},"avant"," qu'elles quittent le réseau",[446,3606,3607],{},"Garantir zéro perte de données en cas de coupure réseau",[19,3609,3610],{},"L'objectif : un pipeline de bout en bout, opérationnel et validé par le client.",[952,3612],{},[23,3614,3616],{"id":3615},"pourquoi-vector-et-pas-un-proxy-http","Pourquoi Vector et pas un proxy HTTP",[19,3618,3619],{},"Lorsque des serveurs sans internet doivent envoyer des données vers un SaaS, le réflexe habituel est de penser à un proxy. Un Squid, un HAProxy, un nginx en reverse proxy.",[19,3621,3622,3625],{},[34,3623,3624],{},"Mais"," ça ne suffit pas ici. On ne veut pas juste relayer du trafic HTTPS. On veut :",[443,3627,3628,3634,3640,3646],{},[446,3629,3630,3633],{},[34,3631,3632],{},"Transformer"," les données en transit (anonymisation)",[446,3635,3636,3639],{},[34,3637,3638],{},"Bufferiser sur disque"," en cas de coupure réseau vers Datadog",[446,3641,3642,3645],{},[34,3643,3644],{},"Séparer les flux"," (logs, métriques, traces) vers les bons endpoints",[446,3647,3648],{},"Avoir un pipeline observable et debuggable",[19,3650,3651],{},"Vector coche toutes ces cases.",[19,3653,3654,3655,504,3660,494,3665,3670,3671,3676,3677,3680],{},"C'est un binaire unique écrit en ",[91,3656,3659],{"href":3657,"rel":3658},"https:\u002F\u002Frust-lang.org\u002Ffr\u002F",[95],"Rust",[91,3661,3664],{"href":3662,"rel":3663},"https:\u002F\u002Fgithub.com\u002Fvectordotdev\u002Fvector",[95],"haute performance",[91,3666,3669],{"href":3667,"rel":3668},"https:\u002F\u002Fvector.dev\u002Fdocs\u002Fsetup\u002Fgoing-to-prod\u002Fsizing\u002F",[95],"~25 MiB\u002Fs par vCPU"," pour des logs structurés — soit ",[91,3672,3675],{"href":3673,"rel":3674},"https:\u002F\u002Fgithub.com\u002Fvectordotdev\u002Fvector#performance",[95],"3x à 18x le débit de Fluentd et 2x à 25x celui de Logstash"," selon les scénarios), avec un support natif du protocole Datadog Agent en source ",[34,3678,3679],{},"et"," en sink. Concrètement, l'agent Datadog sur les serveurs Windows pense parler à Datadog, il parle à Vector et Vector se charge du reste.",[19,3682,3683],{},"Le coût en ressources ? Négligeable.",[19,3685,3686],{},"Contrairement à un proxy maison qu'il faudrait maintenir, Vector traite notre volume de logs avec une empreinte CPU\u002FRAM minimale.",[19,3688,3689,3690,3695],{},"Le bonus : Vector supporte VRL (",[91,3691,3694],{"href":3692,"rel":3693},"https:\u002F\u002Fvector.dev\u002Fdocs\u002Freference\u002Fvrl\u002F",[95],"Vector Remap Language","), un langage de transformation dédié. Exactement ce qu'il faut pour l'anonymisation.",[19,3697,3698],{},[176,3699],{"alt":3700,"src":3701},"Schéma de l’architecture du pipeline Vector simplifé","\u002Fcontent-assets\u002F2026-03-31-connecter-datadog-un-rseau-100-hors-ligne-retour-dexprience-avec-vector\u002Fassets\u002Fimg1.webp",[952,3703],{},[23,3705,3707],{"id":3706},"larchitecture-implémentée","L'architecture implémentée",[19,3709,3710],{},"Un serveur Linux Debian en DMZ fait office de passerelle unique. Il porte Vector qui écoute en TLS sur le port 8443, et un agent Datadog dédié qui surveille Vector lui-même avec une connexion directe vers Datadog (sans passer par Vector — on y reviendra).",[19,3712,3713,3714,3717,3718,3721],{},"Les serveurs Windows envoient ",[34,3715,3716],{},"tout"," vers Vector : logs, métriques, traces APM, données OTLP. L'agent Datadog Windows est configuré avec un bloc ",[352,3719,3720],{},"vector:"," natif qui redirige, de manière transparente, tous les flux.",[19,3723,3724],{},[176,3725],{"alt":3726,"src":3727},"Diagramme de composants de la solution Vector","\u002Fcontent-assets\u002F2026-03-31-connecter-datadog-un-rseau-100-hors-ligne-retour-dexprience-avec-vector\u002Fassets\u002Fimg2.webp",[952,3729],{},[23,3731,3733,3734,3737],{"id":3732},"piège-n1-store_api_key-un-comportement-par-défaut-trompeur","Piège n°1 : ",[352,3735,3736],{},"store_api_key"," — un comportement par défaut trompeur",[19,3739,3740,3741,3744],{},"Ce problème de configuration est le plus subtil qu'on ait rencontré. Tout semblait fonctionner correctement : les agents envoyaient des données et ",[352,3742,3743],{},"vector top"," affichait les flux. Mais côté Datadog, aucune donnée ne remontait, sans message d'erreur explicite.",[84,3746,3748],{"id":3747},"la-raison","La raison ?",[19,3750,3751,3752,3755,3756,3759,3760,3763],{},"L'agent Datadog sur les serveurs Windows a besoin d'une ",[352,3753,3754],{},"api_key"," dans sa config, même s'il n'envoie rien directement à Datadog.\nLe placeholder mis en place était ",[352,3757,3758],{},"00000000000000000000000000000000",". L'idée ? Permettre à Vector d'utiliser sa propre clé API valide via ",[352,3761,3762],{},"default_api_key"," dans ses sinks.",[19,3765,3766,3767,3770,3771,44],{},"Sauf que Vector, par défaut, a ",[352,3768,3769],{},"store_api_key: true"," sur sa source ",[352,3772,3773],{},"datadog_agent",[19,3775,3776,3777,3780,3781,3784,3785,44],{},"Ce paramètre fait que Vector ",[34,3778,3779],{},"stocke la clé API transmise par l'agent dans les métadonnées de chaque événement",". Et au moment de l'envoi vers Datadog, si une clé est présente dans les métadonnées, elle ",[34,3782,3783],{},"prend le dessus"," sur ",[352,3786,3762],{},[19,3788,3789,3790,3793],{},"Résultat : Vector envoie les logs avec la clé ",[352,3791,3792],{},"00000000..."," — qui se fait rejeter par Datadog. Tout cela sans alerte ou notification pour comprendre ce rejet.",[19,3795,3796],{},[176,3797],{"alt":3798,"src":3799},"Schéma pour expliquer la résolution du store_api_key","\u002Fcontent-assets\u002F2026-03-31-connecter-datadog-un-rseau-100-hors-ligne-retour-dexprience-avec-vector\u002Fassets\u002Fimg3.webp",[84,3801,3803],{"id":3802},"la-solution","La solution",[19,3805,3806],{},"Un seul paramètre à changer :",[344,3808,3810],{"className":1106,"code":3809,"language":1108,"meta":350,"style":350},"sources:\n  datadog_agents:\n    type: datadog_agent\n    address: \"0.0.0.0:8443\"\n    store_api_key: false  # ← C'est ça qui manquait\n",[352,3811,3812,3819,3826,3836,3846],{"__ignoreMap":350},[355,3813,3814,3817],{"class":357,"line":358},[355,3815,3816],{"class":1115},"sources",[355,3818,1120],{"class":1119},[355,3820,3821,3824],{"class":357,"line":364},[355,3822,3823],{"class":1115},"  datadog_agents",[355,3825,1120],{"class":1119},[355,3827,3828,3831,3833],{"class":357,"line":370},[355,3829,3830],{"class":1115},"    type",[355,3832,1135],{"class":1119},[355,3834,3835],{"class":1138},"datadog_agent\n",[355,3837,3838,3841,3843],{"class":357,"line":376},[355,3839,3840],{"class":1115},"    address",[355,3842,1135],{"class":1119},[355,3844,3845],{"class":1138},"\"0.0.0.0:8443\"\n",[355,3847,3848,3851,3853,3856],{"class":357,"line":382},[355,3849,3850],{"class":1115},"    store_api_key",[355,3852,1135],{"class":1119},[355,3854,3855],{"class":1264},"false",[355,3857,3859],{"class":3858},"sH3jZ","  # ← C'est ça qui manquait\n",[19,3861,3862,3863,3866,3867,3869],{},"Avec ",[352,3864,3865],{},"store_api_key: false",", Vector ignore la clé transmise par les agents et utilise systématiquement la ",[352,3868,3762],{}," configurée dans chaque sink.",[19,3871,3872,3873,3876],{},"Ce comportement est difficile à diagnostiquer car il ne génère aucune erreur explicite côté Vector. Les données transitent normalement dans le pipeline mais sont rejetées silencieusement par Datadog. C'est en analysant les codes retour HTTP 403 dans les logs ",[352,3874,3875],{},"journalctl"," qu'on a identifié la cause. Le correctif tient en un seul paramètre.",[952,3878],{},[23,3880,3882],{"id":3881},"piège-n2-tls-et-certificats-internes","Piège n°2 : TLS et certificats internes",[19,3884,3885],{},"Les communications agent → Vector passent en TLS sur le port 8443. Le client utilise une PKI interne avec un certificat wildcard.",[19,3887,3888],{},"Côté Vector (Linux), la config TLS est straightforward :",[344,3890,3892],{"className":1106,"code":3891,"language":1108,"meta":350,"style":350},"sources:\n  datadog_agents:\n    type: datadog_agent\n    address: \"0.0.0.0:8443\"\n    tls:\n      enabled: true\n      crt_file: \"\u002Fvector\u002Fcerts\u002Fserver.crt\"\n      key_file: \"\u002Fvector\u002Fcerts\u002Fserver.key\"\n",[352,3893,3894,3900,3906,3914,3922,3929,3938,3948],{"__ignoreMap":350},[355,3895,3896,3898],{"class":357,"line":358},[355,3897,3816],{"class":1115},[355,3899,1120],{"class":1119},[355,3901,3902,3904],{"class":357,"line":364},[355,3903,3823],{"class":1115},[355,3905,1120],{"class":1119},[355,3907,3908,3910,3912],{"class":357,"line":370},[355,3909,3830],{"class":1115},[355,3911,1135],{"class":1119},[355,3913,3835],{"class":1138},[355,3915,3916,3918,3920],{"class":357,"line":376},[355,3917,3840],{"class":1115},[355,3919,1135],{"class":1119},[355,3921,3845],{"class":1138},[355,3923,3924,3927],{"class":357,"line":382},[355,3925,3926],{"class":1115},"    tls",[355,3928,1120],{"class":1119},[355,3930,3931,3934,3936],{"class":357,"line":1157},[355,3932,3933],{"class":1115},"      enabled",[355,3935,1135],{"class":1119},[355,3937,1298],{"class":1264},[355,3939,3940,3943,3945],{"class":357,"line":1165},[355,3941,3942],{"class":1115},"      crt_file",[355,3944,1135],{"class":1119},[355,3946,3947],{"class":1138},"\"\u002Fvector\u002Fcerts\u002Fserver.crt\"\n",[355,3949,3950,3953,3955],{"class":357,"line":1173},[355,3951,3952],{"class":1115},"      key_file",[355,3954,1135],{"class":1119},[355,3956,3957],{"class":1138},"\"\u002Fvector\u002Fcerts\u002Fserver.key\"\n",[19,3959,3960,3961,3964],{},"Côté Windows, c'est là que ça se complique. L'agent Datadog utilise le magasin de certificats Windows, pas un fichier PEM. Si le certificat CA interne n'est pas dans le store ",[352,3962,3963],{},"Trusted Root Certification Authorities"," de la machine, l'agent refuse la connexion TLS sans message d'erreur très explicite.",[344,3966,3970],{"className":3967,"code":3968,"language":3969,"meta":350,"style":350},"language-powershell shiki shiki-themes github-dark-default","Import-Certificate -FilePath \"C:\\\\certs\\\\ca-interne.crt\" -CertStoreLocation Cert:\\\\LocalMachine\\\\Root\n","powershell",[352,3971,3972],{"__ignoreMap":350},[355,3973,3974,3977,3980,3983,3986,3988],{"class":357,"line":358},[355,3975,3976],{"class":1264},"Import-Certificate",[355,3978,3979],{"class":2801}," -",[355,3981,3982],{"class":1119},"FilePath ",[355,3984,3985],{"class":1138},"\"C:\\\\certs\\\\ca-interne.crt\"",[355,3987,3979],{"class":2801},[355,3989,3990],{"class":1119},"CertStoreLocation Cert:\\\\LocalMachine\\\\Root\n",[19,3992,3993,3994,3997],{},"Pensez aussi à vérifier la connectivité avec ",[352,3995,3996],{},"Test-NetConnection"," avant de chercher un bug applicatif :",[344,3999,4001],{"className":3967,"code":4000,"language":3969,"meta":350,"style":350},"Test-NetConnection -ComputerName vector.internal.company.local -Port 8443\n",[352,4002,4003],{"__ignoreMap":350},[355,4004,4005,4007,4009,4012,4015,4018],{"class":357,"line":358},[355,4006,3996],{"class":1264},[355,4008,3979],{"class":2801},[355,4010,4011],{"class":1119},"ComputerName vector.internal.company.local ",[355,4013,4014],{"class":2801},"-",[355,4016,4017],{"class":1119},"Port ",[355,4019,4020],{"class":1264},"8443\n",[952,4022],{},[23,4024,4026],{"id":4025},"la-double-anonymisation-ceinture-et-bretelles","La double anonymisation : ceinture et bretelles",[19,4028,4029,4030,4035],{},"Le client avait une exigence forte : aucune ",[91,4031,4034],{"href":4032,"rel":4033},"https:\u002F\u002Fwww.cnil.fr\u002Ffr\u002Fdefinition\u002Fdonnee-personnelle",[95],"donnée à caractère personnel (DCP)"," ne doit quitter le réseau interne. On a donc mis en place une anonymisation à deux niveaux.",[19,4037,4038],{},[176,4039],{"alt":4040,"src":4041},"Schéma de traitement des données pour l’anonymisation avec Vector","\u002Fcontent-assets\u002F2026-03-31-connecter-datadog-un-rseau-100-hors-ligne-retour-dexprience-avec-vector\u002Fassets\u002Fimg4.webp",[84,4043,4045],{"id":4044},"niveau-1-agent-datadog-serveurs-windows","Niveau 1 : Agent Datadog (serveurs Windows)",[19,4047,4048,4049,4052,4053,4056,4057,4060],{},"L'agent Datadog supporte nativement des ",[352,4050,4051],{},"processing_rules"," de type ",[352,4054,4055],{},"mask_sequences"," dans la section ",[352,4058,4059],{},"logs_config",". On masque à la source :",[344,4062,4064],{"className":1106,"code":4063,"language":1108,"meta":350,"style":350},"logs_config:\n  processing_rules:\n    - type: mask_sequences\n      name: mask_ip_addresses\n      pattern: '(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'\n      replace_placeholder: \"[HIDE_IP]\"\n\n    - type: mask_sequences\n      name: mask_emails\n      pattern: '[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\\\.[a-zA-Z0-9-.]+'\n      replace_placeholder: \"[HIDE_EMAIL]\"\n\n    - type: mask_sequences\n      name: mask_phone_numbers\n      pattern: '(?:\\\\+33|0)[1-9]\\\\d{8}'\n      replace_placeholder: \"[HIDE_PHONE_NUMBER]\"\n",[352,4065,4066,4072,4079,4091,4101,4111,4121,4125,4135,4144,4153,4162,4166,4176,4185,4194],{"__ignoreMap":350},[355,4067,4068,4070],{"class":357,"line":358},[355,4069,4059],{"class":1115},[355,4071,1120],{"class":1119},[355,4073,4074,4077],{"class":357,"line":364},[355,4075,4076],{"class":1115},"  processing_rules",[355,4078,1120],{"class":1119},[355,4080,4081,4084,4086,4088],{"class":357,"line":370},[355,4082,4083],{"class":1119},"    - ",[355,4085,507],{"class":1115},[355,4087,1135],{"class":1119},[355,4089,4090],{"class":1138},"mask_sequences\n",[355,4092,4093,4096,4098],{"class":357,"line":376},[355,4094,4095],{"class":1115},"      name",[355,4097,1135],{"class":1119},[355,4099,4100],{"class":1138},"mask_ip_addresses\n",[355,4102,4103,4106,4108],{"class":357,"line":382},[355,4104,4105],{"class":1115},"      pattern",[355,4107,1135],{"class":1119},[355,4109,4110],{"class":1138},"'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'\n",[355,4112,4113,4116,4118],{"class":357,"line":1157},[355,4114,4115],{"class":1115},"      replace_placeholder",[355,4117,1135],{"class":1119},[355,4119,4120],{"class":1138},"\"[HIDE_IP]\"\n",[355,4122,4123],{"class":357,"line":1165},[355,4124,1271],{"emptyLinePlaceholder":893},[355,4126,4127,4129,4131,4133],{"class":357,"line":1173},[355,4128,4083],{"class":1119},[355,4130,507],{"class":1115},[355,4132,1135],{"class":1119},[355,4134,4090],{"class":1138},[355,4136,4137,4139,4141],{"class":357,"line":1181},[355,4138,4095],{"class":1115},[355,4140,1135],{"class":1119},[355,4142,4143],{"class":1138},"mask_emails\n",[355,4145,4146,4148,4150],{"class":357,"line":1189},[355,4147,4105],{"class":1115},[355,4149,1135],{"class":1119},[355,4151,4152],{"class":1138},"'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\\\.[a-zA-Z0-9-.]+'\n",[355,4154,4155,4157,4159],{"class":357,"line":1197},[355,4156,4115],{"class":1115},[355,4158,1135],{"class":1119},[355,4160,4161],{"class":1138},"\"[HIDE_EMAIL]\"\n",[355,4163,4164],{"class":357,"line":1205},[355,4165,1271],{"emptyLinePlaceholder":893},[355,4167,4168,4170,4172,4174],{"class":357,"line":1213},[355,4169,4083],{"class":1119},[355,4171,507],{"class":1115},[355,4173,1135],{"class":1119},[355,4175,4090],{"class":1138},[355,4177,4178,4180,4182],{"class":357,"line":1221},[355,4179,4095],{"class":1115},[355,4181,1135],{"class":1119},[355,4183,4184],{"class":1138},"mask_phone_numbers\n",[355,4186,4187,4189,4191],{"class":357,"line":1229},[355,4188,4105],{"class":1115},[355,4190,1135],{"class":1119},[355,4192,4193],{"class":1138},"'(?:\\\\+33|0)[1-9]\\\\d{8}'\n",[355,4195,4196,4198,4200],{"class":357,"line":1237},[355,4197,4115],{"class":1115},[355,4199,1135],{"class":1119},[355,4201,4202],{"class":1138},"\"[HIDE_PHONE_NUMBER]\"\n",[84,4204,4206],{"id":4205},"niveau-2-vector-serveur-relai","Niveau 2 : Vector (serveur relai)",[19,4208,4209],{},"Même si l'agent fait le boulot, on applique une seconde passe dans Vector via un transform VRL. Le principe : même si un agent est mal configuré ou qu'un nouveau serveur est ajouté sans les processing rules, les données sont quand même anonymisées avant de sortir vers Datadog.",[344,4211,4213],{"className":1106,"code":4212,"language":1108,"meta":350,"style":350},"transforms:\n  anonymize_logs:\n    type: remap\n    inputs:\n      - \"datadog_agents.logs\"\n    source: |\n      .message = to_string(.message) ?? \"\"\n\n      .message = redact!(.message,\n        [r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'],\n        {\"type\": \"text\", \"replacement\": \"[HIDE_IP]\"}\n      )\n\n      .message = redact!(.message,\n        [r'https?:\u002F\u002F[\\\\w\\\\-]+(\\\\.[\\\\w\\\\-]+)+([\\\\w\\\\-.,@?^=%&:\u002F~+#]*[\\\\w\\\\-@?^=%&\u002F~+#])?'],\n        {\"type\": \"text\", \"replacement\": \"[HIDE_URL]\"}\n      )\n\n      .message = redact!(.message,\n        [r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\\\.[a-zA-Z0-9-.]+'],\n        {\"type\": \"text\", \"replacement\": \"[HIDE_EMAIL]\"}\n      )\n\n      .message = redact!(.message,\n        [r'(?:\\\\+33|0)[1-9]\\\\d{8}'],\n        {\"type\": \"text\", \"replacement\": \"[HIDE_PHONE_NUMBER]\"}\n      )\n",[352,4214,4215,4222,4229,4238,4245,4252,4262,4267,4271,4276,4281,4286,4291,4295,4299,4304,4309,4313,4317,4321,4326,4331,4335,4339,4343,4348,4353],{"__ignoreMap":350},[355,4216,4217,4220],{"class":357,"line":358},[355,4218,4219],{"class":1115},"transforms",[355,4221,1120],{"class":1119},[355,4223,4224,4227],{"class":357,"line":364},[355,4225,4226],{"class":1115},"  anonymize_logs",[355,4228,1120],{"class":1119},[355,4230,4231,4233,4235],{"class":357,"line":370},[355,4232,3830],{"class":1115},[355,4234,1135],{"class":1119},[355,4236,4237],{"class":1138},"remap\n",[355,4239,4240,4243],{"class":357,"line":376},[355,4241,4242],{"class":1115},"    inputs",[355,4244,1120],{"class":1119},[355,4246,4247,4249],{"class":357,"line":382},[355,4248,1151],{"class":1119},[355,4250,4251],{"class":1138},"\"datadog_agents.logs\"\n",[355,4253,4254,4257,4259],{"class":357,"line":1157},[355,4255,4256],{"class":1115},"    source",[355,4258,1135],{"class":1119},[355,4260,4261],{"class":2801},"|\n",[355,4263,4264],{"class":357,"line":1165},[355,4265,4266],{"class":1138},"      .message = to_string(.message) ?? \"\"\n",[355,4268,4269],{"class":357,"line":1173},[355,4270,1271],{"emptyLinePlaceholder":893},[355,4272,4273],{"class":357,"line":1181},[355,4274,4275],{"class":1138},"      .message = redact!(.message,\n",[355,4277,4278],{"class":357,"line":1189},[355,4279,4280],{"class":1138},"        [r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'],\n",[355,4282,4283],{"class":357,"line":1197},[355,4284,4285],{"class":1138},"        {\"type\": \"text\", \"replacement\": \"[HIDE_IP]\"}\n",[355,4287,4288],{"class":357,"line":1205},[355,4289,4290],{"class":1138},"      )\n",[355,4292,4293],{"class":357,"line":1213},[355,4294,1271],{"emptyLinePlaceholder":893},[355,4296,4297],{"class":357,"line":1221},[355,4298,4275],{"class":1138},[355,4300,4301],{"class":357,"line":1229},[355,4302,4303],{"class":1138},"        [r'https?:\u002F\u002F[\\\\w\\\\-]+(\\\\.[\\\\w\\\\-]+)+([\\\\w\\\\-.,@?^=%&:\u002F~+#]*[\\\\w\\\\-@?^=%&\u002F~+#])?'],\n",[355,4305,4306],{"class":357,"line":1237},[355,4307,4308],{"class":1138},"        {\"type\": \"text\", \"replacement\": \"[HIDE_URL]\"}\n",[355,4310,4311],{"class":357,"line":1245},[355,4312,4290],{"class":1138},[355,4314,4315],{"class":357,"line":1256},[355,4316,1271],{"emptyLinePlaceholder":893},[355,4318,4319],{"class":357,"line":1268},[355,4320,4275],{"class":1138},[355,4322,4323],{"class":357,"line":1274},[355,4324,4325],{"class":1138},"        [r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\\\.[a-zA-Z0-9-.]+'],\n",[355,4327,4328],{"class":357,"line":1282},[355,4329,4330],{"class":1138},"        {\"type\": \"text\", \"replacement\": \"[HIDE_EMAIL]\"}\n",[355,4332,4333],{"class":357,"line":1290},[355,4334,4290],{"class":1138},[355,4336,4337],{"class":357,"line":1301},[355,4338,1271],{"emptyLinePlaceholder":893},[355,4340,4341],{"class":357,"line":1306},[355,4342,4275],{"class":1138},[355,4344,4345],{"class":357,"line":1314},[355,4346,4347],{"class":1138},"        [r'(?:\\\\+33|0)[1-9]\\\\d{8}'],\n",[355,4349,4350],{"class":357,"line":1322},[355,4351,4352],{"class":1138},"        {\"type\": \"text\", \"replacement\": \"[HIDE_PHONE_NUMBER]\"}\n",[355,4354,4355],{"class":357,"line":1333},[355,4356,4290],{"class":1138},[19,4358,4359],{},"VRL a l'avantage d'être compilé et très performant. Sur notre volume de logs, l'impact sur le throughput de Vector était négligeable.",[19,4361,4362],{},"La logique est simple : le niveau 1 est la ligne de défense principale, le niveau 2 est le filet de sécurité. Si un admin ajoute un serveur sans configurer les processing rules de l'agent, les PII sont quand même masquées par Vector.",[952,4364],{},[23,4366,4368],{"id":4367},"résilience-le-buffer-disque-write-ahead-log","Résilience : le buffer disque write-ahead log",[19,4370,4371],{},"Que se passe-t-il si la connexion entre Vector et Datadog tombe ? Par défaut, Vector buffer en mémoire. Un crash ou un redémarrage pendant une coupure réseau, et ce sont des heures de logs d'audit qui disparaissent.",[19,4373,4374],{},"On a activé le buffer disque, qui fonctionne comme un write-ahead log :",[344,4376,4378],{"className":1106,"code":4377,"language":1108,"meta":350,"style":350},"sinks:\n  dd_logs:\n    type: datadog_logs\n    inputs:\n      - anonymize_logs\n    default_api_key: \"${DD_API_KEY}\"\n    site: \"datadoghq.eu\"\n    buffer:\n      type: disk\n      max_size: 85899345920  # ~80 Go\n      when_full: block\n",[352,4379,4380,4387,4394,4403,4409,4416,4426,4436,4443,4452,4465],{"__ignoreMap":350},[355,4381,4382,4385],{"class":357,"line":358},[355,4383,4384],{"class":1115},"sinks",[355,4386,1120],{"class":1119},[355,4388,4389,4392],{"class":357,"line":364},[355,4390,4391],{"class":1115},"  dd_logs",[355,4393,1120],{"class":1119},[355,4395,4396,4398,4400],{"class":357,"line":370},[355,4397,3830],{"class":1115},[355,4399,1135],{"class":1119},[355,4401,4402],{"class":1138},"datadog_logs\n",[355,4404,4405,4407],{"class":357,"line":376},[355,4406,4242],{"class":1115},[355,4408,1120],{"class":1119},[355,4410,4411,4413],{"class":357,"line":382},[355,4412,1151],{"class":1119},[355,4414,4415],{"class":1138},"anonymize_logs\n",[355,4417,4418,4421,4423],{"class":357,"line":1157},[355,4419,4420],{"class":1115},"    default_api_key",[355,4422,1135],{"class":1119},[355,4424,4425],{"class":1138},"\"${DD_API_KEY}\"\n",[355,4427,4428,4431,4433],{"class":357,"line":1165},[355,4429,4430],{"class":1115},"    site",[355,4432,1135],{"class":1119},[355,4434,4435],{"class":1138},"\"datadoghq.eu\"\n",[355,4437,4438,4441],{"class":357,"line":1173},[355,4439,4440],{"class":1115},"    buffer",[355,4442,1120],{"class":1119},[355,4444,4445,4447,4449],{"class":357,"line":1181},[355,4446,1344],{"class":1115},[355,4448,1135],{"class":1119},[355,4450,4451],{"class":1138},"disk\n",[355,4453,4454,4457,4459,4462],{"class":357,"line":1189},[355,4455,4456],{"class":1115},"      max_size",[355,4458,1135],{"class":1119},[355,4460,4461],{"class":1264},"85899345920",[355,4463,4464],{"class":3858},"  # ~80 Go\n",[355,4466,4467,4470,4472],{"class":357,"line":1197},[355,4468,4469],{"class":1115},"      when_full",[355,4471,1135],{"class":1119},[355,4473,4474],{"class":1138},"block\n",[19,4476,4477],{},"Le fonctionnement :",[443,4479,4480,4487,4493,4496],{},[446,4481,4482,4483,4486],{},"Chaque événement est ",[34,4484,4485],{},"écrit sur disque"," avant d'être envoyé",[446,4488,4489,4490],{},"En cas de coupure, les événements s'accumulent dans ",[352,4491,4492],{},"\u002Fvector\u002Fbuffer\u002F",[446,4494,4495],{},"Quand la connexion revient, Vector vide automatiquement le buffer",[446,4497,4498],{},"En cas de crash, les données sont récupérées au redémarrage",[19,4500,4501,4502,4505],{},"Les fichiers buffer sont des segments de 128 Mo en append-only. Le paramètre ",[352,4503,4504],{},"when_full: block"," signifie que si le buffer de 80 Go est plein, Vector bloque l'ingestion plutôt que de perdre des données. C'est un choix assumé : on préfère que les agents soient temporairement bloqués plutôt que de perdre des logs.",[84,4507,4509],{"id":4508},"un-point-dattention-sur-le-monitoring-du-buffer","Un point d'attention sur le monitoring du buffer",[19,4511,4512,4513,4516],{},"Le buffer disque crée des fichiers ",[352,4514,4515],{},"buffer-data-X.dat"," qui ne font que grossir — c'est normal, c'est le comportement d'un write-ahead log. Un fichier de quelques Mo qui grossit lentement, c'est le fonctionnement nominal. Si vous voyez plusieurs fichiers apparaître et la taille exploser, c'est que la connexion vers Datadog est dégradée.",[344,4518,4522],{"className":4519,"code":4520,"language":4521,"meta":350,"style":350},"language-bash shiki shiki-themes github-dark-default","# Surveiller en temps réel\nwatch -n 5 'ls -lah \u002Fvector\u002Fbuffer\u002Fdd_logs\u002F'\n","bash",[352,4523,4524,4529],{"__ignoreMap":350},[355,4525,4526],{"class":357,"line":358},[355,4527,4528],{"class":3858},"# Surveiller en temps réel\n",[355,4530,4531,4534,4537,4540],{"class":357,"line":364},[355,4532,4533],{"class":2805},"watch",[355,4535,4536],{"class":1264}," -n",[355,4538,4539],{"class":1264}," 5",[355,4541,4542],{"class":1138}," 'ls -lah \u002Fvector\u002Fbuffer\u002Fdd_logs\u002F'\n",[952,4544],{},[23,4546,4548],{"id":4547},"langle-mort-qui-surveille-le-surveillant","L'angle mort : qui surveille le surveillant ?",[19,4550,4551],{},"Un problème classique avec un relai centralisé : si Vector tombe, toutes les métriques et logs de Vector... ne sont plus transmis. On perd la visibilité exactement quand on en a le plus besoin.",[19,4553,4554,4555,4558,4559,4562],{},"La solution : un ",[34,4556,4557],{},"agent Datadog dédié"," installé directement sur le serveur Vector, qui se connecte à Datadog ",[34,4560,4561],{},"sans passer par Vector",". Cet agent surveille :",[443,4564,4565,4574,4583,4592],{},[446,4566,4567,494,4570,4573],{},[34,4568,4569],{},"Le processus Vector",[352,4571,4572],{},"process.d",") : est-ce que le binaire tourne ?",[446,4575,4576,494,4579,4582],{},[34,4577,4578],{},"Le port 8443",[352,4580,4581],{},"tcp_check.d",") : est-ce que Vector écoute ?",[446,4584,4585,494,4588,4591],{},[34,4586,4587],{},"L'espace disque",[352,4589,4590],{},"disk.d",") : le buffer risque-t-il de saturer ?",[446,4593,4594,494,4597,4600],{},[34,4595,4596],{},"Les logs systemd",[352,4598,4599],{},"journal.d",") : y a-t-il des erreurs ?",[19,4602,4603],{},"Ça crée un canal de monitoring indépendant. Si Vector crash, on le sait immédiatement via l'agent dédié.",[19,4605,4606],{},"Les alertes à poser dans Datadog pour avoir l'esprit tranquille :",[443,4608,4609,4615,4621,4627],{},[446,4610,4611,4614],{},[34,4612,4613],{},"Process down"," : le processus Vector n'est pas détecté depuis 2 minutes",[446,4616,4617,4620],{},[34,4618,4619],{},"Port 8443 injoignable"," : les agents ne peuvent plus envoyer leurs données",[446,4622,4623,4626],{},[34,4624,4625],{},"Disque buffer > 90%"," : risque de perte si le buffer sature",[446,4628,4629,4632],{},[34,4630,4631],{},"Absence de logs applicatifs"," : aucun log reçu depuis 15 minutes (coupure complète)",[952,4634],{},[23,4636,4638],{"id":4637},"la-gestion-des-secrets","La gestion des secrets",[19,4640,4641],{},"Un point qu'on sous-estime souvent : comment gérer la clé API Datadog sans la mettre en dur dans les fichiers de config.",[19,4643,4644,4645,4648,4649,4652,4653,44],{},"Côté Vector, la clé est injectée via une variable d'environnement ",[352,4646,4647],{},"DD_API_KEY"," dans le fichier ",[352,4650,4651],{},"EnvironmentFile"," du service systemd. Le fichier est lisible uniquement par l'utilisateur système ",[352,4654,4655],{},"vector",[344,4657,4659],{"className":1106,"code":4658,"language":1108,"meta":350,"style":350},"# vector.yaml — la clé n'est jamais en dur\nsinks:\n  dd_logs:\n    default_api_key: \"${DD_API_KEY}\"\n",[352,4660,4661,4666,4672,4678],{"__ignoreMap":350},[355,4662,4663],{"class":357,"line":358},[355,4664,4665],{"class":3858},"# vector.yaml — la clé n'est jamais en dur\n",[355,4667,4668,4670],{"class":357,"line":364},[355,4669,4384],{"class":1115},[355,4671,1120],{"class":1119},[355,4673,4674,4676],{"class":357,"line":370},[355,4675,4391],{"class":1115},[355,4677,1120],{"class":1119},[355,4679,4680,4682,4684],{"class":357,"line":376},[355,4681,4420],{"class":1115},[355,4683,1135],{"class":1119},[355,4685,4425],{"class":1138},[344,4687,4689],{"className":4519,"code":4688,"language":4521,"meta":350,"style":350},"# vector.default (EnvironmentFile systemd, chmod 600)\nDD_API_KEY=votre-clé-api\n",[352,4690,4691,4696],{"__ignoreMap":350},[355,4692,4693],{"class":357,"line":358},[355,4694,4695],{"class":3858},"# vector.default (EnvironmentFile systemd, chmod 600)\n",[355,4697,4698,4700,4702],{"class":357,"line":364},[355,4699,4647],{"class":1119},[355,4701,2042],{"class":2801},[355,4703,4704],{"class":1138},"votre-clé-api\n",[19,4706,4707,4708,4710],{},"Côté agents Windows, la clé est un placeholder ",[352,4709,3792],{}," puisque les agents ne contactent jamais Datadog directement. L'avantage : même si quelqu'un lit la config d'un serveur Windows, il n'a pas la vraie clé API.",[19,4712,4713,4714,4717,4718,44],{},"Le certificat TLS privé est aussi protégé en ",[352,4715,4716],{},"chmod 600",", accessible uniquement par l'utilisateur ",[352,4719,4655],{},[952,4721],{},[23,4723,4725],{"id":4724},"ce-que-jaurais-fait-différemment","Ce que j'aurais fait différemment",[19,4727,4728],{},"Quelques leçons tirées de cette intervention :",[19,4730,4731,4734],{},[34,4732,4733],{},"Préparer la checklist en amont."," On a perdu du temps sur des prérequis manquants : ouvertures de flux réseau pas encore faites, certificats pas générés, serveur Linux pas encore provisionné. Une checklist détaillée envoyée au client 2 semaines avant aurait évité ça.",[19,4736,4737,2756,4740,2756,4744,4747,4748,4750],{},[34,4738,4739],{},"Tester",[34,4741,4742],{},[352,4743,3736],{},[34,4745,4746],{},"dès le début."," Ce paramètre est le piège classique de la source ",[352,4749,3773],{}," dans Vector. Si je refais ce setup, c'est le premier truc que je vérifie.",[19,4752,4753,4756],{},[34,4754,4755],{},"Automatiser le déploiement des agents Windows."," On a configuré chaque serveur à la main. Avec Ansible, on aurait pu déployer la config Datadog Agent + certificat CA sur tous les serveurs en une commande.",[19,4758,4759,2756,4762,4768,4769,4772],{},[34,4760,4761],{},"Documenter le",[34,4763,4764,4767],{},[352,4765,4766],{},"vector tap","****."," C'est la commande la plus utile pour débugger. ",[352,4770,4771],{},"vector tap --inputs-of dd_logs"," montre en temps réel les événements qui arrivent dans un sink. Ça m'a sauvé plusieurs fois.",[952,4774],{},[23,4776,4778],{"id":4777},"les-commandes-de-survie","Les commandes de survie",[19,4780,4781],{},"Pour ceux qui souhaitent se lancer avec un setup similaire, voici les commandes utilisées dans notre cas d'étude :",[344,4783,4785],{"className":4519,"code":4784,"language":4521,"meta":350,"style":350},"# Santé de Vector\ncurl \u003Chttp:\u002F\u002F127.0.0.1:8686\u002Fhealth>\n\n# Vue temps réel du pipeline (events in\u002Fout par composant)\nvector top\n\n# Observer les événements en transit avant un sink\nvector tap --inputs-of dd_logs\n\n# Vérifier les métriques d'envoi\ncurl -s \u003Chttp:\u002F\u002F127.0.0.1:8686\u002Fapi\u002Fv1\u002Fmetrics> | grep component_sent_events_total\n\n# Taille du buffer\ncurl -s \u003Chttp:\u002F\u002F127.0.0.1:8686\u002Fapi\u002Fv1\u002Fmetrics> | grep buffer_byte_size\n\n# Valider la config avant de redémarrer\nvector validate --config-dir \u002Fpath\u002Fto\u002Fconfig\u002F\n",[352,4786,4787,4792,4809,4813,4818,4825,4829,4834,4847,4851,4856,4881,4885,4890,4911,4915,4920],{"__ignoreMap":350},[355,4788,4789],{"class":357,"line":358},[355,4790,4791],{"class":3858},"# Santé de Vector\n",[355,4793,4794,4797,4800,4803,4806],{"class":357,"line":364},[355,4795,4796],{"class":2805},"curl",[355,4798,4799],{"class":2801}," \u003C",[355,4801,4802],{"class":1138},"http:\u002F\u002F127.0.0.1:8686\u002Fhealt",[355,4804,4805],{"class":1119},"h",[355,4807,4808],{"class":2801},">\n",[355,4810,4811],{"class":357,"line":370},[355,4812,1271],{"emptyLinePlaceholder":893},[355,4814,4815],{"class":357,"line":376},[355,4816,4817],{"class":3858},"# Vue temps réel du pipeline (events in\u002Fout par composant)\n",[355,4819,4820,4822],{"class":357,"line":382},[355,4821,4655],{"class":2805},[355,4823,4824],{"class":1138}," top\n",[355,4826,4827],{"class":357,"line":1157},[355,4828,1271],{"emptyLinePlaceholder":893},[355,4830,4831],{"class":357,"line":1165},[355,4832,4833],{"class":3858},"# Observer les événements en transit avant un sink\n",[355,4835,4836,4838,4841,4844],{"class":357,"line":1173},[355,4837,4655],{"class":2805},[355,4839,4840],{"class":1138}," tap",[355,4842,4843],{"class":1264}," --inputs-of",[355,4845,4846],{"class":1138}," dd_logs\n",[355,4848,4849],{"class":357,"line":1181},[355,4850,1271],{"emptyLinePlaceholder":893},[355,4852,4853],{"class":357,"line":1189},[355,4854,4855],{"class":3858},"# Vérifier les métriques d'envoi\n",[355,4857,4858,4860,4863,4865,4868,4870,4872,4875,4878],{"class":357,"line":1197},[355,4859,4796],{"class":2805},[355,4861,4862],{"class":1264}," -s",[355,4864,4799],{"class":2801},[355,4866,4867],{"class":1138},"http:\u002F\u002F127.0.0.1:8686\u002Fapi\u002Fv1\u002Fmetric",[355,4869,1973],{"class":1119},[355,4871,2831],{"class":2801},[355,4873,4874],{"class":2801}," |",[355,4876,4877],{"class":2805}," grep",[355,4879,4880],{"class":1138}," component_sent_events_total\n",[355,4882,4883],{"class":357,"line":1205},[355,4884,1271],{"emptyLinePlaceholder":893},[355,4886,4887],{"class":357,"line":1213},[355,4888,4889],{"class":3858},"# Taille du buffer\n",[355,4891,4892,4894,4896,4898,4900,4902,4904,4906,4908],{"class":357,"line":1221},[355,4893,4796],{"class":2805},[355,4895,4862],{"class":1264},[355,4897,4799],{"class":2801},[355,4899,4867],{"class":1138},[355,4901,1973],{"class":1119},[355,4903,2831],{"class":2801},[355,4905,4874],{"class":2801},[355,4907,4877],{"class":2805},[355,4909,4910],{"class":1138}," buffer_byte_size\n",[355,4912,4913],{"class":357,"line":1229},[355,4914,1271],{"emptyLinePlaceholder":893},[355,4916,4917],{"class":357,"line":1237},[355,4918,4919],{"class":3858},"# Valider la config avant de redémarrer\n",[355,4921,4922,4924,4927,4930],{"class":357,"line":1245},[355,4923,4655],{"class":2805},[355,4925,4926],{"class":1138}," validate",[355,4928,4929],{"class":1264}," --config-dir",[355,4931,4932],{"class":1138}," \u002Fpath\u002Fto\u002Fconfig\u002F\n",[952,4934],{},[23,4936,4938],{"id":4937},"en-résumé","En résumé",[19,4940,4941,4942,4945],{},"Mettre Datadog sur des serveurs on-premise sans internet, c'est faisable.\n",[91,4943,3557],{"href":3553,"rel":4944},[95]," est l'outil qui manquait pour combler le gap entre un réseau isolé et un SaaS de monitoring. Il permet de construire un pipeline complet (logs, métriques, traces APM) avec de l'anonymisation, du buffering résilient et un monitoring du monitoring.",[19,4947,4948,4949,4951],{},"Les vrais pièges ne sont pas dans la complexité de l'architecture (qui est assez simple au final), mais dans les détails de configuration. ",[352,4950,3865],{},", les certificats dans le bon magasin Windows, le buffer disque activé — ce sont ces petits paramètres qui font la différence.",[19,4953,4954,4957,4958,4962],{},[34,4955,4956],{},"Si vous travaillez dans le secteur bancaire, l'assurance ou la défense, les environnements air-gapped sont votre quotidien.","\nCe retour d'expérience démontre qu'il existe des solutions pour adopter une observabilité moderne cloud-native, même liée à des contraintes fortes de sécurité. Chez ",[91,4959,1836],{"href":4960,"rel":4961},"https:\u002F\u002Fhoppr.tech\u002F",[95],", nous pouvons aisément nous rendre disponibles pour partager ce retour d'expérience et accompagner vos équipes sur des use cases similaires.",[952,4964],{},[19,4966,4967],{},[1620,4968,4969],{},"Stack utilisée : Vector 0.54, Datadog Agent v7.35+, Datadog .NET Tracer, OpenTelemetry SDK .NET, Debian 11, Windows Server.",[856,4971,4972],{},"html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}",{"title":350,"searchDepth":364,"depth":364,"links":4974},[4975,4976,4977,4978,4983,4984,4988,4991,4992,4993,4994,4995],{"id":3565,"depth":364,"text":3566},{"id":3615,"depth":364,"text":3616},{"id":3706,"depth":364,"text":3707},{"id":3732,"depth":364,"text":4979,"children":4980},"Piège n°1 : store_api_key — un comportement par défaut trompeur",[4981,4982],{"id":3747,"depth":370,"text":3748},{"id":3802,"depth":370,"text":3803},{"id":3881,"depth":364,"text":3882},{"id":4025,"depth":364,"text":4026,"children":4985},[4986,4987],{"id":4044,"depth":370,"text":4045},{"id":4205,"depth":370,"text":4206},{"id":4367,"depth":364,"text":4368,"children":4989},[4990],{"id":4508,"depth":370,"text":4509},{"id":4547,"depth":364,"text":4548},{"id":4637,"depth":364,"text":4638},{"id":4724,"depth":364,"text":4725},{"id":4777,"depth":364,"text":4778},{"id":4937,"depth":364,"text":4938},"2026-03-31T09:19:57.655Z","Comment faire fonctionner Datadog sur des serveurs Windows isolés, sans internet et avec une anonymisation stricte des données ? Retour d'expérience sur la mise en place de Vector pour connecter un cl",{},"\u002Fblogs\u002F2026-03-31-connecter-datadog-un-rseau-100-hors-ligne-retour-dexprience-avec-vector",[5001,5003],{"id":897,"name":898,"image":5002,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466WKI65JWJ%2F20260331%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260331T091955Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEHAaCXVzLXdlc3QtMiJHMEUCIQDSZgDjNi3sP1o45M%2BdiEMmTxbermZOZmAJhrALjcluPAIgdhUhGsn4X4i%2BLTUwRhgpR%2BycyNBzcMiyadnevYSS6u0q%2FwMIORAAGgw2Mzc0MjMxODM4MDUiDGRBhJxGc6GXZ6042yrcA8%2Fhlu1SVrjNWtDftbI5EZadBcy6XDcdg9%2B5I2GVEVqzYoMyruLfNqtQwGQ8fSdHnByX5HzehbigPR4KXzy3t0I%2BUjA%2BsgGnFq1SAY9TCFdeWCm%2F5%2B2pjEf1G5snq%2BbNYoqxJckPr2kLEqOY3b%2FEfRVRvwwo0bw0bQhJ%2BrNJ2WAyZx%2BqLMvAy8a3GihDlJzeicHsGoEZlOv9ZobTschCvLAHTLKAqUg1YpUUo9X8myPCg9wzKh4T8xs3m5zRjPE7D6y1lM%2BvNmq0gX4Y5%2B9S6qd%2BVSN3jk0gqAznAnCeUk%2FTwUhmlUgPxQTys6BY442vdQoimeFBEJoJFsWbUmvAkLTlANf8C9lpu5zI3XVv33%2BbpR1eKE0RP3cVY5iBBAhHAOXGlNL9oGDY3lScWCHq%2F6AH1O8czW7maRtPTx%2BQVe3sWKIQhRw9EMjyQJDIGbRybtR5f4BPz2U4Q37nQRjsDEKbw9sDhy3o2xXAEB4OIRBIUx6%2BwtzXA5GHVy%2FctByHzF32KJjd7NlHKDQWb540An3iYkmMYlGQcF%2BgdcKQTT2AVVIspHM9e%2BSTpEAx8uuhRffuKcZ3xB9qWUZcwGCTsdXI00rs9uGWRJDpZcXDT9HEywLSKdfuor68M%2B4qMIuCrs4GOqUBqZww9qFLtD4EKwiqojXS8g6YR9ncN9513NxjCEU475%2FMXoHCHBh457haiTO5Rr%2BkWN78O%2FxkxIGhEgD2EMho6er%2FrZfq6HY9iv2KK%2Fe1YeRtxVR9q7I%2FOrkalcmIjTQ3kRoDl3AboTpTWmYujp1xDv7RUJyot%2Fv4y7YDXFCmkpfhlQ%2B%2FOjY4PSdm1Ef3PL3B%2FgNt1Xh2zrXwcofdgVjSCdHBfTjw&X-Amz-Signature=0aebaf1925371cf4e94a15006b36e914fa485a156980ae99d9ba2b1e235eef74&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":1577,"name":1578,"image":5004,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466YBLG6UZV%2F20260331%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260331T091957Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEHAaCXVzLXdlc3QtMiJIMEYCIQCZDTZ53wTD%2FMHLqQw7NdLbfyVc18pjXxNyPvVZvvMmNgIhALUx7mgCQ7OCcfSP1mZF2elCzmFHCpVvwKPkwz2h%2B34nKv8DCDkQABoMNjM3NDIzMTgzODA1IgxCvzozw56iEmua0X4q3AODqxNXRnKdPDj%2FKPRTfuKWaWxKQFww6mO5SA5GRawkDcMJwaL8lEMh4eODhSx9x1h%2Fg3mbYXd6BqLXKGpMF%2BaLIoQCSQf9OObRawCnJ%2BOXlLXrL1VLfzgvZtSAMRcraA%2FDHgZxlwfOWUriQcvQdCfeKUNRvapPx2iBO4Bxrny%2BpyZFkCgXC7YO%2FarWsWCd7vGh7YlwdNp8pUKM36emkdvIm6g0W23XWlWks4%2FIATIrV63l1WbuW5D68RysasibgJL0RbZ0vdrcAesMdEX5qV5bp%2BuNSHMOVNCF12zrrFmUBYET7EGPf%2B8A73UDqYmL2bj4uXvRt7gaYiIsezb5jlLXdgSh2nZ0F92R4ti0b5jjATeZHe9KbcSZvtk62R8c6fw9bC1tY7kSH4%2BG%2B1a%2Fcwt%2BWSt9kpqYjms4M1z4lkHFm1DaVLyDiMPOaSy9JFJrrlBJcjHmcJNqfzPrxCVBYvsXpC9RAHMalbCdRnjPuu%2F8RqxbKCg3mAUjMnooHi%2B3IPFcpmgQf0u%2BPI1dlXe6CPDvo7EhNbEgjxDxj8LS4ZPMZFiEaC%2FYeLYZ4PUK8BpbkaHcJRAKx1HmQ7RaP4dGmweudXsar11i1JbjEdce8mxCM3zTSzqDnUDoToMfBTCMgq7OBjqkAZgtXeALAtzeCaTqSToVWmdPKm5TTyuSNp%2BDkkD%2FMmrMZW6skUyaOtIQDc%2B5lxMtGZ7DmkSohqawq9mD6yBsP1tCL2LKPW5B1UhjdojAR9xKATUv5hcXp%2Fmvcqk%2BiWTuU7T8CM8H4I8R7dRY%2FZQJvwoA0Whlk4iEzH3cfBca2mnZ7gYr8N9Jz%2BSX%2F42xyv2Vt%2FpBDUh86ll8KV63pQYW4qslu1hY&X-Amz-Signature=a2b9f094794a34d4486bc67dcf8099314e7f29a74febb40a215fc4303807c98e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":3530,"description":4997},"blogs\u002F2026-03-31-connecter-datadog-un-rseau-100-hors-ligne-retour-dexprience-avec-vector\u002Findex",[906,5008,1591,5009,1592],"datadog","observabilité","BcsgbQIFCrJx7ausEJgeLjsndbYcnr-cI529OwPun3A",{"id":5012,"title":5013,"alt":5014,"authors":5015,"body":5021,"date":5644,"description":5645,"extension":890,"image":891,"meta":5646,"navigation":893,"ogImage":891,"path":5647,"published":893,"reviewers":5648,"seo":5651,"stem":5652,"tags":5653,"__hash__":5656},"blogs\u002Fblogs\u002F2026-03-19-dora-metrics-x-datadog-piloter-sa-vlocit-sans-effort\u002Findex.md","DORA Metrics x Datadog : Piloter sa vélocité sans effort","DORA Metrics x Datadog",[5016],{"id":5017,"name":5018,"image":5019,"linkedin":5020,"x":901},"45c76823-ab7d-4c1f-84b3-0bad16ab91e1","Paul-Alexandre Chrétien",".\u002Fassets\u002Fauthor-paul-alexandre-chrtien.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fpaulalexandrechretien\u002F",{"type":16,"value":5022,"toc":5636},[5023,5026,5038,5041,5048,5058,5065,5070,5359,5375,5379,5386,5393,5540,5544,5570,5574,5577,5583,5589,5593,5604,5610,5624,5633],[19,5024,5025],{},"On ne va pas se mentir : dans les grands groupes, mesurer la performance DevOps ressemble souvent à un parcours du combattant entre Jira, GitHub et des fichiers Excel.",[19,5027,5028,5029,5034,5035,44],{},"Pourtant, ce ",[91,5030,5033],{"href":5031,"rel":5032},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex",[95],"REX inspirant"," le prouve : même à grande échelle, on peut remplacer la saisie manuelle par une culture de la donnée 100% automatisée. La clé du succès n'est pas dans la complexité, mais dans l'",[34,5036,5037],{},"automatisation",[19,5039,5040],{},"Voici comment tracker les deux piliers de la vélocité de livraison applicative avec Datadog.",[23,5042,5044,5045],{"id":5043},"_1-deployment-frequency-le-pouvoir-du-tag-version","1. Deployment Frequency : Le pouvoir du tag ",[352,5046,5047],{},"version",[19,5049,5050,5051,44],{},"La plupart des équipes essaient de compter les déploiements à la main. Avec Datadog, c'est terminé. Si vous êtes sur Kubernetes, il suffit d'adopter le ",[91,5052,5055],{"href":5053,"rel":5054},"https:\u002F\u002Fdocs.datadoghq.com\u002Fgetting_started\u002Ftagging\u002Funified_service_tagging\u002F?tab=kubernetes",[95],[34,5056,5057],{},"Unified Service Tagging",[19,5059,5060,5061,5064],{},"En ajoutant simplement le label ",[352,5062,5063],{},"tags.datadoghq.com\u002Fversion"," à vos manifests, Datadog détecte chaque changement comme un événement de déploiement natif.",[19,5066,5067],{},[34,5068,5069],{},"Exemple de manifest \"Datadog Ready\" :",[344,5071,5073],{"className":1106,"code":5072,"language":1108,"meta":350,"style":350},"apiVersion: apps\u002Fv1\nkind: Deployment\nmetadata:\n  name: my-banger-service\nspec:\n  replicas: 3\n  selector:\n    matchLabels:\n      app: my-banger-service\n  template:\n    metadata:\n      labels:\n        # Les 3 tags magiques du Unified Service Tagging\n        tags.datadoghq.com\u002Fenv: \"prod\"\n        tags.datadoghq.com\u002Fservice: \"my-banger-service\"\n        tags.datadoghq.com\u002Fversion: \"1.2.4\" # C'est ICI que le calcul DORA commence\n    spec:\n      containers:\n      - name: my-app\n        image: my-registry\u002Fmy-app:1.2.4\n        env:\n          # On injecte ces variables pour que l'APM et les Logs héritent aussi des tags\n          - name: DD_ENV\n            valueFrom:\n              fieldRef:\n                fieldPath: metadata.labels['tags.datadoghq.com\u002Fenv']\n          - name: DD_SERVICE\n            valueFrom:\n              fieldRef:\n                fieldPath: metadata.labels['tags.datadoghq.com\u002Fservice']\n          - name: DD_VERSION\n            valueFrom:\n              fieldRef:\n                fieldPath: metadata.labels['tags.datadoghq.com\u002Fversion']\n",[352,5074,5075,5085,5095,5102,5112,5119,5129,5136,5143,5152,5159,5166,5173,5178,5188,5198,5211,5218,5225,5237,5247,5254,5259,5271,5278,5285,5295,5306,5312,5318,5327,5338,5344,5350],{"__ignoreMap":350},[355,5076,5077,5080,5082],{"class":357,"line":358},[355,5078,5079],{"class":1115},"apiVersion",[355,5081,1135],{"class":1119},[355,5083,5084],{"class":1138},"apps\u002Fv1\n",[355,5086,5087,5090,5092],{"class":357,"line":364},[355,5088,5089],{"class":1115},"kind",[355,5091,1135],{"class":1119},[355,5093,5094],{"class":1138},"Deployment\n",[355,5096,5097,5100],{"class":357,"line":370},[355,5098,5099],{"class":1115},"metadata",[355,5101,1120],{"class":1119},[355,5103,5104,5107,5109],{"class":357,"line":376},[355,5105,5106],{"class":1115},"  name",[355,5108,1135],{"class":1119},[355,5110,5111],{"class":1138},"my-banger-service\n",[355,5113,5114,5117],{"class":357,"line":382},[355,5115,5116],{"class":1115},"spec",[355,5118,1120],{"class":1119},[355,5120,5121,5124,5126],{"class":357,"line":1157},[355,5122,5123],{"class":1115},"  replicas",[355,5125,1135],{"class":1119},[355,5127,5128],{"class":1264},"3\n",[355,5130,5131,5134],{"class":357,"line":1165},[355,5132,5133],{"class":1115},"  selector",[355,5135,1120],{"class":1119},[355,5137,5138,5141],{"class":357,"line":1173},[355,5139,5140],{"class":1115},"    matchLabels",[355,5142,1120],{"class":1119},[355,5144,5145,5148,5150],{"class":357,"line":1181},[355,5146,5147],{"class":1115},"      app",[355,5149,1135],{"class":1119},[355,5151,5111],{"class":1138},[355,5153,5154,5157],{"class":357,"line":1189},[355,5155,5156],{"class":1115},"  template",[355,5158,1120],{"class":1119},[355,5160,5161,5164],{"class":357,"line":1197},[355,5162,5163],{"class":1115},"    metadata",[355,5165,1120],{"class":1119},[355,5167,5168,5171],{"class":357,"line":1205},[355,5169,5170],{"class":1115},"      labels",[355,5172,1120],{"class":1119},[355,5174,5175],{"class":357,"line":1213},[355,5176,5177],{"class":3858},"        # Les 3 tags magiques du Unified Service Tagging\n",[355,5179,5180,5183,5185],{"class":357,"line":1221},[355,5181,5182],{"class":1115},"        tags.datadoghq.com\u002Fenv",[355,5184,1135],{"class":1119},[355,5186,5187],{"class":1138},"\"prod\"\n",[355,5189,5190,5193,5195],{"class":357,"line":1229},[355,5191,5192],{"class":1115},"        tags.datadoghq.com\u002Fservice",[355,5194,1135],{"class":1119},[355,5196,5197],{"class":1138},"\"my-banger-service\"\n",[355,5199,5200,5203,5205,5208],{"class":357,"line":1237},[355,5201,5202],{"class":1115},"        tags.datadoghq.com\u002Fversion",[355,5204,1135],{"class":1119},[355,5206,5207],{"class":1138},"\"1.2.4\"",[355,5209,5210],{"class":3858}," # C'est ICI que le calcul DORA commence\n",[355,5212,5213,5216],{"class":357,"line":1245},[355,5214,5215],{"class":1115},"    spec",[355,5217,1120],{"class":1119},[355,5219,5220,5223],{"class":357,"line":1256},[355,5221,5222],{"class":1115},"      containers",[355,5224,1120],{"class":1119},[355,5226,5227,5229,5232,5234],{"class":357,"line":1268},[355,5228,1151],{"class":1119},[355,5230,5231],{"class":1115},"name",[355,5233,1135],{"class":1119},[355,5235,5236],{"class":1138},"my-app\n",[355,5238,5239,5242,5244],{"class":357,"line":1274},[355,5240,5241],{"class":1115},"        image",[355,5243,1135],{"class":1119},[355,5245,5246],{"class":1138},"my-registry\u002Fmy-app:1.2.4\n",[355,5248,5249,5252],{"class":357,"line":1282},[355,5250,5251],{"class":1115},"        env",[355,5253,1120],{"class":1119},[355,5255,5256],{"class":357,"line":1290},[355,5257,5258],{"class":3858},"          # On injecte ces variables pour que l'APM et les Logs héritent aussi des tags\n",[355,5260,5261,5264,5266,5268],{"class":357,"line":1301},[355,5262,5263],{"class":1119},"          - ",[355,5265,5231],{"class":1115},[355,5267,1135],{"class":1119},[355,5269,5270],{"class":1138},"DD_ENV\n",[355,5272,5273,5276],{"class":357,"line":1306},[355,5274,5275],{"class":1115},"            valueFrom",[355,5277,1120],{"class":1119},[355,5279,5280,5283],{"class":357,"line":1314},[355,5281,5282],{"class":1115},"              fieldRef",[355,5284,1120],{"class":1119},[355,5286,5287,5290,5292],{"class":357,"line":1322},[355,5288,5289],{"class":1115},"                fieldPath",[355,5291,1135],{"class":1119},[355,5293,5294],{"class":1138},"metadata.labels['tags.datadoghq.com\u002Fenv']\n",[355,5296,5297,5299,5301,5303],{"class":357,"line":1333},[355,5298,5263],{"class":1119},[355,5300,5231],{"class":1115},[355,5302,1135],{"class":1119},[355,5304,5305],{"class":1138},"DD_SERVICE\n",[355,5307,5308,5310],{"class":357,"line":1341},[355,5309,5275],{"class":1115},[355,5311,1120],{"class":1119},[355,5313,5314,5316],{"class":357,"line":1352},[355,5315,5282],{"class":1115},[355,5317,1120],{"class":1119},[355,5319,5320,5322,5324],{"class":357,"line":1363},[355,5321,5289],{"class":1115},[355,5323,1135],{"class":1119},[355,5325,5326],{"class":1138},"metadata.labels['tags.datadoghq.com\u002Fservice']\n",[355,5328,5329,5331,5333,5335],{"class":357,"line":1369},[355,5330,5263],{"class":1119},[355,5332,5231],{"class":1115},[355,5334,1135],{"class":1119},[355,5336,5337],{"class":1138},"DD_VERSION\n",[355,5339,5340,5342],{"class":357,"line":1377},[355,5341,5275],{"class":1115},[355,5343,1120],{"class":1119},[355,5345,5346,5348],{"class":357,"line":1386},[355,5347,5282],{"class":1115},[355,5349,1120],{"class":1119},[355,5351,5352,5354,5356],{"class":357,"line":1393},[355,5353,5289],{"class":1115},[355,5355,1135],{"class":1119},[355,5357,5358],{"class":1138},"metadata.labels['tags.datadoghq.com\u002Fversion']\n",[1003,5360,5361],{},[19,5362,5363,5366,5367,5370,5371,5374],{},[34,5364,5365],{},"Note :"," On utilise ici un contexte K8s, mais cette logique s'adapte partout. Sur une ",[34,5368,5369],{},"VM",", il suffit de passer ces tags via les variables d'environnement (",[352,5372,5373],{},"DD_VERSION",") ou la configuration de l'Agent Datadog.",[23,5376,5378],{"id":5377},"_2-change-lead-time-la-cicd-comme-source-de-vérité","2. Change Lead Time : La CI\u002FCD comme source de vérité",[19,5380,5381,5382,5385],{},"Le ",[1620,5383,5384],{},"Lead Time for Changes"," (le temps écoulé entre le commit et la mise en production) est souvent le premier vrai défi technique, car il demande de lier la CI\u002FCD au monitoring de prod.",[19,5387,5388,5389,5392],{},"La solution ? ",[34,5390,5391],{},"Datadog CI Visibility",". Au lieu de faire des calculs manuels approximatifs, on injecte un binaire Datadog directement dans votre pipeline (GitHub Actions, GitLab CI, Jenkins) :",[344,5394,5396],{"className":1106,"code":5395,"language":1108,"meta":350,"style":350},"stages:\n  - build\n  - test\n  - publish  # C'est ici qu'on lie le code à Datadog\n\ndatadog-metadata:\n  stage: publish\n  image: \n    name: datadog\u002Fci:v5.9.1\n    entrypoint: [\"\"]\n  variables:\n    DATADOG_SITE: \"datadoghq.eu\"\n    # DATADOG_API_KEY doit être définie dans vos variables CI\u002FCD GitLab\n  script:\n    - datadog-ci git-metadata upload\n  rules:\n    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH # On track seulement la branche principale\n",[352,5397,5398,5405,5413,5420,5430,5434,5441,5451,5459,5469,5483,5490,5499,5504,5511,5518,5525],{"__ignoreMap":350},[355,5399,5400,5403],{"class":357,"line":358},[355,5401,5402],{"class":1115},"stages",[355,5404,1120],{"class":1119},[355,5406,5407,5410],{"class":357,"line":364},[355,5408,5409],{"class":1119},"  - ",[355,5411,5412],{"class":1138},"build\n",[355,5414,5415,5417],{"class":357,"line":370},[355,5416,5409],{"class":1119},[355,5418,5419],{"class":1138},"test\n",[355,5421,5422,5424,5427],{"class":357,"line":376},[355,5423,5409],{"class":1119},[355,5425,5426],{"class":1138},"publish",[355,5428,5429],{"class":3858},"  # C'est ici qu'on lie le code à Datadog\n",[355,5431,5432],{"class":357,"line":382},[355,5433,1271],{"emptyLinePlaceholder":893},[355,5435,5436,5439],{"class":357,"line":1157},[355,5437,5438],{"class":1115},"datadog-metadata",[355,5440,1120],{"class":1119},[355,5442,5443,5446,5448],{"class":357,"line":1165},[355,5444,5445],{"class":1115},"  stage",[355,5447,1135],{"class":1119},[355,5449,5450],{"class":1138},"publish\n",[355,5452,5453,5456],{"class":357,"line":1173},[355,5454,5455],{"class":1115},"  image",[355,5457,5458],{"class":1119},": \n",[355,5460,5461,5464,5466],{"class":357,"line":1181},[355,5462,5463],{"class":1115},"    name",[355,5465,1135],{"class":1119},[355,5467,5468],{"class":1138},"datadog\u002Fci:v5.9.1\n",[355,5470,5471,5474,5477,5480],{"class":357,"line":1189},[355,5472,5473],{"class":1115},"    entrypoint",[355,5475,5476],{"class":1119},": [",[355,5478,5479],{"class":1138},"\"\"",[355,5481,5482],{"class":1119},"]\n",[355,5484,5485,5488],{"class":357,"line":1197},[355,5486,5487],{"class":1115},"  variables",[355,5489,1120],{"class":1119},[355,5491,5492,5495,5497],{"class":357,"line":1205},[355,5493,5494],{"class":1115},"    DATADOG_SITE",[355,5496,1135],{"class":1119},[355,5498,4435],{"class":1138},[355,5500,5501],{"class":357,"line":1213},[355,5502,5503],{"class":3858},"    # DATADOG_API_KEY doit être définie dans vos variables CI\u002FCD GitLab\n",[355,5505,5506,5509],{"class":357,"line":1221},[355,5507,5508],{"class":1115},"  script",[355,5510,1120],{"class":1119},[355,5512,5513,5515],{"class":357,"line":1229},[355,5514,4083],{"class":1119},[355,5516,5517],{"class":1138},"datadog-ci git-metadata upload\n",[355,5519,5520,5523],{"class":357,"line":1237},[355,5521,5522],{"class":1115},"  rules",[355,5524,1120],{"class":1119},[355,5526,5527,5529,5532,5534,5537],{"class":357,"line":1245},[355,5528,4083],{"class":1119},[355,5530,5531],{"class":1115},"if",[355,5533,1135],{"class":1119},[355,5535,5536],{"class":1138},"$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH",[355,5538,5539],{"class":3858}," # On track seulement la branche principale\n",[23,5541,5543],{"id":5542},"pourquoi-cest-lapproche-gagnante","Pourquoi c'est l'approche gagnante ?",[443,5545,5546,5552,5558],{},[446,5547,5548,5551],{},[34,5549,5550],{},"Lien Automatique"," : En lançant cette commande, Datadog associe les hashes des commits au build en cours.",[446,5553,5554,5557],{},[34,5555,5556],{},"Zéro Impact Runtime"," : Contrairement à d'autres outils qui ralentissent l'application, ici tout se passe dans la forge logicielle.",[446,5559,5560,5563,5564,5566,5567,44],{},[34,5561,5562],{},"Réconciliation magique"," : Dès qu’un pod Kubernetes (avec son tag ",[352,5565,5047],{},") pop sur l'infra, Datadog fait le calcul : ",[352,5568,5569],{},"Heure du déploiement - Heure du commit = Lead Time",[23,5571,5573],{"id":5572},"et-sinon-ça-ressemble-à-quoi-après-ce-setup","Et sinon ça ressemble à quoi après ce setup?",[19,5575,5576],{},"Voici deux captures d’écran permettant de voir les metriques “Deployment Frequency” et “Change Lead Time” sur un service en production:",[19,5578,5579],{},[176,5580],{"alt":5581,"src":5582},"Vue unifiée “DORA Metrics” sur Datadog pour un service en production - Deployment Frequency","\u002Fcontent-assets\u002F2026-03-19-dora-metrics-x-datadog-piloter-sa-vlocit-sans-effort\u002Fassets\u002Fimg1.webp",[19,5584,5585],{},[176,5586],{"alt":5587,"src":5588},"Vue unifiée “DORA Metrics” sur Datadog pour un service en production - Change Lead Time","\u002Fcontent-assets\u002F2026-03-19-dora-metrics-x-datadog-piloter-sa-vlocit-sans-effort\u002Fassets\u002Fimg2.webp",[23,5590,5592],{"id":5591},"conclusion-la-donnée-plutôt-que-lopinion","Conclusion : La donnée plutôt que l'opinion",[19,5594,5595,5596,5603],{},"Si vous utilisez déjà Datadog, 90% du travail est fait. En ajoutant un label et une ligne de CI, vous passez du ressenti à une culture de la donnée automatisée. Bien sûr, des alternatives Open Source comme ",[91,5597,5600],{"href":5598,"rel":5599},"https:\u002F\u002Fdevlake.apache.org\u002Fdocs\u002FDORA\u002F",[95],[34,5601,5602],{},"Apache DevLake"," existent, mais l'unification native dans votre monitoring reste un atout majeur.",[19,5605,5606,5607,1513],{},"Cependant, la vélocité n'est que la moitié du chemin. Pour piloter sereinement, il nous reste à automatiser les deux piliers de la ",[34,5608,5609],{},"stabilité",[443,5611,5612,5618],{},[446,5613,5614,5617],{},[34,5615,5616],{},"Change Failure Rate (CFR)"," : Le ratio de déploiements qui partent en fumée.",[446,5619,5620,5623],{},[34,5621,5622],{},"Mean Time to Recovery (MTTR)"," : Votre réactivité face aux incidents.",[19,5625,5626,5627,5632],{},"On s'occupe de la stabilité dans un prochain article. Vous pouvez suivre HoppR sur ",[91,5628,5631],{"href":5629,"rel":5630},"https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fhopprtech\u002F",[95],"LinkedIn"," pour ne pas le rater !",[856,5634,5635],{},"html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":350,"searchDepth":364,"depth":364,"links":5637},[5638,5640,5641,5642,5643],{"id":5043,"depth":364,"text":5639},"1. Deployment Frequency : Le pouvoir du tag version",{"id":5377,"depth":364,"text":5378},{"id":5542,"depth":364,"text":5543},{"id":5572,"depth":364,"text":5573},{"id":5591,"depth":364,"text":5592},"2026-03-19T08:42:50.449Z","On ne va pas se mentir : dans les grands groupes, mesurer la performance DevOps ressemble souvent à un parcours du combattant entre Jira, GitHub et des fichiers Excel.   Pourtant, ce REX inspirant le ",{},"\u002Fblogs\u002F2026-03-19-dora-metrics-x-datadog-piloter-sa-vlocit-sans-effort",[5649],{"id":1577,"name":1578,"image":5650,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466X47CA4QS%2F20260319%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260319T084250Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEE8aCXVzLXdlc3QtMiJHMEUCIQCKU6Iu4QpzsQ2tkRUQBOxFfiOZ4HfQkLEgTKfy%2FJWHoAIgPyga683FjSbPQ2GsppWTNVeSFB4ssAGCCzeS8CLQaMQq%2FwMIGBAAGgw2Mzc0MjMxODM4MDUiDOj2R60cHgGnBqhLcyrcA1pBK91%2FC7sxxYBr6Wlx6GzaRwJFbRV6CdRh0IvpOOkR64ATl3S0ydVCC0tFBxdKj8IqC7gm2rDoEBsRqWjFBHumSXbND9n5u2iSwJxpHgltOp1oPaZBPaKvcGSk8fKNNiJfDShAK0I5pcFcnSu9XFGDuC4qD2plWYVGwRX5updAe3Ik70Nt6Zw3JnmMdjva5%2FmliVY3ddR5m9%2B%2BkxZ9E1u8oqcsZsazmwIiyyrIyH1peO5bIophiHoBcUUOQh0B904T0GdwsoOpC2t9azffF12oIMB4EUJLntX%2BbfCgC%2FagZ8%2FYocGXhyIuBQrih2PPYz4snhS%2BdGu9Tq6QCdHV0pEZh3aTD5UWYIwl9QJWuhpeQXFFlIfNT88e8bgM71LnExaJ0XuNbI8d9rY6a0ok93CV5m%2BDEFLO847dOF7xFerJfXJUgl915TPZhkTguqcH2mc0okDbS3bm3ZFZ16zS0Fdy%2FkINyFv%2FMT27RyZfw2gh2U4ZJVOyofMeoJFj1ZtAXGDatgXRWqmCBuJ%2BHIbbb34I7SN3INyNPwNKxN3BMHWv5RB9Lz8gUUlRlQs06ji9ftTwyN%2BqYbgc25C0mFwYYRYLpT3RvjS4oVywFZ7i4pRn6cHwD3axgT6YsZs%2FMLe%2B7s0GOqUBxHzCa69PV%2BECGw59UfrQfLPXebPFMilfk4LXejsM%2FjExDGVpQwuSFdRQLfRuhkIzNmri9OkFS1tU92R6XjdAoQKZmqR%2Ftkovwr0NYyr%2BpecdISq63hJNOdN6HrK%2BUAVo%2FOktZRT882GA1mvZy73vJiu5pz6fIgMwcoM%2BobZPHmN70C0Gr9ahS9nU5lKzBlqp1qLa3WIfgQUEmrUN5K9J31dPUk2O&X-Amz-Signature=f22395593221d95ab37a04634f21a51e049d9037209df11b04d9896a6efbfc12&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":5013,"description":5645},"blogs\u002F2026-03-19-dora-metrics-x-datadog-piloter-sa-vlocit-sans-effort\u002Findex",[5654,5008,5655,1591,906],"dora metrics","plateform engineering","vYAaAu_DYpkvlMSXsS8tVt4Iq710wPn4JQ8G1g-mj_k",{"id":5658,"title":5659,"alt":5660,"authors":5661,"body":5663,"date":5795,"description":5796,"extension":890,"image":891,"meta":5797,"navigation":893,"ogImage":891,"path":5798,"published":893,"reviewers":5799,"seo":5802,"stem":5803,"tags":5804,"__hash__":5805},"blogs\u002Fblogs\u002F2026-02-03-le-manifeste-du-platform-craftsmanship-lengagement-hoppr\u002Findex.md","Le Manifeste du Platform Craftsmanship : L'engagement HoppR","Platform Craftsmanship Manifesto par HoppR - L'alliance de l'artisanat et du Cloud DevOps",[5662],{"id":5017,"name":5018,"image":5019,"linkedin":5020,"x":901},{"type":16,"value":5664,"toc":5788},[5665,5675,5681,5684,5688,5693,5700,5708,5712,5717,5720,5730,5734,5739,5742,5756,5760,5765,5768,5775,5777,5781],[19,5666,5667,5668,5671,5672,5674],{},"Dans le monde du développement, le ",[1620,5669,5670],{},"Software Craftsmanship"," a rappelé que le code n'est pas une simple commodité, mais un artisanat. Chez ",[34,5673,1836],{},", nous pensons qu'il est temps d'appliquer cette même exigence à l'infrastructure.",[19,5676,5381,5677,5680],{},[34,5678,5679],{},"Platform Engineering"," ne doit pas être une usine à gaz technique, mais un ouvrage d'art au service de ceux qui créent la valeur : les équipes de développement.",[19,5682,5683],{},"Voici les quatre piliers de notre manifeste.",[23,5685,5687],{"id":5686},"_1-lexpérience-au-delà-de-la-technique","1. L'expérience au-delà de la technique",[1003,5689,5690],{},[19,5691,5692],{},"Pas seulement des logiciels bien conçus, mais aussi des plateformes au service des équipes de développement.",[19,5694,5695,5696,5699],{},"Une infrastructure peut être techniquement parfaite mais inutilisable. L'équipe plateforme ne se contente pas de \"monter un cluster K8s\". Elle conçoit une ",[34,5697,5698],{},"Internal Developer Platform (IDP)"," pensée pour la fluidité et l'autonomie.",[443,5701,5702],{},[446,5703,5704,5707],{},[34,5705,5706],{},"La vision HoppR :"," Si une personne de l'équipe de développement doit ouvrir un ticket pour obtenir une base de données, la plateforme a échoué. Le Craftsmanship, c'est offrir le \"Self-Service\" sans sacrifier la sécurité.",[23,5709,5711],{"id":5710},"_2-la-vision-au-delà-de-la-livraison","2. La vision au-delà de la livraison",[1003,5713,5714],{},[19,5715,5716],{},"Pas seulement l’ajout constant de valeur, mais aussi une vision continue.",[19,5718,5719],{},"Livrer des fonctionnalités infra ne suffit pas si on avance à l'aveugle. Le Craftsmanship impose une transparence totale du système.",[443,5721,5722],{},[446,5723,5724,5726,5727,5729],{},[34,5725,5706],{}," Nous intégrons l’",[34,5728,5009],{}," nativement. Une plateforme \"Crafted\" est un système transparent et mesurable, où chaque décision est guidée par la donnée et alignée sur la stratégie long terme de l'entreprise.",[23,5731,5733],{"id":5732},"_3-la-responsabilité-au-delà-de-la-performance","3. La responsabilité au-delà de la performance",[1003,5735,5736],{},[19,5737,5738],{},"Pas seulement une communauté de professionnels, mais aussi des personnes responsables.",[19,5740,5741],{},"L'ingénierie plateforme moderne ne peut plus ignorer l'impact de son travail. L'équipe plateforme est responsable de son empreinte.",[443,5743,5744],{},[446,5745,5746,5748,5749,5751,5752,5755],{},[34,5747,5706],{}," Nous intégrons le ",[34,5750,794],{}," (contrôle des coûts) et le ",[34,5753,5754],{},"GreenOps"," (durabilité) dès la conception. Agir de manière responsable, c'est garantir que la plateforme est aussi efficiente pour le budget de l'entreprise que pour la planète.",[23,5757,5759],{"id":5758},"_4-le-sens-au-delà-de-la-tendance","4. Le sens au-delà de la tendance",[1003,5761,5762],{},[19,5763,5764],{},"Pas seulement des partenariats productifs, mais aussi une innovation porteuse de sens.",[19,5766,5767],{},"L'IA et les technologies émergentes sont partout, mais le Craftsmanship refuse le \"hype-driven development\".",[443,5769,5770],{},[446,5771,5772,5774],{},[34,5773,5706],{}," Nous utilisons l’IA comme un levier d’accélération et non comme un gadget. Innover avec sens, c'est choisir l'outil qui apporte un résultat concret, pas celui qui fait simplement parler sur LinkedIn.",[952,5776],{},[23,5778,5780],{"id":5779},"pourquoi-ce-manifeste-change-la-donne-pour-nos-clients","Pourquoi ce manifeste change la donne pour nos clients ?",[19,5782,5783,5784,5787],{},"En recherchant les éléments de gauche: la qualité, la valeur, le professionnalisme et le partenariat, nous avons réalisé que les éléments de droite: DevEx, Observabilité, FinOps, Innovation choisie, sont les véritables piliers de la réussite moderne.\nLe ",[34,5785,5786],{},"Platform Craftsmanship"," n'est pas qu'une philosophie ; c'est notre méthode de travail chez HoppR pour transformer votre infrastructure en un avantage compétitif durable.",{"title":350,"searchDepth":364,"depth":364,"links":5789},[5790,5791,5792,5793,5794],{"id":5686,"depth":364,"text":5687},{"id":5710,"depth":364,"text":5711},{"id":5732,"depth":364,"text":5733},{"id":5758,"depth":364,"text":5759},{"id":5779,"depth":364,"text":5780},"2026-02-03T11:10:29.021Z","Dans le monde du développement, le _Software Craftsmanship_ a rappelé que le code n'est pas une simple commodité, mais un artisanat. Chez **HoppR**, nous pensons qu'il est temps d'appliquer cette même",{},"\u002Fblogs\u002F2026-02-03-le-manifeste-du-platform-craftsmanship-lengagement-hoppr",[5800],{"id":1582,"name":1583,"image":5801,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466UOV6GZ74%2F20260203%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260203T111028Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEDMaCXVzLXdlc3QtMiJHMEUCIQD6Xyjo9rBgI%2BiSNB06ysaRWlEErYThlHdyupC4mg6OfwIgeNXezDDUaziy4g%2F8AJ24c4Uu0XH2LvdJI%2FDifqoDE5sqiAQI%2FP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDImm6RPPUAAURsSINyrcA5yvDNzDU25JinN6%2FCQ0N5f5pLF62qj6gCNdwKdSFNsFgZvPmi%2B5XmL3yRjR0YHUbqR8C%2FGSTnhvnNHLQeo3aSM9p5Y%2BA40LpF9ZmshckX4DpZThaH5MiaDl4S6XeGjBMqrnfQgSIBoPxbJxbdzXVu9GGQHxG5ZGiDXR3k%2FeRoFKG02CMxVBIeXnjcZrRExNaoh3bkl5edW1TggLVcOOlinHNG8nX2BGeTRD230AktYA0mfa%2FPb7K4zrE4W7xiv5MqOF3Sqf86hJIgDpJsm9nZkiRwR%2B45OOxp4VrB64L4D9lPKNBlRcaoLvlls2%2BBE5ONDWwYDeye3tbgGrl894pomySdjg%2BoCUPylDKExU2W4CaQXBLxBSO1ib2E2w5nlKUqLeaEuX%2B85Kp9QHpfCT7J5TrOJW96aT5kJf8mx1EaFzMD7XJ3YrYJbJ8Lq2Vwyf5C%2FWgoxnQLIjgv2IJpNhdHonnJooOPUbVQHXmKCjvxi3e%2F6xCL0tWsv2fJezKpr9Srt%2FFFH%2FjrBiVnxLR41yrkMcoKBBXfjF5qwPezkdSPvjwBeDG3YdZh0BRzEOpKjjl9QAYUFuQq7JdvmKV1tN%2Bl3sPvgGp87rug0GymKWAGT5IoyAa9LGY6EqbIgeMJiih8wGOqUBhj0Jgyltd2MkQOGI%2BPkpkl3EnVNkjxMFs5hzA7FfunDz3RMyq83%2BjRJBMRkguGb0%2FYNEK%2FzeeVARgjo%2FQIeQDSwqz5y1kMvQwnESP99TfcR%2BeFkbAB9ytqe26Lrz1Ngd2iVyANLEvo5sVw5rTrG6JjSG60McNLMPXS2FlwCtZZ2NRrnZj8AQbGPbdmeCFLfkO9FLKB%2FAgmEPSk%2BWurHfw7O8S0u9&X-Amz-Signature=be52c0a8f0df4d8ac737692d68ab0319fb85093713bb4b58bf60cfc58a95814c&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":5659,"description":5796},"blogs\u002F2026-02-03-le-manifeste-du-platform-craftsmanship-lengagement-hoppr\u002Findex",[5655,906,1879,1591],"gpC_Mg6MulH0mGD8IsrguZQezIcZ4y9hx-0N1N5hxLY",{"id":5807,"title":5808,"alt":5809,"authors":5810,"body":5818,"date":6261,"description":6262,"extension":890,"image":891,"meta":6263,"navigation":893,"ogImage":891,"path":6264,"published":893,"reviewers":6265,"seo":6268,"stem":6269,"tags":6270,"__hash__":6272},"blogs\u002Fblogs\u002F2026-01-14-devbox-ou-comment-enfin-onboarder-un-dev-en-5min-chrono-sur-son-projet\u002Findex.md","Devbox, ou comment (enfin) onboarder un dev en 5min chrono sur son projet","Caisse à outils futuriste \"DEVBOX\" d'où émanent des outils virtuels et des logos de langages de programmation, posée sur un établi technologique avec un cube Docker lumineux.",[5811,5812,5817],{"id":5017,"name":5018,"image":5019,"linkedin":5020,"x":901},{"id":5813,"name":5814,"image":5815,"linkedin":5816,"x":901},"70a8663a-742d-4937-a6d4-5cef079b12c8","Théo Lanord",".\u002Fassets\u002Fauthor-tho-lanord.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fth%C3%A9o-lanord\u002F",{"id":10,"name":11,"image":12,"linkedin":13,"x":14},{"type":16,"value":5819,"toc":6250},[5820,5825,5828,5831,5837,5842,5859,5862,5865,5879,5883,5893,5896,5902,5912,5938,5941,5955,5959,5962,5965,5986,5989,5993,5996,6009,6013,6016,6037,6041,6044,6056,6059,6066,6069,6077,6081,6084,6087,6119,6125,6128,6131,6137,6179,6182,6240,6244,6247],[19,5821,5822],{},[34,5823,5824],{},"Le scénario est un classique du film d'horreur en entreprise.",[19,5826,5827],{},"C'est le \"Day 1\" d'un nouveau développeur. Il est motivé, son café est chaud, sa machine est prête. On lui donne l'accès au repo. Il clone. Il lance le projet.",[19,5829,5830],{},"Et là, le drame :",[19,5832,5833,5834],{},"🔴 ",[1620,5835,5836],{},"Error: Node version 18.x required (found 14.x).",[19,5838,5833,5839],{},[1620,5840,5841],{},"Error: libssl.so.1.1: cannot open shared object file.",[19,5843,5844,5845,5848,5849,504,5852,504,5855,5858],{},"S'ensuivent deux jours de \"bricolage\". On modifie le ",[352,5846,5847],{},".zshrc",", on installe ",[352,5850,5851],{},"nvm",[352,5853,5854],{},"jenv",[352,5856,5857],{},"pyenv",", on casse la config d'un autre projet... Le fameux \"purgatoire de l'environnement local\".",[19,5860,5861],{},"L'onboarding ne devrait pas être une cérémonie mystique. En 2026 ça devrait être un simple script. Surtout si l’on rapporte cela à l’échelle du nombre de développeurs et consultants avec une moyenne (ambitieuse) de 2 ou 3 jours à chaque démarrage. Que de temps perdu !",[19,5863,5864],{},"Et si le fichier de configuration de votre projet suffisait à installer tous les outils, sans la lourdeur de Docker ?",[19,5866,5867,5868,2756,5875,5878],{},"C'est la promesse de ",[91,5869,5872],{"href":5870,"rel":5871},"https:\u002F\u002Fwww.jetify.com\u002Fdevbox",[95],[34,5873,5874],{},"DevBox",[34,5876,5877],{},": une boîte à outils en ligne de commande qui transforme un simple fichier de configuration en un environnement de développement complet, isolé et natif.","  Lancé en 2022 par l'entreprise Jetify, le projet open-source connaît une adoption rapide et cumule déjà plus de 11K étoiles sur GitHub.",[23,5880,5882],{"id":5881},"devbox-la-puissance-de-nix-sans-la-douleur","DevBox : La puissance de Nix, sans la douleur",[19,5884,5885,5886,44],{},"Pour comprendre l'intérêt de DevBox, il faut d'abord saluer le moteur qui tourne en dessous : ",[91,5887,5890],{"href":5888,"rel":5889},"https:\u002F\u002Fnixos.org\u002F",[95],[34,5891,5892],{},"Nix",[19,5894,5895],{},"Nix est le Saint Graal de la gestion de paquets : il est purement fonctionnel, immuable et garantit qu'un paquet installé aujourd'hui sera identique au bit près dans 10 ans.",[19,5897,5898,5901],{},[34,5899,5900],{},"Le problème ?"," Nix est notoirement difficile à apprendre. Il demande de maîtriser un langage de configuration complexe et verbeux. C'est souvent un frein rédhibitoire pour les équipes qui veulent juste coder.",[19,5903,5904,5907,5908,5911],{},[34,5905,5906],{},"C'est là qu'intervient DevBox.","\nVoyez DevBox comme une \"télécommande simplifiée\" ou un ",[1620,5909,5910],{},"wrapper"," élégant.",[443,5913,5914,5924],{},[446,5915,5916,5919,5920,5923],{},[34,5917,5918],{},"Sans DevBox :"," Vous devez écrire des scripts ",[352,5921,5922],{},".nix"," cryptiques pour configurer votre environnement.",[446,5925,5926,5929,5930,5933,5934,5937],{},[34,5927,5928],{},"Avec DevBox :"," Vous remplissez un simple fichier ",[352,5931,5932],{},"devbox.json"," (aussi facile à lire qu'un ",[352,5935,5936],{},"package.json",") et l'outil se charge de \"parler\" à Nix pour vous.",[19,5939,5940],{},"Maintenant que la barrière technique est levée, quelle est la différence d'expérience par rapport à Docker ? Utilisons une analogie simple :",[443,5942,5943,5949],{},[446,5944,5945,5948],{},[34,5946,5947],{},"Docker, c'est l'hôtel."," C'est standardisé, isolé, sécurisé. Mais vous n'êtes pas chez vous. Les fichiers sont montés via des volumes (lent), le réseau est une couche supplémentaire. C'est parfait pour la Production.",[446,5950,5951,5954],{},[34,5952,5953],{},"DevBox, c'est la Réalité Augmentée."," Vous restez chez vous (votre terminal natif, votre OS). Mais quand vous enfilez les lunettes (quand vous lancez DevBox), les outils dont vous avez besoin apparaissent comme par magie. C'est natif, instantané, et ça disparaît quand vous les enlevez.",[23,5956,5958],{"id":5957},"la-preuve-par-lexemple-le-5-minutes-challenge","La Preuve par l'Exemple (Le \"5 Minutes Challenge\")",[19,5960,5961],{},"Assez de théorie. Prenons un cas concret qui parle à tout Tech.",[19,5963,5964],{},"Imaginez un projet Python un peu capricieux qui nécessite :",[443,5966,5967,5973,5979],{},[446,5968,5969,5972],{},[34,5970,5971],{},"Python 3.10"," (alors que votre système est en 3.12).",[446,5974,5975,5978],{},[34,5976,5977],{},"Poetry"," pour gérer les paquets.",[446,5980,5981,5982,5985],{},"Un client ",[34,5983,5984],{},"PostgreSQL"," spécifique.",[19,5987,5988],{},"Avec DevBox, voici à quoi ressemble l'installation :",[84,5990,5992],{"id":5991},"étape-1-création-du-contrat","Étape 1 : Création du contrat",[19,5994,5995],{},"Dans votre dossier projet, initialisez l'environnement.",[344,5997,5999],{"className":4519,"code":5998,"language":4521,"meta":350,"style":350},"devbox init\n",[352,6000,6001],{"__ignoreMap":350},[355,6002,6003,6006],{"class":357,"line":358},[355,6004,6005],{"class":2805},"devbox",[355,6007,6008],{"class":1138}," init\n",[84,6010,6012],{"id":6011},"étape-2-linstallation-isolée","Étape 2 : L'installation isolée",[19,6014,6015],{},"Ajoutez vos outils. DevBox va chercher les binaires pré-compilés (pas de compilation interminable).",[344,6017,6019],{"className":4519,"code":6018,"language":4521,"meta":350,"style":350},"devbox add python@3.10 poetry postgresql\n",[352,6020,6021],{"__ignoreMap":350},[355,6022,6023,6025,6028,6031,6034],{"class":357,"line":358},[355,6024,6005],{"class":2805},[355,6026,6027],{"class":1138}," add",[355,6029,6030],{"class":1138}," python@3.10",[355,6032,6033],{"class":1138}," poetry",[355,6035,6036],{"class":1138}," postgresql\n",[84,6038,6040],{"id":6039},"étape-3-lactivation","Étape 3 : L'activation",[19,6042,6043],{},"Entrez dans la matrice.",[344,6045,6047],{"className":4519,"code":6046,"language":4521,"meta":350,"style":350},"devbox shell\n",[352,6048,6049],{"__ignoreMap":350},[355,6050,6051,6053],{"class":357,"line":358},[355,6052,6005],{"class":2805},[355,6054,6055],{"class":1138}," shell\n",[19,6057,6058],{},"C'est fini.",[19,6060,6061,6062,6065],{},"Si vous tapez ",[352,6063,6064],{},"python --version",", le terminal vous répondra 3.10, même si votre système est pollué par d'autres versions.",[19,6067,6068],{},"Pour le nouveau développeur qui arrive, l'onboarding se résume désormais à deux commandes :",[19,6070,6071,508,6074,44],{},[352,6072,6073],{},"git clone",[352,6075,6076],{},"devbox shell",[23,6078,6080],{"id":6079},"sous-le-capot-pourquoi-cest-fiable","Sous le capot : Pourquoi c'est fiable ?",[19,6082,6083],{},"Je sais ce que vous pensez : \"Encore un wrapper node qui va casser mon PATH ?\"",[19,6085,6086],{},"Non. DevBox est une interface accessible pour Nix, l'un des gestionnaire de paquets les plus robustes.",[443,6088,6089,6103,6113],{},[446,6090,6091,6094,6095,6098,6099,6102],{},[34,6092,6093],{},"Le Store Immuable :"," DevBox n'installe rien dans ",[352,6096,6097],{},"\u002Fusr\u002Fbin",". Tout va dans ",[352,6100,6101],{},"\u002Fnix\u002Fstore",", en lecture seule. Vous pouvez avoir 10 versions de Node.js côte à côte, elles ne se connaissent pas.",[446,6104,6105,6108,6109,6112],{},[34,6106,6107],{},"L'illusion du Shell :"," Quand vous lancez le shell, DevBox modifie temporairement votre ",[352,6110,6111],{},"PATH"," pour pointer vers ces versions isolées.",[446,6114,6115,6118],{},[34,6116,6117],{},"Le Cache Mutualisé :"," C'est là que DevBox brille. Si vous avez cinq projets en Node 18, DevBox ne le télécharge qu'une seule fois. Contrairement à Docker qui réinstalle l'OS à chaque image, DevBox partage les binaires communs. Gain de place, gain de temps.",[23,6120,6122],{"id":6121},"docker-devbox-le-bon-outil-au-bon-endroit",[34,6123,6124],{},"Docker & DevBox : Le bon outil au bon endroit",[19,6126,6127],{},"DevBox et Docker ne sont pas concurrents. Ce sont deux couches différentes de votre stack. Voyez DevBox comme votre Boîte à Outils ultime (Toolbox). Son rôle est de préparer votre établi. Elle vous apporte les langages (Python, Go) et les clients (CLI) nécessaires pour travailler.",[19,6129,6130],{},"Et devinez quoi ? Parmi ces outils, DevBox peut parfaitement installer et configurer... Docker ou Kubernetes.",[19,6132,6133,6136],{},[34,6134,6135],{},"Le scénario idéal pour simuler la Production :"," vous voulez reproduire un environnement de production complexe (Microservices sur K8s) ?",[6138,6139,6140,6161,6170],"ol",{},[446,6141,6142,6144,6145,714,6148,504,6151,504,6154,504,6157,6160],{},[34,6143,5874],{}," installe les ",[1620,6146,6147],{},"commandes",[352,6149,6150],{},"kubectl",[352,6152,6153],{},"helm",[352,6155,6156],{},"terraform",[352,6158,6159],{},"aws-cli"," (dans les versions exactes de la prod).",[446,6162,6163,6165,6166,6169],{},[34,6164,5874],{}," lance les ",[1620,6167,6168],{},"scripts"," : Il configure l'accès à votre cluster local.",[446,6171,6172,6175,6176,6178],{},[34,6173,6174],{},"Docker\u002FK8s"," exécutent les ",[1620,6177,1116],{}," : Ils font tourner les bases de données et les conteneurs applicatifs.",[19,6180,6181],{},"DevBox est le chef d'orchestre, Docker est l'un des instruments.",[187,6183,6184,6197],{},[190,6185,6186],{},[193,6187,6188,6191,6194],{},[196,6189,6190],{},"Rôle",[196,6192,6193],{},"DevBox (La Boîte à Outils)",[196,6195,6196],{},"Docker \u002F Kubernetes (L'Infrastructure)",[208,6198,6199,6207,6218,6229],{},[193,6200,6201,6203,6205],{},[213,6202,6190],{},[213,6204,6193],{},[213,6206,6196],{},[193,6208,6209,6212,6215],{},[213,6210,6211],{},"Mission",[213,6213,6214],{},"Gérer l'outillage.  S'assurer que le développeur a les bonnes clés à molette.",[213,6216,6217],{},"Exécuter les services.  Faire tourner les briques logicielles lourdes.",[193,6219,6220,6223,6226],{},[213,6221,6222],{},"Ce qu'il contient",[213,6224,6225],{},"Compilateurs (Go, Rust), Interpréteurs (Node, Python), CLI ( docker ,  kubectl ,  terraform ).",[213,6227,6228],{},"Bases de données (Postgres, Redis), Message Brokers (Kafka), Applications conteneurisées.",[193,6230,6231,6234,6237],{},[213,6232,6233],{},"Philosophie",[213,6235,6236],{},"\"Je prépare ton environnement de travail.\"",[213,6238,6239],{},"\"Je simule ton environnement de production.\"",[23,6241,6243],{"id":6242},"conclusion-un-json-to-run-them-all","Conclusion :  un JSON to run them All",[19,6245,6246],{},"L'infrastructure-as-code a révolutionné la production. Il est temps qu'elle révolutionne l'onboarding. Vos équipes ne devraient pas perdre de temps à configurer des outils. Elles devraient mettre leur énergie sur les tâches où elles ont un maximum de valeurs.",[856,6248,6249],{},"html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":350,"searchDepth":364,"depth":364,"links":6251},[6252,6253,6258,6259,6260],{"id":5881,"depth":364,"text":5882},{"id":5957,"depth":364,"text":5958,"children":6254},[6255,6256,6257],{"id":5991,"depth":370,"text":5992},{"id":6011,"depth":370,"text":6012},{"id":6039,"depth":370,"text":6040},{"id":6079,"depth":364,"text":6080},{"id":6121,"depth":364,"text":6124},{"id":6242,"depth":364,"text":6243},"2026-01-14T14:07:08.940Z","**Le scénario est un classique du film d'horreur en entreprise.**  C'est le \"Day 1\" d'un nouveau développeur. Il est motivé, son café est chaud, sa machine est prête. On lui donne l'accès au repo. Il ",{},"\u002Fblogs\u002F2026-01-14-devbox-ou-comment-enfin-onboarder-un-dev-en-5min-chrono-sur-son-projet",[6266],{"id":1577,"name":1578,"image":6267,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466WN3QLNCE%2F20260114%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260114T140708Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEFYaCXVzLXdlc3QtMiJHMEUCIFD3v6TLnk5GmyhshqA5BlfwHhBJHcTihKFMH1xh8FAAAiEA6B%2F6vytfoyOMPoOmMOnmMsfzWqvIbVIVyk9SxRBOb5Uq%2FwMIHxAAGgw2Mzc0MjMxODM4MDUiDL6nPHU6OObivJIC6yrcAw%2BGMSR0gWkd909KwYy29%2BOOtd07YmkbUBPfyKQy5r44ubZUvnyvSe0bsnZlS%2BiruXV%2BAGH1i6YY8%2FfO0eW3%2F6bHTqgYg4jmlDqi3uQUyvSa%2B9ROYDaQonWsR1xQGJFRh3Q0FO67nIAv%2FDdPhejHVyc3bu5Yw6WNUkEb8av9H113ExC32mV6U3wm1Glrfc4rYfmQRxxrI9tyYnqjb17BDGot7eqAk5vTw2WgEqj1yLJfwOvOc9Vuvj2TDCT6XHPDxcraBQrDGZdVPhGEWQVOha%2BX0ZXI4ITciElRdlYY%2B4Xxf56q8ql1BFwBeWrjA7zO89T1ldzL4DYM6VVsTI%2BVD8ynF7EoZSRQoDt3FBWNyq0c1mkW%2BJKMcE8sYeppX8dTMf2fLezwknNN0aLAHVZnK4XxoAraRFbu3BRS1JQYOiMEle%2FtcErTA3X1Ta1llKaHRPRxdhMXr5uxW5D9%2BLLE%2B32QkD41lsPHdo%2FOOIPaaf8nG6mGZ6ZBUZnwpIjT8dntPtp3pI2c8d7f7VkQvVivaHWIc72JqjEavGmr4f01RxRFzPXzBA2c5Of4DJfXt3ZzRfhvCzATG5HpgWu5GVBFuYViCkRLytXHpet%2BTTZFhl5dlnBcBH%2Bnqkyy%2FJoJMJy%2FnssGOqUBaV15zB5j5%2BzO0TjePo5cVh5oNvLqVlrJGOL%2BiCjTFmTh%2Bq9TqZAWqhBDL%2Fow4sOiBPVNznBM5914QXUCD%2BT%2BryQHcsg5HeY2UQ6h1yy0DP4ktlenXm4U%2BcfXro6crhACbchkrLUpf2qANNrGa2I1SHj2%2F0yVPzquFLuh52qN6R9WsGQToQ9%2FlG3dzMlsgTMwiceoH4DcDiVxprDPl%2BIIjFNGb2lK&X-Amz-Signature=ba45c2556cf07a2dee7a1066cc21084b7f2a43679687bbef04b8c401bf1a63e5&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":5808,"description":6262},"blogs\u002F2026-01-14-devbox-ou-comment-enfin-onboarder-un-dev-en-5min-chrono-sur-son-projet\u002Findex",[1591,906,1879,6271],"veille tech","8FMs8rBbU5SfyDHKyjU0dSydcWohVaiLs6FQ28TlhKY",{"id":6274,"title":6275,"alt":6276,"authors":6277,"body":6284,"date":6589,"description":6590,"extension":890,"image":891,"meta":6591,"navigation":893,"ogImage":891,"path":6592,"published":893,"reviewers":6593,"seo":6602,"stem":6603,"tags":6604,"__hash__":6609},"blogs\u002Fblogs\u002F2025-12-23-alors-ctait-comment-ce-premier-devfest-lyon-la-suite\u002Findex.md","Alors ? C’était comment ce premier DevFest Lyon ? (la suite)","L’équipe HoppR au Devfest lyon",[6278,6279],{"id":10,"name":11,"image":12,"linkedin":13,"x":14},{"id":6280,"name":6281,"image":6282,"linkedin":6283,"x":901},"2c0f4462-cd38-80e0-8142-c3de50d521c1","Anaïs Cousin",".\u002Fassets\u002Fauthor-anas-cousin.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fana%C3%AFscousin\u002F",{"type":16,"value":6285,"toc":6577},[6286,6301,6307,6314,6320,6325,6330,6335,6341,6356,6363,6380,6386,6396,6399,6419,6422,6425,6428,6432,6439,6445,6448,6451,6463,6467,6470,6473,6483,6487,6490,6493,6497,6510,6513,6519,6525,6528,6535,6542,6555,6558,6561,6572],[19,6287,6288,6289,6294,6295,6300],{},"Pour faire suite à ",[91,6290,6293],{"href":6291,"rel":6292},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon",[95],"l’article de Michaël"," sur la très bonne première édition du ",[91,6296,6299],{"href":6297,"rel":6298},"https:\u002F\u002Fdevfest.gdglyon.com\u002F",[95],"DevFest Lyon",", nous vous présentons deux autres talks auxquels nous avons pu assister et qui nous ont marqué.",[23,6302,6304],{"id":6303},"chaos-monkey-et-si-netflix-révolutionnait-aussi-la-résilience-de-vos-applications",[34,6305,6306],{},"Chaos Monkey : et si Netflix révolutionnait aussi la résilience de vos applications ?",[19,6308,6309],{},[1620,6310,6311],{},[34,6312,6313],{},"Écrit par Anaïs",[19,6315,6316],{},[176,6317],{"alt":6318,"src":6319},"Illustration style synthwave aux néons violets montrant un singe holographique débranchant un câble serveur, ouvrant une faille numérique glitchée. Au premier plan, des ingénieurs surveillent calmement la situation, protégés par un bouclier énergétique bleu. Titre : CHAOS MONKEY.","\u002Fcontent-assets\u002F2025-12-23-alors-ctait-comment-ce-premier-devfest-lyon-la-suite\u002Fassets\u002Fimg1.webp",[19,6321,6322],{},[1620,6323,6324],{},"En ce début décembre 2025, impossible d’y échapper : la sortie de la saison 5 de Stranger Things fait vibrer les réseaux.",[19,6326,6327],{},[1620,6328,6329],{},"Mais saviez-vous que Netflix, en plus de captiver des millions de spectateurs, a aussi révolutionné la façon dont on teste la robustesse des applications ?",[19,6331,6332],{},[1620,6333,6334],{},"Rencontre avec le Chaos Monkey, un outil né dans les coulisses du géant du streaming, et qui pourrait bien sauver votre infrastructure du prochain “Démogorgon” technologique…",[84,6336,6338],{"id":6337},"quand-netflix-inspire-la-résilience-it",[34,6339,6340],{},"Quand Netflix inspire la résilience IT",[19,6342,6343,2756,6346,2756,6353],{},[34,6344,6345],{},"Lors du DevFest Lyon 2025,",[91,6347,6350],{"href":6348,"rel":6349},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Ferwan-le-tutour\u002F",[95],[34,6351,6352],{},"Erwan Le Tutour",[34,6354,6355],{},"a présenté le Chaos Engineering, une pratique inspirée de Netflix.",[19,6357,6358,6359,6362],{},"L’idée ? ",[34,6360,6361],{},"Provoquer des pannes contrôlées"," (coupures réseau, latences, arrêts de serveurs) pour détecter les faiblesses d’un système avant qu’elles ne deviennent critiques.",[19,6364,6365,6366,6369,6370,6373,6374,6379],{},"À l’origine, Netflix utilisait le ",[34,6367,6368],{},"Chaos Monkey",", un outil interne pour tester la résilience de son infrastructure de production face à des millions de requêtes. Aujourd’hui, des solutions comme le ",[34,6371,6372],{},"Chaos Monkey for Spring Boot"," permettent à tous les développeurs d’intégrer cette approche, en simulant des scénarios chaotiques pour renforcer leurs applications. (",[91,6375,6378],{"href":6376,"rel":6377},"https:\u002F\u002Fjavaoperatorsdk.io\u002Fdocs\u002F",[95],"Cliquez ici",", pour les curieux!)",[84,6381,6383],{"id":6382},"pourquoi-adopter-le-chaos-engineering",[34,6384,6385],{},"Pourquoi adopter le Chaos Engineering ?",[19,6387,6388,6389,6392,6393,44],{},"Les systèmes modernes sont de plus en plus complexes, distribués et interconnectés. Dans ce contexte, la question n’est plus ",[1620,6390,6391],{},"si"," une panne va survenir, mais ",[1620,6394,6395],{},"quand",[19,6397,6398],{},"Le Chaos Engineering permet de :",[443,6400,6401,6407,6413],{},[446,6402,6403,6406],{},[34,6404,6405],{},"Détecter les points de fragilité"," avant qu’ils n’impactent les utilisateurs.",[446,6408,6409,6412],{},[34,6410,6411],{},"Améliorer la réactivité"," des équipes en situation de crise.",[446,6414,6415,6418],{},[34,6416,6417],{},"Renforcer la confiance"," dans l’infrastructure, même face à l’inattendu.",[19,6420,6421],{},"Malheureusement personne n’est à l’abri, comme l’attestent les événements récents (AWS\u002FCloudfare)",[19,6423,6424],{},"Alors, prêt à lâcher un Chaos Monkey dans votre environnement pour en tester la solidité ? 🐒💥",[19,6426,6427],{},"Pour conclure cet article : bien moins technique que l’excellent article de Michael (et que celui qui arrive juste après !), ce retour reflète surtout mon regard côté business. Même si je ne suis pas développeuse, c’est justement ce genre de conférences qui me permet de mieux comprendre les enjeux tech du quotidien de mes collègues.",[23,6429,6431],{"id":6430},"développer-un-opérateur-kubernetes-en-java-challenge-accepted","Développer un opérateur Kubernetes en Java : Challenge Accepted !",[19,6433,6434],{},[1620,6435,6436],{},[34,6437,6438],{},"Écrit par Maxime",[19,6440,6441],{},[176,6442],{"alt":6443,"src":6444},"Illustration isométrique style tech-fantasy. Une développeuse injecte une énergie lumineuse orange, générée par du code Java et Quarkus, dans une machine Kubernetes géante en forme de gouvernail qui organise des conteneurs logiciels. Au sol, un panneau 'GO LANGUAGE ONLY ZONE' est brisé. Le titre en haut indique : 'JAVA OPERATOR: CHALLENGE ACCEPTED","\u002Fcontent-assets\u002F2025-12-23-alors-ctait-comment-ce-premier-devfest-lyon-la-suite\u002Fassets\u002Fimg2.webp",[19,6446,6447],{},"Si vous travaillez dans l'écosystème Cloud Native, vous avez forcément ressenti cette pression implicite : pour faire du Kubernetes sérieusement, il faut faire du Go. C'est le langage de l'orchestrateur, c'est le langage de la plupart des outils, et par extension, on finit par croire que c'est le seul choix viable pour étendre son cluster.",[19,6449,6450],{},"J'ai assisté à une conférence qui tord le cou à cette idée reçue, et je pense qu'elle mérite votre attention si votre équipe est majoritairement composée de développeurs Java.",[19,6452,6453,6454,504,6457,6462],{},"Dans son talk ",[34,6455,6456],{},"\"Développer un opérateur Kubernetes en Java, challenge accepted !\"",[91,6458,6461],{"href":6459,"rel":6460},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fphilippartstephane\u002F?originalSubdomain=fr",[95],"Stéphane Phillipart"," s'attaque à un sujet souvent intimidant : les Opérateurs.",[84,6464,6466],{"id":6465},"pourquoi-ce-talk-est-important","Pourquoi ce talk est important",[19,6468,6469],{},"Pour rappel, un opérateur est ce qui permet d'automatiser la gestion d'applications complexes dans Kubernetes. Jusqu'à récemment, la documentation et les exemples étaient quasi exclusivement en Go. Pour une équipe Java, cela voulait dire : apprendre un nouveau langage et une nouvelle toolchain juste pour écrire de l'outillage.",[19,6471,6472],{},"Ce que Stéphane démontre brillamment, c'est que cette barrière n'a plus lieu d'être.",[19,6474,6475,6476,6482],{},"Le cœur de sa présentation repose sur le ",[91,6477,6479],{"href":6376,"rel":6478},[95],[34,6480,6481],{},"Java Operator SDK",". Loin d'être une solution de bricolage, il montre que l'outillage est désormais mature. Ce que j'ai particulièrement apprécié dans sa démarche, c'est le pragmatisme. Il ne s'agit pas de faire du Java pour le plaisir de faire du Java, mais de capitaliser sur les compétences existantes des équipes. Pourquoi forcer des experts JVM à écrire du Go médiocre alors qu'ils pourraient écrire du code Java robuste et testable ?",[84,6484,6486],{"id":6485},"de-la-théorie-au-code","De la théorie au code",[19,6488,6489],{},"La conférence n'est pas qu'une suite de slides théoriques. On passe rapidement au concret avec du live coding. On y voit la création d'un opérateur, la gestion de la boucle de réconciliation (le cœur du réacteur de Kubernetes) et le déploiement.",[19,6491,6492],{},"Il aborde aussi implicitement un point qui fait souvent peur aux Ops : la lourdeur du Java. En combinant le SDK avec des frameworks modernes comme Quarkus (souvent utilisé pour la compilation native), on obtient des opérateurs légers, rapides au démarrage et peu gourmands en mémoire. L'argument de la performance du Go ne tient plus vraiment la route face au Java moderne.",[84,6494,6496],{"id":6495},"mon-avis","Mon avis",[19,6498,6499,6500,6505,6509],{},"Si vous êtes un développeur ou développeuse Java et que vous regardez Kubernetes comme une boîte noire réservée aux Ops ou aux développeurs Go, prenez une heure pour regarder ce talk disponible sur ",[91,6501,6504],{"href":6502,"rel":6503},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=1GUvH3zDsDA&pp=ygVDRMOpdmVsb3BwZXIgdW4gb3DDqXJhdGV1ciBLdWJlcm5ldGVzIGVuIEphdmEgOiBDaGFsbGVuZ2UgQWNjZXB0ZWQgIQ%3D%3D",[95],"Y",[91,6506,6508],{"href":6502,"rel":6507},[95],"ouTube"," via d’autres conférences.",[19,6511,6512],{},"Il dédramatise complètement le développement système sur Kubernetes. C'est une excellente ressource pour convaincre votre CTO ou votre Lead Tech qu'il est possible d'industrialiser vos déploiements sans changer toute votre stack technique.",[23,6514,6516],{"id":6515},"en-conclusion-linnovation-se-partage-surtout-au-devfest-lyon",[34,6517,6518],{},"En conclusion : l’innovation se partage, surtout au DevFest Lyon !",[19,6520,6521,6522],{},"Notre participation à cette première édition du DevFest Lyon a été une véritable source d’inspiration. Entre le Chaos Engineering, qui nous rappelle que la résilience se construit en osant tester nos limites, et la démonstration que Java a toute sa place dans l’écosystème Kubernetes, ces conférences ont confirmé une chose : ",[34,6523,6524],{},"l’innovation naît souvent là où on ne l’attend pas.",[19,6526,6527],{},"Chez HoppR, nous sommes convaincus que partager ces retours d’expérience, ces outils et ces bonnes pratiques est essentiel pour faire progresser toute la communauté tech.  C’est pourquoi nous avons mis en place une véritable culture de l'apprentissage continu.",[19,6529,6530,6531,6534],{},"En interne, cela se traduit par nos ",[34,6532,6533],{},"Maker Days"," : des journées dédiées où nos consultant.es sortent de la production pour tester de nouvelles technos (comme ce fameux Chaos Monkey !), prototyper ou approfondir des concepts complexes. C'est notre laboratoire R&D, et c'est ce qui permet à nos équipes de rester à la pointe.",[19,6536,6537,6538,6541],{},"Mais nous sommes convaincus que le savoir ne doit pas rester cloisonné. Nous avons donc transformé ces retours d’expérience et cette expertise terrain en un ",[34,6539,6540],{},"catalogue de formations concret et pragmatique",". Que vous soyez une entreprise cherchant à faire monter vos équipes en compétences ou un développeur avide d'apprendre, nous partageons ce que nous maîtrisons au quotidien.",[19,6543,6544,6547,6548],{},[34,6545,6546],{},"➡️"," ",[91,6549,6552],{"href":6550,"rel":6551},"https:\u002F\u002Fwww.hoppr.tech\u002Fformations-hoppr",[95],[34,6553,6554],{},"Découvrez nos programmes de formation HoppR",[19,6556,6557],{},"Alors, prêt à libérer votre propre Chaos Monkey ou à développer votre premier opérateur Kubernetes en Java ?",[19,6559,6560],{},"N’hésitez pas à nous faire part de vos retours, de vos questions, ou à nous rejoindre pour en discuter lors de nos prochains événements !",[19,6562,6563,2756,6566,2756,6569],{},[1620,6564,6565],{},"Un grand merci à l’équipe du DevFest Lyon pour l’organisation de cet événement, et à tous",[1620,6567,6568],{},"les speakeuses",[1620,6570,6571],{},"et speakers pour leurs présentations inspirantes.",[19,6573,6574],{},[1620,6575,6576],{},"À l’année prochaine pour de nouvelles découvertes !",{"title":350,"searchDepth":364,"depth":364,"links":6578},[6579,6583,6588],{"id":6303,"depth":364,"text":6306,"children":6580},[6581,6582],{"id":6337,"depth":370,"text":6340},{"id":6382,"depth":370,"text":6385},{"id":6430,"depth":364,"text":6431,"children":6584},[6585,6586,6587],{"id":6465,"depth":370,"text":6466},{"id":6485,"depth":370,"text":6486},{"id":6495,"depth":370,"text":6496},{"id":6515,"depth":364,"text":6518},"2025-12-23T16:39:49.164Z","Pour faire suite à [l’article de Michaël](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon) sur la très bonne première édition du [DevFest Lyon](https:\u002F\u002Fdevfest.gdglyon.com\u002F)",{},"\u002Fblogs\u002F2025-12-23-alors-ctait-comment-ce-premier-devfest-lyon-la-suite",[6594,6596,6598,6600],{"id":5813,"name":5814,"image":6595,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466W4AXLVRW%2F20251223%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251223T163948Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEYaCXVzLXdlc3QtMiJIMEYCIQDPnpGUn%2BqCpnFIqIGXJYm%2FKun2CwO%2FbkU43MWV3kn4ugIhAKSC4Vj6uKRG%2FQsbi35ldAUoJu3J%2BfVrpYehzOrAiUNdKv8DCA8QABoMNjM3NDIzMTgzODA1IgxYOnhHP8q1QNPcr9kq3AMQKG7RZkAyakc0hW8rdOKKYFwnri04Ycy4M2kPAP1zxZ4OAygqjWbe5fUytfCr%2BvqFCtuuoAh%2FbrIdduFm7FspNBpBTD%2BtJ1U%2BsU0c4maBvii7Kazur7y0ZrkYDtKZBHlzsP6KVQEJkFjZM8MPFQ0IxZl8u6eXEX1ZYAzbb91vpaJyFhh8sWhIrxK1QYnSFhNdlyLgl5sc7vN1zipqTj%2BFModWCOhTUuK5lHOKbyHB4ErulD8RKgspA%2BHz1b1ePM4vmEDt5EzjW%2BbY%2FOqQJp%2BiT9gERS0fRhn%2BSmYSZcUyZw8FzLUU9AuZTL%2BxABNx4A0sPjzHfHEX08Ck66%2F0B%2BlE1Sj1qoJlCM2mQXR9RU1eK1BnHDGMYy41HASbHKLetFPo7zXFk2AW6RAgAiXbvvoAl8NKrqJ4tscKivfT8nremJsHxemWNDgZaPf2Holdx8LHwV7CqfZ9j%2FLTf4q2vsbSqKN5ctxe9evJFapDOjU%2B6fdlyLXYrd9Cgu0I7qTXQID2Wk51QMsMwdAkPkS2QTf2xYgjfWgfsbXtv5NBJIycrJL4rkwNRs03UUD3XgWyEQQ67F6fiTsm3GaXnKaCMrnXZCiwd6eXFE%2F9TTJqMvQRjcNh7TkiqdIMjHa%2FXDC8vqrKBjqkASyWZD3FD4b6CgVchADndQ37fY59BuPUOM8%2F83rNgyLCA%2FyItYB9bNyO%2FbGgmW6WbFlgmFdTlSAzP8t6u%2FDNfHvn2PTWp7FSjnRRK6FvFKQSQvIk%2B1EzEkJEYDg0%2BzmmUrSZsXbpKC77QuqQ0klW5aDR6GIu9P8Fti6rjXrRPRCeWDn9C4fz24VI%2FjrKLMnlgdyipLMinNsSvlyrdGnWWDN4K%2Fmz&X-Amz-Signature=4e276c2fda930baf8991e7206d80c6d9d9dcab8f47c8bfc8fbb35bd93848d9b0&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":1582,"name":1583,"image":6597,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4666XAIVRTN%2F20251223%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251223T163948Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEYaCXVzLXdlc3QtMiJGMEQCIEnuOAJUf2Rshe07mNIw0LrH9EpjYKRzEhhhnrv%2FiJL4AiBlBMKpY%2BOuKCkAtBj%2BuA5fIcjRdGBpguWngb9qHAq69ir%2FAwgPEAAaDDYzNzQyMzE4MzgwNSIM5Sf9fQcuCCRMo963KtwDVI0FP8okepoMVcy8fPdIC1JVqsKcYxvSllUIDvz3bVWZyIW0CCsx59p7dp3inN6GnbfUaJNtn9BElzJK9dBwcKzFutAx6xV8tE4s25a0VG1INlhJzwOGq%2FtE%2BGc3zl8WGZe2Mf4erdDFjsM20auMlhExfMB3fNlppYb%2Bs15wgKr%2BNmZzRN55ci65DlKR6OU6b%2F9n0NoODE5pGo1clLXMsbss5U51C1ROHUVJsZR6ZwY1Hqqwrq1Y722xXQzAetGDsdXGoFpiwmcWIJlEAldVpiCWgArYhi54vWNWjQVOgNjVsHl2gSl4dBoju%2FkNl3ijqRJlat0d3D1tVkAdsb2iRZiElHexwcVQlpx1qHeIXq0Rd5j0DQuvyAxj1ktuh92xWZNcM91W%2BfP2Gk3qNR1d0Olnw4i7R0rKQvEuDlDuWG6578afo7v1s125krKupL6nTUetdKU%2Fz3QXrmlrj7SZEXPhqZ%2FmvqLO7HFOOaFiFuqirixmhAW6Ha2pa5D5VHZKHsPVFT91xXNElJpOADSpSAhvZvcLjE94rK%2FF2NyvjxGS8lDyV7rS39WJ8VSq1A04RzYphSEYF3L21W2tBaGc5VIhyLpBB3V5YtrIHO6C3UwfwDPGb3MviRw8JxYwwb6qygY6pgG2MUSsukjvYCzXqgwgHF5KhJIkGs28W7phlzQm0icRuywpO2S%2BzHPuOOV9WIrq0hlzmQP5RkkImvr2533TECOiLPDi5t7k0SsXZ8q48g%2ByWx36uxniARZ7uhReOOjy1vYTRG6PhGEAffVnypy0YyJCo5zb8b0%2F%2F4fSj1OY3fvqxDa14rEJpgRHpvLQsMYtOA1JVm8RSta8mAivuf%2FFrabCN%2FfL4q%2FA&X-Amz-Signature=4a14b9fbd70617e2be2d0878b3392f914e0c912c875fe99c8fb653d2e132cb87&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":1577,"name":1578,"image":6599,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466TGENWUUW%2F20251223%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251223T163949Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEYaCXVzLXdlc3QtMiJHMEUCIQDdbYlpqTUS3MHKXr294zzRuZ5yQznmEEbKsUbTKHxKwwIgbaNEO5L%2BsbyYJWP%2BXSsrT6p%2BQ8JHG5pVRE67vmA2SQQq%2FwMIDxAAGgw2Mzc0MjMxODM4MDUiDHyZQznaVyJGBMnPMSrcA0AqnPpDZeHzIFm5ctGDLP6MMk9oxka5WD9HcgCfxZhpbpJZbrvuspt8g8kWPyEBYVMJvTO7SMJvEQysNwGHm%2BlX%2FEgaKTzcPATTKFxtom8WP4YyTOHAhXYmV1PU43kUU32KZXQfDXeglBzNR3Nn7xxx0ewP82r02pcSdwkyQamIQ%2FfcqRDZ2nVtKi1Ghl%2B3dJ07BjYVe3frTc%2FxwqQxG6w%2FTisKdoxeAkplW8GRC8l6K6nmLOjpD%2F4dDthsFKvqOXI6z8NO3AwEjYO2wf6DoJD28PLSPtgaPDCSCdLULjlmWZMMeEXLYkSx5I6YCRXvl30uzPsia2pxCwag352B8aTcMNE3cN2nqmTmBTXJvYkau%2Fp0PBBObSgbHWqB3rlxe0VV%2Bf5lrWQiILnkMviSOf1b00LcSqoX8VSwYJKJWikH3Awrr5FPMZnOq%2F%2Bqyxm58Ibxb83hZT6JKIl8rbSBRfN%2F7K01krEffQv1xu5DhA91VlC15uwvFFdxGIKAVi%2Bt5sZh%2BXoIhQdKCX0U1fQ%2BL9q6%2BRfzsT4eERWe655piTwoSQQYWMNoeJxImF3zMS1b4D%2FUbQLUtxR7w%2Bomf1r4X76m%2FB3VM6UAgJl76pfHcDEuVCgUDx2GyNC2uh4TMMK%2BqsoGOqUBRe1GhYU7oRbpaObDN69zVFXh9zQjmAm0804TLzpDIlGwFgPAydmy7uAcmDHynkOrYrpo0Y5ejB%2BkSddGXtGWMX0Cj40u7CcS6D37%2FYAMOIX0VfQOOPPnVnrkS%2FgTKzvD%2BaL4ZUXQ3ePH9ueM4VgxnVBwkz6aglCUz4u11Pw6SAUQIz69Wb2I5OqdCd1JZZADIlBO8y1jb8TYV8HqLOVgk1%2F2HZR9&X-Amz-Signature=d2dfeaa7ca1b4ff8a41b6ed6783f396a5513ed9173bf5e9026a3a283f6ab1e2c&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":897,"name":898,"image":6601,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466QHSO5NSN%2F20251223%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251223T163948Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEYaCXVzLXdlc3QtMiJIMEYCIQDZnNiqwJP6%2BrX28Xzb2IJ0%2BVzaXNFUsPrqaZ967PZU%2FAIhANKWFV8toBQHdFYmnBVpBY4jP3vcGA5lFDozIUegTgfPKv8DCA8QABoMNjM3NDIzMTgzODA1IgzOsYpSA9QgtStzyKwq3AO0cbAzyrq%2FgkP18Y5TYaN1DJ1%2BFkrZMK1xm%2FASjOCnPbi1LJ%2FH6%2FxIKnUv%2FvjGKTd%2F1j17x7%2FA1XLAFyuPUd6GAdq%2Bm8vIyOTBiFyMuiIkxu4aqACChZmQDqI2ZuR1t1IokTUq2gTo5%2BALvQREnMT%2BDPTHFQkOTrsUSiyoZr6Otv5VQQL6H8eRHzZrOA5XvB75Gm9rCI1HZiig7AhHrsQ%2F%2FLBcVEPKvj7l9Vy%2FlGQ3iby4BcvzTHPD6cdLiqpyz3951P9JJsB%2FLY7QGu8CNaVtajNVRG%2BuVBKGG9DQNmASGjQ1RyizEFZtq%2F2s%2FtaqWBbGnjep9ApfglIkqyP2NwFn5zsKZVMpuC7N586lYjrQxgXCXjZt5%2BMU2SAgLyJL7zK9XD75ylVTkjJw1YBcnKjj%2BFS3iW6NpKcS0b62gjVjxQ1XFFmo5B%2BWnQCpiHa5Yn3aXFLk%2BZd4mNEB6X28YtYAxOzI1KTFMKCAENTvevFyW3xet5JSqFD%2B1eOVaJSSZray6a4jyo7DxGJgM4s6qtWYzZ%2F1%2BIUMaaE1nHGcX%2Bu5e7cdPTn39ofxY4xbtB9dzP7dTbViLUzgD2gEF0QGHCuIWexj4OfzvdoL0sbh5TyJKy2B8GLvb1C1ujt4CTCtvqrKBjqkASM8jkG%2BtIFYSWk8zpbN06aWBful2xBsKkm%2F5SMLnIs%2FScsfD5Ruqrq1%2F8DigO%2FRod2MlWhKFp9DI%2B8ea9E9HltSm6z6zC4bAQei6ZShQ8hodi3Ymx8vAWaBRznJC%2FxYlBp%2FL5wamxFNqlynpFieFzeDeqsSVdvVc7Ws7GIWk7tkT1fF0auFTQpIXwQhrS1qo7N7msdyjg1APpk%2Bt4ahP60bBKN3&X-Amz-Signature=d020731e6a1b744c7006df2f027f9ab49a03c5bb0efdbb6d5d8760772cb23471&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":6275,"description":6590},"blogs\u002F2025-12-23-alors-ctait-comment-ce-premier-devfest-lyon-la-suite\u002Findex",[6605,6606,6607,6608,2794,906,6271],"kubernetes","devfest","événement","2025","3nvslMeLl3YYAQrpXzL9yuAthKCweU7Nz46T0ykRK1M",{"id":6611,"title":6612,"alt":6613,"authors":6614,"body":6616,"date":7057,"description":7058,"extension":890,"image":891,"meta":7059,"navigation":893,"ogImage":891,"path":7060,"published":893,"reviewers":7061,"seo":7070,"stem":7071,"tags":7072,"__hash__":7074},"blogs\u002Fblogs\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Findex.md","Alors ? C’était comment ce premier DevFest Lyon ?","L’équipe HoppR sur la scène du DevFest Lyon",[6615],{"id":1577,"name":1578,"image":1600,"linkedin":1580,"x":901},{"type":16,"value":6617,"toc":7050},[6618,6624,6637,6640,6646,6649,6652,6655,6659,6664,6667,6682,6691,6697,6700,6721,6727,6730,6733,6737,6742,6751,6776,6785,6788,6794,6797,6800,6815,6818,6845,6848,6862,6865,6869,6874,6883,6886,6889,6895,6898,6909,6912,6920,6924,6929,6938,6946,6949,6955,6958,6973,6986,6989,7014,7017,7020,7024,7027,7030,7041,7044,7047],[19,6619,6620,6621,44],{},"Une question que l’on me pose beaucoup en ce début de semaine. En effet, vendredi 28 novembre 2025, nous avons eu la chance, avec plusieurs collègues de HoppR, de faire partie des 250 participants de la première édition du ",[91,6622,6299],{"href":6297,"rel":6623},[95],[19,6625,6626,6627,508,6632,6636],{},"En effet, notre participation s’inscrit dans le cadre de la veille tech proposée, organisée et prise en charge par HoppR. C’est d’ailleurs comme cela que j’avais pu participer au Lyon Craft plus tôt cette année (et écrire deux articles sur ce blog, à retrouver ",[91,6628,6631],{"href":6629,"rel":6630},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2025-04-24-lyon-craft-2025-12",[95],"ici",[91,6633,6631],{"href":6634,"rel":6635},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2025-05-07-lyon-craft-2025-22",[95],").",[19,6638,6639],{},"Avant de rentrer dans le vif du sujet, nous sommes tous unanimes chez HoppR pour saluer l’organisation au poil de l’évènement. Nous avons toutes et tous été très bien accueillis, et nous avons passé un moment de qualité avec nombre d’acteurs importants de la scène tech lyonnaise.",[19,6641,6642],{},[176,6643],{"alt":6644,"src":6645},"Photo du programme de la journée, directement dans le badge nominatif délivré à l’accueil de l’évènement","\u002Fcontent-assets\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Fassets\u002Fimg1.webp",[19,6647,6648],{},"Nous voici donc arrivés à cette journée de conférences, réparties sur deux tracks, et donc des choix difficiles à faire tant les talks étaient prometteurs.",[19,6650,6651],{},"Beaucoup de thématiques étaient proposées : Data & IA, Frontend, Backend, Software Architecture, Cloud, Infra et DevOps, il y en avait pour tous les goûts. On notera cependant une forte présence de la première thématique : la datascience et les LLM ont la côte !",[19,6653,6654],{},"Je vous propose ici de vous (re)plonger dans celles auxquelles j’ai pu assister en cette froide matinée lyonnaise.",[23,6656,6658],{"id":6657},"keynote-datascience-for-performance","Keynote : Datascience for performance",[19,6660,6661],{},[1620,6662,6663],{},"Par Joseph MESTRALLET - Data & AI - 30 minutes",[19,6665,6666],{},"Après la traditionnelle ouverture par le staff devant une salle pleine, avec remerciement des sponsors et rappels de l’organisation, Joseph prend la parole pour une keynote surprise.",[19,6668,6669,6670,6675,6676,6681],{},"Son CV est impressionnant : il accompagne certains des plus grands champions, comme ",[91,6671,6674],{"href":6672,"rel":6673},"https:\u002F\u002Fwww.equipedefrance.com\u002Fathlete\u002Fquentin-fillon-maillet",[95],"Quentin Fillon Maillet"," (5 médailles de biathlon aux JO de Pékin 2022, dont 2 en or) ou ",[91,6677,6680],{"href":6678,"rel":6679},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FRuth_Croft",[95],"Ruth Croft"," (vainqueure de l’Ultra-Trail du Mont-Blanc 2025). Et comment fait-il pour aider ces grands champions ? Par la data, par la science, par la datascience !",[19,6683,6684,6685,6690],{},"Joseph nous fait un petit historique des liens entre sport de haut niveau et science, de l’amélioration des photos finish à l’exploit du ",[91,6686,6689],{"href":6687,"rel":6688},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FIneos_1:59_Challenge",[95],"marathon en moins de 2h de Kipchoge",". La densification des performances au plus haut niveau a nécessité une nouvelle approche basée sur la science et la data, pour gagner encore les quelques secondes, les quelques centimètres qui font la différence entre un champion olympique et les finalistes qui resteront inconnus du grand public.",[19,6692,6693],{},[176,6694],{"alt":6695,"src":6696},"Ruth Croft à l’arrivée de l’UTMB en 2025","\u002Fcontent-assets\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Fassets\u002Fimg2.webp",[19,6698,6699],{},"Mais revenons au travail de Joseph, qui nous parle de quatre niveaux de datas, toujours plus précis:",[443,6701,6702,6705,6708,6715],{},[446,6703,6704],{},"Les données issues de la littérature",[446,6706,6707],{},"Les données personnalisées, via des applications de suivi comme Strava par exemple",[446,6709,5381,6710],{},[91,6711,6714],{"href":6712,"rel":6713},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FR%C3%A9glage_fin",[95],"fine tuning",[446,6716,6717,6718],{},"Le compute, pour trouver les meilleures conditions pour une course via un ",[1620,6719,6720],{},"digital twin",[19,6722,6723,6724,6726],{},"Cette notion de ",[1620,6725,6720],{}," revient souvent : il s’agit d’un avatar numérique de l’athlète, que l’on fait participer virtuellement des centaines de fois à la prochaine course, avec des paramètres différents, pour trouver la meilleure stratégie à adopter.",[19,6728,6729],{},"Joseph nous parle également de son quotidien aux côtés des athlètes. Ceux-ci doivent être très impliqués au quotidien pour obtenir de la data de la meilleure qualité possible. A l’inverse, une grande confiance avec lui doit être construite, il s’est donc lui aussi mis à la course à pied de manière intensive pour gagner de la connaissance du terrain et de la légitimité.",[19,6731,6732],{},"Le speaker, visiblement passionné, égraine les anecdotes de ses championnes et champions, et montre à quel point ce travail de performance demande une communication et une proximité forte entre le scientifique et les sportifs.",[23,6734,6736],{"id":6735},"démêler-vrais-produits-et-hallucinations-rex-dun-agent-téléphonique-chercheur-de-chaussettes","Démêler vrais produits et hallucinations, REX d’un agent téléphonique chercheur de chaussettes",[19,6738,6739],{},[1620,6740,6741],{},"Par Marie TERRIER - Data & AI - 50 minutes",[19,6743,6744,6745,6750],{},"Marie est CTO d’une ",[91,6746,6749],{"href":6747,"rel":6748},"https:\u002F\u002Fwww.yelda.ai\u002F",[95],"start-up"," proposant un SaaS d’agent vocaux. Cette société a proposé des solutions avant l’avènement des LLMs, et a suivi celui-ci pour présenter des solutions plus performantes. Ainsi, nous faisons un tour de l’historique :",[443,6752,6753,6770,6773],{},[446,6754,6755,6756,6763,6767,6769],{},"2017 : Le Machine Learning existe déjà depuis longtemps, mais les LLMs n’en sont qu’à leurs balbutiements. L’agent vocal est alors basé sur du ",[91,6757,6760],{"href":6758,"rel":6759},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FTraitement_automatique_des_langues",[95],[1620,6761,6762],{},"natural language processing",[91,6764,6766],{"href":6758,"rel":6765},[95]," (NLP)",[1620,6768,44],{}," On essaie de déterminer l’intention du client au bout du fil, et de proposer une réponse pré-généré en fonction. Et si on y parvient pas, alors on demande à l’utilisateur de répéter. Un bon début, mais ce n’est pas très pratique.",[446,6771,6772],{},"2022 : Les LLMs sont utilisés pour ces cas de questions inattendues, et permettent donc de combler le besoin. La fin de l’histoire ?",[446,6774,6775],{},"Fin 2023 : Une nouvelle commande arrive, avec pour problématique la suivante : l’IA peut elle aider les pharmaciens à commander des produits par téléphone ?",[19,6777,6778,6779,6784],{},"A priori, rien de bien sorcier maintenant que nous avons des outils adaptés et efficaces. Mais finalement, c’est la douche froide. Une liste de 40 produits seront proposés, et ceux-ci posent de nombreux problèmes : nous avons ici affaire avec du franglais, sans aucun standard, avec des notions complexes et difficilement transcriptibles comme le ",[91,6780,6783],{"href":6781,"rel":6782},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FMillim%C3%A8tre_de_mercure",[95],"mmHg"," par exemple.",[19,6786,6787],{},"Difficile ainsi de trouver la bonne paire de chaussettes ou de bas de contention à commander…",[19,6789,6790],{},[176,6791],{"alt":6792,"src":6793},"Marie nous présente un échantillon de la liste des 40 produits qui seront disponibles à l’achat. On comprend tout de suite la problématique.","\u002Fcontent-assets\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Fassets\u002Fimg3.webp",[19,6795,6796],{},"De plus, les pharmaciens ne connaissent pas le nom complet de chaque produit, il est donc nécessaire de poser des questions pour être sûrs de comprendre, tout en étant rapide étant donné que nous sommes au téléphone. Le service existant alors est inadapté, tout est trop long, et le LLM pose trop de questions pour arriver au produit désiré.",[19,6798,6799],{},"La solution passe par des sous-agents, qui permettent d’avoir plus de pertinence dans les questions posées tout en étant plus rapide. C’est donc parfait ! Enfin jusqu’à ce que le catalogue passe de 40 à 20000 références dont certaines en allemand…",[19,6801,6802,6803,6808,6809,6814],{},"Nous sommes en 2023, et les LLMs disposent encore de limites, comme de petites ",[91,6804,6807],{"href":6805,"rel":6806},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FFen%C3%AAtre_de_contexte",[95],"fenêtres de contexte"," (8000 tokens puis le modèle “oublie”), une latence trop importante (difficile d’attendre 30s au téléphone) et des ",[91,6810,6813],{"href":6811,"rel":6812},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FHallucination_(intelligence_artificielle)",[95],"hallucinations"," fréquentes.",[19,6816,6817],{},"Plusieurs essais sont donc effectués :",[443,6819,6820,6828,6837],{},[446,6821,6822,6827],{},[91,6823,6826],{"href":6824,"rel":6825},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FG%C3%A9n%C3%A9ration_%C3%A0_enrichissement_contextuel",[95],"RAG"," et prompt dynamique, un bon début mais toujours trop lent et ne gère que 80 produits max lors des tests",[446,6829,6830,6831,6836],{},"Une ",[91,6832,6835],{"href":6833,"rel":6834},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FBase_de_donn%C3%A9es_vectorielle",[95],"base de données vectorielle",", mais beaucoup de produits ont des noms trop proches sémantiquement, et chaque requête donne trop de retours",[446,6838,6839,6844],{},[91,6840,6843],{"href":6841,"rel":6842},"https:\u002F\u002Fwww.algolia.com\u002Ffr",[95],"Algolia",", un moteur de recherche boosté à l’IA, qui donne de bons résultats",[19,6846,6847],{},"La solution se construit alors avec plusieurs briques comme ceci :",[443,6849,6850,6853,6856,6859],{},[446,6851,6852],{},"LLM extracteur, qui fournit un nom de produit partiel",[446,6854,6855],{},"Algolia, permettant d’effectuer la recherche",[446,6857,6858],{},"LLM conversationnel",[446,6860,6861],{},"LLM évaluateur",[19,6863,6864],{},"Ainsi, Marie et son équipe ont pu proposer à leur client un outil répondant pleinement au besoin : celui de permettre à des pharmaciens de commander des produits… dont les fameuses chaussettes du titre !",[23,6866,6868],{"id":6867},"lets-play-factorio","Let’s play Factorio",[19,6870,6871],{},[1620,6872,6873],{},"Par Julien WITTOUCK - Software Architecture - 50 minutes",[19,6875,6876,6877,6882],{},"Julien est un grand fan du jeu ",[91,6878,6881],{"href":6879,"rel":6880},"https:\u002F\u002Ffactorio.com\u002F",[95],"Factorio",". Ce jeu bac-à-sable consiste à construire et gérer une usine permettant d’exploiter des ressources afin de s’échapper de la planète. Tout le plaisir du jeu et d’agrandir et d’optimiser chaque extraction et production.",[19,6884,6885],{},"Le jeu permet, à l’instar de Minecraft, une grande liberté dans sa construction, y compris en utilisant de la logique permettant même de coder dans Factorio.",[19,6887,6888],{},"Julien se propose ici de nous illustrer de nombreux concepts que l’on peut trouver dans nos projets professionnels.",[19,6890,6891],{},[176,6892],{"alt":6893,"src":6894},"Le logo du jeu Factorio","\u002Fcontent-assets\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Fassets\u002Fimg4.webp",[19,6896,6897],{},"Voici les concepts abordés :",[443,6899,6900,6903,6906],{},[446,6901,6902],{},"Développement (Plat de spaghettis, Architecture en couches, Micro-services..)",[446,6904,6905],{},"Urbanisation (ESB, Scaling Vertical\u002FHorizontal)",[446,6907,6908],{},"Sécurité (Métriques & monitoring, DDoS, Firewalls…)",[19,6910,6911],{},"L’exécution est impressionnante, et tous les concepts sont expliqués de manière visuelle et claire. Parfait pour présenter notre travail de tous les jours à des personnes non-tech ! Et il aura fallu plus de 100h pour préparer ce talk original.",[19,6913,6914,6915,44],{},"Si vous souhaitez vous aussi voir ce qu’a construit Julien, un replay de son ",[91,6916,6919],{"href":6917,"rel":6918},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=I07DxOLw10E",[95],"talk est disponible sur YouTube",[23,6921,6923],{"id":6922},"cétait-dans-quel-épisode-déjà-bref-jai-indexé-une-série-culte","C'était dans quel épisode déjà ? Bref, j'ai indexé une série culte",[19,6925,6926],{},[1620,6927,6928],{},"Par Tim Carry - Data & AI - 20 minutes",[19,6930,6931,6932,6937],{},"Tim travaille chez Algolia (oui encore eux). Tim est développeur. Mais surtout, Tim est un très grand fan de la série ",[91,6933,6936],{"href":6934,"rel":6935},"https:\u002F\u002Fwww.imdb.com\u002Ffr\u002Ftitle\u002Ftt2044128\u002F",[95],"Bref"," (note personnelle : il a bien raison !).",[19,6939,6940,6941,44],{},"Il s’est lancé sur un projet personnel qui lui tenait à cœur : un site qui permettrait de trouver l’épisode et l’extrait d’une réplique culte que l’on recherche. Ce sera la genèse de ",[91,6942,6945],{"href":6943,"rel":6944},"https:\u002F\u002Fwww.brefsearch.com\u002F",[95],"brefsearch.com",[19,6947,6948],{},"Les fonctionnalités du site : recherche par ligne de dialogue \u002F pensée, gère les fautes de frappe, aperçu animé de l’extrait au survol, recherche rapide et qui mène directement au moment trouvé.",[19,6950,6951],{},[176,6952],{"alt":6953,"src":6954},"Un exemple : la recherche du terme “Internet” sur brefsearch.com. Le résultat est très rapide et pertinent, et les extraits se jouent au survol.","\u002Fcontent-assets\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Fassets\u002Fimg5.webp",[19,6956,6957],{},"Mais comment cela marche-t-il ?",[19,6959,6960,6961,6966,6967,6972],{},"Tout d’abord, il faut une extraction via ",[91,6962,6965],{"href":6963,"rel":6964},"https:\u002F\u002Fgithub.com\u002Fyt-dlp\u002Fyt-dlp",[95],"Yt-dlp",", un outil en lignes de commande qui permet à Tim de récupérer toutes les vidéos de la ",[91,6968,6971],{"href":6969,"rel":6970},"https:\u002F\u002Fwww.youtube.com\u002Fplaylist?list=PLlFikkv2B2ffwYiFQJmcao3RKtw1DFMz5",[95],"playlist Bref sur YouTube",". Il obtient également beaucoup de metadatas très utiles, et également les sous-titres automatiques.",[19,6974,6975,6976,6981,6982,6985],{},"Un problème se pose cependant, dans Bref, ça parle vite. Les sous-titres automatiques sont de qualité médiocre. Pour récupérer du texte exploitable, une extraction audio est alors faite par Yt-dlp puis passés dans ",[91,6977,6980],{"href":6978,"rel":6979},"https:\u002F\u002Fwww.happyscribe.com\u002Ffr",[95],"HappyScribe",", un outil de ",[1620,6983,6984],{},"speech-to-text"," IA. C’est bien mieux, et la retouche des dialogues est facilement réalisable (et cela donne une raison de plus de revoir la série !)",[19,6987,6988],{},"Et pour la suite :",[443,6990,6991,6999,7002],{},[446,6992,6993,6998],{},[91,6994,6997],{"href":6995,"rel":6996},"https:\u002F\u002Fwww.ffmpeg.org\u002F",[95],"ffmpeg"," permet de construire les frames des lignes de texte trouvées et les aperçus animés",[446,7000,7001],{},"Algolia permet la recherche",[446,7003,7004,7005,7010,7011,6636],{},"Le frontend est hébergé sur Netlify en utilisant le CDN ",[91,7006,7009],{"href":7007,"rel":7008},"https:\u002F\u002Fcloudinary.com\u002F",[95],"Cloudinary",", avec quelques astuces données par Tim (notamment l’utilisation de LQIP (",[1620,7012,7013],{},"Low Quality Image Placeholder",[19,7015,7016],{},"Le résultat ?",[19,7018,7019],{},"Un site efficace, qui fait très bien ce qu’il a à faire, et qui impressionne les créateurs de la série eux-mêmes. Je ne sais pas vous, mais moi cela m’a donné envie de revoir Bref… J’en ai mangé tout le week-end suivant !",[23,7021,7023],{"id":7022},"speechless-fin-de-la-matinée","Speechless & fin de la matinée",[19,7025,7026],{},"Après ces présentations toutes plus intéressantes les unes que les autres, il est maintenant temps de récupérer des forces et de débriefer autour d’un grand buffet. Mais l’heure n’est pas qu’à la pause : un speechless live est organisé.",[19,7028,7029],{},"Le principe ? Plusieurs speakeuses et speakers passent devant le public dans un exercice d’improvisation :",[443,7031,7032,7035,7038],{},[446,7033,7034],{},"Un thème tiré au sort",[446,7036,7037],{},"Un sujet choisi par le public",[446,7039,7040],{},"Des slides imposées, qui n’ont aucun sens",[19,7042,7043],{},"C’était en tout cas un plaisir de voir Carmen Piciorus passer un entretien d’embauche pour devenir gardienne de nains de jardin, et Tim Carry nous pitcher son nouveau film “La revanche des cacahuètes”. Un moment amusant qui clôture une matinée aux petits oignons au DevFest Lyon !",[19,7045,7046],{},"Il est temps ensuite d’attaquer un après-midi qui s’avèrera tout aussi riche en enseignements et en échanges de qualité. Vous voulez en savoir plus ?",[19,7048,7049],{},"Guettez ce blog, j’ai entendu dire qu’un second article était en préparation…",{"title":350,"searchDepth":364,"depth":364,"links":7051},[7052,7053,7054,7055,7056],{"id":6657,"depth":364,"text":6658},{"id":6735,"depth":364,"text":6736},{"id":6867,"depth":364,"text":6868},{"id":6922,"depth":364,"text":6923},{"id":7022,"depth":364,"text":7023},"2025-12-02T10:02:07.045Z","Une question que l’on me pose beaucoup en ce début de semaine. En effet, vendredi 28 novembre 2025, nous avons eu la chance, avec plusieurs collègues de HoppR, de faire partie des 250 participants de ",{},"\u002Fblogs\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon",[7062,7064,7066,7068],{"id":5813,"name":5814,"image":7063,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466Y7KSVBHC%2F20251202%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251202T100206Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEoaCXVzLXdlc3QtMiJHMEUCIQDlPhoO6t9yJQoUoZw%2FLTwJI5MC%2Foym8X1E%2Bg6KJ%2BiFgwIgalDq7jA%2BP85pFMTva72lsMaql%2B9LjtYqLDQH3dgn1M0q%2FwMIExAAGgw2Mzc0MjMxODM4MDUiDNOvwSwCkwWPXxfr2CrcA8769%2FoIXsCvhgFS4Dv2as%2FMadMS7wa5TlBrAZ7cnJv7%2BruPZECofduiEAoBV9ATh622gA0pQ231dPxprnYq6SLobx%2FEXgHUroXG3Hqn%2ByV4BZcmFzpgks2HcaAcuaHoAxQhO%2FJOFl%2FDUsk7u2C%2F03ZHWHalr4QFq8HF2kBEzUf5y9Z7lCS23wHUe9yrlp6dnDaMZv7ctg37nRsZ5cPFFyP%2Bi6DvsRbv4jk7ZR4d1uGo%2FyGh6TxAtZ6bjsPYjOKjZ8cDFQubPif7rBAfK8Gu2lMBuI8Cpd1qw32YzUj4dprm8t1R1SUxs4t9d3SmZ415ZoYHufTwtLVK2sMPIP1y2pVCL5TQxoCQIeZknhH6tf7lN%2BJs7CiIk9lolBqdAUPcwZ3F%2F5Fp4IC63yn6syo0RgnVB8MqfB%2BSgFz%2BdmhDCDcQ%2B54ndcErvY2ae44aPLzBYI6haQ8DpNzmYS6KvY3lcnCqKPTRx2M6%2BTlHpOEeq7CbpF%2FYsMtskDgQyVVqQRGZJJ98f4naA%2F8A41AIqXTDNAK8ifTyOLNOa8pF%2BGwiNsbrbjT%2F4qhB43PK%2FjzXCKtb8czB7vQydYQ0mjlSkxtXFecZ5qOzQIYc%2BJI%2BNhPsJoCLRKw3sr9EwLqY5d6NMJrvuskGOqUBkmJA1855ur4UyoLjGj1WPfKYtvmOStTXYnAk6EEA5p4DMsWp%2FtC79u340iUu7rojNw3oS3XeDN7pdCo%2FZMsMGkduaNvN3RB3crutakC38cpYKKo8%2Fg1VYP9a5GzXDfesiZ4RzRQIMUhkFjYbvPnQiOxmXU%2FxTyvR57RMWG7ApufvcgZqmTQgxzACj5uuwFn8iXfklA7WVG0WqI3CseqOO%2F7ssBqz&X-Amz-Signature=0f9dedf66c69728d181b86c075540248b1da9d52cb45a0d9b21654912eac01eb&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":10,"name":11,"image":7065,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466QRTGLWHL%2F20251202%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251202T100206Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEkaCXVzLXdlc3QtMiJHMEUCIQDm4%2F0Wbjn1yhS08yXFNJ3YxNfXhqedQ1Ibi1ixjAZwQAIgfOCHgnZEctCvQodF01gw3q43a2oTC9uvnFD5rnVsxQkq%2FwMIEhAAGgw2Mzc0MjMxODM4MDUiDEGDfT3DvHNF4e0%2F1ircA%2BMNtVAYwDGaDc4cTMBzN4fvTjoy2vcW6lqQwt0fckDmqFnu4KACIzQS0IBnqRuEKVrwHDf462itGMt45GGMFgrJ%2FwZjcEXN7mqtsDnO6Okzrr8o2cez6enA7ugl2qQa1K9n00YRnX6S9YbDBhvJk4%2Fob8H1RM5f3g%2FWZ0DE%2Bw4ZQtTkqyzk9cmEFnZj9PgP3P5JJ6%2B1XC6y4hKPodsLFwdB%2FiWv93l%2BIQJvtA7Pmzf7MEsf%2Fjfo9lBKh96v0muhHM%2BOW3HziW%2B2%2F43PzDRq0fLk5PEHcyDk0ir6a0d1SE54JtxwNCQ2r4c9kr2U4QPmDgplyC0rvhlk1MkY8KQW%2BbKHW%2B7bDhIIUZKx6blcBvvnsHF8SxMYxMaKSuOigd8%2FfKtXdYhUIv5kl4a4pjX8%2Btgg4E1FEgXY6OOSuvWlAlKEOS1TLV5Mm9BxvLdM6lCaoPeD%2BwjBRBe3QsEal0tM8%2FoPZzY6qjoajqvXvfL6LVwme461vj52ccT9xnaR2bRChgs%2BU8ucdg320zC3PiGEn55r19XsS2syF4KKPQ2ZqotsOp8ddRvwjdUs2yeIjMi8MfSSklsKTRnqzGITcKfg9UPQ%2FkmP4ZIfFJ9BAEug3TroU6elUhH%2FX99VHkbdMJnQuskGOqUBDw6lrXPYCboisCRNK3rSof7RUE8dcfUUhSnHXeQhFy%2Bxtswny8NKyhzu2f3axx%2B8BAWeqnJLi9juYMoEcyH57Z1OlduE9j4c8XNeb5S5QGuPgL2eFFm2Q6A2%2B1%2Bx%2B%2FWc9u8KRHsPWxmnH%2FDvGCo%2B5NAwT2Z59tSaAy4WLaU69x7pOXJw2GLcmvqj7GY8t1wWC%2BgZmvjgT5pr7JoAqMyCTlqWW0p8&X-Amz-Signature=c4e986c0dead60c4b87052795a3446cf2dc94d9ffdea6f9da0065c64e12d46b3&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":897,"name":898,"image":7067,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4664RUX22IJ%2F20251202%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251202T100206Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEoaCXVzLXdlc3QtMiJIMEYCIQC2nkVt1TGIZcU4J2cW%2BwnOm%2FJYMKPRvr9QoJI0ln9rtAIhAMbp5av2Mva0lC3zvk9RTnOZcfJVPe3y49DPXDto73qKKv8DCBMQABoMNjM3NDIzMTgzODA1IgxWonWoO8Q%2F6Tb5h5wq3APC9x01ntajt7LgXx2%2F6oWSdtYAHetuavmLKHuZBE4qZkUxVZlNf8yev7okfjbHkNTEZGT9ewi71Ep6%2Fj7OgQALj8WCrQ0NStHtOAGlQxjSBldfbVhSqpD%2FcKXOxmZe78PH9Bah3KKZgd%2Fzq1QZxCFIUp9YdjF%2FbL9yDF32Qffz6s4hE2xPX%2BIWXiLgy%2FoAHqyuuF9yLOJGFULNae1K0SpX%2BUPc9bGDrF5eqmdZEagZw3NdTYVzpYNJeJjDdTA2wSH9V3zloZQUllFmA2FapNJ7m43SbD5crno2TvsppP%2FIZwtcKkbyYQ1dIu9yUkQcP0YtKL5HESyEHe2wZ%2Fh8ySECV5JLqJ612Tq%2FjQ4WG5IRA3LnmsLqVwlkmclF9qqhCLkr1raV9rxA49bzA9HTJlJbbx9W2IJ%2B1NF9k%2Ba4%2FgPg%2BBKeMMHbVVxnzJVULzJY3wX5CMRMW%2Bsb5j4idcJB9stl3D4taE42iOp%2FRdjAS0hnlyNzgN9wrV0exYYd5KhJjI4Q%2FULsOOo7qA%2B4HsqdYL36zkfJN6T%2BvjrzVG%2FjxzTNwUrTVKwzOHom2lkGd%2BX8KE1Cq3Xx%2FmRIx1Qdp3ua8xccBoGHYsEItydyKDT%2FvmhS8VqeCS3Mf719fVMjDTCT8LrJBjqkAfQTGT%2Fs9MjD6z%2BwJvaGpYM%2F%2Fj7dc8MdLQBOe1TXVGUugJIFO3k9RJBOnpGAcJ8iORYMTxNiQmlpchi%2FeJ%2FloxMKo9KLYsP51i8IawGdvOfcd7gPws3WPQglaWdiRbMl%2BsIKoY3ltOxuyzwHnFe3odYH9Jk7H15EvVy4X7KZns8dNnyZMF19aidySWh55J%2Byb%2BSI0fDuPaOd75%2BN97EwLFgvXSKB&X-Amz-Signature=10f2e76341a5b95b387a7537285d41aa5d73f789611b6e3f7291d5e48bf31b7f&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":1582,"name":1583,"image":7069,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466Y3X2BERO%2F20251202%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251202T100206Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEoaCXVzLXdlc3QtMiJHMEUCIHRw%2FuSZy28SiwpPOCs76n11i%2F1NJe6CZ%2BsRL3AWO%2B2fAiEA4vhBhGzEMfJI4snF1OloxuWCCMbRf1PDwUR5mDJ9XhMq%2FwMIExAAGgw2Mzc0MjMxODM4MDUiDFG70SUdJEiGKkM5bSrcAw9rPmsJGzwqShqiv0%2BeWtdSAO1vDBF77Pr3fo57wA6onGBTD13Mb6SFRhQ9%2Fra6mwI6ViUxzjAKm12NSy5iUxqlpE7OCeRIo9Anm1I3%2BeCrcf9sgDbmjO9%2Fq0CVRI%2FU5IZdPCJ33TU8DMeMHEqWABPbQu2JgRA08oGE7VhNIyxEibEDVBt2efeb9Lo5jxMEz%2FWlDtk3PoQhL%2FLS5Z%2F3VJ46ZG%2FjmqYw0w7eL3RTXvpO3F8ba8FwLP%2BPox3DLRsE%2Bb7RZip03wWeSyGpIyQrk%2Fk%2F5G3jj7VUUplHpHhT5D1Wqy5cXNWNlTczPw5oVN2IUc50L5iFv5LS4fAd8pFkfN62EjccKbWW0KnK539jxa9NktNFfLvcYD%2F6vLcDNwyfQgGP8yceEsSpjcPO0qHzchwhu3DNi7CIZe6US62dUslZUaUrSBMOsmUn%2B9ddPbtRSMqOY%2Bm%2FtLRJg%2FViOt1WXTF3IbqHZ4NJdCtZACK05FQhMzGqqH2dD2ItGI4Omx34fVPkSaT9o4dYKTix8VDrwD5EhMNmYrjOp7D%2BV8xhKoDoiW8JlW1VuSG6lVBEwLYkuwaHxUACflNG8bSl2YauKHvUTet%2FfaANzQSi%2F9UCf9y%2FPrn5IcGO2wdGGRxoMO%2FvuskGOqUBkceK1DQegSzZ4IUtEx%2B4PllbY2t6tdvBH15yyh4%2B%2FGCAcS9vea00xBAgUT4sC5YvyzMBR5INtwcv8At2vEauvXRTSiRU%2B5v13rmi1RpZpgRNRpspuzp4m9IRPeludo%2B%2FPgFsi%2FJ5dUfWIr1kzF%2F6ElvWLADEI9Chpz%2BvdUDbn%2F6ysbTgkF%2F8X4vIJraEEIdfrTio7kDfiOb%2BelfK7YochB5tFNJG&X-Amz-Signature=48a8f72788c038f6fc6755f0a2dd5a263a644eb8957eb8922c1068162f4056db&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":6612,"description":7058},"blogs\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Findex",[1879,7073,6607,6608,6271],"ia","sCW66ulOtCP9_c_OAQWwJLKRWm825rxal5BWlrgds-A",{"id":7076,"title":7077,"alt":7078,"authors":7079,"body":7086,"date":7232,"description":7233,"extension":890,"image":891,"meta":7234,"navigation":893,"ogImage":891,"path":7235,"published":893,"reviewers":7236,"seo":7239,"stem":7240,"tags":7241,"__hash__":7242},"blogs\u002Fblogs\u002F2025-10-20-cloud-nord-une-aventure-tech-collective-et-engage\u002Findex.md","Cloud Nord: une aventure tech, collective et engagée","image de l’événement cloud nord qui aura lieu le 23 octobre 2025 à l’université catholique de Lille",[7080,7081,7083,7085],{"id":10,"name":11,"image":12,"linkedin":13,"x":14},{"id":1582,"name":1583,"image":7082,"linkedin":1585,"x":901},".\u002Fassets\u002Fauthor-emmanuelle-gouvart.webp",{"id":897,"name":898,"image":7084,"linkedin":900,"x":901},".\u002Fassets\u002Fauthor-nicolas-zago.webp",{"id":5017,"name":5018,"image":5019,"linkedin":5020,"x":901},{"type":16,"value":7087,"toc":7223},[7088,7092,7098,7101,7104,7110,7113,7116,7119,7122,7128,7131,7134,7137,7140,7146,7149,7152,7155,7158,7165,7171,7174,7177,7180,7183,7189,7192,7195,7198,7204,7207,7210,7213,7216],[7089,7090,7077],"h1",{"id":7091},"cloud-nord-une-aventure-tech-collective-et-engagée",[23,7093,7095],{"id":7094},"cloud-nord-une-aventure-tech-collective-et-engagée-1",[34,7096,7097],{},"Cloud Nord : une aventure tech, collective et engagée",[19,7099,7100],{},"Organiser un événement tech de 250 à 500 personnes, bâtir un programme de conférences exigeant, coordonner une dizaine de bénévoles, assurer la logistique, la communication, le sponsoring… et faire tout cela bénévolement, en parallèle d’un emploi à temps plein ? C’est le pari que relève chaque année l’équipe organisatrice de Cloud Nord.",[19,7102,7103],{},"Ce rendez-vous devenu incontournable dans l'écosystème tech de Lille, dédié au Cloud et DevOps, est né en 2020 d’une envie simple mais ambitieuse : créer ce qui n’existait pas encore.",[23,7105,7107],{"id":7106},"une-initiative-née-du-terrain-pour-le-terrain",[34,7108,7109],{},"Une initiative née du terrain, pour le terrain",[19,7111,7112],{},"En pleine période de confinement, Nicolas Zago, aux côtés de Maxime Deroullers, Emmanuelle Gouvart et Paul-Alexandre Chrétien (aujourd’hui tous chez HoppR), lance l’idée de créer un événement local, à la fois technique, exigeant, et humain.",[19,7114,7115],{},"« Il existait déjà des événements comme le DevFest (aujourd'hui DevLille) ou AgiLille, qui parlent eux aussi à la communauté tech. Mais aucun ne mettait vraiment le focus sur les enjeux Cloud et DevOps. Alors on a eu envie de créer notre propre rendez-vous, centré sur ces thématiques. » explique Nicolas, CEO fondateur d’HoppR.",[19,7117,7118],{},"La première édition a lieu en ligne, en octobre 2020. Tout est à créer : une association loi 1901, une identité visuelle, un site web, un compte bancaire, une billetterie. Mais l’énergie collective est là. Et surtout, la communauté répond présente.",[19,7120,7121],{},"Depuis, l’événement a grandi, s’est installé à Euratechnologies, puis à l’Université Catholique de Lille en 2025, sans jamais renier son ambition initiale : un programme sérieux dans une ambiance conviviale.",[23,7123,7125],{"id":7124},"un-programme-pensé-pour-et-par-la-communauté-tech",[34,7126,7127],{},"Un programme pensé pour et par la communauté tech",[19,7129,7130],{},"En 2024 Cloud Nord accueille près de 500 participants. L'équipe reçoit en moyenne une centaine de propositions de talks. « Cette année, en 2025, on en a reçu 117, et on en sélectionne une vingtaine » explique Emmanuelle. « On a une plateforme sur laquelle les membres de l’asso et des bénévoles peuvent voter, noter, discuter des propositions. On choisit les sujets qui nous semblent les plus pertinents, utiles, inspirants.»",[19,7132,7133],{},"Le programme est conçu avec une attention particulière à la diversité des sujets, des formats et des profils de speakers. La moitié viennent de la région, l’autre moitié d’ailleurs. Certaines interventions sont très techniques, d’autres plus narratives, toutes partagent une même exigence : transmettre quelque chose de concret.",[19,7135,7136],{},"Dès les premières éditions, les organisateurs ont fait le choix d’un processus de sélection transparent et rigoureux, en s’appuyant sur un comité ouvert à des membres de différentes entreprises et horizons. Objectif : garantir une notation impartiale, éviter toute forme de copinage, et s’assurer d’un événement \"fair\" et de qualité. C’est aussi ce qui a permis de bâtir la fidélité du public au fil des années.",[19,7138,7139],{},"« Ce que les gens nous disent souvent, c’est : j’ai appris plein de choses, j’ai rencontré des gens, j’ai pu poser mes questions » souligne Paul-Alexandre. « Et c’est exactement ce qu’on veut. On n’est pas là pour faire du chiffre, mais pour créer un moment utile. »",[23,7141,7143],{"id":7142},"un-engagement-qui-transforme-aussi-les-organisateurs",[34,7144,7145],{},"Un engagement qui transforme aussi les organisateurs",[19,7147,7148],{},"Au fil des années, les bénévoles ont changé, l’équipe s’est renouvelée, mais le noyau dur reste. Et l’implication dans Cloud Nord est aussi une expérience fondatrice pour celles et ceux qui donnent de leur temps.",[19,7150,7151],{},"Emmanuelle, DRH chez HoppR, voit dans l'organisation de Cloud Nord une activité stimulante et pleinement compatible avec sa vie professionnelle et personnelle. Elle s’occupe notamment du marketing, de la communication et de l’organisation globale de l’événement. « Cet engagement me permet d'être en prise directe avec les enjeux du terrain, d'affiner ma compréhension des pratiques et des attentes des profils tech. Pour recruter efficacement, pour accompagner les carrières, il faut comprendre en profondeur les réalités des métiers. Participer à cet événement me donne une longueur d'avance et me rend plus pertinente dans mon rôle. »",[19,7153,7154],{},"Pour Paul-Alexandre, Senior Cloud Engineer chez HoppR, c’est aussi une façon d’incarner l’esprit craft. Sur les dernières éditions, il a pris en charge plusieurs aspects techniques de l’événement : gestion de la plateforme de billetterie, déploiement de l’application de scan des billets, intégration des outils pour les sponsors afin qu’ils puissent garder le contact avec les visiteurs, mise en ligne et planification des replays sur YouTube, ainsi que le suivi de la plateforme de notation des talks.",[19,7156,7157],{},"« On veut montrer que dans le Nord, on sait faire des choses bien. Ce n’est pas juste un événement, c’est aussi un outil de partage, d’apprentissage, de fierté. Et au fond, c’est très gratifiant de voir quelque chose grandir, année après année. »",[19,7159,7160,7161,7164],{},"Quant à Maxime, Architecte Cloud\u002FDevOps et Agency Leader chez HoppR, il a depuis contribué à la création de ",[34,7162,7163],{},"Cloud Alpes à Lyon",", sur le même modèle : communautaire, qualitatif, accessible.",[23,7166,7168],{"id":7167},"une-vision-alignée-avec-lesprit-hoppr",[34,7169,7170],{},"Une vision alignée avec l'esprit HoppR",[19,7172,7173],{},"L’événement Cloud Nord reflète certaines valeurs profondes que l’on retrouve chez HoppR : le goût du partage, l’engagement dans les communautés, la volonté de faire émerger des talents. Plusieurs membres de l’équipe organisatrice travaillent chez HoppR, et l’événement est naturellement en phase avec ce que l’entreprise cherche à incarner : une culture d’exigence, d’échange, et d’ancrage local.",[19,7175,7176],{},"C'est aussi une mise en pratique concrète de ce que Nicolas encourage au sein de ses équipes : devenir speaker, raconter ses expériences projets, transmettre ce qu'on apprend et apprendre en retour. Aller à la rencontre de la communauté tech pour contribuer à un écosystème qui progresse collectivement. Participer à Cloud Nord, c’est donc aussi prolonger cet engagement dans un cadre plus large, au bénéfice de tous.",[19,7178,7179],{},"Par ailleurs, la mise en lumière de profils, les billets sponsorisés destinés à des publics sous-représentés, les choix de prestataires et partenaires locaux, participent d’une même logique : celle d’un événement qui a du sens.",[19,7181,7182],{},"Depuis trois ans, l’équipe a aussi lancé le \"Tremplin des speakers\", une initiative pour faire émerger de nouveaux talents. Inspiré d’autres formats, mais inédit dans la région, ce mini-événement repose sur un principe simple : les talks présentés sont soumis à un vote, et les mieux notés accèdent ensuite à des scènes comme Cloud Nord, DevLille ou d’autres conférences partenaires. Une manière de créer du renouvellement, de faire circuler les idées et de valoriser les nouvelles voix.",[23,7184,7186],{"id":7185},"zoom-sur-lédition-2025-concentrée-engagée-toujours-gourmande",[34,7187,7188],{},"Zoom sur l'édition 2025 : concentrée, engagée, toujours gourmande",[19,7190,7191],{},"L'édition 2025 s'annonce particulière. Dans un contexte économique moins favorable pour les sponsors, l'équipe a fait le choix d'un format plus resserré, mais sans rien concéder à la qualité. Nouveau lieu (l’Université Catholique de Lille), nouveau traiteur (avec options végé\u002Fvegan et mignardises locales), sponsoring finalisé de justesse… Tout est prêt.",[19,7193,7194],{},"Le programme est en ligne, la billetterie ouverte, et plusieurs places \"diversité\" sont offertes grâce à Exotec, TechSys et Worldline. Comme toujours, ce sont les bénévoles qui ont constitué un programme pointu et varié, parmi lesquels Nicolas cite volontiers quelques coups de cœur : \"K8sGPT\", \"Dapr et Microcks\", \"Docker : plus qu’un choix, une nécessité\"...",[19,7196,7197],{},"Et bien sûr, la pause muffins du matin est de retour, avec ses gaufres, financiers et madeleines locales. Et cette année, petite nouveauté : après avoir mis à l'honneur des brasseurs locaux (tradition bien ancrée dans le Nord), l'événement accueillera pour la première fois un vigneron du Nord : le Domaine du Jeune Bois, qui viendra faire déguster ses cuvées lors de l'after. Une façon de montrer que le terroir régional sait aussi réserver des surprises.",[23,7199,7201],{"id":7200},"une-aventure-collective-qui-continue",[34,7202,7203],{},"Une aventure collective qui continue",[19,7205,7206],{},"Cloud Nord ne serait rien sans la dizaine de bénévoles qui s’impliquent chaque année, en plus du noyau fondateur. Leur engagement, souvent discret mais essentiel, est une part intégrante de la réussite de l'événement. Ils et elles méritent toute la reconnaissance.",[19,7208,7209],{},"Voici les bénévoles 2025 : Emmanuelle Gouvart, Maxime Deroullers, Nicolas Zago, Julien Wittouck, Alexandre Vandekerkhove, Camille Dagbert et Pierre Bourgeois.",[19,7211,7212],{},"« Ce qu’on souhaite, conclut Nicolas, c’est que les gens repartent avec des idées, des contacts, l’envie de creuser un sujet. Et surtout, le sentiment d’avoir passé une journée qui compte. »",[19,7214,7215],{},"Chaque année, Cloud Nord cherche à progresser, à innover, à se renouveler dans ses formats, ses thématiques, ses collaborations. C’est aussi cela, Cloud Nord : un lieu où la technique rencontre l’engagement, et où la communauté se construit, une édition après l’autre.",[19,7217,7218,7219],{},"Pour en savoir plus sur l'événement : ",[91,7220,7221],{"href":7221,"rel":7222},"https:\u002F\u002Fcloudnord.fr\u002F",[95],{"title":350,"searchDepth":364,"depth":364,"links":7224},[7225,7226,7227,7228,7229,7230,7231],{"id":7094,"depth":364,"text":7097},{"id":7106,"depth":364,"text":7109},{"id":7124,"depth":364,"text":7127},{"id":7142,"depth":364,"text":7145},{"id":7167,"depth":364,"text":7170},{"id":7185,"depth":364,"text":7188},{"id":7200,"depth":364,"text":7203},"2025-10-20T13:06:36.456Z","  Organiser un événement tech de 250 à 500 personnes, bâtir un programme de conférences exigeant, coordonner une dizaine de bénévoles, assurer la logistique, la communication, le sponsoring… et faire ",{},"\u002Fblogs\u002F2025-10-20-cloud-nord-une-aventure-tech-collective-et-engage",[7237],{"id":1582,"name":1583,"image":7238,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466RBYBRSPA%2F20251020%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20251020T130636Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEUaCXVzLXdlc3QtMiJHMEUCIHrrOH5PrR6eJ5K951yaAB2s7WnyT9XUk%2BDmLGz0kUM%2BAiEAivskQY9erpOV%2BJtsawuVTTDCacWKPydGLUqLtFIN4DAqiAQI7v%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDCJj5MaF6y%2BbQ4eRgCrcA0BBiH1dQsnD7wgbRRU48aQFbt1UDJ3dF2JTwPFDT2%2BguD8BQqF0y2%2BFyEphmjUHKntIBFa4%2BbP1p7Oo3v%2BUXkBMi57XL5K%2BDjV%2B%2B5B8icTrVXAAltMZtSYhNDpNo2IZJgp4ErfUJHD2H1DZ0a7hZAv00Jz2Vb8qshpWMfd9dl4Hj0t1RsaDvcqC3TtHua%2Fn%2FLZ%2FyqMMfO5vSeR8AdSk9T44t9CtQ2en2K3vZfVN4odSpmaWJ8O3E3WSOzCESJkCe4L%2FF84H%2FZLZF9w%2BMFMr3dtSmTnuwogg04%2FOioZZIzHh2AF6jUCnx%2F0wv621ii7y6kFNgYF1XcVZMa6%2Fa9zGhmKge4r6sg5MNiLGzdOE5Kg145eH1U96RNxTf291zTlN33yJ9jn4zQl%2BGTMCBN7pKGaiWgPlNnGIiTwW%2F89sOcxNeMjawdLjYtNvifHxy3X8hVYKLmPaZaSh%2B5eUp%2BKZQxWF8IpsvzX6MA238HE9jryFemRsaFiZARF8CFww39z56E8Q%2Bfi%2Ff0d3dwZj9YAG7vSLwQjYxZY4TPD3uMkTS7v7AkElBowCePLzeQgIDif6pk%2BpGeEXWj743qZllYmGJRkuDuBDqvd%2BkWdPQlzs6TdvYCblJFfc38ceFqgbMOXY2McGOqUBTWwA1aDWA4L35659Zu6%2B0jM7QIYDtSpaZIJvCk9NcuC7rTxkHwe2lSSj%2B4O2ljWqaYbGgC6fPTZDWkoajpQRToFw6GXb9RCnHr%2BLXijpK%2FJAN8VXWy7wEh0S6uVDX%2BTSWnE0fKFftlHbIpiBdjWRUj2g3h0mM2MYOy9K7K9O3QU15MmujVx7SO4V5Ij934y55twjkgxJpGXTTOCyHFW7zXLII9dg&X-Amz-Signature=4feedc6123dd961c67097e83217e71867cff0a27a1959fb9942d7fbe53a47963&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":7077,"description":7233},"blogs\u002F2025-10-20-cloud-nord-une-aventure-tech-collective-et-engage\u002Findex",[6607,906,1592],"0oP9lUxc5BshFRQyLcGQUGiA3r_tZLUbt3Y-FeI_ae0",{"id":7244,"title":7245,"alt":7246,"authors":7247,"body":7249,"date":7805,"description":7806,"extension":890,"image":891,"meta":7807,"navigation":893,"ogImage":891,"path":7808,"published":893,"reviewers":7809,"seo":7816,"stem":7817,"tags":7818,"__hash__":7823},"blogs\u002Fblogs\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Findex.md","Un IDE avec agent IA, une alternative Open Source à Cursor : tout ce qu’il faut savoir pour bien démarrer avec Void !","Logo de l’IDE Void",[7248],{"id":5813,"name":5814,"image":5815,"linkedin":5816,"x":901},{"type":16,"value":7250,"toc":7789},[7251,7261,7264,7268,7271,7274,7300,7304,7319,7345,7349,7362,7366,7374,7383,7389,7398,7404,7407,7410,7416,7419,7422,7429,7435,7439,7446,7449,7522,7531,7537,7543,7548,7562,7568,7578,7584,7587,7592,7599,7603,7606,7612,7616,7619,7625,7630,7634,7637,7643,7646,7652,7655,7659,7662,7668,7674,7677,7683,7686,7690,7693,7696,7710,7714,7717,7744,7758,7760,7765,7770,7775,7778,7781,7784],[19,7252,7253,7254,508,7257,7260],{},"Cursor séduit par son interface familière, sa compatibilité avec les extensions existantes, et son intégration poussée avec des modèles comme ",[1620,7255,7256],{},"GPT-4",[1620,7258,7259],{},"Claude",". Mais derrière cette puissance se cache une infrastructure propriétaire, où la confidentialité et le contrôle des données peuvent soulever des questions.",[19,7262,7263],{},"Depuis 5 mois, j’utilise, une alternative Open Source, Void. Il m’accompagne dans mes développements notamment dans la reprise de base de code (Suppression de code mort, Abstraction de conditions complexes, Extraction de méthode, etc) et l’ajout de fonctionnalités en Java, Python, Go. A travers ce guide, je souhaite vous partager mon retour d’expérience et vous faire découvrir Void, de ses fonctionnalités essentielles à quelques cas d’usage.",[23,7265,7267],{"id":7266},"pourquoi-lopen-source","Pourquoi l’open-source ?",[19,7269,7270],{},"Quand on parle de développement et d’IA, la principale problématique est la confidentialité d’envoi de code propriétaire à des services tiers. Par exemple, avec Cursor, vous devez envoyer vos données privées via le backend de Cursor à chaque utilisation. Cela entraîne des problèmes évidents de confidentialité. C'est également coûteux pour les développeur·euse·s, et cela signifie qu'une seule personne a le contrôle total d'un puissant modèle d'IA.",[19,7272,7273],{},"Vous l’aurez compris Void, répond à cette problématique. Il propose de nombreuses fonctionnalités dont nous avons maintenant l’habitude :",[443,7275,7276,7282,7288,7294],{},[446,7277,7278,7281],{},[34,7279,7280],{},"Auto-complétion :"," Appliquer les suggestions proposées par l’IA en appuyant sur Tab.",[446,7283,7284,7287],{},[34,7285,7286],{},"Éditeur de lignes :"," Sélectionner des lignes dont nous voulons modifier le contenu en ouvrant une fenêtre dialogue (Ctrl-K) et demandez les modifications.",[446,7289,7290,7293],{},[34,7291,7292],{},"Éditeur de fichiers :"," Nous pouvons aussi inclure des fichiers, voir toute notre base de code, via la fenêtre de dialogue globale (Ctrl-L).",[446,7295,7296,7299],{},[34,7297,7298],{},"“Any LLM, Anywhere”:"," Connexion à nos modèles préférés en local ou via le Cloud.",[23,7301,7303],{"id":7302},"quest-ce-que-cest-void","Qu’est ce que c’est Void ?",[19,7305,7306,7307,7312,7313,7318],{},"Si vous êtes un habitué de VS Code, vous serez à votre aise avec ",[91,7308,7311],{"href":7309,"rel":7310},"https:\u002F\u002Fvoideditor.com\u002F",[95],"Void",". Void est basé sur ",[91,7314,7317],{"href":7315,"rel":7316},"https:\u002F\u002Fvscodium.com\u002F",[95],"VSCodium",", un fork de VS Code. Il met l’accent sur la confidentialité, la personnalisation et l’implication de communauté sans sacrifier les fonctionnalités IA sur les quelles les développeur·euse·s peuvent d’appuyer :",[443,7320,7321,7327,7333,7339],{},[446,7322,7323,7326],{},[34,7324,7325],{},"Fondamentaux de VS Codium\u002FCode :"," Transférer tous nos thèmes, raccourcis clavier et paramètres en un clic.",[446,7328,7329,7332],{},[34,7330,7331],{},"Fonctionnalités communautaires :"," Plugins VS Codium\u002FCode ou même des fonctionnalités d'IA créées par la communauté.",[446,7334,7335,7338],{},[34,7336,7337],{},"Axé sur la confidentialité :"," Héberger les modèles localement ou se connecter directement aux fournisseurs sans intermédiaire.",[446,7340,7341,7344],{},[34,7342,7343],{},"Open-source :"," Consulter, modifier, contribuer au code source.",[23,7346,7348],{"id":7347},"comment-installer-void","Comment installer Void ?",[19,7350,7351,7352,7355,7356,7361],{},"Void est en version bêta ouverte, les installateurs (Windows, Mac & Linux) sont directement disponibles sur leur site : ",[91,7353,7309],{"href":7309,"rel":7354},[95],". Si il y a le moindre soucis, la communauté officielle de Void sur ",[91,7357,7360],{"href":7358,"rel":7359},"https:\u002F\u002Fdiscord.com\u002Finvite\u002FRSNjgaugJs",[95],"Discord"," est très active.",[84,7363,7365],{"id":7364},"connexions-à-un-llm","Connexions à un LLM",[19,7367,7368,7369,44],{},"L'un des principaux avantages de Void repose sur sa flexibilité de connexion à différents LLM. Lors de l’installation, Void propose une connexion a ",[91,7370,7373],{"href":7371,"rel":7372},"https:\u002F\u002Faistudio.google.com\u002Fapikey",[95],"Gemini via API Key",[19,7375,7376,7377,508,7380],{},"A défaut d’être Open Source, cette connexion a un provider externe permet d’avoir accès un LLM puissant à moindre coût en contrôlant nos tokens, voir même gratuit, dans le cas des modèles ",[1620,7378,7379],{},"gemini-2.0-flash",[1620,7381,7382],{},"gemini-2.0-flash-lite.",[19,7384,7385],{},[176,7386],{"alt":7387,"src":7388},"Capture d’écran de l’ajout de l’API Key Gemini dans Void","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg1.webp",[19,7390,7391,7392,7397],{},"Nous verrons qu’il est aussi possible d’héberger nos propres modèles localement. Si vous partez sur le solution ",[91,7393,7396],{"href":7394,"rel":7395},"https:\u002F\u002Follama.com\u002F",[95],"Ollama",", Void est déjà pré-configuré en ce sens.",[19,7399,7400],{},[176,7401],{"alt":7402,"src":7403},"Configuration par défaut pour l’utilisation d’Ollama dans Void","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg2.webp",[19,7405,7406],{},"Dans les deux cas, en cliquant sur les liens dans la configuration, Void nous accompagne pour mettre en place notre token Gemini ou installer Ollama.",[19,7408,7409],{},"Si vous avez configuré votre token Gemini, dans les paramètres des modèles Void (Engrenage en haut à droit), vous devriez trouvez les modèles Gemini actifs.",[19,7411,7412],{},[176,7413],{"alt":7414,"src":7415},"Modèles Gemini actifs après configuration du token","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg3.webp",[19,7417,7418],{},"Wouah ! Le nombre de connecteurs disponibles !",[19,7420,7421],{},"A vous de jouer avec vos clés des différents providers de LLM ! Ici, nous nous allons passer plus de temps sur comment faire tourner un modèle en local car c’est l’une des façon les plus rapides pour avoir de l’auto-complétion et non seulement une fenêtre de dialogue.",[19,7423,7424,7425,7428],{},"En effet, comme vous pouvez le voir dans l’onglet “",[1620,7426,7427],{},"Feature Options","” des paramètres, les modèles Gemini ne sont pas compatibles avec l’auto-complétion (FIM models).",[19,7430,7431],{},[176,7432],{"alt":7433,"src":7434},"L’auto-complétion non compatible avec les modèles de Gemini","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg4.webp",[84,7436,7438],{"id":7437},"utilisation-dun-llm-local","Utilisation d’un LLM local",[19,7440,7441,7442],{},"Pour utiliser un LLM en local, nous pouvons utiliser Ollama. Vous trouverez les différents installateurs (Windows, Mac & Linux) sur leur site : ",[91,7443,7444],{"href":7444,"rel":7445},"https:\u002F\u002Follama.com\u002Fdownload",[95],[19,7447,7448],{},"Il est nécessaire de faire un choix dans le LLM à utiliser, et parmis les LLMs dédiés à l’écriture de code voici les références dans leur domaine car développés par des grandes entreprises ou des laboratoires :",[187,7450,7451,7467],{},[190,7452,7453],{},[193,7454,7455,7458,7461,7464],{},[196,7456,7457],{},"Nom du modèle",[196,7459,7460],{},"FIM Support",[196,7462,7463],{},"Fonctionnalités liés au code",[196,7465,7466],{},"Poids",[208,7468,7469,7483,7496,7509],{},[193,7470,7471,7474,7477,7480],{},[213,7472,7473],{},"CodeLlama  34B",[213,7475,7476],{},"✅",[213,7478,7479],{},"Advanced code generation, refactoring, multi-file context",[213,7481,7482],{},"~19GB",[193,7484,7485,7488,7490,7493],{},[213,7486,7487],{},"Deepseek-Coder  33B",[213,7489,7476],{},[213,7491,7492],{},"Complex logic generation, Java debugging, test creation",[213,7494,7495],{},"~17GB",[193,7497,7498,7501,7503,7506],{},[213,7499,7500],{},"Qwen2.5-Coder  32B",[213,7502,7476],{},[213,7504,7505],{},"Multi-language support, strong architectural reasoning",[213,7507,7508],{},"~16GB",[193,7510,7511,7514,7516,7519],{},[213,7512,7513],{},"CodeLlama  13B",[213,7515,7476],{},[213,7517,7518],{},"Lightweight, good for method-level FIM and snippets",[213,7520,7521],{},"~7GB",[19,7523,7524,7525,7530],{},"Un challenger intéressant, Open-Source et particulièrement transparent dans ces résultats d’évaluation est ",[91,7526,7529],{"href":7527,"rel":7528},"https:\u002F\u002Follama.com\u002Flibrary\u002Fcodestral",[95],"CodeStral"," (~13GB). En auto-complétion, voici les scores disponibles :",[19,7532,7533],{},[176,7534],{"alt":7535,"src":7536},"Score de différents LLMs en chat","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg5.webp",[19,7538,7539],{},[176,7540],{"alt":7541,"src":7542},"Score de différents LLMs en auto-complétion","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg6.webp",[19,7544,7545,7547],{},[34,7546,3624],{}," tous ces LLMs demandent des ressources sur votre machine, notamment de la RAM. Aujourd’hui, au vu du coût en énergie et en achat de la machine, pour ces grands LLMs de référence, il reste plus intéressant de passer par des providers et de payer les tokens utilisés.",[19,7549,7550,7551,7556,7557,7561],{},"Il est toujours possible d’héberger des modèles plus petits sur nos machines. L’un des plus petit est ",[91,7552,7555],{"href":7553,"rel":7554},"https:\u002F\u002Follama.com\u002Flibrary\u002Fqwen2.5-coder",[95],"qwen2.5-coder:0.5b",", un modèle de 398MB. Pour un compromis entre pertinence et ressources, j’utilise ",[91,7558,7560],{"href":7553,"rel":7559},[95],"qwen2.5-coder:3b"," (~1,9GB).",[19,7563,7564],{},[176,7565],{"alt":7566,"src":7567},"Évaluation des différents modèles Qwen2.5-coder ","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg7.webp",[19,7569,7570,7571,508,7574,7577],{},"Dans tous les cas, pour lancer votre modèle, il nous suffit de 2 commandes : ",[352,7572,7573],{},"ollama pull nom_du_modèle",[352,7575,7576],{},"ollama run nom_du_modèle"," . Cette opération est unique, il n’est pas nécessaire de le faire à chaque redémarrage de notre machine.",[19,7579,7580],{},[176,7581],{"alt":7582,"src":7583},"Détection du modèle local par Void","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg8.webp",[19,7585,7586],{},"Voilà ! Aucune action supplémentaire n'est requise. Void détecte automatiquement les modèles exécutés localement. Il ne nous reste plus qu’à les activer.",[1003,7588,7589],{},[19,7590,7591],{},"💡 Si vous souhaitez modifier le point de terminaison de vos modèles hébergés localement, vous pouvez le faire.",[19,7593,7594,7595,7598],{},"Avant de nous lancer dans l’utilisation des fonctionnalités de Void, n’oubliez pas d’activer l’option d’auto-complétion dans les paramètres “",[1620,7596,7597],{},"Features Options","”.",[23,7600,7602],{"id":7601},"utilisation-des-fonctionnalités-de-void","Utilisation des fonctionnalités de Void",[19,7604,7605],{},"J’ai demandé à notre LLM de créer un projet Java avec un simple Controller retournant “Hello, World!”. Les exemples seront basés dessus :",[19,7607,7608],{},[176,7609],{"alt":7610,"src":7611},"Fichier crée par le LLM pour nos futurs exemples","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg9.webp",[84,7613,7615],{"id":7614},"auto-complétion-de-code","Auto-complétion de code",[19,7617,7618],{},"L’auto-complétion de Void comprend le fichier actuel et le code source. À mesure que nous saisissons du code, nous pouvons accepter les suggestions du LLM en appuyant sur Tab.",[19,7620,7621],{},[176,7622],{"alt":7623,"src":7624},"Auto-complétion proposé par le LLM","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg10.webp",[1003,7626,7627],{},[19,7628,7629],{},"💡 L’auto-complétion peut aussi proposer plusieurs lignes à intégrer au code.",[84,7631,7633],{"id":7632},"éditeur-de-lignes-ctrl-k","Éditeur de lignes (Ctrl-K)",[19,7635,7636],{},"Nous avons maintenant besoin de refactoriser notre code. Sélectionnons les lignes à modifier, appuyons sur Ctrl+K. Une fenêtre de chat apparaît !",[19,7638,7639],{},[176,7640],{"alt":7641,"src":7642},"Fenêtre de chat pour la modification de lignes ","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg11.webp",[19,7644,7645],{},"Les modifications nous sons proposées et nous pouvons les accepter ou non (Dans leur intégralité ou ligne par ligne).",[19,7647,7648],{},[176,7649],{"alt":7650,"src":7651},"Suggestions d’insertion de variable par le LLM","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg12.webp",[19,7653,7654],{},"Nous pouvons aussi lui poser des questions plus complexes (Fonctions, documentation, refactorisation). La limite est notre budget de tokens ou notre machine !",[84,7656,7658],{"id":7657},"éditeur-de-fichiers-ctrl-l","Éditeur de fichiers (Ctrl-L)",[19,7660,7661],{},"Nous pouvons aussi avoir des questions plus large sur notre code qui inclut soit des fichiers spécifiques, soit l’entièreté de notre base de code. Pour cela, nous pouvons utiliser le chat global de Void.",[19,7663,7664,7665],{},"Choisissons notre LLM et posons notre question pour améliorer notre code : ",[1620,7666,7667],{},"“Can you suggest me improvements for my code ?”",[19,7669,7670],{},[176,7671],{"alt":7672,"src":7673},"Suggestions d’améliorations par le LLM pour toute la base de code","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg13.webp",[19,7675,7676],{},"Il identifie clairement notre mauvaise gestion des erreurs, de logs et suggère des modifications !",[19,7678,7679],{},[176,7680],{"alt":7681,"src":7682},"Suggestions en détails des améliorations","\u002Fcontent-assets\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Fassets\u002Fimg14.webp",[19,7684,7685],{},"Comme précédemment, nous pouvons accepter les modifications dans leur intégralité ou ligne par ligne.",[23,7687,7689],{"id":7688},"mon-utilisation-en-tant-que-développeur","Mon utilisation en tant que développeur",[19,7691,7692],{},"J’utilise Void depuis maintenant cinq mois principalement dans le cadre de refactoring de mon code. Mes tests restent mes garde-fous et sont conçus et maintenus pour garantir la robustesse de mes développements.",[19,7694,7695],{},"Pour les tâches plus lourdes comme l’édition de lignes ou de fichiers via interface Chat, je m’appuie sur les modèles Gemini, qui me permettent d’accéder à une puissance de calcul que ma machine ne pourrait pas supporter seule.",[19,7697,7698,7699,7705,7706,7709],{},"Pour l’auto-complétion, je privilégie les modèles ",[91,7700,7702],{"href":7553,"rel":7701},[95],[34,7703,7704],{},"Qwen2.5-Coder",", qui offrent un compromis entre légèreté et fonctionnalités. Si je disposais de plus de RAM, je basculerais probablement vers ",[91,7707,7529],{"href":7527,"rel":7708},[95]," qui semble être une alternative prometteuse.",[23,7711,7713],{"id":7712},"pour-les-curieux","Pour les curieux !",[19,7715,7716],{},"L’architecture de Void est modulaire et intègre de manière expérimentale de nombreuses fonctionnalités :",[443,7718,7719,7722,7725],{},[446,7720,7721],{},"Indexation de fichiers : capacités de recherche et de navigation améliorées",[446,7723,7724],{},"Génération de Docstring : assistance automatisée à la documentation",[446,7726,7727,7728,7733,7734,7737,7738,7743],{},"Intégrations de composants externes : ",[91,7729,7732],{"href":7730,"rel":7731},"https:\u002F\u002Fwww.greptile.com\u002F",[95],"Greptile"," (Revue de code), ",[91,7735,7396],{"href":7394,"rel":7736},[95]," (Hébergement local) et ",[91,7739,7742],{"href":7740,"rel":7741},"https:\u002F\u002Fdocsearch.algolia.com\u002F",[95],"DocSearch"," (Recherche de documentation)",[19,7745,7746,7747,7751,7752,7757],{},"N’hésitez pas à faire un tour sur le ",[91,7748,7750],{"href":7358,"rel":7749},[95],"Discord officiel"," et sur le répertoire ",[91,7753,7756],{"href":7754,"rel":7755},"https:\u002F\u002Fgithub.com\u002Fvoideditor\u002Fvoid",[95],"Github"," !",[23,7759,1528],{"id":1527},[1003,7761,7762],{},[19,7763,7764],{},"1️⃣ Void répond à la problématique de confidentialité en nous permettant d’héberger nos modèles sur nos machines et, en garantissant que notre code ne quitte jamais notre environnement !",[1003,7766,7767],{},[19,7768,7769],{},"2️⃣ Void reste ouvert et nous propose des connecteurs aux providers de LLMs et donc une accès à des LLMs puissant !",[1003,7771,7772],{},[19,7773,7774],{},"3️⃣ Void est transparent dans les modifications que font les LLMs à notre code. A nous de valider ou non les suggestions !",[19,7776,7777],{},"Mais… les avantages vont au-delà de la simple confidentialité et des économies de coûts. En tant que projet open source, Void invite la communauté à contribuer pour repousser les limites du développement assisté par l’IA.",[19,7779,7780],{},"La transparence du projet offre également de précieuses opportunités d’apprentissage aux développeur·euse·s intéressés par l’interaction entre les outils de développement traditionnels et l’IA.",[19,7782,7783],{},"Que vous soyez soucieux de la confidentialité, que vous cherchiez à réduire vos coûts ou que vous préférez simplement les outils open source, Void offre une alternative performante qui mérite d’être explorée. N’hésitez pas à prendre le meilleur des deux mondes !",[19,7785,7786],{},[1620,7787,7788],{},"Merci de votre lecture !",{"title":350,"searchDepth":364,"depth":364,"links":7790},[7791,7792,7793,7797,7802,7803,7804],{"id":7266,"depth":364,"text":7267},{"id":7302,"depth":364,"text":7303},{"id":7347,"depth":364,"text":7348,"children":7794},[7795,7796],{"id":7364,"depth":370,"text":7365},{"id":7437,"depth":370,"text":7438},{"id":7601,"depth":364,"text":7602,"children":7798},[7799,7800,7801],{"id":7614,"depth":370,"text":7615},{"id":7632,"depth":370,"text":7633},{"id":7657,"depth":370,"text":7658},{"id":7688,"depth":364,"text":7689},{"id":7712,"depth":364,"text":7713},{"id":1527,"depth":364,"text":1528},"2025-09-03T07:35:06.710Z","Cursor séduit par son interface familière, sa compatibilité avec les extensions existantes, et son intégration poussée avec des modèles comme _GPT-4_ et _Claude_. Mais derrière cette puissance se cach",{},"\u002Fblogs\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void",[7810,7812,7814],{"id":897,"name":898,"image":7811,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466ZDLKRYVF%2F20250903%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250903T073506Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjENb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJGMEQCIG%2BvaXFMQt%2B6Qj8eNPF9N%2BSUaZ0cNFSYx2baFXn%2FbKW6AiB%2B3P5tZFm9jlWPtGCaF4DLnQM3zhKIq%2B9K1uaRu86vnir%2FAwg%2FEAAaDDYzNzQyMzE4MzgwNSIMw5bxg3sltrFNkUxOKtwDSPFYwesUC22hxfy2kHqgnD3lNSSuItCcUQ4D2B97GRE65RzXTWyuJEjU9lXyw0faxArG2NbcoPniX4bE8fwbuMcKV4tugd2BfRB8YnKKm%2FdUSbAmAlXx9Js5nifbWH0mz5L0OK7EhmXYZw%2FO48DOtzIKGei4YFCghhW4%2FYYa9FzQKdjbeM8oEOFaR9h9uK1hEOe7zAvN%2FvzaTyA0gjNR3FwW%2BtmvaYQDQlWqXvdHMXHs8FfJjEYO4SY6BjnDkF9lWlGpnv6BKvaEIyJQai1mARLgQ%2B5gjM5LEnq%2BkSAddwGYXtXp%2FI237%2BmWMbUboqNZeYyFf3UJSJkrW%2Fyqo%2FC6fhqb1k9sS1ytKASXiWgBNPoUN6eZHXi5l0qFJAyXRwpYTJiuidc%2BgVtrOmkSMVm6Eg77ieUq8H6T6Qt6UsVPLWMTRfieE9a4ax0keUk9PFR%2BonQ0Nb%2BfSNlsLrBv6cIo68a42GyZ3jpn4JbMBN4%2Ff%2BnRHg%2FiU%2BWy7NzoTy1QvlZ22%2BfUo0nApRTcnCg%2F647J5OqkDlkoZn6NsrJ0lXgIBxNgRfaQOG4L6q5WSzU%2BbGO2ci89EJqkS32Msug9IjzrK%2F5obEXxrs1NbR5y3KQFLNsUlIVr%2F5%2F%2BvY%2BfjB0w6bjfxQY6pgH4Qs%2Bft%2Fnfe0Fphwrc%2B6PKxo0pBzJsnGHLgN2ghniYkK8tKxZ6GAVtKXnpvqtr5UKhOS%2Ft%2FeS93kZrRV9V5kAZ3xCEq9G9ewA%2FbzgtFtQ6xVAsn6n57V2U8e7e5sXbHtyd780KexydA2%2F%2FelidNyBI5bCZSV8JdqkinYKVwRyw9q2rwEsKmYVBj6E1Rc%2FNLuxtncPdjAWOM2ydYlly118Bry3aufLW&X-Amz-Signature=4e04cd8aee99b1e1f1045840307945dc87a3a9be1036625ac33254fc598ef394&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":1582,"name":1583,"image":7813,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4663B3BM6TB%2F20250903%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250903T073506Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjENb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJHMEUCIG9fB1ykwU%2FbGIaGsJvhCPPFqNNxLym7wZJL2IBrrfByAiEA2dAwm9ubQtgkLGO%2FFfFNhn3sWE%2FTFr8sHTc0Xkpklfoq%2FwMIPxAAGgw2Mzc0MjMxODM4MDUiDCRssieECgWoB2hW9CrcA7GhvJZ2CKT8EoZg3VZPvy670nbucj7%2F6cMOgZD1XxfmYMplYVipz5WRjLwwevWAwXoE1mKhz6zd0oQyeIDP9CuHGXUsrvr6Q2sCuhXhT3RTnE13AO5rhH1dpXfz3kEI87JZy07LvKVUvO%2B6B2xhJq1sy%2B9XvEzffS7L5mUFFIpWs0%2FtJkj01hFq4qgDsPwJ3cdlR7CQpo5bIYAn%2BMwPWsSOoDciHA5ZwqixPZV0u9YvA1NeBGBHP3KHzDoiNWxuBuCpcxeCYFGrWe5O7VSEBOSbSl4vXuxlC6wyJhf%2FmlPnqigdg%2FvfrgZRTy0xE3dV99Z8H9EubyucSlmkVctU58qO4UolWQzTL4I0X5lE%2Bkkfl32%2F2pek7dZyI9N7sCkyxxBfEpXteOoZuGvDrEg3XaDOv%2FZmkcbpfuOwqUSelFSg8Gn8OTalUUWn17GtN1LjCaXoPgsbnrdDZR8B1XUkGbGWDm%2F0zxZEsUWPMocXnICc15HXYSmCj6p49STA4VhMnTDeuGLDYCp7id%2B0JUld6IhNwwVy%2FotUYzJ2OEt0DvmYwFfO3G4HVGV8qHMezrZl%2BDlPjTEiqyhGJNY0o8VJNgPQIEm0ty1O0L5UFBPtS1KXbCaYTUk8j258SoVQMPS438UGOqUBvKpEkUYaVgCRzjUR%2FZldhU5j3j7K%2FQaMUl6dyQEBTObMLMRndG69O6%2BmXG64%2Fr70Bfna5zX7dlSYIi%2FuoiJgFC2U7E%2BhMXIx%2Fj1G7uCZcCFxj%2FSQHZcSuTb06IrCq%2BR%2Bnk%2FNbUPVdqR27Iy5jWH1kwsToggvfdZZpu4uEANo2eIywrfnbeS9DFtIRvQ0QU1wX16503etcJfbx%2FkK5XctZJf6NccA&X-Amz-Signature=f38eb48ec7cf12e65f4309d7f2f18155ec4d49c9d0bf1c92e7b5e766e531cb1e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":10,"name":11,"image":7815,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4667JYBD3L7%2F20250903%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250903T073505Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjENb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJIMEYCIQDNcPq3tjGuMjsX2jiE05qzyBCZlZJd7vSyfz8pUACQIwIhALHMUKQBWe8Q50wZnCaM2SaWqzMy%2BNu6ui6T6FcbYUBXKv8DCD8QABoMNjM3NDIzMTgzODA1Igylzx0C5ER%2BTcsz62wq3ANW0VQXJ9phcHpCMqjXYADIQj83r%2BaNpCT7Avsl5pIFfcsm5sv2sIydUsNgPFEEjCO8sy4LVpeLZeZAIg6d8KZRDoSzoqXKjPIAmUTu5R6EKTr0lY0pNz9460KriIQEujLc75DMkbNskJsaCF%2F6w3x9siUXkK%2BMGKI6ctlRgN%2FGAmwE%2F326tODQ4dI%2Fnaiux%2BUqOvUbEqvoEUAQA65KDci%2FHPBYrrMl4Ux%2B8qGyPYwhpEPF5YVagJKyfVtbA0i47Res9FAF0IroZeKLwW%2FT%2Fj9nUOuA%2BdwkcXd9tgqIp97wVz7F%2FIZIssQqnGD%2BHRWCo8TLO0fPyHM3a9S1GxD2FaabMkyDQL2dx%2BKdd7tV5%2BqzmHf3GvnZG8mF89kIgAuXvyIkL6pnGPZ2c6yN4cLEpSEmjKJs7Eb2%2Bl9u2VCj06nkkwzioo88MiaMQY7uNLGZpZbzHBSezjp4A5XwZIenzSnmD7kFwmcN5jJ9WwyZkk8aiaL%2BLw0ZFI2Mn4V4kZjNHtshKyW%2B6SDW4dJ3m6e8Smzb0yfKsry2%2BIS2dQALSMF7IlcV2HBWQ3U6sTWshkQrk00%2FAkKoUQ9PHdKZw57AgSBIZKiAz5AWM23NJxP5TWLnhS%2FR4LIodJck3z4qUDCNud%2FFBjqkAb%2FKIeBwUN7B%2BizO9jiaQpFlaSZ5MsnstclqDJSmIUeBl8Blmoo47GyO%2FtAO1CdGW%2FigELwrrFw61xd6fJY3Nz4dSXi5YOnx%2BFhkOae0ulyDAgfBkSb%2BYocPzjqDI%2FFluWCHiB74bRqoTWIbj6n82U8uwSdMAV8JJ5vLDR%2B%2FcdZSj8pTeFbpMIcPn0Gyib7rryVu9ZVJeK%2B3HJnfWPSWggXfhLtU&X-Amz-Signature=8f393726be490557a096afcb84d2658e4eecb9f480bcbd1334ee2d4c7aa71a78&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":7245,"description":7806},"blogs\u002F2025-09-03-un-ide-avec-agent-ia-une-alternative-open-source-cursor-tout-ce-quil-faut-savoir-pour-bien-dmarrer-avec-void\u002Findex",[7819,7820,7821,7822,7073],"others","documentation","void","ide","DdcZCpXJfDb-grewP-bh1RjdNGzVaQihm_7bpcqssb0",{"id":7825,"title":7826,"alt":7827,"authors":7828,"body":7835,"date":8026,"description":8027,"extension":890,"image":891,"meta":8028,"navigation":893,"ogImage":891,"path":8029,"published":893,"reviewers":8030,"seo":8040,"stem":8041,"tags":8042,"__hash__":8045},"blogs\u002Fblogs\u002F2025-08-01-refactorer-sans-casser-le-golden-master-appliqu-un-outil-finops\u002Findex.md","Refactorer sans casser : le Golden Master appliqué à un outil FinOPS","Illustration d’un Golden Master sous forme de disquette",[7829,7834],{"id":7830,"name":7831,"image":7832,"linkedin":7833,"x":901},"23ff4462-cd38-8078-b550-c960c1e6ebdb","Sandrine Miras",".\u002Fassets\u002Fauthor-sandrine-miras.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fsandrine-miras\u002F",{"id":5813,"name":5814,"image":5815,"linkedin":5816,"x":901},{"type":16,"value":7836,"toc":8018},[7837,7841,7844,7847,7850,7854,7865,7874,7886,7891,7895,7902,7907,7911,7916,7933,7939,7945,7949,7954,7962,7967,7987,7991,8002,8006,8013,8016],[7089,7838,7840],{"id":7839},"refactorer-sans-casser-le-golden-master","Refactorer sans casser : le Golden Master",[19,7842,7843],{},"appliqué à un outil FinOPS",[19,7845,7846],{},"Refondre un outil critique sans casser l’existant ? Pas simple.\nLa mission était claire : continuer à faire évoluer la solution FinOPS de notre client tout en garantissant que chaque chiffre affiché reste juste. Parce qu’ici, une erreur, ça ne se compte pas en lignes de code… mais en euros.",[19,7848,7849],{},"Pour sécuriser le projet, Théo Lanord, consultant et développeur Full Stack chez HoppR, a choisi une arme simple et efficace : le Golden Master. Une pratique Craft qui n’est pas systématiquement utilisée, mais qui peut sauver un projet. On lui a demandé : pourquoi cette méthode, et qu’est-ce que ça change concrètement ?",[23,7851,7853],{"id":7852},"théo-cétait-quoi-le-contexte-quand-tu-es-arrivé-sur-le-projet","Théo, c’était quoi le contexte quand tu es arrivé sur le projet ?",[19,7855,7856,7859,2756,7862],{},[34,7857,7858],{},"Théo :",[1620,7860,7861],{},"« J’ai rejoint l’équipe tech d’un acteur majeur de la distribution présent dans plusieurs pays, qui développe et maintient des outils internes pour les entreprises du groupe.",[1620,7863,7864],{},"Leur mission est de fournir des services fiables et industrialisés à toutes les équipes de développement du groupe, pour qu’elles puissent livrer rapidement et en toute sécurité.",[19,7866,7867,7870,7871],{},[1620,7868,7869],{},"Pour ça, on s’appuie sur un écosystème"," allant de ",[1620,7872,7873],{},"GitHub pour le versioning, GitHub Actions pour automatiser les déploiements, SonarQube pour analyser la qualité du code, Ghas pour la sécurité, JFrog pour gérer les images, Jira pour le suivi et enfin Confluence pour la doc. Bref, un environnement complet mais complexe, où tout doit s’enchaîner sans faille.",[19,7875,7876,2756,7879,7882,7883],{},[1620,7877,7878],{},"Dans ce contexte, l’outil FinOPS est un produit clé. Il analyse la consommation des ressources Cloud et la traduit en euros permettant aux différentes entités du groupe de savoir combien elles dépensent et sur quoi.",[1620,7880,7881],{},"L’enjeu est fort"," puisque chaque entité ",[1620,7884,7885],{},"a ses propres projets, ses propres besoins, et doit pouvoir maîtriser ses coûts.",[19,7887,7888],{},[1620,7889,7890],{},"Avant, il y avait un budget global pour tout le monde. Aujourd’hui, on est dans une logique de refacturation interne par Business Unit. Ça change tout : chaque équipe doit rendre des comptes et optimiser sa consommation. Et cet outil est le cœur de ce pilotage. »",[23,7892,7894],{"id":7893},"où-se-situait-le-challenge-principal","Où se situait le challenge principal ?",[19,7896,7897,7899],{},[34,7898,7858],{},[1620,7900,7901],{},"« Le problème, c’est que l’entreprise utilisait déjà un outil FinOPS au quotidien. Mais on devait le faire évoluer sans compromettre son fonctionnement actuel. Or, il y avait peu de tests automatisés pour garantir que les comportements en place resteraient corrects.",[19,7903,7904],{},[1620,7905,7906],{},"Quand tu touches à un code hérité sans filet de sécurité, chaque modification est un pari risqué. Tu peux introduire des régressions invisibles… qui auront un impact direct sur la facturation et les arbitrages budgétaires. Et là, l’erreur ne se compte pas en millisecondes de temps de calcul mais en milliers d’euros. »",[23,7908,7910],{"id":7909},"pourquoi-avoir-choisi-le-golden-master","Pourquoi avoir choisi le Golden Master ?",[19,7912,7913],{},[1620,7914,7915],{},"« Parce qu’on avait besoin de figer le comportement actuel avant d’aller plus loin. Le Golden Master, c’est une pratique simple mais redoutablement efficace :",[443,7917,7918,7923,7928],{},[446,7919,7920],{},[1620,7921,7922],{},"On capture l’existant en enregistrant les entrées et sorties du système.",[446,7924,7925],{},[1620,7926,7927],{},"On crée une “photo” de référence qui servira de point de comparaison.",[446,7929,7930],{},[1620,7931,7932],{},"À chaque évolution, on compare les résultats à cette référence pour détecter toute régression.\nEn clair, c’est comme mettre un miroir en face du logiciel : tant que l’image reste identique, tu sais que tu n’as rien cassé. Ça nous a permis de refactorer, modulariser et optimiser le code en toute sérénité, sans réécrire tout le produit. »",[19,7934,1087,7935,7938],{},[34,7936,7937],{},"Pour résumer",", on peut définir le Golden Master comme une méthode de validation utilisée principalement dans les tests de non-régression. Elle consiste à conserver une version de référence du comportement attendu d’un système – souvent sous forme de données d’entrée et de sortie – afin de pouvoir comparer automatiquement les résultats des versions futures et garantir qu'aucune modification n’altère le fonctionnement prévu.",[19,7940,7941],{},[176,7942],{"alt":7943,"src":7944},"Mise en avant de l’importance de la comparaison des output dans le Golden Master","\u002Fcontent-assets\u002F2025-08-01-refactorer-sans-casser-le-golden-master-appliqu-un-outil-finops\u002Fassets\u002Fimg1.webp",[23,7946,7948],{"id":7947},"la-méthode-du-golden-master-est-parfois-critiquée-était-elle-la-meilleure-solution-dans-ce-contexte","La méthode du Golden Master est parfois critiquée. Était-elle la meilleure solution dans ce contexte ?",[19,7950,7951],{},[1620,7952,7953],{},"« Si tu pars from scratch, tu peux faire autrement. Mais dans une situation comme celle-ci, un outil critique, déjà en production, avec des impacts financiers, c’est une assurance vie. Le Golden Master, c’est comme mettre un filet sous un funambule : tu avances serein, tu sais que même si tu tombes, tu ne te blesseras pas.",[19,7955,7956,2756,7959],{},[1620,7957,7958],{},"A noter que",[1620,7960,7961],{},"ça ne remplace pas les tests unitaires ni le TDD. Ça vient en complément, comme un filet de sécurité quand tu n’as pas d’historique fiable. Et ça s’inscrit parfaitement dans une logique Craft : on ne fait pas de la qualité “pour faire joli”, on le fait pour apporter de la confiance et réduire le risque métier. »",[19,7963,7964],{},[34,7965,7966],{},"👉 Le Golden Master en 3 points clés :",[443,7968,7969,7975,7981],{},[446,7970,7971,7974],{},[34,7972,7973],{},"Objectif :"," prévenir les régressions dans un code hérité.",[446,7976,7977,7980],{},[34,7978,7979],{},"Quand l’utiliser :"," reprise de legacy sans confiance dans les tests actuels.",[446,7982,7983,7986],{},[34,7984,7985],{},"Limite :"," il ne valide pas la justesse métier, mais garantit la stabilité des comportements existants.",[23,7988,7990],{"id":7989},"et-concrètement-quel-a-été-limpact-pour-le-client","Et concrètement, quel a été l’impact pour le client ?",[19,7992,7993,2756,7996,2756,7999],{},[1620,7994,7995],{},"« On a pu faire évoluer le produit plus efficacement, avec moins de stress, parce qu’on savait qu’on ne casserait rien d’essentiel. L’équipe a gagné en sérénité, le client en fiabilité. Et au-delà de la technique, ça a changé notre",[1620,7997,7998],{},"posture",[1620,8000,8001],{},"en tant que consultant et celle de notre client en tant qu’utilisateur: on peut refactorer en toute confiance, innover sans risquer de mettre en péril la facturation. »",[23,8003,8005],{"id":8004},"si-tu-devais-résumer-pourquoi-le-craft-est-indispensable-dans-ce-genre-de-projet","Si tu devais résumer, pourquoi le Craft est indispensable dans ce genre de projet ?",[19,8007,8008,8010],{},[34,8009,7858],{},[1620,8011,8012],{},"« Parce que ça crée de la confiance. Pour les devs, qui savent qu’ils peuvent intervenir sans crainte. Pour le client, qui sait que son outil critique ne tombera pas à cause d’une évolution mal contrôlée. Et cette confiance, ça se traduit par plus de qualité, plus de sérénité et plus de vitesse. »",[19,8014,8015],{},"Chez HoppR, on croit que la qualité n’est jamais un luxe, mais une assurance. Le Golden Master est une des pratiques que nous utilisons, mais pas la seule : TDD, pair programming, revue de code… autant de leviers pour livrer des solutions robustes.",[19,8017,7788],{},{"title":350,"searchDepth":364,"depth":364,"links":8019},[8020,8021,8022,8023,8024,8025],{"id":7852,"depth":364,"text":7853},{"id":7893,"depth":364,"text":7894},{"id":7909,"depth":364,"text":7910},{"id":7947,"depth":364,"text":7948},{"id":7989,"depth":364,"text":7990},{"id":8004,"depth":364,"text":8005},"2025-08-01T14:37:21.374Z","appliqué à un outil FinOPS  Refondre un outil critique sans casser l’existant ? Pas simple. La mission était claire : continuer à faire évoluer la solution FinOPS de notre client tout en garantissant ",{},"\u002Fblogs\u002F2025-08-01-refactorer-sans-casser-le-golden-master-appliqu-un-outil-finops",[8031,8034,8039],{"id":8032,"name":8033,"image":901,"linkedin":901,"x":901},"197f4462-cd38-801b-859a-c33742e0ed0d","Pierre-Emmanuel Denys",{"id":8035,"name":8036,"image":8037,"linkedin":8038,"x":901},"174f4462-cd38-8061-bc88-f29602fcef5d","Guillaume Ferlin","https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F27c18bae-6c33-403c-b7fd-7d46ce96c376\u002FGuillaume_Ferlin_Image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466ULFPFZUH%2F20250801%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250801T143721Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEMb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJGMEQCIG1mqZcKiAMfFxyUrFUGHfaT4CcUgj%2BLoBszrMnBcKdXAiAzDBfUqsdSt4Q4ipOxsQZieesJXoa7qrGJlD350URqQiqIBAjv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDYzNzQyMzE4MzgwNSIMdcI0v36Q64VtIlbtKtwDL%2BNrlFhdx1Ke4l94CtVPwXsIzuwNu4ZcUAnnbi29HkBC9nOvGrDrEzbdydY0p6ZBhhd3md7q1HhIgSeKa7dyJN84TeFlkYMgZCqmV2unHi2B%2FOvARfm7%2FhpF7VKbXYFsssXA7%2Bojou0hb%2BeRXUjjqCHJ%2B4l%2B7wkgzufa9aS4OaGfoJj%2Bld06GnqJMjNrzMpCcjxyzOo5BUDGxv8H8Q%2FEZCQKeeG%2B%2BlffOAHpbcaa4YGG6ebhh4PwCZNiJtrMsLlTT076jFJEYyG%2FIUmyXY4pwPYuhX3kceWV2%2FFdZ7xLvvLK3STrjdcHfinSzf2bvjKmSInnRVf27B7QpS0SlvzQBtEX2g4EI7bUDbw2z5x4pgPfhceoX6R2yZFzaC48izTkcsmmwOQLDY6Rl8iAShSURx%2FM1JLq0ThwFdiAosmqhKfgxrbfOMr9KcPyfPdXPWmstqwaMS%2BJdk19a21v0ttyf84J3D6hCTKffSJFn7jsqJcyq78gEqO%2BTUkrs%2BAgLlQSz7kXSXYTkSmI8xTtl8FYscnz61uH2KOCBJlHLjZMCm4ElhjNho1hCnj9FJOQQfXHxJzBtxnkb%2Bs%2B9BAcvtzVNIdr0zxoPc5qttMsp9p88RALtgdpzRGjaWXRUtYwkZazxAY6pgFtPfWHqkUKY%2B2ZtC9UZtQu8d9o%2BD1i%2Bqs2B8iimvVqpJnlCAkGL3KSV%2FlDPd0PrFfrsiTf1gF4CPLtVb1N68fdMMUv8TCpVC0sFfHn0jeqyzT3FBPezG14nCfqkWX8j9%2BjSxTk7XNBg1y5YP0c0GoLFvWODluLCeivL8O%2Fq%2BwV8BmSxNj8HIaH5NBPkmvFN13vcIrHIoEQ41kIRqSdpc5l8AttcKt3&X-Amz-Signature=b37ba0b7d8ebcfef63a5b3d2f7b75ff8c4c2539d2f6e8b41d1a5d76e62704901&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fguillaume-ferlin-262681272\u002F",{"id":1893,"name":1894,"image":901,"linkedin":901,"x":901},{"title":7826,"description":8027},"blogs\u002F2025-08-01-refactorer-sans-casser-le-golden-master-appliqu-un-outil-finops\u002Findex",[1879,6271,8043,8044],"test","testing","ZT0RlBGevXEZHXtRzxGch5IAXtpbuMXUx09jvD3lJyI",{"id":8047,"title":8048,"alt":8049,"authors":8050,"body":8052,"date":8179,"description":8180,"extension":890,"image":891,"meta":8181,"navigation":893,"ogImage":891,"path":8182,"published":893,"reviewers":8183,"seo":8188,"stem":8189,"tags":8190,"__hash__":8192},"blogs\u002Fblogs\u002F2025-07-16-from-scratch-to-craft-lhistoire-dun-programme-de-formation-pas-comme-les-autres\u002Findex.md","From Scratch to Craft : l’histoire d’un programme de formation pas comme les autres","Photo de Edouard pour illustrer le parcours de formation mis en place",[8051],{"id":897,"name":898,"image":7084,"linkedin":900,"x":901},{"type":16,"value":8053,"toc":8172},[8054,8062,8066,8084,8087,8091,8094,8108,8111,8115,8124,8127,8138,8142,8145,8156,8160,8163],[19,8055,8056,8057,8061],{},"Chez HoppR, la montée en compétences ne se décrète pas, elle se cultive. Et qui\nmieux qu'",[91,8058,8060],{"href":1890,"rel":8059},[95],"Édouard Cattez, Head of Craft",", pour incarner cette exigence de qualité et\ncette envie de transmettre ? On est allé lui poser quelques questions sur From\nScratch to Craft, le programme de formation qu’il a conçu et porté tout au long de\nl’année. Un parcours ambitieux, intensément pratique, profondément ancré dans la\nréalité terrain des missions chez nos clients.",[23,8063,8065],{"id":8064},"doù-est-venue-lidée-de-ce-programme","D’où est venue l’idée de ce programme ?",[1003,8067,8068],{},[19,8069,8070,8071,8074,8075,8077,8078,8080,8081,8083],{},"J’ai eu l’occasion de participer à de nombreuses formations dans mes expériences",[8072,8073],"br",{},"\nprécédentes. Mais, souvent, les sujets étaient abordés trop en surface. Pas assez",[8072,8076],{},"\nconcret, pas assez challengeant. Alors quand j’ai eu l’opportunité de créer un cycle",[8072,8079],{},"\nchez HoppR, je suis reparti de zéro avec une idée en tête : transmettre ce que",[8072,8082],{},"\nj’aurais aimé recevoir.",[19,8085,8086],{},"From Scratch to Craft est né d’un double besoin : structurer la formation continue\nchez HoppR, et incarner notre vision exigeante du Craft, à la croisée des\ncompétences techniques et du savoir-être. Le programme aborde bien sûr des sujets\npointus (TDD, DDD, architecture...), mais surtout, il forme à ce qui fait vraiment la\ndifférence sur le terrain : la posture, la communication, la conduite du changement.\nParce que le développement ne se résume pas seulement au code, mais à notre capacité à\nfaire équipe, à convaincre, à embarquer.",[23,8088,8090],{"id":8089},"une-boîte-à-outils-technico-humaine","Une boîte à outils technico-humaine",[19,8092,8093],{},"Le programme vise principalement les consultants tech (développeurs, testeurs,\narchitectes), mais touche aussi les Product Owners. Il propose un enchaînement\nlogique de modules, avec une vraie progression sur l’année.",[1003,8095,8096],{},[19,8097,8098,8099,8101,8102,8104,8105,8107],{},"Chaque thème est abordé de manière hybride : 1 à 2 jours de formation (dont 70%",[8072,8100],{},"\nde pratique), puis on revient dessus un mois plus tard avec un cas client réel en",[8072,8103],{},"\nintroduisant les katas, des exercices répétés pour gagner en fluidité, en réflexe.",[8072,8106],{},"\nCar c’est la pratique qui fait l’expert !",[19,8109,8110],{},"Et bientôt, les katas soft skills feront leur apparition: vulgarisation, diplomatie, réaction sous pression, … autant de sujets qui serviront à muscler les compétences transverses.",[23,8112,8114],{"id":8113},"formation-et-esprit-déquipe","Formation, et esprit d’équipe",[19,8116,8117,8118,6547,8121],{},"Comme partout, la formation a beaucoup de vertus. Mais chez HoppR, c’est aussi\nun temps fort pour les équipes. Faire collectif, quand on est chacun impliqués dans\ndes missions différentes sur le terrain, ça n’est pas toujours facile. C’est rare de tous\nse retrouver. Ce programme de formation nous permet ces temps de partage et aussi\nde convivialité. Cela nourrit le sentiment d’appartenance et ça consolide notre collectif,\n",[34,8119,8120],{},"fait rare à souligner, dans le monde des ESN",[34,8122,8123],{},"!",[19,8125,8126],{},"Le format hybride de From Scratch to Craft, pensé pour durer, intègre également une\ndimension collaborative forte : les consultants sont invités à co-construire les\nmodules.",[1003,8128,8129],{},[19,8130,8131,8132,8134,8135,8137],{},"Quand Bastien m’a dit qu’il voulait enrichir la partie front-end, je lui ai répondu :",[8072,8133],{},"\n”Super, tu vas la faire !”. Il est devenu le premier à rejoindre l’équipe pédagogique. Et",[8072,8136],{},"\nil ne sera pas le dernier.",[23,8139,8141],{"id":8140},"un-programme-vivant-au-service-du-terrain","Un programme vivant, au service du terrain",[19,8143,8144],{},"La vocation de From Scratch to Craft ne s’arrête pas aux frontières de HoppR. Le programme s’ouvre aussi à l’extérieur : des sessions sur-mesure sont proposées chez les clients, et 1 à 2 personnes extérieures peuvent rejoindre certaines de nos sessions. Une façon de faire rayonner la vision Craft HoppR au-delà de nos murs.",[1003,8146,8147],{},[19,8148,8149,8150,8152,8153,8155],{},"Ce que j’aime, c’est que ce programme est en constante évolution. Il vit, il",[8072,8151],{},"\ns’améliore, il m’oblige à me remettre en question. Les participants me challengent, et",[8072,8154],{},"\nc’est tant mieux.",[23,8157,8159],{"id":8158},"en-conclusion","En conclusion ?",[19,8161,8162],{},"From Scratch to Craft, c’est plus qu’un programme de formation : c’est un levier de\ntransformation. Une réponse concrète à notre volonté de cultiver l’excellence, de\njouer collectif, et de faire grandir chacun au service des projets de demain.",[19,8164,8165,8166,8171],{},"Tu souhaites nous rejoindre ou en savoir plus sur le programme de formation, ",[91,8167,8170],{"href":8168,"rel":8169},"https:\u002F\u002Fwww.hoppr.tech\u002Fcontact",[95],"contactes-nous"," pour qu’on en discute !",{"title":350,"searchDepth":364,"depth":364,"links":8173},[8174,8175,8176,8177,8178],{"id":8064,"depth":364,"text":8065},{"id":8089,"depth":364,"text":8090},{"id":8113,"depth":364,"text":8114},{"id":8140,"depth":364,"text":8141},{"id":8158,"depth":364,"text":8159},"2025-07-16T20:45:04.885Z","Chez HoppR, la montée en compétences ne se décrète pas, elle se cultive. Et qui mieux qu'[Édouard Cattez, Head of Craft](https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fedouard-cattez-865794133\u002F), pour incarner cette exi",{},"\u002Fblogs\u002F2025-07-16-from-scratch-to-craft-lhistoire-dun-programme-de-formation-pas-comme-les-autres",[8184,8186],{"id":1577,"name":1578,"image":8185,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466U7TKQO3I%2F20250716%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250716T204504Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEsaCXVzLXdlc3QtMiJHMEUCICDbo4xi5KAjQwIagyPdYh99gyhgxwCFXDh%2FtlctDquUAiEAxDVnKiTszM9vbXOYsJ9pp8IGwqaV1Lw05S6jMAh1gfAq%2FwMIZBAAGgw2Mzc0MjMxODM4MDUiDDyJGyVa%2Bq8DAPx4EyrcA1s28cZsrdqO6XV%2FHwdE4DKwmlnCmZ33wNtXYoKt7tyBTdZBYKAKa0EUpSRaVcfMt6BPuF93MzaITpZdT5kDy89U74TkFIu8n66ORUDa5ncWNd%2BRO5sqM3ro27RJzw3B9rxmKccbYaATUEc6j2RTRdqPGfB86nSMIvtdgBBLmG4INhEEVsyBGvu7pK5%2FuQNom0Z96yCwc%2BI2H2KvfIKYHNE%2Fi5aAJ8Ue8qinrx7whK%2FhMuC%2F04aeD1jtUmuMoBrx%2B4ey8ykZysOA%2F%2FF7Y3%2F5%2BKmxZ5aHgX7ujJnjSpf5XDavGwziiSyiYbeP0iv7UpEy1Z6qiw1PcVR6yonJelCGcmqyJrpzJdnTBQmD7eiKQjKEO6U7WYVdhtrwotj%2BLo%2Fi4fBZ4Cl6NqeZ5PLtz4eh1Rg3Ij3mSXEmsvQsiSGhHCE6C12BY%2Fes448t%2FpzoYKM6ydv8EAnXrhSwHFU2Ul54jF%2FA6VvultCk%2BmHelpa9camWTVKvQqluR6yPYQFmVIUuROMFbR4mFN3ofYM2qg1V4AdJQC4vK%2FTT82KqxaWc%2BsW5YvXKRFYjYrQg9wtCe6VQAP9wPqUtROyfmP3DnmD8%2FMBsxW0g0JCPo8qpZleQXCayQB8r7ub%2F%2BlNGQ1fZMJnx38MGOqUBkptv2EzREwYg4l4XXTLxOmeSXv9U4OQXpNpXJ4B8odw1UykQ5U4RnOZWb4RvvdzgXRTt%2BqJ73bWwk6Hg4K%2FC300uUfylOk2rYU%2FU0Qu2e%2FDwGNBab%2FtpKayFVsv0euYJC8v5Fcn7466msz1ldykBni9%2FaruPw1f7WrCwWIkIsZervdb%2BR61TnhYEgn%2B3thOj7Nhbif%2BjJWMQ6bz7CfhO200F8h6b&X-Amz-Signature=540d13d7cc41550adf5daa489136f608ef50963b854db5adf064af742449f811&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"id":5813,"name":5814,"image":8187,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466722KP3K4%2F20250716%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250716T204504Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEEsaCXVzLXdlc3QtMiJHMEUCIB5GvSuuDzEYfv4i2hCyYt%2BYu9OJo7gYBfTc2QldnDYgAiEAzjQLeem2Wv2i2NuM2gknT3WMTqU%2BPx%2FhKdmBGzirQWIq%2FwMIZBAAGgw2Mzc0MjMxODM4MDUiDDNKg4BprosexZXFoyrcAwoy426ercVBglCE4GA23T0k2Ler9M56hfivSgUctexU43GQu1VPISO40kjkNddR1zLLcQ1xJDsYYeWyZ1nKwNx4ubdIsXAu20KIMpsi4NZCljjXn4PO1zoeZuurVY17hOJ3EMkiV%2Bf4o39RyGLdHLBs%2BIQXTVivwuoTnzfrulfCCbaScUq20Hf8UrHSzLqtaCWCn07IjQViNT9znpvFd8Q%2BioGfGN84Fm2zVZwl20Yx10mny6IsD4GUu%2FkIRM9UVrm4S%2BxNBFQmTxncWbSLSumJYdJAN%2Ffj8v6qgsPjXX1YCYBbglbnu%2BS1o4ppZBdYbPXKasyNNdKE7SfWpYhgrKXwGJROyvNC3oqFT%2BY5RnZKZicIItjju%2BYR7%2BxDnfqzgFJXBHn1s%2FXqbGSQ%2BeKd5JN%2Frg1tkdXfXv1uf1Hl%2BeWUJh%2B6hI4BD190y7ZoVvlv%2BvAwa9XXXiSV4nfj62pj9J83ZIdY7NOJCTzEohuqlF8CjQf7CZYXluJDaoSwwISUmfGQCO4hmCj6ga3wozNSZ2PaZw7m4FYeEKMK7fp2X554bMQtKlJX8ybTdivQJOSNOGRbvs%2BTG1Z95WrTstAwhqvJ4KfyD2uoIEbWuBr58BvqeJVOFrkR1y%2BAiPKAMIXx38MGOqUBaHdkT3H%2FYUC9up1N8bRUAnePswcVfVTi%2BLVhi8%2BE%2BYC%2BjUqCPtrB6p0Kffrlfqtz5Mabc8mKeg7na6SPChM6rZyPBjFoexdW06d3DONP8bHg%2FmNhs858Ut%2F%2B9sKukMdo%2F%2Bi6jvnMLj05IK4JLSR316cXkhwG06JopOdF3Zz0DqI%2FAQggtCSx5O6ngP78c%2BMljnP06J5cT1KE5pMQpgDnWAbuhTwQ&X-Amz-Signature=0c38dd95cbd6ed09ac9ca54775344260cdea0491685ca2bc849d653ae577b709&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject",{"title":8048,"description":8180},"blogs\u002F2025-07-16-from-scratch-to-craft-lhistoire-dun-programme-de-formation-pas-comme-les-autres\u002Findex",[1879,8191],"formation","Q7gBesYsq195cVV6WdoQPxFK6hsJAHwrE522TSvhFog",{"id":8194,"title":8195,"alt":8196,"authors":8197,"body":8199,"date":17848,"description":17849,"extension":890,"image":891,"meta":17850,"navigation":893,"ogImage":891,"path":17851,"published":893,"reviewers":17852,"seo":17859,"stem":17860,"tags":17861,"__hash__":17863},"blogs\u002Fblogs\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Findex.md","Bref, j’ai mis en place les DORA Metrics dans un grand groupe ! (REX 🦖)","Image abstraite représentant les metrics avec un tyrannosaure pour illustrer le REX",[8198],{"id":10,"name":11,"image":12,"linkedin":13,"x":14},{"type":16,"value":8200,"toc":17803},[8201,8213,8229,8232,8236,8240,8243,8246,8257,8260,8280,8286,8290,8298,8304,8314,8317,8331,8335,8338,8342,8347,8361,8364,8368,8373,8394,8399,8402,8409,8413,8418,8429,8434,8454,8459,8462,8465,8469,8474,8488,8493,8504,8514,8518,8521,8550,8554,8559,8573,8578,8581,8584,8588,8596,8599,8603,8608,8623,8628,8639,8643,8648,8659,8664,8672,8676,8681,8689,8694,8702,8706,8711,8722,8727,8738,8742,8747,8758,8763,8774,8777,8781,8789,8793,8798,8801,8815,8818,8822,8937,8941,8993,8997,9051,9055,9063,9067,9070,9077,9080,9099,9105,9112,9181,9453,9456,9459,9466,9469,9472,9492,9879,9882,9889,9892,9912,10219,10222,10226,10234,10237,10243,10249,10255,10259,10264,10712,10715,10975,10980,11359,11361,11561,11566,11936,11938,12140,12145,12518,12520,12719,12722,12726,12977,12979,13116,13120,13329,13331,13416,13420,13629,13631,13715,13719,13937,13939,14023,14026,14030,14035,14039,14326,14328,14464,14468,14776,14778,14834,14838,15146,15148,15204,15208,15212,15217,15221,15508,15510,15665,15669,15893,15895,15914,15918,16141,16143,16162,16166,16172,16194,16197,16201,16438,16624,16628,16639,16869,16873,16884,17256,17260,17271,17368,17372,17377,17388,17393,17404,17409,17420,17425,17428,17572,17577,17580,17591,17594,17598,17605,17622,17625,17636,17640,17647,17650,17653,17657,17664,17667,17671,17678,17681,17684,17704,17707,17711,17714,17746,17750,17753,17773,17776,17779,17782,17785,17800],[19,8202,8203,8204,8208,8209,8212],{},"Nouvel article qui fait suite à mon ",[91,8205,8207],{"href":1811,"rel":8206},[95],"introduction aux DORA Metrics"," 🎉 \nPour rappel, je vous avais défini les ",[34,8210,8211],{},"4 métriques (4 Keys)"," qui permettent de mesurer l'efficacité de la livraison logicielle:",[1003,8214,8215],{},[19,8216,8217,8220,8221,8220,8223,8220,8226],{},[34,8218,8219],{},"Deployment Frequency"," | ",[34,8222,5384],{},[34,8224,8225],{},"Mean Time to Restore",[34,8227,8228],{},"Change Failure Rate",[19,8230,8231],{},"Aujourd'hui, je vous partage mon retour d'expérience (REX) sur leur mise en place chez un client qui souhaitait objectiver et améliorer sa performance de livraison.",[23,8233,8235],{"id":8234},"_1-comprendre-lorganisation-et-définir-les-concepts","1. Comprendre l'organisation et définir les concepts 🏢",[84,8237,8239],{"id":8238},"lorganisation-du-groupe","L'organisation du groupe",[19,8241,8242],{},"Lorsque je suis arrivé chez ce client, j'ai pu constater qu'il y avait de nombreux produits (> 1000) avec des technologies hétérogènes. Mais d'ailleurs, c'est quoi un produit ? La première chose à faire a été de se mettre d'accord sur les définitions !",[19,8244,8245],{},"L'organisation de l'entreprise était la suivante :",[443,8247,8248,8251,8254],{},[446,8249,8250],{},"Le groupe est divisé en plateformes",[446,8252,8253],{},"Les plateformes sont divisées en domaines",[446,8255,8256],{},"Les domaines sont divisés en produits",[19,8258,8259],{},"Après quelques ateliers avec le management et des projets pilotes, nous sommes tombés d'accord sur les définitions suivantes :",[443,8261,8262,8268,8274],{},[446,8263,8264,8267],{},[34,8265,8266],{},"Plateforme"," : Niveau le plus haut de l'organisation, regroupe plusieurs domaines fonctionnels liés",[446,8269,8270,8273],{},[34,8271,8272],{},"Domaine"," : Regroupe des produits ayant des fonctionnalités similaires ou complémentaires",[446,8275,8276,8279],{},[34,8277,8278],{},"Produit"," : Périmètre fonctionnel perceptible par l'utilisateur final, pour lequel les changements lui sont communiqués. Un produit peut être composé de plusieurs composants (microservices ou briques monolithiques) et peut être déployé sur différents environnements de production",[19,8281,8282],{},[176,8283],{"alt":8284,"src":8285},"Schéma d’organisation d’un site e-commerce : la plateforme Commerce regroupe les domaines E-Commerce (catalogue, panier, commande web) et Magasins (catalogue, caisse, commande magasin) ; la plateforme Gestion Clients regroupe les domaines Comptes Clients (gestion client web, magasin, data compliance) et Fidélité (programme de fidélité, newsletters).","\u002Fcontent-assets\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Fassets\u002Fdora_metrics-exemple_orga.webp",[84,8287,8289],{"id":8288},"les-cas-dusage-identifiés","Les cas d'usage identifiés",[19,8291,8292,8293,44],{},"Une fois l'organisation de la société comprise et les concepts définis, il a fallu comprendre tous les cas d'usage des DORA Metrics avec des ateliers comme l'",[91,8294,8297],{"href":8295,"rel":8296},"https:\u002F\u002Fdraft.io\u002Ffr\u002Fexample\u002Fexample-mapping",[95],"Example Mapping",[19,8299,8300],{},[176,8301],{"alt":8302,"src":8303},"Tableau Example Mapping avec quatre catégories : User Stories (jaune), Rules (bleu), Examples (vert), Questions (rose), chacune contenant des post-its de la couleur correspondante.","\u002Fcontent-assets\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Fassets\u002Fexample_mapping.webp",[1003,8305,8306],{},[19,8307,8308,8309,8313],{},"ℹ️ N’hésitez pas à consulter ",[91,8310,8312],{"href":6550,"rel":8311},[95],"notre offre de formations"," si vous souhaitez approfondir vos connaissances Craft et pratiquer ce type d’atelier.",[19,8315,8316],{},"Je ne veux pas vous mettre tous les cas d'usage, car ça serait trop long et ce n'est pas l'objectif de l'article, mais je vais vous donner quelques exemples :",[443,8318,8319,8322,8325,8328],{},[446,8320,8321],{},"En tant que CTO, je souhaite comparer les performances de livraison entre les plateformes (par exemple entre la plateforme Commerce et la plateforme Gestion Clients) pour identifier les meilleures pratiques DevOps à généraliser au niveau du groupe.",[446,8323,8324],{},"En tant que Lead Tech d'un produit e-commerce, je souhaite comparer nos métriques avec celles des autres produits du domaine Commerce (comme le panier ou le catalogue) pour comprendre pourquoi leurs déploiements génèrent moins d'incidents en production.",[446,8326,8327],{},"En tant que Domain Leader Catalogue, je souhaite analyser l'impact du multi-instance sur la fréquence de déploiement. Par exemple, comprendre si les produits déployés sur plusieurs environnements de production (pour différentes BU) ont plus de difficultés à maintenir un rythme de livraison élevé et si oui, comprendre les causes.",[446,8329,8330],{},"En tant que Product Owner, je veux suivre l'évolution de nos métriques après le passage d'une architecture monolithique à des microservices, notamment pour vérifier si la fréquence de déploiement de chaque composant s'améliore comme prévu.",[23,8332,8334],{"id":8333},"_2-les-défis-techniques-et-organisationnels","2. Les défis techniques et organisationnels 🔧",[19,8336,8337],{},"La mise en place des DORA Metrics dans un groupe de cette taille présentait beaucoup de défis majeurs. Avec mon client, nous avons fait le choix d'implémenter les DORA Metrics uniquement sur les produits déployés sur Kubernetes (cela représente environ 80% des produits). Voici les principaux obstacles que nous avons dû surmonter :",[84,8339,8341],{"id":8340},"une-architecture-complexe-à-appréhender","Une architecture complexe à appréhender",[19,8343,8344],{},[34,8345,8346],{},"L'entreprise comportait :",[443,8348,8349,8352,8355,8358],{},[446,8350,8351],{},"Plus de 1000 produits utilisant des technologies différentes",[446,8353,8354],{},"Des produits déployés plusieurs fois pour différentes BU",[446,8356,8357],{},"Un mix d'architectures monolithiques et microservices",[446,8359,8360],{},"Des relations complexes entre composants et produits",[19,8362,8363],{},"Face à cette complexité, nous avons adopté une approche pragmatique : sélectionner quelques produits pilotes représentatifs de l'écosystème pour implémenter les DORA Metrics. Après avoir validé notre méthodologie sur ces cas concrets, nous avons pu déployer progressivement la solution à l'ensemble du portefeuille de produits.",[84,8365,8367],{"id":8366},"des-données-éparpillées","Des données éparpillées",[19,8369,8370],{},[34,8371,8372],{},"Il fallait collecter les données depuis :",[443,8374,8375,8382,8388],{},[446,8376,8377,8378,8381],{},"Les clusters ",[34,8379,8380],{},"Kubernetes"," pour les logs de déploiements",[446,8383,8384,8387],{},[34,8385,8386],{},"GitHub"," pour l'historique des versions",[446,8389,8390,8393],{},[34,8391,8392],{},"ServiceNow"," pour les incidents",[19,8395,8396],{},[34,8397,8398],{},"Le véritable défi ? Corréler ces données hétérogènes pour obtenir une vision cohérente !",[19,8400,8401],{},"Cette mission a nécessité une collaboration transverse entre plusieurs équipes techniques. Nous avons conçu une architecture cloud robuste pour centraliser l'ensemble des données dans une base de données BigQuery. Cette solution nous a d'ailleurs poussés à optimiser nos requêtes et l'utilisation de BigQuery car nous atteignions rapidement les limites de performance 😅.",[19,8403,8404,8405,8408],{},"L'objectif final était de disposer d'un référentiel unique permettant d'exécuter des requêtes SQL complexes ",[1620,8406,8407],{},"(cf l’implémentation des métriques plus bas dans cet article)"," pour calculer précisément nos métriques DORA.",[84,8410,8412],{"id":8411},"des-pratiques-devops-non-standardisées","Des pratiques DevOps non standardisées",[19,8414,8415],{},[34,8416,8417],{},"Une partie des équipes avait :",[443,8419,8420,8423,8426],{},[446,8421,8422],{},"Leur propre workflow de déploiement",[446,8424,8425],{},"Leurs conventions de versioning",[446,8427,8428],{},"Leur façon de gérer les environnements de production",[19,8430,8431],{},[34,8432,8433],{},"Il a fallu aider ces équipes à adopter les bonnes pratiques du groupe à savoir :",[443,8435,8436,8445,8448,8451],{},[446,8437,8438,8439,8444],{},"la norme ",[91,8440,8443],{"href":8441,"rel":8442},"https:\u002F\u002Fsemver.org\u002Flang\u002Ffr\u002F",[95],"SemVer"," pour le versioning",[446,8446,8447],{},"l'utilisation des solutions groupe pour déployer leurs produits sur Kubernetes",[446,8449,8450],{},"la déclaration systématique des incidents dans ServiceNow",[446,8452,8453],{},"etc.",[19,8455,8456],{},[34,8457,8458],{},"La standardisation des pratiques DevOps : un prérequis indispensable aux DORA Metrics",[19,8460,8461],{},"Ce chantier d'harmonisation, bien que colossal pour une organisation de cette envergure, s'est révélé être un puissant levier de transformation ! Même si des standards existaient déjà, les DORA Metrics ont agi comme un révélateur implacable : les projets ne respectant pas les bonnes pratiques étaient immédiatement identifiables par l'absence de données exploitables pour le calcul des métriques.",[19,8463,8464],{},"Cette transparence a créé une incitation naturelle à l'adoption des standards du groupe, bien plus efficace qu'une simple directive top-down.",[84,8466,8468],{"id":8467},"des-données-pas-toujours-fiables","Des données pas toujours fiables",[19,8470,8471],{},[34,8472,8473],{},"Les principaux problèmes :",[443,8475,8476,8479,8482,8485],{},[446,8477,8478],{},"Pas de standard dans le nommage des composants",[446,8480,8481],{},"Des déploiements de configuration qui polluaient les métriques",[446,8483,8484],{},"Une difficulté à identifier les vrais déploiements en production",[446,8486,8487],{},"Des annotations manquantes ou incohérentes",[19,8489,8490],{},[34,8491,8492],{},"Pragmatisme et itération : la clé du succès en environnement réel",[19,8494,8495,8496,8499,8500,8503],{},"Face à l'imperfection inévitable des données en contexte d'entreprise de grande taille, nous avons adopté une approche pragmatique : formuler des ",[34,8497,8498],{},"hypothèses"," clairement documentées et acceptées par toutes les parties prenantes. Ces conventions, bien qu'imparfaites, nous ont permis d'",[34,8501,8502],{},"avancer sans attendre la perfection"," qui arrivera sans doute jamais.",[19,8505,8506,8507,8510,8511,44],{},"Cette démarche s'alignait parfaitement avec la philosophie des DORA Metrics : l'objectif n'est pas d'atteindre une précision absolue, mais de capturer des ",[34,8508,8509],{},"tendances"," significatives permettant d'",[34,8512,8513],{},"orienter l'amélioration continue",[84,8515,8517],{"id":8516},"une-organisation-multi-niveaux-à-respecter","Une organisation multi-niveaux à respecter",[19,8519,8520],{},"Il fallait :",[443,8522,8523,8530,8537,8544],{},[446,8524,8525,8526,8529],{},"Fournir des ",[34,8527,8528],{},"vues adaptées"," à chaque niveau (plateforme, domaine, produit)",[446,8531,8532,8533,8536],{},"Prendre en compte les ",[34,8534,8535],{},"particularités"," de chaque BU",[446,8538,8539,8540,8543],{},"Garder des ",[34,8541,8542],{},"métriques comparables"," malgré les différences",[446,8545,8546,8549],{},[34,8547,8548],{},"Accompagner"," les équipes vers de meilleures pratiques",[84,8551,8553],{"id":8552},"la-dimension-humaine-à-ne-pas-négliger","La dimension humaine à ne pas négliger",[19,8555,8556],{},[34,8557,8558],{},"Nous avons rapidement identifié des craintes légitimes :",[443,8560,8561,8564,8567,8570],{},[446,8562,8563],{},"Peur d'être jugé uniquement sur des chiffres et que les métriques servent à comparer les équipes entre elles",[446,8565,8566],{},"Tentation de biaiser le système (par exemple en multipliant volontairement les déploiements inutiles pour améliorer artificiellement la fréquence)",[446,8568,8569],{},"Réticence à reporter certains incidents pour ne pas impacter le Change Failure Rate",[446,8571,8572],{},"Difficultés à voir les DORA metrics comme outil d'amélioration continue",[19,8574,8575],{},[34,8576,8577],{},"Notre approche : transformer les résistances en adhésion",[19,8579,8580],{},"Plutôt que d'imposer un système de mesure, nous avons choisi d'impliquer les équipes dans sa construction. Nous avons organisé des ateliers de sensibilisation, partagé les objectifs stratégiques derrière ces métriques, et surtout, écouté les préoccupations des équipes.",[19,8582,8583],{},"Cette démarche participative a permis de transformer progressivement la perception des DORA Metrics : d'un outil potentiellement menaçant de surveillance, elles sont devenues un levier d'amélioration continue valorisé par les équipes elles-mêmes.",[23,8585,8587],{"id":8586},"_3-hypothèses-techniques-retenues","3. Hypothèses techniques retenues 🧐",[1003,8589,8590],{},[19,8591,8592,8595],{},[34,8593,8594],{},"Fondations solides : établir des conventions claires et partagées","\nPour bâtir un système de mesure fiable dans un environnement complexe, nous avons dû établir un ensemble d'hypothèses et de conventions. Elles ont été clairement documentées et validées collectivement et elles étaient nécessaires pour calculer les métriques avec des données imparfaites.",[19,8597,8598],{},"Voici les principales conventions que nous avons établies, organisées par domaine :",[84,8600,8602],{"id":8601},"déploiements","Déploiements 🚀",[19,8604,8605],{},[34,8606,8607],{},"Identification des déploiements en production",[443,8609,8610,8613,8620],{},[446,8611,8612],{},"Un déploiement est considéré réussi uniquement quand :",[446,8614,8615,8616,8619],{},"Seuls les déploiements avec l'annotation ",[352,8617,8618],{},"info\u002Fenvironment = prod"," sont pris en compte",[446,8621,8622],{},"Les déploiements de configuration pure sont exclus des métriques",[19,8624,8625],{},[34,8626,8627],{},"Impact utilisateur",[443,8629,8630,8633,8636],{},[446,8631,8632],{},"Un déploiement en production impacte potentiellement l'utilisateur final",[446,8634,8635],{},"Un produit peut être déployé sur plusieurs workspaces (namespace\u002Fcluster)",[446,8637,8638],{},"Une modification d'un composant ou de sa configuration implique une modification du produit",[84,8640,8642],{"id":8641},"lead-time-for-changes-️","Lead Time For Changes ⏱️",[19,8644,8645],{},[34,8646,8647],{},"Traçabilité du code",[443,8649,8650,8653,8656],{},[446,8651,8652],{},"Le code source mentionné dans l'annotation est responsable du déploiement du composant",[446,8654,8655],{},"La correspondance dans le repository Git est matérialisée par un tag",[446,8657,8658],{},"Le temps entre un commit et son tag est négligeable pour le calcul global",[19,8660,8661],{},[34,8662,8663],{},"Limitations acceptées",[443,8665,8666,8669],{},[446,8667,8668],{},"Seuls les tags respectant la norme SemVer sont pris en compte",[446,8670,8671],{},"Les configurations d'environnement sans code source associé créent des déploiements multiples pour une même version",[84,8673,8675],{"id":8674},"incidents-et-récupération","Incidents et récupération 🚨",[19,8677,8678],{},[34,8679,8680],{},"Temporalité des incidents",[443,8682,8683,8686],{},[446,8684,8685],{},"Le temps entre l'apparition réelle d'un incident et son ouverture dans l'outil est considéré comme négligeable",[446,8687,8688],{},"Tous les incidents reportés (automatiquement ou manuellement) ont un impact utilisateur",[19,8690,8691],{},[34,8692,8693],{},"Association déploiement-incident",[443,8695,8696,8699],{},[446,8697,8698],{},"Le déploiement le plus récent d'un composant du produit avant la création de l'incident est considéré comme la cause",[446,8700,8701],{},"En l'absence d'information sur l'instance spécifique, l'incident est associé au produit dans son ensemble",[84,8703,8705],{"id":8704},"structure-organisationnelle","Structure organisationnelle 🏢",[19,8707,8708],{},[34,8709,8710],{},"Définition d'un produit",[443,8712,8713,8716,8719],{},[446,8714,8715],{},"Un produit est un périmètre fonctionnel perceptible par l'utilisateur final",[446,8717,8718],{},"Un produit peut être composé de plusieurs composants (microservices ou briques monolithiques)",[446,8720,8721],{},"Les changements au niveau produit sont communiqués aux utilisateurs",[19,8723,8724],{},[34,8725,8726],{},"Multi-instance",[443,8728,8729,8732,8735],{},[446,8730,8731],{},"Un même produit peut être déployé dans différents environnements de production",[446,8733,8734],{},"Chaque instance est considérée comme une entité distincte pour les métriques de déploiement",[446,8736,8737],{},"Les incidents sont agrégés au niveau produit plutôt qu'au niveau instance",[84,8739,8741],{"id":8740},"limitations-connues","Limitations connues 🚧",[19,8743,8744],{},[34,8745,8746],{},"Données manquantes",[443,8748,8749,8752,8755],{},[446,8750,8751],{},"Certains déploiements peuvent manquer d'annotations complètes",[446,8753,8754],{},"Les tags peuvent ne pas suivre strictement SemVer",[446,8756,8757],{},"La corrélation entre incidents et instances spécifiques n'est pas toujours possible",[19,8759,8760],{},[34,8761,8762],{},"Pistes d'amélioration",[443,8764,8765,8768,8771],{},[446,8766,8767],{},"Implémenter \"configuration as code\" pour mieux tracer les changements de configuration",[446,8769,8770],{},"Étendre la prise en compte des tags au-delà de SemVer",[446,8772,8773],{},"Ajouter la notion d'instance produit dans l'outil de gestion des incidents",[19,8775,8776],{},"Ces hypothèses sont régulièrement revues et ajustées en fonction des retours d'expérience et de l'évolution des pratiques DevOps dans l'organisation.",[23,8778,8780],{"id":8779},"_4-la-collecte-des-données-une-approche-par-source","4. La collecte des données : une approche par source 📊",[1003,8782,8783],{},[19,8784,8785,8788],{},[34,8786,8787],{},"L'architecture de collecte : le cœur technique du projet","\nLe succès des DORA Metrics repose sur notre capacité à collecter, intégrer et corréler des données provenant de multiples systèmes. Cette architecture d'intégration constitue la colonne vertébrale technique de notre solution.",[84,8790,8792],{"id":8791},"architecture-de-données-centralisée","Architecture de données centralisée",[19,8794,8795],{},[34,8796,8797],{},"BigQuery comme référentiel central",[19,8799,8800],{},"Pour répondre aux besoins d'analyse et de corrélation des données, nous avons mis en place une architecture où toutes les données sont centralisées dans Google BigQuery. Cette approche présente plusieurs avantages :",[443,8802,8803,8806,8809,8812],{},[446,8804,8805],{},"Capacité à traiter de grands volumes de données (logs Kubernetes, événements GitHub, tickets ServiceNow)",[446,8807,8808],{},"Possibilité d'exécuter des requêtes SQL complexes pour calculer les métriques",[446,8810,8811],{},"Facilité d'intégration avec des outils de visualisation (pour ce projet, Power BI)",[446,8813,8814],{},"Mise à jour des données en quasi temps réel via des flux de données (streaming)",[19,8816,8817],{},"Examinons maintenant notre approche pour chaque source de données :",[84,8819,8821],{"id":8820},"données-de-déploiement","Données de déploiement",[187,8823,8824,8834],{},[190,8825,8826],{},[193,8827,8828,8831],{},[196,8829,8830],{},"Élément",[196,8832,8833],{},"Description",[208,8835,8836,8843,8865,8892,8919],{},[193,8837,8838,8841],{},[213,8839,8840],{},"Source principale",[213,8842,8380],{},[193,8844,8845,8848],{},[213,8846,8847],{},"Événements collectés",[213,8849,8850],{},[443,8851,8852,8855,8858],{},[446,8853,8854],{},"Collecte des événements de type \"deployment\" avec statut \"success\"",[446,8856,8857],{},"Identification des déploiements via la progression \"Progressing → True\" avec \"NewReplicaSetAvailable\"",[446,8859,8860,8861,8864],{},"Focus sur les déploiements en production via l'annotation  ",[352,8862,8863],{},"info\u002Fenvironment","=prod",[193,8866,8867,8870],{},[213,8868,8869],{},"Annotations existantes sur les pods",[213,8871,8872],{},[443,8873,8874,8880,8886],{},[446,8875,8876,8879],{},[352,8877,8878],{},"info\u002Fproduct_id","  : identifiant unique du produit",[446,8881,8882,8885],{},[352,8883,8884],{},"info\u002Fbu_index","  : identifiant de la Business Unit",[446,8887,8888,8891],{},[352,8889,8890],{},"info\u002Fcluster_name","  : nom du cluster",[193,8893,8894,8897],{},[213,8895,8896],{},"Annotations à ajouter pour les DORA",[213,8898,8899],{},[443,8900,8901,8907,8913],{},[446,8902,8903,8906],{},[352,8904,8905],{},"release.mgmt\u002Fdeploy.src","  : URL du repository source",[446,8908,8909,8912],{},[352,8910,8911],{},"release.mgmt\u002Fdeploy.src-version","  : version déployée",[446,8914,8915,8918],{},[352,8916,8917],{},"release.mgmt\u002Fenv","  : environnement (prod\u002Fprep\u002Fuat\u002Fdev)",[193,8920,8921,8924],{},[213,8922,8923],{},"Points d’attention",[213,8925,8926],{},[443,8927,8928,8931,8934],{},[446,8929,8930],{},"Distinction entre déploiements de configuration et vraies mises en production",[446,8932,8933],{},"Gestion des déploiements multi-instances pour différentes BU",[446,8935,8936],{},"Traçabilité complète via les annotations",[84,8938,8940],{"id":8939},"données-de-code-source","Données de code source",[187,8942,8943,8951],{},[190,8944,8945],{},[193,8946,8947,8949],{},[196,8948,8830],{},[196,8950,8833],{},[208,8952,8953,8960,8975],{},[193,8954,8955,8958],{},[213,8956,8957],{},"Source de vérité",[213,8959,8386],{},[193,8961,8962,8965],{},[213,8963,8964],{},"Sources d’extraction",[213,8966,8967],{},[443,8968,8969,8972],{},[446,8970,8971],{},"Commits  : pour tracer les changements de code",[446,8973,8974],{},"Tags  : pour identifier les versions déployées",[193,8976,8977,8980],{},[213,8978,8979],{},"Corrélation version-déploiement",[213,8981,8982],{},[443,8983,8984,8987,8990],{},[446,8985,8986],{},"Chaque version en production est matérialisée par un tag Git",[446,8988,8989],{},"Les annotations Kubernetes contiennent les références du code source et de la version",[446,8991,8992],{},"La correspondance tag-version permet de calculer précisément le Lead Time",[84,8994,8996],{"id":8995},"données-dincidents","Données d'incidents",[187,8998,8999,9007],{},[190,9000,9001],{},[193,9002,9003,9005],{},[196,9004,8830],{},[196,9006,8833],{},[208,9008,9009,9015,9033],{},[193,9010,9011,9013],{},[213,9012,8840],{},[213,9014,8392],{},[193,9016,9017,9020],{},[213,9018,9019],{},"Critères de sélection des incidents",[213,9021,9022],{},[443,9023,9024,9027,9030],{},[446,9025,9026],{},"Incidents résolus uniquement",[446,9028,9029],{},"Statut ≠ \"Canceled\"",[446,9031,9032],{},"Lien avec produit identifié",[193,9034,9035,9038],{},[213,9036,9037],{},"Limitations actuelles",[213,9039,9040],{},[443,9041,9042,9045,9048],{},[446,9043,9044],{},"Les incidents sont liés à un produit et non à une instance spécifique",[446,9046,9047],{},"Impossibilité de lier directement un incident à une instance particulière",[446,9049,9050],{},"Nécessité d'utiliser des heuristiques pour la corrélation",[23,9052,9054],{"id":9053},"_5-implémentation-et-calcul-des-métriques","5. Implémentation et calcul des métriques 📈",[1003,9056,9057],{},[19,9058,9059,9062],{},[34,9060,9061],{},"De la théorie à la pratique : adapter et calculer les métriques à tous les niveaux","\nLes définitions théoriques des DORA Metrics sont un point de départ, mais leur implémentation concrète nécessite une adaptation fine au contexte spécifique de l'entreprise et une approche multi-échelle pour répondre aux besoins de tous les niveaux de l'organisation.",[84,9064,9066],{"id":9065},"implémentation-des-métriques","Implémentation des métriques",[19,9068,9069],{},"Voici comment nous avons adapté et implémenté chacune des quatre métriques :",[19,9071,9072],{},[1966,9073,9074],{},[34,9075,9076],{},"Lead Time for Changes (Délai de livraison des changements)",[19,9078,9079],{},"Le Lead Time for Changes mesure le temps qui s'écoule entre la dernière modification de code (commit) et son déploiement effectif en production. Dans cette entreprise, nous avons dû sensibiliser les équipes sur l'importance de taguer chaque version déployée pour tracer correctement le code source.",[443,9081,9082,9088,9093],{},[446,9083,9084,9087],{},[34,9085,9086],{},"Extraction:"," à partir des déploiements Kubernetes (annotation \"version\" et \"repo\"), nous retrouvons le commit Git.",[446,9089,9090],{},[34,9091,9092],{},"Calcul:",[446,9094,9095,9098],{},[34,9096,9097],{},"Agrégation:"," comme chaque produit pouvait regrouper plusieurs composants, nous avons choisi de calculer d'abord un Lead Time moyen pour chaque composant, avant de prendre la moyenne de ces composants au niveau du produit.",[19,9100,9101,9104],{},[34,9102,9103],{},"Principale difficulté:"," éviter les déploiements de \"configuration\" sans changement de code, qui fausseraient la métrique. Nous avons donc isolé ces cas dans un tableau de bord à part, pour ne pas influencer le Lead Time for Changes général.",[19,9106,9107],{},[1966,9108,9109],{},[34,9110,9111],{},"Deployment Frequency (Fréquence de déploiement)",[19,9113,9114,9115,9180],{},"La Deployment Frequency indique la cadence à laquelle on pousse des mises à jour en production (exprimée en ",[355,9116,9118],{"className":9117},[1933],[355,9119,9121],{"className":9120,"ariaHidden":1938},[1937],[355,9122,9124,9128,9133,9136,9139,9142],{"className":9123},[1942],[355,9125],{"className":9126,"style":9127},[1946],"height:1.0085em;vertical-align:-0.1944em;",[355,9129,9132],{"className":9130,"style":9131},[1951,1952],"margin-right:0.05724em;","j",[355,9134,1958],{"className":9135},[1951,1952],[355,9137,1966],{"className":9138},[1951,1952],[355,9140,2189],{"className":9141,"style":2188},[1951,1952],[355,9143,9145,9148],{"className":9144},[1951],[355,9146,1973],{"className":9147},[1951,1952],[355,9149,9151],{"className":9150},[1977],[355,9152,9154],{"className":9153},[1981],[355,9155,9157],{"className":9156},[1986],[355,9158,9161],{"className":9159,"style":9160},[1990],"height:0.8141em;",[355,9162,9164,9167],{"style":9163},"top:-3.063em;margin-right:0.05em;",[355,9165],{"className":9166,"style":1999},[1998],[355,9168,9170],{"className":9169},[2003,2004,2005,2006],[355,9171,9173,9176],{"className":9172},[1951,2006],[355,9174,2154],{"className":9175},[1951,2006],[355,9177,9179],{"className":9178},[1951,2006],"1",", ou inverse de l'intervalle entre deux déploiements).",[355,9182,9184],{"className":9183},[1929],[355,9185,9187],{"className":9186},[1933],[355,9188,9190,9257],{"className":9189,"ariaHidden":1938},[1937],[355,9191,9193,9197,9248,9251,9254],{"className":9192},[1942],[355,9194],{"className":9195,"style":9196},[1946],"height:0.9805em;vertical-align:-0.2861em;",[355,9198,9200,9203],{"className":9199},[1951],[355,9201,2117],{"className":9202,"style":2116},[1951,1952],[355,9204,9206],{"className":9205},[1977],[355,9207,9209,9240],{"className":9208},[1981,1982],[355,9210,9212,9237],{"className":9211},[1986],[355,9213,9215],{"className":9214,"style":2471},[1990],[355,9216,9218,9221],{"style":9217},"top:-2.55em;margin-left:-0.1076em;margin-right:0.05em;",[355,9219],{"className":9220,"style":1999},[1998],[355,9222,9224],{"className":9223},[2003,2004,2005,2006],[355,9225,9227,9231,9234],{"className":9226},[1951,2006],[355,9228,9230],{"className":9229},[1951,1952,2006],"co",[355,9232,2068],{"className":9233},[1951,1952,2006],[355,9235,19],{"className":9236},[1951,1952,2006],[355,9238,2023],{"className":9239},[2022],[355,9241,9243],{"className":9242},[1986],[355,9244,9246],{"className":9245,"style":2030},[1990],[355,9247],{},[355,9249],{"className":9250,"style":2037},[2036],[355,9252,2042],{"className":9253},[2041],[355,9255],{"className":9256,"style":2037},[2036],[355,9258,9260,9264],{"className":9259},[1942],[355,9261],{"className":9262,"style":9263},[1946],"height:2.2935em;vertical-align:-0.9721em;",[355,9265,9267,9271,9450],{"className":9266},[1951],[355,9268],{"className":9269},[2168,9270],"nulldelimiter",[355,9272,9275],{"className":9273},[9274],"mfrac",[355,9276,9278,9441],{"className":9277},[1981,1982],[355,9279,9281,9438],{"className":9280},[1986],[355,9282,9285,9415,9426],{"className":9283,"style":9284},[1990],"height:1.3214em;",[355,9286,9288,9292],{"style":9287},"top:-2.314em;",[355,9289],{"className":9290,"style":9291},[1998],"height:3em;",[355,9293,9295,9298,9351,9354,9357,9360,9412],{"className":9294},[1951],[355,9296,2169],{"className":9297},[2168],[355,9299,9301,9304],{"className":9300},[1951],[355,9302,2078],{"className":9303},[1951,1952],[355,9305,9307],{"className":9306},[1977],[355,9308,9310,9343],{"className":9309},[1981,1982],[355,9311,9313,9340],{"className":9312},[1986],[355,9314,9316],{"className":9315,"style":2101},[1990],[355,9317,9318,9321],{"style":1994},[355,9319],{"className":9320,"style":1999},[1998],[355,9322,9324],{"className":9323},[2003,2004,2005,2006],[355,9325,9327,9330,9333,9336],{"className":9326},[1951,2006],[355,9328,2458],{"className":9329},[1951,1952,2006],[355,9331,2196],{"className":9332},[1951,1952,2006],[355,9334,19],{"className":9335},[1951,1952,2006],[355,9337,9339],{"className":9338},[1951,2006],"2",[355,9341,2023],{"className":9342},[2022],[355,9344,9346],{"className":9345},[1986],[355,9347,9349],{"className":9348,"style":2030},[1990],[355,9350],{},[355,9352],{"className":9353,"style":2149},[2036],[355,9355,2154],{"className":9356},[2153],[355,9358],{"className":9359,"style":2149},[2036],[355,9361,9363,9366],{"className":9362},[1951],[355,9364,2078],{"className":9365},[1951,1952],[355,9367,9369],{"className":9368},[1977],[355,9370,9372,9404],{"className":9371},[1981,1982],[355,9373,9375,9401],{"className":9374},[1986],[355,9376,9378],{"className":9377,"style":2101},[1990],[355,9379,9380,9383],{"style":1994},[355,9381],{"className":9382,"style":1999},[1998],[355,9384,9386],{"className":9385},[2003,2004,2005,2006],[355,9387,9389,9392,9395,9398],{"className":9388},[1951,2006],[355,9390,2458],{"className":9391},[1951,1952,2006],[355,9393,2196],{"className":9394},[1951,1952,2006],[355,9396,19],{"className":9397},[1951,1952,2006],[355,9399,9179],{"className":9400},[1951,2006],[355,9402,2023],{"className":9403},[2022],[355,9405,9407],{"className":9406},[1986],[355,9408,9410],{"className":9409,"style":2030},[1990],[355,9411],{},[355,9413,2418],{"className":9414},[2417],[355,9416,9418,9421],{"style":9417},"top:-3.23em;",[355,9419],{"className":9420,"style":9291},[1998],[355,9422],{"className":9423,"style":9425},[9424],"frac-line","border-bottom-width:0.04em;",[355,9427,9429,9432],{"style":9428},"top:-3.677em;",[355,9430],{"className":9431,"style":9291},[1998],[355,9433,9435],{"className":9434},[1951],[355,9436,9179],{"className":9437},[1951],[355,9439,2023],{"className":9440},[2022],[355,9442,9444],{"className":9443},[1986],[355,9445,9448],{"className":9446,"style":9447},[1990],"height:0.9721em;",[355,9449],{},[355,9451],{"className":9452},[2417,9270],[19,9454,9455],{},"Au niveau d'un produit, nous calculons la moyenne des fréquences de déploiement de tous ses composants. Nous avons aussi mis en évidence quelques \"cas limites\", par exemple lorsqu'un composant n'a qu'un seul déploiement. Dans ces situations, on ne peut pas déterminer d'intervalle et la fréquence reste \"N\u002FA\".",[19,9457,9458],{},"C'était essentiel de distinguer un déploiement réellement exposé à l'utilisateur dans l'environnement \"prod\" (annotation \"info\u002Fenvironment=prod\") de simples déploiements sur des environnements de test ou d'intégration.",[19,9460,9461],{},[1966,9462,9463],{},[34,9464,9465],{},"Mean Time to Restore (MTTR) ou Mean Time to Recover (Temps moyen de restauration)",[19,9467,9468],{},"Le MTTR calcule le temps moyen nécessaire pour résoudre un incident ou le temps apparent de défaillance pour l'utilisateur. Au départ, nous avons constaté que l'outil de ticketing (ServiceNow) n'enregistrait pas toujours les champs d'ouverture et de clôture de manière cohérente.",[19,9470,9471],{},"Nous avons donc dû :",[443,9473,9474,9480,9486],{},[446,9475,9476,9479],{},[34,9477,9478],{},"Sensibiliser les équipes support"," : un champ \"date de début d'incident\" doit être rempli le plus précisément possible dès ouverture (sinon nous utilisons la date de création du ticket).",[446,9481,9482,9485],{},[34,9483,9484],{},"Vérifier la date de résolution ou de clôture"," : c'est la référence pour la fin d'incident.",[446,9487,9488,9491],{},[34,9489,9490],{},"Calculer la moyenne"," de (date de fin − date de début) sur tous les incidents clôturés, pour chaque produit.",[355,9493,9495],{"className":9494},[1929],[355,9496,9498],{"className":9497},[1933],[355,9499,9501,9604,9814],{"className":9500,"ariaHidden":1938},[1937],[355,9502,9504,9508,9595,9598,9601],{"className":9503},[1942],[355,9505],{"className":9506,"style":9507},[1946],"height:0.9019em;vertical-align:-0.15em;",[355,9509,9511,9549],{"className":9510},[1951],[355,9512,9515],{"className":9513},[1951,9514],"accent",[355,9516,9518],{"className":9517},[1981],[355,9519,9521],{"className":9520},[1986],[355,9522,9525,9534],{"className":9523,"style":9524},[1990],"height:0.7519em;",[355,9526,9528,9531],{"style":9527},"top:-3em;",[355,9529],{"className":9530,"style":9291},[1998],[355,9532,2078],{"className":9533},[1951,1952],[355,9535,9537,9540],{"style":9536},"top:-3.1841em;",[355,9538],{"className":9539,"style":9291},[1998],[355,9541,9545],{"className":9542,"style":9544},[9543],"accent-body","left:-0.1667em;",[355,9546,9548],{"className":9547},[1951],"ˉ",[355,9550,9552],{"className":9551},[1977],[355,9553,9555,9587],{"className":9554},[1981,1982],[355,9556,9558,9584],{"className":9557},[1986],[355,9559,9561],{"className":9560,"style":2471},[1990],[355,9562,9563,9566],{"style":1994},[355,9564],{"className":9565,"style":1999},[1998],[355,9567,9569],{"className":9568},[2003,2004,2005,2006],[355,9570,9572,9576,9580],{"className":9571},[1951,2006],[355,9573,9575],{"className":9574},[1951,1952,2006],"reco",[355,9577,9579],{"className":9578,"style":2493},[1951,1952,2006],"v",[355,9581,9583],{"className":9582,"style":2188},[1951,1952,2006],"er",[355,9585,2023],{"className":9586},[2022],[355,9588,9590],{"className":9589},[1986],[355,9591,9593],{"className":9592,"style":2250},[1990],[355,9594],{},[355,9596],{"className":9597,"style":2037},[2036],[355,9599,2042],{"className":9600},[2041],[355,9602],{"className":9603,"style":2037},[2036],[355,9605,9607,9611,9674,9677,9753,9756,9805,9808,9811],{"className":9606},[1942],[355,9608],{"className":9609,"style":9610},[1946],"height:2.9535em;vertical-align:-1.3021em;",[355,9612,9614,9617,9671],{"className":9613},[1951],[355,9615],{"className":9616},[2168,9270],[355,9618,9620],{"className":9619},[9274],[355,9621,9623,9662],{"className":9622},[1981,1982],[355,9624,9626,9659],{"className":9625},[1986],[355,9627,9629,9640,9648],{"className":9628,"style":9284},[1990],[355,9630,9631,9634],{"style":9287},[355,9632],{"className":9633,"style":9291},[1998],[355,9635,9637],{"className":9636},[1951],[355,9638,1962],{"className":9639},[1951,1952],[355,9641,9642,9645],{"style":9417},[355,9643],{"className":9644,"style":9291},[1998],[355,9646],{"className":9647,"style":9425},[9424],[355,9649,9650,9653],{"style":9428},[355,9651],{"className":9652,"style":9291},[1998],[355,9654,9656],{"className":9655},[1951],[355,9657,9179],{"className":9658},[1951],[355,9660,2023],{"className":9661},[2022],[355,9663,9665],{"className":9664},[1986],[355,9666,9669],{"className":9667,"style":9668},[1990],"height:0.686em;",[355,9670],{},[355,9672],{"className":9673},[2417,9270],[355,9675],{"className":9676,"style":2064},[2036],[355,9678,9681],{"className":9679},[2056,9680],"op-limits",[355,9682,9684,9744],{"className":9683},[1981,1982],[355,9685,9687,9741],{"className":9686},[1986],[355,9688,9691,9715,9726],{"className":9689,"style":9690},[1990],"height:1.6514em;",[355,9692,9694,9698],{"style":9693},"top:-1.8479em;margin-left:0em;",[355,9695],{"className":9696,"style":9697},[1998],"height:3.05em;",[355,9699,9701],{"className":9700},[2003,2004,2005,2006],[355,9702,9704,9709,9712],{"className":9703},[1951,2006],[355,9705,9708],{"className":9706,"style":9707},[1951,1952,2006],"margin-right:0.03148em;","k",[355,9710,2042],{"className":9711},[2041,2006],[355,9713,9179],{"className":9714},[1951,2006],[355,9716,9718,9721],{"style":9717},"top:-3.05em;",[355,9719],{"className":9720,"style":9697},[1998],[355,9722,9723],{},[355,9724,2060],{"className":9725},[2056,2057,2058],[355,9727,9729,9732],{"style":9728},"top:-4.3em;margin-left:0em;",[355,9730],{"className":9731,"style":9697},[1998],[355,9733,9735],{"className":9734},[2003,2004,2005,2006],[355,9736,9738],{"className":9737},[1951,2006],[355,9739,1962],{"className":9740},[1951,1952,2006],[355,9742,2023],{"className":9743},[2022],[355,9745,9747],{"className":9746},[1986],[355,9748,9751],{"className":9749,"style":9750},[1990],"height:1.3021em;",[355,9752],{},[355,9754,2169],{"className":9755},[2168],[355,9757,9759,9762],{"className":9758},[1951],[355,9760,2078],{"className":9761},[1951,1952],[355,9763,9765],{"className":9764},[1977],[355,9766,9768,9797],{"className":9767},[1981,1982],[355,9769,9771,9794],{"className":9770},[1986],[355,9772,9774],{"className":9773,"style":2101},[1990],[355,9775,9776,9779],{"style":1994},[355,9777],{"className":9778,"style":1999},[1998],[355,9780,9782],{"className":9781},[2003,2004,2005,2006],[355,9783,9785,9788,9791],{"className":9784},[1951,2006],[355,9786,2196],{"className":9787},[1951,1952,2006],[355,9789,1962],{"className":9790},[1951,1952,2006],[355,9792,2458],{"className":9793},[1951,1952,2006],[355,9795,2023],{"className":9796},[2022],[355,9798,9800],{"className":9799},[1986],[355,9801,9803],{"className":9802,"style":2250},[1990],[355,9804],{},[355,9806],{"className":9807,"style":2149},[2036],[355,9809,2154],{"className":9810},[2153],[355,9812],{"className":9813,"style":2149},[2036],[355,9815,9817,9820,9876],{"className":9816},[1942],[355,9818],{"className":9819,"style":2164},[1946],[355,9821,9823,9826],{"className":9822},[1951],[355,9824,2078],{"className":9825},[1951,1952],[355,9827,9829],{"className":9828},[1977],[355,9830,9832,9868],{"className":9831},[1981,1982],[355,9833,9835,9865],{"className":9834},[1986],[355,9836,9839],{"className":9837,"style":9838},[1990],"height:0.2806em;",[355,9840,9841,9844],{"style":1994},[355,9842],{"className":9843,"style":1999},[1998],[355,9845,9847],{"className":9846},[2003,2004,2005,2006],[355,9848,9850,9853,9856,9859,9862],{"className":9849},[1951,2006],[355,9851,1973],{"className":9852},[1951,1952,2006],[355,9854,2078],{"className":9855},[1951,1952,2006],[355,9857,91],{"className":9858},[1951,1952,2006],[355,9860,2189],{"className":9861,"style":2188},[1951,1952,2006],[355,9863,2078],{"className":9864},[1951,1952,2006],[355,9866,2023],{"className":9867},[2022],[355,9869,9871],{"className":9870},[1986],[355,9872,9874],{"className":9873,"style":2250},[1990],[355,9875],{},[355,9877,2418],{"className":9878},[2417],[19,9880,9881],{},"Pour la plupart des cas, cela a fonctionné correctement. Mais, comme souvent, nous avons rencontré des écarts (tickets fermés très tardivement, incidents mal catégorisés, etc.). Il a fallu faire accepter les limites de la mesure (la durée de vie d'un ticket n'est pas toujours égale à la durée réelle de l'incident technique).",[19,9883,9884],{},[1966,9885,9886],{},[34,9887,9888],{},"Change Failure Rate (Taux d'échec des changements)",[19,9890,9891],{},"Le Change Failure Rate (CFR) représente la proportion de déploiements qui entraînent au moins un incident en production. Ici, le plus gros challenge a été de lier les incidents ServiceNow au \"dernier déploiement\" d'un produit. Faute de pouvoir tracer précisément l'instance de composant à l'origine, nous avons adopté la convention suivante :",[443,9893,9894,9900,9906],{},[446,9895,9896,9899],{},[34,9897,9898],{},"Identifier le \"dernier déploiement\""," survenu avant la date de création de l'incident, tous composants du produit confondus.",[446,9901,9902,9905],{},[34,9903,9904],{},"Incrémenter un déploiement \"défaillant\""," si au moins un incident lui est rattaché.",[446,9907,9908,9911],{},[34,9909,9910],{},"Diviser le nombre de déploiements défaillants par le nombre total de déploiements"," du produit, sur la période considérée.",[355,9913,9915],{"className":9914},[1929],[355,9916,9918],{"className":9917},[1933],[355,9919,9921,10031],{"className":9920,"ariaHidden":1938},[1937],[355,9922,9924,9928,10022,10025,10028],{"className":9923},[1942],[355,9925],{"className":9926,"style":9927},[1946],"height:1.0747em;vertical-align:-0.3802em;",[355,9929,9931,9966],{"className":9930},[1951],[355,9932,9934,9939,9943,9946,9949,9954,9957,9960,9963],{"className":9933},[1951],[355,9935,9938],{"className":9936,"style":9937},[1951,1952],"margin-right:0.07153em;","C",[355,9940,9942],{"className":9941},[1951,1952],"han",[355,9944,2494],{"className":9945,"style":2493},[1951,1952],[355,9947,2196],{"className":9948},[1951,1952],[355,9950,9953],{"className":9951,"style":9952},[1951,1952],"margin-right:0.13889em;","F",[355,9955,2184],{"className":9956},[1951,1952],[355,9958,2180],{"className":9959,"style":2179},[1951,1952],[355,9961,1966],{"className":9962},[1951,1952],[355,9964,2134],{"className":9965},[1951,1952],[355,9967,9969],{"className":9968},[1977],[355,9970,9972,10013],{"className":9971},[1981,1982],[355,9973,9975,10010],{"className":9974},[1986],[355,9976,9979],{"className":9977,"style":9978},[1990],"height:0.242em;",[355,9980,9982,9985],{"style":9981},"top:-2.4559em;margin-right:0.05em;",[355,9983],{"className":9984,"style":1999},[1998],[355,9986,9988],{"className":9987},[2003,2004,2005,2006],[355,9989,9991,9994,9998,10001,10004,10007],{"className":9990},[1951,2006],[355,9992,19],{"className":9993},[1951,1952,2006],[355,9995,9997],{"className":9996},[1951,1952,2006],"ro",[355,9999,2458],{"className":10000},[1951,1952,2006],[355,10002,1966],{"className":10003},[1951,1952,2006],[355,10005,2124],{"className":10006},[1951,1952,2006],[355,10008,2078],{"className":10009},[1951,1952,2006],[355,10011,2023],{"className":10012},[2022],[355,10014,10016],{"className":10015},[1986],[355,10017,10020],{"className":10018,"style":10019},[1990],"height:0.3802em;",[355,10021],{},[355,10023],{"className":10024,"style":2037},[2036],[355,10026,2042],{"className":10027},[2041],[355,10029],{"className":10030,"style":2037},[2036],[355,10032,10034,10038],{"className":10033},[1942],[355,10035],{"className":10036,"style":10037},[1946],"height:2.363em;vertical-align:-0.936em;",[355,10039,10041,10044,10216],{"className":10040},[1951],[355,10042],{"className":10043},[2168,9270],[355,10045,10047],{"className":10046},[9274],[355,10048,10050,10207],{"className":10049},[1981,1982],[355,10051,10053,10204],{"className":10052},[1986],[355,10054,10057,10130,10138],{"className":10055,"style":10056},[1990],"height:1.427em;",[355,10058,10059,10062],{"style":9287},[355,10060],{"className":10061,"style":9291},[1998],[355,10063,10065,10069,10072],{"className":10064},[1951],[355,10066,2060],{"className":10067,"style":2059},[2056,2057,10068],"small-op",[355,10070],{"className":10071,"style":2064},[2036],[355,10073,10075],{"className":10074},[1951],[355,10076,10078,10081],{"className":10077},[1951],[355,10079,2458],{"className":10080},[1951,1952],[355,10082,10084],{"className":10083},[1977],[355,10085,10087,10122],{"className":10086},[1981,1982],[355,10088,10090,10119],{"className":10089},[1986],[355,10091,10093],{"className":10092,"style":2101},[1990],[355,10094,10095,10098],{"style":1994},[355,10096],{"className":10097,"style":1999},[1998],[355,10099,10101],{"className":10100},[2003,2004,2005,2006],[355,10102,10104,10107,10110,10113,10116],{"className":10103},[1951,2006],[355,10105,2078],{"className":10106},[1951,1952,2006],[355,10108,1958],{"className":10109},[1951,1952,2006],[355,10111,2078],{"className":10112},[1951,1952,2006],[355,10114,91],{"className":10115},[1951,1952,2006],[355,10117,2180],{"className":10118,"style":2179},[1951,1952,2006],[355,10120,2023],{"className":10121},[2022],[355,10123,10125],{"className":10124},[1986],[355,10126,10128],{"className":10127,"style":2250},[1990],[355,10129],{},[355,10131,10132,10135],{"style":9417},[355,10133],{"className":10134,"style":9291},[1998],[355,10136],{"className":10137,"style":9425},[9424],[355,10139,10140,10143],{"style":9428},[355,10141],{"className":10142,"style":9291},[1998],[355,10144,10146,10149,10152],{"className":10145},[1951],[355,10147,2060],{"className":10148,"style":2059},[2056,2057,10068],[355,10150],{"className":10151,"style":2064},[2036],[355,10153,10155],{"className":10154},[1951],[355,10156,10158,10161],{"className":10157},[1951],[355,10159,2458],{"className":10160},[1951,1952],[355,10162,10164],{"className":10163},[1977],[355,10165,10167,10196],{"className":10166},[1981,1982],[355,10168,10170,10193],{"className":10169},[1986],[355,10171,10173],{"className":10172,"style":2101},[1990],[355,10174,10175,10178],{"style":1994},[355,10176],{"className":10177,"style":1999},[1998],[355,10179,10181],{"className":10180},[2003,2004,2005,2006],[355,10182,10184,10187,10190],{"className":10183},[1951,2006],[355,10185,2117],{"className":10186,"style":2116},[1951,1952,2006],[355,10188,2184],{"className":10189},[1951,1952,2006],[355,10191,2180],{"className":10192,"style":2179},[1951,1952,2006],[355,10194,2023],{"className":10195},[2022],[355,10197,10199],{"className":10198},[1986],[355,10200,10202],{"className":10201,"style":2030},[1990],[355,10203],{},[355,10205,2023],{"className":10206},[2022],[355,10208,10210],{"className":10209},[1986],[355,10211,10214],{"className":10212,"style":10213},[1990],"height:0.936em;",[355,10215],{},[355,10217],{"className":10218},[2417,9270],[19,10220,10221],{},"Bien sûr, cela reste une approximation: on ne sait pas distinguer un incident réellement lié à un composant particulier. D'où la nécessité d'améliorer la remontée d'informations dans ServiceNow (par exemple en demandant explicitement quelle version réelle est touchée).",[84,10223,10225],{"id":10224},"calcul-des-métriques-par-niveau-de-granularité","Calcul des métriques par niveau de granularité 📊",[1003,10227,10228],{},[19,10229,10230,10233],{},[34,10231,10232],{},"Vision multi-échelle : du composant à la plateforme","\nL'une des forces de notre implémentation réside dans sa capacité à fournir des métriques à différents niveaux de granularité. Cette approche multi-échelle permet à chaque niveau de management d'accéder aux indicateurs pertinents pour son périmètre de responsabilité, tout en garantissant la cohérence globale des mesures.",[19,10235,10236],{},"Différentes vues des Dora Metrics de notre solution pour illustrer les calculs un peu plus bas.",[19,10238,10239],{},[176,10240],{"alt":10241,"src":10242},"Vue globale des dora metrics","\u002Fcontent-assets\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Fassets\u002Fimg1.webp",[19,10244,10245],{},[176,10246],{"alt":10247,"src":10248},"Vue détaillée des dora metrics au niveau d’un produit","\u002Fcontent-assets\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Fassets\u002Fimg2.webp",[19,10250,10251],{},[176,10252],{"alt":10253,"src":10254},"Vue pour suivre l’évolution des dora metrics au niveau d’une plateforme","\u002Fcontent-assets\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Fassets\u002Fimg3.webp",[84,10256,10258],{"id":10257},"lead-time-for-changes","Lead Time For Changes",[19,10260,10261],{},[34,10262,10263],{},"Niveau Composant",[355,10265,10267],{"className":10266},[1929],[355,10268,10270],{"className":10269},[1933],[355,10271,10273,10385,10619],{"className":10272,"ariaHidden":1938},[1937],[355,10274,10276,10279,10283,10376,10379,10382],{"className":10275},[1942],[355,10277],{"className":10278,"style":1947},[1946],[355,10280,10282],{"className":10281},[1951],"Δ",[355,10284,10286,10289],{"className":10285},[1951],[355,10287,2078],{"className":10288},[1951,1952],[355,10290,10292],{"className":10291},[1977],[355,10293,10295,10368],{"className":10294},[1981,1982],[355,10296,10298,10365],{"className":10297},[1986],[355,10299,10301],{"className":10300,"style":2101},[1990],[355,10302,10303,10306],{"style":1994},[355,10304],{"className":10305,"style":1999},[1998],[355,10307,10309],{"className":10308},[2003,2004,2005,2006],[355,10310,10312,10316,10319],{"className":10311},[1951,2006],[355,10313,10315],{"className":10314},[1951,1952,2006],"lt",[355,10317,2117],{"className":10318,"style":2116},[1951,1952,2006],[355,10320,10322,10325],{"className":10321},[1951,2006],[355,10323,2124],{"className":10324},[1951,1952,2006],[355,10326,10328],{"className":10327},[1977],[355,10329,10331,10356],{"className":10330},[1981,1982],[355,10332,10334,10353],{"className":10333},[1986],[355,10335,10338],{"className":10336,"style":10337},[1990],"height:0.1645em;",[355,10339,10341,10345],{"style":10340},"top:-2.357em;margin-left:0em;margin-right:0.0714em;",[355,10342],{"className":10343,"style":10344},[1998],"height:2.5em;",[355,10346,10350],{"className":10347},[2003,10348,10349,2006],"reset-size3","size1",[355,10351,2124],{"className":10352},[1951,1952,2006],[355,10354,2023],{"className":10355},[2022],[355,10357,10359],{"className":10358},[1986],[355,10360,10363],{"className":10361,"style":10362},[1990],"height:0.143em;",[355,10364],{},[355,10366,2023],{"className":10367},[2022],[355,10369,10371],{"className":10370},[1986],[355,10372,10374],{"className":10373,"style":2030},[1990],[355,10375],{},[355,10377],{"className":10378,"style":2037},[2036],[355,10380,2042],{"className":10381},[2041],[355,10383],{"className":10384,"style":2037},[2036],[355,10386,10388,10392,10519,10522,10525,10528,10610,10613,10616],{"className":10387},[1942],[355,10389],{"className":10390,"style":10391},[1946],"height:2.4221em;vertical-align:-0.9721em;",[355,10393,10396,10405,10513],{"className":10394},[10395],"minner",[355,10397,10401],{"className":10398,"style":10400},[2168,10399],"delimcenter","top:0em;",[355,10402,2169],{"className":10403},[10404,2005],"delimsizing",[355,10406,10408,10411,10510],{"className":10407},[1951],[355,10409],{"className":10410},[2168,9270],[355,10412,10414],{"className":10413},[9274],[355,10415,10417,10502],{"className":10416},[1981,1982],[355,10418,10420,10499],{"className":10419},[1986],[355,10421,10423,10480,10488],{"className":10422,"style":9284},[1990],[355,10424,10425,10428],{"style":9287},[355,10426],{"className":10427,"style":9291},[1998],[355,10429,10431],{"className":10430},[1951],[355,10432,10434,10437],{"className":10433},[1951],[355,10435,2458],{"className":10436},[1951,1952],[355,10438,10440],{"className":10439},[1977],[355,10441,10443,10472],{"className":10442},[1981,1982],[355,10444,10446,10469],{"className":10445},[1986],[355,10447,10449],{"className":10448,"style":9838},[1990],[355,10450,10451,10454],{"style":1994},[355,10452],{"className":10453,"style":1999},[1998],[355,10455,10457],{"className":10456},[2003,2004,2005,2006],[355,10458,10460,10463,10466],{"className":10459},[1951,2006],[355,10461,2078],{"className":10462},[1951,1952,2006],[355,10464,91],{"className":10465},[1951,1952,2006],[355,10467,2494],{"className":10468,"style":2493},[1951,1952,2006],[355,10470,2023],{"className":10471},[2022],[355,10473,10475],{"className":10474},[1986],[355,10476,10478],{"className":10477,"style":2030},[1990],[355,10479],{},[355,10481,10482,10485],{"style":9417},[355,10483],{"className":10484,"style":9291},[1998],[355,10486],{"className":10487,"style":9425},[9424],[355,10489,10490,10493],{"style":9428},[355,10491],{"className":10492,"style":9291},[1998],[355,10494,10496],{"className":10495},[1951],[355,10497,9179],{"className":10498},[1951],[355,10500,2023],{"className":10501},[2022],[355,10503,10505],{"className":10504},[1986],[355,10506,10508],{"className":10507,"style":9447},[1990],[355,10509],{},[355,10511],{"className":10512},[2417,9270],[355,10514,10516],{"className":10515,"style":10400},[2417,10399],[355,10517,2418],{"className":10518},[10404,2005],[355,10520],{"className":10521,"style":2064},[2036],[355,10523,2060],{"className":10524,"style":2059},[2056,2057,2058],[355,10526,2169],{"className":10527},[2168],[355,10529,10531,10534],{"className":10530},[1951],[355,10532,2078],{"className":10533},[1951,1952],[355,10535,10537],{"className":10536},[1977],[355,10538,10540,10601],{"className":10539},[1981,1982],[355,10541,10543,10598],{"className":10542},[1986],[355,10544,10546],{"className":10545,"style":2101},[1990],[355,10547,10548,10551],{"style":1994},[355,10549],{"className":10550,"style":1999},[1998],[355,10552,10554],{"className":10553},[2003,2004,2005,2006],[355,10555,10557],{"className":10556},[1951,2006],[355,10558,10560,10563],{"className":10559},[1951,2006],[355,10561,2458],{"className":10562},[1951,1952,2006],[355,10564,10566],{"className":10565},[1977],[355,10567,10569,10590],{"className":10568},[1981,1982],[355,10570,10572,10587],{"className":10571},[1986],[355,10573,10576],{"className":10574,"style":10575},[1990],"height:0.3281em;",[355,10577,10578,10581],{"style":10340},[355,10579],{"className":10580,"style":10344},[1998],[355,10582,10584],{"className":10583},[2003,10348,10349,2006],[355,10585,2313],{"className":10586},[1951,1952,2006],[355,10588,2023],{"className":10589},[2022],[355,10591,10593],{"className":10592},[1986],[355,10594,10596],{"className":10595,"style":10362},[1990],[355,10597],{},[355,10599,2023],{"className":10600},[2022],[355,10602,10604],{"className":10603},[1986],[355,10605,10608],{"className":10606,"style":10607},[1990],"height:0.2501em;",[355,10609],{},[355,10611],{"className":10612,"style":2149},[2036],[355,10614,2154],{"className":10615},[2153],[355,10617],{"className":10618,"style":2149},[2036],[355,10620,10622,10626,10709],{"className":10621},[1942],[355,10623],{"className":10624,"style":10625},[1946],"height:1.0001em;vertical-align:-0.2501em;",[355,10627,10629,10632],{"className":10628},[1951],[355,10630,2078],{"className":10631},[1951,1952],[355,10633,10635],{"className":10634},[1977],[355,10636,10638,10701],{"className":10637},[1981,1982],[355,10639,10641,10698],{"className":10640},[1986],[355,10642,10644],{"className":10643,"style":2471},[1990],[355,10645,10646,10649],{"style":1994},[355,10647],{"className":10648,"style":1999},[1998],[355,10650,10652],{"className":10651},[2003,2004,2005,2006],[355,10653,10655,10658],{"className":10654},[1951,2006],[355,10656,2124],{"className":10657},[1951,1952,2006],[355,10659,10661,10664],{"className":10660},[1951,2006],[355,10662,1958],{"className":10663},[1951,1952,2006],[355,10665,10667],{"className":10666},[1977],[355,10668,10670,10690],{"className":10669},[1981,1982],[355,10671,10673,10687],{"className":10672},[1986],[355,10674,10676],{"className":10675,"style":10575},[1990],[355,10677,10678,10681],{"style":10340},[355,10679],{"className":10680,"style":10344},[1998],[355,10682,10684],{"className":10683},[2003,10348,10349,2006],[355,10685,2313],{"className":10686},[1951,1952,2006],[355,10688,2023],{"className":10689},[2022],[355,10691,10693],{"className":10692},[1986],[355,10694,10696],{"className":10695,"style":10362},[1990],[355,10697],{},[355,10699,2023],{"className":10700},[2022],[355,10702,10704],{"className":10703},[1986],[355,10705,10707],{"className":10706,"style":10607},[1990],[355,10708],{},[355,10710,2418],{"className":10711},[2417],[19,10713,10714],{},"où :",[443,10716,10717,10813,10911],{},[446,10718,10719,10812],{},[355,10720,10722],{"className":10721},[1933],[355,10723,10725],{"className":10724,"ariaHidden":1938},[1937],[355,10726,10728,10732],{"className":10727},[1942],[355,10729],{"className":10730,"style":10731},[1946],"height:0.8652em;vertical-align:-0.2501em;",[355,10733,10735,10738],{"className":10734},[1951],[355,10736,2078],{"className":10737},[1951,1952],[355,10739,10741],{"className":10740},[1977],[355,10742,10744,10804],{"className":10743},[1981,1982],[355,10745,10747,10801],{"className":10746},[1986],[355,10748,10750],{"className":10749,"style":2101},[1990],[355,10751,10752,10755],{"style":1994},[355,10753],{"className":10754,"style":1999},[1998],[355,10756,10758],{"className":10757},[2003,2004,2005,2006],[355,10759,10761],{"className":10760},[1951,2006],[355,10762,10764,10767],{"className":10763},[1951,2006],[355,10765,2458],{"className":10766},[1951,1952,2006],[355,10768,10770],{"className":10769},[1977],[355,10771,10773,10793],{"className":10772},[1981,1982],[355,10774,10776,10790],{"className":10775},[1986],[355,10777,10779],{"className":10778,"style":10575},[1990],[355,10780,10781,10784],{"style":10340},[355,10782],{"className":10783,"style":10344},[1998],[355,10785,10787],{"className":10786},[2003,10348,10349,2006],[355,10788,2313],{"className":10789},[1951,1952,2006],[355,10791,2023],{"className":10792},[2022],[355,10794,10796],{"className":10795},[1986],[355,10797,10799],{"className":10798,"style":10362},[1990],[355,10800],{},[355,10802,2023],{"className":10803},[2022],[355,10805,10807],{"className":10806},[1986],[355,10808,10810],{"className":10809,"style":10607},[1990],[355,10811],{}," = Date de déploiement en production",[446,10814,10815,10910],{},[355,10816,10818],{"className":10817},[1933],[355,10819,10821],{"className":10820,"ariaHidden":1938},[1937],[355,10822,10824,10827],{"className":10823},[1942],[355,10825],{"className":10826,"style":10731},[1946],[355,10828,10830,10833],{"className":10829},[1951],[355,10831,2078],{"className":10832},[1951,1952],[355,10834,10836],{"className":10835},[1977],[355,10837,10839,10902],{"className":10838},[1981,1982],[355,10840,10842,10899],{"className":10841},[1986],[355,10843,10845],{"className":10844,"style":2471},[1990],[355,10846,10847,10850],{"style":1994},[355,10848],{"className":10849,"style":1999},[1998],[355,10851,10853],{"className":10852},[2003,2004,2005,2006],[355,10854,10856,10859],{"className":10855},[1951,2006],[355,10857,2124],{"className":10858},[1951,1952,2006],[355,10860,10862,10865],{"className":10861},[1951,2006],[355,10863,1958],{"className":10864},[1951,1952,2006],[355,10866,10868],{"className":10867},[1977],[355,10869,10871,10891],{"className":10870},[1981,1982],[355,10872,10874,10888],{"className":10873},[1986],[355,10875,10877],{"className":10876,"style":10575},[1990],[355,10878,10879,10882],{"style":10340},[355,10880],{"className":10881,"style":10344},[1998],[355,10883,10885],{"className":10884},[2003,10348,10349,2006],[355,10886,2313],{"className":10887},[1951,1952,2006],[355,10889,2023],{"className":10890},[2022],[355,10892,10894],{"className":10893},[1986],[355,10895,10897],{"className":10896,"style":10362},[1990],[355,10898],{},[355,10900,2023],{"className":10901},[2022],[355,10903,10905],{"className":10904},[1986],[355,10906,10908],{"className":10907,"style":10607},[1990],[355,10909],{}," = Date du dernier commit de la version",[446,10912,10913,10974],{},[355,10914,10916],{"className":10915},[1933],[355,10917,10919],{"className":10918,"ariaHidden":1938},[1937],[355,10920,10922,10925],{"className":10921},[1942],[355,10923],{"className":10924,"style":9196},[1946],[355,10926,10928,10931],{"className":10927},[1951],[355,10929,2458],{"className":10930},[1951,1952],[355,10932,10934],{"className":10933},[1977],[355,10935,10937,10966],{"className":10936},[1981,1982],[355,10938,10940,10963],{"className":10939},[1986],[355,10941,10943],{"className":10942,"style":9838},[1990],[355,10944,10945,10948],{"style":1994},[355,10946],{"className":10947,"style":1999},[1998],[355,10949,10951],{"className":10950},[2003,2004,2005,2006],[355,10952,10954,10957,10960],{"className":10953},[1951,2006],[355,10955,2078],{"className":10956},[1951,1952,2006],[355,10958,91],{"className":10959},[1951,1952,2006],[355,10961,2494],{"className":10962,"style":2493},[1951,1952,2006],[355,10964,2023],{"className":10965},[2022],[355,10967,10969],{"className":10968},[1986],[355,10970,10972],{"className":10971,"style":2030},[1990],[355,10973],{}," = Nombre de déploiements en production associés à un tag Git",[19,10976,10977],{},[34,10978,10979],{},"Niveau Produit",[355,10981,10983],{"className":10982},[1929],[355,10984,10986],{"className":10985},[1933],[355,10987,10989,11096],{"className":10988,"ariaHidden":1938},[1937],[355,10990,10992,10996,10999,11087,11090,11093],{"className":10991},[1942],[355,10993],{"className":10994,"style":10995},[1946],"height:1.0307em;vertical-align:-0.3473em;",[355,10997,10282],{"className":10998},[1951],[355,11000,11002,11005],{"className":11001},[1951],[355,11003,2078],{"className":11004},[1951,1952],[355,11006,11008],{"className":11007},[1977],[355,11009,11011,11078],{"className":11010},[1981,1982],[355,11012,11014,11075],{"className":11013},[1986],[355,11015,11017],{"className":11016,"style":2101},[1990],[355,11018,11019,11022],{"style":1994},[355,11020],{"className":11021,"style":1999},[1998],[355,11023,11025],{"className":11024},[2003,2004,2005,2006],[355,11026,11028,11031,11034],{"className":11027},[1951,2006],[355,11029,10315],{"className":11030},[1951,1952,2006],[355,11032,2117],{"className":11033,"style":2116},[1951,1952,2006],[355,11035,11037,11040],{"className":11036},[1951,2006],[355,11038,2124],{"className":11039},[1951,1952,2006],[355,11041,11043],{"className":11042},[1977],[355,11044,11046,11066],{"className":11045},[1981,1982],[355,11047,11049,11063],{"className":11048},[1986],[355,11050,11052],{"className":11051,"style":10337},[1990],[355,11053,11054,11057],{"style":10340},[355,11055],{"className":11056,"style":10344},[1998],[355,11058,11060],{"className":11059},[2003,10348,10349,2006],[355,11061,19],{"className":11062},[1951,1952,2006],[355,11064,2023],{"className":11065},[2022],[355,11067,11069],{"className":11068},[1986],[355,11070,11073],{"className":11071,"style":11072},[1990],"height:0.2819em;",[355,11074],{},[355,11076,2023],{"className":11077},[2022],[355,11079,11081],{"className":11080},[1986],[355,11082,11085],{"className":11083,"style":11084},[1990],"height:0.3473em;",[355,11086],{},[355,11088],{"className":11089,"style":2037},[2036],[355,11091,2042],{"className":11092},[2041],[355,11094],{"className":11095,"style":2037},[2036],[355,11097,11099,11103,11203,11206,11209,11212],{"className":11098},[1942],[355,11100],{"className":11101,"style":11102},[1946],"height:2.1574em;vertical-align:-0.836em;",[355,11104,11106,11109,11200],{"className":11105},[1951],[355,11107],{"className":11108},[2168,9270],[355,11110,11112],{"className":11111},[9274],[355,11113,11115,11191],{"className":11114},[1981,1982],[355,11116,11118,11188],{"className":11117},[1986],[355,11119,11121,11169,11177],{"className":11120,"style":9284},[1990],[355,11122,11123,11126],{"style":9287},[355,11124],{"className":11125,"style":9291},[1998],[355,11127,11129],{"className":11128},[1951],[355,11130,11132,11135],{"className":11131},[1951],[355,11133,1962],{"className":11134},[1951,1952],[355,11136,11138],{"className":11137},[1977],[355,11139,11141,11161],{"className":11140},[1981,1982],[355,11142,11144,11158],{"className":11143},[1986],[355,11145,11147],{"className":11146,"style":2471},[1990],[355,11148,11149,11152],{"style":1994},[355,11150],{"className":11151,"style":1999},[1998],[355,11153,11155],{"className":11154},[2003,2004,2005,2006],[355,11156,2124],{"className":11157},[1951,1952,2006],[355,11159,2023],{"className":11160},[2022],[355,11162,11164],{"className":11163},[1986],[355,11165,11167],{"className":11166,"style":2250},[1990],[355,11168],{},[355,11170,11171,11174],{"style":9417},[355,11172],{"className":11173,"style":9291},[1998],[355,11175],{"className":11176,"style":9425},[9424],[355,11178,11179,11182],{"style":9428},[355,11180],{"className":11181,"style":9291},[1998],[355,11183,11185],{"className":11184},[1951],[355,11186,9179],{"className":11187},[1951],[355,11189,2023],{"className":11190},[2022],[355,11192,11194],{"className":11193},[1986],[355,11195,11198],{"className":11196,"style":11197},[1990],"height:0.836em;",[355,11199],{},[355,11201],{"className":11202},[2417,9270],[355,11204],{"className":11205,"style":2064},[2036],[355,11207,2060],{"className":11208,"style":2059},[2056,2057,2058],[355,11210],{"className":11211,"style":2064},[2036],[355,11213,11215,11221,11224,11353],{"className":11214},[10395],[355,11216,11218],{"className":11217,"style":10400},[2168,10399],[355,11219,2169],{"className":11220},[10404,10349],[355,11222,10282],{"className":11223},[1951],[355,11225,11227,11230],{"className":11226},[1951],[355,11228,2078],{"className":11229},[1951,1952],[355,11231,11233],{"className":11232},[1977],[355,11234,11236,11344],{"className":11235},[1981,1982],[355,11237,11239,11341],{"className":11238},[1986],[355,11240,11242],{"className":11241,"style":2101},[1990],[355,11243,11244,11247],{"style":1994},[355,11245],{"className":11246,"style":1999},[1998],[355,11248,11250],{"className":11249},[2003,2004,2005,2006],[355,11251,11253,11256,11259],{"className":11252},[1951,2006],[355,11254,10315],{"className":11255},[1951,1952,2006],[355,11257,2117],{"className":11258,"style":2116},[1951,1952,2006],[355,11260,11262,11265],{"className":11261},[1951,2006],[355,11263,2124],{"className":11264},[1951,1952,2006],[355,11266,11268],{"className":11267},[1977],[355,11269,11271,11332],{"className":11270},[1981,1982],[355,11272,11274,11329],{"className":11273},[1986],[355,11275,11277],{"className":11276,"style":10337},[1990],[355,11278,11279,11282],{"style":10340},[355,11280],{"className":11281,"style":10344},[1998],[355,11283,11285],{"className":11284},[2003,10348,10349,2006],[355,11286,11288],{"className":11287},[1951,2006],[355,11289,11291,11294],{"className":11290},[1951,2006],[355,11292,2124],{"className":11293},[1951,1952,2006],[355,11295,11297],{"className":11296},[1977],[355,11298,11300,11320],{"className":11299},[1981,1982],[355,11301,11303,11317],{"className":11302},[1986],[355,11304,11307],{"className":11305,"style":11306},[1990],"height:0.3448em;",[355,11308,11310,11314],{"style":11309},"top:-2.3448em;margin-left:0em;margin-right:0.1em;",[355,11311],{"className":11312,"style":11313},[1998],"height:2.6595em;",[355,11315,2313],{"className":11316},[1951,1952,2006],[355,11318,2023],{"className":11319},[2022],[355,11321,11323],{"className":11322},[1986],[355,11324,11327],{"className":11325,"style":11326},[1990],"height:0.3147em;",[355,11328],{},[355,11330,2023],{"className":11331},[2022],[355,11333,11335],{"className":11334},[1986],[355,11336,11339],{"className":11337,"style":11338},[1990],"height:0.3678em;",[355,11340],{},[355,11342,2023],{"className":11343},[2022],[355,11345,11347],{"className":11346},[1986],[355,11348,11351],{"className":11349,"style":11350},[1990],"height:0.4075em;",[355,11352],{},[355,11354,11356],{"className":11355,"style":10400},[2417,10399],[355,11357,2418],{"className":11358},[10404,10349],[19,11360,10714],{},[443,11362,11363,11505],{},[446,11364,11365,11504],{},[355,11366,11368],{"className":11367},[1933],[355,11369,11371],{"className":11370,"ariaHidden":1938},[1937],[355,11372,11374,11378,11381],{"className":11373},[1942],[355,11375],{"className":11376,"style":11377},[1946],"height:1.0908em;vertical-align:-0.4075em;",[355,11379,10282],{"className":11380},[1951],[355,11382,11384,11387],{"className":11383},[1951],[355,11385,2078],{"className":11386},[1951,1952],[355,11388,11390],{"className":11389},[1977],[355,11391,11393,11496],{"className":11392},[1981,1982],[355,11394,11396,11493],{"className":11395},[1986],[355,11397,11399],{"className":11398,"style":2101},[1990],[355,11400,11401,11404],{"style":1994},[355,11402],{"className":11403,"style":1999},[1998],[355,11405,11407],{"className":11406},[2003,2004,2005,2006],[355,11408,11410,11413,11416],{"className":11409},[1951,2006],[355,11411,10315],{"className":11412},[1951,1952,2006],[355,11414,2117],{"className":11415,"style":2116},[1951,1952,2006],[355,11417,11419,11422],{"className":11418},[1951,2006],[355,11420,2124],{"className":11421},[1951,1952,2006],[355,11423,11425],{"className":11424},[1977],[355,11426,11428,11485],{"className":11427},[1981,1982],[355,11429,11431,11482],{"className":11430},[1986],[355,11432,11434],{"className":11433,"style":10337},[1990],[355,11435,11436,11439],{"style":10340},[355,11437],{"className":11438,"style":10344},[1998],[355,11440,11442],{"className":11441},[2003,10348,10349,2006],[355,11443,11445],{"className":11444},[1951,2006],[355,11446,11448,11451],{"className":11447},[1951,2006],[355,11449,2124],{"className":11450},[1951,1952,2006],[355,11452,11454],{"className":11453},[1977],[355,11455,11457,11474],{"className":11456},[1981,1982],[355,11458,11460,11471],{"className":11459},[1986],[355,11461,11463],{"className":11462,"style":11306},[1990],[355,11464,11465,11468],{"style":11309},[355,11466],{"className":11467,"style":11313},[1998],[355,11469,2313],{"className":11470},[1951,1952,2006],[355,11472,2023],{"className":11473},[2022],[355,11475,11477],{"className":11476},[1986],[355,11478,11480],{"className":11479,"style":11326},[1990],[355,11481],{},[355,11483,2023],{"className":11484},[2022],[355,11486,11488],{"className":11487},[1986],[355,11489,11491],{"className":11490,"style":11338},[1990],[355,11492],{},[355,11494,2023],{"className":11495},[2022],[355,11497,11499],{"className":11498},[1986],[355,11500,11502],{"className":11501,"style":11350},[1990],[355,11503],{}," = Lead Time du composant i",[446,11506,11507,11560],{},[355,11508,11510],{"className":11509},[1933],[355,11511,11513],{"className":11512,"ariaHidden":1938},[1937],[355,11514,11516,11520],{"className":11515},[1942],[355,11517],{"className":11518,"style":11519},[1946],"height:0.5806em;vertical-align:-0.15em;",[355,11521,11523,11526],{"className":11522},[1951],[355,11524,1962],{"className":11525},[1951,1952],[355,11527,11529],{"className":11528},[1977],[355,11530,11532,11552],{"className":11531},[1981,1982],[355,11533,11535,11549],{"className":11534},[1986],[355,11536,11538],{"className":11537,"style":2471},[1990],[355,11539,11540,11543],{"style":1994},[355,11541],{"className":11542,"style":1999},[1998],[355,11544,11546],{"className":11545},[2003,2004,2005,2006],[355,11547,2124],{"className":11548},[1951,1952,2006],[355,11550,2023],{"className":11551},[2022],[355,11553,11555],{"className":11554},[1986],[355,11556,11558],{"className":11557,"style":2250},[1990],[355,11559],{}," = Nombre de composants du produit",[19,11562,11563],{},[34,11564,11565],{},"Niveau Domaine",[355,11567,11569],{"className":11568},[1929],[355,11570,11572],{"className":11571},[1933],[355,11573,11575,11681],{"className":11574,"ariaHidden":1938},[1937],[355,11576,11578,11581,11584,11672,11675,11678],{"className":11577},[1942],[355,11579],{"className":11580,"style":1947},[1946],[355,11582,10282],{"className":11583},[1951],[355,11585,11587,11590],{"className":11586},[1951],[355,11588,2078],{"className":11589},[1951,1952],[355,11591,11593],{"className":11592},[1977],[355,11594,11596,11664],{"className":11595},[1981,1982],[355,11597,11599,11661],{"className":11598},[1986],[355,11600,11602],{"className":11601,"style":2101},[1990],[355,11603,11604,11607],{"style":1994},[355,11605],{"className":11606,"style":1999},[1998],[355,11608,11610],{"className":11609},[2003,2004,2005,2006],[355,11611,11613,11616,11619],{"className":11612},[1951,2006],[355,11614,10315],{"className":11615},[1951,1952,2006],[355,11617,2117],{"className":11618,"style":2116},[1951,1952,2006],[355,11620,11622,11625],{"className":11621},[1951,2006],[355,11623,2124],{"className":11624},[1951,1952,2006],[355,11626,11628],{"className":11627},[1977],[355,11629,11631,11652],{"className":11630},[1981,1982],[355,11632,11634,11649],{"className":11633},[1986],[355,11635,11637],{"className":11636,"style":11306},[1990],[355,11638,11640,11643],{"style":11639},"top:-2.3488em;margin-left:0em;margin-right:0.0714em;",[355,11641],{"className":11642,"style":10344},[1998],[355,11644,11646],{"className":11645},[2003,10348,10349,2006],[355,11647,2458],{"className":11648},[1951,1952,2006],[355,11650,2023],{"className":11651},[2022],[355,11653,11655],{"className":11654},[1986],[355,11656,11659],{"className":11657,"style":11658},[1990],"height:0.1512em;",[355,11660],{},[355,11662,2023],{"className":11663},[2022],[355,11665,11667],{"className":11666},[1986],[355,11668,11670],{"className":11669,"style":2030},[1990],[355,11671],{},[355,11673],{"className":11674,"style":2037},[2036],[355,11676,2042],{"className":11677},[2041],[355,11679],{"className":11680,"style":2037},[2036],[355,11682,11684,11687,11786,11789,11792,11795],{"className":11683},[1942],[355,11685],{"className":11686,"style":9263},[1946],[355,11688,11690,11693,11783],{"className":11689},[1951],[355,11691],{"className":11692},[2168,9270],[355,11694,11696],{"className":11695},[9274],[355,11697,11699,11775],{"className":11698},[1981,1982],[355,11700,11702,11772],{"className":11701},[1986],[355,11703,11705,11753,11761],{"className":11704,"style":9284},[1990],[355,11706,11707,11710],{"style":9287},[355,11708],{"className":11709,"style":9291},[1998],[355,11711,11713],{"className":11712},[1951],[355,11714,11716,11719],{"className":11715},[1951],[355,11717,1962],{"className":11718},[1951,1952],[355,11720,11722],{"className":11721},[1977],[355,11723,11725,11745],{"className":11724},[1981,1982],[355,11726,11728,11742],{"className":11727},[1986],[355,11729,11731],{"className":11730,"style":2471},[1990],[355,11732,11733,11736],{"style":1994},[355,11734],{"className":11735,"style":1999},[1998],[355,11737,11739],{"className":11738},[2003,2004,2005,2006],[355,11740,19],{"className":11741},[1951,1952,2006],[355,11743,2023],{"className":11744},[2022],[355,11746,11748],{"className":11747},[1986],[355,11749,11751],{"className":11750,"style":2030},[1990],[355,11752],{},[355,11754,11755,11758],{"style":9417},[355,11756],{"className":11757,"style":9291},[1998],[355,11759],{"className":11760,"style":9425},[9424],[355,11762,11763,11766],{"style":9428},[355,11764],{"className":11765,"style":9291},[1998],[355,11767,11769],{"className":11768},[1951],[355,11770,9179],{"className":11771},[1951],[355,11773,2023],{"className":11774},[2022],[355,11776,11778],{"className":11777},[1986],[355,11779,11781],{"className":11780,"style":9447},[1990],[355,11782],{},[355,11784],{"className":11785},[2417,9270],[355,11787],{"className":11788,"style":2064},[2036],[355,11790,2060],{"className":11791,"style":2059},[2056,2057,2058],[355,11793],{"className":11794,"style":2064},[2036],[355,11796,11798,11804,11807,11930],{"className":11797},[10395],[355,11799,11801],{"className":11800,"style":10400},[2168,10399],[355,11802,2169],{"className":11803},[10404,10349],[355,11805,10282],{"className":11806},[1951],[355,11808,11810,11813],{"className":11809},[1951],[355,11811,2078],{"className":11812},[1951,1952],[355,11814,11816],{"className":11815},[1977],[355,11817,11819,11922],{"className":11818},[1981,1982],[355,11820,11822,11919],{"className":11821},[1986],[355,11823,11825],{"className":11824,"style":2101},[1990],[355,11826,11827,11830],{"style":1994},[355,11828],{"className":11829,"style":1999},[1998],[355,11831,11833],{"className":11832},[2003,2004,2005,2006],[355,11834,11836,11839,11842],{"className":11835},[1951,2006],[355,11837,10315],{"className":11838},[1951,1952,2006],[355,11840,2117],{"className":11841,"style":2116},[1951,1952,2006],[355,11843,11845,11848],{"className":11844},[1951,2006],[355,11846,2124],{"className":11847},[1951,1952,2006],[355,11849,11851],{"className":11850},[1977],[355,11852,11854,11911],{"className":11853},[1981,1982],[355,11855,11857,11908],{"className":11856},[1986],[355,11858,11860],{"className":11859,"style":10337},[1990],[355,11861,11862,11865],{"style":10340},[355,11863],{"className":11864,"style":10344},[1998],[355,11866,11868],{"className":11867},[2003,10348,10349,2006],[355,11869,11871],{"className":11870},[1951,2006],[355,11872,11874,11877],{"className":11873},[1951,2006],[355,11875,19],{"className":11876},[1951,1952,2006],[355,11878,11880],{"className":11879},[1977],[355,11881,11883,11900],{"className":11882},[1981,1982],[355,11884,11886,11897],{"className":11885},[1986],[355,11887,11889],{"className":11888,"style":11306},[1990],[355,11890,11891,11894],{"style":11309},[355,11892],{"className":11893,"style":11313},[1998],[355,11895,2313],{"className":11896},[1951,1952,2006],[355,11898,2023],{"className":11899},[2022],[355,11901,11903],{"className":11902},[1986],[355,11904,11906],{"className":11905,"style":11326},[1990],[355,11907],{},[355,11909,2023],{"className":11910},[2022],[355,11912,11914],{"className":11913},[1986],[355,11915,11917],{"className":11916,"style":11338},[1990],[355,11918],{},[355,11920,2023],{"className":11921},[2022],[355,11923,11925],{"className":11924},[1986],[355,11926,11928],{"className":11927,"style":11350},[1990],[355,11929],{},[355,11931,11933],{"className":11932,"style":10400},[2417,10399],[355,11934,2418],{"className":11935},[10404,10349],[19,11937,10714],{},[443,11939,11940,12081],{},[446,11941,11942,12080],{},[355,11943,11945],{"className":11944},[1933],[355,11946,11948],{"className":11947,"ariaHidden":1938},[1937],[355,11949,11951,11954,11957],{"className":11950},[1942],[355,11952],{"className":11953,"style":11377},[1946],[355,11955,10282],{"className":11956},[1951],[355,11958,11960,11963],{"className":11959},[1951],[355,11961,2078],{"className":11962},[1951,1952],[355,11964,11966],{"className":11965},[1977],[355,11967,11969,12072],{"className":11968},[1981,1982],[355,11970,11972,12069],{"className":11971},[1986],[355,11973,11975],{"className":11974,"style":2101},[1990],[355,11976,11977,11980],{"style":1994},[355,11978],{"className":11979,"style":1999},[1998],[355,11981,11983],{"className":11982},[2003,2004,2005,2006],[355,11984,11986,11989,11992],{"className":11985},[1951,2006],[355,11987,10315],{"className":11988},[1951,1952,2006],[355,11990,2117],{"className":11991,"style":2116},[1951,1952,2006],[355,11993,11995,11998],{"className":11994},[1951,2006],[355,11996,2124],{"className":11997},[1951,1952,2006],[355,11999,12001],{"className":12000},[1977],[355,12002,12004,12061],{"className":12003},[1981,1982],[355,12005,12007,12058],{"className":12006},[1986],[355,12008,12010],{"className":12009,"style":10337},[1990],[355,12011,12012,12015],{"style":10340},[355,12013],{"className":12014,"style":10344},[1998],[355,12016,12018],{"className":12017},[2003,10348,10349,2006],[355,12019,12021],{"className":12020},[1951,2006],[355,12022,12024,12027],{"className":12023},[1951,2006],[355,12025,19],{"className":12026},[1951,1952,2006],[355,12028,12030],{"className":12029},[1977],[355,12031,12033,12050],{"className":12032},[1981,1982],[355,12034,12036,12047],{"className":12035},[1986],[355,12037,12039],{"className":12038,"style":11306},[1990],[355,12040,12041,12044],{"style":11309},[355,12042],{"className":12043,"style":11313},[1998],[355,12045,2313],{"className":12046},[1951,1952,2006],[355,12048,2023],{"className":12049},[2022],[355,12051,12053],{"className":12052},[1986],[355,12054,12056],{"className":12055,"style":11326},[1990],[355,12057],{},[355,12059,2023],{"className":12060},[2022],[355,12062,12064],{"className":12063},[1986],[355,12065,12067],{"className":12066,"style":11338},[1990],[355,12068],{},[355,12070,2023],{"className":12071},[2022],[355,12073,12075],{"className":12074},[1986],[355,12076,12078],{"className":12077,"style":11350},[1990],[355,12079],{}," = Lead Time du produit i",[446,12082,12083,12139],{},[355,12084,12086],{"className":12085},[1933],[355,12087,12089],{"className":12088,"ariaHidden":1938},[1937],[355,12090,12092,12096],{"className":12091},[1942],[355,12093],{"className":12094,"style":12095},[1946],"height:0.7167em;vertical-align:-0.2861em;",[355,12097,12099],{"className":12098},[1951],[355,12100,12102,12105],{"className":12101},[1951],[355,12103,1962],{"className":12104},[1951,1952],[355,12106,12108],{"className":12107},[1977],[355,12109,12111,12131],{"className":12110},[1981,1982],[355,12112,12114,12128],{"className":12113},[1986],[355,12115,12117],{"className":12116,"style":2471},[1990],[355,12118,12119,12122],{"style":1994},[355,12120],{"className":12121,"style":1999},[1998],[355,12123,12125],{"className":12124},[2003,2004,2005,2006],[355,12126,19],{"className":12127},[1951,1952,2006],[355,12129,2023],{"className":12130},[2022],[355,12132,12134],{"className":12133},[1986],[355,12135,12137],{"className":12136,"style":2030},[1990],[355,12138],{}," = Nombre de produits dans le domaine",[19,12141,12142],{},[34,12143,12144],{},"Niveau Plateforme",[355,12146,12148],{"className":12147},[1929],[355,12149,12151],{"className":12150},[1933],[355,12152,12154,12261],{"className":12153,"ariaHidden":1938},[1937],[355,12155,12157,12160,12163,12252,12255,12258],{"className":12156},[1942],[355,12158],{"className":12159,"style":1947},[1946],[355,12161,10282],{"className":12162},[1951],[355,12164,12166,12169],{"className":12165},[1951],[355,12167,2078],{"className":12168},[1951,1952],[355,12170,12172],{"className":12171},[1977],[355,12173,12175,12244],{"className":12174},[1981,1982],[355,12176,12178,12241],{"className":12177},[1986],[355,12179,12181],{"className":12180,"style":2101},[1990],[355,12182,12183,12186],{"style":1994},[355,12184],{"className":12185,"style":1999},[1998],[355,12187,12189],{"className":12188},[2003,2004,2005,2006],[355,12190,12192,12195,12198],{"className":12191},[1951,2006],[355,12193,10315],{"className":12194},[1951,1952,2006],[355,12196,2117],{"className":12197,"style":2116},[1951,1952,2006],[355,12199,12201,12204],{"className":12200},[1951,2006],[355,12202,2124],{"className":12203},[1951,1952,2006],[355,12205,12207],{"className":12206},[1977],[355,12208,12210,12232],{"className":12209},[1981,1982],[355,12211,12213,12229],{"className":12212},[1986],[355,12214,12216],{"className":12215,"style":11306},[1990],[355,12217,12219,12222],{"style":12218},"top:-2.3567em;margin-left:0em;margin-right:0.0714em;",[355,12220],{"className":12221,"style":10344},[1998],[355,12223,12225],{"className":12224},[2003,10348,10349,2006],[355,12226,12228],{"className":12227,"style":9952},[1951,1952,2006],"P",[355,12230,2023],{"className":12231},[2022],[355,12233,12235],{"className":12234},[1986],[355,12236,12239],{"className":12237,"style":12238},[1990],"height:0.1433em;",[355,12240],{},[355,12242,2023],{"className":12243},[2022],[355,12245,12247],{"className":12246},[1986],[355,12248,12250],{"className":12249,"style":2030},[1990],[355,12251],{},[355,12253],{"className":12254,"style":2037},[2036],[355,12256,2042],{"className":12257},[2041],[355,12259],{"className":12260,"style":2037},[2036],[355,12262,12264,12267,12366,12369,12372,12375],{"className":12263},[1942],[355,12265],{"className":12266,"style":11102},[1946],[355,12268,12270,12273,12363],{"className":12269},[1951],[355,12271],{"className":12272},[2168,9270],[355,12274,12276],{"className":12275},[9274],[355,12277,12279,12355],{"className":12278},[1981,1982],[355,12280,12282,12352],{"className":12281},[1986],[355,12283,12285,12333,12341],{"className":12284,"style":9284},[1990],[355,12286,12287,12290],{"style":9287},[355,12288],{"className":12289,"style":9291},[1998],[355,12291,12293],{"className":12292},[1951],[355,12294,12296,12299],{"className":12295},[1951],[355,12297,1962],{"className":12298},[1951,1952],[355,12300,12302],{"className":12301},[1977],[355,12303,12305,12325],{"className":12304},[1981,1982],[355,12306,12308,12322],{"className":12307},[1986],[355,12309,12311],{"className":12310,"style":2101},[1990],[355,12312,12313,12316],{"style":1994},[355,12314],{"className":12315,"style":1999},[1998],[355,12317,12319],{"className":12318},[2003,2004,2005,2006],[355,12320,2458],{"className":12321},[1951,1952,2006],[355,12323,2023],{"className":12324},[2022],[355,12326,12328],{"className":12327},[1986],[355,12329,12331],{"className":12330,"style":2250},[1990],[355,12332],{},[355,12334,12335,12338],{"style":9417},[355,12336],{"className":12337,"style":9291},[1998],[355,12339],{"className":12340,"style":9425},[9424],[355,12342,12343,12346],{"style":9428},[355,12344],{"className":12345,"style":9291},[1998],[355,12347,12349],{"className":12348},[1951],[355,12350,9179],{"className":12351},[1951],[355,12353,2023],{"className":12354},[2022],[355,12356,12358],{"className":12357},[1986],[355,12359,12361],{"className":12360,"style":11197},[1990],[355,12362],{},[355,12364],{"className":12365},[2417,9270],[355,12367],{"className":12368,"style":2064},[2036],[355,12370,2060],{"className":12371,"style":2059},[2056,2057,2058],[355,12373],{"className":12374,"style":2064},[2036],[355,12376,12378,12384,12387,12512],{"className":12377},[10395],[355,12379,12381],{"className":12380,"style":10400},[2168,10399],[355,12382,2169],{"className":12383},[10404,10349],[355,12385,10282],{"className":12386},[1951],[355,12388,12390,12393],{"className":12389},[1951],[355,12391,2078],{"className":12392},[1951,1952],[355,12394,12396],{"className":12395},[1977],[355,12397,12399,12503],{"className":12398},[1981,1982],[355,12400,12402,12500],{"className":12401},[1986],[355,12403,12405],{"className":12404,"style":2101},[1990],[355,12406,12407,12410],{"style":1994},[355,12408],{"className":12409,"style":1999},[1998],[355,12411,12413],{"className":12412},[2003,2004,2005,2006],[355,12414,12416,12419,12422],{"className":12415},[1951,2006],[355,12417,10315],{"className":12418},[1951,1952,2006],[355,12420,2117],{"className":12421,"style":2116},[1951,1952,2006],[355,12423,12425,12428],{"className":12424},[1951,2006],[355,12426,2124],{"className":12427},[1951,1952,2006],[355,12429,12431],{"className":12430},[1977],[355,12432,12434,12491],{"className":12433},[1981,1982],[355,12435,12437,12488],{"className":12436},[1986],[355,12438,12440],{"className":12439,"style":11306},[1990],[355,12441,12442,12445],{"style":11639},[355,12443],{"className":12444,"style":10344},[1998],[355,12446,12448],{"className":12447},[2003,10348,10349,2006],[355,12449,12451],{"className":12450},[1951,2006],[355,12452,12454,12457],{"className":12453},[1951,2006],[355,12455,2458],{"className":12456},[1951,1952,2006],[355,12458,12460],{"className":12459},[1977],[355,12461,12463,12480],{"className":12462},[1981,1982],[355,12464,12466,12477],{"className":12465},[1986],[355,12467,12469],{"className":12468,"style":11306},[1990],[355,12470,12471,12474],{"style":11309},[355,12472],{"className":12473,"style":11313},[1998],[355,12475,2313],{"className":12476},[1951,1952,2006],[355,12478,2023],{"className":12479},[2022],[355,12481,12483],{"className":12482},[1986],[355,12484,12486],{"className":12485,"style":11326},[1990],[355,12487],{},[355,12489,2023],{"className":12490},[2022],[355,12492,12494],{"className":12493},[1986],[355,12495,12498],{"className":12496,"style":12497},[1990],"height:0.376em;",[355,12499],{},[355,12501,2023],{"className":12502},[2022],[355,12504,12506],{"className":12505},[1986],[355,12507,12510],{"className":12508,"style":12509},[1990],"height:0.4132em;",[355,12511],{},[355,12513,12515],{"className":12514,"style":10400},[2417,10399],[355,12516,2418],{"className":12517},[10404,10349],[19,12519,10714],{},[443,12521,12522,12664],{},[446,12523,12524,12663],{},[355,12525,12527],{"className":12526},[1933],[355,12528,12530],{"className":12529,"ariaHidden":1938},[1937],[355,12531,12533,12537,12540],{"className":12532},[1942],[355,12534],{"className":12535,"style":12536},[1946],"height:1.0965em;vertical-align:-0.4132em;",[355,12538,10282],{"className":12539},[1951],[355,12541,12543,12546],{"className":12542},[1951],[355,12544,2078],{"className":12545},[1951,1952],[355,12547,12549],{"className":12548},[1977],[355,12550,12552,12655],{"className":12551},[1981,1982],[355,12553,12555,12652],{"className":12554},[1986],[355,12556,12558],{"className":12557,"style":2101},[1990],[355,12559,12560,12563],{"style":1994},[355,12561],{"className":12562,"style":1999},[1998],[355,12564,12566],{"className":12565},[2003,2004,2005,2006],[355,12567,12569,12572,12575],{"className":12568},[1951,2006],[355,12570,10315],{"className":12571},[1951,1952,2006],[355,12573,2117],{"className":12574,"style":2116},[1951,1952,2006],[355,12576,12578,12581],{"className":12577},[1951,2006],[355,12579,2124],{"className":12580},[1951,1952,2006],[355,12582,12584],{"className":12583},[1977],[355,12585,12587,12644],{"className":12586},[1981,1982],[355,12588,12590,12641],{"className":12589},[1986],[355,12591,12593],{"className":12592,"style":11306},[1990],[355,12594,12595,12598],{"style":11639},[355,12596],{"className":12597,"style":10344},[1998],[355,12599,12601],{"className":12600},[2003,10348,10349,2006],[355,12602,12604],{"className":12603},[1951,2006],[355,12605,12607,12610],{"className":12606},[1951,2006],[355,12608,2458],{"className":12609},[1951,1952,2006],[355,12611,12613],{"className":12612},[1977],[355,12614,12616,12633],{"className":12615},[1981,1982],[355,12617,12619,12630],{"className":12618},[1986],[355,12620,12622],{"className":12621,"style":11306},[1990],[355,12623,12624,12627],{"style":11309},[355,12625],{"className":12626,"style":11313},[1998],[355,12628,2313],{"className":12629},[1951,1952,2006],[355,12631,2023],{"className":12632},[2022],[355,12634,12636],{"className":12635},[1986],[355,12637,12639],{"className":12638,"style":11326},[1990],[355,12640],{},[355,12642,2023],{"className":12643},[2022],[355,12645,12647],{"className":12646},[1986],[355,12648,12650],{"className":12649,"style":12497},[1990],[355,12651],{},[355,12653,2023],{"className":12654},[2022],[355,12656,12658],{"className":12657},[1986],[355,12659,12661],{"className":12660,"style":12509},[1990],[355,12662],{}," = Lead Time du domaine i",[446,12665,12666,12718],{},[355,12667,12669],{"className":12668},[1933],[355,12670,12672],{"className":12671,"ariaHidden":1938},[1937],[355,12673,12675,12678],{"className":12674},[1942],[355,12676],{"className":12677,"style":11519},[1946],[355,12679,12681,12684],{"className":12680},[1951],[355,12682,1962],{"className":12683},[1951,1952],[355,12685,12687],{"className":12686},[1977],[355,12688,12690,12710],{"className":12689},[1981,1982],[355,12691,12693,12707],{"className":12692},[1986],[355,12694,12696],{"className":12695,"style":2101},[1990],[355,12697,12698,12701],{"style":1994},[355,12699],{"className":12700,"style":1999},[1998],[355,12702,12704],{"className":12703},[2003,2004,2005,2006],[355,12705,2458],{"className":12706},[1951,1952,2006],[355,12708,2023],{"className":12709},[2022],[355,12711,12713],{"className":12712},[1986],[355,12714,12716],{"className":12715,"style":2250},[1990],[355,12717],{}," = Nombre de domaines dans la plateforme",[84,12720,8219],{"id":12721},"deployment-frequency",[19,12723,12724],{},[34,12725,10263],{},[355,12727,12729],{"className":12728},[1929],[355,12730,12732],{"className":12731},[1933],[355,12733,12735,12799],{"className":12734,"ariaHidden":1938},[1937],[355,12736,12738,12741,12790,12793,12796],{"className":12737},[1942],[355,12739],{"className":12740,"style":9196},[1946],[355,12742,12744,12747],{"className":12743},[1951],[355,12745,2117],{"className":12746,"style":2116},[1951,1952],[355,12748,12750],{"className":12749},[1977],[355,12751,12753,12782],{"className":12752},[1981,1982],[355,12754,12756,12779],{"className":12755},[1986],[355,12757,12759],{"className":12758,"style":2471},[1990],[355,12760,12761,12764],{"style":9217},[355,12762],{"className":12763,"style":1999},[1998],[355,12765,12767],{"className":12766},[2003,2004,2005,2006],[355,12768,12770,12773,12776],{"className":12769},[1951,2006],[355,12771,9230],{"className":12772},[1951,1952,2006],[355,12774,2068],{"className":12775},[1951,1952,2006],[355,12777,19],{"className":12778},[1951,1952,2006],[355,12780,2023],{"className":12781},[2022],[355,12783,12785],{"className":12784},[1986],[355,12786,12788],{"className":12787,"style":2030},[1990],[355,12789],{},[355,12791],{"className":12792,"style":2037},[2036],[355,12794,2042],{"className":12795},[2041],[355,12797],{"className":12798,"style":2037},[2036],[355,12800,12802,12805],{"className":12801},[1942],[355,12803],{"className":12804,"style":9263},[1946],[355,12806,12808,12811,12974],{"className":12807},[1951],[355,12809],{"className":12810},[2168,9270],[355,12812,12814],{"className":12813},[9274],[355,12815,12817,12966],{"className":12816},[1981,1982],[355,12818,12820,12963],{"className":12819},[1986],[355,12821,12823,12944,12952],{"className":12822,"style":9284},[1990],[355,12824,12825,12828],{"style":9287},[355,12826],{"className":12827,"style":9291},[1998],[355,12829,12831,12883,12886,12889,12892],{"className":12830},[1951],[355,12832,12834,12837],{"className":12833},[1951],[355,12835,2078],{"className":12836},[1951,1952],[355,12838,12840],{"className":12839},[1977],[355,12841,12843,12875],{"className":12842},[1981,1982],[355,12844,12846,12872],{"className":12845},[1986],[355,12847,12849],{"className":12848,"style":2101},[1990],[355,12850,12851,12854],{"style":1994},[355,12852],{"className":12853,"style":1999},[1998],[355,12855,12857],{"className":12856},[2003,2004,2005,2006],[355,12858,12860,12863,12866,12869],{"className":12859},[1951,2006],[355,12861,2458],{"className":12862},[1951,1952,2006],[355,12864,2196],{"className":12865},[1951,1952,2006],[355,12867,19],{"className":12868},[1951,1952,2006],[355,12870,9339],{"className":12871},[1951,2006],[355,12873,2023],{"className":12874},[2022],[355,12876,12878],{"className":12877},[1986],[355,12879,12881],{"className":12880,"style":2030},[1990],[355,12882],{},[355,12884],{"className":12885,"style":2149},[2036],[355,12887,2154],{"className":12888},[2153],[355,12890],{"className":12891,"style":2149},[2036],[355,12893,12895,12898],{"className":12894},[1951],[355,12896,2078],{"className":12897},[1951,1952],[355,12899,12901],{"className":12900},[1977],[355,12902,12904,12936],{"className":12903},[1981,1982],[355,12905,12907,12933],{"className":12906},[1986],[355,12908,12910],{"className":12909,"style":2101},[1990],[355,12911,12912,12915],{"style":1994},[355,12913],{"className":12914,"style":1999},[1998],[355,12916,12918],{"className":12917},[2003,2004,2005,2006],[355,12919,12921,12924,12927,12930],{"className":12920},[1951,2006],[355,12922,2458],{"className":12923},[1951,1952,2006],[355,12925,2196],{"className":12926},[1951,1952,2006],[355,12928,19],{"className":12929},[1951,1952,2006],[355,12931,9179],{"className":12932},[1951,2006],[355,12934,2023],{"className":12935},[2022],[355,12937,12939],{"className":12938},[1986],[355,12940,12942],{"className":12941,"style":2030},[1990],[355,12943],{},[355,12945,12946,12949],{"style":9417},[355,12947],{"className":12948,"style":9291},[1998],[355,12950],{"className":12951,"style":9425},[9424],[355,12953,12954,12957],{"style":9428},[355,12955],{"className":12956,"style":9291},[1998],[355,12958,12960],{"className":12959},[1951],[355,12961,9179],{"className":12962},[1951],[355,12964,2023],{"className":12965},[2022],[355,12967,12969],{"className":12968},[1986],[355,12970,12972],{"className":12971,"style":9447},[1990],[355,12973],{},[355,12975],{"className":12976},[2417,9270],[19,12978,10714],{},[443,12980,12981,13049],{},[446,12982,12983,13048],{},[355,12984,12986],{"className":12985},[1933],[355,12987,12989],{"className":12988,"ariaHidden":1938},[1937],[355,12990,12992,12996],{"className":12991},[1942],[355,12993],{"className":12994,"style":12995},[1946],"height:0.9012em;vertical-align:-0.2861em;",[355,12997,12999,13002],{"className":12998},[1951],[355,13000,2078],{"className":13001},[1951,1952],[355,13003,13005],{"className":13004},[1977],[355,13006,13008,13040],{"className":13007},[1981,1982],[355,13009,13011,13037],{"className":13010},[1986],[355,13012,13014],{"className":13013,"style":2101},[1990],[355,13015,13016,13019],{"style":1994},[355,13017],{"className":13018,"style":1999},[1998],[355,13020,13022],{"className":13021},[2003,2004,2005,2006],[355,13023,13025,13028,13031,13034],{"className":13024},[1951,2006],[355,13026,2458],{"className":13027},[1951,1952,2006],[355,13029,2196],{"className":13030},[1951,1952,2006],[355,13032,19],{"className":13033},[1951,1952,2006],[355,13035,9339],{"className":13036},[1951,2006],[355,13038,2023],{"className":13039},[2022],[355,13041,13043],{"className":13042},[1986],[355,13044,13046],{"className":13045,"style":2030},[1990],[355,13047],{}," = Date du déploiement actuel",[446,13050,13051,13115],{},[355,13052,13054],{"className":13053},[1933],[355,13055,13057],{"className":13056,"ariaHidden":1938},[1937],[355,13058,13060,13063],{"className":13059},[1942],[355,13061],{"className":13062,"style":12995},[1946],[355,13064,13066,13069],{"className":13065},[1951],[355,13067,2078],{"className":13068},[1951,1952],[355,13070,13072],{"className":13071},[1977],[355,13073,13075,13107],{"className":13074},[1981,1982],[355,13076,13078,13104],{"className":13077},[1986],[355,13079,13081],{"className":13080,"style":2101},[1990],[355,13082,13083,13086],{"style":1994},[355,13084],{"className":13085,"style":1999},[1998],[355,13087,13089],{"className":13088},[2003,2004,2005,2006],[355,13090,13092,13095,13098,13101],{"className":13091},[1951,2006],[355,13093,2458],{"className":13094},[1951,1952,2006],[355,13096,2196],{"className":13097},[1951,1952,2006],[355,13099,19],{"className":13100},[1951,1952,2006],[355,13102,9179],{"className":13103},[1951,2006],[355,13105,2023],{"className":13106},[2022],[355,13108,13110],{"className":13109},[1986],[355,13111,13113],{"className":13112,"style":2030},[1990],[355,13114],{}," = Date du déploiement précédent",[19,13117,13118],{},[34,13119,10979],{},[355,13121,13123],{"className":13122},[1929],[355,13124,13126],{"className":13125},[1933],[355,13127,13129,13193],{"className":13128,"ariaHidden":1938},[1937],[355,13130,13132,13135,13184,13187,13190],{"className":13131},[1942],[355,13133],{"className":13134,"style":9196},[1946],[355,13136,13138,13141],{"className":13137},[1951],[355,13139,2117],{"className":13140,"style":2116},[1951,1952],[355,13142,13144],{"className":13143},[1977],[355,13145,13147,13176],{"className":13146},[1981,1982],[355,13148,13150,13173],{"className":13149},[1986],[355,13151,13153],{"className":13152,"style":2101},[1990],[355,13154,13155,13158],{"style":9217},[355,13156],{"className":13157,"style":1999},[1998],[355,13159,13161],{"className":13160},[2003,2004,2005,2006],[355,13162,13164,13167,13170],{"className":13163},[1951,2006],[355,13165,19],{"className":13166},[1951,1952,2006],[355,13168,9997],{"className":13169},[1951,1952,2006],[355,13171,2458],{"className":13172},[1951,1952,2006],[355,13174,2023],{"className":13175},[2022],[355,13177,13179],{"className":13178},[1986],[355,13180,13182],{"className":13181,"style":2030},[1990],[355,13183],{},[355,13185],{"className":13186,"style":2037},[2036],[355,13188,2042],{"className":13189},[2041],[355,13191],{"className":13192,"style":2037},[2036],[355,13194,13196,13200,13262,13265,13268,13271],{"className":13195},[1942],[355,13197],{"className":13198,"style":13199},[1946],"height:2.0074em;vertical-align:-0.686em;",[355,13201,13203,13206,13259],{"className":13202},[1951],[355,13204],{"className":13205},[2168,9270],[355,13207,13209],{"className":13208},[9274],[355,13210,13212,13251],{"className":13211},[1981,1982],[355,13213,13215,13248],{"className":13214},[1986],[355,13216,13218,13229,13237],{"className":13217,"style":9284},[1990],[355,13219,13220,13223],{"style":9287},[355,13221],{"className":13222,"style":9291},[1998],[355,13224,13226],{"className":13225},[1951],[355,13227,1962],{"className":13228},[1951,1952],[355,13230,13231,13234],{"style":9417},[355,13232],{"className":13233,"style":9291},[1998],[355,13235],{"className":13236,"style":9425},[9424],[355,13238,13239,13242],{"style":9428},[355,13240],{"className":13241,"style":9291},[1998],[355,13243,13245],{"className":13244},[1951],[355,13246,9179],{"className":13247},[1951],[355,13249,2023],{"className":13250},[2022],[355,13252,13254],{"className":13253},[1986],[355,13255,13257],{"className":13256,"style":9668},[1990],[355,13258],{},[355,13260],{"className":13261},[2417,9270],[355,13263],{"className":13264,"style":2064},[2036],[355,13266,2060],{"className":13267,"style":2059},[2056,2057,2058],[355,13269],{"className":13270,"style":2064},[2036],[355,13272,13274,13277,13326],{"className":13273},[10395],[355,13275,2169],{"className":13276,"style":10400},[2168,10399],[355,13278,13280,13283],{"className":13279},[1951],[355,13281,2117],{"className":13282,"style":2116},[1951,1952],[355,13284,13286],{"className":13285},[1977],[355,13287,13289,13318],{"className":13288},[1981,1982],[355,13290,13292,13315],{"className":13291},[1986],[355,13293,13295],{"className":13294,"style":2471},[1990],[355,13296,13297,13300],{"style":9217},[355,13298],{"className":13299,"style":1999},[1998],[355,13301,13303],{"className":13302},[2003,2004,2005,2006],[355,13304,13306,13309,13312],{"className":13305},[1951,2006],[355,13307,9230],{"className":13308},[1951,1952,2006],[355,13310,2068],{"className":13311},[1951,1952,2006],[355,13313,19],{"className":13314},[1951,1952,2006],[355,13316,2023],{"className":13317},[2022],[355,13319,13321],{"className":13320},[1986],[355,13322,13324],{"className":13323,"style":2030},[1990],[355,13325],{},[355,13327,2418],{"className":13328,"style":10400},[2417,10399],[19,13330,10714],{},[443,13332,13333,13352],{},[446,13334,13335,13351],{},[355,13336,13338],{"className":13337},[1933],[355,13339,13341],{"className":13340,"ariaHidden":1938},[1937],[355,13342,13344,13348],{"className":13343},[1942],[355,13345],{"className":13346,"style":13347},[1946],"height:0.4306em;",[355,13349,1962],{"className":13350},[1951,1952]," = Nombre de déploiements composants",[446,13353,13354,13415],{},[355,13355,13357],{"className":13356},[1933],[355,13358,13360],{"className":13359,"ariaHidden":1938},[1937],[355,13361,13363,13366],{"className":13362},[1942],[355,13364],{"className":13365,"style":9196},[1946],[355,13367,13369,13372],{"className":13368},[1951],[355,13370,2117],{"className":13371,"style":2116},[1951,1952],[355,13373,13375],{"className":13374},[1977],[355,13376,13378,13407],{"className":13377},[1981,1982],[355,13379,13381,13404],{"className":13380},[1986],[355,13382,13384],{"className":13383,"style":2471},[1990],[355,13385,13386,13389],{"style":9217},[355,13387],{"className":13388,"style":1999},[1998],[355,13390,13392],{"className":13391},[2003,2004,2005,2006],[355,13393,13395,13398,13401],{"className":13394},[1951,2006],[355,13396,9230],{"className":13397},[1951,1952,2006],[355,13399,2068],{"className":13400},[1951,1952,2006],[355,13402,19],{"className":13403},[1951,1952,2006],[355,13405,2023],{"className":13406},[2022],[355,13408,13410],{"className":13409},[1986],[355,13411,13413],{"className":13412,"style":2030},[1990],[355,13414],{}," = Fréquence de déploiement du composant",[19,13417,13418],{},[34,13419,11565],{},[355,13421,13423],{"className":13422},[1929],[355,13424,13426],{"className":13425},[1933],[355,13427,13429,13494],{"className":13428,"ariaHidden":1938},[1937],[355,13430,13432,13436,13485,13488,13491],{"className":13431},[1942],[355,13433],{"className":13434,"style":13435},[1946],"height:0.8889em;vertical-align:-0.1944em;",[355,13437,13439,13442],{"className":13438},[1951],[355,13440,2117],{"className":13441,"style":2116},[1951,1952],[355,13443,13445],{"className":13444},[1977],[355,13446,13448,13477],{"className":13447},[1981,1982],[355,13449,13451,13474],{"className":13450},[1986],[355,13452,13454],{"className":13453,"style":2101},[1990],[355,13455,13456,13459],{"style":9217},[355,13457],{"className":13458,"style":1999},[1998],[355,13460,13462],{"className":13461},[2003,2004,2005,2006],[355,13463,13465,13468,13471],{"className":13464},[1951,2006],[355,13466,2458],{"className":13467},[1951,1952,2006],[355,13469,1958],{"className":13470},[1951,1952,2006],[355,13472,1636],{"className":13473},[1951,1952,2006],[355,13475,2023],{"className":13476},[2022],[355,13478,13480],{"className":13479},[1986],[355,13481,13483],{"className":13482,"style":2250},[1990],[355,13484],{},[355,13486],{"className":13487,"style":2037},[2036],[355,13489,2042],{"className":13490},[2041],[355,13492],{"className":13493,"style":2037},[2036],[355,13495,13497,13500,13562,13565,13568,13571],{"className":13496},[1942],[355,13498],{"className":13499,"style":13199},[1946],[355,13501,13503,13506,13559],{"className":13502},[1951],[355,13504],{"className":13505},[2168,9270],[355,13507,13509],{"className":13508},[9274],[355,13510,13512,13551],{"className":13511},[1981,1982],[355,13513,13515,13548],{"className":13514},[1986],[355,13516,13518,13529,13537],{"className":13517,"style":9284},[1990],[355,13519,13520,13523],{"style":9287},[355,13521],{"className":13522,"style":9291},[1998],[355,13524,13526],{"className":13525},[1951],[355,13527,2068],{"className":13528},[1951,1952],[355,13530,13531,13534],{"style":9417},[355,13532],{"className":13533,"style":9291},[1998],[355,13535],{"className":13536,"style":9425},[9424],[355,13538,13539,13542],{"style":9428},[355,13540],{"className":13541,"style":9291},[1998],[355,13543,13545],{"className":13544},[1951],[355,13546,9179],{"className":13547},[1951],[355,13549,2023],{"className":13550},[2022],[355,13552,13554],{"className":13553},[1986],[355,13555,13557],{"className":13556,"style":9668},[1990],[355,13558],{},[355,13560],{"className":13561},[2417,9270],[355,13563],{"className":13564,"style":2064},[2036],[355,13566,2060],{"className":13567,"style":2059},[2056,2057,2058],[355,13569],{"className":13570,"style":2064},[2036],[355,13572,13574,13577,13626],{"className":13573},[10395],[355,13575,2169],{"className":13576,"style":10400},[2168,10399],[355,13578,13580,13583],{"className":13579},[1951],[355,13581,2117],{"className":13582,"style":2116},[1951,1952],[355,13584,13586],{"className":13585},[1977],[355,13587,13589,13618],{"className":13588},[1981,1982],[355,13590,13592,13615],{"className":13591},[1986],[355,13593,13595],{"className":13594,"style":2101},[1990],[355,13596,13597,13600],{"style":9217},[355,13598],{"className":13599,"style":1999},[1998],[355,13601,13603],{"className":13602},[2003,2004,2005,2006],[355,13604,13606,13609,13612],{"className":13605},[1951,2006],[355,13607,19],{"className":13608},[1951,1952,2006],[355,13610,9997],{"className":13611},[1951,1952,2006],[355,13613,2458],{"className":13614},[1951,1952,2006],[355,13616,2023],{"className":13617},[2022],[355,13619,13621],{"className":13620},[1986],[355,13622,13624],{"className":13623,"style":2030},[1990],[355,13625],{},[355,13627,2418],{"className":13628,"style":10400},[2417,10399],[19,13630,10714],{},[443,13632,13633,13651],{},[446,13634,13635,13650],{},[355,13636,13638],{"className":13637},[1933],[355,13639,13641],{"className":13640,"ariaHidden":1938},[1937],[355,13642,13644,13647],{"className":13643},[1942],[355,13645],{"className":13646,"style":13347},[1946],[355,13648,2068],{"className":13649},[1951,1952]," = Nombre de produits",[446,13652,13653,13714],{},[355,13654,13656],{"className":13655},[1933],[355,13657,13659],{"className":13658,"ariaHidden":1938},[1937],[355,13660,13662,13665],{"className":13661},[1942],[355,13663],{"className":13664,"style":9196},[1946],[355,13666,13668,13671],{"className":13667},[1951],[355,13669,2117],{"className":13670,"style":2116},[1951,1952],[355,13672,13674],{"className":13673},[1977],[355,13675,13677,13706],{"className":13676},[1981,1982],[355,13678,13680,13703],{"className":13679},[1986],[355,13681,13683],{"className":13682,"style":2101},[1990],[355,13684,13685,13688],{"style":9217},[355,13686],{"className":13687,"style":1999},[1998],[355,13689,13691],{"className":13690},[2003,2004,2005,2006],[355,13692,13694,13697,13700],{"className":13693},[1951,2006],[355,13695,19],{"className":13696},[1951,1952,2006],[355,13698,9997],{"className":13699},[1951,1952,2006],[355,13701,2458],{"className":13702},[1951,1952,2006],[355,13704,2023],{"className":13705},[2022],[355,13707,13709],{"className":13708},[1986],[355,13710,13712],{"className":13711,"style":2030},[1990],[355,13713],{}," = Fréquence de déploiement du produit",[19,13716,13717],{},[34,13718,12144],{},[355,13720,13722],{"className":13721},[1929],[355,13723,13725],{"className":13724},[1933],[355,13726,13728,13802],{"className":13727,"ariaHidden":1938},[1937],[355,13729,13731,13734,13793,13796,13799],{"className":13730},[1942],[355,13732],{"className":13733,"style":9196},[1946],[355,13735,13737,13740],{"className":13736},[1951],[355,13738,2117],{"className":13739,"style":2116},[1951,1952],[355,13741,13743],{"className":13742},[1977],[355,13744,13746,13785],{"className":13745},[1981,1982],[355,13747,13749,13782],{"className":13748},[1986],[355,13750,13752],{"className":13751,"style":2101},[1990],[355,13753,13754,13757],{"style":9217},[355,13755],{"className":13756,"style":1999},[1998],[355,13758,13760],{"className":13759},[2003,2004,2005,2006],[355,13761,13763,13766,13769,13772,13775,13779],{"className":13762},[1951,2006],[355,13764,2392],{"className":13765,"style":2179},[1951,1952,2006],[355,13767,91],{"className":13768},[1951,1952,2006],[355,13770,2078],{"className":13771},[1951,1952,2006],[355,13773,2117],{"className":13774,"style":2116},[1951,1952,2006],[355,13776,13778],{"className":13777,"style":2188},[1951,1952,2006],"or",[355,13780,2068],{"className":13781},[1951,1952,2006],[355,13783,2023],{"className":13784},[2022],[355,13786,13788],{"className":13787},[1986],[355,13789,13791],{"className":13790,"style":2030},[1990],[355,13792],{},[355,13794],{"className":13795,"style":2037},[2036],[355,13797,2042],{"className":13798},[2041],[355,13800],{"className":13801,"style":2037},[2036],[355,13803,13805,13808,13870,13873,13876,13879],{"className":13804},[1942],[355,13806],{"className":13807,"style":13199},[1946],[355,13809,13811,13814,13867],{"className":13810},[1951],[355,13812],{"className":13813},[2168,9270],[355,13815,13817],{"className":13816},[9274],[355,13818,13820,13859],{"className":13819},[1981,1982],[355,13821,13823,13856],{"className":13822},[1986],[355,13824,13826,13837,13845],{"className":13825,"style":9284},[1990],[355,13827,13828,13831],{"style":9287},[355,13829],{"className":13830,"style":9291},[1998],[355,13832,13834],{"className":13833},[1951],[355,13835,1958],{"className":13836},[1951,1952],[355,13838,13839,13842],{"style":9417},[355,13840],{"className":13841,"style":9291},[1998],[355,13843],{"className":13844,"style":9425},[9424],[355,13846,13847,13850],{"style":9428},[355,13848],{"className":13849,"style":9291},[1998],[355,13851,13853],{"className":13852},[1951],[355,13854,9179],{"className":13855},[1951],[355,13857,2023],{"className":13858},[2022],[355,13860,13862],{"className":13861},[1986],[355,13863,13865],{"className":13864,"style":9668},[1990],[355,13866],{},[355,13868],{"className":13869},[2417,9270],[355,13871],{"className":13872,"style":2064},[2036],[355,13874,2060],{"className":13875,"style":2059},[2056,2057,2058],[355,13877],{"className":13878,"style":2064},[2036],[355,13880,13882,13885,13934],{"className":13881},[10395],[355,13883,2169],{"className":13884,"style":10400},[2168,10399],[355,13886,13888,13891],{"className":13887},[1951],[355,13889,2117],{"className":13890,"style":2116},[1951,1952],[355,13892,13894],{"className":13893},[1977],[355,13895,13897,13926],{"className":13896},[1981,1982],[355,13898,13900,13923],{"className":13899},[1986],[355,13901,13903],{"className":13902,"style":2101},[1990],[355,13904,13905,13908],{"style":9217},[355,13906],{"className":13907,"style":1999},[1998],[355,13909,13911],{"className":13910},[2003,2004,2005,2006],[355,13912,13914,13917,13920],{"className":13913},[1951,2006],[355,13915,2458],{"className":13916},[1951,1952,2006],[355,13918,1958],{"className":13919},[1951,1952,2006],[355,13921,1636],{"className":13922},[1951,1952,2006],[355,13924,2023],{"className":13925},[2022],[355,13927,13929],{"className":13928},[1986],[355,13930,13932],{"className":13931,"style":2250},[1990],[355,13933],{},[355,13935,2418],{"className":13936,"style":10400},[2417,10399],[19,13938,10714],{},[443,13940,13941,13959],{},[446,13942,13943,13958],{},[355,13944,13946],{"className":13945},[1933],[355,13947,13949],{"className":13948,"ariaHidden":1938},[1937],[355,13950,13952,13955],{"className":13951},[1942],[355,13953],{"className":13954,"style":13347},[1946],[355,13956,1958],{"className":13957},[1951,1952]," = Nombre de domaines",[446,13960,13961,14022],{},[355,13962,13964],{"className":13963},[1933],[355,13965,13967],{"className":13966,"ariaHidden":1938},[1937],[355,13968,13970,13973],{"className":13969},[1942],[355,13971],{"className":13972,"style":13435},[1946],[355,13974,13976,13979],{"className":13975},[1951],[355,13977,2117],{"className":13978,"style":2116},[1951,1952],[355,13980,13982],{"className":13981},[1977],[355,13983,13985,14014],{"className":13984},[1981,1982],[355,13986,13988,14011],{"className":13987},[1986],[355,13989,13991],{"className":13990,"style":2101},[1990],[355,13992,13993,13996],{"style":9217},[355,13994],{"className":13995,"style":1999},[1998],[355,13997,13999],{"className":13998},[2003,2004,2005,2006],[355,14000,14002,14005,14008],{"className":14001},[1951,2006],[355,14003,2458],{"className":14004},[1951,1952,2006],[355,14006,1958],{"className":14007},[1951,1952,2006],[355,14009,1636],{"className":14010},[1951,1952,2006],[355,14012,2023],{"className":14013},[2022],[355,14015,14017],{"className":14016},[1986],[355,14018,14020],{"className":14019,"style":2250},[1990],[355,14021],{}," = Fréquence de déploiement du domaine",[84,14024,8228],{"id":14025},"change-failure-rate",[19,14027,14028],{},[34,14029,10263],{},[443,14031,14032],{},[446,14033,14034],{},"Non calculé à ce niveau en raison de la difficulté à associer précisément les incidents à des composants spécifiques",[19,14036,14037],{},[34,14038,10979],{},[355,14040,14042],{"className":14041},[1929],[355,14043,14045],{"className":14044},[1933],[355,14046,14048,14148],{"className":14047,"ariaHidden":1938},[1937],[355,14049,14051,14054,14057,14060,14063,14066,14069,14072,14075,14078,14081,14139,14142,14145],{"className":14050},[1942],[355,14052],{"className":14053,"style":9196},[1946],[355,14055,9938],{"className":14056,"style":9937},[1951,1952],[355,14058,9942],{"className":14059},[1951,1952],[355,14061,2494],{"className":14062,"style":2493},[1951,1952],[355,14064,2196],{"className":14065},[1951,1952],[355,14067,9953],{"className":14068,"style":9952},[1951,1952],[355,14070,2184],{"className":14071},[1951,1952],[355,14073,2180],{"className":14074,"style":2179},[1951,1952],[355,14076,1966],{"className":14077},[1951,1952],[355,14079,2189],{"className":14080,"style":2188},[1951,1952],[355,14082,14084,14087],{"className":14083},[1951],[355,14085,2196],{"className":14086},[1951,1952],[355,14088,14090],{"className":14089},[1977],[355,14091,14093,14131],{"className":14092},[1981,1982],[355,14094,14096,14128],{"className":14095},[1986],[355,14097,14099],{"className":14098,"style":2101},[1990],[355,14100,14101,14104],{"style":1994},[355,14102],{"className":14103,"style":1999},[1998],[355,14105,14107],{"className":14106},[2003,2004,2005,2006],[355,14108,14110,14113,14116,14119,14122,14125],{"className":14109},[1951,2006],[355,14111,19],{"className":14112},[1951,1952,2006],[355,14114,9997],{"className":14115},[1951,1952,2006],[355,14117,2458],{"className":14118},[1951,1952,2006],[355,14120,1966],{"className":14121},[1951,1952,2006],[355,14123,2124],{"className":14124},[1951,1952,2006],[355,14126,2078],{"className":14127},[1951,1952,2006],[355,14129,2023],{"className":14130},[2022],[355,14132,14134],{"className":14133},[1986],[355,14135,14137],{"className":14136,"style":2030},[1990],[355,14138],{},[355,14140],{"className":14141,"style":2037},[2036],[355,14143,2042],{"className":14144},[2041],[355,14146],{"className":14147,"style":2037},[2036],[355,14149,14151,14154],{"className":14150},[1942],[355,14152],{"className":14153,"style":10037},[1946],[355,14155,14157,14160,14323],{"className":14156},[1951],[355,14158],{"className":14159},[2168,9270],[355,14161,14163],{"className":14162},[9274],[355,14164,14166,14315],{"className":14165},[1981,1982],[355,14167,14169,14312],{"className":14168},[1986],[355,14170,14172,14241,14249],{"className":14171,"style":10056},[1990],[355,14173,14174,14177],{"style":9287},[355,14175],{"className":14176,"style":9291},[1998],[355,14178,14180,14183,14186],{"className":14179},[1951],[355,14181,2060],{"className":14182,"style":2059},[2056,2057,10068],[355,14184],{"className":14185,"style":2064},[2036],[355,14187,14189,14192],{"className":14188},[1951],[355,14190,2458],{"className":14191},[1951,1952],[355,14193,14195],{"className":14194},[1977],[355,14196,14198,14233],{"className":14197},[1981,1982],[355,14199,14201,14230],{"className":14200},[1986],[355,14202,14204],{"className":14203,"style":2101},[1990],[355,14205,14206,14209],{"style":1994},[355,14207],{"className":14208,"style":1999},[1998],[355,14210,14212],{"className":14211},[2003,2004,2005,2006],[355,14213,14215,14218,14221,14224,14227],{"className":14214},[1951,2006],[355,14216,2078],{"className":14217},[1951,1952,2006],[355,14219,1958],{"className":14220},[1951,1952,2006],[355,14222,2078],{"className":14223},[1951,1952,2006],[355,14225,91],{"className":14226},[1951,1952,2006],[355,14228,2180],{"className":14229,"style":2179},[1951,1952,2006],[355,14231,2023],{"className":14232},[2022],[355,14234,14236],{"className":14235},[1986],[355,14237,14239],{"className":14238,"style":2250},[1990],[355,14240],{},[355,14242,14243,14246],{"style":9417},[355,14244],{"className":14245,"style":9291},[1998],[355,14247],{"className":14248,"style":9425},[9424],[355,14250,14251,14254],{"style":9428},[355,14252],{"className":14253,"style":9291},[1998],[355,14255,14257,14260,14263],{"className":14256},[1951],[355,14258,2060],{"className":14259,"style":2059},[2056,2057,10068],[355,14261],{"className":14262,"style":2064},[2036],[355,14264,14266,14269],{"className":14265},[1951],[355,14267,2458],{"className":14268},[1951,1952],[355,14270,14272],{"className":14271},[1977],[355,14273,14275,14304],{"className":14274},[1981,1982],[355,14276,14278,14301],{"className":14277},[1986],[355,14279,14281],{"className":14280,"style":2101},[1990],[355,14282,14283,14286],{"style":1994},[355,14284],{"className":14285,"style":1999},[1998],[355,14287,14289],{"className":14288},[2003,2004,2005,2006],[355,14290,14292,14295,14298],{"className":14291},[1951,2006],[355,14293,2117],{"className":14294,"style":2116},[1951,1952,2006],[355,14296,2184],{"className":14297},[1951,1952,2006],[355,14299,2180],{"className":14300,"style":2179},[1951,1952,2006],[355,14302,2023],{"className":14303},[2022],[355,14305,14307],{"className":14306},[1986],[355,14308,14310],{"className":14309,"style":2030},[1990],[355,14311],{},[355,14313,2023],{"className":14314},[2022],[355,14316,14318],{"className":14317},[1986],[355,14319,14321],{"className":14320,"style":10213},[1990],[355,14322],{},[355,14324],{"className":14325},[2417,9270],[19,14327,10714],{},[443,14329,14330,14394],{},[446,14331,14332,14393],{},[355,14333,14335],{"className":14334},[1933],[355,14336,14338],{"className":14337,"ariaHidden":1938},[1937],[355,14339,14341,14344],{"className":14340},[1942],[355,14342],{"className":14343,"style":9196},[1946],[355,14345,14347,14350],{"className":14346},[1951],[355,14348,2458],{"className":14349},[1951,1952],[355,14351,14353],{"className":14352},[1977],[355,14354,14356,14385],{"className":14355},[1981,1982],[355,14357,14359,14382],{"className":14358},[1986],[355,14360,14362],{"className":14361,"style":2101},[1990],[355,14363,14364,14367],{"style":1994},[355,14365],{"className":14366,"style":1999},[1998],[355,14368,14370],{"className":14369},[2003,2004,2005,2006],[355,14371,14373,14376,14379],{"className":14372},[1951,2006],[355,14374,2117],{"className":14375,"style":2116},[1951,1952,2006],[355,14377,2184],{"className":14378},[1951,1952,2006],[355,14380,2180],{"className":14381,"style":2179},[1951,1952,2006],[355,14383,2023],{"className":14384},[2022],[355,14386,14388],{"className":14387},[1986],[355,14389,14391],{"className":14390,"style":2030},[1990],[355,14392],{}," = Nombre de déploiements précédant au moins un incident",[446,14395,14396,14463],{},[355,14397,14399],{"className":14398},[1933],[355,14400,14402],{"className":14401,"ariaHidden":1938},[1937],[355,14403,14405,14408],{"className":14404},[1942],[355,14406],{"className":14407,"style":2269},[1946],[355,14409,14411,14414],{"className":14410},[1951],[355,14412,2458],{"className":14413},[1951,1952],[355,14415,14417],{"className":14416},[1977],[355,14418,14420,14455],{"className":14419},[1981,1982],[355,14421,14423,14452],{"className":14422},[1986],[355,14424,14426],{"className":14425,"style":2101},[1990],[355,14427,14428,14431],{"style":1994},[355,14429],{"className":14430,"style":1999},[1998],[355,14432,14434],{"className":14433},[2003,2004,2005,2006],[355,14435,14437,14440,14443,14446,14449],{"className":14436},[1951,2006],[355,14438,2078],{"className":14439},[1951,1952,2006],[355,14441,1958],{"className":14442},[1951,1952,2006],[355,14444,2078],{"className":14445},[1951,1952,2006],[355,14447,91],{"className":14448},[1951,1952,2006],[355,14450,2180],{"className":14451,"style":2179},[1951,1952,2006],[355,14453,2023],{"className":14454},[2022],[355,14456,14458],{"className":14457},[1986],[355,14459,14461],{"className":14460,"style":2250},[1990],[355,14462],{}," = Nombre total de déploiements du produit",[19,14465,14466],{},[34,14467,11565],{},[355,14469,14471],{"className":14470},[1929],[355,14472,14474],{"className":14473},[1933],[355,14475,14477,14568],{"className":14476,"ariaHidden":1938},[1937],[355,14478,14480,14483,14486,14489,14492,14495,14498,14501,14504,14507,14510,14559,14562,14565],{"className":14479},[1942],[355,14481],{"className":14482,"style":13435},[1946],[355,14484,9938],{"className":14485,"style":9937},[1951,1952],[355,14487,9942],{"className":14488},[1951,1952],[355,14490,2494],{"className":14491,"style":2493},[1951,1952],[355,14493,2196],{"className":14494},[1951,1952],[355,14496,9953],{"className":14497,"style":9952},[1951,1952],[355,14499,2184],{"className":14500},[1951,1952],[355,14502,2180],{"className":14503,"style":2179},[1951,1952],[355,14505,1966],{"className":14506},[1951,1952],[355,14508,2189],{"className":14509,"style":2188},[1951,1952],[355,14511,14513,14516],{"className":14512},[1951],[355,14514,2196],{"className":14515},[1951,1952],[355,14517,14519],{"className":14518},[1977],[355,14520,14522,14551],{"className":14521},[1981,1982],[355,14523,14525,14548],{"className":14524},[1986],[355,14526,14528],{"className":14527,"style":2101},[1990],[355,14529,14530,14533],{"style":1994},[355,14531],{"className":14532,"style":1999},[1998],[355,14534,14536],{"className":14535},[2003,2004,2005,2006],[355,14537,14539,14542,14545],{"className":14538},[1951,2006],[355,14540,2458],{"className":14541},[1951,1952,2006],[355,14543,1958],{"className":14544},[1951,1952,2006],[355,14546,1636],{"className":14547},[1951,1952,2006],[355,14549,2023],{"className":14550},[2022],[355,14552,14554],{"className":14553},[1986],[355,14555,14557],{"className":14556,"style":2250},[1990],[355,14558],{},[355,14560],{"className":14561,"style":2037},[2036],[355,14563,2042],{"className":14564},[2041],[355,14566],{"className":14567,"style":2037},[2036],[355,14569,14571,14574,14673,14676,14679,14682],{"className":14570},[1942],[355,14572],{"className":14573,"style":9263},[1946],[355,14575,14577,14580,14670],{"className":14576},[1951],[355,14578],{"className":14579},[2168,9270],[355,14581,14583],{"className":14582},[9274],[355,14584,14586,14662],{"className":14585},[1981,1982],[355,14587,14589,14659],{"className":14588},[1986],[355,14590,14592,14640,14648],{"className":14591,"style":9284},[1990],[355,14593,14594,14597],{"style":9287},[355,14595],{"className":14596,"style":9291},[1998],[355,14598,14600],{"className":14599},[1951],[355,14601,14603,14606],{"className":14602},[1951],[355,14604,1962],{"className":14605},[1951,1952],[355,14607,14609],{"className":14608},[1977],[355,14610,14612,14632],{"className":14611},[1981,1982],[355,14613,14615,14629],{"className":14614},[1986],[355,14616,14618],{"className":14617,"style":2471},[1990],[355,14619,14620,14623],{"style":1994},[355,14621],{"className":14622,"style":1999},[1998],[355,14624,14626],{"className":14625},[2003,2004,2005,2006],[355,14627,19],{"className":14628},[1951,1952,2006],[355,14630,2023],{"className":14631},[2022],[355,14633,14635],{"className":14634},[1986],[355,14636,14638],{"className":14637,"style":2030},[1990],[355,14639],{},[355,14641,14642,14645],{"style":9417},[355,14643],{"className":14644,"style":9291},[1998],[355,14646],{"className":14647,"style":9425},[9424],[355,14649,14650,14653],{"style":9428},[355,14651],{"className":14652,"style":9291},[1998],[355,14654,14656],{"className":14655},[1951],[355,14657,9179],{"className":14658},[1951],[355,14660,2023],{"className":14661},[2022],[355,14663,14665],{"className":14664},[1986],[355,14666,14668],{"className":14667,"style":9447},[1990],[355,14669],{},[355,14671],{"className":14672},[2417,9270],[355,14674],{"className":14675,"style":2064},[2036],[355,14677,2060],{"className":14678,"style":2059},[2056,2057,2058],[355,14680],{"className":14681,"style":2064},[2036],[355,14683,14685,14688,14691,14694,14697,14700,14703,14706,14709,14712,14715,14773],{"className":14684},[10395],[355,14686,2169],{"className":14687,"style":10400},[2168,10399],[355,14689,9938],{"className":14690,"style":9937},[1951,1952],[355,14692,9942],{"className":14693},[1951,1952],[355,14695,2494],{"className":14696,"style":2493},[1951,1952],[355,14698,2196],{"className":14699},[1951,1952],[355,14701,9953],{"className":14702,"style":9952},[1951,1952],[355,14704,2184],{"className":14705},[1951,1952],[355,14707,2180],{"className":14708,"style":2179},[1951,1952],[355,14710,1966],{"className":14711},[1951,1952],[355,14713,2189],{"className":14714,"style":2188},[1951,1952],[355,14716,14718,14721],{"className":14717},[1951],[355,14719,2196],{"className":14720},[1951,1952],[355,14722,14724],{"className":14723},[1977],[355,14725,14727,14765],{"className":14726},[1981,1982],[355,14728,14730,14762],{"className":14729},[1986],[355,14731,14733],{"className":14732,"style":2101},[1990],[355,14734,14735,14738],{"style":1994},[355,14736],{"className":14737,"style":1999},[1998],[355,14739,14741],{"className":14740},[2003,2004,2005,2006],[355,14742,14744,14747,14750,14753,14756,14759],{"className":14743},[1951,2006],[355,14745,19],{"className":14746},[1951,1952,2006],[355,14748,9997],{"className":14749},[1951,1952,2006],[355,14751,2458],{"className":14752},[1951,1952,2006],[355,14754,1966],{"className":14755},[1951,1952,2006],[355,14757,2124],{"className":14758},[1951,1952,2006],[355,14760,2078],{"className":14761},[1951,1952,2006],[355,14763,2023],{"className":14764},[2022],[355,14766,14768],{"className":14767},[1986],[355,14769,14771],{"className":14770,"style":2030},[1990],[355,14772],{},[355,14774,2418],{"className":14775,"style":10400},[2417,10399],[19,14777,10714],{},[443,14779,14780],{},[446,14781,14782,12139],{},[355,14783,14785],{"className":14784},[1933],[355,14786,14788],{"className":14787,"ariaHidden":1938},[1937],[355,14789,14791,14794],{"className":14790},[1942],[355,14792],{"className":14793,"style":12095},[1946],[355,14795,14797,14800],{"className":14796},[1951],[355,14798,1962],{"className":14799},[1951,1952],[355,14801,14803],{"className":14802},[1977],[355,14804,14806,14826],{"className":14805},[1981,1982],[355,14807,14809,14823],{"className":14808},[1986],[355,14810,14812],{"className":14811,"style":2471},[1990],[355,14813,14814,14817],{"style":1994},[355,14815],{"className":14816,"style":1999},[1998],[355,14818,14820],{"className":14819},[2003,2004,2005,2006],[355,14821,19],{"className":14822},[1951,1952,2006],[355,14824,2023],{"className":14825},[2022],[355,14827,14829],{"className":14828},[1986],[355,14830,14832],{"className":14831,"style":2030},[1990],[355,14833],{},[19,14835,14836],{},[34,14837,12144],{},[355,14839,14841],{"className":14840},[1929],[355,14842,14844],{"className":14843},[1933],[355,14845,14847,14947],{"className":14846,"ariaHidden":1938},[1937],[355,14848,14850,14853,14856,14859,14862,14865,14868,14871,14874,14877,14880,14938,14941,14944],{"className":14849},[1942],[355,14851],{"className":14852,"style":9196},[1946],[355,14854,9938],{"className":14855,"style":9937},[1951,1952],[355,14857,9942],{"className":14858},[1951,1952],[355,14860,2494],{"className":14861,"style":2493},[1951,1952],[355,14863,2196],{"className":14864},[1951,1952],[355,14866,9953],{"className":14867,"style":9952},[1951,1952],[355,14869,2184],{"className":14870},[1951,1952],[355,14872,2180],{"className":14873,"style":2179},[1951,1952],[355,14875,1966],{"className":14876},[1951,1952],[355,14878,2189],{"className":14879,"style":2188},[1951,1952],[355,14881,14883,14886],{"className":14882},[1951],[355,14884,2196],{"className":14885},[1951,1952],[355,14887,14889],{"className":14888},[1977],[355,14890,14892,14930],{"className":14891},[1981,1982],[355,14893,14895,14927],{"className":14894},[1986],[355,14896,14898],{"className":14897,"style":2101},[1990],[355,14899,14900,14903],{"style":1994},[355,14901],{"className":14902,"style":1999},[1998],[355,14904,14906],{"className":14905},[2003,2004,2005,2006],[355,14907,14909,14912,14915,14918,14921,14924],{"className":14908},[1951,2006],[355,14910,2392],{"className":14911,"style":2179},[1951,1952,2006],[355,14913,91],{"className":14914},[1951,1952,2006],[355,14916,2078],{"className":14917},[1951,1952,2006],[355,14919,2117],{"className":14920,"style":2116},[1951,1952,2006],[355,14922,13778],{"className":14923,"style":2188},[1951,1952,2006],[355,14925,2068],{"className":14926},[1951,1952,2006],[355,14928,2023],{"className":14929},[2022],[355,14931,14933],{"className":14932},[1986],[355,14934,14936],{"className":14935,"style":2030},[1990],[355,14937],{},[355,14939],{"className":14940,"style":2037},[2036],[355,14942,2042],{"className":14943},[2041],[355,14945],{"className":14946,"style":2037},[2036],[355,14948,14950,14953,15052,15055,15058,15061],{"className":14949},[1942],[355,14951],{"className":14952,"style":11102},[1946],[355,14954,14956,14959,15049],{"className":14955},[1951],[355,14957],{"className":14958},[2168,9270],[355,14960,14962],{"className":14961},[9274],[355,14963,14965,15041],{"className":14964},[1981,1982],[355,14966,14968,15038],{"className":14967},[1986],[355,14969,14971,15019,15027],{"className":14970,"style":9284},[1990],[355,14972,14973,14976],{"style":9287},[355,14974],{"className":14975,"style":9291},[1998],[355,14977,14979],{"className":14978},[1951],[355,14980,14982,14985],{"className":14981},[1951],[355,14983,1962],{"className":14984},[1951,1952],[355,14986,14988],{"className":14987},[1977],[355,14989,14991,15011],{"className":14990},[1981,1982],[355,14992,14994,15008],{"className":14993},[1986],[355,14995,14997],{"className":14996,"style":2101},[1990],[355,14998,14999,15002],{"style":1994},[355,15000],{"className":15001,"style":1999},[1998],[355,15003,15005],{"className":15004},[2003,2004,2005,2006],[355,15006,2458],{"className":15007},[1951,1952,2006],[355,15009,2023],{"className":15010},[2022],[355,15012,15014],{"className":15013},[1986],[355,15015,15017],{"className":15016,"style":2250},[1990],[355,15018],{},[355,15020,15021,15024],{"style":9417},[355,15022],{"className":15023,"style":9291},[1998],[355,15025],{"className":15026,"style":9425},[9424],[355,15028,15029,15032],{"style":9428},[355,15030],{"className":15031,"style":9291},[1998],[355,15033,15035],{"className":15034},[1951],[355,15036,9179],{"className":15037},[1951],[355,15039,2023],{"className":15040},[2022],[355,15042,15044],{"className":15043},[1986],[355,15045,15047],{"className":15046,"style":11197},[1990],[355,15048],{},[355,15050],{"className":15051},[2417,9270],[355,15053],{"className":15054,"style":2064},[2036],[355,15056,2060],{"className":15057,"style":2059},[2056,2057,2058],[355,15059],{"className":15060,"style":2064},[2036],[355,15062,15064,15067,15070,15073,15076,15079,15082,15085,15088,15091,15094,15143],{"className":15063},[10395],[355,15065,2169],{"className":15066,"style":10400},[2168,10399],[355,15068,9938],{"className":15069,"style":9937},[1951,1952],[355,15071,9942],{"className":15072},[1951,1952],[355,15074,2494],{"className":15075,"style":2493},[1951,1952],[355,15077,2196],{"className":15078},[1951,1952],[355,15080,9953],{"className":15081,"style":9952},[1951,1952],[355,15083,2184],{"className":15084},[1951,1952],[355,15086,2180],{"className":15087,"style":2179},[1951,1952],[355,15089,1966],{"className":15090},[1951,1952],[355,15092,2189],{"className":15093,"style":2188},[1951,1952],[355,15095,15097,15100],{"className":15096},[1951],[355,15098,2196],{"className":15099},[1951,1952],[355,15101,15103],{"className":15102},[1977],[355,15104,15106,15135],{"className":15105},[1981,1982],[355,15107,15109,15132],{"className":15108},[1986],[355,15110,15112],{"className":15111,"style":2101},[1990],[355,15113,15114,15117],{"style":1994},[355,15115],{"className":15116,"style":1999},[1998],[355,15118,15120],{"className":15119},[2003,2004,2005,2006],[355,15121,15123,15126,15129],{"className":15122},[1951,2006],[355,15124,2458],{"className":15125},[1951,1952,2006],[355,15127,1958],{"className":15128},[1951,1952,2006],[355,15130,1636],{"className":15131},[1951,1952,2006],[355,15133,2023],{"className":15134},[2022],[355,15136,15138],{"className":15137},[1986],[355,15139,15141],{"className":15140,"style":2250},[1990],[355,15142],{},[355,15144,2418],{"className":15145,"style":10400},[2417,10399],[19,15147,10714],{},[443,15149,15150],{},[446,15151,15152,12718],{},[355,15153,15155],{"className":15154},[1933],[355,15156,15158],{"className":15157,"ariaHidden":1938},[1937],[355,15159,15161,15164],{"className":15160},[1942],[355,15162],{"className":15163,"style":11519},[1946],[355,15165,15167,15170],{"className":15166},[1951],[355,15168,1962],{"className":15169},[1951,1952],[355,15171,15173],{"className":15172},[1977],[355,15174,15176,15196],{"className":15175},[1981,1982],[355,15177,15179,15193],{"className":15178},[1986],[355,15180,15182],{"className":15181,"style":2101},[1990],[355,15183,15184,15187],{"style":1994},[355,15185],{"className":15186,"style":1999},[1998],[355,15188,15190],{"className":15189},[2003,2004,2005,2006],[355,15191,2458],{"className":15192},[1951,1952,2006],[355,15194,2023],{"className":15195},[2022],[355,15197,15199],{"className":15198},[1986],[355,15200,15202],{"className":15201,"style":2250},[1990],[355,15203],{},[84,15205,15207],{"id":15206},"mean-time-to-recover","Mean Time To Recover",[19,15209,15210],{},[34,15211,10263],{},[443,15213,15214],{},[446,15215,15216],{},"Non calculé à ce niveau car les incidents sont tracés au niveau produit",[19,15218,15219],{},[34,15220,10979],{},[355,15222,15224],{"className":15223},[1929],[355,15225,15227],{"className":15226},[1933],[355,15228,15230,15309],{"className":15229,"ariaHidden":1938},[1937],[355,15231,15233,15236,15240,15300,15303,15306],{"className":15232},[1942],[355,15234],{"className":15235,"style":1947},[1946],[355,15237,15239],{"className":15238,"style":9952},[1951,1952],"MTT",[355,15241,15243,15247],{"className":15242},[1951],[355,15244,15246],{"className":15245,"style":2017},[1951,1952],"R",[355,15248,15250],{"className":15249},[1977],[355,15251,15253,15292],{"className":15252},[1981,1982],[355,15254,15256,15289],{"className":15255},[1986],[355,15257,15259],{"className":15258,"style":2101},[1990],[355,15260,15262,15265],{"style":15261},"top:-2.55em;margin-left:-0.0077em;margin-right:0.05em;",[355,15263],{"className":15264,"style":1999},[1998],[355,15266,15268],{"className":15267},[2003,2004,2005,2006],[355,15269,15271,15274,15277,15280,15283,15286],{"className":15270},[1951,2006],[355,15272,19],{"className":15273},[1951,1952,2006],[355,15275,9997],{"className":15276},[1951,1952,2006],[355,15278,2458],{"className":15279},[1951,1952,2006],[355,15281,1966],{"className":15282},[1951,1952,2006],[355,15284,2124],{"className":15285},[1951,1952,2006],[355,15287,2078],{"className":15288},[1951,1952,2006],[355,15290,2023],{"className":15291},[2022],[355,15293,15295],{"className":15294},[1986],[355,15296,15298],{"className":15297,"style":2030},[1990],[355,15299],{},[355,15301],{"className":15302,"style":2037},[2036],[355,15304,2042],{"className":15305},[2041],[355,15307],{"className":15308,"style":2037},[2036],[355,15310,15312,15315,15377,15380,15383,15386],{"className":15311},[1942],[355,15313],{"className":15314,"style":13199},[1946],[355,15316,15318,15321,15374],{"className":15317},[1951],[355,15319],{"className":15320},[2168,9270],[355,15322,15324],{"className":15323},[9274],[355,15325,15327,15366],{"className":15326},[1981,1982],[355,15328,15330,15363],{"className":15329},[1986],[355,15331,15333,15344,15352],{"className":15332,"style":9284},[1990],[355,15334,15335,15338],{"style":9287},[355,15336],{"className":15337,"style":9291},[1998],[355,15339,15341],{"className":15340},[1951],[355,15342,1962],{"className":15343},[1951,1952],[355,15345,15346,15349],{"style":9417},[355,15347],{"className":15348,"style":9291},[1998],[355,15350],{"className":15351,"style":9425},[9424],[355,15353,15354,15357],{"style":9428},[355,15355],{"className":15356,"style":9291},[1998],[355,15358,15360],{"className":15359},[1951],[355,15361,9179],{"className":15362},[1951],[355,15364,2023],{"className":15365},[2022],[355,15367,15369],{"className":15368},[1986],[355,15370,15372],{"className":15371,"style":9668},[1990],[355,15373],{},[355,15375],{"className":15376},[2417,9270],[355,15378],{"className":15379,"style":2064},[2036],[355,15381,2060],{"className":15382,"style":2059},[2056,2057,2058],[355,15384],{"className":15385,"style":2064},[2036],[355,15387,15389,15392,15441,15444,15447,15450,15505],{"className":15388},[10395],[355,15390,2169],{"className":15391,"style":10400},[2168,10399],[355,15393,15395,15398],{"className":15394},[1951],[355,15396,2078],{"className":15397},[1951,1952],[355,15399,15401],{"className":15400},[1977],[355,15402,15404,15433],{"className":15403},[1981,1982],[355,15405,15407,15430],{"className":15406},[1986],[355,15408,15410],{"className":15409,"style":2101},[1990],[355,15411,15412,15415],{"style":1994},[355,15413],{"className":15414,"style":1999},[1998],[355,15416,15418],{"className":15417},[2003,2004,2005,2006],[355,15419,15421,15424,15427],{"className":15420},[1951,2006],[355,15422,2196],{"className":15423},[1951,1952,2006],[355,15425,1962],{"className":15426},[1951,1952,2006],[355,15428,2458],{"className":15429},[1951,1952,2006],[355,15431,2023],{"className":15432},[2022],[355,15434,15436],{"className":15435},[1986],[355,15437,15439],{"className":15438,"style":2250},[1990],[355,15440],{},[355,15442],{"className":15443,"style":2149},[2036],[355,15445,2154],{"className":15446},[2153],[355,15448],{"className":15449,"style":2149},[2036],[355,15451,15453,15456],{"className":15452},[1951],[355,15454,2078],{"className":15455},[1951,1952],[355,15457,15459],{"className":15458},[1977],[355,15460,15462,15497],{"className":15461},[1981,1982],[355,15463,15465,15494],{"className":15464},[1986],[355,15466,15468],{"className":15467,"style":9838},[1990],[355,15469,15470,15473],{"style":1994},[355,15471],{"className":15472,"style":1999},[1998],[355,15474,15476],{"className":15475},[2003,2004,2005,2006],[355,15477,15479,15482,15485,15488,15491],{"className":15478},[1951,2006],[355,15480,1973],{"className":15481},[1951,1952,2006],[355,15483,2078],{"className":15484},[1951,1952,2006],[355,15486,91],{"className":15487},[1951,1952,2006],[355,15489,2189],{"className":15490,"style":2188},[1951,1952,2006],[355,15492,2078],{"className":15493},[1951,1952,2006],[355,15495,2023],{"className":15496},[2022],[355,15498,15500],{"className":15499},[1986],[355,15501,15503],{"className":15502,"style":2250},[1990],[355,15504],{},[355,15506,2418],{"className":15507,"style":10400},[2417,10399],[19,15509,10714],{},[443,15511,15512,15530,15595],{},[446,15513,15514,15529],{},[355,15515,15517],{"className":15516},[1933],[355,15518,15520],{"className":15519,"ariaHidden":1938},[1937],[355,15521,15523,15526],{"className":15522},[1942],[355,15524],{"className":15525,"style":13347},[1946],[355,15527,1962],{"className":15528},[1951,1952]," = Nombre d'incidents",[446,15531,15532,15594],{},[355,15533,15535],{"className":15534},[1933],[355,15536,15538],{"className":15537,"ariaHidden":1938},[1937],[355,15539,15541,15545],{"className":15540},[1942],[355,15542],{"className":15543,"style":15544},[1946],"height:0.7651em;vertical-align:-0.15em;",[355,15546,15548,15551],{"className":15547},[1951],[355,15549,2078],{"className":15550},[1951,1952],[355,15552,15554],{"className":15553},[1977],[355,15555,15557,15586],{"className":15556},[1981,1982],[355,15558,15560,15583],{"className":15559},[1986],[355,15561,15563],{"className":15562,"style":2101},[1990],[355,15564,15565,15568],{"style":1994},[355,15566],{"className":15567,"style":1999},[1998],[355,15569,15571],{"className":15570},[2003,2004,2005,2006],[355,15572,15574,15577,15580],{"className":15573},[1951,2006],[355,15575,2196],{"className":15576},[1951,1952,2006],[355,15578,1962],{"className":15579},[1951,1952,2006],[355,15581,2458],{"className":15582},[1951,1952,2006],[355,15584,2023],{"className":15585},[2022],[355,15587,15589],{"className":15588},[1986],[355,15590,15592],{"className":15591,"style":2250},[1990],[355,15593],{}," = Date de résolution de l'incident",[446,15596,15597,15664],{},[355,15598,15600],{"className":15599},[1933],[355,15601,15603],{"className":15602,"ariaHidden":1938},[1937],[355,15604,15606,15609],{"className":15605},[1942],[355,15607],{"className":15608,"style":15544},[1946],[355,15610,15612,15615],{"className":15611},[1951],[355,15613,2078],{"className":15614},[1951,1952],[355,15616,15618],{"className":15617},[1977],[355,15619,15621,15656],{"className":15620},[1981,1982],[355,15622,15624,15653],{"className":15623},[1986],[355,15625,15627],{"className":15626,"style":9838},[1990],[355,15628,15629,15632],{"style":1994},[355,15630],{"className":15631,"style":1999},[1998],[355,15633,15635],{"className":15634},[2003,2004,2005,2006],[355,15636,15638,15641,15644,15647,15650],{"className":15637},[1951,2006],[355,15639,1973],{"className":15640},[1951,1952,2006],[355,15642,2078],{"className":15643},[1951,1952,2006],[355,15645,91],{"className":15646},[1951,1952,2006],[355,15648,2189],{"className":15649,"style":2188},[1951,1952,2006],[355,15651,2078],{"className":15652},[1951,1952,2006],[355,15654,2023],{"className":15655},[2022],[355,15657,15659],{"className":15658},[1986],[355,15660,15662],{"className":15661,"style":2250},[1990],[355,15663],{}," = Date de début de l'incident",[19,15666,15667],{},[34,15668,11565],{},[355,15670,15672],{"className":15671},[1929],[355,15673,15675],{"className":15674},[1933],[355,15676,15678,15746],{"className":15677,"ariaHidden":1938},[1937],[355,15679,15681,15685,15688,15737,15740,15743],{"className":15680},[1942],[355,15682],{"className":15683,"style":15684},[1946],"height:0.8333em;vertical-align:-0.15em;",[355,15686,15239],{"className":15687,"style":9952},[1951,1952],[355,15689,15691,15694],{"className":15690},[1951],[355,15692,15246],{"className":15693,"style":2017},[1951,1952],[355,15695,15697],{"className":15696},[1977],[355,15698,15700,15729],{"className":15699},[1981,1982],[355,15701,15703,15726],{"className":15702},[1986],[355,15704,15706],{"className":15705,"style":2101},[1990],[355,15707,15708,15711],{"style":15261},[355,15709],{"className":15710,"style":1999},[1998],[355,15712,15714],{"className":15713},[2003,2004,2005,2006],[355,15715,15717,15720,15723],{"className":15716},[1951,2006],[355,15718,2458],{"className":15719},[1951,1952,2006],[355,15721,1958],{"className":15722},[1951,1952,2006],[355,15724,1636],{"className":15725},[1951,1952,2006],[355,15727,2023],{"className":15728},[2022],[355,15730,15732],{"className":15731},[1986],[355,15733,15735],{"className":15734,"style":2250},[1990],[355,15736],{},[355,15738],{"className":15739,"style":2037},[2036],[355,15741,2042],{"className":15742},[2041],[355,15744],{"className":15745,"style":2037},[2036],[355,15747,15749,15752,15814,15817,15820,15823],{"className":15748},[1942],[355,15750],{"className":15751,"style":13199},[1946],[355,15753,15755,15758,15811],{"className":15754},[1951],[355,15756],{"className":15757},[2168,9270],[355,15759,15761],{"className":15760},[9274],[355,15762,15764,15803],{"className":15763},[1981,1982],[355,15765,15767,15800],{"className":15766},[1986],[355,15768,15770,15781,15789],{"className":15769,"style":9284},[1990],[355,15771,15772,15775],{"style":9287},[355,15773],{"className":15774,"style":9291},[1998],[355,15776,15778],{"className":15777},[1951],[355,15779,2068],{"className":15780},[1951,1952],[355,15782,15783,15786],{"style":9417},[355,15784],{"className":15785,"style":9291},[1998],[355,15787],{"className":15788,"style":9425},[9424],[355,15790,15791,15794],{"style":9428},[355,15792],{"className":15793,"style":9291},[1998],[355,15795,15797],{"className":15796},[1951],[355,15798,9179],{"className":15799},[1951],[355,15801,2023],{"className":15802},[2022],[355,15804,15806],{"className":15805},[1986],[355,15807,15809],{"className":15808,"style":9668},[1990],[355,15810],{},[355,15812],{"className":15813},[2417,9270],[355,15815],{"className":15816,"style":2064},[2036],[355,15818,2060],{"className":15819,"style":2059},[2056,2057,2058],[355,15821],{"className":15822,"style":2064},[2036],[355,15824,15826,15829,15832,15890],{"className":15825},[10395],[355,15827,2169],{"className":15828,"style":10400},[2168,10399],[355,15830,15239],{"className":15831,"style":9952},[1951,1952],[355,15833,15835,15838],{"className":15834},[1951],[355,15836,15246],{"className":15837,"style":2017},[1951,1952],[355,15839,15841],{"className":15840},[1977],[355,15842,15844,15882],{"className":15843},[1981,1982],[355,15845,15847,15879],{"className":15846},[1986],[355,15848,15850],{"className":15849,"style":2101},[1990],[355,15851,15852,15855],{"style":15261},[355,15853],{"className":15854,"style":1999},[1998],[355,15856,15858],{"className":15857},[2003,2004,2005,2006],[355,15859,15861,15864,15867,15870,15873,15876],{"className":15860},[1951,2006],[355,15862,19],{"className":15863},[1951,1952,2006],[355,15865,9997],{"className":15866},[1951,1952,2006],[355,15868,2458],{"className":15869},[1951,1952,2006],[355,15871,1966],{"className":15872},[1951,1952,2006],[355,15874,2124],{"className":15875},[1951,1952,2006],[355,15877,2078],{"className":15878},[1951,1952,2006],[355,15880,2023],{"className":15881},[2022],[355,15883,15885],{"className":15884},[1986],[355,15886,15888],{"className":15887,"style":2030},[1990],[355,15889],{},[355,15891,2418],{"className":15892,"style":10400},[2417,10399],[19,15894,10714],{},[443,15896,15897],{},[446,15898,15899,12139],{},[355,15900,15902],{"className":15901},[1933],[355,15903,15905],{"className":15904,"ariaHidden":1938},[1937],[355,15906,15908,15911],{"className":15907},[1942],[355,15909],{"className":15910,"style":13347},[1946],[355,15912,2068],{"className":15913},[1951,1952],[19,15915,15916],{},[34,15917,12144],{},[355,15919,15921],{"className":15920},[1929],[355,15922,15924],{"className":15923},[1933],[355,15925,15927,16003],{"className":15926,"ariaHidden":1938},[1937],[355,15928,15930,15933,15936,15994,15997,16000],{"className":15929},[1942],[355,15931],{"className":15932,"style":1947},[1946],[355,15934,15239],{"className":15935,"style":9952},[1951,1952],[355,15937,15939,15942],{"className":15938},[1951],[355,15940,15246],{"className":15941,"style":2017},[1951,1952],[355,15943,15945],{"className":15944},[1977],[355,15946,15948,15986],{"className":15947},[1981,1982],[355,15949,15951,15983],{"className":15950},[1986],[355,15952,15954],{"className":15953,"style":2101},[1990],[355,15955,15956,15959],{"style":15261},[355,15957],{"className":15958,"style":1999},[1998],[355,15960,15962],{"className":15961},[2003,2004,2005,2006],[355,15963,15965,15968,15971,15974,15977,15980],{"className":15964},[1951,2006],[355,15966,2392],{"className":15967,"style":2179},[1951,1952,2006],[355,15969,91],{"className":15970},[1951,1952,2006],[355,15972,2078],{"className":15973},[1951,1952,2006],[355,15975,2117],{"className":15976,"style":2116},[1951,1952,2006],[355,15978,13778],{"className":15979,"style":2188},[1951,1952,2006],[355,15981,2068],{"className":15982},[1951,1952,2006],[355,15984,2023],{"className":15985},[2022],[355,15987,15989],{"className":15988},[1986],[355,15990,15992],{"className":15991,"style":2030},[1990],[355,15993],{},[355,15995],{"className":15996,"style":2037},[2036],[355,15998,2042],{"className":15999},[2041],[355,16001],{"className":16002,"style":2037},[2036],[355,16004,16006,16009,16071,16074,16077,16080],{"className":16005},[1942],[355,16007],{"className":16008,"style":13199},[1946],[355,16010,16012,16015,16068],{"className":16011},[1951],[355,16013],{"className":16014},[2168,9270],[355,16016,16018],{"className":16017},[9274],[355,16019,16021,16060],{"className":16020},[1981,1982],[355,16022,16024,16057],{"className":16023},[1986],[355,16025,16027,16038,16046],{"className":16026,"style":9284},[1990],[355,16028,16029,16032],{"style":9287},[355,16030],{"className":16031,"style":9291},[1998],[355,16033,16035],{"className":16034},[1951],[355,16036,1958],{"className":16037},[1951,1952],[355,16039,16040,16043],{"style":9417},[355,16041],{"className":16042,"style":9291},[1998],[355,16044],{"className":16045,"style":9425},[9424],[355,16047,16048,16051],{"style":9428},[355,16049],{"className":16050,"style":9291},[1998],[355,16052,16054],{"className":16053},[1951],[355,16055,9179],{"className":16056},[1951],[355,16058,2023],{"className":16059},[2022],[355,16061,16063],{"className":16062},[1986],[355,16064,16066],{"className":16065,"style":9668},[1990],[355,16067],{},[355,16069],{"className":16070},[2417,9270],[355,16072],{"className":16073,"style":2064},[2036],[355,16075,2060],{"className":16076,"style":2059},[2056,2057,2058],[355,16078],{"className":16079,"style":2064},[2036],[355,16081,16083,16086,16089,16138],{"className":16082},[10395],[355,16084,2169],{"className":16085,"style":10400},[2168,10399],[355,16087,15239],{"className":16088,"style":9952},[1951,1952],[355,16090,16092,16095],{"className":16091},[1951],[355,16093,15246],{"className":16094,"style":2017},[1951,1952],[355,16096,16098],{"className":16097},[1977],[355,16099,16101,16130],{"className":16100},[1981,1982],[355,16102,16104,16127],{"className":16103},[1986],[355,16105,16107],{"className":16106,"style":2101},[1990],[355,16108,16109,16112],{"style":15261},[355,16110],{"className":16111,"style":1999},[1998],[355,16113,16115],{"className":16114},[2003,2004,2005,2006],[355,16116,16118,16121,16124],{"className":16117},[1951,2006],[355,16119,2458],{"className":16120},[1951,1952,2006],[355,16122,1958],{"className":16123},[1951,1952,2006],[355,16125,1636],{"className":16126},[1951,1952,2006],[355,16128,2023],{"className":16129},[2022],[355,16131,16133],{"className":16132},[1986],[355,16134,16136],{"className":16135,"style":2250},[1990],[355,16137],{},[355,16139,2418],{"className":16140,"style":10400},[2417,10399],[19,16142,10714],{},[443,16144,16145],{},[446,16146,16147,12718],{},[355,16148,16150],{"className":16149},[1933],[355,16151,16153],{"className":16152,"ariaHidden":1938},[1937],[355,16154,16156,16159],{"className":16155},[1942],[355,16157],{"className":16158,"style":13347},[1946],[355,16160,1958],{"className":16161},[1951,1952],[84,16163,16165],{"id":16164},"calcul-des-métriques-avec-bigquery","Calcul des métriques avec BigQuery",[19,16167,16168],{},[176,16169],{"alt":16170,"src":16171},"Image de datacenter","\u002Fcontent-assets\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Fassets\u002Fimg4.webp",[19,16173,16174,6547,16177,6547,16184,6547,16187],{},[1620,16175,16176],{},"Photo by",[91,16178,16181],{"href":16179,"rel":16180},"https:\u002F\u002Funsplash.com\u002F@tvick?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash",[95],[1620,16182,16183],{},"Taylor Vick",[1620,16185,16186],{},"on",[91,16188,16191],{"href":16189,"rel":16190},"https:\u002F\u002Funsplash.com\u002Fphotos\u002Fcable-network-M5tzZtFCOfs?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash",[95],[1620,16192,16193],{},"Unsplash",[19,16195,16196],{},"Toutes nos métriques sont calculées via des requêtes SQL exécutées sur BigQuery. Voici comment nous procédons pour chaque métrique :",[19,16198,16199],{},[34,16200,10258],{},[443,16202,16203,16206],{},[446,16204,16205],{},"Mesure le temps entre une modification de code et son déploiement en production",[446,16207,16208,16209],{},"Formule : ",[355,16210,16212],{"className":16211},[1933],[355,16213,16215,16282,16389],{"className":16214,"ariaHidden":1938},[1937],[355,16216,16218,16221,16224,16273,16276,16279],{"className":16217},[1942],[355,16219],{"className":16220,"style":1947},[1946],[355,16222,10282],{"className":16223},[1951],[355,16225,16227,16230],{"className":16226},[1951],[355,16228,2078],{"className":16229},[1951,1952],[355,16231,16233],{"className":16232},[1977],[355,16234,16236,16265],{"className":16235},[1981,1982],[355,16237,16239,16262],{"className":16238},[1986],[355,16240,16242],{"className":16241,"style":2101},[1990],[355,16243,16244,16247],{"style":1994},[355,16245],{"className":16246,"style":1999},[1998],[355,16248,16250],{"className":16249},[2003,2004,2005,2006],[355,16251,16253,16256,16259],{"className":16252},[1951,2006],[355,16254,10315],{"className":16255},[1951,1952,2006],[355,16257,2117],{"className":16258,"style":2116},[1951,1952,2006],[355,16260,2124],{"className":16261},[1951,1952,2006],[355,16263,2023],{"className":16264},[2022],[355,16266,16268],{"className":16267},[1986],[355,16269,16271],{"className":16270,"style":2030},[1990],[355,16272],{},[355,16274],{"className":16275,"style":2037},[2036],[355,16277,2042],{"className":16278},[2041],[355,16280],{"className":16281,"style":2037},[2036],[355,16283,16285,16289,16380,16383,16386],{"className":16284},[1942],[355,16286],{"className":16287,"style":16288},[1946],"height:0.9682em;vertical-align:-0.3531em;",[355,16290,16292,16295],{"className":16291},[1951],[355,16293,2078],{"className":16294},[1951,1952],[355,16296,16298],{"className":16297},[1977],[355,16299,16301,16371],{"className":16300},[1981,1982],[355,16302,16304,16368],{"className":16303},[1986],[355,16305,16307],{"className":16306,"style":2101},[1990],[355,16308,16309,16312],{"style":1994},[355,16310],{"className":16311,"style":1999},[1998],[355,16313,16315],{"className":16314},[2003,2004,2005,2006],[355,16316,16318],{"className":16317},[1951,2006],[355,16319,16321,16324],{"className":16320},[1951,2006],[355,16322,2458],{"className":16323},[1951,1952,2006],[355,16325,16327],{"className":16326},[1977],[355,16328,16330,16359],{"className":16329},[1981,1982],[355,16331,16333,16356],{"className":16332},[1986],[355,16334,16336],{"className":16335,"style":11306},[1990],[355,16337,16338,16341],{"style":11639},[355,16339],{"className":16340,"style":10344},[1998],[355,16342,16344],{"className":16343},[2003,10348,10349,2006],[355,16345,16347,16350,16353],{"className":16346},[1951,2006],[355,16348,19],{"className":16349},[1951,1952,2006],[355,16351,9997],{"className":16352},[1951,1952,2006],[355,16354,2458],{"className":16355},[1951,1952,2006],[355,16357,2023],{"className":16358},[2022],[355,16360,16362],{"className":16361},[1986],[355,16363,16366],{"className":16364,"style":16365},[1990],"height:0.2901em;",[355,16367],{},[355,16369,2023],{"className":16370},[2022],[355,16372,16374],{"className":16373},[1986],[355,16375,16378],{"className":16376,"style":16377},[1990],"height:0.3531em;",[355,16379],{},[355,16381],{"className":16382,"style":2149},[2036],[355,16384,2154],{"className":16385},[2153],[355,16387],{"className":16388,"style":2149},[2036],[355,16390,16392,16395],{"className":16391},[1942],[355,16393],{"className":16394,"style":15544},[1946],[355,16396,16398,16401],{"className":16397},[1951],[355,16399,2078],{"className":16400},[1951,1952],[355,16402,16404],{"className":16403},[1977],[355,16405,16407,16430],{"className":16406},[1981,1982],[355,16408,16410,16427],{"className":16409},[1986],[355,16411,16413],{"className":16412,"style":2471},[1990],[355,16414,16415,16418],{"style":1994},[355,16416],{"className":16417,"style":1999},[1998],[355,16419,16421],{"className":16420},[2003,2004,2005,2006],[355,16422,16424],{"className":16423},[1951,2006],[355,16425,9230],{"className":16426},[1951,1952,2006],[355,16428,2023],{"className":16429},[2022],[355,16431,16433],{"className":16432},[1986],[355,16434,16436],{"className":16435,"style":2250},[1990],[355,16437],{},[344,16439,16443],{"className":16440,"code":16441,"language":16442,"meta":350,"style":350},"language-sql shiki shiki-themes github-dark-default","-- Calcul du Lead Time For Changes par composant\nSELECT d.component_name,\n       d.product_id,\n       AVG(TIMESTAMP_DIFF(d.deployment_timestamp, c.commit_timestamp, HOUR)) as lead_time_hours\nFROM `dora_metrics.deployments` d\n         JOIN\n     `dora_metrics.git_commits` c\n     ON\n         d.git_tag = c.tag\nWHERE d.environment = 'prod'\n  AND d.deployment_timestamp BETWEEN '2024-01-01' AND '2024-12-31'\nGROUP BY d.component_name, d.product_id\n","sql",[352,16444,16445,16450,16465,16477,16515,16526,16531,16539,16544,16564,16581,16604],{"__ignoreMap":350},[355,16446,16447],{"class":357,"line":358},[355,16448,16449],{"class":3858},"-- Calcul du Lead Time For Changes par composant\n",[355,16451,16452,16455,16458,16460,16463],{"class":357,"line":364},[355,16453,16454],{"class":2801},"SELECT",[355,16456,16457],{"class":1264}," d",[355,16459,44],{"class":1119},[355,16461,16462],{"class":1264},"component_name",[355,16464,3144],{"class":1119},[355,16466,16467,16470,16472,16475],{"class":357,"line":370},[355,16468,16469],{"class":1264},"       d",[355,16471,44],{"class":1119},[355,16473,16474],{"class":1264},"product_id",[355,16476,3144],{"class":1119},[355,16478,16479,16482,16485,16487,16489,16492,16494,16496,16498,16501,16503,16506,16509,16512],{"class":357,"line":376},[355,16480,16481],{"class":1264},"       AVG",[355,16483,16484],{"class":1119},"(TIMESTAMP_DIFF(",[355,16486,2458],{"class":1264},[355,16488,44],{"class":1119},[355,16490,16491],{"class":1264},"deployment_timestamp",[355,16493,504],{"class":1119},[355,16495,2124],{"class":1264},[355,16497,44],{"class":1119},[355,16499,16500],{"class":1264},"commit_timestamp",[355,16502,504],{"class":1119},[355,16504,16505],{"class":2801},"HOUR",[355,16507,16508],{"class":1119},")) ",[355,16510,16511],{"class":2801},"as",[355,16513,16514],{"class":1119}," lead_time_hours\n",[355,16516,16517,16520,16523],{"class":357,"line":382},[355,16518,16519],{"class":2801},"FROM",[355,16521,16522],{"class":1138}," `dora_metrics.deployments`",[355,16524,16525],{"class":1119}," d\n",[355,16527,16528],{"class":357,"line":1157},[355,16529,16530],{"class":2801},"         JOIN\n",[355,16532,16533,16536],{"class":357,"line":1165},[355,16534,16535],{"class":1138},"     `dora_metrics.git_commits`",[355,16537,16538],{"class":1119}," c\n",[355,16540,16541],{"class":357,"line":1173},[355,16542,16543],{"class":2801},"     ON\n",[355,16545,16546,16549,16551,16554,16556,16559,16561],{"class":357,"line":1181},[355,16547,16548],{"class":1264},"         d",[355,16550,44],{"class":1119},[355,16552,16553],{"class":1264},"git_tag",[355,16555,3213],{"class":2801},[355,16557,16558],{"class":1264}," c",[355,16560,44],{"class":1119},[355,16562,16563],{"class":1264},"tag\n",[355,16565,16566,16569,16571,16573,16576,16578],{"class":357,"line":1189},[355,16567,16568],{"class":2801},"WHERE",[355,16570,16457],{"class":1264},[355,16572,44],{"class":1119},[355,16574,16575],{"class":1264},"environment",[355,16577,3213],{"class":2801},[355,16579,16580],{"class":1138}," 'prod'\n",[355,16582,16583,16586,16588,16590,16592,16595,16598,16601],{"class":357,"line":1197},[355,16584,16585],{"class":2801},"  AND",[355,16587,16457],{"class":1264},[355,16589,44],{"class":1119},[355,16591,16491],{"class":1264},[355,16593,16594],{"class":2801}," BETWEEN",[355,16596,16597],{"class":1138}," '2024-01-01'",[355,16599,16600],{"class":2801}," AND",[355,16602,16603],{"class":1138}," '2024-12-31'\n",[355,16605,16606,16609,16611,16613,16615,16617,16619,16621],{"class":357,"line":1205},[355,16607,16608],{"class":2801},"GROUP BY",[355,16610,16457],{"class":1264},[355,16612,44],{"class":1119},[355,16614,16462],{"class":1264},[355,16616,504],{"class":1119},[355,16618,2458],{"class":1264},[355,16620,44],{"class":1119},[355,16622,16623],{"class":1264},"product_id\n",[19,16625,16626],{},[34,16627,8219],{},[443,16629,16630,16633,16636],{},[446,16631,16632],{},"Fréquence des déploiements en production",[446,16634,16635],{},"Calculée par composant puis agrégée au niveau produit",[446,16637,16638],{},"Exclusion des déploiements de configuration",[344,16640,16642],{"className":16440,"code":16641,"language":16442,"meta":350,"style":350},"-- Calcul de la fréquence de déploiement par composant\nWITH deployments_ordered AS (SELECT component_name,\n                                    product_id,\n                                    deployment_timestamp,\n                                    LAG(deployment_timestamp) OVER (\n      PARTITION BY component_name\n      ORDER BY deployment_timestamp\n    ) as previous_deployment\n                             FROM `dora_metrics.deployments`\n                             WHERE environment = 'prod'\n                               AND is_config_only = FALSE\n                               AND deployment_timestamp BETWEEN '2024-01-01' AND '2024-12-31')\nSELECT component_name,\n       product_id,\n       COUNT(*)                                                            as deployment_count,\n       AVG(TIMESTAMP_DIFF(deployment_timestamp, previous_deployment, DAY)) as avg_days_between_deployments,\n       SAFE_DIVIDE(COUNT(*), 365)                                          as deployments_per_day\nFROM deployments_ordered\nWHERE previous_deployment IS NOT NULL\nGROUP BY component_name, product_id\n",[352,16643,16644,16649,16667,16672,16677,16691,16702,16710,16720,16728,16740,16753,16773,16779,16784,16802,16819,16845,16852,16862],{"__ignoreMap":350},[355,16645,16646],{"class":357,"line":358},[355,16647,16648],{"class":3858},"-- Calcul de la fréquence de déploiement par composant\n",[355,16650,16651,16654,16657,16660,16662,16664],{"class":357,"line":364},[355,16652,16653],{"class":2801},"WITH",[355,16655,16656],{"class":1119}," deployments_ordered ",[355,16658,16659],{"class":2801},"AS",[355,16661,494],{"class":1119},[355,16663,16454],{"class":2801},[355,16665,16666],{"class":1119}," component_name,\n",[355,16668,16669],{"class":357,"line":370},[355,16670,16671],{"class":1119},"                                    product_id,\n",[355,16673,16674],{"class":357,"line":376},[355,16675,16676],{"class":1119},"                                    deployment_timestamp,\n",[355,16678,16679,16682,16685,16688],{"class":357,"line":382},[355,16680,16681],{"class":1264},"                                    LAG",[355,16683,16684],{"class":1119},"(deployment_timestamp) ",[355,16686,16687],{"class":2801},"OVER",[355,16689,16690],{"class":1119}," (\n",[355,16692,16693,16696,16699],{"class":357,"line":1157},[355,16694,16695],{"class":2801},"      PARTITION",[355,16697,16698],{"class":2801}," BY",[355,16700,16701],{"class":1119}," component_name\n",[355,16703,16704,16707],{"class":357,"line":1165},[355,16705,16706],{"class":2801},"      ORDER BY",[355,16708,16709],{"class":1119}," deployment_timestamp\n",[355,16711,16712,16715,16717],{"class":357,"line":1173},[355,16713,16714],{"class":1119},"    ) ",[355,16716,16511],{"class":2801},[355,16718,16719],{"class":1119}," previous_deployment\n",[355,16721,16722,16725],{"class":357,"line":1181},[355,16723,16724],{"class":2801},"                             FROM",[355,16726,16727],{"class":1138}," `dora_metrics.deployments`\n",[355,16729,16730,16733,16736,16738],{"class":357,"line":1189},[355,16731,16732],{"class":2801},"                             WHERE",[355,16734,16735],{"class":1119}," environment ",[355,16737,2042],{"class":2801},[355,16739,16580],{"class":1138},[355,16741,16742,16745,16748,16750],{"class":357,"line":1197},[355,16743,16744],{"class":2801},"                               AND",[355,16746,16747],{"class":1119}," is_config_only ",[355,16749,2042],{"class":2801},[355,16751,16752],{"class":1119}," FALSE\n",[355,16754,16755,16757,16760,16763,16765,16767,16770],{"class":357,"line":1205},[355,16756,16744],{"class":2801},[355,16758,16759],{"class":1119}," deployment_timestamp ",[355,16761,16762],{"class":2801},"BETWEEN",[355,16764,16597],{"class":1138},[355,16766,16600],{"class":2801},[355,16768,16769],{"class":1138}," '2024-12-31'",[355,16771,16772],{"class":1119},")\n",[355,16774,16775,16777],{"class":357,"line":1213},[355,16776,16454],{"class":2801},[355,16778,16666],{"class":1119},[355,16780,16781],{"class":357,"line":1221},[355,16782,16783],{"class":1119},"       product_id,\n",[355,16785,16786,16789,16791,16794,16797,16799],{"class":357,"line":1229},[355,16787,16788],{"class":1264},"       COUNT",[355,16790,2169],{"class":1119},[355,16792,16793],{"class":2801},"*",[355,16795,16796],{"class":1119},")                                                            ",[355,16798,16511],{"class":2801},[355,16800,16801],{"class":1119}," deployment_count,\n",[355,16803,16804,16806,16809,16812,16814,16816],{"class":357,"line":1237},[355,16805,16481],{"class":1264},[355,16807,16808],{"class":1119},"(TIMESTAMP_DIFF(deployment_timestamp, previous_deployment, ",[355,16810,16811],{"class":2801},"DAY",[355,16813,16508],{"class":1119},[355,16815,16511],{"class":2801},[355,16817,16818],{"class":1119}," avg_days_between_deployments,\n",[355,16820,16821,16824,16827,16829,16831,16834,16837,16840,16842],{"class":357,"line":1245},[355,16822,16823],{"class":1119},"       SAFE_DIVIDE(",[355,16825,16826],{"class":1264},"COUNT",[355,16828,2169],{"class":1119},[355,16830,16793],{"class":2801},[355,16832,16833],{"class":1119},"), ",[355,16835,16836],{"class":1264},"365",[355,16838,16839],{"class":1119},")                                          ",[355,16841,16511],{"class":2801},[355,16843,16844],{"class":1119}," deployments_per_day\n",[355,16846,16847,16849],{"class":357,"line":1256},[355,16848,16519],{"class":2801},[355,16850,16851],{"class":1119}," deployments_ordered\n",[355,16853,16854,16856,16859],{"class":357,"line":1268},[355,16855,16568],{"class":2801},[355,16857,16858],{"class":1119}," previous_deployment ",[355,16860,16861],{"class":2801},"IS NOT NULL\n",[355,16863,16864,16866],{"class":357,"line":1274},[355,16865,16608],{"class":2801},[355,16867,16868],{"class":1119}," component_name, product_id\n",[19,16870,16871],{},[34,16872,8228],{},[443,16874,16875,16878,16881],{},[446,16876,16877],{},"Taux de déploiements causant au moins un incident en production",[446,16879,16880],{},"Exprimé en pourcentage",[446,16882,16883],{},"Basé sur les déploiements Kubernetes réussis et les incidents ServiceNow résolus",[344,16885,16887],{"className":16440,"code":16886,"language":16442,"meta":350,"style":350},"-- Calcul du Change Failure Rate par produit\nWITH deployments_with_incidents AS (SELECT d.deployment_id,\n                                           d.product_id,\n                                           MAX(CASE WHEN i.incident_id IS NOT NULL THEN 1 ELSE 0 END) as has_incident\n                                    FROM `dora_metrics.deployments` d\n                                             LEFT JOIN\n                                         `dora_metrics.incidents` i\n                                         ON\n                                             d.product_id = i.product_id\n                                                 AND i.created_timestamp > d.deployment_timestamp\n                                                 AND i.created_timestamp \u003C= (SELECT MIN(next_d.deployment_timestamp)\n                                                                             FROM `dora_metrics.deployments` next_d\n                                                                             WHERE next_d.product_id = d.product_id\n                                                                               AND next_d.deployment_timestamp > d.deployment_timestamp)\n                                    WHERE d.environment = 'prod'\n                                      AND d.deployment_timestamp BETWEEN '2024-01-01' AND '2024-12-31'\n                                    GROUP BY d.deployment_id, d.product_id)\nSELECT product_id,\n       COUNT(*)                                       as total_deployments,\n       SUM(has_incident)                              as failed_deployments,\n       SAFE_DIVIDE(SUM(has_incident), COUNT(*)) * 100 as change_failure_rate_percent\nFROM deployments_with_incidents\nGROUP BY product_id\n",[352,16888,16889,16894,16916,16927,16974,16983,16988,16996,17001,17018,17040,17071,17081,17101,17122,17137,17156,17177,17184,17200,17213,17242,17249],{"__ignoreMap":350},[355,16890,16891],{"class":357,"line":358},[355,16892,16893],{"class":3858},"-- Calcul du Change Failure Rate par produit\n",[355,16895,16896,16898,16901,16903,16905,16907,16909,16911,16914],{"class":357,"line":364},[355,16897,16653],{"class":2801},[355,16899,16900],{"class":1119}," deployments_with_incidents ",[355,16902,16659],{"class":2801},[355,16904,494],{"class":1119},[355,16906,16454],{"class":2801},[355,16908,16457],{"class":1264},[355,16910,44],{"class":1119},[355,16912,16913],{"class":1264},"deployment_id",[355,16915,3144],{"class":1119},[355,16917,16918,16921,16923,16925],{"class":357,"line":370},[355,16919,16920],{"class":1264},"                                           d",[355,16922,44],{"class":1119},[355,16924,16474],{"class":1264},[355,16926,3144],{"class":1119},[355,16928,16929,16932,16934,16937,16940,16943,16945,16948,16951,16954,16957,16960,16963,16966,16969,16971],{"class":357,"line":376},[355,16930,16931],{"class":1264},"                                           MAX",[355,16933,2169],{"class":1119},[355,16935,16936],{"class":2801},"CASE",[355,16938,16939],{"class":2801}," WHEN",[355,16941,16942],{"class":1264}," i",[355,16944,44],{"class":1119},[355,16946,16947],{"class":1264},"incident_id",[355,16949,16950],{"class":2801}," IS NOT NULL",[355,16952,16953],{"class":2801}," THEN",[355,16955,16956],{"class":1264}," 1",[355,16958,16959],{"class":2801}," ELSE",[355,16961,16962],{"class":1264}," 0",[355,16964,16965],{"class":2801}," END",[355,16967,16968],{"class":1119},") ",[355,16970,16511],{"class":2801},[355,16972,16973],{"class":1119}," has_incident\n",[355,16975,16976,16979,16981],{"class":357,"line":382},[355,16977,16978],{"class":2801},"                                    FROM",[355,16980,16522],{"class":1138},[355,16982,16525],{"class":1119},[355,16984,16985],{"class":357,"line":1157},[355,16986,16987],{"class":2801},"                                             LEFT JOIN\n",[355,16989,16990,16993],{"class":357,"line":1165},[355,16991,16992],{"class":1138},"                                         `dora_metrics.incidents`",[355,16994,16995],{"class":1119}," i\n",[355,16997,16998],{"class":357,"line":1173},[355,16999,17000],{"class":2801},"                                         ON\n",[355,17002,17003,17006,17008,17010,17012,17014,17016],{"class":357,"line":1181},[355,17004,17005],{"class":1264},"                                             d",[355,17007,44],{"class":1119},[355,17009,16474],{"class":1264},[355,17011,3213],{"class":2801},[355,17013,16942],{"class":1264},[355,17015,44],{"class":1119},[355,17017,16623],{"class":1264},[355,17019,17020,17023,17025,17027,17030,17033,17035,17037],{"class":357,"line":1189},[355,17021,17022],{"class":2801},"                                                 AND",[355,17024,16942],{"class":1264},[355,17026,44],{"class":1119},[355,17028,17029],{"class":1264},"created_timestamp",[355,17031,17032],{"class":2801}," >",[355,17034,16457],{"class":1264},[355,17036,44],{"class":1119},[355,17038,17039],{"class":1264},"deployment_timestamp\n",[355,17041,17042,17044,17046,17048,17050,17053,17055,17057,17060,17062,17065,17067,17069],{"class":357,"line":1197},[355,17043,17022],{"class":2801},[355,17045,16942],{"class":1264},[355,17047,44],{"class":1119},[355,17049,17029],{"class":1264},[355,17051,17052],{"class":2801}," \u003C=",[355,17054,494],{"class":1119},[355,17056,16454],{"class":2801},[355,17058,17059],{"class":1264}," MIN",[355,17061,2169],{"class":1119},[355,17063,17064],{"class":1264},"next_d",[355,17066,44],{"class":1119},[355,17068,16491],{"class":1264},[355,17070,16772],{"class":1119},[355,17072,17073,17076,17078],{"class":357,"line":1205},[355,17074,17075],{"class":2801},"                                                                             FROM",[355,17077,16522],{"class":1138},[355,17079,17080],{"class":1119}," next_d\n",[355,17082,17083,17086,17089,17091,17093,17095,17097,17099],{"class":357,"line":1213},[355,17084,17085],{"class":2801},"                                                                             WHERE",[355,17087,17088],{"class":1264}," next_d",[355,17090,44],{"class":1119},[355,17092,16474],{"class":1264},[355,17094,3213],{"class":2801},[355,17096,16457],{"class":1264},[355,17098,44],{"class":1119},[355,17100,16623],{"class":1264},[355,17102,17103,17106,17108,17110,17112,17114,17116,17118,17120],{"class":357,"line":1221},[355,17104,17105],{"class":2801},"                                                                               AND",[355,17107,17088],{"class":1264},[355,17109,44],{"class":1119},[355,17111,16491],{"class":1264},[355,17113,17032],{"class":2801},[355,17115,16457],{"class":1264},[355,17117,44],{"class":1119},[355,17119,16491],{"class":1264},[355,17121,16772],{"class":1119},[355,17123,17124,17127,17129,17131,17133,17135],{"class":357,"line":1229},[355,17125,17126],{"class":2801},"                                    WHERE",[355,17128,16457],{"class":1264},[355,17130,44],{"class":1119},[355,17132,16575],{"class":1264},[355,17134,3213],{"class":2801},[355,17136,16580],{"class":1138},[355,17138,17139,17142,17144,17146,17148,17150,17152,17154],{"class":357,"line":1237},[355,17140,17141],{"class":2801},"                                      AND",[355,17143,16457],{"class":1264},[355,17145,44],{"class":1119},[355,17147,16491],{"class":1264},[355,17149,16594],{"class":2801},[355,17151,16597],{"class":1138},[355,17153,16600],{"class":2801},[355,17155,16603],{"class":1138},[355,17157,17158,17161,17163,17165,17167,17169,17171,17173,17175],{"class":357,"line":1245},[355,17159,17160],{"class":2801},"                                    GROUP BY",[355,17162,16457],{"class":1264},[355,17164,44],{"class":1119},[355,17166,16913],{"class":1264},[355,17168,504],{"class":1119},[355,17170,2458],{"class":1264},[355,17172,44],{"class":1119},[355,17174,16474],{"class":1264},[355,17176,16772],{"class":1119},[355,17178,17179,17181],{"class":357,"line":1256},[355,17180,16454],{"class":2801},[355,17182,17183],{"class":1119}," product_id,\n",[355,17185,17186,17188,17190,17192,17195,17197],{"class":357,"line":1268},[355,17187,16788],{"class":1264},[355,17189,2169],{"class":1119},[355,17191,16793],{"class":2801},[355,17193,17194],{"class":1119},")                                       ",[355,17196,16511],{"class":2801},[355,17198,17199],{"class":1119}," total_deployments,\n",[355,17201,17202,17205,17208,17210],{"class":357,"line":1274},[355,17203,17204],{"class":1264},"       SUM",[355,17206,17207],{"class":1119},"(has_incident)                              ",[355,17209,16511],{"class":2801},[355,17211,17212],{"class":1119}," failed_deployments,\n",[355,17214,17215,17217,17220,17223,17225,17227,17229,17231,17233,17236,17239],{"class":357,"line":1282},[355,17216,16823],{"class":1119},[355,17218,17219],{"class":1264},"SUM",[355,17221,17222],{"class":1119},"(has_incident), ",[355,17224,16826],{"class":1264},[355,17226,2169],{"class":1119},[355,17228,16793],{"class":2801},[355,17230,16508],{"class":1119},[355,17232,16793],{"class":2801},[355,17234,17235],{"class":1264}," 100",[355,17237,17238],{"class":2801}," as",[355,17240,17241],{"class":1119}," change_failure_rate_percent\n",[355,17243,17244,17246],{"class":357,"line":1290},[355,17245,16519],{"class":2801},[355,17247,17248],{"class":1119}," deployments_with_incidents\n",[355,17250,17251,17253],{"class":357,"line":1301},[355,17252,16608],{"class":2801},[355,17254,17255],{"class":1119}," product_id\n",[19,17257,17258],{},[34,17259,15207],{},[443,17261,17262,17265,17268],{},[446,17263,17264],{},"Temps moyen de résolution des incidents",[446,17266,17267],{},"Calculé à partir des dates d'ouverture et de résolution dans ServiceNow",[446,17269,17270],{},"Agrégé au niveau produit",[344,17272,17274],{"className":16440,"code":17273,"language":16442,"meta":350,"style":350},"-- Calcul du Mean Time To Recover par produit\nSELECT product_id,\n       COUNT(*)                                                         as incident_count,\n       AVG(TIMESTAMP_DIFF(resolved_timestamp, created_timestamp, HOUR)) as mttr_hours\nFROM `dora_metrics.incidents`\nWHERE status = 'Resolved'\n  AND created_timestamp BETWEEN '2024-01-01' AND '2024-12-31'\n  AND resolved_timestamp IS NOT NULL\nGROUP BY product_id\n",[352,17275,17276,17281,17287,17303,17319,17326,17338,17353,17362],{"__ignoreMap":350},[355,17277,17278],{"class":357,"line":358},[355,17279,17280],{"class":3858},"-- Calcul du Mean Time To Recover par produit\n",[355,17282,17283,17285],{"class":357,"line":364},[355,17284,16454],{"class":2801},[355,17286,17183],{"class":1119},[355,17288,17289,17291,17293,17295,17298,17300],{"class":357,"line":370},[355,17290,16788],{"class":1264},[355,17292,2169],{"class":1119},[355,17294,16793],{"class":2801},[355,17296,17297],{"class":1119},")                                                         ",[355,17299,16511],{"class":2801},[355,17301,17302],{"class":1119}," incident_count,\n",[355,17304,17305,17307,17310,17312,17314,17316],{"class":357,"line":376},[355,17306,16481],{"class":1264},[355,17308,17309],{"class":1119},"(TIMESTAMP_DIFF(resolved_timestamp, created_timestamp, ",[355,17311,16505],{"class":2801},[355,17313,16508],{"class":1119},[355,17315,16511],{"class":2801},[355,17317,17318],{"class":1119}," mttr_hours\n",[355,17320,17321,17323],{"class":357,"line":382},[355,17322,16519],{"class":2801},[355,17324,17325],{"class":1138}," `dora_metrics.incidents`\n",[355,17327,17328,17330,17333,17335],{"class":357,"line":1157},[355,17329,16568],{"class":2801},[355,17331,17332],{"class":2801}," status",[355,17334,3213],{"class":2801},[355,17336,17337],{"class":1138}," 'Resolved'\n",[355,17339,17340,17342,17345,17347,17349,17351],{"class":357,"line":1165},[355,17341,16585],{"class":2801},[355,17343,17344],{"class":1119}," created_timestamp ",[355,17346,16762],{"class":2801},[355,17348,16597],{"class":1138},[355,17350,16600],{"class":2801},[355,17352,16603],{"class":1138},[355,17354,17355,17357,17360],{"class":357,"line":1173},[355,17356,16585],{"class":2801},[355,17358,17359],{"class":1119}," resolved_timestamp ",[355,17361,16861],{"class":2801},[355,17363,17364,17366],{"class":357,"line":1181},[355,17365,16608],{"class":2801},[355,17367,17255],{"class":1119},[84,17369,17371],{"id":17370},"fiabilisation-et-optimisation-des-données","Fiabilisation et optimisation des données",[19,17373,17374],{},[34,17375,17376],{},"Infrastructure as Code",[443,17378,17379,17382,17385],{},[446,17380,17381],{},"Utilisation de Terraform pour standardiser les déploiements",[446,17383,17384],{},"Configuration automatique des annotations requises",[446,17386,17387],{},"Validation des formats de données",[19,17389,17390],{},[34,17391,17392],{},"Bonnes pratiques",[443,17394,17395,17398,17401],{},[446,17396,17397],{},"Tagging systématique des versions",[446,17399,17400],{},"Documentation des conventions",[446,17402,17403],{},"Formation des équipes",[19,17405,17406],{},[34,17407,17408],{},"Monitoring",[443,17410,17411,17414,17417],{},[446,17412,17413],{},"Détection des annotations manquantes",[446,17415,17416],{},"Alertes sur les incohérences",[446,17418,17419],{},"Suivi de la qualité des données",[19,17421,17422],{},[34,17423,17424],{},"Optimisation de BigQuery",[19,17426,17427],{},"La gestion d'un volume important de données dans BigQuery a nécessité plusieurs optimisations :",[344,17429,17431],{"className":16440,"code":17430,"language":16442,"meta":350,"style":350},"-- Création de tables partitionnées par date pour améliorer les performances\nCREATE TABLE `dora_metrics.deployments_partitioned`\n    PARTITION BY DATE\n(\n    deployment_timestamp\n)\nAS\nSELECT *\nFROM `dora_metrics.deployments`;\n\n-- Création de vues matérialisées pour les requêtes fréquentes\nCREATE\nMATERIALIZED VIEW `dora_metrics.lead_time_daily`\nAS\nSELECT product_id, DATE (deployment_timestamp) as deployment_date, AVG (TIMESTAMP_DIFF(deployment_timestamp, commit_timestamp, HOUR)) as avg_lead_time_hours\nFROM\n    `dora_metrics.deployments_with_commits`\nGROUP BY\n    product_id, deployment_date;\n\n",[352,17432,17433,17438,17449,17459,17463,17468,17472,17477,17484,17493,17497,17502,17507,17515,17519,17552,17557,17562,17567],{"__ignoreMap":350},[355,17434,17435],{"class":357,"line":358},[355,17436,17437],{"class":3858},"-- Création de tables partitionnées par date pour améliorer les performances\n",[355,17439,17440,17443,17446],{"class":357,"line":364},[355,17441,17442],{"class":2801},"CREATE",[355,17444,17445],{"class":2801}," TABLE",[355,17447,17448],{"class":1138}," `dora_metrics.deployments_partitioned`\n",[355,17450,17451,17454,17456],{"class":357,"line":370},[355,17452,17453],{"class":2801},"    PARTITION",[355,17455,16698],{"class":2801},[355,17457,17458],{"class":2801}," DATE\n",[355,17460,17461],{"class":357,"line":376},[355,17462,3248],{"class":1119},[355,17464,17465],{"class":357,"line":382},[355,17466,17467],{"class":1119},"    deployment_timestamp\n",[355,17469,17470],{"class":357,"line":1157},[355,17471,16772],{"class":1119},[355,17473,17474],{"class":357,"line":1165},[355,17475,17476],{"class":2801},"AS\n",[355,17478,17479,17481],{"class":357,"line":1173},[355,17480,16454],{"class":2801},[355,17482,17483],{"class":2801}," *\n",[355,17485,17486,17488,17490],{"class":357,"line":1181},[355,17487,16519],{"class":2801},[355,17489,16522],{"class":1138},[355,17491,17492],{"class":1119},";\n",[355,17494,17495],{"class":357,"line":1189},[355,17496,1271],{"emptyLinePlaceholder":893},[355,17498,17499],{"class":357,"line":1197},[355,17500,17501],{"class":3858},"-- Création de vues matérialisées pour les requêtes fréquentes\n",[355,17503,17504],{"class":357,"line":1205},[355,17505,17506],{"class":2801},"CREATE\n",[355,17508,17509,17512],{"class":357,"line":1213},[355,17510,17511],{"class":1119},"MATERIALIZED VIEW ",[355,17513,17514],{"class":1138},"`dora_metrics.lead_time_daily`\n",[355,17516,17517],{"class":357,"line":1221},[355,17518,17476],{"class":2801},[355,17520,17521,17523,17526,17529,17532,17534,17537,17540,17543,17545,17547,17549],{"class":357,"line":1229},[355,17522,16454],{"class":2801},[355,17524,17525],{"class":1119}," product_id, ",[355,17527,17528],{"class":2801},"DATE",[355,17530,17531],{"class":1119}," (deployment_timestamp) ",[355,17533,16511],{"class":2801},[355,17535,17536],{"class":1119}," deployment_date, ",[355,17538,17539],{"class":1264},"AVG",[355,17541,17542],{"class":1119}," (TIMESTAMP_DIFF(deployment_timestamp, commit_timestamp, ",[355,17544,16505],{"class":2801},[355,17546,16508],{"class":1119},[355,17548,16511],{"class":2801},[355,17550,17551],{"class":1119}," avg_lead_time_hours\n",[355,17553,17554],{"class":357,"line":1237},[355,17555,17556],{"class":2801},"FROM\n",[355,17558,17559],{"class":357,"line":1245},[355,17560,17561],{"class":1138},"    `dora_metrics.deployments_with_commits`\n",[355,17563,17564],{"class":357,"line":1256},[355,17565,17566],{"class":2801},"GROUP BY\n",[355,17568,17569],{"class":357,"line":1268},[355,17570,17571],{"class":1119},"    product_id, deployment_date;\n",[19,17573,17574],{},[34,17575,17576],{},"Automatisation des flux de données",[19,17578,17579],{},"Nous avons mis en place plusieurs processus automatisés pour maintenir des données à jour :",[443,17581,17582,17585,17588],{},[446,17583,17584],{},"Jobs Cloud Functions pour synchroniser les données ServiceNow toutes les 15 minutes",[446,17586,17587],{},"Webhooks GitHub pour capturer les événements de commit et de tag en temps réel",[446,17589,17590],{},"Export des logs Kubernetes via Cloud Logging avec un délai maximum de 5 minutes",[19,17592,17593],{},"Cette approche nous permet d'obtenir des métriques fiables et exploitables pour l'amélioration continue de nos processus de livraison.",[84,17595,17597],{"id":17596},"points-clés-pour-lagrégation","Points clés pour l'agrégation 🔑",[1003,17599,17600],{},[19,17601,17602],{},[34,17603,17604],{},"Garantir la cohérence et la pertinence des métriques agrégées",[443,17606,17607,17612,17617],{},[446,17608,17609],{},[34,17610,17611],{},"Pondération",[446,17613,17614],{},[34,17615,17616],{},"Exclusions",[446,17618,17619],{},[34,17620,17621],{},"Cas particuliers",[19,17623,17624],{},"Cette approche d'agrégation garantit :",[443,17626,17627,17630,17633],{},[446,17628,17629],{},"Une représentation équitable à chaque niveau",[446,17631,17632],{},"Une cohérence dans le calcul des métriques",[446,17634,17635],{},"Une prise en compte appropriée des cas limites",[84,17637,17639],{"id":17638},"synthèse-de-notre-approche-dimplémentation","Synthèse de notre approche d'implémentation",[1003,17641,17642],{},[19,17643,17644],{},[34,17645,17646],{},"Une implémentation progressive et adaptée au contexte",[19,17648,17649],{},"Notre approche d'implémentation des DORA Metrics a combiné rigueur méthodologique et pragmatisme. Nous avons défini des formules de calcul précises tout en les adaptant aux réalités opérationnelles de l'entreprise. L'agrégation multi-niveaux nous a permis de répondre aux besoins de tous, du développeur individuel jusqu'au comité de direction.",[19,17651,17652],{},"Cette implémentation technique n'était cependant que la première étape. La véritable valeur des DORA Metrics réside dans leur capacité à transformer les pratiques et la culture de l'organisation.",[23,17654,17656],{"id":17655},"_6-bénéfices-enseignements-et-perspectives","6. Bénéfices, enseignements et perspectives 🤔",[1003,17658,17659],{},[19,17660,17661],{},[34,17662,17663],{},"La mise en place des DORA Metrics est un voyage, pas une destination.",[19,17665,17666],{},"Ce retour d'expérience illustre une réalité fondamentale : implémenter les DORA Metrics dans un grand groupe nécessite bien plus qu'une simple application de formules mathématiques. C'est un projet de transformation qui touche à la fois aux aspects techniques, organisationnels et humains.",[84,17668,17670],{"id":17669},"bénéfices-observés","Bénéfices observés",[1003,17672,17673],{},[19,17674,17675],{},[34,17676,17677],{},"Impact transformationnel : au-delà des chiffres",[19,17679,17680],{},"L'implémentation des DORA Metrics a généré des bénéfices qui dépassent largement le cadre de la simple mesure de performance. Elle a catalysé une véritable transformation des pratiques et de la culture de livraison logicielle au sein de l'organisation.",[19,17682,17683],{},"Voici les principaux impacts positifs observés :",[443,17685,17686,17692,17698],{},[446,17687,17688,17691],{},[34,17689,17690],{},"Une meilleure visibilité sur la performance de livraison"," : Les équipes ont pu objectiver leurs points forts (par exemple, une fréquence de déploiement élevée) et leurs axes d'amélioration (par exemple, un très long \"Lead Time for Changes\").",[446,17693,17694,17697],{},[34,17695,17696],{},"Un langage commun entre équipes"," : Les DORA Metrics servent désormais de référence partagée. Lorsqu'il y a un incident, tout le monde comprend la corrélation possible entre le \"dernier déploiement\" et le Change Failure Rate.",[446,17699,17700,17703],{},[34,17701,17702],{},"La mise en lumière de la dette de traçabilité"," : Le besoin de taguer systématiquement les versions, d'indiquer l'instance concernée dans les tickets, etc. a été rendu évident grâce à la mesure du Lead Time for Changes et du Change Failure Rate.",[19,17705,17706],{},"Ces métriques sont imparfaites (comme tout indicateur), mais elles offrent un \"socle\" suffisamment solide pour enclencher de vraies discussions et pour s'améliorer en continu.",[84,17708,17710],{"id":17709},"enseignements-clés","Enseignements clés",[19,17712,17713],{},"Cette expérience a impliqué de nombreuses adaptations et m'a permis de tirer plusieurs enseignements importants :",[443,17715,17716,17722,17728,17734,17740],{},[446,17717,17718,17721],{},[34,17719,17720],{},"Standardisation nécessaire"," : Les DORA Metrics nécessitent une standardisation des pratiques DevOps pour être efficaces",[446,17723,17724,17727],{},[34,17725,17726],{},"Adaptation au contexte"," : Il est essentiel d'adapter les métriques au contexte spécifique de l'entreprise",[446,17729,17730,17733],{},[34,17731,17732],{},"Qualité des données cruciale"," : La fiabilité des métriques dépend directement de la qualité des données collectées",[446,17735,17736,17739],{},[34,17737,17738],{},"Dimension humaine prépondérante"," : L'accompagnement des équipes et la gestion du changement sont aussi importants que l'aspect technique",[446,17741,17742,17745],{},[34,17743,17744],{},"Pragmatisme indispensable"," : Accepter les imperfections initiales et itérer progressivement est la clé du succès",[84,17747,17749],{"id":17748},"perspectives-dévolution","Perspectives d'évolution",[19,17751,17752],{},"Cette première phase d'implémentation nous a permis d'identifier plusieurs axes d'amélioration pour l'avenir :",[443,17754,17755,17761,17767],{},[446,17756,17757,17760],{},[34,17758,17759],{},"Détection des changements de Configuration"," : Déployer une solution pour tracer précisément les modifications de configuration, actuellement difficiles à distinguer des déploiements de code.",[446,17762,17763,17766],{},[34,17764,17765],{},"Granularité des incidents"," : Enrichir ServiceNow pour associer chaque incident au composant ou à l'instance spécifique concernée, permettant ainsi un calcul plus précis du Change Failure Rate.",[446,17768,17769,17772],{},[34,17770,17771],{},"Automatisation accrue"," : Réduire les interventions manuelles dans la collecte et le traitement des données pour améliorer la fiabilité et la fréquence de mise à jour des métriques.",[23,17774,17775],{"id":1527},"Conclusion 🙌",[19,17777,17778],{},"Ce retour d'expérience démontre que la mise en place des DORA Metrics dans un grand groupe est un projet de transformation à part entière. Au-delà des aspects techniques, c'est avant tout un projet humain qui nécessite pédagogie, pragmatisme et persévérance.",[19,17780,17781],{},"Le parcours n’a pas été sans difficultés. Il y des inquiétudes, notamment parmi les personnes directement impliquées dans les projets. Grâce à des sponsors engagés et, surtout, à une approche basée sur la transparence et le temps accordé à chacun, nous avons pu atteindre nos objectifs.",[19,17783,17784],{},"Les bénéfices sont à la hauteur de l'investissement : une meilleure visibilité sur la performance de livraison, un langage commun entre les équipes, et surtout, une culture d'amélioration continue qui s'installe progressivement dans l'organisation.",[1003,17786,17787],{},[19,17788,17789,17790,17794,17795,17799],{},"J'espère que ce partage d'expérience vous sera utile ! N'hésitez à me contacter ",[91,17791,17793],{"href":13,"rel":17792},[95],"sur Linkedin"," ou ",[91,17796,17798],{"href":17797},"mailto:maxime@hoppr.tech","par mail"," si vous souhaitez échanger sur le sujet 🙂",[856,17801,17802],{},"html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":350,"searchDepth":364,"depth":364,"links":17804},[17805,17809,17817,17824,17830,17842,17847],{"id":8234,"depth":364,"text":8235,"children":17806},[17807,17808],{"id":8238,"depth":370,"text":8239},{"id":8288,"depth":370,"text":8289},{"id":8333,"depth":364,"text":8334,"children":17810},[17811,17812,17813,17814,17815,17816],{"id":8340,"depth":370,"text":8341},{"id":8366,"depth":370,"text":8367},{"id":8411,"depth":370,"text":8412},{"id":8467,"depth":370,"text":8468},{"id":8516,"depth":370,"text":8517},{"id":8552,"depth":370,"text":8553},{"id":8586,"depth":364,"text":8587,"children":17818},[17819,17820,17821,17822,17823],{"id":8601,"depth":370,"text":8602},{"id":8641,"depth":370,"text":8642},{"id":8674,"depth":370,"text":8675},{"id":8704,"depth":370,"text":8705},{"id":8740,"depth":370,"text":8741},{"id":8779,"depth":364,"text":8780,"children":17825},[17826,17827,17828,17829],{"id":8791,"depth":370,"text":8792},{"id":8820,"depth":370,"text":8821},{"id":8939,"depth":370,"text":8940},{"id":8995,"depth":370,"text":8996},{"id":9053,"depth":364,"text":9054,"children":17831},[17832,17833,17834,17835,17836,17837,17838,17839,17840,17841],{"id":9065,"depth":370,"text":9066},{"id":10224,"depth":370,"text":10225},{"id":10257,"depth":370,"text":10258},{"id":12721,"depth":370,"text":8219},{"id":14025,"depth":370,"text":8228},{"id":15206,"depth":370,"text":15207},{"id":16164,"depth":370,"text":16165},{"id":17370,"depth":370,"text":17371},{"id":17596,"depth":370,"text":17597},{"id":17638,"depth":370,"text":17639},{"id":17655,"depth":364,"text":17656,"children":17843},[17844,17845,17846],{"id":17669,"depth":370,"text":17670},{"id":17709,"depth":370,"text":17710},{"id":17748,"depth":370,"text":17749},{"id":1527,"depth":364,"text":17775},"2025-05-19T07:04:21.147Z","  Nouvel article qui fait suite à mon [introduction aux DORA Metrics](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-10-31-dora-metrics-valuer-la-performance-de-livraison-logiciellePour rappel, je vous avais défi",{},"\u002Fblogs\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex",[17853,17855,17857],{"id":1577,"name":1578,"image":17854,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4667VDCLJIY%2F20250519%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250519T070421Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEM%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJGMEQCIGBBCPT0nDceez3W3BGyZSAp9VTP1gbHP6Nqqr2pE%2BNgAiB3cE3k3RB7rNftOS9EmDVVS1Lsbh5Xb2Ia%2Bfnvn5SduyqIBAiI%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAAaDDYzNzQyMzE4MzgwNSIMSY9HRup%2BAXGteiXAKtwDmUodglDndRVo1LcYLlVY3v6%2F421tAgt5QE4Km%2BOvwbzlLywe3DWQISAF4AaLgkSap3wRLTVeGvRXDNzu%2Ba70B%2BIwIHRp2Qj4X9JW8eOOad2t2SNsDDQgRJlW51NaoWz2z0DEaA4gV4Wc8qy6DaISJPq7I4jc7F6zaWsenWGcae1Zaw2ItJWg3IuyTvVrGtGV%2Fw%2FJHY3Aib7k6JRoYC3YTqMqFxYPbWnso%2FS4eNS%2Fx5KD01lc9mRA8qEDmVgclhDRSRHNk43K7vJRqy8HMp7eqkHnKgvfwihDYVHBHSR%2BOzVXJw2eWt8JsEgOmDDE7gLX%2BCoE22Zrtw55jpruQp4HT00uNGfb7QB7RjdbVJ%2F%2FpKXmg8FJpigwMln9zroPDZAOggOc4uS6sbOgjtfw95DXwsjQA8CxFFbS7v4z6350%2F1bLmLZmoYmOPxrq0GRtvZMjLVVrYdJYQDyP6BGNHyfw1RHPhao0yvfEqbX5sSMVr0lzQ0PlCaSzO4GWe1uWJh1vEha02YjqPE%2BlgPbYXlm4udoAzLVfC5ksko%2Bh%2BSzeaX4Yjgd6pMttpFzRlx3O75bfCrJ1avfYCWjkiUfv6eBwMruqNbc6j2n6VNlk56IBqkYP6yYwIYWyMZIjmEIwq52rwQY6pgHwBah8BeUChWncYSWs7FXBSY%2BUcuYZhAuJxjoPBxcQ7Bi1%2FF0Bhyznp8a%2FSoz99DSPpob2f4QLRwNU4rlmd7d%2FEJ2enXylud5H3vwXowD%2FyGPio4oEZwwuApGkW0cZBDDYIDrc6RF8IZ6fPFENTBdE2p6nPDjKWS1eR%2FykijI92KZLbk6CgIMJcD6XBB41udml2qGBPkTjtVksXDI3Vd4eo5SaSMhE&X-Amz-Signature=e472e93c2d4eb268a89b6a352180d12f360b654a6fe89a2d143d0641c0670f7f&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1582,"name":1583,"image":17856,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB46677NLYCVN%2F20250519%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250519T070420Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEM%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJHMEUCIQD0EF43nYpEKhTyWKOIGav%2FQ%2BTb25IfMI%2BQIOkFu%2FWCcwIgd5JtEmYcM7on0OKor%2FLc1e2yxxhM9AQPuYtMSuYufY8qiAQIiP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDNbH6feQshRDWGQ2jCrcAyhRSDjT%2BUuGxz3eflkqBL8tuCQUltcfBs0WBNDQIK%2FFuZ0U9WcxktywjfXsC793QYKMsctb%2BSNtHAb2JZiLt%2Fr93O96JjbrzyTEfQWp45tT1DlJOhwLi%2B5AdQWfOGG8qmipV9iRLcIWiWxgjN4YtqSYjo6371UfdR6vpesWFNqWbFmthVReqLspbSlHB7eOxxbxLb%2FxsqXhpG2%2FRhUzidgP%2FkjcvfbtS2Kwb5ZLlU3xygLdhlH4%2BTVjppUEuPBck5%2B2I3Xi0LlTCACg35MnogNs9xMISuUB7dqnfT8gjHwLtDy1vADUYXHWNcGM4qmaPo%2FZYNle8VxCx6G4%2FJE%2BBhJyh9fVyKbmNzk5lP0%2Fa11GC111xaq12K%2FiSP%2BUv1yM%2FxB3uXVol7wue0%2BLt9Y7YgavH7%2BVeU43tfj6tYSEd4MkhEOMmwRdA9xLoLIV2khXRqTk%2BV853BZSVXTtJX%2FhZa1dX565FeaPPUfzj8z8OMh2VEpmoj07%2FhQBM1ZKpNZtiCK%2BmejI1qtAiu3UtyRQ6o4E3%2B27gg1PylN%2FhFSuF7Ler016B%2B%2FMJ3V1aeU2T2A5yaydPG6Of96Y8bR1qbss9JLvM204cHOXIma3SxFeDVmCaD3kGGAnZPSTwEt0MPSeq8EGOqUBCy1nD5O%2FS7qbc7Mg9i5LXGRQm%2F5x6TMMibiryt%2FuPh0tmEcjL52ro3xK1sVEUPPA9CHbL3TBuV3pxfvytRNMeC7s0i1HNur9ntxl1Dfg3zXBB8q%2B%2BjU%2B8%2F%2FpbFVYdzF3edQw8J8EiRIE%2BtTzlzjE6GuplfV2lVfXKzNEsbiWQrMTdzdLStWn3GSLvRjbclK2vCnUkrmEiWim2pdUdQ%2BsJFaALAv6&X-Amz-Signature=547b39163af6e011401dc41737ec0fe9665c995aa2b6a827ee8cbb2cd53d9408&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":897,"name":898,"image":17858,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466XQTI4TQI%2F20250519%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250519T070420Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEM%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJIMEYCIQDRDUDTAmYIqio%2FmaWQri1FF%2F6Z4KBY1PaxOyZbgHhQSgIhAOb9jlC7fm3qoH3eDFj%2BPxZ15AazzVgEBoJH5jIqcLiDKogECIj%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQABoMNjM3NDIzMTgzODA1IgyjWT7Y4DuO7PvWlMIq3AMUwL5De4lYqqfwLM7fZGLxoh1DyMk6FbV3bBODlECw24G0WCNIt9aQVASmXQCRWv%2F5ohii%2F0FJGjDmIYPx3woYclNVyHLHkfNcX%2FydeEGXDHDzzL%2BAuREI270tWNvBOiinUU%2BBEpyjcMSsgfCybsLZKHpIr%2BPc%2FIzj%2Bt7VUMCQGHLKWWXXJ%2Fb7rtsh55oLR0oeDa3XjE1FepXx9SbdiUtD%2BraseErNeAvR%2BOzUgrMBS6lvdJA6K4TiaVyxTyQspDxP0Z0JgIjYu6s9Zuele8SZaa0mAos%2F7tE2FI3J8zI2%2B3oueeslNr3fpYjKSGv8SIVqSOejK6XkbGhwSpfpGXCmaT55MIgwTVbo0fvQmhIwvXXDKJctfROqrrAyTxJupW%2F4ueUf2GY3GoNWDoV9n8Rj2NDav2J8nDRVVElMAzsanXqzDC5Fs7%2BwmTpUoC8j4kOxRcYqvdTRcBXrnsJOLUx857PAptI3uTul%2Fo65In4d751kK%2FIhVw5A6xOHejESjKpimz1dEDgqUPu56z9ETCFahyat5SEKn1Ox8VEK8%2BZazw1FTlJwQVgeSLioZvXDuZetaa3HaMYJ5FDZrm4FZprisT58%2F5o6%2BS%2BwN%2BP1oqvB1xHr%2F6Elya4khKVmfTDDnavBBjqkAZMWTec8zswzxdFRb3PuwsLPiUxj%2FFvWNesvBoWpkSV5qEhcB13ffmkTz8DqZdMYP2P44zQCRFF5ZVP1zHpWJWQbUmOsIsJgC7DFQtl9u8Tm1eZmCjn%2FYmKSLBlH6cPzyLwgxB75oneLvDtO6d%2B9fuh2taZGzEvS5fuK1uunlQwQjmV%2B5ekg3X37gxFLJcCaWo6fO9xfJqmxL4ZqxNArAW3b7hbZ&X-Amz-Signature=2095f8495e05ff76739c85445fcee827c52e27c5e32bf6b2a08510539e5a1c40&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":8195,"description":17849},"blogs\u002F2025-05-19-bref-jai-mis-en-place-les-dora-metrics-dans-un-grand-groupe-rex\u002Findex",[5654,1591,906,5009,907,17862],"performance","ycA5vXwxJYkyDRph3MaKxn750vp-QRZR-YiTh8WN_No",{"id":17865,"title":17866,"alt":17867,"authors":17868,"body":17870,"date":18435,"description":18436,"extension":890,"image":891,"meta":18437,"navigation":893,"ogImage":891,"path":18438,"published":893,"reviewers":18439,"seo":18446,"stem":18447,"tags":18448,"__hash__":18449},"blogs\u002Fblogs\u002F2025-05-07-lyon-craft-2025-22\u002Findex.md","Lyon Craft 2025 2\u002F2","Photo de la scène principale du Lyon Craft 2025, avec le logo de la conférence, avant le talk de conclusion de la journée.",[17869],{"id":1577,"name":1578,"image":1600,"linkedin":1580,"x":901},{"type":16,"value":17871,"toc":18428},[17872,17880,17884,17889,17896,17902,17915,17933,17942,17953,17960,17966,17969,17972,17987,17993,18020,18034,18049,18066,18069,18080,18094,18098,18103,18109,18112,18121,18128,18149,18158,18164,18175,18182,18196,18211,18217,18226,18232,18235,18252,18261,18279,18286,18300,18306,18312,18315,18321,18328,18333,18336,18347,18353,18362,18365,18368,18379,18390,18393,18396,18398,18413,18416,18425],[19,17873,17874,17875,17879],{},"Cet article est la suite de ",[91,17876,17878],{"href":6629,"rel":17877},[95],"mon retour sur Lyon Craft",". Dans cette première partie, nous avions couvert les talks auxquels j’ai eu la chance d’assister dans la matinée. Place maintenant à un après-midi de Craft !",[23,17881,17883],{"id":17882},"smalltalk-voyage-futuriste-dans-le-passé","Smalltalk, voyage futuriste dans le passé !",[19,17885,17886],{},[1620,17887,17888],{},"Par Lionel ARMANET",[19,17890,17891],{},[91,17892,17895],{"href":17893,"rel":17894},"https:\u002F\u002Flyon-craft.fr\u002Fsessions\u002Fsmalltalk-voyage-futuriste-dans-le-passe.html",[95],"Lien vers la conférence",[19,17897,17898],{},[176,17899],{"alt":17900,"src":17901},"Début de talk pour Lionel sur Smalltalk","\u002Fcontent-assets\u002F2025-05-07-lyon-craft-2025-22\u002Fassets\u002Fimg1.webp",[19,17903,17904,17905,17910,17911,17914],{},"Tout commence par une discussion entre Lionel et un de ses collègues. Celui-ci vient pour son premier jour avec un livre, ",[91,17906,17909],{"href":17907,"rel":17908},"https:\u002F\u002Fwww.babelio.com\u002Flivres\u002FMartin-Coder-proprement\u002F125763",[95],"Coder Proprement"," de Robert C. Martin. Lionel parcourt ce livre, un classique du Craft, revient vers son collègue et lui dit \"",[1620,17912,17913],{},"ton bouquin, c'est mon cours de Smalltalk de l'école","\".",[19,17916,17917,17918,17921,17922,17927,17928,44],{},"S’en suit une plongée dans les années 70, au Xerox PARC ",[1620,17919,17920],{},"(Palo Alto Research Center)",". Les créateurs de l’ordinateur ",[91,17923,17926],{"href":17924,"rel":17925},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FXerox_Alto",[95],"Xerox Alto",", un des premiers ordinateurs présentant une interface graphique, inventent le langage ",[91,17929,17932],{"href":17930,"rel":17931},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FSmalltalk",[95],"Smalltalk",[19,17934,17935,17936,17941],{},"Ce langage est le premier à utiliser les concepts clés de la ",[91,17937,17940],{"href":17938,"rel":17939},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FProgrammation_orient%C3%A9e_objet",[95],"POO",". L’idée sous-jacente est une métaphore du monde qui nous entoure, des objets et de leurs interactions. Les concepts objet ici :",[443,17943,17944,17947,17950],{},[446,17945,17946],{},"Encapsulation",[446,17948,17949],{},"Envoyer un message",[446,17951,17952],{},"Recevoir un message",[19,17954,17955,17956,17959],{},"Le Smalltalk est compilé en ",[1620,17957,17958],{},"bytecode"," et interprété par une machine virtuelle, pour plus de portabilité. Jusque là, les amateurs de Java ne sont pas surpris. Et pour cause, Java s’inspire de Smalltalk !",[19,17961,17962],{},[176,17963],{"alt":17964,"src":17965},"Hello World en Smalltalk","\u002Fcontent-assets\u002F2025-05-07-lyon-craft-2025-22\u002Fassets\u002Fimg2.webp",[19,17967,17968],{},"Il est à noter que Smalltalk avait pour but de pouvoir être simple à apprendre (par des enfants par exemple), et à se rapprocher au plus du langage anglais naturel. En Smalltalk, on écrit plus qu’on ne code, et on finit nos instructions par un point.",[19,17970,17971],{},"Pour finir l’histoire, la Xerox Alto est un échec commercial. Steve Jobs ayant visité le Xerox PARC, reprendra l’interface graphique pour créer l’Apple Lisa puis les Macintosh, et l’Objective-C comme successeur au Smalltalk.",[19,17973,17974,17975,17980,17981,17986],{},"Place maintenant à une démonstration de Smalltalk en live avec Lionel. Il utilise ici ",[91,17976,17979],{"href":17977,"rel":17978},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FCuis_Smalltalk",[95],"CUIS",", et nous parle également de ",[91,17982,17985],{"href":17983,"rel":17984},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FPharo",[95],"Pharo",". En effet, une communauté Smalltalk existe toujours pour garder le langage vivant.",[19,17988,17989],{},[176,17990],{"alt":17991,"src":17992},"Démonstration de Smalltalk par Lionel","\u002Fcontent-assets\u002F2025-05-07-lyon-craft-2025-22\u002Fassets\u002Fimg3.webp",[19,17994,17995,17996,18001,18002,18007,18008,18013,18014,18019],{},"En Smalltalk, tout est objet, et tout peut se réécrire. La ",[91,17997,18000],{"href":17998,"rel":17999},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FM%C3%A9taprogrammation",[95],"métaprogrammation"," y est monnaie courante, et l’IDE lui-même (écrit en Smalltalk également) peut-être modifié. Ici, pas de ",[91,18003,18006],{"href":18004,"rel":18005},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FSucre_syntaxique",[95],"sucre syntaxique",", pas d’",[91,18009,18012],{"href":18010,"rel":18011},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FInstruction_conditionnelle_(programmation)",[95],"instruction conditionnelle",", mais du typage dynamique, des ",[91,18015,18018],{"href":18016,"rel":18017},"https:\u002F\u002Fwww.gnu.org\u002Fsoftware\u002Fsmalltalk\u002Fmanual-base\u002Fhtml_node\u002FBlockClosure.html",[95],"BlockClosures"," (équivalent de lambdas en Java par exemple) qui sont eux-mêmes des objets manipulables.",[19,18021,18022,18023,508,18028,18033],{},"Lionel nous fait naviguer sur des concepts simples, comme les objets ",[91,18024,18027],{"href":18025,"rel":18026},"https:\u002F\u002Fwww.gnu.org\u002Fsoftware\u002Fsmalltalk\u002Fmanual-base\u002Fhtml_node\u002FBoolean.html",[95],"Boolean",[91,18029,18032],{"href":18030,"rel":18031},"https:\u002F\u002Fwww.gnu.org\u002Fsoftware\u002Fsmalltalk\u002Fmanual-base\u002Fhtml_node\u002FMessageNotUnderstood.html",[95],"MessageNotUnderstood"," (erreur de fonction introuvable). Etant des objets comme les autres, tous deux pouvant être également réécrits  !",[19,18035,18036,18037,18042,18043,508,18046,44],{},"La notion de test n’est pas présente à cette époque, mais il est quand même possible d’y faire une sorte de TDD. Smalltalk s’écrit en ",[91,18038,18041],{"href":18039,"rel":18040},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FApproches_ascendante_et_descendante",[95],"top-down"," et avec une approche très itérative en ",[1620,18044,18045],{},"baby steps",[1620,18047,18048],{},"red\u002Fgreen\u002Frefactor",[19,18050,18051,18052,18055,18056,18059,18060,18065],{},"Il nous est montré ici à quel point Smalltalk se veut ",[1620,18053,18054],{},"simple & fluent",", se rapprochant vraiment de notions telles que le ",[1620,18057,18058],{},"clean code",". D’ailleurs, le livre ",[91,18061,18064],{"href":18062,"rel":18063},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FDesign_Patterns",[95],"Design Patterns"," de 1994 donne des exemples en Smalltalk.",[19,18067,18068],{},"En conclusion, nous pouvons effectivement faire un parallèle entre les années 70 et maintenant. Beaucoup de concepts qui nous semblent novateurs de nos jours sont en fait tirés ou inspirés d’une époque très lointaine de la programmation. Lionel nous indique trois points qui en découlent :",[443,18070,18071,18074,18077],{},[446,18072,18073],{},"Changer l’anormal (remettre en question les choix, les paradigmes et langages utilisés)",[446,18075,18076],{},"Apprendre de tous (attention à une potentiel hiérarchie entre les développeurs)",[446,18078,18079],{},"Apprendre du passé (se baser sur toutes les connaissances du passé)",[19,18081,18082,2756,18085,18092],{},[1620,18083,18084],{},"Pour plus d’informations, voici un podcast où",[91,18086,18089],{"href":18087,"rel":18088},"https:\u002F\u002Fpodcast.ausha.co\u002Fpunkindev\u002Fs05e10-aux-origines-du-craft-et-de-tdd-smalltalk-avec-lionel-armanet",[95],[1620,18090,18091],{},"Lionel parle de Craft et de Smalltalk avec Sylvain\u002FPunkinDev",[1620,18093,44],{},[23,18095,18097],{"id":18096},"du-style-au-sein-du-craft","Du Style au sein du Craft",[19,18099,18100],{},[1620,18101,18102],{},"Par Aurélie BRACCO et Arnaud FREISMUTH",[19,18104,18105],{},[91,18106,17895],{"href":18107,"rel":18108},"https:\u002F\u002Flyon-craft.fr\u002Fsessions\u002Fdu-style-au-sein-du-craft.html",[95],[19,18110,18111],{},"Aurélie et Arnaud, tous deux développeurs front, sont venus nous parler de concepts craft… graphiques !",[19,18113,18114,18115,18120],{},"Tout d’abord, nous assistons à une présentation de plusieurs concepts bien connus des devs front, comme par exemple le ",[91,18116,18119],{"href":18117,"rel":18118},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FSyst%C3%A8me_de_design",[95],"Design System",", comprenant les blocs de construction et normes à adopter pour un projet \u002F une organisation. Les avantages : cohérence de produit et de marque, collaboration simplifiée, temps de conception diminué, et même une amélioration de l’accessibilité, dont on parlera juste après.",[19,18122,18123,18124,18127],{},"Ce Design System est composé d’un ",[1620,18125,18126],{},"styleguide",", un document qui définit des règles et bonnes pratiques. Il permet une communication visuelle cohérente à l’entreprise\u002Fau projet, et comprend également une charte éditoriale, permettant de savoir à quel public on s’adresse et comment.",[19,18129,18130,18131,18136,18137,18142,18143,18148],{},"Aurélie et Arnaud nous montrent un exemple sur ",[91,18132,18135],{"href":18133,"rel":18134},"https:\u002F\u002Fwww.figma.com\u002F",[95],"Figma",", où sont également définis les couleurs primaires\u002Fsecondaires et leurs teintes, la typographie, les ",[91,18138,18141],{"href":18139,"rel":18140},"https:\u002F\u002Fwww.w3schools.com\u002Fcss\u002Fcss3_borders.asp",[95],"radius",", les ",[91,18144,18147],{"href":18145,"rel":18146},"https:\u002F\u002Fwww.w3schools.com\u002Fcss\u002Fcss3_shadows.asp",[95],"shadows",", etc. qui seront utilisés sur le projet.",[19,18150,18151,18152,18157],{},"Parlons maintenant ",[91,18153,18156],{"href":18154,"rel":18155},"https:\u002F\u002Fbradfrost.com\u002Fblog\u002Fpost\u002Fatomic-web-design\u002F",[95],"Atomic Design",", ce concept structure les interfaces en composants réutilisables, des plus simples (atomes) aux plus complexes (pages), pour une conception modulaire et cohérente.",[19,18159,18160],{},[176,18161],{"alt":18162,"src":18163},"Les composants de l’Atomic Design, dans l’ordre : Atomes, Molécules, Organismes, Templates et enfin Pages","\u002Fcontent-assets\u002F2025-05-07-lyon-craft-2025-22\u002Fassets\u002Fimg4.webp",[19,18165,18166,18167,18170,18171,18174],{},"Dans cette optique, nous pouvons également ajouter la notion de ",[1620,18168,18169],{},"quarks",", encore plus petits que l’atome et inutilisables seuls (par exemple une couleur). L’ensemble de ces éléments est trouvable sur la ",[1620,18172,18173],{},"pattern library"," qu’Aurélie et Arnaud nous présentent alors.",[19,18176,18177,18178,18181],{},"Pour la suite de la démonstration, les deux développeurs nous embarquent sur la création d’un composant accordéon, que nous allons ajouter à leur ",[1620,18179,18180],{},"component library"," (regroupant et standardisant les différents composants graphiques utilisables sur le projet).",[1003,18183,18184],{},[19,18185,18186,18187,18190,18191,44],{},"💡 Si vous ne savez pas ce qu’est un accordéon, ou que vous voulez jeter un œil au ",[1620,18188,18189],{},"Système de Design"," de l’Etat, vous pouvez aller voir ",[91,18192,18195],{"href":18193,"rel":18194},"https:\u002F\u002Fwww.systeme-de-design.gouv.fr\u002Fcomposants-et-modeles\u002Fcomposants\u002Faccordeon\u002F",[95],"l’accordéon des sites gouvernementaux ici",[19,18197,18198,18199,18204,18205,18210],{},"Nous assistons donc à une démonstration sur ",[91,18200,18203],{"href":18201,"rel":18202},"https:\u002F\u002Ftikui.org\u002F",[95],"Tikui"," (projet Open Source). Cette solution s’appuie sur ",[91,18206,18209],{"href":18207,"rel":18208},"https:\u002F\u002Fpugjs.org\u002Fapi\u002Fgetting-started.html",[95],"Pug",", qui permet du templating minimaliste traduisible en HTML. L’accordéon est créé, puis ensuite un groupe d’accordéons.",[19,18212,18213,18214,18216],{},"Dans une appli Vue, on récupère ensuite tout simplement la ",[1620,18215,18173],{}," provenant de Tikui, et l’organisme “groupe d’accordéons” précédemment créé. Et nous voici avec notre composant injecté sur notre application.",[19,18218,18219,18220,18225],{},"S’en suit un focus sur l’",[91,18221,18224],{"href":18222,"rel":18223},"https:\u002F\u002Faccessibilite.numerique.gouv.fr\u002Fobligations\u002Fnotions-accessibilite-numerique\u002F",[95],"accessibilité numérique",", un élément ô combien important. Situation de handicap, connexion lente, matériel ancien ou défectueux, environnement défavorable, les problématiques potentielles d’utilisation d’un produit numérique ne manquent pas. C’est au développeur front qu’incombe la responsabilité de ne pas créer l’inaccessibilité du web.",[19,18227,18228],{},[176,18229],{"alt":18230,"src":18231},"Pourquoi l’accessibilité c’est important ? Aurélie et Arnaud nous informent sur le sujet","\u002Fcontent-assets\u002F2025-05-07-lyon-craft-2025-22\u002Fassets\u002Fimg5.webp",[19,18233,18234],{},"Quelques pistes pour améliorer l’accessibilité numérique de votre produit :",[443,18236,18237,18240,18243,18246,18249],{},[446,18238,18239],{},"conformité aux normes HTML\u002FW3C,  utilisation correcte des balises sémantiques et des attributs aria",[446,18241,18242],{},"tester la navigation clavier",[446,18244,18245],{},"tests avec lecteur d'écran",[446,18247,18248],{},"responsivité et zoom du texte jusque 200%",[446,18250,18251],{},"tests sur différents navigateurs",[19,18253,18254,18255,18260],{},"Aurélie et Arnaud font ici un test avec un lecteur d’écran. Celui-ci démontre que notre accordéon n’est pas encore accessible : le lecteur d’écran ne sait pas si celui-ci est ouvert ou fermé, ce qui n’est pas pratique. Les deux développeurs ajoutent donc l’attribut ",[91,18256,18259],{"href":18257,"rel":18258},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAccessibility\u002FARIA\u002FReference\u002FAttributes\u002Faria-expanded",[95],"aria-expanded"," pour déterminer le statut de l’accordéon, et le tour est joué !",[19,18262,18263,18264,18268,18269,2756,18272,2756,18275,18278],{},"La conclusion donnée ici est un lien avec le Craft, et notamment avec le ",[91,18265,1613],{"href":18266,"rel":18267},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FTest_driven_development",[95]," : le cycle ",[1620,18270,18271],{},"red >",[1620,18273,18274],{},"green >",[1620,18276,18277],{},"refactor"," est ici remplacé par un cycle structure (HTML) > style (CSS) > refacto (qualité, accessibilité).",[23,18280,18282,18285],{"id":18281},"conférence-dessinée-regard-scientifique-sur-lartisanat-logiciel",[355,18283,18284],{},"Conférence dessinée"," Regard scientifique sur l'artisanat logiciel",[19,18287,18288,18291,18298],{},[1620,18289,18290],{},"Par Victor LAMBRET (",[91,18292,18295],{"href":18293,"rel":18294},"https:\u002F\u002Fvlambret.github.io\u002F",[95],[1620,18296,18297],{},"boringdev.eu",[1620,18299,2418],{},[19,18301,18302],{},[91,18303,17895],{"href":18304,"rel":18305},"https:\u002F\u002Flyon-craft.fr\u002Fsessions\u002Fregard-scientifique-sur-l-artisanat-logiciel.html",[95],[19,18307,18308,18309,44],{},"En avant pour une conférence dessinée, Victor nous illustrant ses propos avec des dessins faits maison. Nous allons ici bien sûr parler de Craftsmanship, ou en français d’",[1620,18310,18311],{},"artisanat logiciel",[19,18313,18314],{},"Cet artisanat logiciel, ces concepts, méthodes et outils pour mieux faire, est-ce que cela compte réellement ? Est-ce simplement une accumulation d’effets de mode ? Ne pas faire de Craft conduit-il forcément à l’échec, est-ce si manichéen ? Pour s’en assurer, rien de mieux que de se référer aux études scientifiques.",[19,18316,18317],{},[176,18318],{"alt":18319,"src":18320},"C’est parti pour un regard scientifique sur l'artisanat logiciel, et sur les dessins de Victor","\u002Fcontent-assets\u002F2025-05-07-lyon-craft-2025-22\u002Fassets\u002Fimg6.webp",[19,18322,18323,18324,18327],{},"Par exemple, Robert C. Martin, dans son livre ",[91,18325,17909],{"href":17907,"rel":18326},[95]," (déjà cité plus haut dans cet article, décidément) nous indique que la taille des fonctions est une donnée importante pour jauger la qualité d’un code. En effet, on peut trouver cette citation dans son ouvrage :",[1003,18329,18330],{},[19,18331,18332],{},"The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.",[19,18334,18335],{},"Écrire de plus petites fonctions permettrait de simplifier la programmation. Mais est-ce aussi évident ? Dans un exemple sur du Fortran datant de 83, plus le module était grand, plus le nombre de bugs par ligne était petit, rentrant en contradiction avec Robert C. Martin.",[19,18337,18338,18339,18342,18343,18346],{},"Pour du plus récent et complet, une étude de 2016 compare deux équipes (que je nommerai ici A et B pour que ce soit plus simple). L’équipe A part avec une base de code, une équipe B avec une version “améliorée” respectant le ",[1620,18340,18341],{},"Clean Code."," Le résultat ? En moyenne, A arrive plus facilement à ajouter une fonctionnalité sur son code, B à refactorer, et des bugs furent trouvés beaucoup plus rapidement par l’équipe A. Conclusion : a priori, pas de bénéfice de ",[1620,18344,18345],{},"Clean Code"," sur la compréhension d’un code par des développeurs.",[19,18348,18349],{},[176,18350],{"alt":18351,"src":18352},"Un exemple de slide présenté par Lionel, une illustration parlante de sa conférence","\u002Fcontent-assets\u002F2025-05-07-lyon-craft-2025-22\u002Fassets\u002Fimg7.webp",[19,18354,18355,18356,18361],{},"C’est au tour du TDD de passer à la loupe de Lionel. Une première ",[91,18357,18360],{"href":18358,"rel":18359},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FM%C3%A9ta-analyse",[95],"méta-analyse"," nous indique une tendance : le TDD serait positif pour éviter\u002Fcorriger les bugs, mais en contre-partie la productivité serait impactée négativement. Mais il est compliqué de statuer de manière très claire avec les études industrielles.",[19,18363,18364],{},"IBM et Microsoft ont mené des études comparatives, sur des projets en parallèle. Une équipe utilisait le TDD, systématiquement, l’autre était un groupe contrôle. Là aussi, le temps passé était plus important du côté de l’équipe en TDD (+20% en moyenne), mais le nombre de bugs bien inférieur (de -40% à -90%).",[19,18366,18367],{},"Mais ces études ne portent pas de conclusion clair sur l’efficacité de la pratique du TDD. En effet, ces bugs auraient pu être trouvés par l’équipe de QA, et la notion de TDD dépend parfois d’une équipe, d’un projet, d’une étude à l’autre. De plus, l’échantillon est trop faible : par exemple seuls 0,8% des repos Java hébergés sur GitHub feraient du TDD.",[19,18369,18370,18371,18374,18375,18378],{},"Enfin, Lionel nous évoque une comparaison réalisée entre TDD et ITL (",[1620,18372,18373],{},"Iterative Test Last",", que l’on pourrait également qualifier de ",[1620,18376,18377],{},"reverse TDD","), dans différents contextes, qu’ils soient universitaires ou professionnels, sur des katas bien connus. Les conclusions :",[443,18380,18381,18384,18387],{},[446,18382,18383],{},"pas de grandes différences sur étudiants vs professionnels",[446,18385,18386],{},"pas de grandes différences entre les différents langages de projets",[446,18388,18389],{},"la qualité est légèrement meilleure pour l’ITL, mais pas de manière significative.",[19,18391,18392],{},"On peut en conclure que les deux sont globalement équivalents, et que la qualité vient surtout des concepts de feedback régulier, de refactoring continu, et bien sûr des tests à l’origine de ces deux méthodologies.",[19,18394,18395],{},"En conclusion du talk, Lionel nous conseille de ne pas hésiter à attaquer nos croyances. Tout dépend du contexte et des conditions des projets sur lesquels nous intervenons.",[23,18397,1528],{"id":1527},[19,18399,18400,18401,18406,18407,18412],{},"Après toutes ces conférences, j’ai eu la chance d’assister à une très intéressante ",[91,18402,18405],{"href":18403,"rel":18404},"https:\u002F\u002Flyon-craft.fr\u002Fsessions\u002Fpodcast.html",[95],"table ronde sur le sujet de l’image du Craft"," (à retrouver également en ",[91,18408,18411],{"href":18409,"rel":18410},"https:\u002F\u002Fpodcast.ausha.co\u002Fpunkindev\u002Fs05e14-liveatlyoncraft-table-ronde-sur-l-image-du-craft",[95],"podcast chez PunkinDev","), un sujet dont nous pourrons discuter à l’avenir dans un autre article.",[19,18414,18415],{},"En somme, le bilan de la journée est très positif, et j’en tire beaucoup d’informations et de réflexions sur le sujet du Software Craftsmanship. Je participerai avec plaisir à l’éventuelle prochaine édition.",[19,18417,18418,18419,18424],{},"Les conférences ont été enregistrées et sont retrouvables sur le ",[91,18420,18423],{"href":18421,"rel":18422},"https:\u002F\u002Fwww.youtube.com\u002F@softwarecrafterslyon9383",[95],"YouTube de Software Crafters Lyon",", où vous pourrez également visionner tous les talks dont je n’ai pas pu parler sur ce blog.",[19,18426,18427],{},"Merci de votre lecture et à très bientôt sur ce blog pour reparler de Craft et de plein d’autres belles choses !",{"title":350,"searchDepth":364,"depth":364,"links":18429},[18430,18431,18432,18434],{"id":17882,"depth":364,"text":17883},{"id":18096,"depth":364,"text":18097},{"id":18281,"depth":364,"text":18433},"Conférence dessinée Regard scientifique sur l'artisanat logiciel",{"id":1527,"depth":364,"text":1528},"2025-05-07T14:36:44.718Z","Cet article est la suite de [mon retour sur Lyon Craft](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2025-04-24-lyon-craft-2025-12). Dans cette première partie, nous avions couvert les talks auxquels j’ai eu la chan",{},"\u002Fblogs\u002F2025-05-07-lyon-craft-2025-22",[18440,18442,18444],{"id":1582,"name":1583,"image":18441,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466SQLTIAF2%2F20250507%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250507T143641Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjELb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJHMEUCIGaaze3jgEdj29BimvIE1eGEt4qcalirK6%2FWgg9g4VXdAiEA2s2DRTx%2FquxcccKRcDDhOWLiQThMIdIwyUz9GvfAyYIq%2FwMIXxAAGgw2Mzc0MjMxODM4MDUiDMRJa%2BxwLownPoG3IyrcA5%2Bszya42miksRJHP6y%2FlvJP9Rckvb5%2BAI1jicKYgmFdOENO%2FfizcRhBrvXjTkyrFKvWZBnN21gnYEGSq5jNjn34c2tdyizCbgS2o4Iu5WcPjpIJL55qIf6%2F2gULe1cRqIOuJ48rDbjX6TePNNqL52G1RRw3Ay3HhnBPfzxTQRnywmDA12ehDGZiszlILVE%2FyYSOV%2FYpd2029bYw9J2bBwctBVGUnSSQ22ofy3DedPAvR7p%2BkMaU09Z5tXNMDsNubkoqZoIc7xFgPy99eOwKHTOVnct0Yf5wPjZM4X%2FcJNk8dw1yh%2FBhkemS2jIEghRtNYYdZqFivTr6TUG12UqCaOIQRGj8GQvnZh3auvGy3OcRU%2F5m1CF9vpAVsW04H%2BwNJMZ6YOmLdwZDYaA7lS4EBrxcb2RCqqRhlgrzEJGR9F0Y0cfGYisH7X4gc7VScJfL82YLsWpZb6UfTMbasF2M6YN4xvJDk%2FDg%2FqsVrPwijuPQ%2FoQJueDdvcN9cxtB2P14rg%2B62hE9ATlJgHe23%2F5rFMUJEDnUPdW3N%2FSjMA01k0MNzm7GugUpCAM0LsEDQkThSwrtHiKKHYWR%2Fh86O7GOdVSHEPgkU29d7%2BtWhX0XWcCK651XvFE9%2FTCg%2B8xSMP%2FN7cAGOqUB4jy0APhdW%2BErX1PpMP0PXNeaUNivHk%2Bm2MRgonNUbdLTSBS3nTkOYx6k6KwlMCi0WF6pf7Lvtmd%2FPlxjoeMEjA5FCC8ssMZFNGE6RrzrrUkUUzi96xWge5H8ZGgwlLwecYDKzalplbbZY0VifoILWWwGrsM%2BvOjv5Q8Pvom5AE85Umx%2BSyZZHDwpM5jMghiKarsWEUX32ZWcY0Wb8dCK8EXN5PGW&X-Amz-Signature=f8d741c680fcbaa2d614ae05ccd4476c1fe5ee5d263e2526fe8c7d933f245601&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":5813,"name":5814,"image":18443,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466USHIWH35%2F20250507%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250507T143644Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjELb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJHMEUCIQDI6VFScPT%2BI3I6BD536jpkQPrkeA%2BbPftds4nXdYDgjgIgPnZIPY%2FRgFHtx1tcrXyCWcijN%2FFaO7jtsforzr15Tq4q%2FwMIXxAAGgw2Mzc0MjMxODM4MDUiDCZO8N8P2NAfXTTDOSrcA%2FgkSBnN9EE62zrEPz657yafi0ZOaY5w7xj9f8rGGjDsXVnhiXFe0mwQ9cwejPEnf7A2uTaxdpAnYF%2FXX6C7KgJWAGrtUdb8e6nBQ8w06SJZE1m%2FYzGoeJ4AlWoyZdCK214swZe2daBed6TndMX%2B9zEeoc2nhcIVejUe2ZkLgM8ueR6lVdQtSPthOqecKCOokepMclEaeWdimnZm60VNvco5NT%2BTKUPnxLZjnDpEw6tuTpiLmIICsn%2BnCAfmFU8qXIywCkiyeTHv68Q4lNSqnOruxJnHlaKITMNrePffyviFjY4vMjNazpeFsHbErK%2FilGDyFc7VPH6OyW6IXDJO4M%2BkcBQFhJOy31HlT5Ror3DVIQhtTgCn4vZJKPFRG4mba%2FfizDKlQhAuapwpyPn45L8ju8C4g3OWI%2FCFI5woHaThZJjI%2B7uaD%2F7GzR9%2F66RiErJkGLwbWUY9SIPZFSSA04Et%2BJhX6XGvsjQZ5G5sbR32NL22w4kHGlSwC3cfD8m93L%2FP0uWQyybqRMdaAJqWoMfWzpfnemeQT%2Fd1BTNhVNUyYQreKsKJ99WeK0lDLIMydzExOrMiM%2BfedIYH2kmaVUIMjrW4jf5%2BOrFnWS1XIIZzD6BlR4R5hYwvpBskMI3O7cAGOqUBifel974t2leDwzdqu4SDnKsVyHpK9w7r4RvRWXIbc67J2doJg4W%2FcIEpa1yC%2BO7kw07Ee7rVvRWZQeNliCmms4vMYWDaxLkAjAr4WGRnDN7KRdGakXMlbDBwnO34q6vBy5JJf3b1cGjN1xNgjF1B58IkhScl5hVaI3jDRKFIsUh5vs8DZI%2Fa6XO9rO5MhddzyPKFrnt1efUcDC%2FKaA1mSrxDGbAy&X-Amz-Signature=6a4d4c88d15a7eb01702572dbf16211e542898d3fb8f8cdddf194730c044939d&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":10,"name":11,"image":18445,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4665EYDPHT7%2F20250507%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250507T143641Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjELb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJGMEQCIG0EXEyE1pXT6gi9pnqyvkaP8ZxWWRsKmmOieqQiOHpXAiBKg9dgfHm%2BShieFhmyoH%2F2CAADimVSzT3SNmH1o6t0nCr%2FAwhfEAAaDDYzNzQyMzE4MzgwNSIMzTls379yYnws2GePKtwDQ1bS97UeqDzfoF7q%2F7fjhOaJXQ2NqAEHJioVxoHnyN%2F%2BnS85XI0dj1tu0kwUJBDi%2FoVmzKyEhPx0gmwXsGikV7IwoH1vhtbqoyMdZwT7RI2bRS1g8KwZfBx%2FqHpP4z%2Fav1cr9td4ygCOfTcFygVGglIc%2FHoJ9CYzgHyM084pGxGCE1fXi7sXvEhdYSbtoqt1UdcD4C%2FyHIa6V1Xhqy0Uets3uzVTRmBCngj0JCtCsLFPY97Xyo%2BuOzzdlvKSun5VSusI%2BbB%2BoG8X%2F3wB0z58dzt%2F5qvSP21DgQFvWTGMe9qY6oCEOX7G8njBPb7JXZfKvdU91RLKV31auGh4WjvgZ620afFU43C4cxE6PEBOrMfs9Yt8d%2FRNu6%2FeI%2Beh9NwuDJUA1WXyvQvpKfhy0FtcZVqAu%2Fo6Hp%2FD50CDjrJivs8vDzlbWIwlf5IIWdbiKWKfNENreGxD4mo%2Fgn6VogkX6UdszuP4XiI%2FixQ4TZbUOfyZeS6OuvvOXUjiC384%2BCa3Bw3ZIpBxzy3B8cnNG7Jkzq77IjoyRJbc1jhjNaTXVRnnXH3Hznqc9FKQmNLhbg7hEbkIo6GReGjIfC9AZIr7Z3%2BPXk15vUbHjQQbICCrufGfBjmn54%2BG3OrlnCswh87twAY6pgHqm6aayYs46ytFdEbIoqMt%2Buk5pDL85bLMuJuk%2FQnuhd96b95P1xAv4Pu3vtI1osrfD115iKvRbomJyU1Gl3S7SwfFe0mv1c%2FoyEgZiIpCVvI8WzhO5Z9hxUPe8FQALuJu12GBhoQdagyFQvf9Ht1lbftfj00ZJv7ynG4I%2FaDZSd38eBp1M0ygI8wwDDyYlJ8zLYf0DHq4XHAiPSSPLYsEVjKOKVRE&X-Amz-Signature=b8109bc670122dbf25b92481a5b8841c12310f13099ec289ec98af779f14726b&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":17866,"description":18436},"blogs\u002F2025-05-07-lyon-craft-2025-22\u002Findex",[6607,6608,1879],"JGNL2uMKCOn8AXAh_6F39Jmwbc8A14_BylccDlX37AY",{"id":18451,"title":18452,"alt":18453,"authors":18454,"body":18456,"date":18852,"description":18853,"extension":890,"image":891,"meta":18854,"navigation":893,"ogImage":891,"path":18855,"published":893,"reviewers":18856,"seo":18866,"stem":18867,"tags":18868,"__hash__":18869},"blogs\u002Fblogs\u002F2025-04-24-lyon-craft-2025-12\u002Findex.md","Lyon Craft 2025 1\u002F2","Photo de l’écran d’accueil au Lyon Craft 2025, présentant la liste des sessions prévues ainsi que le plan des lieux.",[18455],{"id":1577,"name":1578,"image":1600,"linkedin":1580,"x":901},{"type":16,"value":18457,"toc":18845},[18458,18464,18476,18479,18483,18488,18494,18497,18500,18503,18529,18532,18549,18560,18567,18573,18576,18579,18590,18596,18600,18605,18611,18614,18617,18625,18633,18643,18649,18657,18660,18669,18672,18705,18708,18719,18722,18735,18741,18748,18753,18759,18772,18775,18783,18786,18789,18826,18829,18835,18839,18842],[19,18459,18460,18461],{},"Retour sur la conférence Lyon Craft 2025 qui s’est déroulée le lundi 14 Avril 2025. Au programme, comme l’indique la conférence elle-même : “",[34,18462,18463],{},"Des passionné·e·s, des ateliers, des présentations et… c’est déjà pas mal !”",[19,18465,18466,18467,18471,18472,18475],{},"Une journée sur le thème du ",[91,18468,5670],{"href":18469,"rel":18470},"https:\u002F\u002Fmanifesto.softwarecraftsmanship.org\u002F",[95]," donc, dans l’optique d’apprendre ou de se perfectionner dans ces thématiques avec des experts locaux. Après une séquence d’introduction et de remerciement des sponsors (dont ",[91,18473,1836],{"href":1834,"rel":18474},[95]," qui était VIP), une vingtaine de sessions, couvrant talks et workshops (et même une table ronde) étaient proposées.",[19,18477,18478],{},"Je vous propose de revenir avec moi sur les sessions auxquelles j’ai assisté, en commençant dans cet article par celles du matin.",[23,18480,18482],{"id":18481},"ia-générative-tdd-et-architecture-hexagonale-une-synergie-révolutionnaire","IA Générative, TDD et Architecture Hexagonale : Une Synergie Révolutionnaire ?",[19,18484,18485],{},[1620,18486,18487],{},"Par Florine CHEVRIER et Clément VIRIEUX",[19,18489,18490],{},[91,18491,17895],{"href":18492,"rel":18493},"https:\u002F\u002Flyon-craft.fr\u002Fsessions\u002Fia-generative-et-architecture-hexagonale-une-synergie-revolutionnaire.html",[95],[19,18495,18496],{},"Pour bien démarrer la journée, Florine et Clément nous proposent de réaliser un kata avec l’IA. Nous sommes donc directement plongés dans les sujets en vogue du moment.",[19,18498,18499],{},"L’idée ici : faire du TDD avec une IA en lui fournissant les éléments nécessaires pour développer une nouvelle fonctionnalité dans un projet front. Le contexte : nous avons une application bancaire très simple, et nous souhaitons mettre en place une fonctionnalité “nouveau virement” avec un bouton dédié.",[19,18501,18502],{},"Pour ce faire, trois outils seront utilisés ici :",[443,18504,18505,18513,18521],{},[446,18506,18507,18512],{},[91,18508,18511],{"href":18509,"rel":18510},"https:\u002F\u002Fgithub.com\u002Fcline\u002Fcline",[95],"Cline",", un agent IA qui vient s’intégrer à Visual Studio Code",[446,18514,18515,18520],{},[91,18516,18519],{"href":18517,"rel":18518},"https:\u002F\u002Fwww.anthropic.com\u002Fclaude\u002Fsonnet",[95],"Claude 3.7 Sonnet ",", l’IA spécialisée dans le codage derrière Cline",[446,18522,18523,18528],{},[91,18524,18527],{"href":18525,"rel":18526},"https:\u002F\u002Fopenrouter.ai\u002F",[95],"Open Router",", pour pouvoir switcher d’IA et être à l’état de l’art ou contrôler les coûts",[19,18530,18531],{},"À présent, comment communiquer avec cette IA ? Pour développer, elle va se baser sur un prompt indiquant :",[443,18533,18534,18543,18546],{},[446,18535,18536,18537,18542],{},"Des contraintes d’architecture, sous forme de tests. Nous souhaitons ici obliger l’IA à suivre une ",[91,18538,18541],{"href":18539,"rel":18540},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FArchitecture_hexagonale",[95],"architecture hexagonale"," déjà en place",[446,18544,18545],{},"Une capture d’écran d’une maquette Figma faite par un UX\u002FUI",[446,18547,18548],{},"Des tests Cypress, pour définir les règles de gestion fonctionnelles, et qui seront à la base de notre TDD. À noter que ces tests auraient été rédigés également pour un développement par un humain",[19,18550,18551,18552,18555,18556,18559],{},"Cline va ainsi d’abord passer une première phase ",[34,18553,18554],{},"PLAN",", pour indiquer ce qu’elle souhaite mettre en place, ainsi qu’une estimation des coûts de l’API. C’est une sorte de dry run si l’on veut. Ensuite, il sera temps de passer à la seconde phase ",[34,18557,18558],{},"ACT",", où l’IA va réellement coder pour nous.",[19,18561,18562,18563,18566],{},"À noter que Cline peut apprendre de ses erreurs. De nouvelles règles sont ajoutées au fur et à mesure dans un fichier ",[1620,18564,18565],{},".clinerules",", un fichier texte lisible également par l’humain. Ici, ce sont les développeurs qui demandent à Cline de les ajouter quand ils sont confrontés à une erreur de l’IA.",[19,18568,18569],{},[176,18570],{"alt":18571,"src":18572},"Cline sur le Marketplace Visual Studio Code","\u002Fcontent-assets\u002F2025-04-24-lyon-craft-2025-12\u002Fassets\u002Fimg1.webp",[19,18574,18575],{},"Revenons à notre démonstration. Nous sommes ici plus sûr du test-first que sur du TDD en réalité, mais l’IA traite le prompt. Surprise (effet démo), Cline oublie lors de la présentation d’ajouter le bouton alors qu’il a développé la fonctionnalité. Les tests Cypress ne passent pas. Au deuxième essai, plus de problème, l’IA se base sur ce qu’elle peut lire dans le terminal, et est satisfaite de son travail : les tests Cypress passent. Effectivement, le bouton et la fonctionnalité sont présents et correspondent à l’attendu.(",[19,18577,18578],{},"Maintenant, Florine et Clément demandent à l’IA de développer la suite de la fonctionnalité : le formulaire du virement. Même principe : tests Cypress correspondants + capture d’écran en maquette. Les fonctionnalités sont présentes et tout fonctionne, le respect de la maquette est par contre très approximative, une problématique a priori très présente avec ce genre d’outils.",[19,18580,18581,18582,18585,18586,18589],{},"C’est d’ailleurs un bon point de ce talk, nos deux speakers restent critiques par rapport aux outils d’IA qu’ils utilisent. La démonstration est bluffante de rapidité, l’API de l’IA n’a coûté que 1,5$ pour cette démo. Mais le code, bien que répondant aux critères évoqués, n’est pas à la qualité d’un bon développeur humain. D’ailleurs, au quotidien, l’équipe laissent à Cline les droits de lecture, mais l’écriture passe par une validation manuelle. Et il y a d’autres subtilités à connaître qui viennent avec l’expérience de l’outil (",[1620,18583,18584],{},"clinerules",", mauvaise gestion des erreurs, erreurs de compréhension de la maquette, gestion de la ",[1620,18587,18588],{},"context window",", etc.).",[19,18591,18592],{},[176,18593],{"alt":18594,"src":18595},"Florine explique les informations que Clément est en train de donner à l’IA","\u002Fcontent-assets\u002F2025-04-24-lyon-craft-2025-12\u002Fassets\u002Fimg2.webp",[23,18597,18599],{"id":18598},"the-choice-must-go-on-mais-le-bon-de-préférence","The choice must go on, mais le bon de préférence",[19,18601,18602],{},[1620,18603,18604],{},"Par Céline LOUVET",[19,18606,18607],{},[91,18608,17895],{"href":18609,"rel":18610},"https:\u002F\u002Flyon-craft.fr\u002Fsessions\u002Fthe-choice-must-go-on.html",[95],[19,18612,18613],{},"Un sujet qui a été, est et sera toujours d’une importance capitale pour un projet, quelque soit le domaine : comment faire le bon (ou le moins pire) choix pour un projet ?",[19,18615,18616],{},"Tout d’abord, Céline nous confie la définition du projet réussi. Pour les décideurs, le respect du budget, du délai et la satisfaction utilisateur sont les principales métriques permettant de jauger la réussite du projet. À cela viennent s’ajouter, concernant les développeurs, leur bien-être et la maintenabilité du projet.",[19,18618,18619,18620,1513],{},"Viennent ensuite quelques chiffres issus du ",[91,18621,18624],{"href":18622,"rel":18623},"https:\u002F\u002Ffile.notion.so\u002Ff\u002Ff\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fce54b1c6-d205-4f58-b57c-a0c9c377767e\u002FCHAOSReport2015_rev.pdf?table=block&id=1dcf4462-cd38-80cf-9017-e873e03fa39b&spaceId=5863e833-64f2-4f13-9f7a-2c92c72b5bbf&expirationTimestamp=1745280000000&signature=PgRSPuAWReZL_sg2opmSPe1NqAHZsjtjcJLHQEb-fs4&downloadName=CHAOSReport2015_rev.pdf",[95],"CHAOS report",[443,18626,18627,18630],{},[446,18628,18629],{},"Le budget est respecté à 44%, le délai à 40%, le périmètre à 56%",[446,18631,18632],{},"Les projets réussissent à 36%, sont en difficulté à 45% et échouent à 19%",[19,18634,18635,18636,18639,18640,44],{},"10 facteurs de mise en difficulté sont ainsi identifiés, dont on ressortira par exemple les ",[34,18637,18638],{},"besoins flous",", et le ",[34,18641,18642],{},"choix de technologies non maîtrisées",[19,18644,18645],{},[176,18646],{"alt":18647,"src":18648},"Les 10 facteurs de mise en difficulté identifiés pour un projet","\u002Fcontent-assets\u002F2025-04-24-lyon-craft-2025-12\u002Fassets\u002Fimg3.webp",[19,18650,18651,18652,44],{},"Première piste pour expliquer ces problématiques, les besoins flous. Se basant sur une expérience personnelle, Céline nous évoque un cas courant : l’expression d'une solution à la place du besoin. Comment s’en sortir dans ce cas ? En utilisant par exemple la fameuse technique des ",[91,18653,18656],{"href":18654,"rel":18655},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FCinq_pourquoi",[95],"cinq pourquoi",[19,18658,18659],{},"Ainsi, la demande “j’ai besoin d’un bouton pour télécharger un CSV” est devenue une page web dynamique avec des données financières et un envoi de mail avec cette même page en lien.",[19,18661,18662,18663,18668],{},"Également, attention à ne pas créer de faux besoins (",[91,18664,18667],{"href":18665,"rel":18666},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FProbl%C3%A8me_XY",[95],"Problème XY","), à identifier l’inconnu (ce qui manque de clarté) et à se concentrer sur le futur proche (plus on anticipe, plus c’est flou).",[19,18670,18671],{},"On se concentre ainsi sur la valeur à apporter, avec des critères d’acceptation par exemple, et on identifie ainsi les objectifs à atteindre tout en prenant compte des contraintes impossibles à ignorer (budget, temps, réglementation, etc.).",[19,18673,18674,18675,18678,18679,18684,18685,18690,18691,18694,18701,18704],{},"Il faut connaître l’existant (technologies, équipe, méthodes, dettes, etc.), et mettre par exemple en place un ",[1620,18676,18677],{},"tech radar",", comme celui de ",[91,18680,18683],{"href":18681,"rel":18682},"https:\u002F\u002Fopensource.zalando.com\u002Ftech-radar\u002F",[95],"Zalando par exemple",". De même, on pourra mettre en place des ",[91,18686,18689],{"href":18687,"rel":18688},"https:\u002F\u002Fwww.redhat.com\u002Ffr\u002Ftopics\u002Fdevops\u002Fgolden-paths",[95],"golden paths"," pour répondre aux besoins les plus communs. Gardons en tête, comme Céline nous le répétera tout au long de son talk, qu’il n’y a pas de ",[1620,18692,18693],{},"silver bullet (”",[91,18695,18698],{"href":18696,"rel":18697},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FPas_de_balle_en_argent",[95],[1620,18699,18700],{},"No Silver Bullet",[1620,18702,18703],{},"”)",", c’est-à-dire pas de solution miracle.",[19,18706,18707],{},"Trois complexités sont ici représentées :",[443,18709,18710,18713,18716],{},[446,18711,18712],{},"Essentielle, ce qui a trait au problème à résoudre",[446,18714,18715],{},"Obligatoire, liée à la technologie (et donc à un choix)",[446,18717,18718],{},"Accidentelle, liée à de mauvaises décisions (et donc à un choix)",[19,18720,18721],{},"Nous avons la main sur les deux dernières, qu’il nous faudra viser à réduire.",[19,18723,18724,18725,18728,18729,18734],{},"Un conseil : tous les choix devraient être tracés dans des ",[1620,18726,18727],{},"decisions records"," (comme les ",[91,18730,18733],{"href":18731,"rel":18732},"https:\u002F\u002Fadr.github.io\u002F",[95],"ADR par exemple",") pour y expliquer les raisons du choix, et capitaliser sur ces décisions.",[19,18736,18737],{},[176,18738],{"alt":18739,"src":18740},"La slide la plus utilisée lors de cette conférence : pas de “silver bullet”, c’est-à-dire pas de solution miracle","\u002Fcontent-assets\u002F2025-04-24-lyon-craft-2025-12\u002Fassets\u002Fimg4.webp",[23,18742,18744,18747],{"id":18743},"rex-le-craft-en-startup",[355,18745,18746],{},"REX"," Le craft en startup",[19,18749,18750],{},[1620,18751,18752],{},"Par Anne JACQUET et Philippe LEBOC",[19,18754,18755],{},[91,18756,17895],{"href":18757,"rel":18758},"https:\u002F\u002Flyon-craft.fr\u002Fsessions\u002Frex-le-craft-en-startup.html",[95],[19,18760,18761,18762,18767,18768,18771],{},"Anne et Philippe travaillent actuellement dans la start-up ",[91,18763,18766],{"href":18764,"rel":18765},"https:\u002F\u002Fwww.auxodynamics.com\u002F",[95],"Auxo",", fondée il y a quasiment deux ans (à peine moins âgée que ",[91,18769,1836],{"href":1834,"rel":18770},[95],"). Le produit proposé accompagne la transformation durable des entreprises, à partir de leurs données financières et opérationnelles. L’équipe technique se compose d’une dizaine de personnes développant le produit. Les technologies employées : Java \u002F SpringBoot, Vue.js et AWS.",[19,18773,18774],{},"Nos deux speakers sont les deux développeurs backend de l’équipe. Ils commencent par nous faire un rappel de certains concepts :",[443,18776,18777,18780],{},[446,18778,18779],{},"Monolithe \u002F Monolithe distribué \u002F Microservices \u002F Nanoservices",[446,18781,18782],{},"Synchrone \u002F Asynchrone",[19,18784,18785],{},"La solution technique est ici partie sur des microservices asynchrones, qui échangent des messages via Kafka. Mais un des microservices a ensuite nécessité des appels synchrones, nous sommes donc ici sur un mix des deux. Les microservices partagent tous une “shared library” commune, contenant de la configuration, des briques techniques, des concepts métier partagés, etc.",[19,18787,18788],{},"Nous passons ensuite en revue de nombreux concepts mis en place sur leur produit, dont certains biens connus des crafteurs :",[443,18790,18791,18794,18803,18806,18812,18815,18818],{},[446,18792,18793],{},"Architecture hexagonale",[446,18795,18796,18797,18802],{},"Pyramide de tests : Unitaire > Intégration > Comportement (",[91,18798,18801],{"href":18799,"rel":18800},"https:\u002F\u002Fcucumber.io\u002F",[95],"Cucumber",") > End-to-end",[446,18804,18805],{},"Respect des principes REST (PUT vs PATCH par ex.) et comment cela est mis en place (idempotence, pagination, etc.)",[446,18807,18808,18811],{},[91,18809,542],{"href":538,"rel":18810},[95],", contrats entre front et back",[446,18813,18814],{},"Assertions dans le domaine, exceptions dans le domaine traduites ensuite et renvoyant un statut HTTP adéquat",[446,18816,18817],{},"Annotations Java pour valider request body, query parameters et path parameters",[446,18819,18820,18825],{},[91,18821,18824],{"href":18822,"rel":18823},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FOptimistic_concurrency_control",[95],"Optimistic lock"," pour des questions de performance",[19,18827,18828],{},"Au final, Anne et Philippe font ici un tour complet de tout ce qui a été mis en place pour assurer la qualité du produit et de son implémentation technique. On voit ici que tout ce qui a été mis en place l’a été pour une bonne raison. Ces conseils ne sont d’ailleurs pas spécifiques à un contexte de startup.",[19,18830,18831],{},[176,18832],{"alt":18833,"src":18834},"Fin de conférence pour Anne et Philippe","\u002Fcontent-assets\u002F2025-04-24-lyon-craft-2025-12\u002Fassets\u002Fimg5.webp",[23,18836,18838],{"id":18837},"fin-de-cette-matinée","Fin de cette matinée",[19,18840,18841],{},"Après cette belle matinée et tous ces concepts craft abordés, la faim se fait sentir, et il est temps pour tout le monde de profiter d’un déjeuner bien mérité.",[19,18843,18844],{},"Je vous propose de continuer ce retour de conférence dans un second article à paraître, où nous parlerons front, regard scientifique et… Smalltalk !",{"title":350,"searchDepth":364,"depth":364,"links":18846},[18847,18848,18849,18851],{"id":18481,"depth":364,"text":18482},{"id":18598,"depth":364,"text":18599},{"id":18743,"depth":364,"text":18850},"REX Le craft en startup",{"id":18837,"depth":364,"text":18838},"2025-04-24T14:50:16.697Z","Retour sur la conférence Lyon Craft 2025 qui s’est déroulée le lundi 14 Avril 2025. Au programme, comme l’indique la conférence elle-même : “**Des passionné·e·s, des ateliers, des présentations et… c’",{},"\u002Fblogs\u002F2025-04-24-lyon-craft-2025-12",[18857,18859,18861],{"id":1582,"name":1583,"image":18858,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466ZZP3LNIZ%2F20250424%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250424T145016Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEH8aCXVzLXdlc3QtMiJGMEQCIAD4hutXa0ml3Y8EZ316barAph9dGk3IRKbBJ6H2NPkkAiAdQG9T0owlAUFInwuzoMAQM01j1NtLiiZG2jW%2FT%2FjX9Sr%2FAwgYEAAaDDYzNzQyMzE4MzgwNSIMTN%2FWccyZZyqeFjXDKtwD7likSB1JMnGkfv56Ja%2BDQbgTvr%2FuJpffy5MHg%2BJJ%2BVxIrE8T7Zw7%2BvvkaExh1fWWPq67xJJ0DJDM%2Ft9Www2JFLzAGwhWQRoTTDxSWuHpSpf6kwgapJaMIAA%2FclFRJnE%2FHc3xXXWWELIAgjzltcVwh5cbNj8JI5Qp3gDQztRRhTnx7%2B0demwgkRXJMsTvGl37RLwMb29yHrc3yR6JnZOKM9T25ZXu95SRD9xAmJkCp209j5R04n0Yjy0QJ7Sni32FBwcRJhh6Wg1e2Kyk80QnjAQ7lNCH6EoRDSV8Fe%2FH3ZKYqFdDNa5lEUwIOt7SnGG%2FGtQu2kIlEb%2FS0SgpQBKpGtuDPe7G%2F3sQ2pI8NLWlUqEfikpjbDnR3OINc7Gz3lxesdG9U6YBSK%2F25acDDqAgrv7KtTidxsXrLao8hWQ38TEpwQQSicWbPT1yM3bIZbnPNOy9Bt2qCfA0q60kftPkXY2g5Lo6HrMP1zWlYV2FRxivvTHB5q%2FYBPLz0%2FqsN3b5gGo8kcQUso9UP4toIrOUjXDXUX28ntdwfdHzDltQAmuPUmPNiVjPcCBRItdwRVXUdtEBIalb3JDRTk1YDxz7PIOCQsLGq2IvdfqryYvGXGfIe5R%2FD0wSqVzRjLowpJ6pwAY6pgEgu8gqJrHbvb0l%2B2yitK%2FU094ki4AwNAQuta9J%2BzV%2BzNuwqbK%2F44yu4xRTm5GmLX20gbrkJdK1hmfEQ6Yvq0gfsLRcah%2F5nVaybYz4ggsj4RjepHqij2rdOpB%2B9mDEVs2hzbADQQSC%2B2Xa8Ial%2BLh0RvQv%2FnGulFlegFMIg%2BewQwGSHiAjqGXjZFix8O5Kep53wEA8nmg8sXPTkR6XCqygwwUJAItM&X-Amz-Signature=ea9ad56797425f78e31cddc4a233f3fb6f6a3d762a4de2d79c59c807a7fd2c48&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":5813,"name":5814,"image":18860,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466ZQTQSD5B%2F20250424%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250424T145016Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEH4aCXVzLXdlc3QtMiJIMEYCIQDbg0WLCaqDYBaT5EAm90fC9VoyYCY744P%2B1c3G4qB%2ByQIhAM36Uk9ob7vyZOspNUFT728A6IE7FMyTluR9N6yZIWZNKv8DCBcQABoMNjM3NDIzMTgzODA1IgxwBrjSMTqOr1iBNTkq3AOkQ79%2BucvRaAFugoBvlSJSfacPAIgOWapcuAgBDgIZ8t6ucyaNiHnoN8RJQf%2FsUFXbmNZOi7QsD%2F8kn5fpfedw%2BDrtUHhOgSREmYFSeYUX4j0gKDARi4R7gJVa0atIUnSEiqXcpxljIGEaJlhVpuZu3cI6TdRRCvBO%2FkHFnh%2FMsWBA23IGHMJ1wzVZP23rwOcU%2BPb6Fee4AN6y%2BmxJuv6KGk6745C65PQvJrhBonJ1xHYywuFqr2GgYXuUPB7csZ%2FzzYo%2BA0xYXIhkf5qETQqYXwbGBDxJDT5xYyZiqiGr7xhtPRrKb%2F0eJfdUoBXTNr3alIIexaZ2j%2FUk9WREQBtyRuvZxJfIBz053pG2%2FzII6mFzE7T5PeuhfeYG6bSYiVOV3RYhueioXzukCtuBDzv0U9nT5i98QQZd2HX7rGlFW8gU3BiEwCYLP0A4yVuckpgFKy5bzU3ri9BrDBxBUhZtDdl%2FQAvibikqUv5xqK9DbYuE7UzzF7x1B%2FCjIGdRT648ftoW22ktXjYNMygX5URd8CHEJFTgCpXUqGF3MVgCRZ%2F%2FeWK6dV9h7ZoeXiGpPnHsZf8ikcN2JR5PQsF3roTMauTBpbHak62F14FkazBMpu0IPYpdUacDvOCZ1jDGgqnABjqkAZeHxXrKXw%2FyxBY0qW0PJk%2Fqwy%2FzyEtCN3aab7YFWGbU1XZ7wZg1wMEmfandoQ%2FF9QDrKfu6vDxaWidbSI%2Bqhc9%2BxMtpFIp8mwOXqFBUJyQedEzox0S20vcgrYK7yS%2BNppUdMCz1QWCmd8RAB3PZHWVDw6FxvJE5ObD14am0QJf3JYZDzVfvLjKSL8dbXCpHRZ8Lh7bP3AHjubFmBqIKqx9hjJJs&X-Amz-Signature=4b999cb952cb26fd3de1e914824e91a2eb46e1bf095d9dc88f2a653b3c2f1104&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":18862,"name":18863,"image":18864,"linkedin":18865,"x":901},"4f37105b-9f64-4dcc-8a19-a1f4d5489826","Samuel Bally","https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fb8425b05-a0a4-4560-964d-259e8a84c063\u002Fsamuel.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB4662CQLWNJA%2F20250424%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250424T145016Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEH4aCXVzLXdlc3QtMiJIMEYCIQCmhL9dbISruox6fMvLj6hlUJwDL2RNROCNk%2BRnyXewpAIhAPIZL8fOAQYfTbrQhTi1roY4yx9Y4wlxLIexFvMQ8SxfKv8DCBcQABoMNjM3NDIzMTgzODA1IgxKEHa2%2BtpiCyu7zb4q3ANQvi91jPvQtMl6sDwBYHgyOYunstmWOnOtycBpk8d2NIALAsY8hqSc5vdD2oApdfs%2BUQIHYZQ1qEm2OyVx7UYR6O4ftWad0slO4MKujNa3%2BQzNSa24AWMSWQEnvvtwFi8Rd0I9Q8dD8xmROSgGgJbKYxkU96LJg25t4uKHYUyTlZ1F6jkIV9PtKWMLJ0XM7fVrDrHObwgND4g3ngRTArfVxNR3LaIvoNHvHuOkduBpf%2F0uzIE6glxdSb0wzTW74DZUTv%2F68rI%2Fnw6ePZRTJTYmFk0fxy%2BifaPRO7%2B9CjT2eA4xak9ibyRakRnoxJI%2Fkwe6FctuAYBzsttofBD8eQREOxcp%2BqesuA4KkHUIe9oR4%2FOV8GD9vBX3xtpZcodp97CvsECaxbBmVRVhBLna4I7MZcc7ISurFOEBh3JM1%2FHdVvcXrkWMZXcsYnvMtonQRbXx0jp4gy3J0NigBQDYvUQZV6%2F7TTqpIhCig%2Fzc0UCn3kQp8jTn%2FJQFnZ0KkTDPIiEyKDixz42R%2B5uTU2bWP8CmnQST2BIl2yoxVeUMZJkyaG7Q6pA%2Bvm3gFjJubT11CeEwZckBuf%2FP1HAPkl6iKEDik4szHdjg4vI2sRvP0s8V%2BBVinUfBLcRIWCi65jDWg6nABjqkAbyEEgUPtQBKSOClV6oaBk3mWzg%2BSZcaOqklt6UcxlmfihqrfgPXbDJl0JXZkWJOPhbq8gg4sffVR9w1Sun0twXdMHAP0Ek2NyRy0PxQVgS0k1q%2FHCaUH0kPyma8c3pj96t6ckwXeXsBY%2FBYOV7Jk3FZJ6%2BrfQUitMPu2EzyziL8JenDdqjasIspgXU8X8qwMX3ZxV4TItv9BQsVYjc6j2C25O2q&X-Amz-Signature=1dab69f2b448359e58c91caae1e683bb810dc844845994020bbdd895da8d33b5&X-Amz-SignedHeaders=host&x-id=GetObject","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fsamuel-bally\u002F",{"title":18452,"description":18853},"blogs\u002F2025-04-24-lyon-craft-2025-12\u002Findex",[6607,6608,1879],"K6Kk6szdZICyofOvs45o1g8MLue3DQMf-WQkz_bx5xM",{"id":18871,"title":18872,"alt":18873,"authors":18874,"body":18877,"date":20015,"description":20016,"extension":890,"image":891,"meta":20017,"navigation":893,"ogImage":891,"path":20018,"published":893,"reviewers":20019,"seo":20024,"stem":20025,"tags":20026,"__hash__":20028},"blogs\u002Fblogs\u002F2025-04-15-dbrief-react-paris-2025\u002Findex.md","Débrief React Paris 2025","Photographie de la salle de conférence de React Paris. Le décor est luxueux mêlant moulures en bois et tons beiges pour la décoration",[18875,18876],{"id":1893,"name":1894,"image":1895,"linkedin":901,"x":901},{"id":8032,"name":8033,"image":1895,"linkedin":901,"x":901},{"type":16,"value":18878,"toc":20001},[18879,18882,18885,18888,18894,18898,18909,18915,18935,18941,18950,18976,18989,18995,19009,19018,19021,19024,19027,19043,19048,19051,19057,19062,19065,19072,19079,19108,19115,19120,19123,19187,19190,19226,19249,19253,19262,19273,19278,19281,19318,19323,19330,19341,19355,19365,19368,19396,19407,19416,19419,19424,19427,19436,19442,19445,19454,19460,19463,19466,19475,19481,19488,19493,19499,19505,19508,19511,19516,19519,19522,19563,19567,19576,19588,19591,19594,19597,19602,19608,19613,19620,19625,19628,19635,19640,19643,19646,19651,19658,19662,19668,19686,19689,19693,19702,19705,19718,19721,19726,19729,19762,19767,19770,19849,19852,19862,19865,19909,19914,19917,19920,19948,19951,19954,19958,19967,19998],[7089,18880,18872],{"id":18881},"débrief-react-paris-2025",[19,18883,18884],{},"React Paris est un événement organisé par BeJs, association d’origine belge déjà à l’origine des événements React Brussels, React Africa et BeJS Conf. BeJS a été fondée en 2019 avec pour mission de présenter des conférences JavaScript dans des régions sous-représentées comme la Tunisie et le Maroc.",[19,18886,18887],{},"React Paris, comme les autres conférences BeJs, met en avant la diversité des intervenants grâce à des appels à propositions anonymisés, avec des règles privilégiant les speakers internationaux intervenants pour la première fois tout en faisant la part belle à la représentation locale.",[19,18889,18890,18891,44],{},"En outre, les talks sponsorisés y sont interdits et sont ",[1620,18892,18893],{},"single-track",[23,18895,18897],{"id":18896},"les-speakers-et-les-sujets","Les speakers et les sujets",[19,18899,18900,18901,18904,18905,18908],{},"React Paris 2024 nous avait offert le plaisir de voir des talks de Josh W. Comeau et d’Anthony Fu. S’étalant sur deux jours, React Paris 2025 promettait de belles conférences avec notamment la participation de Kent C. Dodds, TkDodo (maintainer ",[352,18902,18903],{},"TanStack\u002Fquery",") et David Khourshid (créateur de ",[352,18906,18907],{},"XState","). En outre, des talks sur l’accessibilité (Kateryna Porshnieva), les d_esign systems_ (Yu Ling Cheng, Jean Burellier), les React Server Components (Aurora Scharff), le testing côté frontend (Violina Popova, Kate Marshalkina) mais aussi la clean architecture dans un projet Remix (Antoine Chalifour) ainsi que le rôle de l'IA dans l'écosystème React (Tejas Kumar) étaient au menu de ces deux jours.",[19,18910,18911,18912,1513],{},"La grande majorité des conférences étaient de qualité et faisaient la part belle à des sujets et des approches variés. Pour cette année, nous vous proposons d’entrer dans le détail de quelques conférences relatives à l’écosystème front ",[1620,18913,18914],{},"(bien que mon cœur t’appartiendra toujours cher petit framework au logo de molécule ⚛︎)",[443,18916,18917,18920,18923,18926,18929,18932],{},[446,18918,18919],{},"les dernières nouveautés CSS",[446,18921,18922],{},"l’accessibilité",[446,18924,18925],{},"les React Server Components",[446,18927,18928],{},"la naissance d’une nouvelle stratégie de tests incluant des champignons",[446,18930,18931],{},"comment mal utiliser un framework front",[446,18933,18934],{},"les mathématiques à la rescousse des développeurs front",[23,18936,18938],{"id":18937},"csss-not-dead",[34,18939,18940],{},"CSS’s not dead",[19,18942,18943],{},[91,18944,18947],{"href":18945,"rel":18946},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=h_tMtyvVPY0",[95],[1620,18948,18949],{},"I Can’t Believe It’s Not JavaScript",[19,18951,18952,18953,18958,18959,18958,18964,18969,18970,18975],{},"Depuis quelques années les conférences mettant en avant les nouvelles fonctionnalités CSS fleurissent. Jemima Abu revient dans son talk sur quelques unes de ces avancées qui permettront, quand la feature ne sera pas disponible depuis seulement 3 mois ou expérimentale, d’implémenter des ",[91,18954,18957],{"href":18955,"rel":18956},"https:\u002F\u002Fdeveloper.mozilla.org\u002Ffr\u002Fdocs\u002FWeb\u002FHTML\u002FGlobal_attributes\u002Fpopover",[95],"pop-over",", des ",[91,18960,18963],{"href":18961,"rel":18962},"https:\u002F\u002Fdeveloper.mozilla.org\u002Ffr\u002Fdocs\u002FWeb\u002FHTML\u002FElement\u002Fdialog#compatibilit%C3%A9_des_navigateurs",[95],"modal",[91,18965,18968],{"href":18966,"rel":18967},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FHTML\u002FElement\u002Fsummary#browser_compatibility",[95],"accordéons"," voire des ",[91,18971,18974],{"href":18972,"rel":18973},"https:\u002F\u002Fscroll-driven-animations.style\u002F",[95],"animations de scroll"," sans avoir à écrire de JavaScript.",[19,18977,18978,18979,18984,18985,18988],{},"C’est une bonne nouvelle, les implémentations en JavaScript pour ces éléments UI étant souvent impératives et assez bancales. Heureusement, Jemina Abu nous rappelle que ",[91,18980,18983],{"href":18981,"rel":18982},"https:\u002F\u002Fdeveloper.mozilla.org\u002Ffr\u002Fdocs\u002FWeb\u002FCSS\u002F:has#compatibilit%C3%A9_des_navigateurs",[95],"dès maintenant"," il est possible d’utiliser le fantastique sélecteur CSS ",[352,18986,18987],{},":has"," pour, notamment, cibler un parent en fonction de ses enfants 🤯.",[19,18990,18991],{},[176,18992],{"alt":18993,"src":18994},"mème de la peluche Elmo en enfer disant en anglais “OMG AMAZING”","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fimg1.webp",[23,18996,18998,2756,19001,2756,19006],{"id":18997},"i-lt3-html",[34,18999,19000],{},"I",[34,19002,19003],{},[352,19004,19005],{},"&lt;3",[34,19007,19008],{},"HTML",[19,19010,19011],{},[91,19012,19015],{"href":19013,"rel":19014},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=tFO0-aMxitY",[95],[1620,19016,19017],{},"Demystifying Accessibility in React Apps",[19,19019,19020],{},"L'accessibilité est un aspect crucial du développement web moderne, garantissant que les applications peuvent être utilisées par tous, y compris les personnes en situation de handicap. L’accessibilité ça n’est pas que pour les autres, c’est aussi pour soi plus tard.",[19,19022,19023],{},"Soyons donc un peu égoïste et ne demandons pas la permission pour écrire du code accessible, après tout le faisons-nous pour écrire du code propre ?",[19,19025,19026],{},"Lors de sa conférence, Kateryna Porshnieva rappelle les outils courants utilisés par les personnes en situation de handicap (lecteurs d’écran, voice control, etc.) et présente plusieurs outils et techniques pour améliorer l'accessibilité des applications React. Elle insiste notamment sur :",[443,19028,19029,19032],{},[446,19030,19031],{},"l’importance du HTML et de sa sémantique",[446,19033,19034,19035,19038,19039,19042],{},"le recours à ",[352,19036,19037],{},"ARIA","  (",[1620,19040,19041],{},"Accessible Rich Internet Applications"," soit« un ensemble de rôles et d’attributs qui définissent comment rendre le contenu et les applications web accessibles pour les personnes avec des handicaps ») lequel peut parfois poser plus de problèmes qu’il n’en résout s’il est mal utilisé",[19,19044,19045],{},[34,19046,19047],{},"L'importance de l'HTML",[19,19049,19050],{},"Tout commence avec le HTML. La structure HTML se transforme en arbre DOM, puis en interface utilisateur visuelle. L'arbre d'accessibilité, exposé aux technologies d'assistance et accessible aux dev tools, est également créé à partir de cette structure.",[19,19052,19053],{},[176,19054],{"alt":19055,"src":19056},"Schéma avec de gauche à droite : le HTML avec une flèche pointant vers l’arbre du DOM, l’arbre du DOM avec deux flèches dont l’une pointe vers le rendu visuel et l’autre vers l’arbre d’accessibilité","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fimg2.webp",[19,19058,19059],{},[34,19060,19061],{},"Sémantique et ARIA",[19,19063,19064],{},"La sémantique HTML joue un rôle essentiel en transmettant le sens des éléments. Cependant, dans les interfaces modernes, les balises HTML peuvent ne pas suffire. La boîte à outils d’ARIA vient en aide en modifiant la signification des éléments HTML.",[19,19066,19067,19068,6636],{},"Prudence toutefois car la spécification ARIA recommande son utilisation uniquement lorsque la sémantique HTML ne permet pas de répondre à un besoin spécifique car, paradoxalement, les sites qui utilisent ARIA ont 34 % d'erreurs d'accessibilité en plus par rapport à ceux qui n'en font pas usage (",[91,19069,503],{"href":19070,"rel":19071},"https:\u002F\u002Fwebaim.org\u002Fprojects\u002Fmillion\u002F#:~:text=74.6%25%20of%20the%20one%20million%20home%20pages%20used%20ARIA%20(excluding%20ARIA%20landmark%20roles).%20Home%20pages%20with%20ARIA%20present%20averaged%2034.2%25%20more%20detected%20errors%20than%20those%20without%20ARIA",[95],[19,19073,19074,19075,19078],{},"Ainsi, transformer une ⁠",[352,19076,19077],{},"\u003Cdiv>"," en bouton en lui ajoutant le rôle adéquat :",[344,19080,19084],{"className":19081,"code":19082,"language":19083,"meta":350,"style":350},"language-html shiki shiki-themes github-dark-default","\u003Cdiv role=\"button\">click\u003C\u002Fdiv>\n","html",[352,19085,19086],{"__ignoreMap":350},[355,19087,19088,19090,19093,19096,19098,19101,19104,19106],{"class":357,"line":358},[355,19089,2826],{"class":1119},[355,19091,19092],{"class":1115},"div",[355,19094,19095],{"class":1264}," role",[355,19097,2042],{"class":1119},[355,19099,19100],{"class":1138},"\"button\"",[355,19102,19103],{"class":1119},">click\u003C\u002F",[355,19105,19092],{"class":1115},[355,19107,4808],{"class":1119},[19,19109,19110,19111,19114],{},"n’est pas une solution miracle : appliquer ⁠",[352,19112,19113],{},"role=\"button\""," à une div implique de fournir les fonctionnalités attendues d'un bouton à cet élément en plus de la simple indication de son rôle.",[19,19116,19117],{},[34,19118,19119],{},"Quelques éléments de la boîte à outils d’ARIA",[19,19121,19122],{},"Parmi les bonnes pratiques évoqués par Kateryna Porshnieva, on compte :",[443,19124,19125,19140,19151,19161],{},[446,19126,19127,19128,19131,19132,19135,19136,19139],{},"l’attribut ⁠",[352,19129,19130],{},"aria-hidden",", utile pour masquer les éléments décoratifs, évitant qu'ils ne perturbent l'expérience utilisateur des lecteurs d'écran. Attention toutefois au recours à ",[352,19133,19134],{},"aria-label"," pour les boutons en forme d’icône puisque ces labels ne peuvent être traduits automatiquement. On préférera cacher visuellement le label (",[352,19137,19138],{},".sr"," avec Tailwind par exemple)",[446,19141,19142,19143,19146,19147,19150],{},"une bonne gestion du focus en ayant recours à ",[352,19144,19145],{},":focus-visible"," plutôt qu’au destructeur ⁠",[352,19148,19149],{},"*:focus { outline: none; }"," — le navigateur se chargeant de gérer intelligemment le focus visible ou non",[446,19152,19153,19156,19157,19160],{},[352,19154,19155],{},":not(:has(:focus-visible))"," pour la gestion des éléments apparaissant au ",[1620,19158,19159],{},"hover"," associé à l’utilisation de media queries ciblant les écrans tactiles",[446,19162,19163,19164,19166,19167,19170,19171,19178,19179,19182,19183,19186],{},"pour les formulaires, les recommendations sont nombreuses et de bon sens. On citera la génération d’",[352,19165,511],{}," unique avec le hook ",[352,19168,19169],{},"useId"," de React, l’utilisation astucieuse de ",[91,19172,19175],{"href":19173,"rel":19174},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAccessibility\u002FARIA\u002FReference\u002FAttributes\u002Faria-describedby",[95],[352,19176,19177],{},"aria-describedby"," pour contrebalancer le support hésitant de ",[352,19180,19181],{},"aria-errormessage"," et un peu de politesse avec les notifications dynamiques grâce à ",[352,19184,19185],{},"aria-live=\"polite\""," pour les notifications non urgentes.",[19,19188,19189],{},"Enfin, Kateryna Porshnieva rappelle qu’un code accessible, c’est aussi des tests front plus robustes !",[344,19191,19195],{"className":19192,"code":19193,"language":19194,"meta":350,"style":350},"language-javascript shiki shiki-themes github-dark-default","const usernameError = screen.getByRole(\"alert\", {\n  name: \u002Fusername is too short\u002Fi\n});\n\nexpect(usernameError).toBeInTheDocument();\nexpect(username).toBeInvalid();\n","javascript",[352,19196,19197,19202,19207,19212,19216,19221],{"__ignoreMap":350},[355,19198,19199],{"class":357,"line":358},[355,19200,19201],{},"const usernameError = screen.getByRole(\"alert\", {\n",[355,19203,19204],{"class":357,"line":364},[355,19205,19206],{},"  name: \u002Fusername is too short\u002Fi\n",[355,19208,19209],{"class":357,"line":370},[355,19210,19211],{},"});\n",[355,19213,19214],{"class":357,"line":376},[355,19215,1271],{"emptyLinePlaceholder":893},[355,19217,19218],{"class":357,"line":382},[355,19219,19220],{},"expect(usernameError).toBeInTheDocument();\n",[355,19222,19223],{"class":357,"line":1157},[355,19224,19225],{},"expect(username).toBeInvalid();\n",[19,19227,19228,19229,504,19234,19239,19240,19243,19244,44],{},"Concernant le test de l’accessibilité en elle-même, Il existe plusieurs outils comme ",[91,19230,19233],{"href":19231,"rel":19232},"https:\u002F\u002Fwww.deque.com\u002Faxe\u002Fdevtools\u002F",[95],"axe DevTools",[91,19235,19238],{"href":19236,"rel":19237},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Flighthouse\u002Faccessibility\u002Fscoring?hl=fr",[95],"Lighthouse"," et le plugin ESLint ",[352,19241,19242],{},"jsx-a11y",". Enfin, des testeurs spécialisés peuvent être recrutés sur des plateformes comme ",[91,19245,19248],{"href":19246,"rel":19247},"https:\u002F\u002Fmakeitfable.com\u002F?utm_source=https%3A%2F%2Fblog.hoppr.tech",[95],"Fable",[23,19250,19252],{"id":19251},"rsc-pas-de-client-pas-de-problème","RSC : pas de client, pas de problème",[19,19254,19255],{},[91,19256,19259],{"href":19257,"rel":19258},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=dA-8FY5xlbk",[95],[1620,19260,19261],{},"React Server Components: Elevating speed, interactivity, and user experience",[19,19263,19264,19265,19268,19269,19272],{},"Voilà une démo impressionnante d'une application Todo réalisée par Aurora Scharff avec les composants serveur de React (RSC) – sans utiliser ⁠",[352,19266,19267],{},"useEffect"," ni ",[352,19270,19271],{},"⁠useState",". L'application finale s'affiche rapidement et répond rapidement, malgré des temps de réponse simulés côté backend vraiment très longs.",[19,19274,19275],{},[34,19276,19277],{},"Présentation de RSC",[19,19279,19280],{},"Les RSC s'exécutent côté serveur ou au moment de la compilation, sans dépendre des API du navigateur, de l'état ou des effets. Brièvement, ses avantages sont les suivants :",[443,19282,19283,19289,19295,19301],{},[446,19284,19285,19288],{},[34,19286,19287],{},"Réduction de la taille du bundle."," La taille du bundle envoyé au client est réduite, ce qui améliore les performances lors du chargement des pages",[446,19290,19291,19294],{},[34,19292,19293],{},"Récupération asynchrone des données."," Les données sont récupérées de manière asynchrone depuis le composant lui-même, sans attendre que le composant soit monté côté client et sans devoir gérer un état local",[446,19296,19297,19300],{},[34,19298,19299],{},"Accès direct aux ressources du backend."," Les ressources du backend sont accessibles directement puisque les appels sont exécutés côté serveur.",[446,19302,19303,2756,19306,19311,19313,19314,19317],{},[34,19304,19305],{},"Report du rendu et",[1620,19307,19308],{},[34,19309,19310],{},"progressive enhancement",[34,19312,44],{}," Les composants non essentiels au chargement de la page sont rendus au besoin, avec une UI de chargement (",[352,19315,19316],{},"⁠\u003CSuspense>","), divisant le coût des requêtes réseau et du rendu entre client et serveur.",[19,19319,19320],{},[34,19321,19322],{},"Et côté code ?",[19,19324,19325,19326,19329],{},"Disponible depuis React 19, le hook ",[352,19327,19328],{},"⁠use"," est utilisé pour rendre de manière asynchrone un composant client qui prend une promesse en propriété, utile lorsque le composant a besoin d'accéder à des API du navigateur (et doit donc être un composant client) mais que le parent est un composant serveur qui ne doit pas bloquer le rendu pour des données dépendantes.",[19,19331,19332,19333,19336,19337,19340],{},"React 19 introduit également ",[352,19334,19335],{},"⁠useOptimistic"," pour rendre l'interface utilisateur sans attendre la réponse asynchrone. Aurora Scharff insiste également sur la pertinence d’utiliser ",[352,19338,19339],{},"⁠cache"," (toujours en canary au premier semestre 2025) :",[443,19342,19343,19352],{},[446,19344,19345,19346,19351],{},"pour mettre en cache des requêtes\u002Fcoûteux calculs, permettant le pré-chargement de données côté serveur (cf. ",[91,19347,19350],{"href":19348,"rel":19349},"https:\u002F\u002Ffr.react.dev\u002Freference\u002Freact\u002Fcache#preload-data",[95],"la documentation de React"," à ce sujet)",[446,19353,19354],{},"et, plus important encore, pour conserver le caractère composable des composants : deux composants peuvent appeler le même service API, sans redondance, les données récupérées par le premier seront réutilisables pour le deuxième",[19,19356,19357,19358,19360,19361,19364],{},"L'amélioration progressive (",[1620,19359,19310],{},") est également possible via le composant ⁠",[352,19362,19363],{},"\u003CForm>"," de Next.js, qui repose sur HTML plutôt que sur JavaScript.",[19,19366,19367],{},"Enfin, le talk se termine sur quelques bonnes pratiques liées à l’utilisation des RSC :",[443,19369,19370,19377,19388],{},[446,19371,19372,19373,19376],{},"résoudre les promesses le plus profondément possible dans l'arbre de composants et non au plus haut niveau de la page (👉 ",[352,19374,19375],{},"getServerSideProps",") → ne bloque plus le rendu",[446,19378,19379,19380,19387],{},"les indicateurs de chargement avec interface utilisateur adaptée deviennent capitaux pour le ",[91,19381,19384],{"href":19382,"rel":19383},"https:\u002F\u002Fweb.dev\u002Farticles\u002Fcls?hl=fr",[95],[1620,19385,19386],{},"cumulative layout shift"," et par extension pour une meilleure expérience utilisateur",[446,19389,19390,19391,2418],{},"utiliser l'URL comme source de vérité de l'état de l'application (cf. l’excellent talk de François Best ",[91,19392,19395],{"href":19393,"rel":19394},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=U__Rwsp8v78",[95],"« Type-Safe URL State Management in React with nuqs »",[23,19397,19399,2756,19404],{"id":19398},"champignon-testing-de-paris",[1620,19400,19401],{},[34,19402,19403],{},"Champignon testing de",[34,19405,19406],{},"Paris",[19,19408,19409],{},[91,19410,19413],{"href":19411,"rel":19412},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=OYZNTPp04hw",[95],[1620,19414,19415],{},"At the top of the pyramid: Playwright testing at scale",[19,19417,19418],{},"Kate Marshalkina fait un chouette retour d’expérience sur une codebase chaotique, très partiellement écrite en TypeScript et avec des tests peu efficaces.",[19,19420,19421],{},[34,19422,19423],{},"Une petite histoire des stratégies de test",[19,19425,19426],{},"Kate revient d’abord sur les patterns pratiqués dans l’industrie :",[19,19428,19429,19430,19435],{},"La ",[91,19431,19434],{"href":19432,"rel":19433},"https:\u002F\u002Fmartinfowler.com\u002Fbliki\u002FTestPyramid.html",[95],"pyramide de test"," proposée par Mike Cohn et revue par Martin Fowler :",[19,19437,19438],{},[176,19439],{"alt":19440,"src":19441},"Schéma représentant une pyramide de test dont la base au sol est constitué des tests unitaires, le sommet des tests UI et le milieu des tests de service \u002F d’intégration","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fimg3.webp",[19,19443,19444],{},"Soulignant la fragilité des tests UI (si l’UI change, le test est obsolète), cette stratégie mise la plupart des efforts sur les tests unitaires afin d’assurer que le core de l’application est protégé par la batterie de test.",[19,19446,19447,19448,19453],{},"Malheureusement, certaines applications continuent de renverser cette pyramide pour finir par donner naissance au ",[91,19449,19452],{"href":19450,"rel":19451},"https:\u002F\u002Falisterscott.github.io\u002FTestingPyramids.html",[95],"software testing ice-cream cone","  :",[19,19455,19456],{},[176,19457],{"alt":19458,"src":19459},"Schéma représentant une pyramide de test inversé dont le sommet est au sol. Le sommet comprend les tests unitaires, le milieu les tests d’intégration et la base les tests automatisés e2e. Au-dessus de la base est représenté une forme ovale indiquant les tests de régression manuels. Le tout ressemble à un cornet de glace avec la pyramide formant le cornet et la forme ovale la boule de glace","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fimg4.webp",[19,19461,19462],{},"Dans cette situation, les tests de régression manuels sont nombreux, soumis aux variables humaines (erreur, imprécision, omission, lenteur) et bien souvent les tests fonctionnels automatisés (e2e) trop nombreux, lents et fragiles. La part des tests unitaires est réduite à peau de chagrin.",[19,19464,19465],{},"Cet anti-pattern se manifeste dans les codebases où la condition pour appliquer la pyramide de test n’est pas remplie : un code suffisamment découpé pour obtenir des tests unitaires pertinents et utiles.",[19,19467,19468,19469,19474],{},"Une stratégie plus , popularisée sous la forme du ",[91,19470,19473],{"href":19471,"rel":19472},"https:\u002F\u002Fkentcdodds.com\u002Fblog\u002Fwrite-tests",[95],"Testing Trophy"," de Kent C. Dodds, est le testing diamond :",[19,19476,19477],{},[176,19478],{"alt":19479,"src":19480},"Schéma représentant un diamant sous forme de losange. En bas en haut on trouve : les tests unitaires, les tests d’intégration (au centre, couvrant la plus grande surface du losange), les tests automatisés e2e et les tests manuels. Les tests unitaires d’un côté et l’ensemble formé par les tests automatisés e2e + les test manuels occupent une surface identique du losange, l’un en bas sous les tests d’intégration, l’autre en haut au-dessus des tests d’intégration","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fdiamond-testing.webp",[19,19482,19483,19484,19487],{},"Avec le ",[1620,19485,19486],{},"testing diamond",", la confiance générée par les tests provient principalement des tests d’intégration (scope le plus large) auxquels s’ajoute le test du cœur critique de l’application (tests unitaires) et du happy flow ou smoke testing via des tests e2e automatisés ou des scripts manuels pour les scripts tiers.",[19,19489,19490],{},[34,19491,19492],{},"Tester c’est douter ? Tester c’est cueillir un champignon",[19,19494,19495,19496,44],{},"Étant donné l’état de la codebase et les délais du projet sur lequel est intervenue Kate Marshalkina, aucune de ces stratégies ne pouvait s’appliquer. Il a donc fallu établir une stratégie davantage personnalisée pour parvenir à une barrière de tests utile et maintenable : le ",[1620,19497,19498],{},"testing mushroom",[19,19500,19501],{},[176,19502],{"alt":19503,"src":19504},"Schéma représentant un champignon formé par un rectangle ouvert à son sommet et une forme ovale qui coiffe le rectangle. En bas du rectangle se trouve les tests unitaires, au sommet du rectangle on trouve les tests d’intégration qui sont mélangés avec les tests automatisés e2e ","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fimg5.webp",[19,19506,19507],{},"Au premier abord, cette stratégie semble identique à l’anti-pattern de l’ice-cream cone mais la différence se situe principalement dans l’imbrication des tests d’intégration, difficiles ou peu utiles dans le cadre d’un frontend, avec les tests e2e.",[19,19509,19510],{},"Il y a quelques années encore les tests snapshot de composants étaient courants et occasionnaient une perte de temps et un grand nombre de faux-positifs. Ce temps perdu est réinjecté dans une plus grande attention portée à la solidité et pertinence des tests e2e. En effet, l’avantage de cette stratégie est que, loin d’être une panacée, elle est un compromis entre toutes les stratégies historiques, adaptée à un contexte particulier et s’appuyant sur le fait qu’aujourd’hui les tests fonctionnels automatisés en manipulant l’UI ne sont plus difficiles et coûteux… à condition de les exécuter correctement.",[19,19512,19513],{},[34,19514,19515],{},"La performance des tests e2e",[19,19517,19518],{},"Ne crions pas victoire trop vite car la performance des tests e2e est encore un problème. La trop longue durée des pipelines, la mauvaise conception des scénarios, leur multiplication et la fragilité des tests demeure fréquentes.",[19,19520,19521],{},"Ainsi, Kate Marshalkina termine son talk en présentant les bonnes pratiques que son équipe et elle ont appliqué afin de rendre les tests e2e écrits avec Playwright performants, rapides, utiles et lisibles par tous :",[443,19523,19524,19535,19541,19560],{},[446,19525,19526,19530,19531,19534],{},[91,19527,19528],{"href":19528,"rel":19529},"https:\u002F\u002Fgithub.com\u002Fvitalest\u002Fplaywright-network-cache",[95]," pour consommer depuis un cache local les appels API similaires exécutés dans les tests précédents, d’où l’inclusion des tests intégrations dans la partie E2E (le chapeau du champignon). Tout comme la ",[1620,19532,19533],{},"mushroom strategy"," elle-même, c’est un trade-off entre des tests e2e demandant de maintenir de fastidieux mocks d’API au risque de se retrouver avec de faux-positifs et de ne pas capturer de vrais bugs et ceux attaquant directement l’API.",[446,19536,19537,19540],{},[352,19538,19539],{},"eslint-plugin-playwright"," pour corriger les mauvaises pratiques",[446,19542,19543,19544,19549,19550,19553,19554,19559],{},"utilisation du ",[91,19545,19548],{"href":19546,"rel":19547},"https:\u002F\u002Fplaywright.dev\u002Fdocs\u002Fpom",[95],"Page Object Model"," et du décorateur ",[352,19551,19552],{},"@step()"," pour exposer de manière claire les actions possible sur une page et grouper les actions haut niveau de l’utilisateur En combinaison avec ",[91,19555,19558],{"href":19556,"rel":19557},"https:\u002F\u002Fgithub.com\u002Fallure-framework",[95],"Allure",", les tests E2E, leurs résultats et leurs itérations sont compréhensibles pour les individus non techniques de l’équipe",[446,19561,19562],{},"lancement en parallèle des tests et augmentation du nombre de workers",[23,19564,19566],{"id":19565},"remixer-remix","Remixer Remix",[19,19568,19569],{},[91,19570,19573],{"href":19571,"rel":19572},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=i1cVfJz4Vlw",[95],[1620,19574,19575],{},"Remix The Wrong (?) way",[19,19577,19578,19579,19582,19583,44],{},"Dans cette conférence, Antoine Chalifour nous fait part de ce qui l’a poussé à s’éloigner des opinions de Remix afin de modeler le framework selon ",[1620,19580,19581],{},"ses"," besoins, celui de son produit ",[91,19584,19587],{"href":19585,"rel":19586},"https:\u002F\u002Fwww.geckosocial.app\u002F?utm_source=https%3A%2F%2Fblog.hoppr.tech",[95],"Geckosocial",[19,19589,19590],{},"Le projet d’Antoine permet de gérer ses publications de manière automatisée sur LinkedIn et d'autres plateformes. Il est composé d’un éditeur de texte, d’une fonctionnalité de mentions d'utilisateurs, d’une vue calendrier, de capacités d'édition de texte enrichi et d’une intégration d'IA.",[19,19592,19593],{},"Ok mais… c’est quoi déjà Remix ?",[19,19595,19596],{},"Remix c’est un méta-framework React web full-stack particulièrement puissant et offrant un ensemble de fonctionnalités côté serveur solides. Une des particularités de Remix est qu’il couple fortement le routage et la récupération de données, ce qui peut influencer la manière dont il est utilisé dans un projet.",[19,19598,19599],{},[34,19600,19601],{},"Qu’est ce qui a mené à « utiliser Remix de la mauvaise manière » ?",[19,19603,19604],{},[176,19605],{"alt":19606,"src":19607},"Mème d’internet représentant un agriculteur disant en anglais “Ce n’est pas grand chose mais au moins c’est un travail honnête”. Le haut de l’image précise “quand tu utilises Remix uniquement pour le routing après avoir abandonné ses features principales”","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fimg6.webp",[19,19609,19610],{},[34,19611,19612],{},"1. Limitations du Rendu Côté Serveur",[19,19614,19615,19616,19619],{},"Certains composants comme ceux avec rendu de date rendent difficile l’utilisation du SSR. De plus, l'éditeur de texte enrichi utilisant ",[1620,19617,19618],{},"Lexical"," a besoin des nœuds DOM et fonctionne uniquement côté client. Ainsi, le SSR a été désactivé pour l'expérience utilisateur connecté.",[19,19621,19622],{},[34,19623,19624],{},"2. Données Non Plus Couplées aux Routes",[19,19626,19627],{},"Les données non plus couplées aux routes sont un autre facteur qui a contribué à l'utilisation inappropriée de Remix dans le cas d’Antoine.",[19,19629,19630,19631,19634],{},"Les exigences de données sont devenues plus complexes pour chaque écran, et les données sont réutilisées entre les composants qui ne correspondent pas aux routes. De plus, certains ",[1620,19632,19633],{},"dialog"," nécessitent des données asynchrones mais ne sont pas liés à des routes spécifiques. Cela a rendu la revalidation coûteuse car les routes parentes chargeaient trop de données",[19,19636,19637],{},[34,19638,19639],{},"3. Formulaires Complexes",[19,19641,19642],{},"Enfin, les formulaires complexes sont également à l’origine de l'utilisation détournée de Remix.",[19,19644,19645],{},"Au fil du projet, les formulaires ont évolué au-delà de simples entrées, demandant une validation conditionnelle. Il a fallu également compter avec les difficultés liées aux tableaux d'objets dans les formulaires et aux actions n’étant pas toujours déclenchées par des boutons de soumission.",[19,19647,19648],{},[34,19649,19650],{},"Est-ce que Remix a encore sa place dans sa stack techno, est-ce toujours utile ?",[19,19652,19653,19654,19657],{},"Sa réponse est un grand OUI ! Remix fournit une excellente DX (",[1620,19655,19656],{},"developer experience",") grâce à Vite, incluant la mise en page et le routing imbriqué, le rendu côté serveur (SSR) avec amélioration progressive pour des pages spécifiques, des redirections d'authentification côté serveur ainsi que l'intégration avec des serveurs Node existants.",[84,19659,19661],{"id":19660},"les-points-clés-a-retenir-de-son-talk","Les points clés a retenir de son talk ?",[19,19663,19664],{},[176,19665],{"alt":19666,"src":19667},"Mème d’internet en deux lignes. La première ligne représente le chanteur Drake faisant un geste de dégoût associé au texte “Utiliser Remix comme prévu par ses créateurs”. La deuxième ligne représente également le chanteur Drake faisant un signe d’approbation et associé au texte “Utiliser Remix de la mauvaise façon mais qui fonctionne pour ton projet”","\u002Fcontent-assets\u002F2025-04-15-dbrief-react-paris-2025\u002Fassets\u002Fimg7.webp",[443,19669,19670,19677,19680,19683],{},[446,19671,19672,19673,19676],{},"Les frameworks ne sont que des outils ",[34,19674,19675],{},":"," rien n’oblige à utiliser toutes ses fonctionnalités (👉 edge middleware)",[446,19678,19679],{},"Migrer progressivement pour ne pas tout réécrire d’un coup",[446,19681,19682],{},"Continuer à déployer en production pendant la migration",[446,19684,19685],{},"Utiliser ce qui fonctionne pour les besoins spécifiques du produit – amen",[19,19687,19688],{},"En résumé, Antoine a proposé un excellent talk montrant que la tech est au service des développeurs et non l’inverse !",[23,19690,19692],{"id":19691},"un-mathématicien-et-un-développeur-entrent-dans-un-foo-bar","Un mathématicien et un développeur entrent dans un foo bar…",[19,19694,19695],{},[91,19696,19699],{"href":19697,"rel":19698},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=ULTiZDTNeyI",[95],[1620,19700,19701],{},"From Chaos to Clarity: Mathematical Foundations for Maintainable React Applications",[19,19703,19704],{},"Cette conférence étonnante d’Héla Ben Khalfallah porte sur la façon d'optimiser une codebase React grâce à un trio de concepts mathématiques :",[443,19706,19707,19710,19713],{},[446,19708,19709],{},"la théorie des graphes",[446,19711,19712],{},"la théorie des catégories",[446,19714,19715],{},[1620,19716,19717],{},"lambda-calculus",[19,19719,19720],{},"L’objectif derrière ces concepts intimidants est clair : produire du code robuste et performant.",[19,19722,19723],{},[34,19724,19725],{},"Théorie des graphes : visualiser et structurer notre code react",[19,19727,19728],{},"Même si l'idée de représenter une application comme un graph est familière, Héla rappelle les caractéristiques nécessaires du graph afin que la représentation soit pertinente :",[443,19730,19731,19734,19747],{},[446,19732,19733],{},"modéliser les fichiers comme des nœuds et les imports comme des arêtes pour repérer immédiatement les dépendances circulaires pouvant perturber la maintenance et le bundling",[446,19735,19736,19737,19740,19741,19746],{},"identifier les communities : les algorithmes de ",[1620,19738,19739],{},"community detection"," (e.g. ",[91,19742,19745],{"href":19743,"rel":19744},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FM%C3%A9thode_de_Louvain",[95],"Louvain",") montrent comment regrouper les fichiers pour maximiser la cohésion interne et minimiser les dépendances extérieures. C'est un outil objectif pour organiser les dossiers et les packages de manière optimale.",[446,19748,19749,19750,19753,19754,19757,19758,19761],{},"mesurer l'influence de chaque fichier : les métriques comme la ",[1620,19751,19752],{},"centrality",", la ",[1620,19755,19756],{},"density"," ou le ",[1620,19759,19760],{},"sparsing"," permettent de repérer rapidement les zones à réfactoriser, les fichiers critiques à tester en priorité et les morceaux de code spaghetti pénalisant l'évolution du projet",[19,19763,19764],{},[34,19765,19766],{},"Catégorie théorie ou comment revenir à des fonctions pures et des transformations unifiées",[19,19768,19769],{},"Et une petite plongée dans la théorie des catégories pour la conception fonctionnelle en compagnie d’Héla. L'objectif est de passer des mutations et des effets secondaires aux transformations. Quelques principes :",[443,19771,19772,19775,19820],{},[446,19773,19774],{},"préférer le morphisme à la mutation : au lieu de muter les données, appliquer une suite de transformations qui maintiendra la structure de départ et minimisera les effets de bord",[446,19776,19777,508,19784,19791,19793,19794,19797,19798,19801,19802,19805,19806,19809,19810,19815,19816,19819],{},[91,19778,19781],{"href":19779,"rel":19780},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FFunctor",[95],[1620,19782,19783],{},"Functors",[91,19785,19788],{"href":19786,"rel":19787},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FMonad_(functional_programming)",[95],[1620,19789,19790],{},"Monads",[1620,19792,44],{}," Concrètement, en JavaScript, les ",[352,19795,19796],{},"Array","s sont naturellement des functors via le ",[352,19799,19800],{},".map",", tandis que les structures comme ",[352,19803,19804],{},"Promise"," fonctionnent comme des monades via le ",[352,19807,19808],{},".then",". Ces concepts rappellent simplement à quel point découper son code en transformations pures peut simplifier les tests et la lisibilité. Ou encore ",[91,19811,19814],{"href":19812,"rel":19813},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fneverthrow",[95],"neverthrow"," qui est un package npm qui propose une Monad ",[352,19817,19818],{},"Result"," i.e la meilleure manière de gérer un résultat qui peut être en erreur 😎_._",[446,19821,19822,19825,19826,504,19828,508,19831,19833,19834,19837,19838,19840,19841,19844,19845,19848],{},[34,19823,19824],{},"Transducers","\nL'optimisation de ",[352,19827,2876],{},[352,19829,19830],{},"filter",[352,19832,2892],{}," en une seule itération, sans créer d'intermédiaire superflu, reste un incontournable pour les ensembles de données volumineux.\nConcrètement, faire un ",[352,19835,19836],{},".filter"," suivi d’un ",[352,19839,19800],{}," puis d’un ",[352,19842,19843],{},".reduce",", même si la complexité algorithmique reste la même (potentiellement ",[352,19846,19847],{},"O(n)","), sur un gros volume de données, il peut être intéressant de les regrouper afin d’éviter 2 tours de boucle superflus.",[19,19850,19851],{},"On voit ici à quel point les bonnes pratiques côté code s’inspirent de la théorie des catégories et traduisent ses principes… comme le montre parfaitement la composition !",[19,19853,19854,2756,19857],{},[34,19855,19856],{},"Lambda calculus : optimiser grâce à la composition et aux",[1620,19858,19859],{},[34,19860,19861],{},"lazy evaluations",[19,19863,19864],{},"Le Lambda calculus fournit un éventail d’outils qui sont déjà bien connus des développeurs :",[443,19866,19867,19874,19889,19895],{},[446,19868,19869,19870,19873],{},"le ",[1620,19871,19872],{},"currying"," pour transformer les fonctions à multiples arguments en une chaîne de fonctions à un seul argument. Loin d’être accessoire ou superficiel, c'est un moyen efficace de réutiliser les sous-ensemble d’une logique",[446,19875,19876,19877,19880,19881,19884,19885,19888],{},"les ",[1620,19878,19879],{},"Higer-Order Functions"," (HOFs), importantes pour la composition, par exemple d’un ",[1620,19882,19883],{},"debounce"," et d’un ",[1620,19886,19887],{},"throttle",". Mieux on segmente les responsabilités dans nos HOFs, plus c'est réutilisable et clair",[446,19890,19891,19894],{},[1620,19892,19893],{},"lazy evaluation et memoization"," : deux grands classiques ! D’une part n'évaluer que ce dont on a besoin quand on en a besoin, d’autre part conserver le résultat pour éviter de répéter des opérations coûteuses",[446,19896,19897,19898,19901,19902,19905,19906],{},"le pattern du trampoline pour gérer la récursivité en JavaScript sans causer de ",[1620,19899,19900],{},"stack overflow."," L’idée du trampoline est de retourner une fonction exécutée par le trampoline (appelée ",[1620,19903,19904],{},"continuation",") plutôt que d’ajouter sempiternellement un niveau à la stack jusqu’à l’overflow_._ C’est le trampoline, la fonction wrapper, qui se charge d’appeler la fonction récursive à la fin de son traitement plutôt que la fonction récursive qui s’appelle elle-même. C’est un pattern indispensable dans un contexte de code récursif puisqu’à date JavaScript ne supporte malheureusement pas les ",[1620,19907,19908],{},"Tail Recursive Functions.",[19,19910,19911],{},[34,19912,19913],{},"Pourquoi ce talk est un précieux rappel ?",[19,19915,19916],{},"Toutes ces bonnes pratiques pour un code robuste ne devraient pas être surprenantes pour beaucoup de développeurs. Mais cette conférence est la bienvenue car de la théorie à la pratique il y a parfois un abysse. Même en tant que développeur senior, la tentation de laisser s'installer quelques entorses à la pureté des fonctions est fréquente.",[19,19918,19919],{},"Héla a donc rappelé de manière concise et claire pourquoi ces outils et techniques sont utiles :",[443,19921,19922,19928],{},[446,19923,19924,19925,19927],{},"Une meilleure maintenabilité ",[34,19926,19675],{}," des fonctions pures et un code bien modulaire se manipulent et se refactorisent plus facilement",[446,19929,19930,19931,19933,19934,19937,19938,508,19941,504,19944,19947],{},"Une plus grande performance ",[34,19932,19675],{}," la ",[1620,19935,19936],{},"lazy evaluation,"," la bonne organisation des imports et l’utilisation des outils de la théorie des catégories (morphisme, ",[1620,19939,19940],{},"functors",[1620,19942,19943],{},"monads",[1620,19945,19946],{},"transducers",") afin d’éviter les side-effects peuvent se révéler réellement determinants pour un projet React ou front de grande envergure",[19,19949,19950],{},"Ces techniques sont déjà au cœur de la plupart des bonnes pratiques et les voir présentées ensemble dans un format clair et méthodique est un rappel utile pour garder un projet propre et évolutif.",[19,19952,19953],{},"Bref, un indispensable à intégrer ou réintégrer dans les équipes souhaitant maintenir un standard de qualité élevé sur leurs applications React.",[23,19955,19957],{"id":19956},"les-autres-conférences","Les autres conférences",[19,19959,19960,19961,19966],{},"C’est tout pour nous cette année, n’hésitez pas à consulter sur ",[91,19962,19965],{"href":19963,"rel":19964},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=nYOAWjcRuBY&list=PL53Z0yyYnpWitP8Zv01TSEQmKLvuRh_Dj",[95],"YouTube"," ces conférences et les autres pour ne pas manquer notamment :",[443,19968,19969,19977,19987],{},[446,19970,19869,19971,19976],{},[91,19972,19975],{"href":19973,"rel":19974},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=-W3_dxNDHVw",[95],"cours d’histoire"," de Kent C. Dodds “des origines obscures et un peu sales du web aux RSC” (nom non officiel) ;",[446,19978,19979,19986],{},[91,19980,19983],{"href":19981,"rel":19982},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=LzCEfzHh8Eo",[95],[1620,19984,19985],{},"A Tale of Two Components: Mastering A\u002FB Testing in React"," de Violina Popova sur sujet un peu niche mais pointu et brillamment exposé ;",[446,19988,19989,19990,19997],{},"la petite leçon de bon sens de TkDodo avec ",[91,19991,19994],{"href":19992,"rel":19993},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=l3PxErcKeAI",[95],[1620,19995,19996],{},"React Query API Design - Lessons Learned"," qui, sans être hélas très surprenante, offre quelques retours d’expérience sur la difficulté de humaine et technique de produire du code pour l’Open Source.",[856,19999,20000],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .sPWt5, html code.shiki .sPWt5{--shiki-default:#7EE787}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}",{"title":350,"searchDepth":364,"depth":364,"links":20002},[20003,20004,20005,20007,20008,20010,20013,20014],{"id":18896,"depth":364,"text":18897},{"id":18937,"depth":364,"text":18940},{"id":18997,"depth":364,"text":20006},"I &lt;3 HTML",{"id":19251,"depth":364,"text":19252},{"id":19398,"depth":364,"text":20009},"Champignon testing de Paris",{"id":19565,"depth":364,"text":19566,"children":20011},[20012],{"id":19660,"depth":370,"text":19661},{"id":19691,"depth":364,"text":19692},{"id":19956,"depth":364,"text":19957},"2025-04-15T07:20:37.563Z"," React Paris est un événement organisé par BeJs, association d’origine belge déjà à l’origine des événements React Brussels, React Africa et BeJS Conf. BeJS a été fondée en 2019 avec pour mission de p",{},"\u002Fblogs\u002F2025-04-15-dbrief-react-paris-2025",[20020,20022],{"id":5813,"name":5814,"image":20021,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466S2JJIBLE%2F20250415%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250415T072037Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEJ%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJHMEUCIQCRKK2GX8ZGlbk7tJJGQY5hZdbx3fEoIk1h%2FLudLPyD7AIgGXvLeISbp35lBICj1oFdN%2BoUTJmFn%2BzLSkkGVOfXu0Uq%2FwMIKBAAGgw2Mzc0MjMxODM4MDUiDMX9alt9PW7E4t30XyrcA5ahO2V8DBPmczeLmpnoxnA68tp5PIMBYLPUHJ4aw6mrECxXXu1KEU6dqBzsTsSrd6QTRHWjcBT69uyeLwLrYYeoaV1XAvaoRxy78zc6ehbpuRw0rRP79%2FKADKkQ2X%2BIQrOcz%2Fog3MArYcPINO%2F%2BzQYHTQwsk428aET9cXvX%2BQw3v1g7jsXsASPVU8rc6Xm7TTfDgmvveBixLCjRqNEbnOseI4esrMtmYb5NvcZdsbNXxEbVYpJM0d83qUm8kJGPN78Sb%2FVdl7L69Hs4PyvTmYXPOcgYp%2BCwUsQehcR0FoGAAwum1va%2Bn1mpF%2FTe9tMMfDhgdP9uYC0ITvojIWQ3DOMHFKqVSuHiQrbVd0CHopQdOcpWhtisuutwmyAmP6SvymYTPorlsaiSmpCxkMsEtjNaceBfg9Dp%2FsueGnCYIfVxkR%2Bn8LY%2BNv00BXYFg8Lu%2B3bWe4MbVioYTHJ8N2Ld2UL8tbJZ0WwQpgAwcrynqBtmSyzWdX63Wstqik8Yo2Grnq3im4kI4v9lzg4APZVASr9ZvGtku%2BQKD0%2BQE64y5k1cJwM8uIhKmdtYcFs8nKXFyi4CRUYfuHKQM5LtiL8ZBUtCMtpRGbdHXIz%2FVubEbMA5wTd2oj%2F2kz89SzuWMICA%2BL8GOqUB9FRt1kzYEMIHw7nNJ6bsbc2cIQVUJoxOHfmn8GkCihLQj0HLUyuxeYldcfkeBLe3qUSevJyamAgcdOoGN7QyRqkZT0nVZzN%2FZglozy8qiEBOXkj23Pa5TRx5YcgAhBjha8xnznicwV1covjlrkMu%2Fogppz7wmIBeWrAZRhe3kFZArhjMN8tjQUy%2F4VGBdeNZ6lJ%2FfhN44%2FRwg1%2BHCZVxBrUyorNA&X-Amz-Signature=bcab8d8364d2bc7b4b9c0db3da5f06866bce409576051747590078b3ad494e71&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":897,"name":898,"image":20023,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466267U6E46%2F20250415%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250415T072034Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEJ%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLXdlc3QtMiJIMEYCIQCnrM%2Bk5Sk%2F11pBLISFJydtzvTUs5KhMkh7tlOFgNr4yQIhAK8VJ7yK9YuXc%2Fczuzn3EgtiMGQrUQs5opBS2CNTX%2FrJKv8DCCgQABoMNjM3NDIzMTgzODA1Igz%2BNwZ5qQF1hkqm%2BIAq3AMtCS%2BcPyJkN%2Farh%2F%2BEeLzsnvLnNAYye7qH3Wm6bkWmcMG7dgAEM%2BRAyCJnuZbwBIs8D2%2FkDWNpFSvjqqWZqX6JiMFY5ruxGXqNZ%2B441PgJVEuMZVZ0zUsnHhbSWGikOOrblcTlQiaf71WK0AcARvV9HKNHH3ZTfUpAJd87UzDcrrkLRNKJGas4L%2Bp5i%2FhH6jmX%2Bngt1XAhLfnfiqCJK%2BnYeEG02z8gK8azHjNrPBQYyENvdreGBaD%2F42xC6mIjLoccis%2BMVUZ0bKfOO59FcuTLNswmEuC2%2FacigjIL0aSphWdcR2Jo3%2FcafyD05LSyzVqPc%2FBzXn4IZmowrmAEiw6RgrKU6x8909X5s29c6uYLiw3537VNBHLIA42Qtq8BVvn60Ro9kAegouqCrRZjliSQZp%2FcdkAIqCWjLmp3Ab5MeqtdH5ZncZThtOxiwwFByd%2BhozKhYzAoLpVJtCEPlql5ECKoaZD3%2BRsVRENHEzwMEX%2BgDrJTENh%2Fxv4n11evWZX7khwe3KN4Z2cxnh3LNO74hzpgapB1BMbKOWluOc4ndt4vhEx5o1h1s7yXCXa3KzCsKQ16RxeO1bNM89dh0%2BZCkiCqWCAI%2FK9%2Bq5evm947Jb9i%2Bes5VLabU3YfaDCggPi%2FBjqkAQwy5Vu7UCHrZyfN1ZaerXFy9B%2B3KQUVia%2F%2F1xY45lsdrqlk5iu6EgGG5n01l9E7%2FULqRyL3tkk5uroVlIgIn8SB55QOP0LHfwTKz33NVJhCYJ%2FUih1qw94qzvbyFvD00gvRjjQEc0KTjjvqiEUyVRviB%2B%2B8JS3tEi%2BBOhTowmkZzhP2Pt2cSaVvxkJAkLmRFFcLDGBfA37wqywpdRIuOmGSFaC4&X-Amz-Signature=187a3b781ea82533fd6a00ff971bf14a0bd6c4ae8a564b90abd2cca3f7f0f2de&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":18872,"description":20016},"blogs\u002F2025-04-15-dbrief-react-paris-2025\u002Findex",[6607,20027,7819],"front-end","lXw7tIB6b7uvHshpFjQ8DvjuCQETMUr4UR3Y-SMAW1Y",{"id":20030,"title":20031,"alt":20032,"authors":20033,"body":20041,"date":20231,"description":20232,"extension":890,"image":891,"meta":20233,"navigation":893,"ogImage":891,"path":20234,"published":893,"reviewers":20235,"seo":20243,"stem":20244,"tags":20245,"__hash__":20246},"blogs\u002Fblogs\u002F2025-01-28-interview-chti-tremplin\u002Findex.md","Interview Ch’ti Tremplin","Elisa et Edouard, les 2 interviewés pour le tremplin 2024",[20034,20035,20036],{"id":897,"name":898,"image":7084,"linkedin":900,"x":901},{"id":1887,"name":1888,"image":1889,"linkedin":1890,"x":1891},{"id":20037,"name":20038,"image":20039,"linkedin":20040,"x":901},"f09c2e62-135b-40c0-a141-b239e8e1e761","Elisa Degobert",".\u002Fassets\u002Fauthor-elisa-degobert.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fdegobert\u002F",{"type":16,"value":20042,"toc":20216},[20043,20046,20055,20061,20065,20071,20074,20080,20083,20086,20092,20095,20098,20101,20107,20110,20113,20116,20119,20125,20128,20131,20137,20141,20147,20150,20156,20163,20166,20172,20175,20181,20184,20187,20193,20196,20207],[19,20044,20045],{},"Participer à une conférence en tant que speaker peut sembler intimidant, mais c’est aussi une expérience incroyablement enrichissante. C’est précisément pour aider celles et ceux qui souhaitent franchir ce cap et se lancer que le Ch’ti Tremplin a vu le jour : un programme qui accompagne six participants pendant plusieurs semaines pour les aider à affiner leur sujet, structurer leur talk, créer un support percutant et se préparer à parler devant un public.",[19,20047,20048,20049,20054],{},"A la précédente édition, 2 HoppRs ont participé au tremplin :  Elisa en tant que coachée pour son premier sujet \"",[91,20050,20053],{"href":20051,"rel":20052},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=8EN_hqU5zPU",[95],"À la découverte de Dependency Track","\" et Edouard en tant que coach.\nPetite interview pour vous partager leur expériences, les coulisses de cette expérience, les défis qu’ils ont relevés et les enseignements qu’ils en ont tirés 😄",[19,20056,20057],{},[176,20058],{"alt":20059,"src":20060},"Présentation des interviewés Elisa Degobert, Software Crafteuse  chez HoppR et Edouard Cattez Head of Craft chez HoppR","\u002Fcontent-assets\u002F2025-01-28-interview-chti-tremplin\u002Fassets\u002Fimg1.webp",[23,20062,20064],{"id":20063},"retours-de-elisa-sur-sa-participation-au-tremplin","Retours de Elisa sur sa participation au Tremplin",[84,20066,20068],{"id":20067},"elisa-quest-ce-qui-ta-donné-envie-de-participer-au-chti-tremplin-pourquoi-as-tu-choisi-de-parler-de-dependency-track",[34,20069,20070],{},"Elisa : Qu'est-ce qui t’a donné envie de participer au Ch’ti Tremplin ? Pourquoi as-tu choisi de parler de \"Dependency Track\" ?",[19,20072,20073],{},"Depuis que je participe à des conférences tech comme Cloud Nord ou le Devfest, j’ai toujours été admirative des speakers. Leur capacité à captiver une salle, à transmettre leur passion et à rendre des sujets complexes accessibles me fascinait. Mais honnêtement, je me disais que je ne serais jamais capable de faire la même chose. Monter sur scène et parler devant une audience me semblait hors de portée, presque inatteignable.",[19,20075,20076,20077],{},"Quand on m’a présenté le Ch’ti Tremplin et qu’on m’a encouragée à tenter l’aventure, j’ai d’abord hésité. J’avais peur de ne pas être à la hauteur. Mais l’idée que ce concours offrait un cadre bienveillant et un accompagnement m’a rassurée. C’était une chance unique de sortir de ma zone de confort, tout en me sentant soutenue. Alors, je me suis dit : ",[1620,20078,20079],{},"\"Pourquoi pas moi ? Si je ne tente pas maintenant, je ne le ferai jamais.\"",[19,20081,20082],{},"Le choix de parler de Dependency-Track n’a pas été un hasard. J’ai eu la chance de travailler sur la mise en place de cet outil au sein de la forge de développement de Worldline, où il a révolutionné notre manière de gérer la sécurité. Grâce à Dependency-Track, nous avons pu analyser plus de 3 500 applications, détecter des vulnérabilités et prioriser efficacement leur résolution. Ce sujet me tenait particulièrement à cœur, car je sais à quel point la sécurité peut être perçue comme un casse-tête pour les développeurs. Avec cet outil, j’ai vu qu’il était possible de transformer une contrainte en une opportunité d’amélioration, sans friction excessive.",[19,20084,20085],{},"J’ai aussi choisi Dependency-Track pour une raison très pratique : je connaissais bien le sujet ! C’était un projet auquel j’avais directement contribué, ce qui me permettait d’en parler avec naturel, sans avoir à réciter un texte appris par cœur. Je savais que si j’avais le trac sur scène, je pourrais improviser plus facilement, en me basant sur mes propres expériences.",[84,20087,20089],{"id":20088},"elisa-comment-as-tu-vécu-les-semaines-de-coaching-quest-ce-qui-a-été-le-plus-marquant-ou-le-plus-challengeant-pour-toi-dans-cette-préparation",[34,20090,20091],{},"Elisa : Comment as-tu vécu les semaines de coaching ? Qu’est-ce qui a été le plus marquant ou le plus challengeant pour toi dans cette préparation ?",[19,20093,20094],{},"J’ai découvert un monde que je ne connaissais pas : celui de la préparation d’un talk. On ne se rend pas compte du travail qu’il faut pour structurer un message, capter l’attention d’un public et transmettre des idées de manière claire et impactante.\nLes semaines de coaching ont été une expérience à la fois enrichissante et exigeante, elles ont été rythmées par les répétitions en groupes restreints pour avoir des retours constructifs et enrichir ma présentation.",[19,20096,20097],{},"En parallèle, mon coach m’a guidé avec des conseils précieux et des anecdotes issues de son expérience en tant que speaker. Toute cette organisation m’a beaucoup aidé à garder le cap et à prendre confiance en moi pour le jour J.",[19,20099,20100],{},"Le plus challengeant pour moi a été d’adopter un ton plus narratif dans ma présentation. La dernière chose que je souhaitais c’était de présenter mon sujet de manière trop scolaire et ennuyeuse. Parler en public, ce n’est pas juste transmettre des informations, c’est aussi raconter une histoire et donner des idées de réflexion pour que l’audience réagisse et en tire quelque chose. Mon coach m’a aidé à trouver un fil rouge auquel je pourrais aussi me rattacher pendant ma présentation.",[84,20102,20104],{"id":20103},"elisa-quest-ce-que-cette-expérience-ta-apporté-que-ce-soit-sur-le-plan-personnel-ou-professionnel-y-a-t-il-quelque-chose-qui-ta-surprise-dans-ton-propre-parcours",[34,20105,20106],{},"Elisa : Qu’est-ce que cette expérience t’a apporté, que ce soit sur le plan personnel ou professionnel ? Y a-t-il quelque chose qui t’a surprise dans ton propre parcours ?",[19,20108,20109],{},"Participer au Ch’ti Tremplin m’a fait grandir, tant sur le plan personnel que professionnel.",[19,20111,20112],{},"Sur le plan personnel, j’ai gagné en confiance en moi. Je me suis prouvée que je pouvais non seulement partager mes idées devant un public, mais aussi captiver et intéresser des gens avec un sujet qui me tient à cœur.",[19,20114,20115],{},"Sur le plan professionnel, cette expérience a renforcé ma capacité à vulgariser des sujets techniques. Cela m’a aussi ouvert de nouvelles perspectives : aujourd’hui, je me sens plus à l’aise pour participer à d’autres conférences.",[19,20117,20118],{},"Enfin, cette aventure m’a permis de rencontrer des personnes incroyables, toutes animées par l’envie de partager leurs connaissances.",[84,20120,20122],{"id":20121},"elisa-si-tu-devais-donner-un-conseil-à-quelquun-qui-hésite-à-se-lancer-dans-une-aventure-comme-le-chti-tremplin-que-lui-dirais-tu",[34,20123,20124],{},"Elisa : Si tu devais donner un conseil à quelqu’un qui hésite à se lancer dans une aventure comme le Ch’ti Tremplin, que lui dirais-tu ?",[19,20126,20127],{},"Si vous hésitez à participer à une aventure comme le Ch’ti Tremplin, je n’ai qu’un conseil : foncez ! Oui, c’est un défi. Oui, cela demande du travail. Mais les bénéfices que vous en tirerez en valent largement la peine.",[19,20129,20130],{},"Vous n’avez pas besoin d’être parfait⋅e ou \"expert⋅e\" pour vous lancer. Ce qui compte, c’est d’avoir envie de partager quelque chose qui vous tient à cœur. Et surtout, vous ne serez pas seul⋅e. Le cadre bienveillant et l’accompagnement proposé vous aideront à progresser à chaque étape. Le plus dur, c’est de faire le premier pas et d’oser.",[19,20132,20133],{},[176,20134],{"alt":20135,"src":20136},"Elisa, le jour J sur scène à la conférence Cloud Nord","\u002Fcontent-assets\u002F2025-01-28-interview-chti-tremplin\u002Fassets\u002Fimg2.webp",[23,20138,20140],{"id":20139},"retour-dedouard-sur-son-rôle-de-coach","Retour d’Edouard sur son rôle de coach",[84,20142,20144],{"id":20143},"edouard-quest-ce-qui-ta-motivé-à-devenir-coach-pour-le-chti-tremplin-et-quas-tu-pensé-du-sujet-delisa-dependency-track",[34,20145,20146],{},"Edouard : Qu’est-ce qui t’a motivé à devenir coach pour le Ch’ti Tremplin ? Et qu’as-tu pensé du sujet d’Elisa, \"Dependency Track\" ?",[19,20148,20149],{},"J’aime beaucoup accompagner les gens dans la prise de parole car c’est un domaine que j’affectionne particulièrement. Le sujet d’Elisa était l’occasion de remettre en perspective le travail du développeur vis à vis de son outillage. C’est une passerelle parfaite entre le monde du développement et le monde du cloud & devops.",[84,20151,20153],{"id":20152},"edouard-comment-as-tu-accompagné-elisa-dans-la-structuration-de-son-talk-quels-ont-été-selon-toi-les-plus-grands-progrès-quelle-a-réalisés-pendant-ces-semaines",[34,20154,20155],{},"Edouard : Comment as-tu accompagné Elisa dans la structuration de son talk ? Quels ont été, selon toi, les plus grands progrès qu’elle a réalisés pendant ces semaines ?",[19,20157,20158,20159,20162],{},"En réalité, Elisa n’a eu aucune difficulté à définir un plan. Ce qui lui manquait surtout, c’était l’",[1620,20160,20161],{},"histoire",", ce fil conducteur qui permet à l’audience de comprendre le déroulé sans effort et de s’ancrer dans une situation qui peut lui arriver.",[19,20164,20165],{},"L’effort était à mettre sur sa démo live, qui d’après moi était plus importante que ses slides.",[84,20167,20169],{"id":20168},"edouard-quest-ce-que-cette-expérience-ta-apporté-en-tant-que-coach-as-tu-découvert-ou-renforcé-certaines-compétences",[34,20170,20171],{},"Edouard : Qu’est-ce que cette expérience t’a apporté en tant que coach ? As-tu découvert ou renforcé certaines compétences ?",[19,20173,20174],{},"Je dirais que cette expérience va dans la continuité de mon rôle de Head of Craft chez HoppR. J’ai pu transmettre mes connaissances et mes expériences en toute bienveillance et sans chercher à être le coach “héros” que l’on peut voir dans certains films.",[84,20176,20178],{"id":20177},"edouard-quel-conseil-donnerais-tu-à-quelquun-qui-souhaiterait-devenir-coach-pour-une-aventure-comme-le-chti-tremplin",[34,20179,20180],{},"Edouard : Quel conseil donnerais-tu à quelqu’un qui souhaiterait devenir coach pour une aventure comme le Ch’ti Tremplin ?",[19,20182,20183],{},"Pourquoi la personne souhaite elle devenir speaker ? Qu’est-ce qui la satisferait dans l’idée de monter sur scène et de présenter son sujet ?",[19,20185,20186],{},"C’est pour moi des questions fondamentales que doit se poser un speaker, et donc son coach. Grâce à ça, le coach peut accompagner le coaché dans le format de la présentation ainsi que son contenu.",[23,20188,20190],{"id":20189},"alors-quattends-tu-pour-te-lancer",[34,20191,20192],{},"Alors, qu’attends-tu pour te lancer ?",[19,20194,20195],{},"Le Ch’ti Tremplin est une opportunité unique de te préparer à devenir speaker, dans un cadre bienveillant et avec l’accompagnement personnalisé d’un coach dédié. Que tu sois passionné⋅e par le développement logiciel, le DevOps ou le Cloud, ou que tu souhaites simplement partager une idée qui te tient à cœur, ce programme est fait pour toi.",[19,20197,20198,20199,20202,20203,20206],{},"En plus, lors de la soirée finale, le public choisira deux talks qui seront sélectionnés pour le programme de ",[34,20200,20201],{},"DevLille"," les 12 et 13 juin, et un talk qui rejoindra celui de ",[34,20204,20205],{},"Cloud Nord"," en octobre à Euratech. Une belle manière de débuter sur scène devant une audience tech !",[19,20208,20209,20210,20215],{},"Ne réfléchis pas trop longtemps : ",[91,20211,20214],{"href":20212,"rel":20213},"https:\u002F\u002Fforms.gle\u002Fpvgu9tSFGSkumY3B7",[95],"Les candidatures sont ouvertes jusqu’au 15 février",", alors fonce ! 😉",{"title":350,"searchDepth":364,"depth":364,"links":20217},[20218,20224,20230],{"id":20063,"depth":364,"text":20064,"children":20219},[20220,20221,20222,20223],{"id":20067,"depth":370,"text":20070},{"id":20088,"depth":370,"text":20091},{"id":20103,"depth":370,"text":20106},{"id":20121,"depth":370,"text":20124},{"id":20139,"depth":364,"text":20140,"children":20225},[20226,20227,20228,20229],{"id":20143,"depth":370,"text":20146},{"id":20152,"depth":370,"text":20155},{"id":20168,"depth":370,"text":20171},{"id":20177,"depth":370,"text":20180},{"id":20189,"depth":364,"text":20192},"2025-01-28T07:40:21.432Z","Participer à une conférence en tant que speaker peut sembler intimidant, mais c’est aussi une expérience incroyablement enrichissante. C’est précisément pour aider celles et ceux qui souhaitent franch",{},"\u002Fblogs\u002F2025-01-28-interview-chti-tremplin",[20236,20238,20240,20242],{"id":10,"name":11,"image":20237,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20250128%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250128T074021Z&X-Amz-Expires=3600&X-Amz-Signature=c132405c84ba034764ac18052c695cb2b5c280474efac32900cd06e40264f342&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":8035,"name":8036,"image":20239,"linkedin":8038,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F27c18bae-6c33-403c-b7fd-7d46ce96c376\u002FGuillaume_Ferlin_Image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20250128%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250128T074021Z&X-Amz-Expires=3600&X-Amz-Signature=6e0534932218a0bda9f5bdb521380dd6f3927faacdb5c7f73423dc1ec546c3e3&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":5813,"name":5814,"image":20241,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20250128%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250128T074021Z&X-Amz-Expires=3600&X-Amz-Signature=1e352029ec982bf3ae50ae0825535c2478ee301db1bb24cb8aefbda7eddcc66c&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1893,"name":1894,"image":901,"linkedin":901,"x":901},{"title":20031,"description":20232},"blogs\u002F2025-01-28-interview-chti-tremplin\u002Findex",[6607,1879],"6ngSjFnQS_iV5MB8euHxF97OP8U3EoUDXAx3SWTWF5s",{"id":20248,"title":20249,"alt":20250,"authors":20251,"body":20253,"date":21144,"description":21145,"extension":890,"image":891,"meta":21146,"navigation":893,"ogImage":891,"path":21147,"published":893,"reviewers":21148,"seo":21152,"stem":21153,"tags":21154,"__hash__":21157},"blogs\u002Fblogs\u002F2025-01-07-tlchargement-et-gestion-de-packages-npm-avec-bun-et-axios\u002Findex.md","Téléchargement et gestion de packages npm avec Bun et Axios","Image d’illustration représentant un ordinateur téléchargeant et installant, entouré des logos de Bun, npm et Axios",[20252],{"id":1577,"name":1578,"image":1600,"linkedin":1580,"x":901},{"type":16,"value":20254,"toc":21136},[20255,20279,20308,20315,20324,20330,20334,20351,20365,20371,20381,20395,20399,20402,20418,20432,20571,20574,20589,20599,20603,20609,20612,20631,20646,20649,20687,20695,20739,20753,20990,20993,21004,21008,21011,21057,21065,21071,21075,21090,21098,21108,21110,21118,21124,21133],[1003,20256,20257],{},[19,20258,20259,20260,20262,20263,20270,20271,20273,20274],{},"ℹ️ ",[34,20261,5365],{}," Dragee.io a grandi depuis cet article, et est devenu ",[34,20264,20265],{},[91,20266,20269],{"href":20267,"rel":20268},"https:\u002F\u002Fapp.fixentropy.io",[95],"Fixentropy.io",". ",[8072,20272],{},"Vous souhaitez combattre votre entropie logicielle ? N'hésitez pas à ",[91,20275,20278],{"href":20276,"rel":20277},"https:\u002F\u002Fcal.com\u002Fschedule-your-call\u002Fschedule-your-call",[95],"prendre rendez-vous pour une démonstration.",[19,20280,20281,20282,20287,20288,20293,20297,20301,20302,20307],{},"Nouvelle étape pour notre projet ",[91,20283,20286],{"href":20284,"rel":20285},"https:\u002F\u002Fgithub.com\u002Fdragee-io",[95],"Dragee.io",". Nous avons déjà vu ",[91,20289,20292],{"href":20290,"rel":20291},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-11-14-crer-une-cli-pour-un-projet-modulaire-avec-commanderjs",[95],"comment créer ",[91,20294,20296],{"href":20290,"rel":20295},[95],"la ",[91,20298,20300],{"href":20290,"rel":20299},[95],"CLI qui est au cœur du projet",", et également comment ",[91,20303,20306],{"href":20304,"rel":20305},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel",[95],"documenter de manière dynamique nos asserters",", porteurs des règles d’architecture.",[19,20309,20310,20311,20314],{},"C’est un excellent début, mais il manque quand même le point le plus important : maintenant, il s’agit de récupérer et d’installer ces ",[1620,20312,20313],{},"asserters"," en vue de leur utilisation.",[19,20316,20317,20318,20320,20321,20323],{},"En effet, ",[34,20319,20286],{}," a pour mission, entre autres, de nous permettre de vérifier le respect de règles d’architecture au sein de notre projet. Pour cela, des ",[1620,20322,20313],{}," liés à la typologie d’architecture vont entrer en jeu.",[19,20325,20326,20327,20329],{},"Ces ",[1620,20328,20313],{}," ne sont pas directement importés dans la CLI de Dragee, ils sont téléchargés à la volée, au besoin. Et nous allons maintenant nous demander comment.",[23,20331,20333],{"id":20332},"anatomie-dun-asserter-et-extraction-du-namespace","Anatomie d’un asserter et extraction du namespace",[19,20335,20336,20337,20340,20341,20344,20345,20347,20348,20350],{},"Pour rappel, un ",[34,20338,20339],{},"asserter"," est un module comprenant des règles d’architecture. Il est basé sur un ",[34,20342,20343],{},"namespace"," correspondant à une typologie d’architecture (DDD, clean, etc.). A chaque ",[1620,20346,20343],{}," correspond un ",[1620,20349,20339],{}," différent.",[19,20352,20353,20354,20359,20360,44],{},"Dans cet article, nous prendrons pour exemple notre tout premier asserter, ",[91,20355,20358],{"href":20356,"rel":20357},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fddd-asserter",[95],"ddd-asserter",", qui comme son nom l’indique comprend un set de règles concernant le ",[91,20361,20364],{"href":20362,"rel":20363},"https:\u002F\u002Fblog.hoppr.tech\u002Ftags\u002Fddd",[95],"Domain-Driven Design",[19,20366,20367,20368,20370],{},"A la construction d’un rapport d’architecture, notre CLI va détecter le ",[1620,20369,20343],{}," des dragées, et va automatiquement télécharger l’asserter correspondant auprès de npm. Cet asserter va ensuite être installé en local, et leurs règles jouées sur les dragées à analyser.",[1003,20372,20373],{},[19,20374,20375,20376,44],{},"📄 Les règles d’architecture de l’asserter DDD sont disponibles ",[91,20377,20380],{"href":20378,"rel":20379},"https:\u002F\u002Fdragee-vercel-doc.vercel.app\u002Fdocs\u002Fasserters\u002Fddd-asserter\u002F",[95],"sur le site de Dragee",[1003,20382,20383],{},[19,20384,20385,20386,20389,20390,44],{},"📌 Nous avons également des ",[1620,20387,20388],{},"graphers"," (modélisateurs d’architecture) qui sont traités de la même manière, par exemple ",[91,20391,20394],{"href":20392,"rel":20393},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fddd-grapher",[95],"ddd-grapher",[23,20396,20398],{"id":20397},"téléchargement-de-lasserter","Téléchargement de l’asserter",[19,20400,20401],{},"Le téléchargement d’un asserter va se faire via deux appels à l’API npm :",[443,20403,20404,20412],{},[446,20405,20406,20407],{},"Appel de récupération des ",[91,20408,20411],{"href":20409,"rel":20410},"https:\u002F\u002Fgithub.com\u002Fnpm\u002Fregistry\u002Fblob\u002Fmain\u002Fdocs\u002Fresponses\u002Fpackage-metadata.md",[95],"métadonnées sur le package npm",[446,20413,20414,20415,2418],{},"Appel de téléchargement du package (",[1620,20416,20417],{},"tarball",[19,20419,20420,20421,20426,20427,2756,20429,1513],{},"Pour effectuer ces appels, nous allons utiliser ",[91,20422,20425],{"href":20423,"rel":20424},"https:\u002F\u002Faxios-http.com\u002F",[95],"Axios",", un client HTTP travaillant avec des promesses, très simple à utiliser. Ainsi, cela donne, en simplifiant la construction de l’URL d’appel, pour l’",[1620,20428,20339],{},[91,20430,20358],{"href":20356,"rel":20431},[95],[344,20433,20437],{"className":20434,"code":20435,"language":20436,"meta":350,"style":350},"language-typescript shiki shiki-themes github-dark-default","import axios from 'axios';\n\n\u002F\u002F Appel 1 : Métadonnées packages\nconst projectArchiveUrl = 'https:\u002F\u002Fregistry.npmjs.org\u002F@dragee-io\u002Fddd-asserter\u002Flatest';\nconst downloadInfo = await axios.get(projectArchiveUrl, {\n    headers: { Accept: 'application\u002Fjson' }\n});\n\n\u002F\u002F Appel 2 : Téléchargement package\nconst tarball = downloadInfo.data.dist.tarball;\nconst { data } = await axios.get(tarball, {\n    responseType: 'arraybuffer'\n});\n","typescript",[352,20438,20439,20455,20459,20464,20479,20499,20510,20514,20518,20523,20535,20559,20567],{"__ignoreMap":350},[355,20440,20441,20444,20447,20450,20453],{"class":357,"line":358},[355,20442,20443],{"class":2801},"import",[355,20445,20446],{"class":1119}," axios ",[355,20448,20449],{"class":2801},"from",[355,20451,20452],{"class":1138}," 'axios'",[355,20454,17492],{"class":1119},[355,20456,20457],{"class":357,"line":364},[355,20458,1271],{"emptyLinePlaceholder":893},[355,20460,20461],{"class":357,"line":370},[355,20462,20463],{"class":3858},"\u002F\u002F Appel 1 : Métadonnées packages\n",[355,20465,20466,20469,20472,20474,20477],{"class":357,"line":376},[355,20467,20468],{"class":2801},"const",[355,20470,20471],{"class":1264}," projectArchiveUrl",[355,20473,3213],{"class":2801},[355,20475,20476],{"class":1138}," 'https:\u002F\u002Fregistry.npmjs.org\u002F@dragee-io\u002Fddd-asserter\u002Flatest'",[355,20478,17492],{"class":1119},[355,20480,20481,20483,20486,20488,20491,20494,20496],{"class":357,"line":382},[355,20482,20468],{"class":2801},[355,20484,20485],{"class":1264}," downloadInfo",[355,20487,3213],{"class":2801},[355,20489,20490],{"class":2801}," await",[355,20492,20493],{"class":1119}," axios.",[355,20495,3075],{"class":2845},[355,20497,20498],{"class":1119},"(projectArchiveUrl, {\n",[355,20500,20501,20504,20507],{"class":357,"line":1157},[355,20502,20503],{"class":1119},"    headers: { Accept: ",[355,20505,20506],{"class":1138},"'application\u002Fjson'",[355,20508,20509],{"class":1119}," }\n",[355,20511,20512],{"class":357,"line":1165},[355,20513,19211],{"class":1119},[355,20515,20516],{"class":357,"line":1173},[355,20517,1271],{"emptyLinePlaceholder":893},[355,20519,20520],{"class":357,"line":1181},[355,20521,20522],{"class":3858},"\u002F\u002F Appel 2 : Téléchargement package\n",[355,20524,20525,20527,20530,20532],{"class":357,"line":1189},[355,20526,20468],{"class":2801},[355,20528,20529],{"class":1264}," tarball",[355,20531,3213],{"class":2801},[355,20533,20534],{"class":1119}," downloadInfo.data.dist.tarball;\n",[355,20536,20537,20539,20542,20545,20548,20550,20552,20554,20556],{"class":357,"line":1197},[355,20538,20468],{"class":2801},[355,20540,20541],{"class":1119}," { ",[355,20543,20544],{"class":1264},"data",[355,20546,20547],{"class":1119}," } ",[355,20549,2042],{"class":2801},[355,20551,20490],{"class":2801},[355,20553,20493],{"class":1119},[355,20555,3075],{"class":2845},[355,20557,20558],{"class":1119},"(tarball, {\n",[355,20560,20561,20564],{"class":357,"line":1205},[355,20562,20563],{"class":1119},"    responseType: ",[355,20565,20566],{"class":1138},"'arraybuffer'\n",[355,20568,20569],{"class":357,"line":1213},[355,20570,19211],{"class":1119},[19,20572,20573],{},"Les deux appels effectués ici sont :",[443,20575,20576,20583],{},[446,20577,20578,20579],{},"GET ",[91,20580,20581],{"href":20581,"rel":20582},"https:\u002F\u002Fregistry.npmjs.org\u002F@dragee-io\u002Fddd-asserter\u002Flatest",[95],[446,20584,20578,20585],{},[91,20586,20587],{"href":20587,"rel":20588},"https:\u002F\u002Fregistry.npmjs.org\u002F@dragee-io\u002Fddd-asserter\u002F-\u002Fddd-asserter-0.0.2-latest.tgz",[95],[1003,20590,20591],{},[19,20592,20593,20594],{},"📄 Pour plus d’informations sur l’API registry de npm : ",[91,20595,20598],{"href":20596,"rel":20597},"https:\u002F\u002Fgithub.com\u002Fnpm\u002Fregistry\u002Fblob\u002Fmain\u002Fdocs\u002FREGISTRY-API.md",[95],"docs\u002FREGISTRY-API.md",[23,20600,20602],{"id":20601},"vérification-de-lintégrité-du-package","Vérification de l’intégrité du package",[19,20604,20605,20606,20608],{},"Nous avons réussi à télécharger nos ",[1620,20607,20313],{}," distants. Mais rien ne nous dit qu’ils n’aient pas été altérés ou corrompus pendant le process. Il est donc temps d’ajouter une étape de sécurité, et de vérifier l’intégrité de nos packages.",[19,20610,20611],{},"Comme nous l’avons vu plus haut, le téléchargement auprès de npm se fait en deux appels : les métadonnées puis le package. La réponse au premier appel contient les informations nécessaires pour effectuer la vérification.",[19,20613,20614,20615,20620,20621,20624,20625,20630],{},"Plus en détail, ",[91,20616,20619],{"href":20617,"rel":20618},"https:\u002F\u002Fblog.npmjs.org\u002Fpost\u002F172999548390\u002Fnew-pgp-machinery",[95],"npm nous conseille"," d’utiliser un champ nommé ",[1620,20622,20623],{},"integrity",", basée sur la ",[91,20626,20629],{"href":20627,"rel":20628},"https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FSecurity\u002FSubresource_Integrity",[95],"spécification SRI",". Nous allons récupérer cette valeur, une chaîne de caractère encodé en base 64 avec un cryptage SHA512. Exemple avec un de nos asserters :",[344,20632,20636],{"className":20633,"code":20634,"language":20635,"meta":350,"style":350},"language-shell shiki shiki-themes github-dark-default","sha512-xao4irn1WY822p6XcOEUkWfK0U\u002FukIvvn\u002F3lBLJ\u002FA6+d9RpwemKwuxTz5e6QZ8eOvJm17lul08O4v0DY\u002Fmh+rw==\n","shell",[352,20637,20638],{"__ignoreMap":350},[355,20639,20640,20643],{"class":357,"line":358},[355,20641,20642],{"class":2805},"sha512-xao4irn1WY822p6XcOEUkWfK0U\u002FukIvvn\u002F3lBLJ\u002FA6+d9RpwemKwuxTz5e6QZ8eOvJm17lul08O4v0DY\u002Fmh+rw",[355,20644,20645],{"class":1138},"==\n",[19,20647,20648],{},"Recalculons ce hash. Nous pourrions par exemple utiliser cette commande :",[344,20650,20652],{"className":20633,"code":20651,"language":20635,"meta":350,"style":350},"cat [PACKAGE] | openssl dgst -sha512 -binary | openssl base64 -A \n",[352,20653,20654],{"__ignoreMap":350},[355,20655,20656,20659,20662,20665,20668,20671,20674,20677,20679,20681,20684],{"class":357,"line":358},[355,20657,20658],{"class":2805},"cat",[355,20660,20661],{"class":1119}," [PACKAGE] ",[355,20663,20664],{"class":2801},"|",[355,20666,20667],{"class":2805}," openssl",[355,20669,20670],{"class":1138}," dgst",[355,20672,20673],{"class":1264}," -sha512",[355,20675,20676],{"class":1264}," -binary",[355,20678,4874],{"class":2801},[355,20680,20667],{"class":2805},[355,20682,20683],{"class":1138}," base64",[355,20685,20686],{"class":1264}," -A\n",[19,20688,20689,20690,1513],{},"Ou alors, avec l’outil ",[91,20691,20694],{"href":20692,"rel":20693},"https:\u002F\u002Ffr.linux-console.net\u002F?p=15125",[95],"shasum",[344,20696,20698],{"className":20633,"code":20697,"language":20635,"meta":350,"style":350},"shasum -b -a 512 [PACKAGE] | awk '{ print $1 }' | xxd -r -p | base64\n",[352,20699,20700],{"__ignoreMap":350},[355,20701,20702,20704,20707,20710,20713,20715,20717,20720,20723,20725,20728,20731,20734,20736],{"class":357,"line":358},[355,20703,20694],{"class":2805},[355,20705,20706],{"class":1264}," -b",[355,20708,20709],{"class":1264}," -a",[355,20711,20712],{"class":1264}," 512",[355,20714,20661],{"class":1119},[355,20716,20664],{"class":2801},[355,20718,20719],{"class":2805}," awk",[355,20721,20722],{"class":1138}," '{ print $1 }'",[355,20724,4874],{"class":2801},[355,20726,20727],{"class":2805}," xxd",[355,20729,20730],{"class":1264}," -r",[355,20732,20733],{"class":1264}," -p",[355,20735,4874],{"class":2801},[355,20737,20738],{"class":2805}," base64\n",[19,20740,20741,20742,20747,20748,1513],{},"Et nous obtenons le même résultat, sous réserve que le package soit valide. Maintenant, en TypeScript dans notre projet ",[91,20743,20746],{"href":20744,"rel":20745},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-package-installer\u002Fblob\u002Fmain\u002Fsrc\u002Fservices\u002Fproject.service.ts",[95],"dragee-package-installer",", et grâce au module ",[91,20749,20752],{"href":20750,"rel":20751},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Fcrypto.html",[95],"crypto de Node",[344,20754,20756],{"className":20434,"code":20755,"language":20436,"meta":350,"style":350},"import { hash } from 'node:crypto';\n\nconst generateChecksumFile = (fileName: string, algorithm: string): string => {\n    const fileData = readFileSync(fileName);\n    return hash(algorithm, fileData, 'base64');\n};\n\nexport const controlPackageIntegrity = (\n    downloadDataIntegrity: string, filePath: string, projectName: string\n) => {\n    const [algorithm, integrity] = downloadDataIntegrity.split('-');\n    const generatedChecksum = generateChecksumFile(filePath, algorithm);\n    if (generatedChecksum !== integrity)\n        throw Error(`Could not verify ${projectName} package integrity`);\n};\n",[352,20757,20758,20772,20776,20815,20831,20846,20851,20855,20870,20898,20907,20938,20952,20966,20986],{"__ignoreMap":350},[355,20759,20760,20762,20765,20767,20770],{"class":357,"line":358},[355,20761,20443],{"class":2801},[355,20763,20764],{"class":1119}," { hash } ",[355,20766,20449],{"class":2801},[355,20768,20769],{"class":1138}," 'node:crypto'",[355,20771,17492],{"class":1119},[355,20773,20774],{"class":357,"line":364},[355,20775,1271],{"emptyLinePlaceholder":893},[355,20777,20778,20780,20783,20785,20787,20790,20792,20795,20797,20800,20802,20804,20806,20808,20810,20813],{"class":357,"line":370},[355,20779,20468],{"class":2801},[355,20781,20782],{"class":2845}," generateChecksumFile",[355,20784,3213],{"class":2801},[355,20786,494],{"class":1119},[355,20788,20789],{"class":2805},"fileName",[355,20791,19675],{"class":2801},[355,20793,20794],{"class":1264}," string",[355,20796,504],{"class":1119},[355,20798,20799],{"class":2805},"algorithm",[355,20801,19675],{"class":2801},[355,20803,20794],{"class":1264},[355,20805,2418],{"class":1119},[355,20807,19675],{"class":2801},[355,20809,20794],{"class":1264},[355,20811,20812],{"class":2801}," =>",[355,20814,3031],{"class":1119},[355,20816,20817,20820,20823,20825,20828],{"class":357,"line":376},[355,20818,20819],{"class":2801},"    const",[355,20821,20822],{"class":1264}," fileData",[355,20824,3213],{"class":2801},[355,20826,20827],{"class":2845}," readFileSync",[355,20829,20830],{"class":1119},"(fileName);\n",[355,20832,20833,20835,20838,20841,20844],{"class":357,"line":382},[355,20834,3242],{"class":2801},[355,20836,20837],{"class":2845}," hash",[355,20839,20840],{"class":1119},"(algorithm, fileData, ",[355,20842,20843],{"class":1138},"'base64'",[355,20845,3048],{"class":1119},[355,20847,20848],{"class":357,"line":1157},[355,20849,20850],{"class":1119},"};\n",[355,20852,20853],{"class":357,"line":1165},[355,20854,1271],{"emptyLinePlaceholder":893},[355,20856,20857,20860,20863,20866,20868],{"class":357,"line":1173},[355,20858,20859],{"class":2801},"export",[355,20861,20862],{"class":2801}," const",[355,20864,20865],{"class":2845}," controlPackageIntegrity",[355,20867,3213],{"class":2801},[355,20869,16690],{"class":1119},[355,20871,20872,20875,20877,20879,20881,20884,20886,20888,20890,20893,20895],{"class":357,"line":1181},[355,20873,20874],{"class":2805},"    downloadDataIntegrity",[355,20876,19675],{"class":2801},[355,20878,20794],{"class":1264},[355,20880,504],{"class":1119},[355,20882,20883],{"class":2805},"filePath",[355,20885,19675],{"class":2801},[355,20887,20794],{"class":1264},[355,20889,504],{"class":1119},[355,20891,20892],{"class":2805},"projectName",[355,20894,19675],{"class":2801},[355,20896,20897],{"class":1264}," string\n",[355,20899,20900,20902,20905],{"class":357,"line":1189},[355,20901,16968],{"class":1119},[355,20903,20904],{"class":2801},"=>",[355,20906,3031],{"class":1119},[355,20908,20909,20911,20914,20916,20918,20920,20923,20925,20928,20931,20933,20936],{"class":357,"line":1197},[355,20910,20819],{"class":2801},[355,20912,20913],{"class":1119}," [",[355,20915,20799],{"class":1264},[355,20917,504],{"class":1119},[355,20919,20623],{"class":1264},[355,20921,20922],{"class":1119},"] ",[355,20924,2042],{"class":2801},[355,20926,20927],{"class":1119}," downloadDataIntegrity.",[355,20929,20930],{"class":2845},"split",[355,20932,2169],{"class":1119},[355,20934,20935],{"class":1138},"'-'",[355,20937,3048],{"class":1119},[355,20939,20940,20942,20945,20947,20949],{"class":357,"line":1205},[355,20941,20819],{"class":2801},[355,20943,20944],{"class":1264}," generatedChecksum",[355,20946,3213],{"class":2801},[355,20948,20782],{"class":2845},[355,20950,20951],{"class":1119},"(filePath, algorithm);\n",[355,20953,20954,20957,20960,20963],{"class":357,"line":1213},[355,20955,20956],{"class":2801},"    if",[355,20958,20959],{"class":1119}," (generatedChecksum ",[355,20961,20962],{"class":2801},"!==",[355,20964,20965],{"class":1119}," integrity)\n",[355,20967,20968,20971,20974,20976,20979,20981,20984],{"class":357,"line":1221},[355,20969,20970],{"class":2801},"        throw",[355,20972,20973],{"class":2845}," Error",[355,20975,2169],{"class":1119},[355,20977,20978],{"class":1138},"`Could not verify ${",[355,20980,20892],{"class":1119},[355,20982,20983],{"class":1138},"} package integrity`",[355,20985,3048],{"class":1119},[355,20987,20988],{"class":357,"line":1229},[355,20989,20850],{"class":1119},[19,20991,20992],{},"Nous pouvons ainsi vérifier le checksum et l’intégrité du package téléchargé, avant de l’extraire et de l’installer.",[1003,20994,20995],{},[19,20996,20997,20998,21000,21001,21003],{},"📌 Bien entendu, si l’",[1620,20999,20339],{}," est déjà téléchargé et installé, la CLI le détecte et saute toutes ces étapes. Nous parlerons de la mise à jour des ",[1620,21002,20313],{}," installés dans un autre article à paraître.",[23,21005,21007],{"id":21006},"extraction-et-installation","Extraction et installation",[19,21009,21010],{},"Notre package étant maintenant téléchargé et sûr, nous allons pouvoir en extraire l’asserter et l’installer. Pour ce faire, nous allons passer par plusieurs étapes :",[443,21012,21013,21021,21029,21042,21050],{},[446,21014,21015,21016],{},"Lecture du tarball en Buffer grâce à ",[91,21017,21020],{"href":21018,"rel":21019},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Ffs.html#fsreadfilesyncpath-options",[95],"Node:fs",[446,21022,21023,21024,44],{},"Extraction du package avec  ",[91,21025,21028],{"href":21026,"rel":21027},"https:\u002F\u002Fgithub.com\u002Fisaacs\u002Fnode-tar",[95],"node-tar",[446,21030,21031,21032,21037,21038,21041],{},"Écriture des fichiers grâce à l’",[91,21033,21036],{"href":21034,"rel":21035},"https:\u002F\u002Fbun.sh\u002Fguides\u002Fwrite-file\u002Fbasic",[95],"API Bun"," dans un dossier ",[1620,21039,21040],{},"registry"," en local",[446,21043,21044,21045],{},"Installation des dépendances de l’asserter avec ",[91,21046,21049],{"href":21047,"rel":21048},"https:\u002F\u002Fbun.sh\u002Fdocs\u002Fcli\u002Finstall",[95],"Bun install",[446,21051,21052,21053],{},"Suppression du tarball via ",[91,21054,21020],{"href":21055,"rel":21056},"https:\u002F\u002Fnodejs.org\u002Fapi\u002Ffs.html#fsunlinkpath-callback",[95],[19,21058,21059,21060,21064],{},"Il n’y a maintenant plus qu’à importer l’asserter installé. C’est ici que le travail de notre projet ",[91,21061,20746],{"href":21062,"rel":21063},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-package-installer",[95]," se termine, en renvoyant l’asserter importé à la CLI.",[19,21066,21067],{},[176,21068],{"alt":21069,"src":21070},"Process des asserters dans Dragee.io, composé des différentes étapes : détection namespace, téléchargement, validation de l’intégrité, extraction, installation, import et utilisation","\u002Fcontent-assets\u002F2025-01-07-tlchargement-et-gestion-de-packages-npm-avec-bun-et-axios\u002Fassets\u002Fimg1.webp",[23,21072,21074],{"id":21073},"utilisation-des-assertersgraphers","Utilisation des asserters\u002Fgraphers",[19,21076,21077,21078,21080,21081,21086,21087,21089],{},"Les ",[1620,21079,20313],{}," téléchargés et installés, ils sont donc importés dynamiquement dans notre CLI. Ces modules reposent tous sur la même structure, grâce au package ",[91,21082,21085],{"href":21083,"rel":21084},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-model",[95],"dragee-model",". Celui-ci contient toutes les définitions de type des ",[1620,21088,20313],{},", règles, dragées, etc.",[19,21091,21092,21093,44],{},"Une fonction, elle aussi importée de ce package, va nous permettre de traiter les asserters de manière générique : la bien nommée ",[91,21094,21097],{"href":21095,"rel":21096},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-model\u002Fblob\u002Fmain\u002Fasserter\u002Findex.ts#L117",[95],"asserterHandler",[19,21099,21100,21101,21104,21105,44],{},"C’est l’avantage de ce fonctionnement se basant sur des types et fonctions mises en commun par ",[91,21102,21085],{"href":21083,"rel":21103},[95],". La CLI peut ainsi utiliser n’importe quel asserter validé, demandé par les dragées et répondant aux pré-requis du type ",[1620,21106,21107],{},"Asserter",[23,21109,1528],{"id":1527},[19,21111,21112,21113,21115,21116,44],{},"Notre projet ",[34,21114,20286],{}," continue de grandir. Correctement documenté et construit, il est à présent parfaitement capable, grâce à sa CLI et son package idoine, de télécharger, installer et utiliser nos ",[1620,21117,20313],{},[19,21119,21120,21121,21123],{},"Le process mis en place nous permet d’effectuer toutes ces actions, de manière souple et sécurisée. Et nul besoin de préciser quel ",[1620,21122,20339],{}," utiliser, la CLI se charge de le détecter. Toutes ces actions sont effectuées de manière invisible pour les utilisateurs. Ainsi, cette analyse est extrêmement simple à mettre en place pour les dragées issues d’un projet.",[19,21125,21126,21127,21132],{},"N’hésitez pas à consulter ",[91,21128,21131],{"href":21129,"rel":21130},"https:\u002F\u002Fblog.hoppr.tech\u002Ftags\u002FDragee.io",[95],"les autres articles en lien avec Dragee.io",", pour découvrir d’autres solutions techniques à des problématiques posées lors de son développement, et voir avec nous ce beau projet grandir.",[856,21134,21135],{},"html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .sc3cj, html code.shiki .sc3cj{--shiki-default:#D2A8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}",{"title":350,"searchDepth":364,"depth":364,"links":21137},[21138,21139,21140,21141,21142,21143],{"id":20332,"depth":364,"text":20333},{"id":20397,"depth":364,"text":20398},{"id":20601,"depth":364,"text":20602},{"id":21006,"depth":364,"text":21007},{"id":21073,"depth":364,"text":21074},{"id":1527,"depth":364,"text":1528},"2025-01-07T08:45:19.283Z","Nouvelle étape pour notre projet [Dragee.io](https:\u002F\u002Fgithub.com\u002Fdragee-io). Nous avons déjà vu [comment créer ](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-11-14-crer-une-cli-pour-un-projet-modulaire-avec-comm",{},"\u002Fblogs\u002F2025-01-07-tlchargement-et-gestion-de-packages-npm-avec-bun-et-axios",[21149,21151],{"id":5813,"name":5814,"image":21150,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20250107%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20250107T084519Z&X-Amz-Expires=3600&X-Amz-Signature=4b8e375ee06970c61e404297e625978693bb7ea11b1b0eda1ef1896feea745d0&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":8035,"name":8036,"image":901,"linkedin":8038,"x":901},{"title":20249,"description":21145},"blogs\u002F2025-01-07-tlchargement-et-gestion-de-packages-npm-avec-bun-et-axios\u002Findex",[20436,1879,21155,21156],"fixentropy.io","dragee.io","8epbcjTyiwgVmkdOrTiArtR_Gy4GXaZaQQrfFVUHRgo",{"id":21159,"title":21160,"alt":21161,"authors":21162,"body":21165,"date":21418,"description":21419,"extension":890,"image":891,"meta":21420,"navigation":893,"ogImage":891,"path":21421,"published":893,"reviewers":21422,"seo":21427,"stem":21428,"tags":21429,"__hash__":21431},"blogs\u002Fblogs\u002F2024-12-11-low-carbon-dans-le-cloud-partie-3\u002Findex.md","Low Carbon dans le Cloud - Partie 3","Error 404. This is not green enough",[21163],{"id":18862,"name":18863,"image":21164,"linkedin":18865,"x":901},".\u002Fassets\u002Fauthor-samuel-bally.webp",{"type":16,"value":21166,"toc":21398},[21167,21181,21185,21188,21199,21205,21211,21216,21222,21225,21229,21232,21243,21249,21255,21260,21266,21269,21272,21275,21281,21287,21292,21297,21300,21314,21317,21320,21326,21338,21349,21353,21360,21370,21376,21379,21386,21388,21395],[19,21168,19429,21169,21174,21175,21180],{},[91,21170,21173],{"href":21171,"rel":21172},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-1",[95],"première partie"," abordait les concepts GreenOps et la ",[91,21176,21179],{"href":21177,"rel":21178},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-2",[95],"seconde partie"," les méthodes pour mesurer votre production de gaz à effet de serre. Dans cet article nous allons aborder les architectures Cloud Green. Nous allons donc rentrer dans des méthodes d’amélioration concrète. Pour cela, il faut comprendre les facteurs clés à prendre en compte.",[23,21182,21184],{"id":21183},"les-3-facteurs-clés-de-larchitecture-cloud-green","Les 3 facteurs clés de l’architecture Cloud Green",[19,21186,21187],{},"L'architecture Cloud Green repose sur l'optimisation des ressources pour minimiser l'impact environnemental tout en maintenant des performances élevées. Il ne faut pas tomber dans la pauvreté numérique mais dans une certaine forme de sobriété saine. Parmi les piliers de cette approche, trois facteurs jouent un rôle essentiel :",[443,21189,21190,21193,21196],{},[446,21191,21192],{},"La répartition géographique où sont hébergés vos services Cloud (ou le type de source d’énergie pour les sites véritablement autonomes)",[446,21194,21195],{},"Le moment où une charge de travail est exécutée (par exemple je génère mon modèle IA à 11H)",[446,21197,21198],{},"La répartition de la charge de travail dans le temps.",[23,21200,21202],{"id":21201},"spatial-shifting-optimisation-géographique",[34,21203,21204],{},"Spatial Shifting : Optimisation Géographique",[19,21206,21207],{},[176,21208],{"alt":21209,"src":21210},"Spatial Shifting","\u002Fcontent-assets\u002F2024-12-11-low-carbon-dans-le-cloud-partie-3\u002Fassets\u002Fimg1.webp",[19,21212,5381,21213,21215],{},[1620,21214,21209],{}," consiste à exploiter les ressources cloud disponibles dans différentes régions géographiques pour minimiser l’impact environnemental. Bonne nouvelle, les principaux Cloud Providers proposent plusieurs régions (exemple: Paris, Dublin, Hong Kong, Stockholm, ...).",[84,21217,21219],{"id":21218},"comment-ça-fonctionne",[34,21220,21221],{},"Comment ça fonctionne ?",[19,21223,21224],{},"Les fournisseurs cloud opèrent dans des zones ayant des mix énergétiques différents. Comme vu dans l’article précédent, un centre de données en Norvège, alimenté principalement par des énergies renouvelables, a une empreinte carbone bien moindre qu’un centre situé dans une région dépendant du charbon. En redirigeant les charges de travail vers des régions avec une énergie plus verte, il est possible de réduire considérablement les émissions.",[84,21226,21228],{"id":21227},"mon-retour-dexpérience","Mon retour d’expérience",[19,21230,21231],{},"Je considère qu’il s’agit du meilleur facteur d’optimisation possible si nous partons d’un pays qui ne propose ni énergie verte, ni nucléaire. Les gains de CO2 peuvent atteindre les 1 000%. Cependant, il faut prendre en compte des effets de bord importants :",[443,21233,21234,21237,21240],{},[446,21235,21236],{},"Une migration peut être complexe surtout si nous ne sommes pas sur de l’infrastructure as code",[446,21238,21239],{},"Le prix des services cloud change en fonction de la région, la différence peut être de l’ordre de 20%",[446,21241,21242],{},"Il faut prendre en compte les performances si nous nous éloignons des utilisateurs (par exemple : une application pour la Pologne avec des services hébergés en France).",[23,21244,21246],{"id":21245},"temporal-shifting-exploitation-des-fenêtres-de-temps",[34,21247,21248],{},"Temporal Shifting : Exploitation des Fenêtres de Temps",[19,21250,21251],{},[176,21252],{"alt":21253,"src":21254},"Temporal Shifting","\u002Fcontent-assets\u002F2024-12-11-low-carbon-dans-le-cloud-partie-3\u002Fassets\u002Fimg2.webp",[19,21256,5381,21257,21259],{},[1620,21258,21253],{}," consiste à planifier les charges de travail pour qu’elles s’exécutent aux moments où l’énergie renouvelable est la plus abondante.",[84,21261,21263],{"id":21262},"pourquoi-est-ce-efficace",[34,21264,21265],{},"Pourquoi est-ce efficace ?",[19,21267,21268],{},"La disponibilité d’énergie renouvelable fluctue en fonction de l’heure et des conditions météorologiques. Par exemple, l’énergie solaire est abondante en journée, tandis que l’éolienne peut être plus efficace la nuit. En ajustant les horaires d’utilisation des services Cloud, nous pouvons optimiser la consommation énergétique et en corrélation la production de gaz à effet de serre.",[84,21270,21228],{"id":21271},"mon-retour-dexpérience-1",[19,21273,21274],{},"Il s’agit d’un excellent moyen de gérer des tâches récurrentes comme les sauvegardes ou la mise à jour de son modèle IA. Malheureusement, cette méthode d’architecture Green n’est pas adaptée aux énergies non renouvelables ni à tous nos besoins.",[23,21276,21278],{"id":21277},"demand-shifting-ajustement-de-la-demande",[34,21279,21280],{},"Demand Shifting : Ajustement de la Demande",[19,21282,21283],{},[176,21284],{"alt":21285,"src":21286},"Demand Shifting","\u002Fcontent-assets\u002F2024-12-11-low-carbon-dans-le-cloud-partie-3\u002Fassets\u002Fimg3.webp",[19,21288,5381,21289,21291],{},[1620,21290,21285],{}," vise à réduire ou à redistribuer la demande en fonction de la disponibilité des ressources et de l’impact énergétique.",[84,21293,21295],{"id":21294},"comment-ça-fonctionne-1",[34,21296,21221],{},[19,21298,21299],{},"Nous savons pertinemment que nous ne pouvons pas mettre en pause une fission nucléaire et que nous ne pouvons pas stocker l’excédant d’énergie produit la nuit. Dans la philosophie du Demand Shifting, nous sommes assez proche des tarifs heures pleine heure creuse d’EDF. Voici, 2 situations plus parlantes:",[443,21301,21302,21308],{},[446,21303,21304,21307],{},[34,21305,21306],{},"Étalement de la charge"," : Répartir les traitements sur plusieurs périodes pour éviter les pics de demande.",[446,21309,21310,21313],{},[34,21311,21312],{},"Gestion des utilisateurs"," : Encourager les utilisateurs finaux à consommer des ressources à des moments spécifiques grâce à des incitations (comme des tarifs réduits).",[84,21315,21228],{"id":21316},"mon-retour-dexpérience-2",[19,21318,21319],{},"C’est certainement la méthode la plus impactante pour les usagers et sa mise en œuvre demande de sortir de l’aspect purement technique.",[23,21321,21323],{"id":21322},"limpact-combiné-des-3-facteurs",[34,21324,21325],{},"L’Impact Combiné des 3 Facteurs",[19,21327,21328,21329,21331,21332,21334,21335,21337],{},"En combinant le ",[1620,21330,21209],{},", le ",[1620,21333,21253],{}," et le ",[1620,21336,21285],{},", il est possible d’atteindre un niveau d’efficacité encore plus important en profitant de l’effet de synergie. En résumé, ces stratégies permettent :",[443,21339,21340,21343,21346],{},[446,21341,21342],{},"Une réduction significative de l’empreinte carbone et potentiellement des coûts.",[446,21344,21345],{},"Une meilleure résilience de vos applications grâce à une répartition dynamique des charges d’utilisation des services Cloud.",[446,21347,21348],{},"Une contribution active aux objectifs de durabilité de votre entreprise (RSE).",[23,21350,21352],{"id":21351},"aller-plus-loin-dans-léco-cloud-native-avec-le-serverless","Aller plus loin dans l’éco-Cloud-Native avec le Serverless",[19,21354,21355,21356,21359],{},"L’adoption du ",[34,21357,21358],{},"Serverless,"," comme principale architecture de vos projets, apparaît comme une solution intéressante. En effet, le modèle Serverless, en permettant de consommer des ressources uniquement lorsqu’elles sont nécessaires (à la seconde près), réduit le gaspillage énergétique et d’optimiser les coûts.",[19,21361,21362,21363,21331,21365,21334,21367],{},"De plus, les architectures Serverless sont compatibles avec le ",[34,21364,21209],{},[34,21366,21253],{},[34,21368,21369],{},"Demand Shifting.",[19,21371,21372],{},[176,21373],{"alt":21374,"src":21375},"https:\u002F\u002Faws.amazon.com\u002Ffr\u002Fserverless\u002F","\u002Fcontent-assets\u002F2024-12-11-low-carbon-dans-le-cloud-partie-3\u002Fassets\u002Fimg4.webp",[84,21377,21228],{"id":21378},"mon-retour-dexpérience-3",[19,21380,21381,21382,21385],{},"Il est important de souligner que cette architecture est complexe à gérer à grande échelle. Un projet de 300 fonctions interdépendantes imposera beaucoup de contraintes. Il est possible d’introduire le Serverless dans vos projets en le mixant avec une architecture plus courante comme du Kubernetes. Le ",[34,21383,21384],{},"Function as a Service"," s’associe bien avec une approche Frontend ou des tâches récurrentes. Nous vous proposerons un article complet sur le Serverless prochainement sur notre blog.",[23,21387,1528],{"id":1527},[19,21389,21390,21391,21394],{},"Vous avez maintenant quelques exemples de démarches green pour agir avec vos applications dans le Cloud. Il ne faudra pas oublier de mettre en place des KPI et une Observabilité Green pour aller au bout de votre projet. Pour cela, je vous conseille de lire la ",[91,21392,21179],{"href":21177,"rel":21393},[95]," de notre article.",[19,21396,21397],{},"Il existe bien sûr d’autres mécanismes permettant d’améliorer vos architectures Cloud que nous aborderons dans un autre volet.",{"title":350,"searchDepth":364,"depth":364,"links":21399},[21400,21401,21405,21409,21413,21414,21417],{"id":21183,"depth":364,"text":21184},{"id":21201,"depth":364,"text":21204,"children":21402},[21403,21404],{"id":21218,"depth":370,"text":21221},{"id":21227,"depth":370,"text":21228},{"id":21245,"depth":364,"text":21248,"children":21406},[21407,21408],{"id":21262,"depth":370,"text":21265},{"id":21271,"depth":370,"text":21228},{"id":21277,"depth":364,"text":21280,"children":21410},[21411,21412],{"id":21294,"depth":370,"text":21221},{"id":21316,"depth":370,"text":21228},{"id":21322,"depth":364,"text":21325},{"id":21351,"depth":364,"text":21352,"children":21415},[21416],{"id":21378,"depth":370,"text":21228},{"id":1527,"depth":364,"text":1528},"2024-12-11T16:34:44.847Z","La [première partie](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-1) abordait les concepts GreenOps et la [seconde partie](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-09-26-low-carb",{},"\u002Fblogs\u002F2024-12-11-low-carbon-dans-le-cloud-partie-3",[21423,21425],{"id":10,"name":11,"image":21424,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20241211%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241211T163444Z&X-Amz-Expires=3600&X-Amz-Signature=c9d6d6801859737747500b04eb94e511aed919049c4069983d15148b541edf61&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1577,"name":1578,"image":21426,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20241211%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241211T163444Z&X-Amz-Expires=3600&X-Amz-Signature=3eab78f42c8c71eff9464a07870eca0de30b713c29b80df6745642226f3a3ba3&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":21160,"description":21419},"blogs\u002F2024-12-11-low-carbon-dans-le-cloud-partie-3\u002Findex",[21430,907,906,905],"green","qY2gRx9hbZB1kD2tEj0Q1ja_rogKcmzkAbeeBwJ6oMM",{"id":21433,"title":21434,"alt":21435,"authors":21436,"body":21438,"date":21860,"description":21861,"extension":890,"image":891,"meta":21862,"navigation":893,"ogImage":891,"path":21863,"published":893,"reviewers":21864,"seo":21871,"stem":21872,"tags":21873,"__hash__":21874},"blogs\u002Fblogs\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel\u002Findex.md","Génération, agrégation et déploiement de documentation TSDoc avec Docusaurus et Vercel","Page de documentation Dragee.io en fond, avec les logos de Docusaurus, Bun et Vercel",[21437],{"id":1577,"name":1578,"image":1600,"linkedin":1580,"x":901},{"type":16,"value":21439,"toc":21853},[21440,21456,21467,21473,21483,21486,21497,21500,21504,21507,21521,21620,21629,21638,21644,21648,21656,21664,21670,21720,21728,21732,21739,21748,21754,21761,21774,21780,21787,21791,21799,21802,21808,21814,21820,21827,21830,21832,21842,21845,21850],[1003,21441,21442],{},[19,21443,20259,21444,20262,21446,20270,21451,20273,21453],{},[34,21445,5365],{},[34,21447,21448],{},[91,21449,20269],{"href":20267,"rel":21450},[95],[8072,21452],{},[91,21454,20278],{"href":20276,"rel":21455},[95],[19,21457,21458,21459,21463,21464,44],{},"Suite à l’article ",[91,21460,21462],{"href":20290,"rel":21461},[95],"Créer une CLI pour un projet modulaire avec Commander.js",", nous avons maintenant une CLI efficace et fiable pour notre projet ",[91,21465,20286],{"href":20284,"rel":21466},[95],[19,21468,21469,21470,21472],{},"Nous pouvons grâce à elle écrire nos ",[1620,21471,20313],{}," facilement, et les règles d’architecture qui y sont associées, ce qui nous permettra d’analyser le respect de ces règles par un projet à tester.",[19,21474,21475,21476,21479,21480,21482],{},"Cependant, à l’image de n’importe quel ",[1620,21477,21478],{},"linter",", il nous devient nécessaire d’avoir un descriptif de chaque règle et comment la respecter. De plus, nous souhaiterions avoir un catalogue référentiel des ",[1620,21481,20313],{}," et règles qui existent, en plus d’une documentation générale sur le projet Dragee.",[19,21484,21485],{},"Nous avons besoin que ce catalogue soit :",[443,21487,21488,21491,21494],{},[446,21489,21490],{},"dynamique (1 commit ⇒ 1 déploiement)",[446,21492,21493],{},"facile à paramétrer et personnaliser",[446,21495,21496],{},"s’adapte facilement à des modifications sur n’importe quelle règle. Hors de question de venir modifier un site à la main à chaque nouvelle version de notre asserter DDD !",[19,21498,21499],{},"Creusons alors le sujet.",[23,21501,21503],{"id":21502},"documentation-tsdoctypedoc","Documentation TSDoc\u002FTypeDoc",[19,21505,21506],{},"Quel est le meilleur endroit pour poser de la documentation sur une règle donnée ? Dans le code, en commentaire de la dite règle.",[19,21508,21509,21510,21515,21516,1513],{},"Nous allons nous appuyer sur le standard de documentation ",[91,21511,21514],{"href":21512,"rel":21513},"https:\u002F\u002Ftsdoc.org\u002F",[95],"TSDoc"," pour TypeScript. Voici un exemple, sur ",[91,21517,21520],{"href":21518,"rel":21519},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fddd-asserter\u002Fblob\u002Fmain\u002Fsrc\u002Frules\u002Faggregates-allowed-dependencies.rule.ts",[95],"une des règles de notre asserter DDD",[344,21522,21524],{"className":20434,"code":21523,"language":20436,"meta":350,"style":350},"\u002F**\n * **aggregates-allowed-dependencies :**\n * Aggregates can only have dependencies of types \"ddd\u002Fvalue_object\", \"ddd\u002Fentity\" and \"ddd\u002Fevent\"\n *\n * ## Examples\n * Example of incorrect dragees for this rule:\n * ```json\n * {\n *     \"name\": \"AService\",\n *     \"profile\": \"ddd\u002Fservice\"\n * },\n\n...\n\n *\n * @module Aggregates Allowed Dependencies\n *\n *\u002F\n",[352,21525,21526,21531,21536,21541,21545,21550,21555,21560,21565,21570,21575,21580,21584,21589,21593,21597,21611,21615],{"__ignoreMap":350},[355,21527,21528],{"class":357,"line":358},[355,21529,21530],{"class":3858},"\u002F**\n",[355,21532,21533],{"class":357,"line":364},[355,21534,21535],{"class":3858}," * **aggregates-allowed-dependencies :**\n",[355,21537,21538],{"class":357,"line":370},[355,21539,21540],{"class":3858}," * Aggregates can only have dependencies of types \"ddd\u002Fvalue_object\", \"ddd\u002Fentity\" and \"ddd\u002Fevent\"\n",[355,21542,21543],{"class":357,"line":376},[355,21544,17483],{"class":3858},[355,21546,21547],{"class":357,"line":382},[355,21548,21549],{"class":3858}," * ## Examples\n",[355,21551,21552],{"class":357,"line":1157},[355,21553,21554],{"class":3858}," * Example of incorrect dragees for this rule:\n",[355,21556,21557],{"class":357,"line":1165},[355,21558,21559],{"class":3858}," * ```json\n",[355,21561,21562],{"class":357,"line":1173},[355,21563,21564],{"class":3858}," * {\n",[355,21566,21567],{"class":357,"line":1181},[355,21568,21569],{"class":3858}," *     \"name\": \"AService\",\n",[355,21571,21572],{"class":357,"line":1189},[355,21573,21574],{"class":3858}," *     \"profile\": \"ddd\u002Fservice\"\n",[355,21576,21577],{"class":357,"line":1197},[355,21578,21579],{"class":3858}," * },\n",[355,21581,21582],{"class":357,"line":1205},[355,21583,1271],{"emptyLinePlaceholder":893},[355,21585,21586],{"class":357,"line":1213},[355,21587,21588],{"class":3858},"...\n",[355,21590,21591],{"class":357,"line":1221},[355,21592,1271],{"emptyLinePlaceholder":893},[355,21594,21595],{"class":357,"line":1229},[355,21596,17483],{"class":3858},[355,21598,21599,21602,21605,21608],{"class":357,"line":1237},[355,21600,21601],{"class":3858}," * ",[355,21603,21604],{"class":2801},"@module",[355,21606,21607],{"class":2805}," Aggregates",[355,21609,21610],{"class":3858}," Allowed Dependencies\n",[355,21612,21613],{"class":357,"line":1245},[355,21614,17483],{"class":3858},[355,21616,21617],{"class":357,"line":1256},[355,21618,21619],{"class":3858}," *\u002F\n",[19,21621,21622,21623,21628],{},"Vous pouvez ici noter que nous sommes partis sur un commentaire écrit en ",[91,21624,21627],{"href":21625,"rel":21626},"https:\u002F\u002Fwww.markdownguide.org\u002Fgetting-started\u002F",[95],"Markdown",", souple, efficace, facilement lisible ici et nous permettant d’utiliser TypeDoc (et Docusaurus) ensuite.",[19,21630,21631,21632,21637],{},"En local dans le projet de l’asserter, nous avons pu installer l’outil ",[91,21633,21636],{"href":21634,"rel":21635},"https:\u002F\u002Ftypedoc.org\u002F",[95],"TypeDoc"," nous permettant de générer du HTML grâce à ces commentaires. Cela nous donne un premier résultat intéressant, mais encore peu souple et surtout uniquement dédié au projet en cours.",[19,21639,21640],{},[176,21641],{"alt":21642,"src":21643},"Capture d’écran de la documentation d’un asserter, générée en HTML par TypeDoc.","\u002Fcontent-assets\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel\u002Fassets\u002Fimg1.webp",[23,21645,21647],{"id":21646},"git-submodules","Git submodules",[19,21649,21650,21651,21655],{},"Nous avons créé un nouveau projet, ",[91,21652,21653],{"href":21653,"rel":21654},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-vercel-doc",[95],", qui sera celui contenant les outils nous permettant de générer le résultat de notre agrégation de documentation. L’objectif est de centraliser ce processus, en impactant le moins possible les projets à documenter.",[19,21657,21658,21659,44],{},"Mais comment faire le lien entre le projet de génération de documentation et les projets à documenter ? Nous avons choisi d’utiliser les ",[91,21660,21663],{"href":21661,"rel":21662},"https:\u002F\u002Fgit-scm.com\u002Fbook\u002Ffr\u002Fv2\u002FUtilitaires-Git-Sous-modules",[95],"sous-modules (submodules) Git",[19,21665,21077,21666,21669],{},[34,21667,21668],{},"git submodules"," sont une fonctionnalité de Git permettant d'intégrer un dépôt Git distinct au sein d’un autre dépôt en tant que sous-dossier.",[344,21671,21673],{"className":20633,"code":21672,"language":20635,"meta":350,"style":350},"# Installation d'un sous-module ddd-asserter dans un dossier du projet\ngit submodule add https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fddd-asserter projects\u002Fddd-asserter\n\n# Mise à jour des sous-modules du projet\ngit submodule update --recursive --remote\n",[352,21674,21675,21680,21696,21700,21705],{"__ignoreMap":350},[355,21676,21677],{"class":357,"line":358},[355,21678,21679],{"class":3858},"# Installation d'un sous-module ddd-asserter dans un dossier du projet\n",[355,21681,21682,21685,21688,21690,21693],{"class":357,"line":364},[355,21683,21684],{"class":2805},"git",[355,21686,21687],{"class":1138}," submodule",[355,21689,6027],{"class":1138},[355,21691,21692],{"class":1138}," https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fddd-asserter",[355,21694,21695],{"class":1138}," projects\u002Fddd-asserter\n",[355,21697,21698],{"class":357,"line":370},[355,21699,1271],{"emptyLinePlaceholder":893},[355,21701,21702],{"class":357,"line":376},[355,21703,21704],{"class":3858},"# Mise à jour des sous-modules du projet\n",[355,21706,21707,21709,21711,21714,21717],{"class":357,"line":382},[355,21708,21684],{"class":2805},[355,21710,21687],{"class":1138},[355,21712,21713],{"class":1138}," update",[355,21715,21716],{"class":1264}," --recursive",[355,21718,21719],{"class":1264}," --remote\n",[19,21721,21722,21723,21727],{},"Cette approche est d’ailleurs employée sur l’exemple ",[91,21724,21725],{"href":21725,"rel":21726},"https:\u002F\u002Fgithub.com\u002Ftypedoc2md\u002Fdocusaurus-plugin-typedoc-example",[95],", pour Docusaurus et son plugin TypeDoc, que nous allons maintenant utiliser.",[23,21729,21731],{"id":21730},"docusaurus","Docusaurus",[19,21733,21734,21738],{},[91,21735,21731],{"href":21736,"rel":21737},"https:\u002F\u002Fdocusaurus.io\u002F",[95]," est un framework open-source permettant de créer facilement des sites web statiques de documentation technique. Basé sur React, il permet de gérer du contenu en Markdown, d’intégrer des plugins et des options de personnalisation pour un site propre et optimisé.",[19,21740,21741,21742,21747],{},"Parmi les plugins à disposition, un nous intéresse particulièrement dans notre cas : ",[91,21743,21746],{"href":21744,"rel":21745},"https:\u002F\u002Ftypedoc-plugin-markdown.org\u002Fplugins\u002Fdocusaurus",[95],"docusaurus-plugin-typedoc",". Comme son nom l’indique, ce plugin nous permet d’intégrer TypeDoc dans le cycle de Docusaurus. C’est lui qui portera ainsi la transformation TSDoc → Markdown. Avec la configuration souhaitée, la documentation s’intègrera ainsi automatiquement dans notre site Docusaurus.",[19,21749,21750],{},[176,21751],{"alt":21752,"src":21753},"Capture d’écran d’une page de documentation de règle d’asserter du site Dragee, généré par Docusarus","\u002Fcontent-assets\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel\u002Fassets\u002Fimg2.webp",[19,21755,21756,21757,44],{},"D’autres plugins utiles existent pour améliorer l’expérience, comme par exemple une barre de recherche avec ",[91,21758,21759],{"href":21759,"rel":21760},"https:\u002F\u002Fgithub.com\u002Fcmfcmf\u002Fdocusaurus-search-local",[95],[19,21762,21763,21764,21768,21769,21773],{},"Il est également possible d’ajouter des ressources statiques (pour la première page par exemple), des liens (vers le ",[91,21765,21767],{"href":20284,"rel":21766},[95],"code source de Dragee",", ou les liens ",[91,21770,1836],{"href":21771,"rel":21772},"https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fhopprtech",[95],") et de personnaliser le thème du site.",[19,21775,21776],{},[176,21777],{"alt":21778,"src":21779},"Capture d’écran de la page d’accueil du site Dragee, généré par Docusaurus","\u002Fcontent-assets\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel\u002Fassets\u002Fimg3.webp",[19,21781,21782,21783,21786],{},"Nous avons maintenant un site qui répond à nos attentes, avec une documentation centralisée dans notre projet ",[91,21784,21653],{"href":21653,"rel":21785},[95],". Il ne reste plus qu’à le déployer.",[23,21788,21790],{"id":21789},"vercel","Vercel",[19,21792,21793,21794,21798],{},"Pour présenter brièvement ",[91,21795,21790],{"href":21796,"rel":21797},"https:\u002F\u002Fvercel.com\u002F",[95],", c’est une plateforme optimisée pour déployer rapidement des applications web front-end. Elle offre un déploiement continu et des outils intégrés pour gérer des sites statiques ou dynamiques.",[19,21800,21801],{},"Vercel est un outil que nous connaissons bien chez HoppR, puisque c’est ce qui nous permet par exemple de déployer le blog que vous êtes en train de lire. Compatible avec Docusaurus, et permettant un déploiement couplé à Git, c’est l’outil idéal ici.",[19,21803,21804,21805,44],{},"Reprenons notre projet de documentation  ",[91,21806,21653],{"href":21653,"rel":21807},[95],[19,21809,21810,21811,21813],{},"Après configuration de Vercel, celui-ci va écouter les modifications apportées à la branche ",[1620,21812,1636],{}," du dépôt Git. A chaque nouveau commit sur cette branche, Vercel va automatiquement builder et redéployer la nouvelle version du site.",[19,21815,21816],{},[176,21817],{"alt":21818,"src":21819},"Capture d’écran du projet dragee-vercel-doc dans Vercel","\u002Fcontent-assets\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel\u002Fassets\u002Fimg4.webp",[19,21821,21822,21823],{},"Et voilà le résultat : ",[91,21824,21825],{"href":21825,"rel":21826},"https:\u002F\u002Fdragee-vercel-doc.vercel.app\u002F",[95],[19,21828,21829],{},"A noter que Vercel comprend toute une suite d’outils, permettant notamment l’analyse détaillée du trafic sur le site, une configuration simple, et même des environnements de preview déployés automatiquement pour tester chaque modification.",[23,21831,1528],{"id":1527},[19,21833,21834,21835,21837,21838,21841],{},"Maintenant le projet ",[34,21836,20286],{}," possède sa page, contenant une présentation succincte du projet, de la documentation et surtout un catalogue dynamique des projets ",[1620,21839,21840],{},"asserters\u002Fgraphers"," utilisables.",[19,21843,21844],{},"L’utilisation couplée de TypeDoc, Docusaurus et Vercel nous permet d’avoir une documentation simple et dynamique. Saisir les informations afférentes à une règle d’utilisation créé la documentation en lien dans notre catalogue de règles en ligne. Pratique !",[19,21846,21126,21847,21132],{},[91,21848,21131],{"href":21129,"rel":21849},[95],[856,21851,21852],{},"html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}",{"title":350,"searchDepth":364,"depth":364,"links":21854},[21855,21856,21857,21858,21859],{"id":21502,"depth":364,"text":21503},{"id":21646,"depth":364,"text":21647},{"id":21730,"depth":364,"text":21731},{"id":21789,"depth":364,"text":21790},{"id":1527,"depth":364,"text":1528},"2024-12-10T14:06:41.238Z","Suite à l’article [Créer une CLI pour un projet modulaire avec Commander.js](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-11-14-crer-une-cli-pour-un-projet-modulaire-avec-commanderjs), nous avons maintenant une",{},"\u002Fblogs\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel",[21865,21867,21869],{"id":10,"name":11,"image":21866,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20241210%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241210T140640Z&X-Amz-Expires=3600&X-Amz-Signature=1717ec06fe9281a6c6b23e68d1fd207de01aa4d0cec6dd9b0636ee1190e866e1&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":5813,"name":5814,"image":21868,"linkedin":5816,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F53946b9e-3bb9-45bd-a8b4-429c51156179\u002FT04PC176TGB-U05EW3YF61Z-5e129f612df3-512.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20241210%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241210T140640Z&X-Amz-Expires=3600&X-Amz-Signature=0872fb5dcb83126c48893f920e3646ae9781de7422ef2c6f6a650328b58a220a&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":897,"name":898,"image":21870,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45FSPPWI6X%2F20241210%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241210T140641Z&X-Amz-Expires=3600&X-Amz-Signature=db471f714fdcc59e94e41fb243834ba490d9e08146460424a8c63b6361cd4928&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":21434,"description":21861},"blogs\u002F2024-12-10-gnration-agrgation-et-dploiement-de-documentation-tsdoc-avec-docusaurus-et-vercel\u002Findex",[20436,7820,1879,21155,21156],"d4yFBeCY6STzyff7xYFckttIk9SB5MaSL-wqdtWxygE",{"id":21876,"title":21462,"alt":21877,"authors":21878,"body":21880,"date":23213,"description":23214,"extension":890,"image":891,"meta":23215,"navigation":893,"ogImage":891,"path":23216,"published":893,"reviewers":23217,"seo":23224,"stem":23225,"tags":23226,"__hash__":23227},"blogs\u002Fblogs\u002F2024-11-14-crer-une-cli-pour-un-projet-modulaire-avec-commanderjs\u002Findex.md","Lignes de code utilisant Commander.js pour créer une CLI, tirées du projet Dragee.io. ",[21879],{"id":1577,"name":1578,"image":1600,"linkedin":1580,"x":901},{"type":16,"value":21881,"toc":23204},[21882,21898,21914,21921,21927,21931,21934,21950,21957,21969,21984,21989,21993,22005,22021,22231,22237,22240,22246,22307,22319,22384,22389,22487,22697,22700,22757,22761,22765,22785,22792,22925,22939,22943,22955,22958,23065,23068,23177,23179,23196,23201],[1003,21883,21884],{},[19,21885,20259,21886,20262,21888,20270,21893,20273,21895],{},[34,21887,5365],{},[34,21889,21890],{},[91,21891,20269],{"href":20267,"rel":21892},[95],[8072,21894],{},[91,21896,20278],{"href":20276,"rel":21897},[95],[19,21899,21900,21903,21904,21909,21910,21913],{},[91,21901,20286],{"href":20284,"rel":21902},[95]," est un nouveau projet lié à l'architecture logicielle, permettant entre autres l'analyse d'une architecture dans la vision ",[91,21905,21908],{"href":21906,"rel":21907},"https:\u002F\u002Fblog.hoppr.tech\u002Ftags\u002Fcraft",[95],"Craft"," portée par ",[91,21911,1836],{"href":1834,"rel":21912},[95],". Nos ambitions pour ce projet sont fortes, celui-ci se voulant une solution complète et constituée de nombreuses fonctionnalités. Nous aurons d’ailleurs d’autres occasions de vous partager son avancée.",[19,21915,21916,21917,21920],{},"Les fonctionnalités allant être ajoutées de manière itérative, nous avons étudié la meilleure façon de faire grandir le projet. Nous sommes donc partis sur une CLI (",[1620,21918,21919],{},"Command-Line Interface",") présentant des commandes simples à l’utilisateur. Elle sera le cœur de notre solution, auquel viendront se greffer les futurs nouveaux modules.",[19,21922,21923,21924,21926],{},"Dans cet article, je vais vous présenter notre manière d’intégrer ces modules dans l’écosystème ",[34,21925,20286],{},", en créant des commandes qui leurs sont propres, et en les ajoutant à celles déjà existantes dans la CLI centrale.",[23,21928,21930],{"id":21929},"présentation-de-commanderjs","Présentation de Commander.js",[19,21932,21933],{},"Tout d’abord, nous avons besoin d’un outil pour développer cette CLI.",[19,21935,21936,21937,21942,21943,504,21945,44],{},"Nous avons pour cela choisi le projet ",[91,21938,21941],{"href":21939,"rel":21940},"https:\u002F\u002Fgithub.com\u002Ftj\u002Fcommander.js\u002Ftree\u002Fmaster",[95],"Commander.js",", qui permet d’en créer une facilement, sur des environnements d’exécution JS\u002FTS tels que Node.js, ou, dans le cas du projet ",[34,21944,20286],{},[91,21946,21949],{"href":21947,"rel":21948},"https:\u002F\u002Fbun.sh\u002F",[95],"Bun",[19,21951,21952,21953,21956],{},"Cela nous permet de concevoir ",[91,21954,20286],{"href":20284,"rel":21955},[95]," avec une stack où nos développeurs, principalement issus du monde du web, seront à l’aise, plutôt que d’investir dans une solution non maîtrisée (par exemple Go) ou pas encore assez mature.",[19,21958,21959,21960,21965,21966,21968],{},"Un ",[91,21961,21964],{"href":21962,"rel":21963},"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002Fcommander",[95],"package npm"," étant disponible, nous allons ici pouvoir installer ",[34,21967,21941],{}," en dépendance de nos projets :",[344,21970,21972],{"className":20633,"code":21971,"language":20635,"meta":350,"style":350},"bun add commander\n",[352,21973,21974],{"__ignoreMap":350},[355,21975,21976,21979,21981],{"class":357,"line":358},[355,21977,21978],{"class":2805},"bun",[355,21980,6027],{"class":1138},[355,21982,21983],{"class":1138}," commander\n",[19,21985,21986,21988],{},[34,21987,21941],{}," va nous permettre de gérer le parsing des arguments, de traiter les cas d’erreurs et d’afficher une documentation (description, aide, etc.) pour chaque commande. Cet outil contient beaucoup d’options de configuration, nous resterons ici sur une utilisation simple.",[23,21990,21992],{"id":21991},"création-dune-commande","Création d’une commande",[19,21994,21995,21996,21999,22000,44],{},"Dans la galaxie des projets ",[91,21997,20286],{"href":20284,"rel":21998},[95],", nous disposons donc d’un projet central, celui exposant cette fameuse CLI, le bien nommé ",[91,22001,22004],{"href":22002,"rel":22003},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-cli",[95],"dragee-cli",[19,22006,22007,22008,22011,22012,22015,22016,44],{},"Il contient de base deux commandes pour nos besoins fonctionnels : une pour générer des rapports (nommée ",[1620,22009,22010],{},"report","), l’autre pour générer des modélisations d’architecture (",[1620,22013,22014],{},"draw","). Écrivons la première, et plaçons-là dans notre ",[91,22017,22020],{"href":22018,"rel":22019},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-cli\u002Fblob\u002Fmain\u002Findex.ts",[95],"index.ts",[344,22022,22024],{"className":20434,"code":22023,"language":20436,"meta":350,"style":350},"import { Command } from 'commander';\nimport { reportCommandhandler } from '.\u002Fsrc\u002Fcommands\u002Freport-command.handler.ts';\n\nconst report = new Command('report')\n    .alias('r')\n    .summary('builds asserters rules report')\n    .description(\n        'Builds asserters rules report.\\n' +\n            '- Lookups dragees in [--from-dir] directory\\n' +\n            '- Downloads asserters for dragees namespaces\\n' +\n            '- Executes rules from asserters\\n' +\n            '- Builds reports in [--to-dir] directory'\n    )\n    .option('--from, --from-dir \u003Cpath-to-dir>', 'directory in where to lookup for dragees', '.')\n    .option('--to --to-dir \u003Cpath-to-dir>', 'directory in where to store reports', '.\u002Fdragee\u002Freports')\n    .action(reportCommandhandler);\n",[352,22025,22026,22040,22054,22058,22079,22094,22108,22117,22131,22142,22153,22164,22169,22174,22198,22221],{"__ignoreMap":350},[355,22027,22028,22030,22033,22035,22038],{"class":357,"line":358},[355,22029,20443],{"class":2801},[355,22031,22032],{"class":1119}," { Command } ",[355,22034,20449],{"class":2801},[355,22036,22037],{"class":1138}," 'commander'",[355,22039,17492],{"class":1119},[355,22041,22042,22044,22047,22049,22052],{"class":357,"line":364},[355,22043,20443],{"class":2801},[355,22045,22046],{"class":1119}," { reportCommandhandler } ",[355,22048,20449],{"class":2801},[355,22050,22051],{"class":1138}," '.\u002Fsrc\u002Fcommands\u002Freport-command.handler.ts'",[355,22053,17492],{"class":1119},[355,22055,22056],{"class":357,"line":370},[355,22057,1271],{"emptyLinePlaceholder":893},[355,22059,22060,22062,22065,22067,22069,22072,22074,22077],{"class":357,"line":376},[355,22061,20468],{"class":2801},[355,22063,22064],{"class":1264}," report",[355,22066,3213],{"class":2801},[355,22068,2857],{"class":2801},[355,22070,22071],{"class":2845}," Command",[355,22073,2169],{"class":1119},[355,22075,22076],{"class":1138},"'report'",[355,22078,16772],{"class":1119},[355,22080,22081,22084,22087,22089,22092],{"class":357,"line":382},[355,22082,22083],{"class":1119},"    .",[355,22085,22086],{"class":2845},"alias",[355,22088,2169],{"class":1119},[355,22090,22091],{"class":1138},"'r'",[355,22093,16772],{"class":1119},[355,22095,22096,22098,22101,22103,22106],{"class":357,"line":1157},[355,22097,22083],{"class":1119},[355,22099,22100],{"class":2845},"summary",[355,22102,2169],{"class":1119},[355,22104,22105],{"class":1138},"'builds asserters rules report'",[355,22107,16772],{"class":1119},[355,22109,22110,22112,22115],{"class":357,"line":1165},[355,22111,22083],{"class":1119},[355,22113,22114],{"class":2845},"description",[355,22116,3248],{"class":1119},[355,22118,22119,22122,22125,22128],{"class":357,"line":1173},[355,22120,22121],{"class":1138},"        'Builds asserters rules report.",[355,22123,22124],{"class":2801},"\\n",[355,22126,22127],{"class":1138},"'",[355,22129,22130],{"class":2801}," +\n",[355,22132,22133,22136,22138,22140],{"class":357,"line":1181},[355,22134,22135],{"class":1138},"            '- Lookups dragees in [--from-dir] directory",[355,22137,22124],{"class":2801},[355,22139,22127],{"class":1138},[355,22141,22130],{"class":2801},[355,22143,22144,22147,22149,22151],{"class":357,"line":1189},[355,22145,22146],{"class":1138},"            '- Downloads asserters for dragees namespaces",[355,22148,22124],{"class":2801},[355,22150,22127],{"class":1138},[355,22152,22130],{"class":2801},[355,22154,22155,22158,22160,22162],{"class":357,"line":1197},[355,22156,22157],{"class":1138},"            '- Executes rules from asserters",[355,22159,22124],{"class":2801},[355,22161,22127],{"class":1138},[355,22163,22130],{"class":2801},[355,22165,22166],{"class":357,"line":1205},[355,22167,22168],{"class":1138},"            '- Builds reports in [--to-dir] directory'\n",[355,22170,22171],{"class":357,"line":1213},[355,22172,22173],{"class":1119},"    )\n",[355,22175,22176,22178,22181,22183,22186,22188,22191,22193,22196],{"class":357,"line":1221},[355,22177,22083],{"class":1119},[355,22179,22180],{"class":2845},"option",[355,22182,2169],{"class":1119},[355,22184,22185],{"class":1138},"'--from, --from-dir \u003Cpath-to-dir>'",[355,22187,504],{"class":1119},[355,22189,22190],{"class":1138},"'directory in where to lookup for dragees'",[355,22192,504],{"class":1119},[355,22194,22195],{"class":1138},"'.'",[355,22197,16772],{"class":1119},[355,22199,22200,22202,22204,22206,22209,22211,22214,22216,22219],{"class":357,"line":1229},[355,22201,22083],{"class":1119},[355,22203,22180],{"class":2845},[355,22205,2169],{"class":1119},[355,22207,22208],{"class":1138},"'--to --to-dir \u003Cpath-to-dir>'",[355,22210,504],{"class":1119},[355,22212,22213],{"class":1138},"'directory in where to store reports'",[355,22215,504],{"class":1119},[355,22217,22218],{"class":1138},"'.\u002Fdragee\u002Freports'",[355,22220,16772],{"class":1119},[355,22222,22223,22225,22228],{"class":357,"line":1237},[355,22224,22083],{"class":1119},[355,22226,22227],{"class":2845},"action",[355,22229,22230],{"class":1119},"(reportCommandhandler);\n",[19,22232,22233,22234],{},"Cette commande contient un certain nombre d’informations (description, options), et surtout l’action à réaliser, une fonction passée en paramètre, ici nommée ",[1620,22235,22236],{},"reportCommandhandler.",[19,22238,22239],{},"La bonne pratique est ici de l’importer d’un fichier à part. En effet, la commande est à la CLI ce que le contrôleur est à nos applications web. L’action est équivalente à un service métier, placée ailleurs et appelée par notre commande, dont seule la définition est décrite dans l’index.",[19,22241,22242,22243,22245],{},"Nous allons ensuite, sur le même modèle, créer la commande ",[1620,22244,22014],{},". Pour finaliser notre CLI, nous devons également créer la commande de plus haut niveau, incorporant ces deux commandes :",[344,22247,22249],{"className":20434,"code":22248,"language":20436,"meta":350,"style":350},"new Command()\n    .addCommand(report)\n    .addCommand(draw)\n    .showHelpAfterError()\n    .showSuggestionAfterError()\n    .parse(process.argv);\n",[352,22250,22251,22260,22270,22279,22288,22297],{"__ignoreMap":350},[355,22252,22253,22256,22258],{"class":357,"line":358},[355,22254,22255],{"class":2801},"new",[355,22257,22071],{"class":2845},[355,22259,2868],{"class":1119},[355,22261,22262,22264,22267],{"class":357,"line":364},[355,22263,22083],{"class":1119},[355,22265,22266],{"class":2845},"addCommand",[355,22268,22269],{"class":1119},"(report)\n",[355,22271,22272,22274,22276],{"class":357,"line":370},[355,22273,22083],{"class":1119},[355,22275,22266],{"class":2845},[355,22277,22278],{"class":1119},"(draw)\n",[355,22280,22281,22283,22286],{"class":357,"line":376},[355,22282,22083],{"class":1119},[355,22284,22285],{"class":2845},"showHelpAfterError",[355,22287,2868],{"class":1119},[355,22289,22290,22292,22295],{"class":357,"line":382},[355,22291,22083],{"class":1119},[355,22293,22294],{"class":2845},"showSuggestionAfterError",[355,22296,2868],{"class":1119},[355,22298,22299,22301,22304],{"class":357,"line":1157},[355,22300,22083],{"class":1119},[355,22302,22303],{"class":2845},"parse",[355,22305,22306],{"class":1119},"(process.argv);\n",[19,22308,22309,22310,22313,22314,44],{},"L’exécutable de ",[91,22311,20286],{"href":20284,"rel":22312},[95]," est ensuite construit à l’aide d’une ",[91,22315,22318],{"href":22316,"rel":22317},"https:\u002F\u002Fbun.sh\u002Fdocs\u002Fbundler\u002Fexecutables",[95],"commande native de Bun",[344,22320,22322],{"className":20633,"code":22321,"language":20635,"meta":350,"style":350},"> bun run build\n$ bun build index.ts --target bun --compile --outfile dist\u002Fdragee-cli\n [237ms]  bundle  151 modules\n  [51ms] compile  dist\u002Fdragee-cli.exe\n",[352,22323,22324,22331,22359,22373],{"__ignoreMap":350},[355,22325,22326,22328],{"class":357,"line":358},[355,22327,2831],{"class":2801},[355,22329,22330],{"class":1119}," bun run build\n",[355,22332,22333,22336,22339,22342,22345,22348,22350,22353,22356],{"class":357,"line":364},[355,22334,22335],{"class":2805},"$",[355,22337,22338],{"class":1138}," bun",[355,22340,22341],{"class":1138}," build",[355,22343,22344],{"class":1138}," index.ts",[355,22346,22347],{"class":1264}," --target",[355,22349,22338],{"class":1138},[355,22351,22352],{"class":1264}," --compile",[355,22354,22355],{"class":1264}," --outfile",[355,22357,22358],{"class":1138}," dist\u002Fdragee-cli\n",[355,22360,22361,22364,22367,22370],{"class":357,"line":370},[355,22362,22363],{"class":1119}," [237ms]  ",[355,22365,22366],{"class":2805},"bundle",[355,22368,22369],{"class":1264},"  151",[355,22371,22372],{"class":1138}," modules\n",[355,22374,22375,22378,22381],{"class":357,"line":376},[355,22376,22377],{"class":1119},"  [51ms] ",[355,22379,22380],{"class":2805},"compile",[355,22382,22383],{"class":1138},"  dist\u002Fdragee-cli.exe\n",[19,22385,22386,22387,1513],{},"Et voici ce que tout cela donne, avec les options de documentation (help) sur la commande parent, puis sur la commande ",[1620,22388,22014],{},[344,22390,22392],{"className":20633,"code":22391,"language":20635,"meta":350,"style":350},"> .\u002Fdragee-cli --help\nUsage: index [options] [command]\n\nOptions:\n  -h, --help          display help for command\n\nCommands:\n  report|r [options]  builds asserters rules report\n  draw|d [options]    builds graphers graphs models\n  help [command]      display help for command\n",[352,22393,22394,22401,22412,22416,22421,22441,22445,22450,22462,22474],{"__ignoreMap":350},[355,22395,22396,22398],{"class":357,"line":358},[355,22397,2831],{"class":2801},[355,22399,22400],{"class":1119}," .\u002Fdragee-cli --help\n",[355,22402,22403,22406,22409],{"class":357,"line":364},[355,22404,22405],{"class":2805},"Usage:",[355,22407,22408],{"class":1138}," index",[355,22410,22411],{"class":1119}," [options] [command]\n",[355,22413,22414],{"class":357,"line":370},[355,22415,1271],{"emptyLinePlaceholder":893},[355,22417,22418],{"class":357,"line":376},[355,22419,22420],{"class":2805},"Options:\n",[355,22422,22423,22426,22429,22432,22435,22438],{"class":357,"line":382},[355,22424,22425],{"class":2805},"  -h,",[355,22427,22428],{"class":1264}," --help",[355,22430,22431],{"class":1138},"          display",[355,22433,22434],{"class":1138}," help",[355,22436,22437],{"class":1138}," for",[355,22439,22440],{"class":1138}," command\n",[355,22442,22443],{"class":357,"line":1157},[355,22444,1271],{"emptyLinePlaceholder":893},[355,22446,22447],{"class":357,"line":1165},[355,22448,22449],{"class":2805},"Commands:\n",[355,22451,22452,22455,22457,22459],{"class":357,"line":1173},[355,22453,22454],{"class":2805},"  report",[355,22456,20664],{"class":2801},[355,22458,2189],{"class":2805},[355,22460,22461],{"class":1119}," [options]  builds asserters rules report\n",[355,22463,22464,22467,22469,22471],{"class":357,"line":1181},[355,22465,22466],{"class":2805},"  draw",[355,22468,20664],{"class":2801},[355,22470,2458],{"class":2805},[355,22472,22473],{"class":1119}," [options]    builds graphers graphs models\n",[355,22475,22476,22479,22482,22485],{"class":357,"line":1189},[355,22477,22478],{"class":2805},"  help",[355,22480,22481],{"class":1119}," [command]      display help ",[355,22483,22484],{"class":2801},"for",[355,22486,22440],{"class":1119},[344,22488,22490],{"className":20633,"code":22489,"language":20635,"meta":350,"style":350},"> .\u002Fdragee-cli report --help\nUsage: index report|r [options]\n\nBuilds asserters rules report.\n- Lookups dragees in [--from-dir] directory\n- Downloads asserters for dragees namespaces\n- Executes rules from asserters\n- Builds reports in [--to-dir] directory\n\nOptions:\n  --from, --from-dir \u003Cpath-to-dir>  directory in where to lookup for dragees (default: \".\")\n  --to --to-dir \u003Cpath-to-dir>       directory in where to store reports (default: \".\u002Fdragee\u002Freports\")\n  -h, --help                        display help for command\n",[352,22491,22492,22499,22514,22518,22532,22548,22564,22579,22594,22598,22602,22645,22682],{"__ignoreMap":350},[355,22493,22494,22496],{"class":357,"line":358},[355,22495,2831],{"class":2801},[355,22497,22498],{"class":1119}," .\u002Fdragee-cli report --help\n",[355,22500,22501,22503,22505,22507,22509,22511],{"class":357,"line":364},[355,22502,22405],{"class":2805},[355,22504,22408],{"class":1138},[355,22506,22064],{"class":1138},[355,22508,20664],{"class":2801},[355,22510,2189],{"class":2805},[355,22512,22513],{"class":1119}," [options]\n",[355,22515,22516],{"class":357,"line":370},[355,22517,1271],{"emptyLinePlaceholder":893},[355,22519,22520,22523,22526,22529],{"class":357,"line":376},[355,22521,22522],{"class":2805},"Builds",[355,22524,22525],{"class":1138}," asserters",[355,22527,22528],{"class":1138}," rules",[355,22530,22531],{"class":1138}," report.\n",[355,22533,22534,22536,22539,22542,22545],{"class":357,"line":382},[355,22535,4014],{"class":2805},[355,22537,22538],{"class":1138}," Lookups",[355,22540,22541],{"class":1138}," dragees",[355,22543,22544],{"class":1138}," in",[355,22546,22547],{"class":1119}," [--from-dir] directory\n",[355,22549,22550,22552,22555,22557,22559,22561],{"class":357,"line":1157},[355,22551,4014],{"class":2805},[355,22553,22554],{"class":1138}," Downloads",[355,22556,22525],{"class":1138},[355,22558,22437],{"class":1138},[355,22560,22541],{"class":1138},[355,22562,22563],{"class":1138}," namespaces\n",[355,22565,22566,22568,22571,22573,22576],{"class":357,"line":1165},[355,22567,4014],{"class":2805},[355,22569,22570],{"class":1138}," Executes",[355,22572,22528],{"class":1138},[355,22574,22575],{"class":1138}," from",[355,22577,22578],{"class":1138}," asserters\n",[355,22580,22581,22583,22586,22589,22591],{"class":357,"line":1173},[355,22582,4014],{"class":2805},[355,22584,22585],{"class":1138}," Builds",[355,22587,22588],{"class":1138}," reports",[355,22590,22544],{"class":1138},[355,22592,22593],{"class":1119}," [--to-dir] directory\n",[355,22595,22596],{"class":357,"line":1181},[355,22597,1271],{"emptyLinePlaceholder":893},[355,22599,22600],{"class":357,"line":1189},[355,22601,22420],{"class":2805},[355,22603,22604,22607,22610,22612,22615,22617,22619,22622,22624,22627,22630,22633,22635,22637,22640,22643],{"class":357,"line":1197},[355,22605,22606],{"class":2805},"  --from,",[355,22608,22609],{"class":1264}," --from-dir",[355,22611,4799],{"class":2801},[355,22613,22614],{"class":1138},"path-to-di",[355,22616,2189],{"class":1119},[355,22618,2831],{"class":2801},[355,22620,22621],{"class":1138},"  directory",[355,22623,22544],{"class":1138},[355,22625,22626],{"class":1138}," where",[355,22628,22629],{"class":1138}," to",[355,22631,22632],{"class":1138}," lookup",[355,22634,22437],{"class":1138},[355,22636,22541],{"class":1138},[355,22638,22639],{"class":1119}," (default: ",[355,22641,22642],{"class":1138},"\".\"",[355,22644,16772],{"class":1119},[355,22646,22647,22650,22653,22655,22657,22659,22661,22664,22666,22668,22670,22673,22675,22677,22680],{"class":357,"line":1205},[355,22648,22649],{"class":2805},"  --to",[355,22651,22652],{"class":1264}," --to-dir",[355,22654,4799],{"class":2801},[355,22656,22614],{"class":1138},[355,22658,2189],{"class":1119},[355,22660,2831],{"class":2801},[355,22662,22663],{"class":1138},"       directory",[355,22665,22544],{"class":1138},[355,22667,22626],{"class":1138},[355,22669,22629],{"class":1138},[355,22671,22672],{"class":1138}," store",[355,22674,22588],{"class":1138},[355,22676,22639],{"class":1119},[355,22678,22679],{"class":1138},"\".\u002Fdragee\u002Freports\"",[355,22681,16772],{"class":1119},[355,22683,22684,22686,22688,22691,22693,22695],{"class":357,"line":1213},[355,22685,22425],{"class":2805},[355,22687,22428],{"class":1264},[355,22689,22690],{"class":1138},"                        display",[355,22692,22434],{"class":1138},[355,22694,22437],{"class":1138},[355,22696,22440],{"class":1138},[19,22698,22699],{},"Ce qui donne à l’usage :",[344,22701,22703],{"className":20633,"code":22702,"language":20635,"meta":350,"style":350},"> .\u002Fdragee-cli report --from-dir .\u002Ftest\u002Fapproval\u002Fsample\u002F --to-dir .\u002Foutput\nLooking up for dragees in directory: .\u002Ftest\u002Fapproval\u002Fsample\u002F\nLooking up for namespaces\nLooking up for projects\n...\n",[352,22704,22705,22712,22732,22742,22753],{"__ignoreMap":350},[355,22706,22707,22709],{"class":357,"line":358},[355,22708,2831],{"class":2801},[355,22710,22711],{"class":1119}," .\u002Fdragee-cli report --from-dir .\u002Ftest\u002Fapproval\u002Fsample\u002F --to-dir .\u002Foutput\n",[355,22713,22714,22717,22720,22722,22724,22726,22729],{"class":357,"line":364},[355,22715,22716],{"class":2805},"Looking",[355,22718,22719],{"class":1138}," up",[355,22721,22437],{"class":1138},[355,22723,22541],{"class":1138},[355,22725,22544],{"class":1138},[355,22727,22728],{"class":1138}," directory:",[355,22730,22731],{"class":1138}," .\u002Ftest\u002Fapproval\u002Fsample\u002F\n",[355,22733,22734,22736,22738,22740],{"class":357,"line":370},[355,22735,22716],{"class":2805},[355,22737,22719],{"class":1138},[355,22739,22437],{"class":1138},[355,22741,22563],{"class":1138},[355,22743,22744,22746,22748,22750],{"class":357,"line":376},[355,22745,22716],{"class":2805},[355,22747,22719],{"class":1138},[355,22749,22437],{"class":1138},[355,22751,22752],{"class":1138}," projects\n",[355,22754,22755],{"class":357,"line":382},[355,22756,21588],{"class":1264},[23,22758,22760],{"id":22759},"architecture-modulaire","Architecture modulaire",[84,22762,22764],{"id":22763},"module-enfant","Module enfant",[19,22766,22767,22768,22773,22774,22776,22777,22779,22780,22784],{},"Maintenant que notre projet CLI est créé et fonctionnel, nous allons nous attaquer à un nouveau module, ",[91,22769,22772],{"href":22770,"rel":22771},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-asserter-generator",[95],"dragee-asserter-generator",". Celui-ci a pour mission de générer un squelette d’",[1620,22775,20339],{}," pour le projet ",[34,22778,20286],{},", comme ",[91,22781,22783],{"href":20356,"rel":22782},[95],"ddd-asserter ","par exemple.",[19,22786,22787,22788,1513],{},"Après ajout de la dépendance Commander à ce second projet, on crée la commande nécessaire dans ",[91,22789,22772],{"href":22790,"rel":22791},"https:\u002F\u002Fgithub.com\u002Fdragee-io\u002Fdragee-asserter-generator\u002Fblob\u002Fmain\u002Findex.ts",[95],[344,22793,22795],{"className":20434,"code":22794,"language":20436,"meta":350,"style":350},"import { Command } from 'commander';\n\nexport const generateAsserter = new Command('generate-asserter')\n    .alias('ga')\n    .summary('generates a new asserter project')\n    .description('Generates a new asserter project.\\nBased on a standard dragee asserter template, with mandatory dependancies and a sample rule.')\n    .requiredOption('-n, --name \u003Cstring>', 'name of the new asserter project')\n    .requiredOption('-od, --output-dir \u003Cstring>', 'output dir for the new asserter project')\n    .action(generatorHandler);\n",[352,22796,22797,22809,22813,22835,22848,22861,22879,22898,22916],{"__ignoreMap":350},[355,22798,22799,22801,22803,22805,22807],{"class":357,"line":358},[355,22800,20443],{"class":2801},[355,22802,22032],{"class":1119},[355,22804,20449],{"class":2801},[355,22806,22037],{"class":1138},[355,22808,17492],{"class":1119},[355,22810,22811],{"class":357,"line":364},[355,22812,1271],{"emptyLinePlaceholder":893},[355,22814,22815,22817,22819,22822,22824,22826,22828,22830,22833],{"class":357,"line":370},[355,22816,20859],{"class":2801},[355,22818,20862],{"class":2801},[355,22820,22821],{"class":1264}," generateAsserter",[355,22823,3213],{"class":2801},[355,22825,2857],{"class":2801},[355,22827,22071],{"class":2845},[355,22829,2169],{"class":1119},[355,22831,22832],{"class":1138},"'generate-asserter'",[355,22834,16772],{"class":1119},[355,22836,22837,22839,22841,22843,22846],{"class":357,"line":376},[355,22838,22083],{"class":1119},[355,22840,22086],{"class":2845},[355,22842,2169],{"class":1119},[355,22844,22845],{"class":1138},"'ga'",[355,22847,16772],{"class":1119},[355,22849,22850,22852,22854,22856,22859],{"class":357,"line":382},[355,22851,22083],{"class":1119},[355,22853,22100],{"class":2845},[355,22855,2169],{"class":1119},[355,22857,22858],{"class":1138},"'generates a new asserter project'",[355,22860,16772],{"class":1119},[355,22862,22863,22865,22867,22869,22872,22874,22877],{"class":357,"line":1157},[355,22864,22083],{"class":1119},[355,22866,22114],{"class":2845},[355,22868,2169],{"class":1119},[355,22870,22871],{"class":1138},"'Generates a new asserter project.",[355,22873,22124],{"class":2801},[355,22875,22876],{"class":1138},"Based on a standard dragee asserter template, with mandatory dependancies and a sample rule.'",[355,22878,16772],{"class":1119},[355,22880,22881,22883,22886,22888,22891,22893,22896],{"class":357,"line":1165},[355,22882,22083],{"class":1119},[355,22884,22885],{"class":2845},"requiredOption",[355,22887,2169],{"class":1119},[355,22889,22890],{"class":1138},"'-n, --name \u003Cstring>'",[355,22892,504],{"class":1119},[355,22894,22895],{"class":1138},"'name of the new asserter project'",[355,22897,16772],{"class":1119},[355,22899,22900,22902,22904,22906,22909,22911,22914],{"class":357,"line":1173},[355,22901,22083],{"class":1119},[355,22903,22885],{"class":2845},[355,22905,2169],{"class":1119},[355,22907,22908],{"class":1138},"'-od, --output-dir \u003Cstring>'",[355,22910,504],{"class":1119},[355,22912,22913],{"class":1138},"'output dir for the new asserter project'",[355,22915,16772],{"class":1119},[355,22917,22918,22920,22922],{"class":357,"line":1181},[355,22919,22083],{"class":1119},[355,22921,22227],{"class":2845},[355,22923,22924],{"class":1119},"(generatorHandler);\n",[19,22926,22927,22928,22931,22932,22935,22936,22938],{},"Notez ici que l’on ",[34,22929,22930],{},"exporte"," la commande ",[1620,22933,22934],{},"generate-asserter",". Cela va nous permettre de la rendre accessible pour ",[1620,22937,22004],{},", et c’est justement ce que nous allons faire à présent.",[84,22940,22942],{"id":22941},"module-parent","Module parent",[19,22944,22945,22946,22948,22949,22951,22952,6784],{},"Nous allons ajouter la dépendance à ",[1620,22947,22772],{}," dans ",[1620,22950,22004],{},". Nous ferons ainsi pour chaque autre module à rattacher à notre CLI, comme ",[1620,22953,22954],{},"dragee-grapher-generator",[19,22956,22957],{},"Une fois cela fait, nous ajoutons tout simplement ces commandes au CLI central, après import :",[344,22959,22961],{"className":20434,"code":22960,"language":20436,"meta":350,"style":350},"import { generateAsserter } from '@dragee-io\u002Fasserter-generator';\nimport { generateGrapher } from '@dragee-io\u002Fgrapher-generator';\n\n...\nnew Command()\n    .addCommand(generateAsserter)\n    .addCommand(generateGrapher)\n    .addCommand(report)\n    .addCommand(draw)\n    .showHelpAfterError()\n    .showSuggestionAfterError()\n    .parse(process.argv);\n",[352,22962,22963,22977,22991,22995,22999,23007,23016,23025,23033,23041,23049,23057],{"__ignoreMap":350},[355,22964,22965,22967,22970,22972,22975],{"class":357,"line":358},[355,22966,20443],{"class":2801},[355,22968,22969],{"class":1119}," { generateAsserter } ",[355,22971,20449],{"class":2801},[355,22973,22974],{"class":1138}," '@dragee-io\u002Fasserter-generator'",[355,22976,17492],{"class":1119},[355,22978,22979,22981,22984,22986,22989],{"class":357,"line":364},[355,22980,20443],{"class":2801},[355,22982,22983],{"class":1119}," { generateGrapher } ",[355,22985,20449],{"class":2801},[355,22987,22988],{"class":1138}," '@dragee-io\u002Fgrapher-generator'",[355,22990,17492],{"class":1119},[355,22992,22993],{"class":357,"line":370},[355,22994,1271],{"emptyLinePlaceholder":893},[355,22996,22997],{"class":357,"line":376},[355,22998,21588],{"class":2801},[355,23000,23001,23003,23005],{"class":357,"line":382},[355,23002,22255],{"class":2801},[355,23004,22071],{"class":2845},[355,23006,2868],{"class":1119},[355,23008,23009,23011,23013],{"class":357,"line":1157},[355,23010,22083],{"class":1119},[355,23012,22266],{"class":2845},[355,23014,23015],{"class":1119},"(generateAsserter)\n",[355,23017,23018,23020,23022],{"class":357,"line":1165},[355,23019,22083],{"class":1119},[355,23021,22266],{"class":2845},[355,23023,23024],{"class":1119},"(generateGrapher)\n",[355,23026,23027,23029,23031],{"class":357,"line":1173},[355,23028,22083],{"class":1119},[355,23030,22266],{"class":2845},[355,23032,22269],{"class":1119},[355,23034,23035,23037,23039],{"class":357,"line":1181},[355,23036,22083],{"class":1119},[355,23038,22266],{"class":2845},[355,23040,22278],{"class":1119},[355,23042,23043,23045,23047],{"class":357,"line":1189},[355,23044,22083],{"class":1119},[355,23046,22285],{"class":2845},[355,23048,2868],{"class":1119},[355,23050,23051,23053,23055],{"class":357,"line":1197},[355,23052,22083],{"class":1119},[355,23054,22294],{"class":2845},[355,23056,2868],{"class":1119},[355,23058,23059,23061,23063],{"class":357,"line":1205},[355,23060,22083],{"class":1119},[355,23062,22303],{"class":2845},[355,23064,22306],{"class":1119},[19,23066,23067],{},"Et voilà !",[344,23069,23071],{"className":20633,"code":23070,"language":20635,"meta":350,"style":350},"> .\u002Fdragee-cli --help\nUsage: index [options] [command]\n\nOptions:\n  -h, --help                      display help for command\n\nCommands:\n  generate-asserter|ga [options]  generates a new asserter project\n  generate-grapher|gg [options]   generates a new grapher project\n  report|r [options]              builds asserters rules report\n  draw|d [options]                builds graphers graphs models\n  help [command]                  display help for command\n",[352,23072,23073,23079,23087,23091,23095,23110,23114,23118,23131,23144,23155,23166],{"__ignoreMap":350},[355,23074,23075,23077],{"class":357,"line":358},[355,23076,2831],{"class":2801},[355,23078,22400],{"class":1119},[355,23080,23081,23083,23085],{"class":357,"line":364},[355,23082,22405],{"class":2805},[355,23084,22408],{"class":1138},[355,23086,22411],{"class":1119},[355,23088,23089],{"class":357,"line":370},[355,23090,1271],{"emptyLinePlaceholder":893},[355,23092,23093],{"class":357,"line":376},[355,23094,22420],{"class":2805},[355,23096,23097,23099,23101,23104,23106,23108],{"class":357,"line":382},[355,23098,22425],{"class":2805},[355,23100,22428],{"class":1264},[355,23102,23103],{"class":1138},"                      display",[355,23105,22434],{"class":1138},[355,23107,22437],{"class":1138},[355,23109,22440],{"class":1138},[355,23111,23112],{"class":357,"line":1157},[355,23113,1271],{"emptyLinePlaceholder":893},[355,23115,23116],{"class":357,"line":1165},[355,23117,22449],{"class":2805},[355,23119,23120,23123,23125,23128],{"class":357,"line":1173},[355,23121,23122],{"class":2805},"  generate-asserter",[355,23124,20664],{"class":2801},[355,23126,23127],{"class":2805},"ga",[355,23129,23130],{"class":1119}," [options]  generates a new asserter project\n",[355,23132,23133,23136,23138,23141],{"class":357,"line":1181},[355,23134,23135],{"class":2805},"  generate-grapher",[355,23137,20664],{"class":2801},[355,23139,23140],{"class":2805},"gg",[355,23142,23143],{"class":1119}," [options]   generates a new grapher project\n",[355,23145,23146,23148,23150,23152],{"class":357,"line":1189},[355,23147,22454],{"class":2805},[355,23149,20664],{"class":2801},[355,23151,2189],{"class":2805},[355,23153,23154],{"class":1119}," [options]              builds asserters rules report\n",[355,23156,23157,23159,23161,23163],{"class":357,"line":1197},[355,23158,22466],{"class":2805},[355,23160,20664],{"class":2801},[355,23162,2458],{"class":2805},[355,23164,23165],{"class":1119}," [options]                builds graphers graphs models\n",[355,23167,23168,23170,23173,23175],{"class":357,"line":1205},[355,23169,22478],{"class":2805},[355,23171,23172],{"class":1119}," [command]                  display help ",[355,23174,22484],{"class":2801},[355,23176,22440],{"class":1119},[23,23178,1528],{"id":1527},[19,23180,23181,23182,23186,23187,23190,23191,6636],{},"La CLI comme cœur de notre système va nous permettre d’accroître les capacités de ",[91,23183,20286],{"href":23184,"rel":23185},"http:\u002F\u002Fdragee.io\u002F",[95]," au fur et à mesure. La modularité alliée à Commander.js nous permet de développer, tester et valider indépendamment chaque fonctionnalité. L’intégration des commandes dans la CLI centrale est simple, comme nous l’avons vu dans cet article. Enfin, le runtime de ",[91,23188,21949],{"href":21947,"rel":23189},[95]," nous permet une exécution rapide des commandes (",[91,23192,23195],{"href":23193,"rel":23194},"https:\u002F\u002Fbun.sh\u002Fblog\u002Fbun-v1.0",[95],"démarrage 4 fois plus rapide que Node.js par exemple",[19,23197,21126,23198,21132],{},[91,23199,21131],{"href":21129,"rel":23200},[95],[856,23202,23203],{},"html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .sc3cj, html code.shiki .sc3cj{--shiki-default:#D2A8FF}",{"title":350,"searchDepth":364,"depth":364,"links":23205},[23206,23207,23208,23212],{"id":21929,"depth":364,"text":21930},{"id":21991,"depth":364,"text":21992},{"id":22759,"depth":364,"text":22760,"children":23209},[23210,23211],{"id":22763,"depth":370,"text":22764},{"id":22941,"depth":370,"text":22942},{"id":1527,"depth":364,"text":1528},"2024-11-14T09:03:58.106Z","[Dragee.io](https:\u002F\u002Fgithub.com\u002Fdragee-io) est un nouveau projet lié à l'architecture logicielle, permettant entre autres l'analyse d'une architecture dans la vision [Craft](https:\u002F\u002Fblog.hoppr.tech\u002Ftag",{},"\u002Fblogs\u002F2024-11-14-crer-une-cli-pour-un-projet-modulaire-avec-commanderjs",[23218,23220,23222],{"id":1582,"name":1583,"image":23219,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241114%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241114T090357Z&X-Amz-Expires=3600&X-Amz-Signature=a05938aa617f8ff2268f50065cb89ede0f8055125c3fb418afa4079e6bc62396&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":10,"name":11,"image":23221,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241114%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241114T090358Z&X-Amz-Expires=3600&X-Amz-Signature=8cee0f8d165f64e2d0a1bcb832c3252b4c9584435828cd62b42463e76370ed10&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1887,"name":1888,"image":23223,"linkedin":1890,"x":1891},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F02dd23b5-238a-4713-ad54-432f3fa5119b\u002Fecattez_profile.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241114%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241114T090357Z&X-Amz-Expires=3600&X-Amz-Signature=be9d313f6a07aecbdf9651e0563914178ae2cbcdc1751cfe0b6b1c23e8e8d089&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":21462,"description":23214},"blogs\u002F2024-11-14-crer-une-cli-pour-un-projet-modulaire-avec-commanderjs\u002Findex",[20436,1879,21155,21156],"dtDKDCV_WylgtltXZyaGMrtG3ZqITs2ouwO40hZ-jho",{"id":23229,"title":23230,"alt":23231,"authors":23232,"body":23234,"date":23393,"description":23394,"extension":890,"image":891,"meta":23395,"navigation":893,"ogImage":891,"path":23396,"published":893,"reviewers":23397,"seo":23406,"stem":23407,"tags":23408,"__hash__":23409},"blogs\u002Fblogs\u002F2024-10-31-dora-metrics-valuer-la-performance-de-livraison-logicielle\u002Findex.md","DORA Metrics : Évaluer la performance de livraison logicielle","Image illustrant les DORA Metrics avec une fusée qui décolle vers la lune dans un style pop",[23233],{"id":10,"name":11,"image":12,"linkedin":13,"x":14},{"type":16,"value":23235,"toc":23386},[23236,23239,23246,23249,23253,23262,23265,23272,23275,23282,23285,23292,23295,23302,23305,23319,23323,23326,23337,23340,23343,23349,23357,23361,23364,23368,23371,23374,23376,23379],[19,23237,23238],{},"Cet article explore les DORA Metrics, également connues sous le nom de « Four Keys », un standard émergent pour évaluer la performance de la livraison logicielle. Ayant eu l'opportunité de mettre en place ces métriques chez un grand acteur du retail — comptant plus de 50 000 projets, 8 000 développeurs et présent sur les 5 continents — je souhaite partager les leçons et recommandations tirées de cette expérience.",[19,23240,23241,23242,44],{},"Dans cet article, nous nous concentrerons sur les aspects théoriques et fondamentaux des ",[91,23243,1813],{"href":23244,"rel":23245},"https:\u002F\u002Fblog.hoppr.tech\u002Ftags\u002Fdora%20metrics",[95],[19,23247,23248],{},"L'objectif est de vous permettre de saisir les concepts essentiels, tandis que les articles suivants détailleront la mise en place pratique, les adaptations nécessaires (car il y a toujours un écart entre théorie et pratique), ainsi que les avantages et les limites que j'ai pu observer dans l'application de ce modèle.",[23,23250,23252],{"id":23251},"quest-ce-que-les-métriques-dora","Qu'est-ce que les métriques DORA ?",[19,23254,23255,23256,23261],{},"Les métriques DORA, issues du rapport  \"",[91,23257,23260],{"href":23258,"rel":23259},"https:\u002F\u002Fcloud.google.com\u002Fdevops\u002Fstate-of-devops",[95],"Accelerate State of DevOps","\" de DORA (DevOps Research and Assessment), sont un ensemble de quatre indicateurs clés de performance (KPI) qui permettent d'évaluer de manière objective l'efficacité et la stabilité des processus de développement et de déploiement logiciel d'une organisation.",[19,23263,23264],{},"Examinons chacune de ces métriques en détail :",[6138,23266,23267],{},[446,23268,23269],{},[34,23270,23271],{},"Lead Time for Changes (Délai de livraison des changements)",[19,23273,23274],{},"Cette métrique mesure le temps écoulé entre le moment où un changement est codé et le moment où il est déployé en production. Un délai plus court indique une capacité à répondre rapidement aux besoins des utilisateurs, améliorant ainsi l'expérience utilisateur.",[6138,23276,23277],{"start":364},[446,23278,23279],{},[34,23280,23281],{},"Deployment Frequency (Fréquence de déploiement)",[19,23283,23284],{},"Elle mesure la fréquence à laquelle les changements sont déployés en production. Une fréquence élevée suggère que le déploiement est devenu une opération de routine, ce qui permet une réponse rapide aux besoins des utilisateurs et améliore la boucle de feedback.",[6138,23286,23287],{"start":370},[446,23288,23289],{},[34,23290,23291],{},"Mean Time to Restore (MTTR) (Temps moyen de restauration)",[19,23293,23294],{},"Le MTTR mesure le temps nécessaire pour restaurer le service après un incident en production. Un MTTR court indique une réactivité élevée et une boucle de feedback courte, ce qui devrait améliorer l'expérience utilisateur.",[6138,23296,23297],{"start":376},[446,23298,23299],{},[34,23300,23301],{},"Change Failure Rate (Taux d'échec des changements)",[19,23303,23304],{},"Cette métrique mesure le taux de changements qui entraînent un échec ou un incident. Un taux faible implique une bonne compréhension des besoins des utilisateurs et une réponse appropriée, ce qui devrait améliorer l'expérience utilisateur.",[19,23306,23307,23308,23312,23313,23318],{},"Pour calculer les 4 keys, l'équipe DORA a développé une solution sur ",[91,23309,8386],{"href":23310,"rel":23311},"https:\u002F\u002Fgithub.com\u002Fdora-team\u002Ffourkeys\u002Ftree\u002Fmain",[95],".\nVous y trouverez les ",[91,23314,23317],{"href":23315,"rel":23316},"https:\u002F\u002Fgithub.com\u002Fdora-team\u002Ffourkeys\u002Fblob\u002Fmain\u002FMETRICS.md",[95],"requêtes SQL nécessaires au calcul des métriques",". Bien que cette solution soit difficilement applicable telle quelle — car peu adaptée au contexte spécifique de chaque entreprise — elle constitue néanmoins une excellente base théorique pour comprendre le fonctionnement des métriques.",[23,23320,23322],{"id":23321},"les-niveaux-de-performance","Les niveaux de performance",[19,23324,23325],{},"Les métriques DORA définissent trois niveaux de performance principaux :",[443,23327,23328,23331,23334],{},[446,23329,23330],{},"Low",[446,23332,23333],{},"Medium",[446,23335,23336],{},"High",[19,23338,23339],{},"Selon les années, un quatrième niveau peut être ajouté : Elite, mais la logique reste la même.",[19,23341,23342],{},"Ces niveaux de performance permettent aux équipes de se positionner par rapport aux meilleures pratiques de l'industrie et d'identifier les domaines d'amélioration potentiels dans leurs processus de développement et de livraison logicielle.",[19,23344,23345],{},[176,23346],{"alt":23347,"src":23348},"Tableau \"Software delivery performance metric\" avec 4 colonnes (Software delivery performance metric, Low, Medium, High) et 4 lignes de métriques : Deployment frequency, Lead time for changes, Time to restore service, Change failure rate, montrant les valeurs pour chaque niveau de performance (Low, Medium, High).","\u002Fcontent-assets\u002F2024-10-31-dora-metrics-valuer-la-performance-de-livraison-logicielle\u002Fassets\u002Fimg1.webp",[19,23350,23351,23352,44],{},"Pour plus de détails sur ces seuils de performance, vous pouvez ",[91,23353,23356],{"href":23354,"rel":23355},"https:\u002F\u002Fcloud.google.com\u002Fblog\u002Fproducts\u002Fdevops-sre\u002Fdora-2022-accelerate-state-of-devops-report-now-out?hl=en",[95],"consulter la documentation DORA officielle",[23,23358,23360],{"id":23359},"pourquoi-ces-métriques-sont-elles-importantes","Pourquoi ces métriques sont-elles importantes ?",[19,23362,23363],{},"En mesurant et en surveillant ces métriques, les équipes de développement obtiennent une vue d'ensemble de leur performance et peuvent identifier des axes d'amélioration. Par exemple, si le délai de livraison des changements est élevé (disons 2 semaines au lieu de plusieurs livraisons par jour pour une performance élevée), l'équipe peut se concentrer sur l'amélioration de ses processus de développement. Si le MTTR est élevé (par exemple, 24 heures au lieu de moins d'une heure pour une performance élevée), l'accent peut être mis sur l'amélioration des processus de réponse aux incidents.",[23,23365,23367],{"id":23366},"une-approche-data-driven","Une approche “Data-Driven”",[19,23369,23370],{},"En utilisant ces métriques, les équipes peuvent prendre des décisions fondées sur des données concrètes plutôt que sur l'intuition. Ces décisions deviennent ainsi objectives et communicables, s'appuyant sur des preuves tangibles plutôt que sur des émotions ou des biais.",[19,23372,23373],{},"De plus, l'utilisation de métriques communes à travers les équipes et les projets facilite le partage d'expériences et l'amélioration continue. En collectant et en analysant ces données, les équipes peuvent mesurer les résultats de leurs efforts d'amélioration continue et partager leurs expériences à travers l'organisation.",[23,23375,1528],{"id":1527},[19,23377,23378],{},"Les métriques DORA (Four Keys) offrent un cadre pour évaluer et améliorer la performance de livraison logicielle. Ces quatre indicateurs  permettent aux équipes d'être en amélioration continue, de répondre plus efficacement aux besoins des utilisateurs et, en fin de compte, de livrer des logiciels de meilleure qualité, plus rapidement et de manière plus fiable.",[19,23380,23381,23385],{},[91,23382,23384],{"href":23244,"rel":23383},[95],"Dans un prochain article",", nous aborderons l'aspect pratique et verrons qu'il n'est pas si simple de mettre en place les métriques DORA, et surtout de les adapter au contexte métier et organisationnel de l’entreprise.",{"title":350,"searchDepth":364,"depth":364,"links":23387},[23388,23389,23390,23391,23392],{"id":23251,"depth":364,"text":23252},{"id":23321,"depth":364,"text":23322},{"id":23359,"depth":364,"text":23360},{"id":23366,"depth":364,"text":23367},{"id":1527,"depth":364,"text":1528},"2024-10-31T16:34:09.365Z","Cet article explore les DORA Metrics, également connues sous le nom de « Four Keys », un standard émergent pour évaluer la performance de la livraison logicielle. Ayant eu l'opportunité de mettre en p",{},"\u002Fblogs\u002F2024-10-31-dora-metrics-valuer-la-performance-de-livraison-logicielle",[23398,23400,23402,23404],{"id":5017,"name":5018,"image":23399,"linkedin":5020,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc4f79dcc-a6ed-4a79-9947-416b33e5b90a\u002FPhoto_Profil_CV_1200px_%2813%29.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T163408Z&X-Amz-Expires=3600&X-Amz-Signature=17d42cc8fa7348e15880615a184d9cc03d4312fbba9f691f469ea7575728026d&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1582,"name":1583,"image":23401,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T163408Z&X-Amz-Expires=3600&X-Amz-Signature=199b4667885bca080d58b9704e19238b32d17675e3c643b6f5c73ce405930bc3&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":897,"name":898,"image":23403,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T163408Z&X-Amz-Expires=3600&X-Amz-Signature=b41d2e5cff05fcfcad7a6b7423c10495eeac36a4925a05cac543c2bc49d9c71a&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1887,"name":1888,"image":23405,"linkedin":1890,"x":1891},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F02dd23b5-238a-4713-ad54-432f3fa5119b\u002Fecattez_profile.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T163409Z&X-Amz-Expires=3600&X-Amz-Signature=62a6fb7395f1a4beceedbc9d816bde48517d66ab1f0715d4174e49c2314436f2&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":23230,"description":23394},"blogs\u002F2024-10-31-dora-metrics-valuer-la-performance-de-livraison-logicielle\u002Findex",[5654,1591,907,17862,5009,906],"02O3nnqMxX0qEIFlEpZBfSKGGmji9sEf_8tK7bdpLXs",{"id":23411,"title":23412,"alt":23413,"authors":23414,"body":23416,"date":23717,"description":23718,"extension":890,"image":891,"meta":23719,"navigation":893,"ogImage":891,"path":23720,"published":893,"reviewers":23721,"seo":23728,"stem":23729,"tags":23730,"__hash__":23731},"blogs\u002Fblogs\u002F2024-10-31-lobservabilit-un-pilier-essentiel-dans-ladoption-du-cloud-et-des-architectures-modernes\u002Findex.md","L'Observabilité : Un Pilier Essentiel dans l’adoption du Cloud et des architectures modernes","Observabilité et stratégie",[23415],{"id":18862,"name":18863,"image":21164,"linkedin":18865,"x":901},{"type":16,"value":23417,"toc":23704},[23418,23421,23438,23441,23444,23448,23451,23477,23480,23487,23490,23494,23497,23529,23533,23536,23539,23542,23545,23549,23557,23560,23566,23570,23573,23600,23604,23607,23610,23613,23633,23639,23642,23646,23649,23653,23656,23659,23663,23666,23680,23684,23687,23694,23698,23701],[19,23419,23420],{},"Avec l'essor des technologies, notamment de l’IA, les grands groupes comme les start-up se tournent vers des plateformes modernes, parfois complexes (microservices, kubernetes, NoSQL, kafka, …), ainsi que vers des environnements Clouds tels que GCP, AWS ou Azure . Cette utilisation n’est pas toujours encapsulée dans un écosystème optimal dont voici les principaux organes:",[443,23422,23423,23426,23429,23432,23435],{},[446,23424,23425],{},"Le DevOps\u002FSRE",[446,23427,23428],{},"L’Agilité",[446,23430,23431],{},"Les bonnes pratiques d’architecture",[446,23433,23434],{},"Les bonnes pratiques de développement (Software Craftsmanship)",[446,23436,23437],{},"L’Observabilité",[19,23439,23440],{},"Souvent traité dans un second temps, l’Observabilité est pourtant essentielle à la réussite et au suivi de votre projet. Comment pouvons-nous améliorer notre application si nous ne sommes pas capables de mesurer ? L’observation des applications dans leur ensemble permet de valider que vous vous dirigez dans la bonne direction (ou la mauvaise).",[19,23442,23443],{},"Dans cet article, nous allons explorer comment l'Observabilité est incontournable pour maitriser votre transformation et comment Datadog a su proposer une des solutions d’Observabilité les plus avancées du marché.",[23,23445,23447],{"id":23446},"comprendre-lobservabilité-et-ses-enjeux","Comprendre l’Observabilité et ses Enjeux",[19,23449,23450],{},"L'Observabilité est un concept qui découle du monitoring (infrastructures, applications). Elle est d’ailleurs souvent confondue avec la supervision. Cependant, l’Observabilité est plus complexe et apporte un grand nombre de nouveaux concepts:",[443,23452,23453,23456,23459,23462,23465,23468,23471,23474],{},[446,23454,23455],{},"Accessible à tous (métier et technique)",[446,23457,23458],{},"Corrélation des données",[446,23460,23461],{},"Propose une vue d’ensemble (expérience utilisateur, sécurité, application, Cloud, ...)",[446,23463,23464],{},"Accepte plus de type de données comme le coûts d’utilisation des services Cloud",[446,23466,23467],{},"Intègre une gestion des incidents",[446,23469,23470],{},"Propose des services d’aide à la décision basé sur l‘IA",[446,23472,23473],{},"L’approche proactive (détection avant l’incident)",[446,23475,23476],{},"vision holistique de vos produits (applications)",[19,23478,23479],{},"En termes plus simples, c'est la capacité à comprendre ce qui se passe dans un système complexe en observant ses métriques, ses logs, ses traces et toutes autres données pertinentes. Dans le principe, plus vous ingérez de types de données, plus l’observation sera efficace. L’origine d’un événement (incident, changement de performance, volumétrie, …) est instantanément compréhensible et nous le voyons avec toutes ses adhérences. Par exemple, une perte de qualité sur l’application mobile peut-être identifiée par une trace (ligne de code), une métrique Cloud, à un journal et à un autre évènement tel qu’une mise en production.",[19,23481,23482,23483,23486],{},"Cette évolution de la supervision, permet également des démarches FinOps et ",[91,23484,5754],{"href":21171,"rel":23485},[95],", très utiles avec les services Cloud.",[19,23488,23489],{},"En raison de la nature distribuée des architectures Cloud modernes, il devient essentiel d’avoir une visibilité complète et en temps réel sur les applications pour détecter les problèmes potentiels avant qu'ils n'affectent les utilisateurs.",[23,23491,23493],{"id":23492},"pourquoi-lobservabilité-est-cruciale","Pourquoi l'Observabilité est cruciale",[19,23495,23496],{},"Lors de l’adoption ou la migration vers le Cloud Public, plusieurs éléments doivent être surveillés de près :",[6138,23498,23499,23505,23511,23517,23523],{},[446,23500,23501,23504],{},[34,23502,23503],{},"Performance des Applications :","  Plus votre application sera performante, plus vous serez en capacité d’optimiser votre utilisation du Cloud, donc votre facture. De plus, la latence, le temps de réponse des applications peuvent fluctuer au cours de la migration. Il est important d’avoir une vue très détaillée (à la ligne de code) des performances pendant la phase d’adoption ou de migration.",[446,23506,23507,23510],{},[34,23508,23509],{},"Disponibilité des Services :"," La transition vers le Cloud implique souvent le découpage des applications en microservices. Cette réorganisation entraîne une multiplication des points de défaillance potentiels. Une vue d’ensemble permet de suivre la santé de chaque service et d’éviter de se perdre dans des applications, notamment avec le FaaS (Function-as-a-Service).",[446,23512,23513,23516],{},[34,23514,23515],{},"Coût :"," Le Cloud Public offre une flexibilité exceptionnelle, mais peut aussi générer des coûts imprévus. L'Observabilité peut mettre en évidence les ressources sous-utilisées ou sur-provisionnées, aidant ainsi à optimiser les coûts.",[446,23518,23519,23522],{},[34,23520,23521],{},"Sécurité :"," Il est important de ne pas délaisser la sécurité qui doit faire partie intégrante de l’observation de vos applications.",[446,23524,23525,23528],{},[34,23526,23527],{},"Ressenti utilisateur :"," Une migration peut, même dans le cas de meilleures performances backend, avoir un impact significatif sur vos utilisateurs. S’il est positif, cette donnée justifiera votre décision de migrer.",[23,23530,23532],{"id":23531},"comment-aborder-lobservabilité","Comment aborder l’Observabilité",[19,23534,23535],{},"L’Observabilité ne doit pas être considérée comme solution à un problème technique. Son succès repose dans des fondations basées sur vos besoins métiers et son acceptation par tous.",[19,23537,23538],{},"A contrario de la supervision, qui n’est qu’un moyen technique de répondre à un besoin technique, il est essentiel de se poser les bonnes questions: ce dont vous avez réellement besoin doit être identifié.",[19,23540,23541],{},"Prenons l’exemple d’une Fintech:  elle doit répondre à des critères stricts comme la qualité de son service, la sécurité des données ou encore répondre à une forte croissance. Dans ce contexte, il parait évident que ses critères ne sont pas réservés aux équipes de développement. Il est préférable que les équipes directions ou clientèles connaissent l’état de leur solution et qu’un incident soit détecté rapidement, voire avant qu’il ne se produise. Et dans le cas d’un dysfonctionnement, il est impératif d’identifier le plus rapidement possible l’origine du problème. C’est ce que doit permettre l’Observabilité.",[19,23543,23544],{},"Une solution trop technique et complexe, ne servira que les équipes techniques et ne permettra pas forcément de comprendre l’impact pour les clients ou sur le CA de l’entreprise. De plus, un outil qui ne rassemble pas et n’exploite pas l’ensemble des données utiles à cette tâche ne sera pas efficace.",[23,23546,23548],{"id":23547},"datadog-lincontournable","Datadog, l’incontournable",[19,23550,23551,23552,23556],{},"Malgré un marché établi dans le domaine du monitoring et de la supervision, ",[91,23553,3547],{"href":23554,"rel":23555},"https:\u002F\u002Fwww.datadoghq.com\u002Ffr",[95]," a su se faire une place de leader avec l’émergence du Cloud Public.",[19,23558,23559],{},"Ayant accompagné de nombreuses sociétés avec Datadog notamment un leader de l’immobilier, une filiale d’un des plus gros fournisseurs mondiaux de services de restauration ou encore une Fintech; je vous propose mes retours d’expériences.",[19,23561,23562],{},[176,23563],{"alt":23564,"src":23565},"Gartner, Magic Quadrant for Observability Platforms, Gregg Siegfried, Padraig Byrne, Mrudula Bangera, Matt Crossley, 12 August 2024","\u002Fcontent-assets\u002F2024-10-31-lobservabilit-un-pilier-essentiel-dans-ladoption-du-cloud-et-des-architectures-modernes\u002Fassets\u002Fimg1.webp",[23,23567,23569],{"id":23568},"démarrer-de-zéro","Démarrer de zéro",[19,23571,23572],{},"Partons sur cette Startup bancaire. Elle disposait malgré ses liens avec une des principales banques française d’une indépendance technologique. Plus exactement, nous avons développé de zéro une solution bancaire en nous appuyant uniquement de technologies Cloud Public et sur Datadog bien évidement. Nous avions pris en compte les critères Fintech, cités plus haut, mais nous avions un objectif plus urgent: le Time to Market. Avec une disponibilité de l’application en quelques mois et des responsabilité bancaires, la question de l’Observabilité a été intégrée dès l’origine. Datadog donnait une vision :",[443,23574,23575,23582,23585,23588,23591,23594,23597],{},[446,23576,23577,23578,2418],{},"des tests métiers (approche ",[91,23579,23581],{"href":20362,"rel":23580},[95],"DDD",[446,23583,23584],{},"la qualité de l’expérience utilisateur",[446,23586,23587],{},"la surveillance de la sécurité de l’intégralité de l’application et de son développement",[446,23589,23590],{},"le taux de disponibilité, dont les SLA du Core Banking",[446,23592,23593],{},"l’impact utilisateur des mises en production (jusqu’à 300\u002Fsemaine dans les premiers mois)",[446,23595,23596],{},"des performances",[446,23598,23599],{},"des KPI métier, technique, FinOps, etc…\nCependant son implémentation était relativement simple car intégrée dès l’origine. Maintenant, évoquons le déploiement à l’échelle d’une entreprise de promotion immobilière cotée, avec des centaines de projets historiques comme novateurs.",[23,23601,23603],{"id":23602},"intégrer-lobservabilité-à-léchelle","Intégrer l’Observabilité à l’échelle",[19,23605,23606],{},"Dans cette situation, il ne faut pas que la solution soit portée par des objectifs purement techniques. Il y a également des enjeux d’échelle qui impliquent une organisation de l’Observabilité et des enjeux financiers et écologiques (CSRD).",[19,23608,23609],{},"Dans un premier temps, il faut prendre en compte l’ensemble des besoins de tous les acteurs : du DSI au développeur en passant par les responsables métiers. Pensez également à intégrer les responsables FinOps et GreenOps. Il est également indispensable d’avoir un inventaire des projets avec leurs priorités et criticités. Une étude permettra de choisir le meilleur outil mais aussi les étapes nécessaires à son adoption. Dans mon cas où la migration Cloud Public était finalisée, Datadog remporta haut la main la première place.",[19,23611,23612],{},"La seconde étape passe par la définitions des rôles des différents utilisateurs et la segmentation des données. Heureusement, Datadog propose un bon nombre de solutions:",[443,23614,23615,23618,23621,23624,23627,23630],{},[446,23616,23617],{},"Organisation sur plusieurs comptes",[446,23619,23620],{},"Droits et RBAC",[446,23622,23623],{},"Index par données",[446,23625,23626],{},"Visibilité des Dashbords",[446,23628,23629],{},"Filtres",[446,23631,23632],{},"Etc…\nUne fois la question de l’organisation traitée, nous pouvons réaliser un premier MVP (Produit minimum viable) d’un échantillon de projets représentatifs basé sur: leurs criticités, leurs aspects technologiques mais aussi leurs contextes fonctionnels.",[19,23634,23635],{},[176,23636],{"alt":23637,"src":23638},"Datadog propose une vision Map","\u002Fcontent-assets\u002F2024-10-31-lobservabilit-un-pilier-essentiel-dans-ladoption-du-cloud-et-des-architectures-modernes\u002Fassets\u002Fimg2.webp",[19,23640,23641],{},"Aujourd’hui, l’entreprise utilise Datadog sur l’ensemble de son spectre de projet (de l’agence immobilière à l’application de gestion des ventes) avec l’ensemble des équipes (technique ou non). Les rituels intègrent les rapports, l’infogérance est traitée via la solution, le pilotage FinOps du groupe est assuré par Datadog.",[23,23643,23645],{"id":23644},"passer-au-niveau-supérieur-en-alliant-méthodologie-et-observabilité","Passer au niveau supérieur en alliant méthodologie et Observabilité",[19,23647,23648],{},"S’appuyer sur les piliers d’une approche moderne augmentera l’efficacité de l’Observabilité. Il est essentiel que tous les acteurs de vos projets interagissent avec votre outil d’Observabilité, en consomment et en intégrant leurs données. Ces outils sont un investissement financier qu’il est important de rentabiliser dans une démarche ouverte.",[23,23650,23652],{"id":23651},"software-craftsmanship-pour-une-meilleure-intégration-de-lobservabilité","Software Craftsmanship : Pour une meilleure intégration de l’Observabilité",[19,23654,23655],{},"Le software craftsmanship est un mouvement qui prône l’excellence dans le développement logiciel, avec une attention particulière à la qualité du code, la testabilité et la maintenabilité.",[19,23657,23658],{},"Un code bien structuré, découplé et respectant les bonnes pratiques de software craftsmanship est plus facilement observable. Par exemple, les logs sont standardisés, les métriques sont instrumentées de manière cohérente et les erreurs sont gérées proprement.",[23,23660,23662],{"id":23661},"devops-une-observabilité-industrialisée","DevOps: Une Observabilité industrialisée",[19,23664,23665],{},"L’approche DevOps améliore encore la perspective d’Observabilité. En effet, nous pouvons industrialiser un ensemble de nouveaux éléments:",[443,23667,23668,23671,23674,23677],{},[446,23669,23670],{},"Déployer votre Observabilité en mode infrastructure as code (données, dashboard, alarme, …)",[446,23672,23673],{},"Les tests dans vos pipelines de déploiements intégrés avec votre outil d’Observabilité.",[446,23675,23676],{},"Automatiser des tests notamment dans vos déploiements sans indisponibilité (canary, blue and green, …)",[446,23678,23679],{},"Visualiser l’impact financier ou green d’une nouvelle fonctionnalité",[23,23681,23683],{"id":23682},"agilité-lobservabilité-mesure-vos-kpi","Agilité: L’Observabilité mesure vos KPI",[19,23685,23686],{},"Afin de suivre l’avancée de votre projet et remonter des données pertinentes pendant vos rituels, un outil d’Observabilité sera un grand allié. C’est dans ces circonstances que l’on comprend l’intérêt de l’accessibilité lié à l’Observabilité, car ces données sont récupérables directement par le chef de projet, le scrum master, etc.",[19,23688,23689,23690,44],{},"N’oubliez pas d’intégrer des KPI impacts environnementaux à vos projets (consommation carbone, valeur énergétique par utilisateur, …). Vous pouvez vous inspirez de notre article ",[91,23691,23693],{"href":21177,"rel":23692},[95],"Low Carbon dans le Cloud - Partie 2",[23,23695,23697],{"id":23696},"pour-conclure","Pour conclure",[19,23699,23700],{},"Que vous soyez DSI, CTO ou encore CPTO, vous avez une vision stratégique de l’Observabilité. C’est pour vous un élément concurrentiel, un gain de qualité de vos produits, un gain d’argent des fois conséquent. Cependant, l’appropriation d’une solution avec la bonne méthodologie par vos équipes n’est pas une chose simple. Vous faire accompagner dans cette démarche sera certainement un gain de temps et de réussite, mais soyez vigilant de choisir un partenaire qui sera capable d’aborder ce chantier à votre niveau.",[19,23702,23703],{},"Nous avons mis en avant Dadadog car, dans 9 fois sur 10, il ressort gagnant de nos études et benchmark, depuis déjà quelques années. Aujourd’hui convaincu par notre expérience dans l’accompagnement à l’Observabilité, HoppR a décidé de mettre en place un partenariat unique avec Datadog : HoppR et Datadog pour une Observabilité comme pilier stratégique.",{"title":350,"searchDepth":364,"depth":364,"links":23705},[23706,23707,23708,23709,23710,23711,23712,23713,23714,23715,23716],{"id":23446,"depth":364,"text":23447},{"id":23492,"depth":364,"text":23493},{"id":23531,"depth":364,"text":23532},{"id":23547,"depth":364,"text":23548},{"id":23568,"depth":364,"text":23569},{"id":23602,"depth":364,"text":23603},{"id":23644,"depth":364,"text":23645},{"id":23651,"depth":364,"text":23652},{"id":23661,"depth":364,"text":23662},{"id":23682,"depth":364,"text":23683},{"id":23696,"depth":364,"text":23697},"2024-10-31T16:21:44.196Z","Avec l'essor des technologies, notamment de l’IA, les grands groupes comme les start-up se tournent vers des plateformes modernes, parfois complexes (microservices, kubernetes, NoSQL, kafka, …), ainsi",{},"\u002Fblogs\u002F2024-10-31-lobservabilit-un-pilier-essentiel-dans-ladoption-du-cloud-et-des-architectures-modernes",[23722,23724,23726],{"id":1577,"name":1578,"image":23723,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T162144Z&X-Amz-Expires=3600&X-Amz-Signature=575fafdda7bf9cfe162a2357d2b8c4fd07170d9f398f28e2958fb9d613a531d5&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1582,"name":1583,"image":23725,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T162144Z&X-Amz-Expires=3600&X-Amz-Signature=c3ec652c8438443b244fcc323f7d69cb3a6689d16e46ccd7512dd616836f78b1&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":897,"name":898,"image":23727,"linkedin":900,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Ff8f82a79-9d41-4302-b1a5-37882985167f\u002Fnicoz_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T162144Z&X-Amz-Expires=3600&X-Amz-Signature=df02b8ec0091aabb844ccd87f5ecc73a9d04622d0ecf0cd9ca81d722f3ca1c8f&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":23412,"description":23718},"blogs\u002F2024-10-31-lobservabilit-un-pilier-essentiel-dans-ladoption-du-cloud-et-des-architectures-modernes\u002Findex",[906,905,5009,1591,1879],"IHNFVwmNOBdYB2cwFLg5qdqDGTksVCSw5EHmKp_U_kQ",{"id":23733,"title":23734,"alt":23735,"authors":23736,"body":23738,"date":23799,"description":23800,"extension":890,"image":891,"meta":23801,"navigation":893,"ogImage":891,"path":23802,"published":893,"reviewers":23803,"seo":23806,"stem":23807,"tags":23808,"__hash__":23809},"blogs\u002Fblogs\u002F2024-10-31-podcast-greenops-tamara-guilbert-x-samuel-bally\u002Findex.md","Podcast GreenOps Tamara Guilbert x Samuel Bally","Tamara et Samuel en podcast",[23737],{"id":897,"name":898,"image":7084,"linkedin":900,"x":901},{"type":16,"value":23739,"toc":23793},[23740,23744,23747,23750,23754,23757,23760,23764,23767,23770,23774,23777,23780,23783,23790],[7089,23741,23743],{"id":23742},"le-greenops-lavenir-de-la-tech","🚀 Le GreenOps : L'Avenir de la Tech ?",[19,23745,23746],{},"Dans un monde où l'impact environnemental devient un sujet incontournable, la tech ne fait pas exception. Le concept de GreenOps émerge comme une réponse à cette problématique, et pourrait bien définir l'avenir de notre industrie.🌱",[19,23748,23749],{},"Dans son dernier épisode de Tech Your Dream, Tamara Guilbert a reçu Samuel Bally, Head of Cloud chez HoppR pour échanger ce sujet. Un grand merci pour invitation !",[23,23751,23753],{"id":23752},"️de-quoi-parles-le-podcast","🎙️ De quoi parles le podcast ?",[19,23755,23756],{},"Si vous vous intéressez au Green dans le Cloud, ce podcast sera parfait pour débuter. L’évangélisation sur les notions de GreenOps, l’équilibre entre coût et production de gaz à effet de serre ou encore les leviers d’actions sont évoqués. Samuel vous raconte son expérience, ce qui a marché et les voies sans issues. Une immersion dans le GreenOps garanti sans GreenWashing.🌿",[19,23758,23759],{},"“C'est tellement compliqué à mesurer que plus nous essayons d'être précis plus nous avons de chances d'être loin de la vérité” - Samuel Bally",[84,23761,23763],{"id":23762},"outils-clés-pour-un-cloud-plus-vert","🌍  Outils Clés pour un Cloud Plus Vert",[19,23765,23766],{},"Lors du podcast, Samuel partage des méthodes et outils pour évaluer l'impact carbone des projets technologiques. L'idée est d'aller au-delà des simples indicateurs de performance classiques, en introduisant des KPI écologiques.",[19,23768,23769],{},"L'observabilité est proposée comme une alliée précieuse. En suivant des Dashboard Green, nous pouvons ajuster la trajectoire de votre produit et comparer vos données CO2 avec les coûts, les performances ou encore l’impact utilisateur.",[84,23771,23773],{"id":23772},"un-enjeux-pour-les-entreprises"," 🌱 Un enjeux pour les entreprises",[19,23775,23776],{},"Le podcast évoque les problématiques liée à la #CSRD (La Directive relative à la publication d'informations en matière de durabilité par les entreprises).",[19,23778,23779],{},"Samuel propose un approche raisonnée, afin de garder la main sur votre feuille de route et vos dépenses.",[19,23781,23782],{},"💚 S’engager dans une démarche GreenOps, c’est aussi une manière de se démarquer dans un secteur concurrentiel en constante évolution, notamment avec l’IA si consommatrice d’énergie.",[19,23784,23785,23786],{},"Retrouvez dès maintenant l’intégralité du podcast : ",[91,23787,23788],{"href":23788,"rel":23789},"https:\u002F\u002Fopen.spotify.com\u002Fepisode\u002F2zihL4JMegzJML40oPyda1?si=uOM3YnVvQ4uX12qe5OG62w",[95],[19,23791,23792],{},"Bonne écoute 😄",{"title":350,"searchDepth":364,"depth":364,"links":23794},[23795],{"id":23752,"depth":364,"text":23753,"children":23796},[23797,23798],{"id":23762,"depth":370,"text":23763},{"id":23772,"depth":370,"text":23773},"2024-10-31T16:21:19.696Z"," Dans un monde où l'impact environnemental devient un sujet incontournable, la tech ne fait pas exception. Le concept de GreenOps émerge comme une réponse à cette problématique, et pourrait bien défin",{},"\u002Fblogs\u002F2024-10-31-podcast-greenops-tamara-guilbert-x-samuel-bally",[23804],{"id":18862,"name":18863,"image":23805,"linkedin":18865,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fb8425b05-a0a4-4560-964d-259e8a84c063\u002Fsamuel.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45GO43JXI4%2F20241031%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241031T162119Z&X-Amz-Expires=3600&X-Amz-Signature=1acb072d7d3f299253ce2bf16aae31eef99a752fc127927e9f4b7b68015536a3&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":23734,"description":23800},"blogs\u002F2024-10-31-podcast-greenops-tamara-guilbert-x-samuel-bally\u002Findex",[21430,906],"MtFkCIMJNLmPN8bUI98WafRYOPeYxfXmDejtm5ahmds",{"id":23811,"title":23812,"alt":23813,"authors":23814,"body":23816,"date":24110,"description":24111,"extension":890,"image":891,"meta":24112,"navigation":893,"ogImage":891,"path":24113,"published":893,"reviewers":24114,"seo":24119,"stem":24120,"tags":24121,"__hash__":24124},"blogs\u002Fblogs\u002F2024-10-11-retour-survivre-dans-la-js-jungle-des-outils-de-tests-de-lise-quesnel-au-devfest-2024\u002Findex.md","Retour \"Survivre dans la JS-jungle des outils de tests\" de Lise QUESNEL au Devfest 2024","Conférence de Lise QUESNEL au DevFest 2024",[23815],{"id":5813,"name":5814,"image":5815,"linkedin":5816,"x":901},{"type":16,"value":23817,"toc":24096},[23818,23822,23831,23834,23838,23841,23844,23848,23851,23855,23858,23866,23870,23873,23894,23900,23904,23907,23914,23918,23921,23928,23932,23935,23938,23961,23965,23968,23999,24003,24006,24009,24012,24058,24062,24065,24068,24077,24081,24084,24087],[23,23819,23821],{"id":23820},"introduction","Introduction",[19,23823,23824,23825,23830],{},"Cet article fait suite au ",[91,23826,23829],{"href":23827,"rel":23828},"https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-08-27-retour-sur-le-devfest",[95],"retour de HoppR sur le DevFest 2024"," et se concentre sur la conférence de Lise QUESNEL qui aborde les outils de tests JavaScript.",[19,23832,23833],{},"Pour être concis, je vous résume les points qui m'ont le plus intéressés et ne reprendrai pas toutes les métaphores utilisées dans sa conférence.\nBref ! Re-déroulons le chemin de JS-Jungle ensemble !",[23,23835,23837],{"id":23836},"tester-cest-douter","Tester, c'est douter ?",[19,23839,23840],{},"Avant de rentrer véritablement dans la JS-Jungle, répondons au pourquoi ? Et oui, pourquoi tester ?\nTester manuellement est une activité chronophage avec des résultats non répétables. Les forces des tests automatisés sont leur rapidité et leur répétabilité.\nCes deux qualités diminuent la longueur des boucles de feedback que ce soit en local, en pipeline de CI\u002FCD ou même en recette.",[19,23842,23843],{},"Et en quoi réduire la longueur des boucles de feedback est intéressant ?\nPlus l'erreur est détectée tard dans la chaîne de valeur, plus elle sera coûteuse à réparer (Localisation, recontextualisation, etc).\nAssocié à de petites incrémentations, tester permet de délivrer de la valeur plus rapidement toute en augmentant la qualité.\nDe mon point de vue, il est aussi l'occasion d'augmenter la confiance entre les différentes parties prenantes (développeurs, PO, QA, etc) pour, à terme, diminuer la pression au quotidien.",[23,23845,23847],{"id":23846},"les-typologies-doutils-de-test","Les typologies d'outils de test",[19,23849,23850],{},"Il est nécessaire de comprendre les différentes typologies car elles ne doivent pas être utilisées toutes en même temps. Chaque contexte a son besoin.",[23,23852,23854],{"id":23853},"les-lanceurs-test-runner","Les lanceurs (Test runner)",[19,23856,23857],{},"Leur but est d'exécuter les tests et d'exporter leurs résultats.",[19,23859,23860,23861],{},"Exemple: ",[91,23862,23865],{"href":23863,"rel":23864},"https:\u002F\u002Fkarma-runner.github.io\u002Flatest\u002Findex.html",[95],"Karma",[23,23867,23869],{"id":23868},"les-structurateurs","Les structurateurs",[19,23871,23872],{},"Leur but est de structurer l'écriture des tests pour facilité leur lisibilité, écriture et maintenance.",[19,23874,23875,23876,23881,23882,23887,23888,23893],{},"Les deux syntaxes, aussi appelées modèles de tests ou patterns, les plus connues sont AAA (",[91,23877,23880],{"href":23878,"rel":23879},"https:\u002F\u002Fwiki.c2.com\u002F?ArrangeActAssert=",[95],"Arrange Act Assert",") et Gerkhin (",[91,23883,23886],{"href":23884,"rel":23885},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGiven-When-Then",[95],"Given When Then",").\nToutes les deux expriment un contexte, une action puis des conséquences. Gerkhin se distingue par son approche ",[91,23889,23892],{"href":23890,"rel":23891},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FProgrammation_pilot%C3%A9e_par_le_comportement",[95],"comportementale"," des sujets métiers.\nCela permet notamment d'obtenir un nommage\u002Flangage commun compréhensible par les développeurs et le métier.",[19,23895,23860,23896],{},[91,23897,18801],{"href":23898,"rel":23899},"https:\u002F\u002Fgithub.com\u002Fcucumber\u002Fcucumber-js",[95],[23,23901,23903],{"id":23902},"les-utilitaires","Les utilitaires",[19,23905,23906],{},"Leur but est de vérifier les attendus et de lever des exceptions claires. Cette notion est appelé \"Assertion\".",[19,23908,23860,23909],{},[91,23910,23913],{"href":23911,"rel":23912},"https:\u002F\u002Fwww.chaijs.com\u002F",[95],"Chai",[23,23915,23917],{"id":23916},"les-spies-stubs-et-mocks","Les spies, stubs et mocks",[19,23919,23920],{},"Leur but est d'isoler la partie du code testée par la simulation du fonctionnement de ces dépendances ou encore l'analyse à l'appel de ces dépendances.",[19,23922,23860,23923],{},[91,23924,23927],{"href":23925,"rel":23926},"https:\u002F\u002Fsinonjs.org\u002F",[95],"Sinon",[23,23929,23931],{"id":23930},"les-multi-typologies","Les multi-typologies",[19,23933,23934],{},"Si vous ne vous sentez pas d'avoir trop de dépendances dans votre projet, il existe aussi des outils couvrants toutes ces typologies :",[19,23936,23937],{},"Exemples:",[443,23939,23940,23947,23954],{},[446,23941,23942],{},[91,23943,23946],{"href":23944,"rel":23945},"https:\u002F\u002Fjestjs.io\u002Ffr\u002F",[95],"Jest",[446,23948,23949],{},[91,23950,23953],{"href":23951,"rel":23952},"https:\u002F\u002Fvitejs.dev\u002F",[95],"Vite",[446,23955,23956],{},[91,23957,23960],{"href":23958,"rel":23959},"https:\u002F\u002Fjasmine.github.io\u002F",[95],"Jasmine",[23,23962,23964],{"id":23963},"les-contrôleurs-de-navigateurs","Les contrôleurs de navigateurs",[19,23966,23967],{},"La typologie des contrôleurs de navigateurs est à part dans le sens où leur but est de simuler un comportement utilisateur au plus proche du navigateur.\nIl y a 3 manières de contrôler un navigateur :",[443,23969,23970,23978,23986],{},[446,23971,23972,23973],{},"Via ces drivers : ",[91,23974,23977],{"href":23975,"rel":23976},"https:\u002F\u002Fwww.selenium.dev\u002Fselenium\u002Fdocs\u002Fapi\u002Fjavascript\u002Findex.html",[95],"Selenium",[446,23979,23980,23981],{},"Via script JS : ",[91,23982,23985],{"href":23983,"rel":23984},"https:\u002F\u002Fwww.cypress.io\u002F",[95],"Cypress",[446,23987,23988,23989,17794,23994],{},"Via API Native : ",[91,23990,23993],{"href":23991,"rel":23992},"https:\u002F\u002Fplaywright.dev\u002F",[95],"Playwright",[91,23995,23998],{"href":23996,"rel":23997},"https:\u002F\u002Fpptr.dev\u002F",[95],"Puppeteer",[23,24000,24002],{"id":24001},"les-tests-bancals","Les tests bancals",[19,24004,24005],{},"Si vous avez déjà commencé vos premiers tests, vous tomberez sur des tests bancals (Flaky en anglais) dont le résultat n'est pas répétable de manière certaine. Un jour il passe, l'autre non...",[19,24007,24008],{},"Un élément de réponse pour comprendre pourquoi il ne passe pas tout le temps est que le test est basé sur “quelque chose” de variable. Dans certains cas, pour contourner cette variabilité, nous pouvons simuler (mocker) ou remplacer l’élément variant.",[19,24010,24011],{},"Exemple:",[443,24013,24014,24017,24020,24023,24032,24035,24038],{},[446,24015,24016],{},"Lecture d'un tableau de données dans un ordre non déterministe",[446,24018,24019],{},"Modification des données par un test précédent",[446,24021,24022],{},"Appel à une date relative (Aujourd'hui, demain, hier)",[446,24024,24025,24026,24031],{},"Sélecteur CSS non sûr (Vous pouvez utiliser les rôles: ",[91,24027,24030],{"href":24028,"rel":24029},"https:\u002F\u002Ftesting-library.com\u002F",[95],"Testing-library",")\nDes conseils pour garder une base de tests saine et, en conséquence, une confiance envers vos tests:",[446,24033,24034],{},"\"N'hésitez pas à mettre vos tests bancals en quarantaine\"",[446,24036,24037],{},"\"Mettez des règles sur vos quarantaines (Nombre de jours maximums en quarantaine, nombre de tests maximum, etc)\"",[446,24039,24040,24041,24046,24047,24052,24053,44],{},"“De manière générale, respectez les principes ",[91,24042,24045],{"href":24043,"rel":24044},"https:\u002F\u002Fdzone.com\u002Farticles\u002Ffirst-principles-solid-rules-for-tests",[95],"FIRST","”\nIl existe des questions ouvertes que sont l'unité d'un test unitaire, la sociabilité des tests ou l'utilité d'un test qui sont en fait des sujets exploratoires.\nSi vous êtes totalement perdu, les langages front étant orientés composant, il est plus simple de prendre comme unité par défaut le composant (attention, ",[91,24048,24051],{"href":24049,"rel":24050},"https:\u002F\u002Fwww.entropywins.wtf\u002Fblog\u002F2017\u002F01\u002F02\u002Fsimple-is-not-easy\u002F",[95],"simple n'est pas facile",").\nPour explorer ces notions, vous pouvez essayer ",[91,24054,24057],{"href":24055,"rel":24056},"https:\u002F\u002Fmedium.com\u002F@imenezzine\u002Ftdd-vs-test-first-development-quelle-est-la-diff%C3%A9rence-ccbea4771484",[95],"le test-first ou encore le test driven developement",[23,24059,24061],{"id":24060},"les-stratégies-de-tests","Les stratégies de tests",[19,24063,24064],{},"Vous trouverez dans la JS-Jungle de nombreux noms de tests (unitaire, intégration, bout en bout, acceptance, composants, contracts, etc).\nLeurs significations varient en fonction des équipes, ce sont vos collègues qui vous expliquerons, au mieux, leur vision.",[19,24066,24067],{},"De manière simplifiée, nous dirons que nous avons des tests unitaires pour les fonctions utilitaires, des tests d’intégration pour les composants et des tests de bout en bout pour simuler le comportement utilisateur.\nPlus vous vous rapprochez des tests unitaires, plus vos unités de test sont fines et rapides mais moins vous pouvez avoir confiance en ceux-ci seules.",[19,24069,24070,24071,24076],{},"La question finale sera donc lesquels utiliser et en quelle proportion ?\nVous trouverez de nombreuses distributions de tests : ",[91,24072,24075],{"href":24073,"rel":24074},"https:\u002F\u002Fthetestingarchitect.substack.com\u002Fp\u002Ftest-pyramid-test-honeycomb-test",[95],"la pyramide, l'alvéole, le trophée",".\nL'orientation des langages front modernes pousse vers l'utilisation de la distribution en trophée (Plus de tests de bout en bout que de tests unitaires et moins de tests de bout en bout que de tests d'intégration).",[23,24078,24080],{"id":24079},"ouverture","Ouverture",[19,24082,24083],{},"J'aimerais insister sur l'analyse statique de votre langage. Même si ce n'est pas un test en soit, le fait de typer, de créer des interfaces pour vos échanges, cela vous aidera à donner de la confiance en votre code et même à visualiser les sujets métiers.",[19,24085,24086],{},"Enfin, les tests manuels ne sont pas à bannir. Ils ne sont pas adaptés pour garantir la non-régression. Par contre, leur flexibilité est avantageuse pour des sujets exploratoires (Nouvelles erreurs, cas à la marge, etc). Peut-être devrions nous les appeler “tests exploratoires” ? A vous d'y répondre et de continuer de délivrer de la valeur pour vos utilisateurs et clients !",[19,24088,24089,24090,24095],{},"Merci de votre lecture et merci aussi à Lise QUESNEL pour son talk !\nJ'en profite pour la féliciter pour la qualité de la narration et de son écriture.\nN'hésitez pas à regarder la ",[91,24091,24094],{"href":24092,"rel":24093},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=LqwfhxyiwXU&list=PLuZ_sYdawLiXf92Uq5iE5LlYKrOv1IUvx&index=7",[95],"rediffusion"," de cette conférence.",{"title":350,"searchDepth":364,"depth":364,"links":24097},[24098,24099,24100,24101,24102,24103,24104,24105,24106,24107,24108,24109],{"id":23820,"depth":364,"text":23821},{"id":23836,"depth":364,"text":23837},{"id":23846,"depth":364,"text":23847},{"id":23853,"depth":364,"text":23854},{"id":23868,"depth":364,"text":23869},{"id":23902,"depth":364,"text":23903},{"id":23916,"depth":364,"text":23917},{"id":23930,"depth":364,"text":23931},{"id":23963,"depth":364,"text":23964},{"id":24001,"depth":364,"text":24002},{"id":24060,"depth":364,"text":24061},{"id":24079,"depth":364,"text":24080},"2024-10-11T12:52:42.324Z","Cet article fait suite au [retour de HoppR sur le DevFest 2024](https:\u002F\u002Fblog.hoppr.tech\u002Fblogs\u002F2024-08-27-retour-sur-le-devfest) et se concentre sur la conférence de Lise QUESNEL qui aborde les outils",{},"\u002Fblogs\u002F2024-10-11-retour-survivre-dans-la-js-jungle-des-outils-de-tests-de-lise-quesnel-au-devfest-2024",[24115,24117],{"id":1577,"name":1578,"image":24116,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20241011%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241011T125242Z&X-Amz-Expires=3600&X-Amz-Signature=dfeb6b874b089d1b0802df82a5a3f85d6ab5167b870d244e384d1c65947e1aca&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1582,"name":1583,"image":24118,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20241011%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20241011T125242Z&X-Amz-Expires=3600&X-Amz-Signature=a0d7333f5bdeefc5c004ae47d547f6548bfe142cd76f8676bc5bbf202d4f08d3&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":23812,"description":24111},"blogs\u002F2024-10-11-retour-survivre-dans-la-js-jungle-des-outils-de-tests-de-lise-quesnel-au-devfest-2024\u002Findex",[6606,24122,6271,24123,8044,7819],"2024","js","7BMIJC1Di8S_kLnK3D1Pitbt7H854hiMLVwvVgfmlAs",{"id":24126,"title":24127,"alt":24128,"authors":24129,"body":24131,"date":25198,"description":25199,"extension":890,"image":891,"meta":25200,"navigation":893,"ogImage":891,"path":25201,"published":893,"reviewers":25202,"seo":25211,"stem":25212,"tags":25213,"__hash__":25216},"blogs\u002Fblogs\u002F2024-09-27-sauvegarder-ltat-final-dun-agrgat-par-ses-vnements\u002Findex.md","Sauvegarder l’état final d’un agrégat par ses événements","Des aggregats imaginés sous la forme de cellules organiques",[24130],{"id":1887,"name":1888,"image":1889,"linkedin":1890,"x":1891},{"type":16,"value":24132,"toc":25191},[24133,24136,24144,24147,24150,24154,24157,24168,24509,24512,24520,24525,24529,24532,24546,24551,24554,24559,24621,24625,24628,24631,25006,25021,25180,25183,25185,25188],[19,24134,24135],{},"Pré-requis pour ne pas être trop perdu",[443,24137,24138,24141],{},[446,24139,24140],{},"quelques bases en Domain Driven Design (DDD)",[446,24142,24143],{},"quelques bases en JPA \u002F Hibernate",[19,24145,24146],{},"La notion d’agrégat du Domain Driven Design désigne un ensemble cohérent d’objets du domaine qui doit être manipulé comme une seule unité métier. Dans cette logique, les décisions métiers sont prises par l'agrégat et prennent la forme d'événements (Domain Event). L'événement est donc la représentation d'une mutation: l'agrégat a changé d'état.",[19,24148,24149],{},"Je vous propose ainsi de voir comme l'on peut persister l'état final d'un agrégat en ne se basant que sur les décisions qu'il a prises.",[23,24151,24153],{"id":24152},"lagrégat","L'agrégat",[19,24155,24156],{},"L'exemple que nous allons prendre parle de l'accès d'un utilisateur dont les règles de gestion sont les suivantes:",[443,24158,24159,24162,24165],{},[446,24160,24161],{},"l'accès peut être suspendu",[446,24163,24164],{},"si l'accès est suspendu, il ne peut pas être suspendu à nouveau (erreur)",[446,24166,24167],{},"l'accès peut être réactivé",[344,24169,24171],{"className":2792,"code":24170,"language":2794,"meta":350,"style":350},"@Aggregate \u002F\u002F Annotation personnalisée à des fins de documentation\nclass UserAccess {\n\n    \u002F\u002F Le mot clé \"transient\" est faculatif, il me sert surtout à indiquer que les événements ne seront pas persistés en tant que tel\n    private final transient List\u003CUserAccessEvent> occurredEvents = new ArrayList\u003C>();\n\n    private final UserId id;\n    private Instant suspendedAt;\n\n    public List\u003CUserEvent> occurredEvents() {\n        return List.copyOf(occurredEvents);\n    }\n\n    public void suspend(Clock now) {\n        if (suspendedAt != null) {\n            throw new UserAccessIsAlreadySuspended(id);\n        }\n\n        UserAccessSuspended event = UserAccessSuspended.builder()\n                .userId(id)\n                .suspendedAt(now.instant())\n                .build();\n\n        \u002F\u002F La décision prise par l'aggrégat est stockée\n        this.occurredEvents.add(event);\n\n        \u002F\u002F L'état interne de l'aggrégat est muté\n        this.apply(event);\n    }\n\n    private void apply(UserAccessSuspended event) {\n        this.suspendedAt = event.suspendedAt();\n    }\n\n    \u002F\u002F ... d'autres règles ici ...\n}\n",[352,24172,24173,24184,24194,24198,24203,24234,24238,24250,24260,24264,24280,24293,24297,24301,24319,24335,24348,24353,24357,24375,24385,24401,24410,24414,24419,24432,24436,24441,24451,24455,24459,24476,24492,24496,24500,24505],{"__ignoreMap":350},[355,24174,24175,24178,24181],{"class":357,"line":358},[355,24176,24177],{"class":1119},"@",[355,24179,24180],{"class":2801},"Aggregate",[355,24182,24183],{"class":3858}," \u002F\u002F Annotation personnalisée à des fins de documentation\n",[355,24185,24186,24189,24192],{"class":357,"line":364},[355,24187,24188],{"class":2801},"class",[355,24190,24191],{"class":2805}," UserAccess",[355,24193,3031],{"class":1119},[355,24195,24196],{"class":357,"line":370},[355,24197,1271],{"emptyLinePlaceholder":893},[355,24199,24200],{"class":357,"line":376},[355,24201,24202],{"class":3858},"    \u002F\u002F Le mot clé \"transient\" est faculatif, il me sert surtout à indiquer que les événements ne seront pas persistés en tant que tel\n",[355,24204,24205,24208,24210,24213,24216,24218,24221,24224,24227,24229,24231],{"class":357,"line":382},[355,24206,24207],{"class":2801},"    private",[355,24209,3093],{"class":2801},[355,24211,24212],{"class":2801}," transient",[355,24214,24215],{"class":1119}," List",[355,24217,2826],{"class":2805},[355,24219,24220],{"class":2801},"UserAccessEvent",[355,24222,24223],{"class":2805},"> ",[355,24225,24226],{"class":1119},"occurredEvents",[355,24228,3213],{"class":2801},[355,24230,2857],{"class":2801},[355,24232,24233],{"class":1119}," ArrayList\u003C>();\n",[355,24235,24236],{"class":357,"line":1157},[355,24237,1271],{"emptyLinePlaceholder":893},[355,24239,24240,24242,24244,24247],{"class":357,"line":1165},[355,24241,24207],{"class":2801},[355,24243,3093],{"class":2801},[355,24245,24246],{"class":1119}," UserId",[355,24248,24249],{"class":1119}," id;\n",[355,24251,24252,24254,24257],{"class":357,"line":1173},[355,24253,24207],{"class":2801},[355,24255,24256],{"class":1119}," Instant",[355,24258,24259],{"class":1119}," suspendedAt;\n",[355,24261,24262],{"class":357,"line":1181},[355,24263,1271],{"emptyLinePlaceholder":893},[355,24265,24266,24268,24271,24274,24276,24278],{"class":357,"line":1189},[355,24267,2839],{"class":2801},[355,24269,24270],{"class":1119}," List\u003C",[355,24272,24273],{"class":2801},"UserEvent",[355,24275,24223],{"class":1119},[355,24277,24226],{"class":2845},[355,24279,2849],{"class":1119},[355,24281,24282,24284,24287,24290],{"class":357,"line":1197},[355,24283,2854],{"class":2801},[355,24285,24286],{"class":1119}," List.",[355,24288,24289],{"class":2845},"copyOf",[355,24291,24292],{"class":1119},"(occurredEvents);\n",[355,24294,24295],{"class":357,"line":1205},[355,24296,2905],{"class":1119},[355,24298,24299],{"class":357,"line":1213},[355,24300,1271],{"emptyLinePlaceholder":893},[355,24302,24303,24305,24308,24311,24314,24317],{"class":357,"line":1221},[355,24304,2839],{"class":2801},[355,24306,24307],{"class":2801}," void",[355,24309,24310],{"class":2845}," suspend",[355,24312,24313],{"class":1119},"(Clock ",[355,24315,24316],{"class":2805},"now",[355,24318,2973],{"class":1119},[355,24320,24321,24324,24327,24330,24333],{"class":357,"line":1229},[355,24322,24323],{"class":2801},"        if",[355,24325,24326],{"class":1119}," (suspendedAt ",[355,24328,24329],{"class":2801},"!=",[355,24331,24332],{"class":1264}," null",[355,24334,2973],{"class":1119},[355,24336,24337,24340,24342,24345],{"class":357,"line":1237},[355,24338,24339],{"class":2801},"            throw",[355,24341,2857],{"class":2801},[355,24343,24344],{"class":2845}," UserAccessIsAlreadySuspended",[355,24346,24347],{"class":1119},"(id);\n",[355,24349,24350],{"class":357,"line":1245},[355,24351,24352],{"class":1119},"        }\n",[355,24354,24355],{"class":357,"line":1256},[355,24356,1271],{"emptyLinePlaceholder":893},[355,24358,24359,24362,24365,24367,24370,24373],{"class":357,"line":1268},[355,24360,24361],{"class":1119},"        UserAccessSuspended",[355,24363,24364],{"class":1119}," event",[355,24366,3213],{"class":2801},[355,24368,24369],{"class":1119}," UserAccessSuspended.",[355,24371,24372],{"class":2845},"builder",[355,24374,2868],{"class":1119},[355,24376,24377,24379,24382],{"class":357,"line":1274},[355,24378,2873],{"class":1119},[355,24380,24381],{"class":2845},"userId",[355,24383,24384],{"class":1119},"(id)\n",[355,24386,24387,24389,24392,24395,24398],{"class":357,"line":1282},[355,24388,2873],{"class":1119},[355,24390,24391],{"class":2845},"suspendedAt",[355,24393,24394],{"class":1119},"(now.",[355,24396,24397],{"class":2845},"instant",[355,24399,24400],{"class":1119},"())\n",[355,24402,24403,24405,24408],{"class":357,"line":1290},[355,24404,2873],{"class":1119},[355,24406,24407],{"class":2845},"build",[355,24409,3078],{"class":1119},[355,24411,24412],{"class":357,"line":1301},[355,24413,1271],{"emptyLinePlaceholder":893},[355,24415,24416],{"class":357,"line":1306},[355,24417,24418],{"class":3858},"        \u002F\u002F La décision prise par l'aggrégat est stockée\n",[355,24420,24421,24424,24427,24429],{"class":357,"line":1314},[355,24422,24423],{"class":1264},"        this",[355,24425,24426],{"class":1119},".occurredEvents.",[355,24428,3434],{"class":2845},[355,24430,24431],{"class":1119},"(event);\n",[355,24433,24434],{"class":357,"line":1322},[355,24435,1271],{"emptyLinePlaceholder":893},[355,24437,24438],{"class":357,"line":1333},[355,24439,24440],{"class":3858},"        \u002F\u002F L'état interne de l'aggrégat est muté\n",[355,24442,24443,24445,24447,24449],{"class":357,"line":1341},[355,24444,24423],{"class":1264},[355,24446,44],{"class":1119},[355,24448,3418],{"class":2845},[355,24450,24431],{"class":1119},[355,24452,24453],{"class":357,"line":1352},[355,24454,2905],{"class":1119},[355,24456,24457],{"class":357,"line":1363},[355,24458,1271],{"emptyLinePlaceholder":893},[355,24460,24461,24463,24465,24468,24471,24474],{"class":357,"line":1369},[355,24462,24207],{"class":2801},[355,24464,24307],{"class":2801},[355,24466,24467],{"class":2845}," apply",[355,24469,24470],{"class":1119},"(UserAccessSuspended ",[355,24472,24473],{"class":2805},"event",[355,24475,2973],{"class":1119},[355,24477,24478,24480,24483,24485,24488,24490],{"class":357,"line":1377},[355,24479,24423],{"class":1264},[355,24481,24482],{"class":1119},".suspendedAt ",[355,24484,2042],{"class":2801},[355,24486,24487],{"class":1119}," event.",[355,24489,24391],{"class":2845},[355,24491,3078],{"class":1119},[355,24493,24494],{"class":357,"line":1386},[355,24495,2905],{"class":1119},[355,24497,24498],{"class":357,"line":1393},[355,24499,1271],{"emptyLinePlaceholder":893},[355,24501,24502],{"class":357,"line":1402},[355,24503,24504],{"class":3858},"    \u002F\u002F ... d'autres règles ici ...\n",[355,24506,24507],{"class":357,"line":1411},[355,24508,2725],{"class":1119},[19,24510,24511],{},"La décision métier est représentée ici de deux manières:",[443,24513,24514,24517],{},[446,24515,24516],{},"l'exception UserAccessIsAlreadySuspended",[446,24518,24519],{},"l'événement UserAccessSuspended",[1003,24521,24522],{},[19,24523,24524],{},"Bon à savoir, un événement s'étant déjà produit, une bonne manière de le nommer est de l'écrire au passé. L'exception quant à elle est écrite avec la convention IsXX pour décrire un fait.",[23,24526,24528],{"id":24527},"persister-lagrégat","Persister l'agrégat",[19,24530,24531],{},"L'agrégat sera manipulé dans la couche application par un service qui couvrira la totalité du geste métier:",[443,24533,24534,24537,24540,24543],{},[446,24535,24536],{},"Récupération de l'agrégat",[446,24538,24539],{},"Prise de décision",[446,24541,24542],{},"Gestion des erreurs",[446,24544,24545],{},"Persistance de l'agrégat",[1003,24547,24548],{},[19,24549,24550],{},"Dans la clean architecture, ce service prend souvent le nom de Use case.",[19,24552,24553],{},"L'agrégat sera récupéré et persisté au travers d'une interface qui va abstraire toute la logique d'infrastructure.",[1003,24555,24556],{},[19,24557,24558],{},"Dans l'architecture hexagonale, cette interface porte le nom de port.",[344,24560,24562],{"className":2792,"code":24561,"language":2794,"meta":350,"style":350},"interface UserAccessPort {\n\n    UserAccess getById(UserId userId);\n\n    void save(UserAccess access);\n\n}\n",[352,24563,24564,24574,24578,24593,24597,24613,24617],{"__ignoreMap":350},[355,24565,24566,24569,24572],{"class":357,"line":358},[355,24567,24568],{"class":2801},"interface",[355,24570,24571],{"class":2805}," UserAccessPort",[355,24573,3031],{"class":1119},[355,24575,24576],{"class":357,"line":364},[355,24577,1271],{"emptyLinePlaceholder":893},[355,24579,24580,24583,24586,24589,24591],{"class":357,"line":370},[355,24581,24582],{"class":1119},"    UserAccess ",[355,24584,24585],{"class":2845},"getById",[355,24587,24588],{"class":1119},"(UserId ",[355,24590,24381],{"class":2805},[355,24592,3048],{"class":1119},[355,24594,24595],{"class":357,"line":376},[355,24596,1271],{"emptyLinePlaceholder":893},[355,24598,24599,24602,24605,24608,24611],{"class":357,"line":382},[355,24600,24601],{"class":2801},"    void",[355,24603,24604],{"class":2845}," save",[355,24606,24607],{"class":1119},"(UserAccess ",[355,24609,24610],{"class":2805},"access",[355,24612,3048],{"class":1119},[355,24614,24615],{"class":357,"line":1157},[355,24616,1271],{"emptyLinePlaceholder":893},[355,24618,24619],{"class":357,"line":1165},[355,24620,2725],{"class":1119},[84,24622,24624],{"id":24623},"implémentation","Implémentation",[19,24626,24627],{},"Nous pourrions exposer un getter pour la propriété suspendedAt. Le problème s'il en est de cette méthode réside dans le fait que l'agrégat se mettrait à exposer tout ou partie de son état interne. D'une certaine manière, la modélisation de notre agrégat serait dépendante de la manière de la consommer. C'est là où les événements jouent un rôle important: ils sont faits pour être consommés.",[19,24629,24630],{},"Pour sauvegarder l'agrégat, nous allons parcourir chaque événement qu'il aura pu créer. Pour chaque événement, nous allons effectuer une opération JPA. A contrario, récupérer l'agrégat depuis la persistance se fera par un mapping direct des propriétés.",[344,24632,24634],{"className":2792,"code":24633,"language":2794,"meta":350,"style":350},"class UserAccessAdapter implements UserAccessPort {\n\n    private final JpaUserAccesses jpaUserAccesses;\n\n    @Override\n    public UserAccess getById(UserId userId) {\n        return jpaUserAccesses.findById(userId)\n                .map(UserAccessAdapter::toUserAccess)\n                .orElseThrow(() -> new UserAccessNotFound(userId));\n    }\n\n    private static UserAccess toUserAccess(UserAccessEntity entity) {\n        \u002F\u002F Ici, on recrée l'agrégat à partir d'un pattern builder\n        \u002F\u002F Demain, nous pourrions peut être le récréer à partir des événements\n        return UserAccess.builder()\n                .id(UserId.from(entity.getId()))\n                .suspendedAt(entity.getSuspendedAt())\n                .build();\n    }\n\n    @Override\n    public void save(User user) {\n        user.occurredEvents().forEach(event -> {\n            switch(event) {\n                case UserAccessSuspended e -> apply(e);\n                case UserAccessUnlocked e -> apply(e);\n                \u002F\u002F ... other events ...\n            }\n        });\n    }\n\n    private void apply(UserAccessSuspended event) {\n        jpaUserAccesses.apply(event);\n    }\n\n    private void apply(UserAccessUnlocked event) {\n        jpaUserAccesses.apply(event);\n    }\n\n}\n",[352,24635,24636,24650,24654,24666,24670,24678,24693,24706,24720,24741,24745,24749,24769,24774,24779,24790,24810,24823,24831,24835,24839,24845,24861,24881,24889,24904,24917,24922,24927,24932,24936,24940,24954,24963,24967,24971,24986,24994,24998,25002],{"__ignoreMap":350},[355,24637,24638,24640,24643,24646,24648],{"class":357,"line":358},[355,24639,24188],{"class":2801},[355,24641,24642],{"class":2805}," UserAccessAdapter",[355,24644,24645],{"class":2801}," implements",[355,24647,24571],{"class":1264},[355,24649,3031],{"class":1119},[355,24651,24652],{"class":357,"line":364},[355,24653,1271],{"emptyLinePlaceholder":893},[355,24655,24656,24658,24660,24663],{"class":357,"line":370},[355,24657,24207],{"class":2801},[355,24659,3093],{"class":2801},[355,24661,24662],{"class":1119}," JpaUserAccesses",[355,24664,24665],{"class":1119}," jpaUserAccesses;\n",[355,24667,24668],{"class":357,"line":376},[355,24669,1271],{"emptyLinePlaceholder":893},[355,24671,24672,24675],{"class":357,"line":382},[355,24673,24674],{"class":1119},"    @",[355,24676,24677],{"class":2801},"Override\n",[355,24679,24680,24682,24685,24687,24689,24691],{"class":357,"line":1157},[355,24681,2839],{"class":2801},[355,24683,24684],{"class":1119}," UserAccess ",[355,24686,24585],{"class":2845},[355,24688,24588],{"class":1119},[355,24690,24381],{"class":2805},[355,24692,2973],{"class":1119},[355,24694,24695,24697,24700,24703],{"class":357,"line":1165},[355,24696,2854],{"class":2801},[355,24698,24699],{"class":1119}," jpaUserAccesses.",[355,24701,24702],{"class":2845},"findById",[355,24704,24705],{"class":1119},"(userId)\n",[355,24707,24708,24710,24712,24715,24717],{"class":357,"line":1173},[355,24709,2873],{"class":1119},[355,24711,2876],{"class":2845},[355,24713,24714],{"class":1119},"(UserAccessAdapter",[355,24716,2882],{"class":2801},[355,24718,24719],{"class":1119},"toUserAccess)\n",[355,24721,24722,24724,24727,24730,24733,24735,24738],{"class":357,"line":1181},[355,24723,2873],{"class":1119},[355,24725,24726],{"class":2845},"orElseThrow",[355,24728,24729],{"class":1119},"(() ",[355,24731,24732],{"class":2801},"->",[355,24734,2857],{"class":2801},[355,24736,24737],{"class":2845}," UserAccessNotFound",[355,24739,24740],{"class":1119},"(userId));\n",[355,24742,24743],{"class":357,"line":1189},[355,24744,2905],{"class":1119},[355,24746,24747],{"class":357,"line":1197},[355,24748,1271],{"emptyLinePlaceholder":893},[355,24750,24751,24753,24756,24758,24761,24764,24767],{"class":357,"line":1205},[355,24752,24207],{"class":2801},[355,24754,24755],{"class":2801}," static",[355,24757,24684],{"class":1119},[355,24759,24760],{"class":2845},"toUserAccess",[355,24762,24763],{"class":1119},"(UserAccessEntity ",[355,24765,24766],{"class":2805},"entity",[355,24768,2973],{"class":1119},[355,24770,24771],{"class":357,"line":1213},[355,24772,24773],{"class":3858},"        \u002F\u002F Ici, on recrée l'agrégat à partir d'un pattern builder\n",[355,24775,24776],{"class":357,"line":1221},[355,24777,24778],{"class":3858},"        \u002F\u002F Demain, nous pourrions peut être le récréer à partir des événements\n",[355,24780,24781,24783,24786,24788],{"class":357,"line":1229},[355,24782,2854],{"class":2801},[355,24784,24785],{"class":1119}," UserAccess.",[355,24787,24372],{"class":2845},[355,24789,2868],{"class":1119},[355,24791,24792,24794,24796,24799,24801,24804,24807],{"class":357,"line":1237},[355,24793,2873],{"class":1119},[355,24795,511],{"class":2845},[355,24797,24798],{"class":1119},"(UserId.",[355,24800,20449],{"class":2845},[355,24802,24803],{"class":1119},"(entity.",[355,24805,24806],{"class":2845},"getId",[355,24808,24809],{"class":1119},"()))\n",[355,24811,24812,24814,24816,24818,24821],{"class":357,"line":1245},[355,24813,2873],{"class":1119},[355,24815,24391],{"class":2845},[355,24817,24803],{"class":1119},[355,24819,24820],{"class":2845},"getSuspendedAt",[355,24822,24400],{"class":1119},[355,24824,24825,24827,24829],{"class":357,"line":1256},[355,24826,2873],{"class":1119},[355,24828,24407],{"class":2845},[355,24830,3078],{"class":1119},[355,24832,24833],{"class":357,"line":1268},[355,24834,2905],{"class":1119},[355,24836,24837],{"class":357,"line":1274},[355,24838,1271],{"emptyLinePlaceholder":893},[355,24840,24841,24843],{"class":357,"line":1282},[355,24842,24674],{"class":1119},[355,24844,24677],{"class":2801},[355,24846,24847,24849,24851,24853,24856,24859],{"class":357,"line":1290},[355,24848,2839],{"class":2801},[355,24850,24307],{"class":2801},[355,24852,24604],{"class":2845},[355,24854,24855],{"class":1119},"(User ",[355,24857,24858],{"class":2805},"user",[355,24860,2973],{"class":1119},[355,24862,24863,24866,24868,24871,24874,24877,24879],{"class":357,"line":1301},[355,24864,24865],{"class":1119},"        user.",[355,24867,24226],{"class":2845},[355,24869,24870],{"class":1119},"().",[355,24872,24873],{"class":2845},"forEach",[355,24875,24876],{"class":1119},"(event ",[355,24878,24732],{"class":2801},[355,24880,3031],{"class":1119},[355,24882,24883,24886],{"class":357,"line":1306},[355,24884,24885],{"class":2801},"            switch",[355,24887,24888],{"class":1119},"(event) {\n",[355,24890,24891,24894,24897,24899,24901],{"class":357,"line":1314},[355,24892,24893],{"class":2801},"                case",[355,24895,24896],{"class":1119}," UserAccessSuspended e ",[355,24898,24732],{"class":2801},[355,24900,24467],{"class":2845},[355,24902,24903],{"class":1119},"(e);\n",[355,24905,24906,24908,24911,24913,24915],{"class":357,"line":1322},[355,24907,24893],{"class":2801},[355,24909,24910],{"class":1119}," UserAccessUnlocked e ",[355,24912,24732],{"class":2801},[355,24914,24467],{"class":2845},[355,24916,24903],{"class":1119},[355,24918,24919],{"class":357,"line":1333},[355,24920,24921],{"class":3858},"                \u002F\u002F ... other events ...\n",[355,24923,24924],{"class":357,"line":1341},[355,24925,24926],{"class":1119},"            }\n",[355,24928,24929],{"class":357,"line":1352},[355,24930,24931],{"class":1119},"        });\n",[355,24933,24934],{"class":357,"line":1363},[355,24935,2905],{"class":1119},[355,24937,24938],{"class":357,"line":1369},[355,24939,1271],{"emptyLinePlaceholder":893},[355,24941,24942,24944,24946,24948,24950,24952],{"class":357,"line":1377},[355,24943,24207],{"class":2801},[355,24945,24307],{"class":2801},[355,24947,24467],{"class":2845},[355,24949,24470],{"class":1119},[355,24951,24473],{"class":2805},[355,24953,2973],{"class":1119},[355,24955,24956,24959,24961],{"class":357,"line":1386},[355,24957,24958],{"class":1119},"        jpaUserAccesses.",[355,24960,3418],{"class":2845},[355,24962,24431],{"class":1119},[355,24964,24965],{"class":357,"line":1393},[355,24966,2905],{"class":1119},[355,24968,24969],{"class":357,"line":1402},[355,24970,1271],{"emptyLinePlaceholder":893},[355,24972,24973,24975,24977,24979,24982,24984],{"class":357,"line":1411},[355,24974,24207],{"class":2801},[355,24976,24307],{"class":2801},[355,24978,24467],{"class":2845},[355,24980,24981],{"class":1119},"(UserAccessUnlocked ",[355,24983,24473],{"class":2805},[355,24985,2973],{"class":1119},[355,24987,24988,24990,24992],{"class":357,"line":1417},[355,24989,24958],{"class":1119},[355,24991,3418],{"class":2845},[355,24993,24431],{"class":1119},[355,24995,24996],{"class":357,"line":1425},[355,24997,2905],{"class":1119},[355,24999,25000],{"class":357,"line":1434},[355,25001,1271],{"emptyLinePlaceholder":893},[355,25003,25004],{"class":357,"line":1441},[355,25005,2725],{"class":1119},[19,25007,25008,25009,25014,25015,25020],{},"L’association de ",[91,25010,25013],{"href":25011,"rel":25012},"https:\u002F\u002Fdocs.jboss.org\u002Fhibernate\u002Form\u002F3.5\u002Freference\u002Ffr\u002Fhtml\u002Fqueryhql.html",[95],"HQL"," et de ",[91,25016,25019],{"href":25017,"rel":25018},"https:\u002F\u002Fdocs.spring.io\u002Fspring-framework\u002Freference\u002Fcore\u002Fexpressions.html",[95],"SPEL"," nous permet ainsi d'écrire nos requêtes SQL à partir de nos événements.",[344,25022,25024],{"className":2792,"code":25023,"language":2794,"meta":350,"style":350},"@Repository\ninterface JpaUserAccesses extends JpaRepository\u003CUserAccessEntity, String> {\n\n    @Modifying\n    @Query(\"\"\"\n        UPDATE UserAccess u\n        SET u.suspendedAt = :#{#event.suspendedAt()}\n        WHERE u.id = :#{#event.userId().value()}\n    \"\"\")\n    void apply(UserAccessSuspended event);\n\n    @Modifying\n    @Query(\"\"\"\n        UPDATE UserAccess u\n        SET u.suspendedAt = null\n        WHERE u.id = :#{#event.userId().value()}\n        \"\"\")\n    void apply(UserAccessUnlocked event);\n\n    \u002F\u002F ... apply other events ...\n}\n",[352,25025,25026,25033,25058,25062,25069,25081,25086,25091,25096,25103,25115,25119,25125,25135,25139,25144,25148,25155,25167,25171,25176],{"__ignoreMap":350},[355,25027,25028,25030],{"class":357,"line":358},[355,25029,24177],{"class":1119},[355,25031,25032],{"class":2801},"Repository\n",[355,25034,25035,25037,25039,25042,25045,25047,25050,25052,25055],{"class":357,"line":364},[355,25036,24568],{"class":2801},[355,25038,24662],{"class":2805},[355,25040,25041],{"class":2801}," extends",[355,25043,25044],{"class":1264}," JpaRepository",[355,25046,2826],{"class":1119},[355,25048,25049],{"class":2801},"UserAccessEntity",[355,25051,504],{"class":1119},[355,25053,25054],{"class":2801},"String",[355,25056,25057],{"class":1119},"> {\n",[355,25059,25060],{"class":357,"line":370},[355,25061,1271],{"emptyLinePlaceholder":893},[355,25063,25064,25066],{"class":357,"line":376},[355,25065,24674],{"class":1119},[355,25067,25068],{"class":2801},"Modifying\n",[355,25070,25071,25073,25076,25078],{"class":357,"line":382},[355,25072,24674],{"class":1119},[355,25074,25075],{"class":2801},"Query",[355,25077,2169],{"class":1119},[355,25079,25080],{"class":1138},"\"\"\"\n",[355,25082,25083],{"class":357,"line":1157},[355,25084,25085],{"class":1138},"        UPDATE UserAccess u\n",[355,25087,25088],{"class":357,"line":1165},[355,25089,25090],{"class":1138},"        SET u.suspendedAt = :#{#event.suspendedAt()}\n",[355,25092,25093],{"class":357,"line":1173},[355,25094,25095],{"class":1138},"        WHERE u.id = :#{#event.userId().value()}\n",[355,25097,25098,25101],{"class":357,"line":1181},[355,25099,25100],{"class":1138},"    \"\"\"",[355,25102,16772],{"class":1119},[355,25104,25105,25107,25109,25111,25113],{"class":357,"line":1189},[355,25106,24601],{"class":2801},[355,25108,24467],{"class":2845},[355,25110,24470],{"class":1119},[355,25112,24473],{"class":2805},[355,25114,3048],{"class":1119},[355,25116,25117],{"class":357,"line":1197},[355,25118,1271],{"emptyLinePlaceholder":893},[355,25120,25121,25123],{"class":357,"line":1205},[355,25122,24674],{"class":1119},[355,25124,25068],{"class":2801},[355,25126,25127,25129,25131,25133],{"class":357,"line":1213},[355,25128,24674],{"class":1119},[355,25130,25075],{"class":2801},[355,25132,2169],{"class":1119},[355,25134,25080],{"class":1138},[355,25136,25137],{"class":357,"line":1221},[355,25138,25085],{"class":1138},[355,25140,25141],{"class":357,"line":1229},[355,25142,25143],{"class":1138},"        SET u.suspendedAt = null\n",[355,25145,25146],{"class":357,"line":1237},[355,25147,25095],{"class":1138},[355,25149,25150,25153],{"class":357,"line":1245},[355,25151,25152],{"class":1138},"        \"\"\"",[355,25154,16772],{"class":1119},[355,25156,25157,25159,25161,25163,25165],{"class":357,"line":1256},[355,25158,24601],{"class":2801},[355,25160,24467],{"class":2845},[355,25162,24981],{"class":1119},[355,25164,24473],{"class":2805},[355,25166,3048],{"class":1119},[355,25168,25169],{"class":357,"line":1268},[355,25170,1271],{"emptyLinePlaceholder":893},[355,25172,25173],{"class":357,"line":1274},[355,25174,25175],{"class":3858},"    \u002F\u002F ... apply other events ...\n",[355,25177,25178],{"class":357,"line":1282},[355,25179,2725],{"class":1119},[19,25181,25182],{},"Notez qu’il est bien sûr possible d’appliquer les événements en utilisant pleinement l’entity manager de Hibernate plutôt que d’exécuter des UPDATE directement sur la base.",[23,25184,1528],{"id":1527},[19,25186,25187],{},"Il n'est pas très compliqué de modéliser les décisions métiers sous forme d'événements. Au travers d'une histoire, nous sommes capables de sauvegarder un état de fait.\nSerions-nous maintenant capables de reconstruire l'agrégat à partir de ses décisions ? L'event sourcing attendra une prochaine fois.",[856,25189,25190],{},"html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}html pre.shiki code .sc3cj, html code.shiki .sc3cj{--shiki-default:#D2A8FF}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}",{"title":350,"searchDepth":364,"depth":364,"links":25192},[25193,25194,25197],{"id":24152,"depth":364,"text":24153},{"id":24527,"depth":364,"text":24528,"children":25195},[25196],{"id":24623,"depth":370,"text":24624},{"id":1527,"depth":364,"text":1528},"2024-09-27T09:33:34.264Z","Pré-requis pour ne pas être trop perdu  - quelques bases en Domain Driven Design (DDD) - quelques bases en JPA \u002F Hibernate   La notion d’agrégat du Domain Driven Design désigne un ensemble cohérent d’",{},"\u002Fblogs\u002F2024-09-27-sauvegarder-ltat-final-dun-agrgat-par-ses-vnements",[25203,25205,25207,25209],{"id":1582,"name":1583,"image":25204,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240927%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240927T093334Z&X-Amz-Expires=3600&X-Amz-Signature=79fc8167b197f482c4bd87d3d40b54e1c53d1b4fe8c478ea78dbaf9250fdb750&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1577,"name":1578,"image":25206,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240927%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240927T093333Z&X-Amz-Expires=3600&X-Amz-Signature=7a4418996d6bb7aac5876de858fe01b816d0b62f1f1c7b761f697d218080dac3&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":10,"name":11,"image":25208,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240927%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240927T093333Z&X-Amz-Expires=3600&X-Amz-Signature=824e4bf8f3ec04e004c2c1869033ea8cb59a4b4592fa9a25af8b59caa28bdbbd&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":5017,"name":5018,"image":25210,"linkedin":5020,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc4f79dcc-a6ed-4a79-9947-416b33e5b90a\u002FPhoto_Profil_CV_1200px_%2813%29.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240927%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240927T093333Z&X-Amz-Expires=3600&X-Amz-Signature=03af5b1a4f1831ca5b0e776cfe5fe96613027c1589f760f3089fa5ac4db41e79&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":24127,"description":25199},"blogs\u002F2024-09-27-sauvegarder-ltat-final-dun-agrgat-par-ses-vnements\u002Findex",[1879,25214,25215],"ddd","jpa","SJfbGcyVyeYxrrRAKoiMst-Ec0DGTOkPu-7NJSgTF6Q",{"id":25218,"title":23693,"alt":21161,"authors":25219,"body":25221,"date":25403,"description":25404,"extension":890,"image":891,"meta":25405,"navigation":893,"ogImage":891,"path":25406,"published":893,"reviewers":25407,"seo":25414,"stem":25415,"tags":25416,"__hash__":25417},"blogs\u002Fblogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-2\u002Findex.md",[25220],{"id":18862,"name":18863,"image":21164,"linkedin":18865,"x":901},{"type":16,"value":25222,"toc":25393},[25223,25232,25237,25241,25244,25250,25253,25256,25262,25265,25269,25272,25275,25278,25282,25291,25294,25303,25307,25316,25319,25323,25331,25334,25336,25368,25372,25378,25386,25390],[19,25224,25225,25226,25231],{},"Dans notre première partie de l'article, nous avons établi la relation entre CO2, énergie et finance. Aujourd'hui, je vous propose, dans une version simplifiée, de mesurer votre impact carbone dans le Cloud avec des services managés sans information sur le hardware. Nous resterons sur le ",[91,25227,25230],{"href":25228,"rel":25229},"https:\u002F\u002Fglobalclimateinitiatives.com\u002Fe-brochures-connaissances\u002Fscope\u002F",[95],"Scope 3 des émissions"," afin d'être cohérent avec cette simplification.",[1003,25233,25234],{},[19,25235,25236],{},"Le numérique émet près de 4 % des gaz à effet de serre à l'échelle mondiale",[23,25238,25240],{"id":25239},"simuler-la-consommation-de-manière-classique","Simuler la consommation de manière classique",[19,25242,25243],{},"Il est aisé de mesurer la consommation électrique de votre téléphone ou votre PC. Nous pouvons le faire via des applications ou simplement avec un compteur de consommation électrique branché entre la prise et votre chargeur. Ensuite, avec une simple opération mathématique, nous pouvons obtenir la production de CO2 en fonction de l'origine de production électrique.",[19,25245,25246],{},[176,25247],{"alt":25248,"src":25249},"Exemple d’étiquette énergétique","\u002Fcontent-assets\u002F2024-09-26-low-carbon-dans-le-cloud-partie-2\u002Fassets\u002Fimg1.webp",[19,25251,25252],{},"Prenons en exemple une télévision qui consomme jusqu'à 240 kWh pour 1000 h. En multipliant par le coefficient moyen pour la production d'énergie Française (partons arbitrairement sur 29 g d'eCO2\u002FkWh) nous obtenons environ 7 kg d'équivalent C02 pour 1000 h d'utilisation.",[19,25254,25255],{},"Pour un serveur dans un centre de données, nous prenons en compte l'Indicateur d'efficacité énergétique aussi appelé PUE. Cet indicateur prend en compte les équipements tiers comme la climatisation.",[19,25257,25258],{},[176,25259],{"alt":25260,"src":25261},"L'image montre la formule du PUE (Power Usage Effectiveness) pour un centre informatique. Elle est définie comme le rapport entre l'énergie totale consommée par le centre informatique et l'énergie consommée par les équipements informatiques.","https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F7dbbc970-dea0-42ec-a9e1-168e6a7cf8b6\u002FLimage_montre_la_formule_du_PUE_%28Power_Usage_Effectiveness%29_pour_un_centre_informatique._Elle_est_definie_comme_le_rapport_entre_lenergie_totale_consommee_par_le_centre_informatique_et_lenergie.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240926T191415Z&X-Amz-Expires=3600&X-Amz-Signature=c3552ce9e5737e4aec85099b1578a78bc667e33b8a6bb39746253b97d91c220a&X-Amz-SignedHeaders=host&x-id=GetObject",[19,25263,25264],{},"Imaginons que cette TV est branchée dans un centre de données avec un PUE de 1,2. Nous multiplions sa consommation par un facteur 20 % qui fait passer la consommation globale pour cette télévision à 8,4 kg d'équivalent CO2 sur 1000 h d'utilisation.",[23,25266,25268],{"id":25267},"offuscation-du-cloud","Offuscation du Cloud",[19,25270,25271],{},"Les sujets Green ont le vent en poupe, mais nous manquons clairement de transparence sur les services du Cloud. Plus le service est managé moins nous en savons. Les acteurs du marché comme Microsoft ont fait un grand pas en avant. Cependant, dans l'ensemble, nous marchons à l'aveugle.",[19,25273,25274],{},"Sur certains services en IaaS (Infrastructure as a Service), des outils permettent de définir la partie matérielle et donc de définir, grâce aux données constructeurs, la consommation. Et parfois, le fournisseur Cloud nous communique le PUE.",[19,25276,25277],{},"Pour les autres services CaaS, FaaS, PaaS ou encore SaaS, cela est beaucoup plus compliqué.",[23,25279,25281],{"id":25280},"pourquoi-une-méthode-simplifiée","Pourquoi une méthode simplifiée",[19,25283,25284,25285,25290],{},"Une méthode simple permet de rester compréhensible et adoptable par tous, mais elle a aussi l'avantage d'éviter le ",[91,25286,25289],{"href":25287,"rel":25288},"https:\u002F\u002Ffr.wikipedia.org\u002Fwiki\u002FParadoxe_du_littoral#:~:text=Le%20paradoxe%20du%20littoral%20est,a%20pas%20de%20longueur%20d%C3%A9finie.",[95],"paradoxe des littoraux"," : plus nous essayons d'être précis plus nous nous éloignons d'une vue d'ensemble cohérente.",[19,25292,25293],{},"Maintenant, prenons du recul et demandons-nous si avoir une vision extrêmement précise de sa production de gaz à effet de serre est nécessaire ? Dans la très grande majorité des cas, la réponse est non. Il est beaucoup plus intéressant d'avoir une notion d'échelle dans une fourchette réaliste et de pouvoir définir une tendance dans le temps. Une démarche GreenOps consiste à diminuer sa production de polluants, pas à en faire sa comptabilité.",[1003,25295,25296],{},[19,25297,19429,25298],{},[91,25299,25302],{"href":25300,"rel":25301},"https:\u002F\u002Fgreensoftware.foundation\u002F",[95],"Green Software Foundation",[23,25304,25306],{"id":25305},"la-méthode","La méthode",[19,25308,25309,25310,25315],{},"Pour débuter avec une vision Green, inutile d'installer une application ou d'ajouter une librairie à votre code. Nous pouvons partir des simulateurs de coût comme le ",[91,25311,25314],{"href":25312,"rel":25313},"https:\u002F\u002Fcalculator.aws\u002F#\u002F",[95],"AWS Pricing Calculator"," ou directement d'une facture.",[19,25317,25318],{},"La constante veut que nous puissions toujours récupérer certaines métriques comme le nombre de VCPU, la taille de la RAM ou le stockage utilisés. Il est vrai que nous ne connaissons pas toujours le modèle de processeur, la marque du SSD ou la carte graphique. Toutefois, nous pouvons compléter ses informations avec le type d'architecture processeur. Par exemple, savoir que nous avons un processeur de type AWS Gravitons, nous permet de réduire la consommation de 60 % vis-à-vis d'un processeur générique.",[84,25320,25322],{"id":25321},"cloud-carbon-footprint","Cloud Carbon Footprint",[19,25324,25325,25326,25330],{},"Maintenant que nous avons une vision globale de notre utilisation du Cloud, comment passons-nous à la vision CO2 ? La méthodologie ",[91,25327,25322],{"href":25328,"rel":25329},"https:\u002F\u002Fwww.cloudcarbonfootprint.org\u002Fdocs\u002Fmethodology\u002F",[95]," sera votre meilleur allié. Vous allez pouvoir récupérer le PUE moyen des Cloud Providers américains ainsi que les valeurs de consommation minimum et maximum sur l'ensemble du scope.",[19,25332,25333],{},"Par exemple voici les données pour AWS:",[19,25335,58],{},[443,25337,25338,25341,25344,25347,25350,25353,25356,25359],{},[446,25339,25340],{},"Moyenne Minimum Watts (0% CPU ): 0.74",[446,25342,25343],{},"Moyenne Maximum Watts (100% CPU Utilization): 3.5",[446,25345,25346],{},"Moyenne d'utilisation CPU par centre de données: 50%",[446,25348,25349],{},"Stockage HDD Watt Heure \u002F Terabyte: 0.65",[446,25351,25352],{},"Stockage SSD Storage Watt Heure \u002F Terabyte: 1.2",[446,25354,25355],{},"Réseau Kilowatt Heure\u002F Gigabyte: 0.001",[446,25357,25358],{},"Mémoire Kilowatt Heure \u002F Gigabyte: 0.000392",[446,25360,25361,25362,25367],{},"Moyenne du PUE: 1.135\nJe ne peux que vous conseiller de lire attentivement la page ",[91,25363,25366],{"href":25364,"rel":25365},"https:\u002F\u002Fwww.cloudcarbonfootprint.org\u002Fdocs\u002Fmethodology",[95],"méthodologie du CCF",". Je ne rentrerais pas plus en détail dans les formules que vous trouverez aisément sur le site de l'organisation Cloud Carbon Footprint. Cependant, j'aimerais vous proposer un conseil pour le suivi de cette consommation de manière industrialisée.",[84,25369,25371],{"id":25370},"votre-dashboard-green","Votre Dashboard Green",[19,25373,25374],{},[176,25375],{"alt":25376,"src":25377},"Dashboard DataDog","\u002Fcontent-assets\u002F2024-09-26-low-carbon-dans-le-cloud-partie-2\u002Fassets\u002Fimg2.webp",[19,25379,25380,25381,25385],{},"En utilisant des outils d'observabilité comme ",[91,25382,25384],{"href":3543,"rel":25383},[95],"DataDog",", vous êtes en capacité de faire vos propres Dashboards. En sachant, que si vous avez déjà vos utilisations de VCPU et autres métriques intégrées dans votre outil d'observabilité, vous êtes capables de faire la conversion dynamique en kWh et équivalent CO2. Cette solution permet d'avoir rapidement beaucoup d'indicateurs de suivi du CO2 dans la durée mais aussi en temps réel.",[23,25387,25389],{"id":25388},"le-mot-de-la-fin","Le mot de la fin",[19,25391,25392],{},"Vous pouvez désormais commencer votre suivi de CO2. Si cette approche est trop technique, il existe également des solutions clé en main sur le marché. Elles seront par contre souvent assez onéreuses.  Aussi au besoin les équipes HoppR sont disponibles pour apporter du conseil sur ces sujets\nDans la suite de cette série d'articles sur la Sustainability (Durabilité), nous aborderons les techniques d'architectures Green.",{"title":350,"searchDepth":364,"depth":364,"links":25394},[25395,25396,25397,25398,25402],{"id":25239,"depth":364,"text":25240},{"id":25267,"depth":364,"text":25268},{"id":25280,"depth":364,"text":25281},{"id":25305,"depth":364,"text":25306,"children":25399},[25400,25401],{"id":25321,"depth":370,"text":25322},{"id":25370,"depth":370,"text":25371},{"id":25388,"depth":364,"text":25389},"2024-09-26T19:14:17.111Z","Dans notre première partie de l'article, nous avons établi la relation entre CO2, énergie et finance. Aujourd'hui, je vous propose, dans une version simplifiée, de mesurer votre impact carbone dans le",{},"\u002Fblogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-2",[25408,25410,25412],{"id":1577,"name":1578,"image":25409,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240926T191417Z&X-Amz-Expires=3600&X-Amz-Signature=9a6ac271ef20e015de8631306a9a3d9ee599b8bd6515bc6660813db235ccc1f1&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":5017,"name":5018,"image":25411,"linkedin":5020,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc4f79dcc-a6ed-4a79-9947-416b33e5b90a\u002FPhoto_Profil_CV_1200px_%2813%29.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240926T191416Z&X-Amz-Expires=3600&X-Amz-Signature=54de1d32f7760312fb5a03455f51114ce13ce45c879f9cc601adc7b39a29b9f8&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":10,"name":11,"image":25413,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240926T191416Z&X-Amz-Expires=3600&X-Amz-Signature=ffc2acf38d64db342f06c5554d8cbc0a7da3f6ab5effba78949ba08d7fca35a7&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":23693,"description":25404},"blogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-2\u002Findex",[21430,907,906],"JmWCNopHxtcEchQWeZycMdlgQL7txr2aCx1j_2jvISo",{"id":25419,"title":25420,"alt":21161,"authors":25421,"body":25423,"date":25526,"description":25527,"extension":890,"image":891,"meta":25528,"navigation":893,"ogImage":891,"path":25529,"published":893,"reviewers":25530,"seo":25535,"stem":25536,"tags":25537,"__hash__":25538},"blogs\u002Fblogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-1\u002Findex.md","Low Carbon dans le Cloud - Partie 1",[25422],{"id":18862,"name":18863,"image":21164,"linkedin":18865,"x":901},{"type":16,"value":25424,"toc":25516},[25425,25428,25431,25434,25438,25441,25444,25447,25451,25460,25463,25466,25472,25475,25478,25481,25485,25488,25492,25495,25499,25502,25506,25509,25513],[19,25426,25427],{},"Le Green Code aurait permis d'économiser des centaines de millions de tonnes de CO2 rien que ces 3 dernières années. Et si nous faisions un effort supplémentaire côté infrastructure ?",[19,25429,25430],{},"Auprès des particuliers, ce sont sûrement les applications mobiles qui sont le plus consommées. Toutefois, en entreprise, les centres de données avec des climatiseurs de la taille de Matignon sont encore la norme. Sans parler de l'IA qui vient tuer le match.",[19,25432,25433],{},"Heureusement, nous pouvons limiter la casse et revenir dans les bonnes grâces de Greta.",[23,25435,25437],{"id":25436},"notions","Notions",[19,25439,25440],{},"Reprenons les basiques: comment notre application génère du CO2 ? Le stockage, la charge CPU, le refroidissement consomment de l'énergie. Pour produire cette énergie exprimée en kWh, nous brûlons des matières premières, nous extrayons de l'uranium, nous produisons des panneaux solaires, etc. Toutes ces solutions produisent plus ou moins de polluants comme: le CO2, des métaux lourds, des gaz acidifiants, etc. Et bien sûr, tout ça a aussi un coût financier variable : par exemple l'énergie dite verte est plus chère.",[19,25442,25443],{},"Il est important de souligner que la source d'énergie du centre de données est le facteur numéro 1 pour ajuster sa production de CO2.",[19,25445,25446],{},"En effet, un centre de données qui consomme 2 fois plus d'électricité qu'un autre peut produire moins de CO2. Comme nous allons le voir en fonction de l'origine électrique, la différence peut être de facteur 100 !",[23,25448,25450],{"id":25449},"la-france-reste-un-des-meilleurs-choix","La France reste un des meilleurs choix",[19,25452,25453,25454,25459],{},"Le site ",[91,25455,25458],{"href":25456,"rel":25457},"https:\u002F\u002Fapp.electricitymaps.com\u002F",[95],"electricitymaps"," nous propose une carte monde des émissions de CO2. Il est facile de comparer la production de CO2 par pays tout en analysant l'origine de cette production (charbon, nucléaire, solaire, …).",[19,25461,25462],{},"Il y a d'énormes différences entre les pays. À l'heure où j'écris cet article, l'Inde produit 66 fois plus de gaz carboné que la Suède pour produire 1 kWh.",[19,25464,25465],{},"Intensité carbone de la France -",[19,25467,25468],{},[176,25469],{"alt":25470,"src":25471},"electricity Map de l’Europe","\u002Fcontent-assets\u002F2024-09-26-low-carbon-dans-le-cloud-partie-1\u002Fassets\u002Fimg1.webp",[19,25473,25474],{},"La France, grâce essentiellement au nucléaire et aux énergies renouvelables, est dans les meilleurs élèves de la planète. Bonne nouvelle pour les consommateurs de Cloud, nous avons un grand nombre de Cloud en France (OVH, Scaleway, Outscale, …) et les grands fournisseurs américains proposent une région (exécution des services et stockage) dans notre beau pays.",[19,25476,25477],{},"Malheureusement, il y a une contrepartie ! En effet, héberger ses données en France (23 g d'équivalent Co2 pour 1 kWh) coûte plus cher qu'en Irlande (525 g) ou en Allemagne (187 g) avec les fournisseurs américains.",[19,25479,25480],{},"Il est important de souligner que certains centres de données peuvent être alimentés par une production d'énergie indépendante du pays (autoproduction, contrat privé, …).",[23,25482,25484],{"id":25483},"le-greenops-un-adversaire-du-finops","Le GreenOps un adversaire du FinOps ?",[19,25486,25487],{},"Le cas précédent met en avant une dualité entre le CO2 et les impacts budgétaires. Heureusement, le Cloud n'est pas un univers cornélien ou nous devons choisir entre pollution et économie financière. Il faut être capable d'ajuster les curseurs entre les coûts et l'écologie.",[84,25489,25491],{"id":25490},"pauvreté-et-sobriété-numérique","Pauvreté et sobriété numérique",[19,25493,25494],{},"Il n'est pas question de se priver d'utiliser les services Cloud pour réduire son CO2. Les compromis seront de mise mais permettront d'atteindre la sobriété et ne vous brideront aucunement. Parfois les planètes seront alignées : c'est le cas pour conjuguer souveraineté des données et diminution de l'impact carbone pour les entreprises françaises.",[84,25496,25498],{"id":25497},"marketing","Marketing",[19,25500,25501],{},"L'écologie est bankable, nous n'allons pas nous mentir, avant tout pour son attrait marketing. En effet, l'impact commercial d'acte Green est réel. Il doit être mis dans la balance afin d'ajuster le curseur GreenOps\u002FFinOps.",[84,25503,25505],{"id":25504},"réglementation","Réglementation",[19,25507,25508],{},"Pour le respect des lois à caractère RSE, une démarche GreenOps est un grand atout.",[23,25510,25512],{"id":25511},"en-introduction-de-la-partie-2","En introduction de la partie 2",[19,25514,25515],{},"Il est important de pouvoir suivre ces deux métriques: coût et production de carbone. Ce qui ne peut pas être mesuré est difficilement améliorable. Le Cloud amène avec lui de belles pratiques et de belles améliorations notamment en terme de vision. Dans la seconde partie, nous parlerons d'observabilité avec un focus particulier sur l'impact carbone.",{"title":350,"searchDepth":364,"depth":364,"links":25517},[25518,25519,25520,25525],{"id":25436,"depth":364,"text":25437},{"id":25449,"depth":364,"text":25450},{"id":25483,"depth":364,"text":25484,"children":25521},[25522,25523,25524],{"id":25490,"depth":370,"text":25491},{"id":25497,"depth":370,"text":25498},{"id":25504,"depth":370,"text":25505},{"id":25511,"depth":364,"text":25512},"2024-09-26T19:13:02.656Z","Le Green Code aurait permis d'économiser des centaines de millions de tonnes de CO2 rien que ces 3 dernières années. Et si nous faisions un effort supplémentaire côté infrastructure ?  Auprès des part",{},"\u002Fblogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-1",[25531,25533],{"id":1577,"name":1578,"image":25532,"linkedin":1580,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F82ebd0fe-de28-43f3-ab7b-0431af41baad\u002FPhoto_HoppR.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240926T191302Z&X-Amz-Expires=3600&X-Amz-Signature=ceadc4bf7580a016b5ac0b1159488b990250b831bccf0691e4ae7bf3f87eacff&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1582,"name":1583,"image":25534,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240926%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240926T191302Z&X-Amz-Expires=3600&X-Amz-Signature=50667715cef901f68af532d995c162dddd923a9c2bf34787c4e5d7006748310b&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":25420,"description":25527},"blogs\u002F2024-09-26-low-carbon-dans-le-cloud-partie-1\u002Findex",[21430,907,906],"Y7Ei6m636NzxgiHlwmA2Jh7hDNLk5faiBtqECaU3eYw",{"id":25540,"title":25541,"alt":25542,"authors":25543,"body":25552,"date":25795,"description":25796,"extension":890,"image":891,"meta":25797,"navigation":893,"ogImage":891,"path":25798,"published":893,"reviewers":25799,"seo":25804,"stem":25805,"tags":25806,"__hash__":25807},"blogs\u002Fblogs\u002F2024-08-27-retour-sur-le-devfest\u002Findex.md","Retour sur le DevFest","Les 6 et 7 Juin dernier s'est déroulée la 7ᵉ édition du DevFest Lille. Toute l'équipe HoppR était présente à l'événement. Retour sur cette journée riche en découvertes techniques et humaines",[25544,25545,25546,25551],{"id":897,"name":898,"image":7084,"linkedin":900,"x":901},{"id":5813,"name":5814,"image":5815,"linkedin":5816,"x":901},{"id":25547,"name":25548,"image":25549,"linkedin":25550,"x":901},"44e68e06-deec-41b6-87a4-833fec8c9953","Sébastien Jaupart",".\u002Fassets\u002Fauthor-sbastien-jaupart.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fsebastien-jaupart\u002F",{"id":20037,"name":20038,"image":20039,"linkedin":20040,"x":901},{"type":16,"value":25553,"toc":25786},[25554,25558,25561,25567,25570,25573,25577,25580,25591,25597,25603,25608,25611,25615,25619,25622,25625,25628,25631,25634,25637,25640,25643,25646,25649,25658,25662,25665,25668,25671,25674,25677,25680,25683,25686,25700,25703,25723,25726,25735,25739,25742,25745,25748,25751,25754,25757,25760,25768,25772,25775,25783],[7089,25555,25557],{"id":25556},"devfest-lille-saison-7","DevFest Lille, saison 7 !",[19,25559,25560],{},"Les 6 et 7 Juin dernier s'est déroulée la 7ᵉ édition du DevFest Lille au Grand Palais. Pour la première fois sur un format de 2 jours avec une soirée organisée à Grand Scène (on y reviendra plus tard). \nUne édition plus riche, plus dense avec 56 conférences et Talks, 1500 participants et une quarantaine de sponsors dont HoppR.",[19,25562,25563],{},[176,25564],{"alt":25565,"src":25566},"Photo de l’équipe HoppR","\u002Fcontent-assets\u002F2024-08-27-retour-sur-le-devfest\u002Fassets\u002Fimg1.webp",[19,25568,25569],{},"Toute l'équipe HoppR était présente à l'événement. Retour sur cette journée riche en découvertes techniques et humaines d'Emma, Elisa, Edouard, Théo, Nicolas G & Z, Anthony, Guillaume !",[19,25571,25572],{},"D’ailleurs, certains en ont profité pour compiler leur retour d’expérience et prendre des notes sur les talks qui les ont interpellés !\nAlors si vous n’avez pas pu y participer ou tout voir, la suite devrait vous intéresser !",[23,25574,25576],{"id":25575},"petit-détour-sur-lengagement-du-devfest-lille","Petit détour sur l'engagement du DevFest Lille",[19,25578,25579],{},"Depuis quelques années, l'équipe du DevFest a fait un gros effort pour réduire l'impact de la conférence, notamment sur les déchets. Avec pour mot d'ordre, supprimer, réutiliser ou recycler et plusieurs initiatives déjà en place :",[443,25581,25582,25585,25588],{},[446,25583,25584],{},"Fin des goodies (souvent inutiles) et thématique pour réutiliser les kakemonos et stand des années précédentes (organisation et sponsors).",[446,25586,25587],{},"Partenariat avec la Consignerie pour proposer aux participants des boissons dans des bouteilles en verre et des gobelets consignés.",[446,25589,25590],{},"Repas zéro déchet.",[19,25592,25593],{},[176,25594],{"alt":25595,"src":25596},"Consigne boissons du Devfest","\u002Fcontent-assets\u002F2024-08-27-retour-sur-le-devfest\u002Fassets\u002Fimg2.webp",[19,25598,25599],{},[176,25600],{"alt":25601,"src":25602},"Stand déjeuner avec lunch bag du Devfest","\u002Fcontent-assets\u002F2024-08-27-retour-sur-le-devfest\u002Fassets\u002Fimg3.webp",[19,25604,25605],{},[176,25606],{"alt":25601,"src":25607},"\u002Fcontent-assets\u002F2024-08-27-retour-sur-le-devfest\u002Fassets\u002Fimg4.webp",[19,25609,25610],{},"À noter aussi leur travail sur l'accessibilité avec le sous-titrage réalisé par le Messageur, pour que les conférences puissent être accessible à tous les publics en situation de handicap 👏",[23,25612,25614],{"id":25613},"retour-sur-les-conférences","Retour sur les conférences",[84,25616,25618],{"id":25617},"survivre-dans-la-js-jungle-des-outils-de-tests-lise-quesnel-par-théo-lanord","Survivre dans la JS-jungle des outils de tests  (Lise Quesnel) par  Théo Lanord",[19,25620,25621],{},"Je tiens à faire un retour sur la conférence de Lise QUESNEL pour la remercier de m'avoir aider à voir plus clair dans la JS-jungle des outils de tests !",[19,25623,25624],{},"Avant tout, est-ce que tester, c'est douter ? Et oui, pourquoi tester ?",[19,25626,25627],{},"Tester manuellement est une activité chronophage avec des résultats non répétables. La force des tests automatisés est leur rapidité et leur répétabilité.\nCes deux qualités diminuent les boucles de feedback que soit en local, en pipeline de CI\u002FCD ou même en recette.",[19,25629,25630],{},"En quoi réduire la boucle de feedback est intéressant ?",[19,25632,25633],{},"Plus l'erreur est détectée tard dans la chaîne de valeur, plus elle sera coûteuse à réparer (Localisation, recontextualisation, etc).\nAssocié à de petites incrémentations, tester permet de délivrer de la valeur plus rapidement tout en augmentant la qualité.\nCe qui me tient à cœur, c'est d'augmenter la confiance entre les différentes parties prenantes (développeurs, PO, QA, etc) pour, à terme, diminuer la pression au quotidien.",[19,25635,25636],{},"Choisir ses outils en fonction du contexte",[19,25638,25639],{},"De nombreuses typologies d'outils existent (lanceurs, structurateurs, utilitaires, mocks, etc). Certains outils implémenteront tout ou partie de ces typologies.\nLe choix des outils varie en fonction de votre besoin et contexte.\nDans de nombreux cas, ils vous donneront des modèles de test sur lesquels poser vos premiers tests. Il est important de votre côté d'avoir un nommage de test explicite qui pourra déboucher vers un langage commun compréhensible par les développeurs et le métier.",[19,25641,25642],{},"Classifier les tests : Equilibre entre coût, rapidité et confiance",[19,25644,25645],{},"Vous trouverez dans la JS-Jungle de nombreux noms de tests (unitaire, intégration, bout en bout, acceptance, composants, contracts, etc). Je ne peux que vous conseiller d'en discuter avec vos collègues pour vous approprier ces notions au sein de votre équipe.",[19,25647,25648],{},"La question final sera donc lesquels utiliser et en quelle proportion ?",[19,25650,25651,25652,25657],{},"Si j'ai touché votre curiosité, n'hésitez à regarder mon ",[91,25653,25656],{"href":25654,"rel":25655},"https:\u002F\u002Fblog.hoppr.tech\u002Fretour_%22survivre_dans_la_JS-jungle_des_outils_de_tests%22_de_lise_quesnel_au_devfest_2024",[95],"retour plus complet sur cette même conférence",".\nEncore un grand merci et fécilitations pour la qualité de rédaction (métaphores, images, etc) et de narration de sa conférence !",[84,25659,25661],{"id":25660},"de-lexclusion-à-linclusion-laccessibilité-numérique-pour-tous-et-toutes-emmanuelle-aboaf-par-elisa-degobert","De l'exclusion à l'inclusion : l'accessibilité numérique pour tous et toutes (Emmanuelle Aboaf) par Elisa Degobert",[19,25663,25664],{},"En France, 1 personne sur 6 est atteinte d’un handicap et il est la plupart du temps invisible. Pourtant, la majorité des sites web ne sont PAS accessibles.",[19,25666,25667],{},"Au-delà de l'enjeu moral de l'inclusion, ne pas rendre son site accessible, c'est réduire sa cible d'utilisateurs potentiels.",[19,25669,25670],{},"L'accessibilité nous profite à tous",[19,25672,25673],{},"On peut penser que les problèmes d'accessibilité ne nous touchent pas mais tout le monde bénéficie au quotidien d'inventions pensées pour des personnes atteintes de handicap: les SMS, la télécommande ou encore les livres audio en sont des exemples.",[19,25675,25676],{},"S'il s'agit d'une problématique permanente pour de nombreuses personnes, nous subissons tous à un moment de notre vie ce manque d’accessibilité, que ce soit de manière permanente, temporaire ou situationnelle.",[19,25678,25679],{},"En effet un rhume peut affecter notre capacité à parler, un bras cassé à utiliser nos mains (handicaps temporaires) ou des situations peuvent altérer nos capacités: lorsque nous sommes dans des endroits bruyants notre ouïe est impactée, lorsque l'on doit garder un bébé à bras tout en naviguant sur l'ordinateur notre motricité est impactée, etc.",[19,25681,25682],{},"Les erreurs que l'on fait tous et toutes…",[19,25684,25685],{},"La majorité des erreurs relèvent d'un usage imparfait du langage HTML :",[443,25687,25688,25691,25694,25697],{},[446,25689,25690],{},"textes alternatifs manquants (alt dans les images et les boutons contenant qu'une image),",[446,25692,25693],{},"étiquettes manquantes dans les formulaires (un label doit avoir l'attribut for défini avec le même nom que l'attribut id de l'input correspondant),",[446,25695,25696],{},"liens vides (les urls ne suffisent pas toujours à savoir quel lien correspond à quoi, utilisez l'attribut title)",[446,25698,25699],{},"langue manquante du site (l'attribut lang dans la balise html définit la langue du site).\nPar exemple, en définissant la langue de votre site, les lecteurs d'écran vont savoir quel accent utiliser\n(pour ne pas lire du texte français avec un accent anglais) et votre navigateur évitera de faire des traductions surprenantes\n(comme traduire le prénom Jimmy par pied-de-biche !).",[19,25701,25702],{},"Comment savoir si votre site est accessible ?",[19,25704,25705,25706,25711,25712,25717,25718,25722],{},"👉 Vous pouvez retrouver plein de ressources sur le sujet de l'accessibilité sur le ",[91,25707,25710],{"href":25708,"rel":25709},"https:\u002F\u002Fwww.a11yproject.com\u002F",[95],"projet a11y","\net la liste des règles d'accessibilité sur ",[91,25713,25716],{"href":25714,"rel":25715},"https:\u002F\u002Fwcag.com\u002F",[95],"WCAG",", avec des exemples concrets.\n",[91,25719,19238],{"href":25720,"rel":25721},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Flighthouse\u002Foverview",[95]," peut aussi vous aider à auditer l'accessibilité de votre site.",[19,25724,25725],{},"L'important est de sensibiliser à l'accessibilité autour de soi mais il est difficile de savoir si notre site est accessible.\navant de l'avoir confronté aux utilisateurs concernés.\nComme l'a conclu E. Aboaf, l'important est d'inclure des personnes handicapées dans les process : \"Nothing with us without us\" !",[19,25727,25728,25729,25734],{},"Je vous encourage vivement à aller voir le replay de son talk 🎤 pour en savoir plus et d'explorer ",[91,25730,25733],{"href":25731,"rel":25732},"https:\u002F\u002Fbento.me\u002Feaboaf",[95],"son site"," pour consulter ses articles sur le sujet.",[84,25736,25738],{"id":25737},"maîtrisez-la-hype-passion-versus-raison-william-leemans-par-sébastien-jaupart","Maîtrisez la Hype : Passion versus Raison (William Leemans) par Sébastien Jaupart",[19,25740,25741],{},"La passion nous pousse parfois à tester les nouveautés de notre secteur. Parfois un peu trop...",[19,25743,25744],{},"S'exercer sur de nouvelles technologies contribue grandement à l'apprentissage et développent notre capacité à nous adapter. Néanmoins, les contraintes temporelles et financières d'un projet peuvent rapidement nous rattraper. Adopter une technologie trop tôt (par \"effet de mode\") ou s'entêter sur des technologies inadaptées à nos besoins peut avoir des effets néfastes pour nos projets.",[19,25746,25747],{},"William Leemans nous alertent face au \"chant des sirènes de la Hype\" et nous proposent un ensemble de bonnes pratiques, astuces et concepts pour s'y prémunir et faire les bons choix.",[19,25749,25750],{},"La notion de spike (que j'avoue avoir un peu oublié avec le temps) nous impose de timeboxer les essais d'une technologie pour, in fine, documenter et partager les découvertes et résultats obtenus et juger de la pertinence de son usage sur le projet.",[19,25752,25753],{},"Les choix éclairés d'une personne ou d'une équipe ne le sont pas toujours par d'autres. Généralement pris sur la base d'un contexte, ils peuvent être tracés par le biais d'un ADR (Architecture Decision Record), document retraçant un choix (architectural, de technologie, etc) incluant le contexte, les raisons de ce choix et ses potentielles alternatives. Ils encouragent la réflexion critique, améliorent la communication au sein des équipes et facilitent l'apprentissage continu. Très utile également pour onboarder de nouveaux collaborateurs sur un projet.",[19,25755,25756],{},"Quels que soient nos choix, les intérêts du projet doivent primer. Pour éviter de choisir un framework inadapté à nos contraintes, il est impératif d'analyser les besoins de nos projets. Pour cela, il est nécessaire de se documenter un maximum, s'imprégner de la philosophie de l'outil et appliquer directement les bonnes pratiques préconisées par la documentation officielle. La sobriété est de mise. Plus la stack est simple, moins il y aura de maintenance.",[19,25758,25759],{},"Bref, un équilibre à trouver entre innovation et stabilité.",[19,25761,5381,25762,25767],{},[91,25763,25766],{"href":25764,"rel":25765},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=TPhRprV2L24",[95],"replay de la conférence"," est disponible sur Youtube.",[23,25769,25771],{"id":25770},"rattrapage","Rattrapage",[19,25773,25774],{},"Avec 3 salles et plus d'une cinquantaine de sujets, il est impossible de suivre tous les sujets et c'est parfois difficile de faire son choix.",[19,25776,25777,25778],{},"No stress, l'équipe a tout prévu et des replays sont disponibles sur la ",[91,25779,25782],{"href":25780,"rel":25781},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=eDCmfZUmsUA&list=PLuZ_sYdawLiXf92Uq5iE5LlYKrOv1IUvx&pp=iAQB",[95],"chaine Youtube du GDG France",[19,25784,25785],{},"Allez on se voit l’année prochaine 😄",{"title":350,"searchDepth":364,"depth":364,"links":25787},[25788,25789,25794],{"id":25575,"depth":364,"text":25576},{"id":25613,"depth":364,"text":25614,"children":25790},[25791,25792,25793],{"id":25617,"depth":370,"text":25618},{"id":25660,"depth":370,"text":25661},{"id":25737,"depth":370,"text":25738},{"id":25770,"depth":364,"text":25771},"2024-08-27T10:22:46.143Z","Les 6 et 7 Juin dernier s'est déroulée la 7ᵉ édition du DevFest Lille au Grand Palais. Pour la première fois sur un format de 2 jours avec une soirée organisée à Grand Scène (on y reviendra plus tard",{},"\u002Fblogs\u002F2024-08-27-retour-sur-le-devfest",[25800,25802],{"id":10,"name":11,"image":25801,"linkedin":13,"x":14},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240827%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240827T102245Z&X-Amz-Expires=3600&X-Amz-Signature=11e2bdc81f73ae453331fd5d334bb1e97c35bc5f075ccbf072c6d349e83108d4&X-Amz-SignedHeaders=host&x-id=GetObject",{"id":1582,"name":1583,"image":25803,"linkedin":1585,"x":901},"https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240827%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240827T102244Z&X-Amz-Expires=3600&X-Amz-Signature=15fc0a4d1e4645500844a19498b80c1d868a04913c404520471b3a6a00be86a0&X-Amz-SignedHeaders=host&x-id=GetObject",{"title":25541,"description":25796},"blogs\u002F2024-08-27-retour-sur-le-devfest\u002Findex",[6271,6607,6606,7819],"N5ACW7zjk3mqK58dp5xjkD97DXrYtJXkvL1CNeYvIB8",1778688640569]