[{"data":1,"prerenderedAt":7118},["ShallowReactive",2],{"search-api":-1,"listing-tag-Architecture-page-1":3},[4,4892,6326],{"_path":5,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":9,"description":10,"id":11,"date":12,"listed":13,"nocomments":7,"hidden":7,"categories":14,"tags":15,"--cover":20,"readingTime":21,"body":26,"_type":4886,"_id":4887,"_source":4888,"_file":4889,"_stem":4890,"_extension":4891},"/fr/architecture-craft/dependency-inversion-pratique","architecture-craft",false,"","Dependency Inversion Principle : 3 exemples concrets","Le DIP est le principe SOLID le plus mal compris. Pas un pattern de conception — une règle sur la direction des dépendances. Trois implémentations dans trois langages.",30,"2026-03-13",true,[6],[16,17,18,19],"SOLID","Dependency Inversion","Architecture","Clean Code","covers/articles/dependency-inversion-principe.jpg",{"text":22,"minutes":23,"time":24,"words":25},"8 min read",7.155,429300,1431,{"type":27,"children":28,"toc":4877},"root",[29,37,43,48,53,57,64,78,83,479,488,536,539,545,589,597,602,605,611,1691,1699,2193,2206,2209,2215,3707,3717,3720,3726,4651,4669,4672,4678,4686,4704,4712,4730,4748,4751,4757,4772,4785,4798,4819,4856,4859,4871],{"type":30,"tag":31,"props":32,"children":34},"element","h1",{"id":33},"dependency-inversion-principle-3-exemples-concrets",[35],{"type":36,"value":9},"text",{"type":30,"tag":38,"props":39,"children":40},"p",{},[41],{"type":36,"value":42},"Chez un client dans le secteur du retail en ligne que j'accompagnais (20 développeurs, 8 services backend), la suite de tests prenait 18 minutes à s'exécuter. Pas parce que les tests étaient lents. Parce que chaque test unitaire démarrait une vraie base de données PostgreSQL, un vrai serveur Redis, et appelait le vrai Sendgrid.",{"type":30,"tag":38,"props":44,"children":45},{},[46],{"type":36,"value":47},"Ce n'était pas un problème de tests. C'était un problème d'architecture : les modules métier dépendaient directement des implémentations concrètes d'infrastructure.",{"type":30,"tag":38,"props":49,"children":50},{},[51],{"type":36,"value":52},"Après avoir introduit le Dependency Inversion Principle sur les 8 services les plus critiques, la suite de tests est passée à 3 minutes. La couverture de tests a augmenté de 35% à 72% en 3 mois. Pas parce que les développeurs avaient soudain envie d'écrire des tests, mais parce que les tests étaient devenus faciles à écrire.",{"type":30,"tag":54,"props":55,"children":56},"hr",{},[],{"type":30,"tag":58,"props":59,"children":61},"h2",{"id":60},"le-problème-la-dépendance-directe",[62],{"type":36,"value":63},"Le problème : la dépendance directe",{"type":30,"tag":38,"props":65,"children":66},{},[67,69,76],{"type":36,"value":68},"Robert C. Martin (Uncle Bob) a formulé le DIP en 1996 dans ses travaux sur les principes SOLID : \"Les modules de haut niveau ne doivent pas dépendre des modules de bas niveau. Les deux doivent dépendre d'abstractions.\" C'est la règle de dépendance au cœur de la ",{"type":30,"tag":70,"props":71,"children":73},"a",{"href":72},"/fr/architecture-craft/clean-architecture-3-regles",[74],{"type":36,"value":75},"Clean Architecture",{"type":36,"value":77}," : les flèches de dépendance doivent toujours pointer vers l'intérieur, vers le domaine métier.",{"type":30,"tag":38,"props":79,"children":80},{},[81],{"type":36,"value":82},"En pratique, la quasi-totalité des codebases sans discipline architecturale viole ce principe :",{"type":30,"tag":84,"props":85,"children":89},"pre",{"code":86,"language":87,"meta":8,"className":88,"style":8},"# Violation du DIP — le module de haut niveau dépend du module de bas niveau\n\nclass OrderService:\n    def __init__(self):\n        self.db = PostgreSQLDatabase(host=\"localhost\", port=5432)  # dépendance directe\n        self.email = SendgridEmailClient(api_key=\"...\")              # dépendance directe\n\n    def create_order(self, order_data):\n        order_id = self.db.save(order_data)\n        self.email.send_confirmation(order_data[\"email\"], order_id)\n        return order_id\n","python","language-python shiki shiki-themes catppuccin-frappe github-dark",[90],{"type":30,"tag":91,"props":92,"children":93},"code",{"__ignoreMap":8},[94,106,115,137,168,251,304,312,348,398,465],{"type":30,"tag":95,"props":96,"children":99},"span",{"class":97,"line":98},"line",1,[100],{"type":30,"tag":95,"props":101,"children":103},{"style":102},"--shiki-default:#737994;--shiki-default-font-style:italic;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit",[104],{"type":36,"value":105},"# Violation du DIP — le module de haut niveau dépend du module de bas niveau\n",{"type":30,"tag":95,"props":107,"children":109},{"class":97,"line":108},2,[110],{"type":30,"tag":95,"props":111,"children":112},{"emptyLinePlaceholder":13},[113],{"type":36,"value":114},"\n",{"type":30,"tag":95,"props":116,"children":118},{"class":97,"line":117},3,[119,125,131],{"type":30,"tag":95,"props":120,"children":122},{"style":121},"--shiki-default:#CA9EE6;--shiki-dark:#F97583",[123],{"type":36,"value":124},"class",{"type":30,"tag":95,"props":126,"children":128},{"style":127},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[129],{"type":36,"value":130}," OrderService",{"type":30,"tag":95,"props":132,"children":134},{"style":133},"--shiki-default:#949CBB;--shiki-dark:#E1E4E8",[135],{"type":36,"value":136},":\n",{"type":30,"tag":95,"props":138,"children":140},{"class":97,"line":139},4,[141,146,152,157,163],{"type":30,"tag":95,"props":142,"children":143},{"style":121},[144],{"type":36,"value":145},"    def",{"type":30,"tag":95,"props":147,"children":149},{"style":148},"--shiki-default:#99D1DB;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[150],{"type":36,"value":151}," __init__",{"type":30,"tag":95,"props":153,"children":154},{"style":133},[155],{"type":36,"value":156},"(",{"type":30,"tag":95,"props":158,"children":160},{"style":159},"--shiki-default:#E78284;--shiki-default-font-style:italic;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit",[161],{"type":36,"value":162},"self",{"type":30,"tag":95,"props":164,"children":165},{"style":133},[166],{"type":36,"value":167},"):\n",{"type":30,"tag":95,"props":169,"children":171},{"class":97,"line":170},5,[172,178,183,189,195,201,205,211,215,221,226,231,235,241,246],{"type":30,"tag":95,"props":173,"children":175},{"style":174},"--shiki-default:#E78284;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[176],{"type":36,"value":177},"        self",{"type":30,"tag":95,"props":179,"children":180},{"style":133},[181],{"type":36,"value":182},".",{"type":30,"tag":95,"props":184,"children":186},{"style":185},"--shiki-default:#C6D0F5;--shiki-dark:#E1E4E8",[187],{"type":36,"value":188},"db ",{"type":30,"tag":95,"props":190,"children":192},{"style":191},"--shiki-default:#81C8BE;--shiki-dark:#F97583",[193],{"type":36,"value":194},"=",{"type":30,"tag":95,"props":196,"children":198},{"style":197},"--shiki-default:#8CAAEE;--shiki-dark:#E1E4E8",[199],{"type":36,"value":200}," PostgreSQLDatabase",{"type":30,"tag":95,"props":202,"children":203},{"style":133},[204],{"type":36,"value":156},{"type":30,"tag":95,"props":206,"children":208},{"style":207},"--shiki-default:#EA999C;--shiki-default-font-style:italic;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit",[209],{"type":36,"value":210},"host",{"type":30,"tag":95,"props":212,"children":213},{"style":191},[214],{"type":36,"value":194},{"type":30,"tag":95,"props":216,"children":218},{"style":217},"--shiki-default:#A6D189;--shiki-dark:#9ECBFF",[219],{"type":36,"value":220},"\"localhost\"",{"type":30,"tag":95,"props":222,"children":223},{"style":133},[224],{"type":36,"value":225},",",{"type":30,"tag":95,"props":227,"children":228},{"style":207},[229],{"type":36,"value":230}," port",{"type":30,"tag":95,"props":232,"children":233},{"style":191},[234],{"type":36,"value":194},{"type":30,"tag":95,"props":236,"children":238},{"style":237},"--shiki-default:#EF9F76;--shiki-dark:#79B8FF",[239],{"type":36,"value":240},"5432",{"type":30,"tag":95,"props":242,"children":243},{"style":133},[244],{"type":36,"value":245},")",{"type":30,"tag":95,"props":247,"children":248},{"style":102},[249],{"type":36,"value":250},"  # dépendance directe\n",{"type":30,"tag":95,"props":252,"children":254},{"class":97,"line":253},6,[255,259,263,268,272,277,281,286,290,295,299],{"type":30,"tag":95,"props":256,"children":257},{"style":174},[258],{"type":36,"value":177},{"type":30,"tag":95,"props":260,"children":261},{"style":133},[262],{"type":36,"value":182},{"type":30,"tag":95,"props":264,"children":265},{"style":185},[266],{"type":36,"value":267},"email ",{"type":30,"tag":95,"props":269,"children":270},{"style":191},[271],{"type":36,"value":194},{"type":30,"tag":95,"props":273,"children":274},{"style":197},[275],{"type":36,"value":276}," SendgridEmailClient",{"type":30,"tag":95,"props":278,"children":279},{"style":133},[280],{"type":36,"value":156},{"type":30,"tag":95,"props":282,"children":283},{"style":207},[284],{"type":36,"value":285},"api_key",{"type":30,"tag":95,"props":287,"children":288},{"style":191},[289],{"type":36,"value":194},{"type":30,"tag":95,"props":291,"children":292},{"style":217},[293],{"type":36,"value":294},"\"...\"",{"type":30,"tag":95,"props":296,"children":297},{"style":133},[298],{"type":36,"value":245},{"type":30,"tag":95,"props":300,"children":301},{"style":102},[302],{"type":36,"value":303},"              # dépendance directe\n",{"type":30,"tag":95,"props":305,"children":307},{"class":97,"line":306},7,[308],{"type":30,"tag":95,"props":309,"children":310},{"emptyLinePlaceholder":13},[311],{"type":36,"value":114},{"type":30,"tag":95,"props":313,"children":315},{"class":97,"line":314},8,[316,320,326,330,334,338,344],{"type":30,"tag":95,"props":317,"children":318},{"style":121},[319],{"type":36,"value":145},{"type":30,"tag":95,"props":321,"children":323},{"style":322},"--shiki-default:#8CAAEE;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[324],{"type":36,"value":325}," create_order",{"type":30,"tag":95,"props":327,"children":328},{"style":133},[329],{"type":36,"value":156},{"type":30,"tag":95,"props":331,"children":332},{"style":159},[333],{"type":36,"value":162},{"type":30,"tag":95,"props":335,"children":336},{"style":133},[337],{"type":36,"value":225},{"type":30,"tag":95,"props":339,"children":341},{"style":340},"--shiki-default:#EA999C;--shiki-default-font-style:italic;--shiki-dark:#E1E4E8;--shiki-dark-font-style:inherit",[342],{"type":36,"value":343}," order_data",{"type":30,"tag":95,"props":345,"children":346},{"style":133},[347],{"type":36,"value":167},{"type":30,"tag":95,"props":349,"children":351},{"class":97,"line":350},9,[352,357,361,366,370,375,379,384,388,393],{"type":30,"tag":95,"props":353,"children":354},{"style":185},[355],{"type":36,"value":356},"        order_id ",{"type":30,"tag":95,"props":358,"children":359},{"style":191},[360],{"type":36,"value":194},{"type":30,"tag":95,"props":362,"children":363},{"style":174},[364],{"type":36,"value":365}," self",{"type":30,"tag":95,"props":367,"children":368},{"style":133},[369],{"type":36,"value":182},{"type":30,"tag":95,"props":371,"children":372},{"style":185},[373],{"type":36,"value":374},"db",{"type":30,"tag":95,"props":376,"children":377},{"style":133},[378],{"type":36,"value":182},{"type":30,"tag":95,"props":380,"children":381},{"style":197},[382],{"type":36,"value":383},"save",{"type":30,"tag":95,"props":385,"children":386},{"style":133},[387],{"type":36,"value":156},{"type":30,"tag":95,"props":389,"children":390},{"style":185},[391],{"type":36,"value":392},"order_data",{"type":30,"tag":95,"props":394,"children":395},{"style":133},[396],{"type":36,"value":397},")\n",{"type":30,"tag":95,"props":399,"children":401},{"class":97,"line":400},10,[402,406,410,415,419,424,428,432,437,442,447,451,456,461],{"type":30,"tag":95,"props":403,"children":404},{"style":174},[405],{"type":36,"value":177},{"type":30,"tag":95,"props":407,"children":408},{"style":133},[409],{"type":36,"value":182},{"type":30,"tag":95,"props":411,"children":412},{"style":185},[413],{"type":36,"value":414},"email",{"type":30,"tag":95,"props":416,"children":417},{"style":133},[418],{"type":36,"value":182},{"type":30,"tag":95,"props":420,"children":421},{"style":197},[422],{"type":36,"value":423},"send_confirmation",{"type":30,"tag":95,"props":425,"children":426},{"style":133},[427],{"type":36,"value":156},{"type":30,"tag":95,"props":429,"children":430},{"style":340},[431],{"type":36,"value":392},{"type":30,"tag":95,"props":433,"children":434},{"style":133},[435],{"type":36,"value":436},"[",{"type":30,"tag":95,"props":438,"children":439},{"style":217},[440],{"type":36,"value":441},"\"",{"type":30,"tag":95,"props":443,"children":445},{"style":444},"--shiki-default:#A6D189;--shiki-default-font-style:italic;--shiki-dark:#9ECBFF;--shiki-dark-font-style:inherit",[446],{"type":36,"value":414},{"type":30,"tag":95,"props":448,"children":449},{"style":217},[450],{"type":36,"value":441},{"type":30,"tag":95,"props":452,"children":453},{"style":133},[454],{"type":36,"value":455},"],",{"type":30,"tag":95,"props":457,"children":458},{"style":185},[459],{"type":36,"value":460}," order_id",{"type":30,"tag":95,"props":462,"children":463},{"style":133},[464],{"type":36,"value":397},{"type":30,"tag":95,"props":466,"children":468},{"class":97,"line":467},11,[469,474],{"type":30,"tag":95,"props":470,"children":471},{"style":121},[472],{"type":36,"value":473},"        return",{"type":30,"tag":95,"props":475,"children":476},{"style":185},[477],{"type":36,"value":478}," order_id\n",{"type":30,"tag":38,"props":480,"children":481},{},[482],{"type":30,"tag":483,"props":484,"children":485},"strong",{},[486],{"type":36,"value":487},"Ce que ça coûte concrètement :",{"type":30,"tag":489,"props":490,"children":491},"ul",{},[492,506,516,526],{"type":30,"tag":493,"props":494,"children":495},"li",{},[496,498,504],{"type":36,"value":497},"Impossible de tester ",{"type":30,"tag":91,"props":499,"children":501},{"className":500},[],[502],{"type":36,"value":503},"OrderService",{"type":36,"value":505}," sans une vraie base de données PostgreSQL et un compte Sendgrid",{"type":30,"tag":493,"props":507,"children":508},{},[509,511],{"type":36,"value":510},"Changer de base de données oblige à modifier ",{"type":30,"tag":91,"props":512,"children":514},{"className":513},[],[515],{"type":36,"value":503},{"type":30,"tag":493,"props":517,"children":518},{},[519,521],{"type":36,"value":520},"Changer d'email provider oblige à modifier ",{"type":30,"tag":91,"props":522,"children":524},{"className":523},[],[525],{"type":36,"value":503},{"type":30,"tag":493,"props":527,"children":528},{},[529,534],{"type":30,"tag":91,"props":530,"children":532},{"className":531},[],[533],{"type":36,"value":503},{"type":36,"value":535}," connaît des détails d'implémentation (host, port, api_key) qui n'ont rien à voir avec la logique métier de commande",{"type":30,"tag":54,"props":537,"children":538},{},[],{"type":30,"tag":58,"props":540,"children":542},{"id":541},"le-principe-inverser-la-direction-des-dépendances",[543],{"type":36,"value":544},"Le principe : inverser la direction des dépendances",{"type":30,"tag":38,"props":546,"children":547},{},[548,550,555,557,563,565,571,573,579,581,587],{"type":36,"value":549},"La solution DIP : ",{"type":30,"tag":91,"props":551,"children":553},{"className":552},[],[554],{"type":36,"value":503},{"type":36,"value":556}," ne dépend pas de ",{"type":30,"tag":91,"props":558,"children":560},{"className":559},[],[561],{"type":36,"value":562},"PostgreSQLDatabase",{"type":36,"value":564}," ni de ",{"type":30,"tag":91,"props":566,"children":568},{"className":567},[],[569],{"type":36,"value":570},"SendgridEmailClient",{"type":36,"value":572},". Il dépend d'abstractions (",{"type":30,"tag":91,"props":574,"children":576},{"className":575},[],[577],{"type":36,"value":578},"OrderRepository",{"type":36,"value":580},", ",{"type":30,"tag":91,"props":582,"children":584},{"className":583},[],[585],{"type":36,"value":586},"EmailNotifier",{"type":36,"value":588},") que les implémentations concrètes respectent.",{"type":30,"tag":84,"props":590,"children":592},{"code":591},"Sans DIP :\nOrderService → PostgreSQLDatabase\nOrderService → SendgridEmailClient\n\nAvec DIP :\nOrderService → OrderRepository (abstraction) ← PostgreSQLOrderRepository (implémentation)\nOrderService → EmailNotifier (abstraction)   ← SendgridEmailNotifier (implémentation)\n",[593],{"type":30,"tag":91,"props":594,"children":595},{"__ignoreMap":8},[596],{"type":36,"value":591},{"type":30,"tag":38,"props":598,"children":599},{},[600],{"type":36,"value":601},"La flèche s'inverse : l'implémentation concrète dépend de l'abstraction, pas l'inverse.",{"type":30,"tag":54,"props":603,"children":604},{},[],{"type":30,"tag":58,"props":606,"children":608},{"id":607},"exemple-1-python-injection-par-constructeur",[609],{"type":36,"value":610},"Exemple 1 : Python, injection par constructeur",{"type":30,"tag":84,"props":612,"children":614},{"code":613,"language":87,"meta":8,"className":88,"style":8},"from abc import ABC, abstractmethod\n\nclass OrderRepository(ABC):\n    @abstractmethod\n    def save(self, order_data: dict) -> str:\n        pass\n\nclass EmailNotifier(ABC):\n    @abstractmethod\n    def send_confirmation(self, email: str, order_id: str) -> None:\n        pass\n\n# Le module de haut niveau — dépend uniquement des abstractions\nclass OrderService:\n    def __init__(self, repository: OrderRepository, notifier: EmailNotifier):\n        self.repository = repository\n        self.notifier = notifier\n\n    def create_order(self, order_data: dict) -> str:\n        order_id = self.repository.save(order_data)\n        self.notifier.send_confirmation(order_data[\"email\"], order_id)\n        return order_id\n\n# Les implémentations concrètes\nclass PostgreSQLOrderRepository(OrderRepository):\n    def save(self, order_data: dict) -> str:\n        return self.db.execute(\"INSERT INTO orders ...\", order_data)\n\nclass SendgridEmailNotifier(EmailNotifier):\n    def send_confirmation(self, email: str, order_id: str) -> None:\n        self.client.send(to=email, template=\"order_confirmation\", data={\"order_id\": order_id})\n\n# Composition à la racine de l'application\ndef create_order_service():\n    repository = PostgreSQLOrderRepository(db)\n    notifier = SendgridEmailNotifier(api_key=os.getenv(\"SENDGRID_KEY\"))\n    return OrderService(repository, notifier)\n",[615],{"type":30,"tag":91,"props":616,"children":617},{"__ignoreMap":8},[618,651,658,683,692,749,757,764,788,795,866,873,881,890,906,965,991,1017,1025,1077,1122,1183,1195,1203,1212,1237,1289,1339,1347,1372,1439,1536,1544,1553,1572,1601,1658],{"type":30,"tag":95,"props":619,"children":620},{"class":97,"line":98},[621,626,631,636,642,646],{"type":30,"tag":95,"props":622,"children":623},{"style":121},[624],{"type":36,"value":625},"from",{"type":30,"tag":95,"props":627,"children":628},{"style":185},[629],{"type":36,"value":630}," abc ",{"type":30,"tag":95,"props":632,"children":633},{"style":121},[634],{"type":36,"value":635},"import",{"type":30,"tag":95,"props":637,"children":639},{"style":638},"--shiki-default:#C6D0F5;--shiki-dark:#79B8FF",[640],{"type":36,"value":641}," ABC",{"type":30,"tag":95,"props":643,"children":644},{"style":133},[645],{"type":36,"value":225},{"type":30,"tag":95,"props":647,"children":648},{"style":185},[649],{"type":36,"value":650}," abstractmethod\n",{"type":30,"tag":95,"props":652,"children":653},{"class":97,"line":108},[654],{"type":30,"tag":95,"props":655,"children":656},{"emptyLinePlaceholder":13},[657],{"type":36,"value":114},{"type":30,"tag":95,"props":659,"children":660},{"class":97,"line":117},[661,665,670,674,679],{"type":30,"tag":95,"props":662,"children":663},{"style":121},[664],{"type":36,"value":124},{"type":30,"tag":95,"props":666,"children":667},{"style":127},[668],{"type":36,"value":669}," OrderRepository",{"type":30,"tag":95,"props":671,"children":672},{"style":133},[673],{"type":36,"value":156},{"type":30,"tag":95,"props":675,"children":676},{"style":638},[677],{"type":36,"value":678},"ABC",{"type":30,"tag":95,"props":680,"children":681},{"style":133},[682],{"type":36,"value":167},{"type":30,"tag":95,"props":684,"children":685},{"class":97,"line":139},[686],{"type":30,"tag":95,"props":687,"children":689},{"style":688},"--shiki-default:#EF9F76;--shiki-default-font-style:italic;--shiki-dark:#B392F0;--shiki-dark-font-style:inherit",[690],{"type":36,"value":691},"    @abstractmethod\n",{"type":30,"tag":95,"props":693,"children":694},{"class":97,"line":170},[695,699,704,708,712,716,720,725,731,735,740,745],{"type":30,"tag":95,"props":696,"children":697},{"style":121},[698],{"type":36,"value":145},{"type":30,"tag":95,"props":700,"children":701},{"style":322},[702],{"type":36,"value":703}," save",{"type":30,"tag":95,"props":705,"children":706},{"style":133},[707],{"type":36,"value":156},{"type":30,"tag":95,"props":709,"children":710},{"style":159},[711],{"type":36,"value":162},{"type":30,"tag":95,"props":713,"children":714},{"style":133},[715],{"type":36,"value":225},{"type":30,"tag":95,"props":717,"children":718},{"style":340},[719],{"type":36,"value":343},{"type":30,"tag":95,"props":721,"children":722},{"style":133},[723],{"type":36,"value":724},":",{"type":30,"tag":95,"props":726,"children":728},{"style":727},"--shiki-default:#EF9F76;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[729],{"type":36,"value":730}," dict",{"type":30,"tag":95,"props":732,"children":733},{"style":133},[734],{"type":36,"value":245},{"type":30,"tag":95,"props":736,"children":737},{"style":133},[738],{"type":36,"value":739}," ->",{"type":30,"tag":95,"props":741,"children":742},{"style":727},[743],{"type":36,"value":744}," str",{"type":30,"tag":95,"props":746,"children":747},{"style":133},[748],{"type":36,"value":136},{"type":30,"tag":95,"props":750,"children":751},{"class":97,"line":253},[752],{"type":30,"tag":95,"props":753,"children":754},{"style":121},[755],{"type":36,"value":756},"        pass\n",{"type":30,"tag":95,"props":758,"children":759},{"class":97,"line":306},[760],{"type":30,"tag":95,"props":761,"children":762},{"emptyLinePlaceholder":13},[763],{"type":36,"value":114},{"type":30,"tag":95,"props":765,"children":766},{"class":97,"line":314},[767,771,776,780,784],{"type":30,"tag":95,"props":768,"children":769},{"style":121},[770],{"type":36,"value":124},{"type":30,"tag":95,"props":772,"children":773},{"style":127},[774],{"type":36,"value":775}," EmailNotifier",{"type":30,"tag":95,"props":777,"children":778},{"style":133},[779],{"type":36,"value":156},{"type":30,"tag":95,"props":781,"children":782},{"style":638},[783],{"type":36,"value":678},{"type":30,"tag":95,"props":785,"children":786},{"style":133},[787],{"type":36,"value":167},{"type":30,"tag":95,"props":789,"children":790},{"class":97,"line":350},[791],{"type":30,"tag":95,"props":792,"children":793},{"style":688},[794],{"type":36,"value":691},{"type":30,"tag":95,"props":796,"children":797},{"class":97,"line":400},[798,802,807,811,815,819,824,828,832,836,840,844,848,852,856,862],{"type":30,"tag":95,"props":799,"children":800},{"style":121},[801],{"type":36,"value":145},{"type":30,"tag":95,"props":803,"children":804},{"style":322},[805],{"type":36,"value":806}," send_confirmation",{"type":30,"tag":95,"props":808,"children":809},{"style":133},[810],{"type":36,"value":156},{"type":30,"tag":95,"props":812,"children":813},{"style":159},[814],{"type":36,"value":162},{"type":30,"tag":95,"props":816,"children":817},{"style":133},[818],{"type":36,"value":225},{"type":30,"tag":95,"props":820,"children":821},{"style":340},[822],{"type":36,"value":823}," email",{"type":30,"tag":95,"props":825,"children":826},{"style":133},[827],{"type":36,"value":724},{"type":30,"tag":95,"props":829,"children":830},{"style":727},[831],{"type":36,"value":744},{"type":30,"tag":95,"props":833,"children":834},{"style":133},[835],{"type":36,"value":225},{"type":30,"tag":95,"props":837,"children":838},{"style":340},[839],{"type":36,"value":460},{"type":30,"tag":95,"props":841,"children":842},{"style":133},[843],{"type":36,"value":724},{"type":30,"tag":95,"props":845,"children":846},{"style":727},[847],{"type":36,"value":744},{"type":30,"tag":95,"props":849,"children":850},{"style":133},[851],{"type":36,"value":245},{"type":30,"tag":95,"props":853,"children":854},{"style":133},[855],{"type":36,"value":739},{"type":30,"tag":95,"props":857,"children":859},{"style":858},"--shiki-default:#CA9EE6;--shiki-dark:#79B8FF",[860],{"type":36,"value":861}," None",{"type":30,"tag":95,"props":863,"children":864},{"style":133},[865],{"type":36,"value":136},{"type":30,"tag":95,"props":867,"children":868},{"class":97,"line":467},[869],{"type":30,"tag":95,"props":870,"children":871},{"style":121},[872],{"type":36,"value":756},{"type":30,"tag":95,"props":874,"children":876},{"class":97,"line":875},12,[877],{"type":30,"tag":95,"props":878,"children":879},{"emptyLinePlaceholder":13},[880],{"type":36,"value":114},{"type":30,"tag":95,"props":882,"children":884},{"class":97,"line":883},13,[885],{"type":30,"tag":95,"props":886,"children":887},{"style":102},[888],{"type":36,"value":889},"# Le module de haut niveau — dépend uniquement des abstractions\n",{"type":30,"tag":95,"props":891,"children":893},{"class":97,"line":892},14,[894,898,902],{"type":30,"tag":95,"props":895,"children":896},{"style":121},[897],{"type":36,"value":124},{"type":30,"tag":95,"props":899,"children":900},{"style":127},[901],{"type":36,"value":130},{"type":30,"tag":95,"props":903,"children":904},{"style":133},[905],{"type":36,"value":136},{"type":30,"tag":95,"props":907,"children":909},{"class":97,"line":908},15,[910,914,918,922,926,930,935,939,944,948,953,957,961],{"type":30,"tag":95,"props":911,"children":912},{"style":121},[913],{"type":36,"value":145},{"type":30,"tag":95,"props":915,"children":916},{"style":148},[917],{"type":36,"value":151},{"type":30,"tag":95,"props":919,"children":920},{"style":133},[921],{"type":36,"value":156},{"type":30,"tag":95,"props":923,"children":924},{"style":159},[925],{"type":36,"value":162},{"type":30,"tag":95,"props":927,"children":928},{"style":133},[929],{"type":36,"value":225},{"type":30,"tag":95,"props":931,"children":932},{"style":340},[933],{"type":36,"value":934}," repository",{"type":30,"tag":95,"props":936,"children":937},{"style":133},[938],{"type":36,"value":724},{"type":30,"tag":95,"props":940,"children":942},{"style":941},"--shiki-default:#EA999C;--shiki-dark:#E1E4E8",[943],{"type":36,"value":669},{"type":30,"tag":95,"props":945,"children":946},{"style":133},[947],{"type":36,"value":225},{"type":30,"tag":95,"props":949,"children":950},{"style":340},[951],{"type":36,"value":952}," notifier",{"type":30,"tag":95,"props":954,"children":955},{"style":133},[956],{"type":36,"value":724},{"type":30,"tag":95,"props":958,"children":959},{"style":941},[960],{"type":36,"value":775},{"type":30,"tag":95,"props":962,"children":963},{"style":133},[964],{"type":36,"value":167},{"type":30,"tag":95,"props":966,"children":968},{"class":97,"line":967},16,[969,973,977,982,986],{"type":30,"tag":95,"props":970,"children":971},{"style":174},[972],{"type":36,"value":177},{"type":30,"tag":95,"props":974,"children":975},{"style":133},[976],{"type":36,"value":182},{"type":30,"tag":95,"props":978,"children":979},{"style":185},[980],{"type":36,"value":981},"repository ",{"type":30,"tag":95,"props":983,"children":984},{"style":191},[985],{"type":36,"value":194},{"type":30,"tag":95,"props":987,"children":988},{"style":185},[989],{"type":36,"value":990}," repository\n",{"type":30,"tag":95,"props":992,"children":994},{"class":97,"line":993},17,[995,999,1003,1008,1012],{"type":30,"tag":95,"props":996,"children":997},{"style":174},[998],{"type":36,"value":177},{"type":30,"tag":95,"props":1000,"children":1001},{"style":133},[1002],{"type":36,"value":182},{"type":30,"tag":95,"props":1004,"children":1005},{"style":185},[1006],{"type":36,"value":1007},"notifier ",{"type":30,"tag":95,"props":1009,"children":1010},{"style":191},[1011],{"type":36,"value":194},{"type":30,"tag":95,"props":1013,"children":1014},{"style":185},[1015],{"type":36,"value":1016}," notifier\n",{"type":30,"tag":95,"props":1018,"children":1020},{"class":97,"line":1019},18,[1021],{"type":30,"tag":95,"props":1022,"children":1023},{"emptyLinePlaceholder":13},[1024],{"type":36,"value":114},{"type":30,"tag":95,"props":1026,"children":1028},{"class":97,"line":1027},19,[1029,1033,1037,1041,1045,1049,1053,1057,1061,1065,1069,1073],{"type":30,"tag":95,"props":1030,"children":1031},{"style":121},[1032],{"type":36,"value":145},{"type":30,"tag":95,"props":1034,"children":1035},{"style":322},[1036],{"type":36,"value":325},{"type":30,"tag":95,"props":1038,"children":1039},{"style":133},[1040],{"type":36,"value":156},{"type":30,"tag":95,"props":1042,"children":1043},{"style":159},[1044],{"type":36,"value":162},{"type":30,"tag":95,"props":1046,"children":1047},{"style":133},[1048],{"type":36,"value":225},{"type":30,"tag":95,"props":1050,"children":1051},{"style":340},[1052],{"type":36,"value":343},{"type":30,"tag":95,"props":1054,"children":1055},{"style":133},[1056],{"type":36,"value":724},{"type":30,"tag":95,"props":1058,"children":1059},{"style":727},[1060],{"type":36,"value":730},{"type":30,"tag":95,"props":1062,"children":1063},{"style":133},[1064],{"type":36,"value":245},{"type":30,"tag":95,"props":1066,"children":1067},{"style":133},[1068],{"type":36,"value":739},{"type":30,"tag":95,"props":1070,"children":1071},{"style":727},[1072],{"type":36,"value":744},{"type":30,"tag":95,"props":1074,"children":1075},{"style":133},[1076],{"type":36,"value":136},{"type":30,"tag":95,"props":1078,"children":1080},{"class":97,"line":1079},20,[1081,1085,1089,1093,1097,1102,1106,1110,1114,1118],{"type":30,"tag":95,"props":1082,"children":1083},{"style":185},[1084],{"type":36,"value":356},{"type":30,"tag":95,"props":1086,"children":1087},{"style":191},[1088],{"type":36,"value":194},{"type":30,"tag":95,"props":1090,"children":1091},{"style":174},[1092],{"type":36,"value":365},{"type":30,"tag":95,"props":1094,"children":1095},{"style":133},[1096],{"type":36,"value":182},{"type":30,"tag":95,"props":1098,"children":1099},{"style":185},[1100],{"type":36,"value":1101},"repository",{"type":30,"tag":95,"props":1103,"children":1104},{"style":133},[1105],{"type":36,"value":182},{"type":30,"tag":95,"props":1107,"children":1108},{"style":197},[1109],{"type":36,"value":383},{"type":30,"tag":95,"props":1111,"children":1112},{"style":133},[1113],{"type":36,"value":156},{"type":30,"tag":95,"props":1115,"children":1116},{"style":185},[1117],{"type":36,"value":392},{"type":30,"tag":95,"props":1119,"children":1120},{"style":133},[1121],{"type":36,"value":397},{"type":30,"tag":95,"props":1123,"children":1125},{"class":97,"line":1124},21,[1126,1130,1134,1139,1143,1147,1151,1155,1159,1163,1167,1171,1175,1179],{"type":30,"tag":95,"props":1127,"children":1128},{"style":174},[1129],{"type":36,"value":177},{"type":30,"tag":95,"props":1131,"children":1132},{"style":133},[1133],{"type":36,"value":182},{"type":30,"tag":95,"props":1135,"children":1136},{"style":185},[1137],{"type":36,"value":1138},"notifier",{"type":30,"tag":95,"props":1140,"children":1141},{"style":133},[1142],{"type":36,"value":182},{"type":30,"tag":95,"props":1144,"children":1145},{"style":197},[1146],{"type":36,"value":423},{"type":30,"tag":95,"props":1148,"children":1149},{"style":133},[1150],{"type":36,"value":156},{"type":30,"tag":95,"props":1152,"children":1153},{"style":340},[1154],{"type":36,"value":392},{"type":30,"tag":95,"props":1156,"children":1157},{"style":133},[1158],{"type":36,"value":436},{"type":30,"tag":95,"props":1160,"children":1161},{"style":217},[1162],{"type":36,"value":441},{"type":30,"tag":95,"props":1164,"children":1165},{"style":444},[1166],{"type":36,"value":414},{"type":30,"tag":95,"props":1168,"children":1169},{"style":217},[1170],{"type":36,"value":441},{"type":30,"tag":95,"props":1172,"children":1173},{"style":133},[1174],{"type":36,"value":455},{"type":30,"tag":95,"props":1176,"children":1177},{"style":185},[1178],{"type":36,"value":460},{"type":30,"tag":95,"props":1180,"children":1181},{"style":133},[1182],{"type":36,"value":397},{"type":30,"tag":95,"props":1184,"children":1186},{"class":97,"line":1185},22,[1187,1191],{"type":30,"tag":95,"props":1188,"children":1189},{"style":121},[1190],{"type":36,"value":473},{"type":30,"tag":95,"props":1192,"children":1193},{"style":185},[1194],{"type":36,"value":478},{"type":30,"tag":95,"props":1196,"children":1198},{"class":97,"line":1197},23,[1199],{"type":30,"tag":95,"props":1200,"children":1201},{"emptyLinePlaceholder":13},[1202],{"type":36,"value":114},{"type":30,"tag":95,"props":1204,"children":1206},{"class":97,"line":1205},24,[1207],{"type":30,"tag":95,"props":1208,"children":1209},{"style":102},[1210],{"type":36,"value":1211},"# Les implémentations concrètes\n",{"type":30,"tag":95,"props":1213,"children":1215},{"class":97,"line":1214},25,[1216,1220,1225,1229,1233],{"type":30,"tag":95,"props":1217,"children":1218},{"style":121},[1219],{"type":36,"value":124},{"type":30,"tag":95,"props":1221,"children":1222},{"style":127},[1223],{"type":36,"value":1224}," PostgreSQLOrderRepository",{"type":30,"tag":95,"props":1226,"children":1227},{"style":133},[1228],{"type":36,"value":156},{"type":30,"tag":95,"props":1230,"children":1231},{"style":127},[1232],{"type":36,"value":578},{"type":30,"tag":95,"props":1234,"children":1235},{"style":133},[1236],{"type":36,"value":167},{"type":30,"tag":95,"props":1238,"children":1240},{"class":97,"line":1239},26,[1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"type":30,"tag":95,"props":1242,"children":1243},{"style":121},[1244],{"type":36,"value":145},{"type":30,"tag":95,"props":1246,"children":1247},{"style":322},[1248],{"type":36,"value":703},{"type":30,"tag":95,"props":1250,"children":1251},{"style":133},[1252],{"type":36,"value":156},{"type":30,"tag":95,"props":1254,"children":1255},{"style":159},[1256],{"type":36,"value":162},{"type":30,"tag":95,"props":1258,"children":1259},{"style":133},[1260],{"type":36,"value":225},{"type":30,"tag":95,"props":1262,"children":1263},{"style":340},[1264],{"type":36,"value":343},{"type":30,"tag":95,"props":1266,"children":1267},{"style":133},[1268],{"type":36,"value":724},{"type":30,"tag":95,"props":1270,"children":1271},{"style":727},[1272],{"type":36,"value":730},{"type":30,"tag":95,"props":1274,"children":1275},{"style":133},[1276],{"type":36,"value":245},{"type":30,"tag":95,"props":1278,"children":1279},{"style":133},[1280],{"type":36,"value":739},{"type":30,"tag":95,"props":1282,"children":1283},{"style":727},[1284],{"type":36,"value":744},{"type":30,"tag":95,"props":1286,"children":1287},{"style":133},[1288],{"type":36,"value":136},{"type":30,"tag":95,"props":1290,"children":1292},{"class":97,"line":1291},27,[1293,1297,1301,1305,1309,1313,1318,1322,1327,1331,1335],{"type":30,"tag":95,"props":1294,"children":1295},{"style":121},[1296],{"type":36,"value":473},{"type":30,"tag":95,"props":1298,"children":1299},{"style":174},[1300],{"type":36,"value":365},{"type":30,"tag":95,"props":1302,"children":1303},{"style":133},[1304],{"type":36,"value":182},{"type":30,"tag":95,"props":1306,"children":1307},{"style":185},[1308],{"type":36,"value":374},{"type":30,"tag":95,"props":1310,"children":1311},{"style":133},[1312],{"type":36,"value":182},{"type":30,"tag":95,"props":1314,"children":1315},{"style":197},[1316],{"type":36,"value":1317},"execute",{"type":30,"tag":95,"props":1319,"children":1320},{"style":133},[1321],{"type":36,"value":156},{"type":30,"tag":95,"props":1323,"children":1324},{"style":217},[1325],{"type":36,"value":1326},"\"INSERT INTO orders ...\"",{"type":30,"tag":95,"props":1328,"children":1329},{"style":133},[1330],{"type":36,"value":225},{"type":30,"tag":95,"props":1332,"children":1333},{"style":185},[1334],{"type":36,"value":343},{"type":30,"tag":95,"props":1336,"children":1337},{"style":133},[1338],{"type":36,"value":397},{"type":30,"tag":95,"props":1340,"children":1342},{"class":97,"line":1341},28,[1343],{"type":30,"tag":95,"props":1344,"children":1345},{"emptyLinePlaceholder":13},[1346],{"type":36,"value":114},{"type":30,"tag":95,"props":1348,"children":1350},{"class":97,"line":1349},29,[1351,1355,1360,1364,1368],{"type":30,"tag":95,"props":1352,"children":1353},{"style":121},[1354],{"type":36,"value":124},{"type":30,"tag":95,"props":1356,"children":1357},{"style":127},[1358],{"type":36,"value":1359}," SendgridEmailNotifier",{"type":30,"tag":95,"props":1361,"children":1362},{"style":133},[1363],{"type":36,"value":156},{"type":30,"tag":95,"props":1365,"children":1366},{"style":127},[1367],{"type":36,"value":586},{"type":30,"tag":95,"props":1369,"children":1370},{"style":133},[1371],{"type":36,"value":167},{"type":30,"tag":95,"props":1373,"children":1374},{"class":97,"line":11},[1375,1379,1383,1387,1391,1395,1399,1403,1407,1411,1415,1419,1423,1427,1431,1435],{"type":30,"tag":95,"props":1376,"children":1377},{"style":121},[1378],{"type":36,"value":145},{"type":30,"tag":95,"props":1380,"children":1381},{"style":322},[1382],{"type":36,"value":806},{"type":30,"tag":95,"props":1384,"children":1385},{"style":133},[1386],{"type":36,"value":156},{"type":30,"tag":95,"props":1388,"children":1389},{"style":159},[1390],{"type":36,"value":162},{"type":30,"tag":95,"props":1392,"children":1393},{"style":133},[1394],{"type":36,"value":225},{"type":30,"tag":95,"props":1396,"children":1397},{"style":340},[1398],{"type":36,"value":823},{"type":30,"tag":95,"props":1400,"children":1401},{"style":133},[1402],{"type":36,"value":724},{"type":30,"tag":95,"props":1404,"children":1405},{"style":727},[1406],{"type":36,"value":744},{"type":30,"tag":95,"props":1408,"children":1409},{"style":133},[1410],{"type":36,"value":225},{"type":30,"tag":95,"props":1412,"children":1413},{"style":340},[1414],{"type":36,"value":460},{"type":30,"tag":95,"props":1416,"children":1417},{"style":133},[1418],{"type":36,"value":724},{"type":30,"tag":95,"props":1420,"children":1421},{"style":727},[1422],{"type":36,"value":744},{"type":30,"tag":95,"props":1424,"children":1425},{"style":133},[1426],{"type":36,"value":245},{"type":30,"tag":95,"props":1428,"children":1429},{"style":133},[1430],{"type":36,"value":739},{"type":30,"tag":95,"props":1432,"children":1433},{"style":858},[1434],{"type":36,"value":861},{"type":30,"tag":95,"props":1436,"children":1437},{"style":133},[1438],{"type":36,"value":136},{"type":30,"tag":95,"props":1440,"children":1442},{"class":97,"line":1441},31,[1443,1447,1451,1456,1460,1465,1469,1474,1478,1482,1486,1491,1495,1500,1504,1509,1513,1518,1523,1527,1531],{"type":30,"tag":95,"props":1444,"children":1445},{"style":174},[1446],{"type":36,"value":177},{"type":30,"tag":95,"props":1448,"children":1449},{"style":133},[1450],{"type":36,"value":182},{"type":30,"tag":95,"props":1452,"children":1453},{"style":185},[1454],{"type":36,"value":1455},"client",{"type":30,"tag":95,"props":1457,"children":1458},{"style":133},[1459],{"type":36,"value":182},{"type":30,"tag":95,"props":1461,"children":1462},{"style":197},[1463],{"type":36,"value":1464},"send",{"type":30,"tag":95,"props":1466,"children":1467},{"style":133},[1468],{"type":36,"value":156},{"type":30,"tag":95,"props":1470,"children":1471},{"style":207},[1472],{"type":36,"value":1473},"to",{"type":30,"tag":95,"props":1475,"children":1476},{"style":191},[1477],{"type":36,"value":194},{"type":30,"tag":95,"props":1479,"children":1480},{"style":185},[1481],{"type":36,"value":414},{"type":30,"tag":95,"props":1483,"children":1484},{"style":133},[1485],{"type":36,"value":225},{"type":30,"tag":95,"props":1487,"children":1488},{"style":207},[1489],{"type":36,"value":1490}," template",{"type":30,"tag":95,"props":1492,"children":1493},{"style":191},[1494],{"type":36,"value":194},{"type":30,"tag":95,"props":1496,"children":1497},{"style":217},[1498],{"type":36,"value":1499},"\"order_confirmation\"",{"type":30,"tag":95,"props":1501,"children":1502},{"style":133},[1503],{"type":36,"value":225},{"type":30,"tag":95,"props":1505,"children":1506},{"style":207},[1507],{"type":36,"value":1508}," data",{"type":30,"tag":95,"props":1510,"children":1511},{"style":191},[1512],{"type":36,"value":194},{"type":30,"tag":95,"props":1514,"children":1515},{"style":133},[1516],{"type":36,"value":1517},"{",{"type":30,"tag":95,"props":1519,"children":1520},{"style":217},[1521],{"type":36,"value":1522},"\"order_id\"",{"type":30,"tag":95,"props":1524,"children":1525},{"style":133},[1526],{"type":36,"value":724},{"type":30,"tag":95,"props":1528,"children":1529},{"style":185},[1530],{"type":36,"value":460},{"type":30,"tag":95,"props":1532,"children":1533},{"style":133},[1534],{"type":36,"value":1535},"})\n",{"type":30,"tag":95,"props":1537,"children":1539},{"class":97,"line":1538},32,[1540],{"type":30,"tag":95,"props":1541,"children":1542},{"emptyLinePlaceholder":13},[1543],{"type":36,"value":114},{"type":30,"tag":95,"props":1545,"children":1547},{"class":97,"line":1546},33,[1548],{"type":30,"tag":95,"props":1549,"children":1550},{"style":102},[1551],{"type":36,"value":1552},"# Composition à la racine de l'application\n",{"type":30,"tag":95,"props":1554,"children":1556},{"class":97,"line":1555},34,[1557,1562,1567],{"type":30,"tag":95,"props":1558,"children":1559},{"style":121},[1560],{"type":36,"value":1561},"def",{"type":30,"tag":95,"props":1563,"children":1564},{"style":322},[1565],{"type":36,"value":1566}," create_order_service",{"type":30,"tag":95,"props":1568,"children":1569},{"style":133},[1570],{"type":36,"value":1571},"():\n",{"type":30,"tag":95,"props":1573,"children":1575},{"class":97,"line":1574},35,[1576,1581,1585,1589,1593,1597],{"type":30,"tag":95,"props":1577,"children":1578},{"style":185},[1579],{"type":36,"value":1580},"    repository ",{"type":30,"tag":95,"props":1582,"children":1583},{"style":191},[1584],{"type":36,"value":194},{"type":30,"tag":95,"props":1586,"children":1587},{"style":197},[1588],{"type":36,"value":1224},{"type":30,"tag":95,"props":1590,"children":1591},{"style":133},[1592],{"type":36,"value":156},{"type":30,"tag":95,"props":1594,"children":1595},{"style":185},[1596],{"type":36,"value":374},{"type":30,"tag":95,"props":1598,"children":1599},{"style":133},[1600],{"type":36,"value":397},{"type":30,"tag":95,"props":1602,"children":1604},{"class":97,"line":1603},36,[1605,1610,1614,1618,1622,1626,1630,1635,1639,1644,1648,1653],{"type":30,"tag":95,"props":1606,"children":1607},{"style":185},[1608],{"type":36,"value":1609},"    notifier ",{"type":30,"tag":95,"props":1611,"children":1612},{"style":191},[1613],{"type":36,"value":194},{"type":30,"tag":95,"props":1615,"children":1616},{"style":197},[1617],{"type":36,"value":1359},{"type":30,"tag":95,"props":1619,"children":1620},{"style":133},[1621],{"type":36,"value":156},{"type":30,"tag":95,"props":1623,"children":1624},{"style":207},[1625],{"type":36,"value":285},{"type":30,"tag":95,"props":1627,"children":1628},{"style":191},[1629],{"type":36,"value":194},{"type":30,"tag":95,"props":1631,"children":1632},{"style":185},[1633],{"type":36,"value":1634},"os",{"type":30,"tag":95,"props":1636,"children":1637},{"style":133},[1638],{"type":36,"value":182},{"type":30,"tag":95,"props":1640,"children":1641},{"style":197},[1642],{"type":36,"value":1643},"getenv",{"type":30,"tag":95,"props":1645,"children":1646},{"style":133},[1647],{"type":36,"value":156},{"type":30,"tag":95,"props":1649,"children":1650},{"style":217},[1651],{"type":36,"value":1652},"\"SENDGRID_KEY\"",{"type":30,"tag":95,"props":1654,"children":1655},{"style":133},[1656],{"type":36,"value":1657},"))\n",{"type":30,"tag":95,"props":1659,"children":1661},{"class":97,"line":1660},37,[1662,1667,1671,1675,1679,1683,1687],{"type":30,"tag":95,"props":1663,"children":1664},{"style":121},[1665],{"type":36,"value":1666},"    return",{"type":30,"tag":95,"props":1668,"children":1669},{"style":197},[1670],{"type":36,"value":130},{"type":30,"tag":95,"props":1672,"children":1673},{"style":133},[1674],{"type":36,"value":156},{"type":30,"tag":95,"props":1676,"children":1677},{"style":185},[1678],{"type":36,"value":1101},{"type":30,"tag":95,"props":1680,"children":1681},{"style":133},[1682],{"type":36,"value":225},{"type":30,"tag":95,"props":1684,"children":1685},{"style":185},[1686],{"type":36,"value":952},{"type":30,"tag":95,"props":1688,"children":1689},{"style":133},[1690],{"type":36,"value":397},{"type":30,"tag":38,"props":1692,"children":1693},{},[1694],{"type":30,"tag":483,"props":1695,"children":1696},{},[1697],{"type":36,"value":1698},"Le gain pour les tests :",{"type":30,"tag":84,"props":1700,"children":1702},{"code":1701,"language":87,"meta":8,"className":88,"style":8},"# Test sans base de données ni Sendgrid — s'exécute en millisecondes\nclass InMemoryOrderRepository(OrderRepository):\n    def __init__(self):\n        self.orders = {}\n\n    def save(self, order_data: dict) -> str:\n        order_id = str(uuid.uuid4())\n        self.orders[order_id] = order_data\n        return order_id\n\ndef test_create_order():\n    repository = InMemoryOrderRepository()\n    notifier = MockEmailNotifier()\n    service = OrderService(repository, notifier)\n\n    order_id = service.create_order({\"email\": \"user@example.com\", \"items\": [...]})\n\n    assert order_id in repository.orders\n    assert len(notifier.sent_confirmations) == 1\n",[1703],{"type":30,"tag":91,"props":1704,"children":1705},{"__ignoreMap":8},[1706,1714,1738,1761,1786,1793,1844,1882,1922,1933,1940,1956,1976,1996,2032,2039,2112,2119,2150],{"type":30,"tag":95,"props":1707,"children":1708},{"class":97,"line":98},[1709],{"type":30,"tag":95,"props":1710,"children":1711},{"style":102},[1712],{"type":36,"value":1713},"# Test sans base de données ni Sendgrid — s'exécute en millisecondes\n",{"type":30,"tag":95,"props":1715,"children":1716},{"class":97,"line":108},[1717,1721,1726,1730,1734],{"type":30,"tag":95,"props":1718,"children":1719},{"style":121},[1720],{"type":36,"value":124},{"type":30,"tag":95,"props":1722,"children":1723},{"style":127},[1724],{"type":36,"value":1725}," InMemoryOrderRepository",{"type":30,"tag":95,"props":1727,"children":1728},{"style":133},[1729],{"type":36,"value":156},{"type":30,"tag":95,"props":1731,"children":1732},{"style":127},[1733],{"type":36,"value":578},{"type":30,"tag":95,"props":1735,"children":1736},{"style":133},[1737],{"type":36,"value":167},{"type":30,"tag":95,"props":1739,"children":1740},{"class":97,"line":117},[1741,1745,1749,1753,1757],{"type":30,"tag":95,"props":1742,"children":1743},{"style":121},[1744],{"type":36,"value":145},{"type":30,"tag":95,"props":1746,"children":1747},{"style":148},[1748],{"type":36,"value":151},{"type":30,"tag":95,"props":1750,"children":1751},{"style":133},[1752],{"type":36,"value":156},{"type":30,"tag":95,"props":1754,"children":1755},{"style":159},[1756],{"type":36,"value":162},{"type":30,"tag":95,"props":1758,"children":1759},{"style":133},[1760],{"type":36,"value":167},{"type":30,"tag":95,"props":1762,"children":1763},{"class":97,"line":139},[1764,1768,1772,1777,1781],{"type":30,"tag":95,"props":1765,"children":1766},{"style":174},[1767],{"type":36,"value":177},{"type":30,"tag":95,"props":1769,"children":1770},{"style":133},[1771],{"type":36,"value":182},{"type":30,"tag":95,"props":1773,"children":1774},{"style":185},[1775],{"type":36,"value":1776},"orders ",{"type":30,"tag":95,"props":1778,"children":1779},{"style":191},[1780],{"type":36,"value":194},{"type":30,"tag":95,"props":1782,"children":1783},{"style":133},[1784],{"type":36,"value":1785}," {}\n",{"type":30,"tag":95,"props":1787,"children":1788},{"class":97,"line":170},[1789],{"type":30,"tag":95,"props":1790,"children":1791},{"emptyLinePlaceholder":13},[1792],{"type":36,"value":114},{"type":30,"tag":95,"props":1794,"children":1795},{"class":97,"line":253},[1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840],{"type":30,"tag":95,"props":1797,"children":1798},{"style":121},[1799],{"type":36,"value":145},{"type":30,"tag":95,"props":1801,"children":1802},{"style":322},[1803],{"type":36,"value":703},{"type":30,"tag":95,"props":1805,"children":1806},{"style":133},[1807],{"type":36,"value":156},{"type":30,"tag":95,"props":1809,"children":1810},{"style":159},[1811],{"type":36,"value":162},{"type":30,"tag":95,"props":1813,"children":1814},{"style":133},[1815],{"type":36,"value":225},{"type":30,"tag":95,"props":1817,"children":1818},{"style":340},[1819],{"type":36,"value":343},{"type":30,"tag":95,"props":1821,"children":1822},{"style":133},[1823],{"type":36,"value":724},{"type":30,"tag":95,"props":1825,"children":1826},{"style":727},[1827],{"type":36,"value":730},{"type":30,"tag":95,"props":1829,"children":1830},{"style":133},[1831],{"type":36,"value":245},{"type":30,"tag":95,"props":1833,"children":1834},{"style":133},[1835],{"type":36,"value":739},{"type":30,"tag":95,"props":1837,"children":1838},{"style":727},[1839],{"type":36,"value":744},{"type":30,"tag":95,"props":1841,"children":1842},{"style":133},[1843],{"type":36,"value":136},{"type":30,"tag":95,"props":1845,"children":1846},{"class":97,"line":306},[1847,1851,1855,1859,1863,1868,1872,1877],{"type":30,"tag":95,"props":1848,"children":1849},{"style":185},[1850],{"type":36,"value":356},{"type":30,"tag":95,"props":1852,"children":1853},{"style":191},[1854],{"type":36,"value":194},{"type":30,"tag":95,"props":1856,"children":1857},{"style":727},[1858],{"type":36,"value":744},{"type":30,"tag":95,"props":1860,"children":1861},{"style":133},[1862],{"type":36,"value":156},{"type":30,"tag":95,"props":1864,"children":1865},{"style":185},[1866],{"type":36,"value":1867},"uuid",{"type":30,"tag":95,"props":1869,"children":1870},{"style":133},[1871],{"type":36,"value":182},{"type":30,"tag":95,"props":1873,"children":1874},{"style":197},[1875],{"type":36,"value":1876},"uuid4",{"type":30,"tag":95,"props":1878,"children":1879},{"style":133},[1880],{"type":36,"value":1881},"())\n",{"type":30,"tag":95,"props":1883,"children":1884},{"class":97,"line":314},[1885,1889,1893,1898,1902,1907,1912,1917],{"type":30,"tag":95,"props":1886,"children":1887},{"style":174},[1888],{"type":36,"value":177},{"type":30,"tag":95,"props":1890,"children":1891},{"style":133},[1892],{"type":36,"value":182},{"type":30,"tag":95,"props":1894,"children":1895},{"style":340},[1896],{"type":36,"value":1897},"orders",{"type":30,"tag":95,"props":1899,"children":1900},{"style":133},[1901],{"type":36,"value":436},{"type":30,"tag":95,"props":1903,"children":1904},{"style":340},[1905],{"type":36,"value":1906},"order_id",{"type":30,"tag":95,"props":1908,"children":1909},{"style":133},[1910],{"type":36,"value":1911},"]",{"type":30,"tag":95,"props":1913,"children":1914},{"style":191},[1915],{"type":36,"value":1916}," =",{"type":30,"tag":95,"props":1918,"children":1919},{"style":185},[1920],{"type":36,"value":1921}," order_data\n",{"type":30,"tag":95,"props":1923,"children":1924},{"class":97,"line":350},[1925,1929],{"type":30,"tag":95,"props":1926,"children":1927},{"style":121},[1928],{"type":36,"value":473},{"type":30,"tag":95,"props":1930,"children":1931},{"style":185},[1932],{"type":36,"value":478},{"type":30,"tag":95,"props":1934,"children":1935},{"class":97,"line":400},[1936],{"type":30,"tag":95,"props":1937,"children":1938},{"emptyLinePlaceholder":13},[1939],{"type":36,"value":114},{"type":30,"tag":95,"props":1941,"children":1942},{"class":97,"line":467},[1943,1947,1952],{"type":30,"tag":95,"props":1944,"children":1945},{"style":121},[1946],{"type":36,"value":1561},{"type":30,"tag":95,"props":1948,"children":1949},{"style":322},[1950],{"type":36,"value":1951}," test_create_order",{"type":30,"tag":95,"props":1953,"children":1954},{"style":133},[1955],{"type":36,"value":1571},{"type":30,"tag":95,"props":1957,"children":1958},{"class":97,"line":875},[1959,1963,1967,1971],{"type":30,"tag":95,"props":1960,"children":1961},{"style":185},[1962],{"type":36,"value":1580},{"type":30,"tag":95,"props":1964,"children":1965},{"style":191},[1966],{"type":36,"value":194},{"type":30,"tag":95,"props":1968,"children":1969},{"style":197},[1970],{"type":36,"value":1725},{"type":30,"tag":95,"props":1972,"children":1973},{"style":133},[1974],{"type":36,"value":1975},"()\n",{"type":30,"tag":95,"props":1977,"children":1978},{"class":97,"line":883},[1979,1983,1987,1992],{"type":30,"tag":95,"props":1980,"children":1981},{"style":185},[1982],{"type":36,"value":1609},{"type":30,"tag":95,"props":1984,"children":1985},{"style":191},[1986],{"type":36,"value":194},{"type":30,"tag":95,"props":1988,"children":1989},{"style":197},[1990],{"type":36,"value":1991}," MockEmailNotifier",{"type":30,"tag":95,"props":1993,"children":1994},{"style":133},[1995],{"type":36,"value":1975},{"type":30,"tag":95,"props":1997,"children":1998},{"class":97,"line":892},[1999,2004,2008,2012,2016,2020,2024,2028],{"type":30,"tag":95,"props":2000,"children":2001},{"style":185},[2002],{"type":36,"value":2003},"    service ",{"type":30,"tag":95,"props":2005,"children":2006},{"style":191},[2007],{"type":36,"value":194},{"type":30,"tag":95,"props":2009,"children":2010},{"style":197},[2011],{"type":36,"value":130},{"type":30,"tag":95,"props":2013,"children":2014},{"style":133},[2015],{"type":36,"value":156},{"type":30,"tag":95,"props":2017,"children":2018},{"style":185},[2019],{"type":36,"value":1101},{"type":30,"tag":95,"props":2021,"children":2022},{"style":133},[2023],{"type":36,"value":225},{"type":30,"tag":95,"props":2025,"children":2026},{"style":185},[2027],{"type":36,"value":952},{"type":30,"tag":95,"props":2029,"children":2030},{"style":133},[2031],{"type":36,"value":397},{"type":30,"tag":95,"props":2033,"children":2034},{"class":97,"line":908},[2035],{"type":30,"tag":95,"props":2036,"children":2037},{"emptyLinePlaceholder":13},[2038],{"type":36,"value":114},{"type":30,"tag":95,"props":2040,"children":2041},{"class":97,"line":967},[2042,2047,2051,2056,2060,2065,2070,2075,2079,2084,2088,2093,2097,2102,2107],{"type":30,"tag":95,"props":2043,"children":2044},{"style":185},[2045],{"type":36,"value":2046},"    order_id ",{"type":30,"tag":95,"props":2048,"children":2049},{"style":191},[2050],{"type":36,"value":194},{"type":30,"tag":95,"props":2052,"children":2053},{"style":185},[2054],{"type":36,"value":2055}," service",{"type":30,"tag":95,"props":2057,"children":2058},{"style":133},[2059],{"type":36,"value":182},{"type":30,"tag":95,"props":2061,"children":2062},{"style":197},[2063],{"type":36,"value":2064},"create_order",{"type":30,"tag":95,"props":2066,"children":2067},{"style":133},[2068],{"type":36,"value":2069},"({",{"type":30,"tag":95,"props":2071,"children":2072},{"style":217},[2073],{"type":36,"value":2074},"\"email\"",{"type":30,"tag":95,"props":2076,"children":2077},{"style":133},[2078],{"type":36,"value":724},{"type":30,"tag":95,"props":2080,"children":2081},{"style":217},[2082],{"type":36,"value":2083}," \"user@example.com\"",{"type":30,"tag":95,"props":2085,"children":2086},{"style":133},[2087],{"type":36,"value":225},{"type":30,"tag":95,"props":2089,"children":2090},{"style":217},[2091],{"type":36,"value":2092}," \"items\"",{"type":30,"tag":95,"props":2094,"children":2095},{"style":133},[2096],{"type":36,"value":724},{"type":30,"tag":95,"props":2098,"children":2099},{"style":133},[2100],{"type":36,"value":2101}," [",{"type":30,"tag":95,"props":2103,"children":2104},{"style":638},[2105],{"type":36,"value":2106},"...",{"type":30,"tag":95,"props":2108,"children":2109},{"style":133},[2110],{"type":36,"value":2111},"]})\n",{"type":30,"tag":95,"props":2113,"children":2114},{"class":97,"line":993},[2115],{"type":30,"tag":95,"props":2116,"children":2117},{"emptyLinePlaceholder":13},[2118],{"type":36,"value":114},{"type":30,"tag":95,"props":2120,"children":2121},{"class":97,"line":1019},[2122,2127,2132,2137,2141,2145],{"type":30,"tag":95,"props":2123,"children":2124},{"style":121},[2125],{"type":36,"value":2126},"    assert",{"type":30,"tag":95,"props":2128,"children":2129},{"style":185},[2130],{"type":36,"value":2131}," order_id ",{"type":30,"tag":95,"props":2133,"children":2134},{"style":121},[2135],{"type":36,"value":2136},"in",{"type":30,"tag":95,"props":2138,"children":2139},{"style":185},[2140],{"type":36,"value":934},{"type":30,"tag":95,"props":2142,"children":2143},{"style":133},[2144],{"type":36,"value":182},{"type":30,"tag":95,"props":2146,"children":2147},{"style":185},[2148],{"type":36,"value":2149},"orders\n",{"type":30,"tag":95,"props":2151,"children":2152},{"class":97,"line":1027},[2153,2157,2162,2166,2170,2174,2179,2183,2188],{"type":30,"tag":95,"props":2154,"children":2155},{"style":121},[2156],{"type":36,"value":2126},{"type":30,"tag":95,"props":2158,"children":2159},{"style":727},[2160],{"type":36,"value":2161}," len",{"type":30,"tag":95,"props":2163,"children":2164},{"style":133},[2165],{"type":36,"value":156},{"type":30,"tag":95,"props":2167,"children":2168},{"style":185},[2169],{"type":36,"value":1138},{"type":30,"tag":95,"props":2171,"children":2172},{"style":133},[2173],{"type":36,"value":182},{"type":30,"tag":95,"props":2175,"children":2176},{"style":185},[2177],{"type":36,"value":2178},"sent_confirmations",{"type":30,"tag":95,"props":2180,"children":2181},{"style":133},[2182],{"type":36,"value":245},{"type":30,"tag":95,"props":2184,"children":2185},{"style":191},[2186],{"type":36,"value":2187}," ==",{"type":30,"tag":95,"props":2189,"children":2190},{"style":237},[2191],{"type":36,"value":2192}," 1\n",{"type":30,"tag":2194,"props":2195,"children":2200},"cta",{"cta":2196,"href":2197,"title":2198,"type":2199},"Réserver mon diagnostic gratuit →","https://app.kamanga.fr/forms/discovery-call","Votre codebase est difficile à tester parce que les dépendances sont fortement couplées ?","call",[2201],{"type":30,"tag":38,"props":2202,"children":2203},{},[2204],{"type":36,"value":2205},"Introduire le DIP dans un codebase existant nécessite une stratégie progressive, pas un refactoring massif qui bloque toute l'équipe. En 30 minutes, on peut identifier les zones de couplage les plus problématiques et définir un plan de refactoring réaliste avec des gains mesurables.",{"type":30,"tag":54,"props":2207,"children":2208},{},[],{"type":30,"tag":58,"props":2210,"children":2212},{"id":2211},"exemple-2-typescript-interfaces-et-injection-par-framework",[2213],{"type":36,"value":2214},"Exemple 2 : TypeScript, interfaces et injection par framework",{"type":30,"tag":84,"props":2216,"children":2220},{"code":2217,"language":2218,"meta":8,"className":2219,"style":8},"// Les abstractions (interfaces TypeScript)\ninterface OrderRepository {\n    save(orderData: OrderData): Promise\u003Cstring>;\n    findById(orderId: string): Promise\u003COrder | null>;\n}\n\ninterface PaymentGateway {\n    charge(amount: number, currency: string, paymentMethod: string): Promise\u003CPaymentResult>;\n}\n\n// Le module de haut niveau\nclass OrderService {\n    constructor(\n        private readonly repository: OrderRepository,\n        private readonly payment: PaymentGateway\n    ) {}\n\n    async createPaidOrder(orderData: OrderData): Promise\u003COrder> {\n        const paymentResult = await this.payment.charge(\n            orderData.total,\n            orderData.currency,\n            orderData.paymentMethodId\n        );\n\n        if (!paymentResult.success) {\n            throw new PaymentFailedError(paymentResult.errorCode);\n        }\n\n        const orderId = await this.repository.save({\n            ...orderData,\n            paymentId: paymentResult.transactionId,\n            status: 'paid'\n        });\n\n        return this.repository.findById(orderId);\n    }\n}\n\n// Test — sans Stripe, sans base de données\ndescribe('OrderService', () => {\n    it('should create order with successful payment', async () => {\n        const mockRepository: OrderRepository = {\n            save: jest.fn().mockResolvedValue('order-123'),\n            findById: jest.fn().mockResolvedValue({ id: 'order-123', status: 'paid' })\n        };\n\n        const mockPayment: PaymentGateway = {\n            charge: jest.fn().mockResolvedValue({ success: true, transactionId: 'txn-456' })\n        };\n\n        const service = new OrderService(mockRepository, mockPayment);\n        const order = await service.createPaidOrder({ total: 1000, currency: 'EUR' });\n\n        expect(order.status).toBe('paid');\n    });\n});\n","typescript","language-typescript shiki shiki-themes catppuccin-frappe github-dark",[2221],{"type":30,"tag":91,"props":2222,"children":2223},{"__ignoreMap":8},[2224,2232,2249,2309,2375,2383,2390,2406,2495,2502,2509,2517,2532,2545,2575,2600,2612,2619,2676,2727,2748,2768,2784,2796,2803,2840,2877,2885,2892,2940,2956,2985,3002,3018,3025,3062,3070,3077,3085,3094,3130,3169,3198,3256,3342,3351,3359,3388,3473,3481,3489,3531,3616,3624,3673,3690],{"type":30,"tag":95,"props":2225,"children":2226},{"class":97,"line":98},[2227],{"type":30,"tag":95,"props":2228,"children":2229},{"style":102},[2230],{"type":36,"value":2231},"// Les abstractions (interfaces TypeScript)\n",{"type":30,"tag":95,"props":2233,"children":2234},{"class":97,"line":108},[2235,2240,2244],{"type":30,"tag":95,"props":2236,"children":2237},{"style":121},[2238],{"type":36,"value":2239},"interface",{"type":30,"tag":95,"props":2241,"children":2242},{"style":127},[2243],{"type":36,"value":669},{"type":30,"tag":95,"props":2245,"children":2246},{"style":133},[2247],{"type":36,"value":2248}," {\n",{"type":30,"tag":95,"props":2250,"children":2251},{"class":97,"line":117},[2252,2257,2261,2266,2270,2275,2279,2283,2288,2294,2299,2304],{"type":30,"tag":95,"props":2253,"children":2254},{"style":322},[2255],{"type":36,"value":2256},"    save",{"type":30,"tag":95,"props":2258,"children":2259},{"style":133},[2260],{"type":36,"value":156},{"type":30,"tag":95,"props":2262,"children":2263},{"style":207},[2264],{"type":36,"value":2265},"orderData",{"type":30,"tag":95,"props":2267,"children":2268},{"style":191},[2269],{"type":36,"value":724},{"type":30,"tag":95,"props":2271,"children":2272},{"style":127},[2273],{"type":36,"value":2274}," OrderData",{"type":30,"tag":95,"props":2276,"children":2277},{"style":133},[2278],{"type":36,"value":245},{"type":30,"tag":95,"props":2280,"children":2281},{"style":191},[2282],{"type":36,"value":724},{"type":30,"tag":95,"props":2284,"children":2285},{"style":127},[2286],{"type":36,"value":2287}," Promise",{"type":30,"tag":95,"props":2289,"children":2291},{"style":2290},"--shiki-default:#99D1DB;--shiki-dark:#E1E4E8",[2292],{"type":36,"value":2293},"\u003C",{"type":30,"tag":95,"props":2295,"children":2296},{"style":858},[2297],{"type":36,"value":2298},"string",{"type":30,"tag":95,"props":2300,"children":2301},{"style":2290},[2302],{"type":36,"value":2303},">",{"type":30,"tag":95,"props":2305,"children":2306},{"style":133},[2307],{"type":36,"value":2308},";\n",{"type":30,"tag":95,"props":2310,"children":2311},{"class":97,"line":139},[2312,2317,2321,2326,2330,2335,2339,2343,2347,2351,2356,2361,2367,2371],{"type":30,"tag":95,"props":2313,"children":2314},{"style":322},[2315],{"type":36,"value":2316},"    findById",{"type":30,"tag":95,"props":2318,"children":2319},{"style":133},[2320],{"type":36,"value":156},{"type":30,"tag":95,"props":2322,"children":2323},{"style":207},[2324],{"type":36,"value":2325},"orderId",{"type":30,"tag":95,"props":2327,"children":2328},{"style":191},[2329],{"type":36,"value":724},{"type":30,"tag":95,"props":2331,"children":2332},{"style":858},[2333],{"type":36,"value":2334}," string",{"type":30,"tag":95,"props":2336,"children":2337},{"style":133},[2338],{"type":36,"value":245},{"type":30,"tag":95,"props":2340,"children":2341},{"style":191},[2342],{"type":36,"value":724},{"type":30,"tag":95,"props":2344,"children":2345},{"style":127},[2346],{"type":36,"value":2287},{"type":30,"tag":95,"props":2348,"children":2349},{"style":2290},[2350],{"type":36,"value":2293},{"type":30,"tag":95,"props":2352,"children":2353},{"style":127},[2354],{"type":36,"value":2355},"Order",{"type":30,"tag":95,"props":2357,"children":2358},{"style":191},[2359],{"type":36,"value":2360}," |",{"type":30,"tag":95,"props":2362,"children":2364},{"style":2363},"--shiki-default:#CA9EE6;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[2365],{"type":36,"value":2366}," null",{"type":30,"tag":95,"props":2368,"children":2369},{"style":2290},[2370],{"type":36,"value":2303},{"type":30,"tag":95,"props":2372,"children":2373},{"style":133},[2374],{"type":36,"value":2308},{"type":30,"tag":95,"props":2376,"children":2377},{"class":97,"line":170},[2378],{"type":30,"tag":95,"props":2379,"children":2380},{"style":133},[2381],{"type":36,"value":2382},"}\n",{"type":30,"tag":95,"props":2384,"children":2385},{"class":97,"line":253},[2386],{"type":30,"tag":95,"props":2387,"children":2388},{"emptyLinePlaceholder":13},[2389],{"type":36,"value":114},{"type":30,"tag":95,"props":2391,"children":2392},{"class":97,"line":306},[2393,2397,2402],{"type":30,"tag":95,"props":2394,"children":2395},{"style":121},[2396],{"type":36,"value":2239},{"type":30,"tag":95,"props":2398,"children":2399},{"style":127},[2400],{"type":36,"value":2401}," PaymentGateway",{"type":30,"tag":95,"props":2403,"children":2404},{"style":133},[2405],{"type":36,"value":2248},{"type":30,"tag":95,"props":2407,"children":2408},{"class":97,"line":314},[2409,2414,2418,2423,2427,2432,2436,2441,2445,2449,2453,2458,2462,2466,2470,2474,2478,2482,2487,2491],{"type":30,"tag":95,"props":2410,"children":2411},{"style":322},[2412],{"type":36,"value":2413},"    charge",{"type":30,"tag":95,"props":2415,"children":2416},{"style":133},[2417],{"type":36,"value":156},{"type":30,"tag":95,"props":2419,"children":2420},{"style":207},[2421],{"type":36,"value":2422},"amount",{"type":30,"tag":95,"props":2424,"children":2425},{"style":191},[2426],{"type":36,"value":724},{"type":30,"tag":95,"props":2428,"children":2429},{"style":858},[2430],{"type":36,"value":2431}," number",{"type":30,"tag":95,"props":2433,"children":2434},{"style":133},[2435],{"type":36,"value":225},{"type":30,"tag":95,"props":2437,"children":2438},{"style":207},[2439],{"type":36,"value":2440}," currency",{"type":30,"tag":95,"props":2442,"children":2443},{"style":191},[2444],{"type":36,"value":724},{"type":30,"tag":95,"props":2446,"children":2447},{"style":858},[2448],{"type":36,"value":2334},{"type":30,"tag":95,"props":2450,"children":2451},{"style":133},[2452],{"type":36,"value":225},{"type":30,"tag":95,"props":2454,"children":2455},{"style":207},[2456],{"type":36,"value":2457}," paymentMethod",{"type":30,"tag":95,"props":2459,"children":2460},{"style":191},[2461],{"type":36,"value":724},{"type":30,"tag":95,"props":2463,"children":2464},{"style":858},[2465],{"type":36,"value":2334},{"type":30,"tag":95,"props":2467,"children":2468},{"style":133},[2469],{"type":36,"value":245},{"type":30,"tag":95,"props":2471,"children":2472},{"style":191},[2473],{"type":36,"value":724},{"type":30,"tag":95,"props":2475,"children":2476},{"style":127},[2477],{"type":36,"value":2287},{"type":30,"tag":95,"props":2479,"children":2480},{"style":2290},[2481],{"type":36,"value":2293},{"type":30,"tag":95,"props":2483,"children":2484},{"style":127},[2485],{"type":36,"value":2486},"PaymentResult",{"type":30,"tag":95,"props":2488,"children":2489},{"style":2290},[2490],{"type":36,"value":2303},{"type":30,"tag":95,"props":2492,"children":2493},{"style":133},[2494],{"type":36,"value":2308},{"type":30,"tag":95,"props":2496,"children":2497},{"class":97,"line":350},[2498],{"type":30,"tag":95,"props":2499,"children":2500},{"style":133},[2501],{"type":36,"value":2382},{"type":30,"tag":95,"props":2503,"children":2504},{"class":97,"line":400},[2505],{"type":30,"tag":95,"props":2506,"children":2507},{"emptyLinePlaceholder":13},[2508],{"type":36,"value":114},{"type":30,"tag":95,"props":2510,"children":2511},{"class":97,"line":467},[2512],{"type":30,"tag":95,"props":2513,"children":2514},{"style":102},[2515],{"type":36,"value":2516},"// Le module de haut niveau\n",{"type":30,"tag":95,"props":2518,"children":2519},{"class":97,"line":875},[2520,2524,2528],{"type":30,"tag":95,"props":2521,"children":2522},{"style":121},[2523],{"type":36,"value":124},{"type":30,"tag":95,"props":2525,"children":2526},{"style":127},[2527],{"type":36,"value":130},{"type":30,"tag":95,"props":2529,"children":2530},{"style":133},[2531],{"type":36,"value":2248},{"type":30,"tag":95,"props":2533,"children":2534},{"class":97,"line":883},[2535,2540],{"type":30,"tag":95,"props":2536,"children":2537},{"style":121},[2538],{"type":36,"value":2539},"    constructor",{"type":30,"tag":95,"props":2541,"children":2542},{"style":133},[2543],{"type":36,"value":2544},"(\n",{"type":30,"tag":95,"props":2546,"children":2547},{"class":97,"line":892},[2548,2553,2558,2562,2566,2570],{"type":30,"tag":95,"props":2549,"children":2550},{"style":121},[2551],{"type":36,"value":2552},"        private",{"type":30,"tag":95,"props":2554,"children":2555},{"style":121},[2556],{"type":36,"value":2557}," readonly",{"type":30,"tag":95,"props":2559,"children":2560},{"style":207},[2561],{"type":36,"value":934},{"type":30,"tag":95,"props":2563,"children":2564},{"style":191},[2565],{"type":36,"value":724},{"type":30,"tag":95,"props":2567,"children":2568},{"style":127},[2569],{"type":36,"value":669},{"type":30,"tag":95,"props":2571,"children":2572},{"style":133},[2573],{"type":36,"value":2574},",\n",{"type":30,"tag":95,"props":2576,"children":2577},{"class":97,"line":908},[2578,2582,2586,2591,2595],{"type":30,"tag":95,"props":2579,"children":2580},{"style":121},[2581],{"type":36,"value":2552},{"type":30,"tag":95,"props":2583,"children":2584},{"style":121},[2585],{"type":36,"value":2557},{"type":30,"tag":95,"props":2587,"children":2588},{"style":207},[2589],{"type":36,"value":2590}," payment",{"type":30,"tag":95,"props":2592,"children":2593},{"style":191},[2594],{"type":36,"value":724},{"type":30,"tag":95,"props":2596,"children":2597},{"style":127},[2598],{"type":36,"value":2599}," PaymentGateway\n",{"type":30,"tag":95,"props":2601,"children":2602},{"class":97,"line":967},[2603,2608],{"type":30,"tag":95,"props":2604,"children":2605},{"style":133},[2606],{"type":36,"value":2607},"    )",{"type":30,"tag":95,"props":2609,"children":2610},{"style":133},[2611],{"type":36,"value":1785},{"type":30,"tag":95,"props":2613,"children":2614},{"class":97,"line":993},[2615],{"type":30,"tag":95,"props":2616,"children":2617},{"emptyLinePlaceholder":13},[2618],{"type":36,"value":114},{"type":30,"tag":95,"props":2620,"children":2621},{"class":97,"line":1019},[2622,2627,2632,2636,2640,2644,2648,2652,2656,2660,2664,2668,2672],{"type":30,"tag":95,"props":2623,"children":2624},{"style":121},[2625],{"type":36,"value":2626},"    async",{"type":30,"tag":95,"props":2628,"children":2629},{"style":322},[2630],{"type":36,"value":2631}," createPaidOrder",{"type":30,"tag":95,"props":2633,"children":2634},{"style":133},[2635],{"type":36,"value":156},{"type":30,"tag":95,"props":2637,"children":2638},{"style":207},[2639],{"type":36,"value":2265},{"type":30,"tag":95,"props":2641,"children":2642},{"style":191},[2643],{"type":36,"value":724},{"type":30,"tag":95,"props":2645,"children":2646},{"style":127},[2647],{"type":36,"value":2274},{"type":30,"tag":95,"props":2649,"children":2650},{"style":133},[2651],{"type":36,"value":245},{"type":30,"tag":95,"props":2653,"children":2654},{"style":191},[2655],{"type":36,"value":724},{"type":30,"tag":95,"props":2657,"children":2658},{"style":127},[2659],{"type":36,"value":2287},{"type":30,"tag":95,"props":2661,"children":2662},{"style":2290},[2663],{"type":36,"value":2293},{"type":30,"tag":95,"props":2665,"children":2666},{"style":127},[2667],{"type":36,"value":2355},{"type":30,"tag":95,"props":2669,"children":2670},{"style":2290},[2671],{"type":36,"value":2303},{"type":30,"tag":95,"props":2673,"children":2674},{"style":133},[2675],{"type":36,"value":2248},{"type":30,"tag":95,"props":2677,"children":2678},{"class":97,"line":1027},[2679,2684,2689,2693,2698,2704,2709,2714,2718,2723],{"type":30,"tag":95,"props":2680,"children":2681},{"style":121},[2682],{"type":36,"value":2683},"        const",{"type":30,"tag":95,"props":2685,"children":2686},{"style":638},[2687],{"type":36,"value":2688}," paymentResult",{"type":30,"tag":95,"props":2690,"children":2691},{"style":191},[2692],{"type":36,"value":1916},{"type":30,"tag":95,"props":2694,"children":2695},{"style":121},[2696],{"type":36,"value":2697}," await",{"type":30,"tag":95,"props":2699,"children":2701},{"style":2700},"--shiki-default:#E78284;--shiki-dark:#79B8FF",[2702],{"type":36,"value":2703}," this",{"type":30,"tag":95,"props":2705,"children":2707},{"style":2706},"--shiki-default:#81C8BE;--shiki-dark:#E1E4E8",[2708],{"type":36,"value":182},{"type":30,"tag":95,"props":2710,"children":2711},{"style":185},[2712],{"type":36,"value":2713},"payment",{"type":30,"tag":95,"props":2715,"children":2716},{"style":2706},[2717],{"type":36,"value":182},{"type":30,"tag":95,"props":2719,"children":2720},{"style":322},[2721],{"type":36,"value":2722},"charge",{"type":30,"tag":95,"props":2724,"children":2725},{"style":185},[2726],{"type":36,"value":2544},{"type":30,"tag":95,"props":2728,"children":2729},{"class":97,"line":1079},[2730,2735,2739,2744],{"type":30,"tag":95,"props":2731,"children":2732},{"style":185},[2733],{"type":36,"value":2734},"            orderData",{"type":30,"tag":95,"props":2736,"children":2737},{"style":2706},[2738],{"type":36,"value":182},{"type":30,"tag":95,"props":2740,"children":2741},{"style":185},[2742],{"type":36,"value":2743},"total",{"type":30,"tag":95,"props":2745,"children":2746},{"style":133},[2747],{"type":36,"value":2574},{"type":30,"tag":95,"props":2749,"children":2750},{"class":97,"line":1124},[2751,2755,2759,2764],{"type":30,"tag":95,"props":2752,"children":2753},{"style":185},[2754],{"type":36,"value":2734},{"type":30,"tag":95,"props":2756,"children":2757},{"style":2706},[2758],{"type":36,"value":182},{"type":30,"tag":95,"props":2760,"children":2761},{"style":185},[2762],{"type":36,"value":2763},"currency",{"type":30,"tag":95,"props":2765,"children":2766},{"style":133},[2767],{"type":36,"value":2574},{"type":30,"tag":95,"props":2769,"children":2770},{"class":97,"line":1185},[2771,2775,2779],{"type":30,"tag":95,"props":2772,"children":2773},{"style":185},[2774],{"type":36,"value":2734},{"type":30,"tag":95,"props":2776,"children":2777},{"style":2706},[2778],{"type":36,"value":182},{"type":30,"tag":95,"props":2780,"children":2781},{"style":185},[2782],{"type":36,"value":2783},"paymentMethodId\n",{"type":30,"tag":95,"props":2785,"children":2786},{"class":97,"line":1197},[2787,2792],{"type":30,"tag":95,"props":2788,"children":2789},{"style":185},[2790],{"type":36,"value":2791},"        )",{"type":30,"tag":95,"props":2793,"children":2794},{"style":133},[2795],{"type":36,"value":2308},{"type":30,"tag":95,"props":2797,"children":2798},{"class":97,"line":1205},[2799],{"type":30,"tag":95,"props":2800,"children":2801},{"emptyLinePlaceholder":13},[2802],{"type":36,"value":114},{"type":30,"tag":95,"props":2804,"children":2805},{"class":97,"line":1214},[2806,2811,2816,2821,2826,2830,2835],{"type":30,"tag":95,"props":2807,"children":2808},{"style":121},[2809],{"type":36,"value":2810},"        if",{"type":30,"tag":95,"props":2812,"children":2813},{"style":185},[2814],{"type":36,"value":2815}," (",{"type":30,"tag":95,"props":2817,"children":2818},{"style":191},[2819],{"type":36,"value":2820},"!",{"type":30,"tag":95,"props":2822,"children":2823},{"style":185},[2824],{"type":36,"value":2825},"paymentResult",{"type":30,"tag":95,"props":2827,"children":2828},{"style":2706},[2829],{"type":36,"value":182},{"type":30,"tag":95,"props":2831,"children":2832},{"style":185},[2833],{"type":36,"value":2834},"success) ",{"type":30,"tag":95,"props":2836,"children":2837},{"style":133},[2838],{"type":36,"value":2839},"{\n",{"type":30,"tag":95,"props":2841,"children":2842},{"class":97,"line":1239},[2843,2848,2854,2859,2864,2868,2873],{"type":30,"tag":95,"props":2844,"children":2845},{"style":121},[2846],{"type":36,"value":2847},"            throw",{"type":30,"tag":95,"props":2849,"children":2851},{"style":2850},"--shiki-default:#CA9EE6;--shiki-default-font-weight:bold;--shiki-dark:#F97583;--shiki-dark-font-weight:inherit",[2852],{"type":36,"value":2853}," new",{"type":30,"tag":95,"props":2855,"children":2856},{"style":322},[2857],{"type":36,"value":2858}," PaymentFailedError",{"type":30,"tag":95,"props":2860,"children":2861},{"style":185},[2862],{"type":36,"value":2863},"(paymentResult",{"type":30,"tag":95,"props":2865,"children":2866},{"style":2706},[2867],{"type":36,"value":182},{"type":30,"tag":95,"props":2869,"children":2870},{"style":185},[2871],{"type":36,"value":2872},"errorCode)",{"type":30,"tag":95,"props":2874,"children":2875},{"style":133},[2876],{"type":36,"value":2308},{"type":30,"tag":95,"props":2878,"children":2879},{"class":97,"line":1291},[2880],{"type":30,"tag":95,"props":2881,"children":2882},{"style":133},[2883],{"type":36,"value":2884},"        }\n",{"type":30,"tag":95,"props":2886,"children":2887},{"class":97,"line":1341},[2888],{"type":30,"tag":95,"props":2889,"children":2890},{"emptyLinePlaceholder":13},[2891],{"type":36,"value":114},{"type":30,"tag":95,"props":2893,"children":2894},{"class":97,"line":1349},[2895,2899,2904,2908,2912,2916,2920,2924,2928,2932,2936],{"type":30,"tag":95,"props":2896,"children":2897},{"style":121},[2898],{"type":36,"value":2683},{"type":30,"tag":95,"props":2900,"children":2901},{"style":638},[2902],{"type":36,"value":2903}," orderId",{"type":30,"tag":95,"props":2905,"children":2906},{"style":191},[2907],{"type":36,"value":1916},{"type":30,"tag":95,"props":2909,"children":2910},{"style":121},[2911],{"type":36,"value":2697},{"type":30,"tag":95,"props":2913,"children":2914},{"style":2700},[2915],{"type":36,"value":2703},{"type":30,"tag":95,"props":2917,"children":2918},{"style":2706},[2919],{"type":36,"value":182},{"type":30,"tag":95,"props":2921,"children":2922},{"style":185},[2923],{"type":36,"value":1101},{"type":30,"tag":95,"props":2925,"children":2926},{"style":2706},[2927],{"type":36,"value":182},{"type":30,"tag":95,"props":2929,"children":2930},{"style":322},[2931],{"type":36,"value":383},{"type":30,"tag":95,"props":2933,"children":2934},{"style":185},[2935],{"type":36,"value":156},{"type":30,"tag":95,"props":2937,"children":2938},{"style":133},[2939],{"type":36,"value":2839},{"type":30,"tag":95,"props":2941,"children":2942},{"class":97,"line":11},[2943,2948,2952],{"type":30,"tag":95,"props":2944,"children":2945},{"style":191},[2946],{"type":36,"value":2947},"            ...",{"type":30,"tag":95,"props":2949,"children":2950},{"style":185},[2951],{"type":36,"value":2265},{"type":30,"tag":95,"props":2953,"children":2954},{"style":133},[2955],{"type":36,"value":2574},{"type":30,"tag":95,"props":2957,"children":2958},{"class":97,"line":1441},[2959,2964,2968,2972,2976,2981],{"type":30,"tag":95,"props":2960,"children":2961},{"style":185},[2962],{"type":36,"value":2963},"            paymentId",{"type":30,"tag":95,"props":2965,"children":2966},{"style":2706},[2967],{"type":36,"value":724},{"type":30,"tag":95,"props":2969,"children":2970},{"style":185},[2971],{"type":36,"value":2688},{"type":30,"tag":95,"props":2973,"children":2974},{"style":2706},[2975],{"type":36,"value":182},{"type":30,"tag":95,"props":2977,"children":2978},{"style":185},[2979],{"type":36,"value":2980},"transactionId",{"type":30,"tag":95,"props":2982,"children":2983},{"style":133},[2984],{"type":36,"value":2574},{"type":30,"tag":95,"props":2986,"children":2987},{"class":97,"line":1538},[2988,2993,2997],{"type":30,"tag":95,"props":2989,"children":2990},{"style":185},[2991],{"type":36,"value":2992},"            status",{"type":30,"tag":95,"props":2994,"children":2995},{"style":2706},[2996],{"type":36,"value":724},{"type":30,"tag":95,"props":2998,"children":2999},{"style":217},[3000],{"type":36,"value":3001}," 'paid'\n",{"type":30,"tag":95,"props":3003,"children":3004},{"class":97,"line":1546},[3005,3010,3014],{"type":30,"tag":95,"props":3006,"children":3007},{"style":133},[3008],{"type":36,"value":3009},"        }",{"type":30,"tag":95,"props":3011,"children":3012},{"style":185},[3013],{"type":36,"value":245},{"type":30,"tag":95,"props":3015,"children":3016},{"style":133},[3017],{"type":36,"value":2308},{"type":30,"tag":95,"props":3019,"children":3020},{"class":97,"line":1555},[3021],{"type":30,"tag":95,"props":3022,"children":3023},{"emptyLinePlaceholder":13},[3024],{"type":36,"value":114},{"type":30,"tag":95,"props":3026,"children":3027},{"class":97,"line":1574},[3028,3032,3036,3040,3044,3048,3053,3058],{"type":30,"tag":95,"props":3029,"children":3030},{"style":121},[3031],{"type":36,"value":473},{"type":30,"tag":95,"props":3033,"children":3034},{"style":2700},[3035],{"type":36,"value":2703},{"type":30,"tag":95,"props":3037,"children":3038},{"style":2706},[3039],{"type":36,"value":182},{"type":30,"tag":95,"props":3041,"children":3042},{"style":185},[3043],{"type":36,"value":1101},{"type":30,"tag":95,"props":3045,"children":3046},{"style":2706},[3047],{"type":36,"value":182},{"type":30,"tag":95,"props":3049,"children":3050},{"style":322},[3051],{"type":36,"value":3052},"findById",{"type":30,"tag":95,"props":3054,"children":3055},{"style":185},[3056],{"type":36,"value":3057},"(orderId)",{"type":30,"tag":95,"props":3059,"children":3060},{"style":133},[3061],{"type":36,"value":2308},{"type":30,"tag":95,"props":3063,"children":3064},{"class":97,"line":1603},[3065],{"type":30,"tag":95,"props":3066,"children":3067},{"style":133},[3068],{"type":36,"value":3069},"    }\n",{"type":30,"tag":95,"props":3071,"children":3072},{"class":97,"line":1660},[3073],{"type":30,"tag":95,"props":3074,"children":3075},{"style":133},[3076],{"type":36,"value":2382},{"type":30,"tag":95,"props":3078,"children":3080},{"class":97,"line":3079},38,[3081],{"type":30,"tag":95,"props":3082,"children":3083},{"emptyLinePlaceholder":13},[3084],{"type":36,"value":114},{"type":30,"tag":95,"props":3086,"children":3088},{"class":97,"line":3087},39,[3089],{"type":30,"tag":95,"props":3090,"children":3091},{"style":102},[3092],{"type":36,"value":3093},"// Test — sans Stripe, sans base de données\n",{"type":30,"tag":95,"props":3095,"children":3097},{"class":97,"line":3096},40,[3098,3103,3107,3112,3116,3121,3126],{"type":30,"tag":95,"props":3099,"children":3100},{"style":322},[3101],{"type":36,"value":3102},"describe",{"type":30,"tag":95,"props":3104,"children":3105},{"style":185},[3106],{"type":36,"value":156},{"type":30,"tag":95,"props":3108,"children":3109},{"style":217},[3110],{"type":36,"value":3111},"'OrderService'",{"type":30,"tag":95,"props":3113,"children":3114},{"style":133},[3115],{"type":36,"value":225},{"type":30,"tag":95,"props":3117,"children":3118},{"style":133},[3119],{"type":36,"value":3120}," ()",{"type":30,"tag":95,"props":3122,"children":3123},{"style":191},[3124],{"type":36,"value":3125}," =>",{"type":30,"tag":95,"props":3127,"children":3128},{"style":133},[3129],{"type":36,"value":2248},{"type":30,"tag":95,"props":3131,"children":3133},{"class":97,"line":3132},41,[3134,3139,3143,3148,3152,3157,3161,3165],{"type":30,"tag":95,"props":3135,"children":3136},{"style":322},[3137],{"type":36,"value":3138},"    it",{"type":30,"tag":95,"props":3140,"children":3141},{"style":185},[3142],{"type":36,"value":156},{"type":30,"tag":95,"props":3144,"children":3145},{"style":217},[3146],{"type":36,"value":3147},"'should create order with successful payment'",{"type":30,"tag":95,"props":3149,"children":3150},{"style":133},[3151],{"type":36,"value":225},{"type":30,"tag":95,"props":3153,"children":3154},{"style":121},[3155],{"type":36,"value":3156}," async",{"type":30,"tag":95,"props":3158,"children":3159},{"style":133},[3160],{"type":36,"value":3120},{"type":30,"tag":95,"props":3162,"children":3163},{"style":191},[3164],{"type":36,"value":3125},{"type":30,"tag":95,"props":3166,"children":3167},{"style":133},[3168],{"type":36,"value":2248},{"type":30,"tag":95,"props":3170,"children":3172},{"class":97,"line":3171},42,[3173,3177,3182,3186,3190,3194],{"type":30,"tag":95,"props":3174,"children":3175},{"style":121},[3176],{"type":36,"value":2683},{"type":30,"tag":95,"props":3178,"children":3179},{"style":638},[3180],{"type":36,"value":3181}," mockRepository",{"type":30,"tag":95,"props":3183,"children":3184},{"style":191},[3185],{"type":36,"value":724},{"type":30,"tag":95,"props":3187,"children":3188},{"style":127},[3189],{"type":36,"value":669},{"type":30,"tag":95,"props":3191,"children":3192},{"style":191},[3193],{"type":36,"value":1916},{"type":30,"tag":95,"props":3195,"children":3196},{"style":133},[3197],{"type":36,"value":2248},{"type":30,"tag":95,"props":3199,"children":3201},{"class":97,"line":3200},43,[3202,3207,3211,3216,3220,3225,3230,3234,3239,3243,3248,3252],{"type":30,"tag":95,"props":3203,"children":3204},{"style":185},[3205],{"type":36,"value":3206},"            save",{"type":30,"tag":95,"props":3208,"children":3209},{"style":2706},[3210],{"type":36,"value":724},{"type":30,"tag":95,"props":3212,"children":3213},{"style":185},[3214],{"type":36,"value":3215}," jest",{"type":30,"tag":95,"props":3217,"children":3218},{"style":2706},[3219],{"type":36,"value":182},{"type":30,"tag":95,"props":3221,"children":3222},{"style":322},[3223],{"type":36,"value":3224},"fn",{"type":30,"tag":95,"props":3226,"children":3227},{"style":185},[3228],{"type":36,"value":3229},"()",{"type":30,"tag":95,"props":3231,"children":3232},{"style":2706},[3233],{"type":36,"value":182},{"type":30,"tag":95,"props":3235,"children":3236},{"style":322},[3237],{"type":36,"value":3238},"mockResolvedValue",{"type":30,"tag":95,"props":3240,"children":3241},{"style":185},[3242],{"type":36,"value":156},{"type":30,"tag":95,"props":3244,"children":3245},{"style":217},[3246],{"type":36,"value":3247},"'order-123'",{"type":30,"tag":95,"props":3249,"children":3250},{"style":185},[3251],{"type":36,"value":245},{"type":30,"tag":95,"props":3253,"children":3254},{"style":133},[3255],{"type":36,"value":2574},{"type":30,"tag":95,"props":3257,"children":3259},{"class":97,"line":3258},44,[3260,3265,3269,3273,3277,3281,3285,3289,3293,3297,3301,3306,3310,3315,3319,3324,3328,3333,3338],{"type":30,"tag":95,"props":3261,"children":3262},{"style":185},[3263],{"type":36,"value":3264},"            findById",{"type":30,"tag":95,"props":3266,"children":3267},{"style":2706},[3268],{"type":36,"value":724},{"type":30,"tag":95,"props":3270,"children":3271},{"style":185},[3272],{"type":36,"value":3215},{"type":30,"tag":95,"props":3274,"children":3275},{"style":2706},[3276],{"type":36,"value":182},{"type":30,"tag":95,"props":3278,"children":3279},{"style":322},[3280],{"type":36,"value":3224},{"type":30,"tag":95,"props":3282,"children":3283},{"style":185},[3284],{"type":36,"value":3229},{"type":30,"tag":95,"props":3286,"children":3287},{"style":2706},[3288],{"type":36,"value":182},{"type":30,"tag":95,"props":3290,"children":3291},{"style":322},[3292],{"type":36,"value":3238},{"type":30,"tag":95,"props":3294,"children":3295},{"style":185},[3296],{"type":36,"value":156},{"type":30,"tag":95,"props":3298,"children":3299},{"style":133},[3300],{"type":36,"value":1517},{"type":30,"tag":95,"props":3302,"children":3303},{"style":185},[3304],{"type":36,"value":3305}," id",{"type":30,"tag":95,"props":3307,"children":3308},{"style":2706},[3309],{"type":36,"value":724},{"type":30,"tag":95,"props":3311,"children":3312},{"style":217},[3313],{"type":36,"value":3314}," 'order-123'",{"type":30,"tag":95,"props":3316,"children":3317},{"style":133},[3318],{"type":36,"value":225},{"type":30,"tag":95,"props":3320,"children":3321},{"style":185},[3322],{"type":36,"value":3323}," status",{"type":30,"tag":95,"props":3325,"children":3326},{"style":2706},[3327],{"type":36,"value":724},{"type":30,"tag":95,"props":3329,"children":3330},{"style":217},[3331],{"type":36,"value":3332}," 'paid'",{"type":30,"tag":95,"props":3334,"children":3335},{"style":133},[3336],{"type":36,"value":3337}," }",{"type":30,"tag":95,"props":3339,"children":3340},{"style":185},[3341],{"type":36,"value":397},{"type":30,"tag":95,"props":3343,"children":3345},{"class":97,"line":3344},45,[3346],{"type":30,"tag":95,"props":3347,"children":3348},{"style":133},[3349],{"type":36,"value":3350},"        };\n",{"type":30,"tag":95,"props":3352,"children":3354},{"class":97,"line":3353},46,[3355],{"type":30,"tag":95,"props":3356,"children":3357},{"emptyLinePlaceholder":13},[3358],{"type":36,"value":114},{"type":30,"tag":95,"props":3360,"children":3362},{"class":97,"line":3361},47,[3363,3367,3372,3376,3380,3384],{"type":30,"tag":95,"props":3364,"children":3365},{"style":121},[3366],{"type":36,"value":2683},{"type":30,"tag":95,"props":3368,"children":3369},{"style":638},[3370],{"type":36,"value":3371}," mockPayment",{"type":30,"tag":95,"props":3373,"children":3374},{"style":191},[3375],{"type":36,"value":724},{"type":30,"tag":95,"props":3377,"children":3378},{"style":127},[3379],{"type":36,"value":2401},{"type":30,"tag":95,"props":3381,"children":3382},{"style":191},[3383],{"type":36,"value":1916},{"type":30,"tag":95,"props":3385,"children":3386},{"style":133},[3387],{"type":36,"value":2248},{"type":30,"tag":95,"props":3389,"children":3391},{"class":97,"line":3390},48,[3392,3397,3401,3405,3409,3413,3417,3421,3425,3429,3433,3438,3442,3447,3451,3456,3460,3465,3469],{"type":30,"tag":95,"props":3393,"children":3394},{"style":185},[3395],{"type":36,"value":3396},"            charge",{"type":30,"tag":95,"props":3398,"children":3399},{"style":2706},[3400],{"type":36,"value":724},{"type":30,"tag":95,"props":3402,"children":3403},{"style":185},[3404],{"type":36,"value":3215},{"type":30,"tag":95,"props":3406,"children":3407},{"style":2706},[3408],{"type":36,"value":182},{"type":30,"tag":95,"props":3410,"children":3411},{"style":322},[3412],{"type":36,"value":3224},{"type":30,"tag":95,"props":3414,"children":3415},{"style":185},[3416],{"type":36,"value":3229},{"type":30,"tag":95,"props":3418,"children":3419},{"style":2706},[3420],{"type":36,"value":182},{"type":30,"tag":95,"props":3422,"children":3423},{"style":322},[3424],{"type":36,"value":3238},{"type":30,"tag":95,"props":3426,"children":3427},{"style":185},[3428],{"type":36,"value":156},{"type":30,"tag":95,"props":3430,"children":3431},{"style":133},[3432],{"type":36,"value":1517},{"type":30,"tag":95,"props":3434,"children":3435},{"style":185},[3436],{"type":36,"value":3437}," success",{"type":30,"tag":95,"props":3439,"children":3440},{"style":2706},[3441],{"type":36,"value":724},{"type":30,"tag":95,"props":3443,"children":3444},{"style":237},[3445],{"type":36,"value":3446}," true",{"type":30,"tag":95,"props":3448,"children":3449},{"style":133},[3450],{"type":36,"value":225},{"type":30,"tag":95,"props":3452,"children":3453},{"style":185},[3454],{"type":36,"value":3455}," transactionId",{"type":30,"tag":95,"props":3457,"children":3458},{"style":2706},[3459],{"type":36,"value":724},{"type":30,"tag":95,"props":3461,"children":3462},{"style":217},[3463],{"type":36,"value":3464}," 'txn-456'",{"type":30,"tag":95,"props":3466,"children":3467},{"style":133},[3468],{"type":36,"value":3337},{"type":30,"tag":95,"props":3470,"children":3471},{"style":185},[3472],{"type":36,"value":397},{"type":30,"tag":95,"props":3474,"children":3476},{"class":97,"line":3475},49,[3477],{"type":30,"tag":95,"props":3478,"children":3479},{"style":133},[3480],{"type":36,"value":3350},{"type":30,"tag":95,"props":3482,"children":3484},{"class":97,"line":3483},50,[3485],{"type":30,"tag":95,"props":3486,"children":3487},{"emptyLinePlaceholder":13},[3488],{"type":36,"value":114},{"type":30,"tag":95,"props":3490,"children":3492},{"class":97,"line":3491},51,[3493,3497,3501,3505,3509,3513,3518,3522,3527],{"type":30,"tag":95,"props":3494,"children":3495},{"style":121},[3496],{"type":36,"value":2683},{"type":30,"tag":95,"props":3498,"children":3499},{"style":638},[3500],{"type":36,"value":2055},{"type":30,"tag":95,"props":3502,"children":3503},{"style":191},[3504],{"type":36,"value":1916},{"type":30,"tag":95,"props":3506,"children":3507},{"style":2850},[3508],{"type":36,"value":2853},{"type":30,"tag":95,"props":3510,"children":3511},{"style":322},[3512],{"type":36,"value":130},{"type":30,"tag":95,"props":3514,"children":3515},{"style":185},[3516],{"type":36,"value":3517},"(mockRepository",{"type":30,"tag":95,"props":3519,"children":3520},{"style":133},[3521],{"type":36,"value":225},{"type":30,"tag":95,"props":3523,"children":3524},{"style":185},[3525],{"type":36,"value":3526}," mockPayment)",{"type":30,"tag":95,"props":3528,"children":3529},{"style":133},[3530],{"type":36,"value":2308},{"type":30,"tag":95,"props":3532,"children":3534},{"class":97,"line":3533},52,[3535,3539,3544,3548,3552,3556,3560,3565,3569,3573,3578,3582,3587,3591,3595,3599,3604,3608,3612],{"type":30,"tag":95,"props":3536,"children":3537},{"style":121},[3538],{"type":36,"value":2683},{"type":30,"tag":95,"props":3540,"children":3541},{"style":638},[3542],{"type":36,"value":3543}," order",{"type":30,"tag":95,"props":3545,"children":3546},{"style":191},[3547],{"type":36,"value":1916},{"type":30,"tag":95,"props":3549,"children":3550},{"style":121},[3551],{"type":36,"value":2697},{"type":30,"tag":95,"props":3553,"children":3554},{"style":185},[3555],{"type":36,"value":2055},{"type":30,"tag":95,"props":3557,"children":3558},{"style":2706},[3559],{"type":36,"value":182},{"type":30,"tag":95,"props":3561,"children":3562},{"style":322},[3563],{"type":36,"value":3564},"createPaidOrder",{"type":30,"tag":95,"props":3566,"children":3567},{"style":185},[3568],{"type":36,"value":156},{"type":30,"tag":95,"props":3570,"children":3571},{"style":133},[3572],{"type":36,"value":1517},{"type":30,"tag":95,"props":3574,"children":3575},{"style":185},[3576],{"type":36,"value":3577}," total",{"type":30,"tag":95,"props":3579,"children":3580},{"style":2706},[3581],{"type":36,"value":724},{"type":30,"tag":95,"props":3583,"children":3584},{"style":237},[3585],{"type":36,"value":3586}," 1000",{"type":30,"tag":95,"props":3588,"children":3589},{"style":133},[3590],{"type":36,"value":225},{"type":30,"tag":95,"props":3592,"children":3593},{"style":185},[3594],{"type":36,"value":2440},{"type":30,"tag":95,"props":3596,"children":3597},{"style":2706},[3598],{"type":36,"value":724},{"type":30,"tag":95,"props":3600,"children":3601},{"style":217},[3602],{"type":36,"value":3603}," 'EUR'",{"type":30,"tag":95,"props":3605,"children":3606},{"style":133},[3607],{"type":36,"value":3337},{"type":30,"tag":95,"props":3609,"children":3610},{"style":185},[3611],{"type":36,"value":245},{"type":30,"tag":95,"props":3613,"children":3614},{"style":133},[3615],{"type":36,"value":2308},{"type":30,"tag":95,"props":3617,"children":3619},{"class":97,"line":3618},53,[3620],{"type":30,"tag":95,"props":3621,"children":3622},{"emptyLinePlaceholder":13},[3623],{"type":36,"value":114},{"type":30,"tag":95,"props":3625,"children":3627},{"class":97,"line":3626},54,[3628,3633,3638,3642,3647,3651,3656,3660,3665,3669],{"type":30,"tag":95,"props":3629,"children":3630},{"style":322},[3631],{"type":36,"value":3632},"        expect",{"type":30,"tag":95,"props":3634,"children":3635},{"style":185},[3636],{"type":36,"value":3637},"(order",{"type":30,"tag":95,"props":3639,"children":3640},{"style":2706},[3641],{"type":36,"value":182},{"type":30,"tag":95,"props":3643,"children":3644},{"style":185},[3645],{"type":36,"value":3646},"status)",{"type":30,"tag":95,"props":3648,"children":3649},{"style":2706},[3650],{"type":36,"value":182},{"type":30,"tag":95,"props":3652,"children":3653},{"style":322},[3654],{"type":36,"value":3655},"toBe",{"type":30,"tag":95,"props":3657,"children":3658},{"style":185},[3659],{"type":36,"value":156},{"type":30,"tag":95,"props":3661,"children":3662},{"style":217},[3663],{"type":36,"value":3664},"'paid'",{"type":30,"tag":95,"props":3666,"children":3667},{"style":185},[3668],{"type":36,"value":245},{"type":30,"tag":95,"props":3670,"children":3671},{"style":133},[3672],{"type":36,"value":2308},{"type":30,"tag":95,"props":3674,"children":3676},{"class":97,"line":3675},55,[3677,3682,3686],{"type":30,"tag":95,"props":3678,"children":3679},{"style":133},[3680],{"type":36,"value":3681},"    }",{"type":30,"tag":95,"props":3683,"children":3684},{"style":185},[3685],{"type":36,"value":245},{"type":30,"tag":95,"props":3687,"children":3688},{"style":133},[3689],{"type":36,"value":2308},{"type":30,"tag":95,"props":3691,"children":3693},{"class":97,"line":3692},56,[3694,3699,3703],{"type":30,"tag":95,"props":3695,"children":3696},{"style":133},[3697],{"type":36,"value":3698},"}",{"type":30,"tag":95,"props":3700,"children":3701},{"style":185},[3702],{"type":36,"value":245},{"type":30,"tag":95,"props":3704,"children":3705},{"style":133},[3706],{"type":36,"value":2308},{"type":30,"tag":38,"props":3708,"children":3709},{},[3710,3715],{"type":30,"tag":483,"props":3711,"children":3712},{},[3713],{"type":36,"value":3714},"L'avantage TypeScript :",{"type":36,"value":3716}," les interfaces sont vérifiées à la compilation. Si une implémentation ne respecte pas l'interface, le compilateur rejette le code avant même l'exécution.",{"type":30,"tag":54,"props":3718,"children":3719},{},[],{"type":30,"tag":58,"props":3721,"children":3723},{"id":3722},"exemple-3-java-le-dip-avec-spring",[3724],{"type":36,"value":3725},"Exemple 3 : Java, le DIP avec Spring",{"type":30,"tag":84,"props":3727,"children":3731},{"code":3728,"language":3729,"meta":8,"className":3730,"style":8},"// L'abstraction\npublic interface NotificationService {\n    void sendOrderConfirmation(String userId, String orderId);\n    void sendShippingUpdate(String userId, String orderId, String trackingCode);\n}\n\n// Le module de haut niveau (service métier)\n@Service\npublic class OrderFulfillmentService {\n\n    private final OrderRepository orderRepository;\n    private final NotificationService notificationService;\n\n    public OrderFulfillmentService(\n            OrderRepository orderRepository,\n            NotificationService notificationService) {\n        this.orderRepository = orderRepository;\n        this.notificationService = notificationService;\n    }\n\n    public void fulfillOrder(String orderId) {\n        Order order = orderRepository.findById(orderId)\n            .orElseThrow(() -> new OrderNotFoundException(orderId));\n\n        order.setStatus(OrderStatus.FULFILLING);\n        orderRepository.save(order);\n\n        notificationService.sendOrderConfirmation(order.getUserId(), orderId);\n    }\n}\n\n// Implémentation de test\n@Service\n@Profile(\"test\")\npublic class MockNotificationService implements NotificationService {\n\n    private final List\u003CString> sentNotifications = new ArrayList\u003C>();\n\n    @Override\n    public void sendOrderConfirmation(String userId, String orderId) {\n        sentNotifications.add(\"confirmation:\" + userId + \":\" + orderId);\n    }\n}\n","java","language-java shiki shiki-themes catppuccin-frappe github-dark",[3732],{"type":30,"tag":91,"props":3733,"children":3734},{"__ignoreMap":8},[3735,3743,3765,3811,3864,3871,3878,3886,3901,3922,3929,3955,3979,3986,4002,4018,4038,4067,4095,4102,4109,4146,4187,4231,4238,4277,4306,4313,4360,4367,4374,4381,4389,4400,4425,4454,4461,4512,4519,4532,4579,4637,4644],{"type":30,"tag":95,"props":3736,"children":3737},{"class":97,"line":98},[3738],{"type":30,"tag":95,"props":3739,"children":3740},{"style":102},[3741],{"type":36,"value":3742},"// L'abstraction\n",{"type":30,"tag":95,"props":3744,"children":3745},{"class":97,"line":108},[3746,3751,3756,3761],{"type":30,"tag":95,"props":3747,"children":3748},{"style":121},[3749],{"type":36,"value":3750},"public",{"type":30,"tag":95,"props":3752,"children":3753},{"style":121},[3754],{"type":36,"value":3755}," interface",{"type":30,"tag":95,"props":3757,"children":3758},{"style":127},[3759],{"type":36,"value":3760}," NotificationService",{"type":30,"tag":95,"props":3762,"children":3763},{"style":133},[3764],{"type":36,"value":2248},{"type":30,"tag":95,"props":3766,"children":3767},{"class":97,"line":117},[3768,3773,3778,3782,3788,3793,3797,3802,3806],{"type":30,"tag":95,"props":3769,"children":3770},{"style":121},[3771],{"type":36,"value":3772},"    void",{"type":30,"tag":95,"props":3774,"children":3775},{"style":322},[3776],{"type":36,"value":3777}," sendOrderConfirmation",{"type":30,"tag":95,"props":3779,"children":3780},{"style":133},[3781],{"type":36,"value":156},{"type":30,"tag":95,"props":3783,"children":3785},{"style":3784},"--shiki-default:#CA9EE6;--shiki-dark:#E1E4E8",[3786],{"type":36,"value":3787},"String",{"type":30,"tag":95,"props":3789,"children":3790},{"style":207},[3791],{"type":36,"value":3792}," userId",{"type":30,"tag":95,"props":3794,"children":3795},{"style":133},[3796],{"type":36,"value":225},{"type":30,"tag":95,"props":3798,"children":3799},{"style":3784},[3800],{"type":36,"value":3801}," String",{"type":30,"tag":95,"props":3803,"children":3804},{"style":207},[3805],{"type":36,"value":2903},{"type":30,"tag":95,"props":3807,"children":3808},{"style":133},[3809],{"type":36,"value":3810},");\n",{"type":30,"tag":95,"props":3812,"children":3813},{"class":97,"line":139},[3814,3818,3823,3827,3831,3835,3839,3843,3847,3851,3855,3860],{"type":30,"tag":95,"props":3815,"children":3816},{"style":121},[3817],{"type":36,"value":3772},{"type":30,"tag":95,"props":3819,"children":3820},{"style":322},[3821],{"type":36,"value":3822}," sendShippingUpdate",{"type":30,"tag":95,"props":3824,"children":3825},{"style":133},[3826],{"type":36,"value":156},{"type":30,"tag":95,"props":3828,"children":3829},{"style":3784},[3830],{"type":36,"value":3787},{"type":30,"tag":95,"props":3832,"children":3833},{"style":207},[3834],{"type":36,"value":3792},{"type":30,"tag":95,"props":3836,"children":3837},{"style":133},[3838],{"type":36,"value":225},{"type":30,"tag":95,"props":3840,"children":3841},{"style":3784},[3842],{"type":36,"value":3801},{"type":30,"tag":95,"props":3844,"children":3845},{"style":207},[3846],{"type":36,"value":2903},{"type":30,"tag":95,"props":3848,"children":3849},{"style":133},[3850],{"type":36,"value":225},{"type":30,"tag":95,"props":3852,"children":3853},{"style":3784},[3854],{"type":36,"value":3801},{"type":30,"tag":95,"props":3856,"children":3857},{"style":207},[3858],{"type":36,"value":3859}," trackingCode",{"type":30,"tag":95,"props":3861,"children":3862},{"style":133},[3863],{"type":36,"value":3810},{"type":30,"tag":95,"props":3865,"children":3866},{"class":97,"line":170},[3867],{"type":30,"tag":95,"props":3868,"children":3869},{"style":133},[3870],{"type":36,"value":2382},{"type":30,"tag":95,"props":3872,"children":3873},{"class":97,"line":253},[3874],{"type":30,"tag":95,"props":3875,"children":3876},{"emptyLinePlaceholder":13},[3877],{"type":36,"value":114},{"type":30,"tag":95,"props":3879,"children":3880},{"class":97,"line":306},[3881],{"type":30,"tag":95,"props":3882,"children":3883},{"style":102},[3884],{"type":36,"value":3885},"// Le module de haut niveau (service métier)\n",{"type":30,"tag":95,"props":3887,"children":3888},{"class":97,"line":314},[3889,3895],{"type":30,"tag":95,"props":3890,"children":3892},{"style":3891},"--shiki-default:#EF9F76;--shiki-dark:#E1E4E8",[3893],{"type":36,"value":3894},"@",{"type":30,"tag":95,"props":3896,"children":3898},{"style":3897},"--shiki-default:#EF9F76;--shiki-dark:#F97583",[3899],{"type":36,"value":3900},"Service\n",{"type":30,"tag":95,"props":3902,"children":3903},{"class":97,"line":350},[3904,3908,3913,3918],{"type":30,"tag":95,"props":3905,"children":3906},{"style":121},[3907],{"type":36,"value":3750},{"type":30,"tag":95,"props":3909,"children":3910},{"style":121},[3911],{"type":36,"value":3912}," class",{"type":30,"tag":95,"props":3914,"children":3915},{"style":127},[3916],{"type":36,"value":3917}," OrderFulfillmentService",{"type":30,"tag":95,"props":3919,"children":3920},{"style":133},[3921],{"type":36,"value":2248},{"type":30,"tag":95,"props":3923,"children":3924},{"class":97,"line":400},[3925],{"type":30,"tag":95,"props":3926,"children":3927},{"emptyLinePlaceholder":13},[3928],{"type":36,"value":114},{"type":30,"tag":95,"props":3930,"children":3931},{"class":97,"line":467},[3932,3937,3942,3946,3951],{"type":30,"tag":95,"props":3933,"children":3934},{"style":121},[3935],{"type":36,"value":3936},"    private",{"type":30,"tag":95,"props":3938,"children":3939},{"style":121},[3940],{"type":36,"value":3941}," final",{"type":30,"tag":95,"props":3943,"children":3944},{"style":3784},[3945],{"type":36,"value":669},{"type":30,"tag":95,"props":3947,"children":3948},{"style":185},[3949],{"type":36,"value":3950}," orderRepository",{"type":30,"tag":95,"props":3952,"children":3953},{"style":133},[3954],{"type":36,"value":2308},{"type":30,"tag":95,"props":3956,"children":3957},{"class":97,"line":875},[3958,3962,3966,3970,3975],{"type":30,"tag":95,"props":3959,"children":3960},{"style":121},[3961],{"type":36,"value":3936},{"type":30,"tag":95,"props":3963,"children":3964},{"style":121},[3965],{"type":36,"value":3941},{"type":30,"tag":95,"props":3967,"children":3968},{"style":3784},[3969],{"type":36,"value":3760},{"type":30,"tag":95,"props":3971,"children":3972},{"style":185},[3973],{"type":36,"value":3974}," notificationService",{"type":30,"tag":95,"props":3976,"children":3977},{"style":133},[3978],{"type":36,"value":2308},{"type":30,"tag":95,"props":3980,"children":3981},{"class":97,"line":883},[3982],{"type":30,"tag":95,"props":3983,"children":3984},{"emptyLinePlaceholder":13},[3985],{"type":36,"value":114},{"type":30,"tag":95,"props":3987,"children":3988},{"class":97,"line":892},[3989,3994,3998],{"type":30,"tag":95,"props":3990,"children":3991},{"style":121},[3992],{"type":36,"value":3993},"    public",{"type":30,"tag":95,"props":3995,"children":3996},{"style":322},[3997],{"type":36,"value":3917},{"type":30,"tag":95,"props":3999,"children":4000},{"style":133},[4001],{"type":36,"value":2544},{"type":30,"tag":95,"props":4003,"children":4004},{"class":97,"line":908},[4005,4010,4014],{"type":30,"tag":95,"props":4006,"children":4007},{"style":3784},[4008],{"type":36,"value":4009},"            OrderRepository",{"type":30,"tag":95,"props":4011,"children":4012},{"style":207},[4013],{"type":36,"value":3950},{"type":30,"tag":95,"props":4015,"children":4016},{"style":133},[4017],{"type":36,"value":2574},{"type":30,"tag":95,"props":4019,"children":4020},{"class":97,"line":967},[4021,4026,4030,4034],{"type":30,"tag":95,"props":4022,"children":4023},{"style":3784},[4024],{"type":36,"value":4025},"            NotificationService",{"type":30,"tag":95,"props":4027,"children":4028},{"style":207},[4029],{"type":36,"value":3974},{"type":30,"tag":95,"props":4031,"children":4032},{"style":133},[4033],{"type":36,"value":245},{"type":30,"tag":95,"props":4035,"children":4036},{"style":133},[4037],{"type":36,"value":2248},{"type":30,"tag":95,"props":4039,"children":4040},{"class":97,"line":993},[4041,4046,4050,4055,4059,4063],{"type":30,"tag":95,"props":4042,"children":4043},{"style":2700},[4044],{"type":36,"value":4045},"        this",{"type":30,"tag":95,"props":4047,"children":4048},{"style":133},[4049],{"type":36,"value":182},{"type":30,"tag":95,"props":4051,"children":4052},{"style":185},[4053],{"type":36,"value":4054},"orderRepository ",{"type":30,"tag":95,"props":4056,"children":4057},{"style":191},[4058],{"type":36,"value":194},{"type":30,"tag":95,"props":4060,"children":4061},{"style":185},[4062],{"type":36,"value":3950},{"type":30,"tag":95,"props":4064,"children":4065},{"style":133},[4066],{"type":36,"value":2308},{"type":30,"tag":95,"props":4068,"children":4069},{"class":97,"line":1019},[4070,4074,4078,4083,4087,4091],{"type":30,"tag":95,"props":4071,"children":4072},{"style":2700},[4073],{"type":36,"value":4045},{"type":30,"tag":95,"props":4075,"children":4076},{"style":133},[4077],{"type":36,"value":182},{"type":30,"tag":95,"props":4079,"children":4080},{"style":185},[4081],{"type":36,"value":4082},"notificationService ",{"type":30,"tag":95,"props":4084,"children":4085},{"style":191},[4086],{"type":36,"value":194},{"type":30,"tag":95,"props":4088,"children":4089},{"style":185},[4090],{"type":36,"value":3974},{"type":30,"tag":95,"props":4092,"children":4093},{"style":133},[4094],{"type":36,"value":2308},{"type":30,"tag":95,"props":4096,"children":4097},{"class":97,"line":1027},[4098],{"type":30,"tag":95,"props":4099,"children":4100},{"style":133},[4101],{"type":36,"value":3069},{"type":30,"tag":95,"props":4103,"children":4104},{"class":97,"line":1079},[4105],{"type":30,"tag":95,"props":4106,"children":4107},{"emptyLinePlaceholder":13},[4108],{"type":36,"value":114},{"type":30,"tag":95,"props":4110,"children":4111},{"class":97,"line":1124},[4112,4116,4121,4126,4130,4134,4138,4142],{"type":30,"tag":95,"props":4113,"children":4114},{"style":121},[4115],{"type":36,"value":3993},{"type":30,"tag":95,"props":4117,"children":4118},{"style":121},[4119],{"type":36,"value":4120}," void",{"type":30,"tag":95,"props":4122,"children":4123},{"style":322},[4124],{"type":36,"value":4125}," fulfillOrder",{"type":30,"tag":95,"props":4127,"children":4128},{"style":133},[4129],{"type":36,"value":156},{"type":30,"tag":95,"props":4131,"children":4132},{"style":3784},[4133],{"type":36,"value":3787},{"type":30,"tag":95,"props":4135,"children":4136},{"style":207},[4137],{"type":36,"value":2903},{"type":30,"tag":95,"props":4139,"children":4140},{"style":133},[4141],{"type":36,"value":245},{"type":30,"tag":95,"props":4143,"children":4144},{"style":133},[4145],{"type":36,"value":2248},{"type":30,"tag":95,"props":4147,"children":4148},{"class":97,"line":1185},[4149,4154,4159,4163,4167,4171,4175,4179,4183],{"type":30,"tag":95,"props":4150,"children":4151},{"style":3784},[4152],{"type":36,"value":4153},"        Order",{"type":30,"tag":95,"props":4155,"children":4156},{"style":185},[4157],{"type":36,"value":4158}," order ",{"type":30,"tag":95,"props":4160,"children":4161},{"style":191},[4162],{"type":36,"value":194},{"type":30,"tag":95,"props":4164,"children":4165},{"style":185},[4166],{"type":36,"value":3950},{"type":30,"tag":95,"props":4168,"children":4169},{"style":133},[4170],{"type":36,"value":182},{"type":30,"tag":95,"props":4172,"children":4173},{"style":322},[4174],{"type":36,"value":3052},{"type":30,"tag":95,"props":4176,"children":4177},{"style":133},[4178],{"type":36,"value":156},{"type":30,"tag":95,"props":4180,"children":4181},{"style":185},[4182],{"type":36,"value":2325},{"type":30,"tag":95,"props":4184,"children":4185},{"style":133},[4186],{"type":36,"value":397},{"type":30,"tag":95,"props":4188,"children":4189},{"class":97,"line":1197},[4190,4195,4200,4205,4209,4213,4218,4222,4226],{"type":30,"tag":95,"props":4191,"children":4192},{"style":133},[4193],{"type":36,"value":4194},"            .",{"type":30,"tag":95,"props":4196,"children":4197},{"style":322},[4198],{"type":36,"value":4199},"orElseThrow",{"type":30,"tag":95,"props":4201,"children":4202},{"style":133},[4203],{"type":36,"value":4204},"(()",{"type":30,"tag":95,"props":4206,"children":4207},{"style":121},[4208],{"type":36,"value":739},{"type":30,"tag":95,"props":4210,"children":4211},{"style":121},[4212],{"type":36,"value":2853},{"type":30,"tag":95,"props":4214,"children":4215},{"style":322},[4216],{"type":36,"value":4217}," OrderNotFoundException",{"type":30,"tag":95,"props":4219,"children":4220},{"style":133},[4221],{"type":36,"value":156},{"type":30,"tag":95,"props":4223,"children":4224},{"style":185},[4225],{"type":36,"value":2325},{"type":30,"tag":95,"props":4227,"children":4228},{"style":133},[4229],{"type":36,"value":4230},"));\n",{"type":30,"tag":95,"props":4232,"children":4233},{"class":97,"line":1205},[4234],{"type":30,"tag":95,"props":4235,"children":4236},{"emptyLinePlaceholder":13},[4237],{"type":36,"value":114},{"type":30,"tag":95,"props":4239,"children":4240},{"class":97,"line":1214},[4241,4246,4250,4255,4259,4264,4268,4273],{"type":30,"tag":95,"props":4242,"children":4243},{"style":185},[4244],{"type":36,"value":4245},"        order",{"type":30,"tag":95,"props":4247,"children":4248},{"style":133},[4249],{"type":36,"value":182},{"type":30,"tag":95,"props":4251,"children":4252},{"style":322},[4253],{"type":36,"value":4254},"setStatus",{"type":30,"tag":95,"props":4256,"children":4257},{"style":133},[4258],{"type":36,"value":156},{"type":30,"tag":95,"props":4260,"children":4261},{"style":185},[4262],{"type":36,"value":4263},"OrderStatus",{"type":30,"tag":95,"props":4265,"children":4266},{"style":133},[4267],{"type":36,"value":182},{"type":30,"tag":95,"props":4269,"children":4270},{"style":185},[4271],{"type":36,"value":4272},"FULFILLING",{"type":30,"tag":95,"props":4274,"children":4275},{"style":133},[4276],{"type":36,"value":3810},{"type":30,"tag":95,"props":4278,"children":4279},{"class":97,"line":1239},[4280,4285,4289,4293,4297,4302],{"type":30,"tag":95,"props":4281,"children":4282},{"style":185},[4283],{"type":36,"value":4284},"        orderRepository",{"type":30,"tag":95,"props":4286,"children":4287},{"style":133},[4288],{"type":36,"value":182},{"type":30,"tag":95,"props":4290,"children":4291},{"style":322},[4292],{"type":36,"value":383},{"type":30,"tag":95,"props":4294,"children":4295},{"style":133},[4296],{"type":36,"value":156},{"type":30,"tag":95,"props":4298,"children":4299},{"style":185},[4300],{"type":36,"value":4301},"order",{"type":30,"tag":95,"props":4303,"children":4304},{"style":133},[4305],{"type":36,"value":3810},{"type":30,"tag":95,"props":4307,"children":4308},{"class":97,"line":1291},[4309],{"type":30,"tag":95,"props":4310,"children":4311},{"emptyLinePlaceholder":13},[4312],{"type":36,"value":114},{"type":30,"tag":95,"props":4314,"children":4315},{"class":97,"line":1341},[4316,4321,4325,4330,4334,4338,4342,4347,4352,4356],{"type":30,"tag":95,"props":4317,"children":4318},{"style":185},[4319],{"type":36,"value":4320},"        notificationService",{"type":30,"tag":95,"props":4322,"children":4323},{"style":133},[4324],{"type":36,"value":182},{"type":30,"tag":95,"props":4326,"children":4327},{"style":322},[4328],{"type":36,"value":4329},"sendOrderConfirmation",{"type":30,"tag":95,"props":4331,"children":4332},{"style":133},[4333],{"type":36,"value":156},{"type":30,"tag":95,"props":4335,"children":4336},{"style":185},[4337],{"type":36,"value":4301},{"type":30,"tag":95,"props":4339,"children":4340},{"style":133},[4341],{"type":36,"value":182},{"type":30,"tag":95,"props":4343,"children":4344},{"style":322},[4345],{"type":36,"value":4346},"getUserId",{"type":30,"tag":95,"props":4348,"children":4349},{"style":133},[4350],{"type":36,"value":4351},"(),",{"type":30,"tag":95,"props":4353,"children":4354},{"style":185},[4355],{"type":36,"value":2903},{"type":30,"tag":95,"props":4357,"children":4358},{"style":133},[4359],{"type":36,"value":3810},{"type":30,"tag":95,"props":4361,"children":4362},{"class":97,"line":1349},[4363],{"type":30,"tag":95,"props":4364,"children":4365},{"style":133},[4366],{"type":36,"value":3069},{"type":30,"tag":95,"props":4368,"children":4369},{"class":97,"line":11},[4370],{"type":30,"tag":95,"props":4371,"children":4372},{"style":133},[4373],{"type":36,"value":2382},{"type":30,"tag":95,"props":4375,"children":4376},{"class":97,"line":1441},[4377],{"type":30,"tag":95,"props":4378,"children":4379},{"emptyLinePlaceholder":13},[4380],{"type":36,"value":114},{"type":30,"tag":95,"props":4382,"children":4383},{"class":97,"line":1538},[4384],{"type":30,"tag":95,"props":4385,"children":4386},{"style":102},[4387],{"type":36,"value":4388},"// Implémentation de test\n",{"type":30,"tag":95,"props":4390,"children":4391},{"class":97,"line":1546},[4392,4396],{"type":30,"tag":95,"props":4393,"children":4394},{"style":3891},[4395],{"type":36,"value":3894},{"type":30,"tag":95,"props":4397,"children":4398},{"style":3897},[4399],{"type":36,"value":3900},{"type":30,"tag":95,"props":4401,"children":4402},{"class":97,"line":1555},[4403,4407,4412,4416,4421],{"type":30,"tag":95,"props":4404,"children":4405},{"style":3891},[4406],{"type":36,"value":3894},{"type":30,"tag":95,"props":4408,"children":4409},{"style":3897},[4410],{"type":36,"value":4411},"Profile",{"type":30,"tag":95,"props":4413,"children":4414},{"style":133},[4415],{"type":36,"value":156},{"type":30,"tag":95,"props":4417,"children":4418},{"style":217},[4419],{"type":36,"value":4420},"\"test\"",{"type":30,"tag":95,"props":4422,"children":4423},{"style":133},[4424],{"type":36,"value":397},{"type":30,"tag":95,"props":4426,"children":4427},{"class":97,"line":1574},[4428,4432,4436,4441,4446,4450],{"type":30,"tag":95,"props":4429,"children":4430},{"style":121},[4431],{"type":36,"value":3750},{"type":30,"tag":95,"props":4433,"children":4434},{"style":121},[4435],{"type":36,"value":3912},{"type":30,"tag":95,"props":4437,"children":4438},{"style":127},[4439],{"type":36,"value":4440}," MockNotificationService",{"type":30,"tag":95,"props":4442,"children":4443},{"style":121},[4444],{"type":36,"value":4445}," implements",{"type":30,"tag":95,"props":4447,"children":4448},{"style":127},[4449],{"type":36,"value":3760},{"type":30,"tag":95,"props":4451,"children":4452},{"style":133},[4453],{"type":36,"value":2248},{"type":30,"tag":95,"props":4455,"children":4456},{"class":97,"line":1603},[4457],{"type":30,"tag":95,"props":4458,"children":4459},{"emptyLinePlaceholder":13},[4460],{"type":36,"value":114},{"type":30,"tag":95,"props":4462,"children":4463},{"class":97,"line":1660},[4464,4468,4472,4477,4481,4485,4489,4494,4498,4502,4507],{"type":30,"tag":95,"props":4465,"children":4466},{"style":121},[4467],{"type":36,"value":3936},{"type":30,"tag":95,"props":4469,"children":4470},{"style":121},[4471],{"type":36,"value":3941},{"type":30,"tag":95,"props":4473,"children":4474},{"style":3784},[4475],{"type":36,"value":4476}," List",{"type":30,"tag":95,"props":4478,"children":4479},{"style":133},[4480],{"type":36,"value":2293},{"type":30,"tag":95,"props":4482,"children":4483},{"style":121},[4484],{"type":36,"value":3787},{"type":30,"tag":95,"props":4486,"children":4487},{"style":133},[4488],{"type":36,"value":2303},{"type":30,"tag":95,"props":4490,"children":4491},{"style":185},[4492],{"type":36,"value":4493}," sentNotifications ",{"type":30,"tag":95,"props":4495,"children":4496},{"style":191},[4497],{"type":36,"value":194},{"type":30,"tag":95,"props":4499,"children":4500},{"style":121},[4501],{"type":36,"value":2853},{"type":30,"tag":95,"props":4503,"children":4504},{"style":3784},[4505],{"type":36,"value":4506}," ArrayList",{"type":30,"tag":95,"props":4508,"children":4509},{"style":133},[4510],{"type":36,"value":4511},"\u003C>();\n",{"type":30,"tag":95,"props":4513,"children":4514},{"class":97,"line":3079},[4515],{"type":30,"tag":95,"props":4516,"children":4517},{"emptyLinePlaceholder":13},[4518],{"type":36,"value":114},{"type":30,"tag":95,"props":4520,"children":4521},{"class":97,"line":3087},[4522,4527],{"type":30,"tag":95,"props":4523,"children":4524},{"style":3891},[4525],{"type":36,"value":4526},"    @",{"type":30,"tag":95,"props":4528,"children":4529},{"style":3897},[4530],{"type":36,"value":4531},"Override\n",{"type":30,"tag":95,"props":4533,"children":4534},{"class":97,"line":3096},[4535,4539,4543,4547,4551,4555,4559,4563,4567,4571,4575],{"type":30,"tag":95,"props":4536,"children":4537},{"style":121},[4538],{"type":36,"value":3993},{"type":30,"tag":95,"props":4540,"children":4541},{"style":121},[4542],{"type":36,"value":4120},{"type":30,"tag":95,"props":4544,"children":4545},{"style":322},[4546],{"type":36,"value":3777},{"type":30,"tag":95,"props":4548,"children":4549},{"style":133},[4550],{"type":36,"value":156},{"type":30,"tag":95,"props":4552,"children":4553},{"style":3784},[4554],{"type":36,"value":3787},{"type":30,"tag":95,"props":4556,"children":4557},{"style":207},[4558],{"type":36,"value":3792},{"type":30,"tag":95,"props":4560,"children":4561},{"style":133},[4562],{"type":36,"value":225},{"type":30,"tag":95,"props":4564,"children":4565},{"style":3784},[4566],{"type":36,"value":3801},{"type":30,"tag":95,"props":4568,"children":4569},{"style":207},[4570],{"type":36,"value":2903},{"type":30,"tag":95,"props":4572,"children":4573},{"style":133},[4574],{"type":36,"value":245},{"type":30,"tag":95,"props":4576,"children":4577},{"style":133},[4578],{"type":36,"value":2248},{"type":30,"tag":95,"props":4580,"children":4581},{"class":97,"line":3132},[4582,4587,4591,4596,4600,4605,4610,4615,4620,4625,4629,4633],{"type":30,"tag":95,"props":4583,"children":4584},{"style":185},[4585],{"type":36,"value":4586},"        sentNotifications",{"type":30,"tag":95,"props":4588,"children":4589},{"style":133},[4590],{"type":36,"value":182},{"type":30,"tag":95,"props":4592,"children":4593},{"style":322},[4594],{"type":36,"value":4595},"add",{"type":30,"tag":95,"props":4597,"children":4598},{"style":133},[4599],{"type":36,"value":156},{"type":30,"tag":95,"props":4601,"children":4602},{"style":217},[4603],{"type":36,"value":4604},"\"confirmation:\"",{"type":30,"tag":95,"props":4606,"children":4607},{"style":191},[4608],{"type":36,"value":4609}," +",{"type":30,"tag":95,"props":4611,"children":4612},{"style":185},[4613],{"type":36,"value":4614}," userId ",{"type":30,"tag":95,"props":4616,"children":4617},{"style":191},[4618],{"type":36,"value":4619},"+",{"type":30,"tag":95,"props":4621,"children":4622},{"style":217},[4623],{"type":36,"value":4624}," \":\"",{"type":30,"tag":95,"props":4626,"children":4627},{"style":191},[4628],{"type":36,"value":4609},{"type":30,"tag":95,"props":4630,"children":4631},{"style":185},[4632],{"type":36,"value":2903},{"type":30,"tag":95,"props":4634,"children":4635},{"style":133},[4636],{"type":36,"value":3810},{"type":30,"tag":95,"props":4638,"children":4639},{"class":97,"line":3171},[4640],{"type":30,"tag":95,"props":4641,"children":4642},{"style":133},[4643],{"type":36,"value":3069},{"type":30,"tag":95,"props":4645,"children":4646},{"class":97,"line":3200},[4647],{"type":30,"tag":95,"props":4648,"children":4649},{"style":133},[4650],{"type":36,"value":2382},{"type":30,"tag":38,"props":4652,"children":4653},{},[4654,4659,4661,4667],{"type":30,"tag":483,"props":4655,"children":4656},{},[4657],{"type":36,"value":4658},"L'avantage Spring :",{"type":36,"value":4660}," ",{"type":30,"tag":91,"props":4662,"children":4664},{"className":4663},[],[4665],{"type":36,"value":4666},"@Profile(\"test\")",{"type":36,"value":4668}," permet d'utiliser automatiquement le mock en environnement de test sans modifier le code métier. Le framework gère le wiring, le code métier reste pur.",{"type":30,"tag":54,"props":4670,"children":4671},{},[],{"type":30,"tag":58,"props":4673,"children":4675},{"id":4674},"quand-appliquer-le-dip-et-quand-ne-pas-le-faire",[4676],{"type":36,"value":4677},"Quand appliquer le DIP, et quand ne pas le faire",{"type":30,"tag":38,"props":4679,"children":4680},{},[4681],{"type":30,"tag":483,"props":4682,"children":4683},{},[4684],{"type":36,"value":4685},"Appliquer le DIP :",{"type":30,"tag":489,"props":4687,"children":4688},{},[4689,4694,4699],{"type":30,"tag":493,"props":4690,"children":4691},{},[4692],{"type":36,"value":4693},"Toute dépendance vers un système externe (base de données, API tierce, service d'email, service de paiement, file de message)",{"type":30,"tag":493,"props":4695,"children":4696},{},[4697],{"type":36,"value":4698},"Toute dépendance vers une infrastructure susceptible de changer",{"type":30,"tag":493,"props":4700,"children":4701},{},[4702],{"type":36,"value":4703},"Tout code que vous voulez unit-tester sans infrastructure",{"type":30,"tag":38,"props":4705,"children":4706},{},[4707],{"type":30,"tag":483,"props":4708,"children":4709},{},[4710],{"type":36,"value":4711},"Ne pas appliquer le DIP mécaniquement :",{"type":30,"tag":489,"props":4713,"children":4714},{},[4715,4720,4725],{"type":30,"tag":493,"props":4716,"children":4717},{},[4718],{"type":36,"value":4719},"Les entités et value objects du domaine (Order, User, Money) : pas de logique d'infrastructure",{"type":30,"tag":493,"props":4721,"children":4722},{},[4723],{"type":36,"value":4724},"Les utilitaires purs (calculs mathématiques, formatage de dates) : pas d'effet de bord",{"type":30,"tag":493,"props":4726,"children":4727},{},[4728],{"type":36,"value":4729},"Les dépendances stables et peu susceptibles de changer dans des petits projets",{"type":30,"tag":38,"props":4731,"children":4732},{},[4733,4738,4740,4746],{"type":30,"tag":483,"props":4734,"children":4735},{},[4736],{"type":36,"value":4737},"Le signal",{"type":36,"value":4739}," : si écrire un test unitaire pour votre classe nécessite de démarrer une base de données, une queue de messages, ou de configurer un service externe, appliquez le DIP. Cette question est aussi centrale dans les ",{"type":30,"tag":70,"props":4741,"children":4743},{"href":4742},"/fr/dette-technique/tests-integration-legacy-pieges",[4744],{"type":36,"value":4745},"tests d'intégration sur du code legacy",{"type":36,"value":4747}," : l'absence de DIP est souvent ce qui rend ces tests si difficiles et si fragiles à mettre en place.",{"type":30,"tag":54,"props":4749,"children":4750},{},[],{"type":30,"tag":58,"props":4752,"children":4754},{"id":4753},"faq-sur-le-dependency-inversion-principle",[4755],{"type":36,"value":4756},"FAQ sur le Dependency Inversion Principle",{"type":30,"tag":4758,"props":4759,"children":4760},"details",{},[4761,4767],{"type":30,"tag":4762,"props":4763,"children":4764},"summary",{},[4765],{"type":36,"value":4766},"1. Quelle est la différence entre DIP et Dependency Injection ?",{"type":30,"tag":38,"props":4768,"children":4769},{},[4770],{"type":36,"value":4771},"Le DIP est un principe architectural : les modules doivent dépendre d'abstractions. La Dependency Injection (DI) est une technique d'implémentation du DIP : les dépendances sont fournies de l'extérieur plutôt que créées à l'intérieur. On peut respecter le DIP sans DI (ex : factory pattern). On peut utiliser la DI sans respecter le DIP (ex : injecter une classe concrète sans interface). En pratique, les deux vont généralement ensemble.",{"type":30,"tag":4758,"props":4773,"children":4774},{},[4775,4780],{"type":30,"tag":4762,"props":4776,"children":4777},{},[4778],{"type":36,"value":4779},"2. Les containers DI (Spring, .NET DI, Angular) font-ils le travail à notre place ?",{"type":30,"tag":38,"props":4781,"children":4782},{},[4783],{"type":36,"value":4784},"Ils automatisent le wiring (qui injecte quoi), mais ne créent pas les abstractions à notre place. Spring injecte les classes concrètes si vous ne créez pas d'interfaces. La discipline architecturale de créer des interfaces pour les dépendances d'infrastructure reste une décision de l'équipe. Le framework ne peut pas la prendre à votre place.",{"type":30,"tag":4758,"props":4786,"children":4787},{},[4788,4793],{"type":30,"tag":4762,"props":4789,"children":4790},{},[4791],{"type":36,"value":4792},"3. Le DIP ne crée-t-il pas trop d'abstractions ?",{"type":30,"tag":38,"props":4794,"children":4795},{},[4796],{"type":36,"value":4797},"Oui, si mal appliqué. Créer une interface pour chaque classe, même les plus stables, est du sur-engineering. La règle que Martin Fowler formule clairement : créer une abstraction quand il y a au moins 2 implémentations possibles (production + test, provider A + provider B) ou quand la dépendance est vers un système externe. \"Pas d'abstraction prématurée\" s'applique au DIP comme à tout principe.",{"type":30,"tag":4758,"props":4799,"children":4800},{},[4801,4806],{"type":30,"tag":4762,"props":4802,"children":4803},{},[4804],{"type":36,"value":4805},"4. Comment introduire le DIP progressivement dans un codebase existant ?",{"type":30,"tag":38,"props":4807,"children":4808},{},[4809,4811,4817],{"type":36,"value":4810},"Le strangler fig pattern appliqué au DIP : ne pas refactorer tout le code existant d'un coup. À chaque nouvelle fonctionnalité ou bug fix qui touche une classe avec dépendances directes, extraire l'interface et introduire l'injection. Après 6 mois de cette discipline, les zones les plus actives du codebase respectent le DIP. Les zones stables peuvent rester dans l'état existant si elles ne causent pas de problèmes. Dans un contexte de ",{"type":30,"tag":70,"props":4812,"children":4814},{"href":4813},"/fr/dette-technique/legacy-code-evaluer-risque",[4815],{"type":36,"value":4816},"code legacy fortement couplé",{"type":36,"value":4818},", cette approche progressive est souvent la seule viable sans bloquer les livraisons.",{"type":30,"tag":4758,"props":4820,"children":4821},{},[4822,4827],{"type":30,"tag":4762,"props":4823,"children":4824},{},[4825],{"type":36,"value":4826},"5. Le DIP s'applique-t-il aux frontends (React, Vue) ?",{"type":30,"tag":38,"props":4828,"children":4829},{},[4830,4832,4838,4840,4846,4848,4854],{"type":36,"value":4831},"Oui. En React : les composants ne doivent pas appeler directement ",{"type":30,"tag":91,"props":4833,"children":4835},{"className":4834},[],[4836],{"type":36,"value":4837},"fetch()",{"type":36,"value":4839}," ou ",{"type":30,"tag":91,"props":4841,"children":4843},{"className":4842},[],[4844],{"type":36,"value":4845},"axios",{"type":36,"value":4847}," : ils doivent dépendre d'une abstraction (un service, un hook custom, un context) qui peut être mockée dans les tests. ",{"type":30,"tag":91,"props":4849,"children":4851},{"className":4850},[],[4852],{"type":36,"value":4853},"useOrderService()",{"type":36,"value":4855}," hook qui cache l'implémentation HTTP, facilement mockable dans les tests. Le DIP s'applique partout où il y a des effets de bord, frontend inclus.",{"type":30,"tag":54,"props":4857,"children":4858},{},[],{"type":30,"tag":2194,"props":4860,"children":4865},{"cta":4861,"href":4862,"title":4863,"type":4864},"Faire mon auto-évaluation →","/ema","Ressource gratuite : Engineering Maturity Self-Assessment","resource",[4866],{"type":30,"tag":38,"props":4867,"children":4868},{},[4869],{"type":36,"value":4870},"L'Engineering Maturity Self-Assessment couvre le domaine Craft & Conception : évaluez votre niveau sur les principes SOLID, le couplage, et la testabilité. Obtenez un score de maturité et des recommandations concrètes en 10 minutes.",{"type":30,"tag":4872,"props":4873,"children":4874},"style",{},[4875],{"type":36,"value":4876},"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 .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":8,"searchDepth":108,"depth":108,"links":4878},[4879,4880,4881,4882,4883,4884,4885],{"id":60,"depth":108,"text":63},{"id":541,"depth":108,"text":544},{"id":607,"depth":108,"text":610},{"id":2211,"depth":108,"text":2214},{"id":3722,"depth":108,"text":3725},{"id":4674,"depth":108,"text":4677},{"id":4753,"depth":108,"text":4756},"markdown","content:fr:architecture-craft:dependency-inversion-pratique.md","content","fr/architecture-craft/dependency-inversion-pratique.md","fr/architecture-craft/dependency-inversion-pratique","md",{"_path":4893,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":4894,"description":4895,"id":908,"date":4896,"listed":13,"nocomments":7,"hidden":7,"categories":4897,"tags":4898,"--cover":4902,"readingTime":4903,"body":4907,"_type":4886,"_id":6323,"_source":4888,"_file":6324,"_stem":6325,"_extension":4891},"/fr/architecture-craft/couplage-temporel-code-asynchrone","Le couplage temporel : la dette cachée dans votre code asynchrone","Le couplage temporel est invisible dans les revues de code et catastrophique en production. Comment l'identifier, le mesurer et l'éliminer progressivement.","2026-02-06",[6],[4899,4900,18,4901],"Couplage Temporel","Asynchrone","Dette Technique","covers/articles/couplage-temporel-asynchrone.jpg",{"text":22,"minutes":4904,"time":4905,"words":4906},7.505,450300,1501,{"type":27,"children":4908,"toc":6307},[4909,4914,4919,4924,4929,4934,4937,4943,4955,4960,4970,5103,5115,5118,5124,5131,5136,5146,5151,5157,5162,5683,5689,5694,5707,5716,5719,5725,5743,5766,5776,5794,5797,5803,5809,5814,6140,6146,6159,6164,6170,6175,6192,6195,6201,6211,6223,6226,6232,6245,6266,6279,6292,6295,6303],{"type":30,"tag":31,"props":4910,"children":4912},{"id":4911},"le-couplage-temporel-la-dette-cachée-dans-votre-code-asynchrone",[4913],{"type":36,"value":4894},{"type":30,"tag":38,"props":4915,"children":4916},{},[4917],{"type":36,"value":4918},"Un vendredi soir, 22h. J'étais en astreinte pour une plateforme de paiement dans le secteur bancaire. La chaîne de traitement des virements tombait de façon intermittente depuis 48 heures : 2 à 3 fois par jour, toujours \"résolue\" par un retry manuel ou une correction en base. Le bug semblait se résoudre de lui-même.",{"type":30,"tag":38,"props":4920,"children":4921},{},[4922],{"type":36,"value":4923},"Trois heures plus tard, j'avais trouvé : une contrainte d'ordre implicite entre deux services asynchrones. L'un devait recevoir un événement \"CompteValidé\" avant de traiter un événement \"VirementInitié\". Lors des pics de charge, les deux événements arrivaient dans le désordre. Le service traitait le virement sur un compte qui n'existait pas encore dans son état local.",{"type":30,"tag":38,"props":4925,"children":4926},{},[4927],{"type":36,"value":4928},"Rien dans le code ne signalait cette contrainte. Elle était documentée dans un commentaire Confluence que personne ne lisait plus.",{"type":30,"tag":38,"props":4930,"children":4931},{},[4932],{"type":36,"value":4933},"Ce problème avait un nom : le couplage temporel. Et il était présent depuis 18 mois.",{"type":30,"tag":54,"props":4935,"children":4936},{},[],{"type":30,"tag":58,"props":4938,"children":4940},{"id":4939},"ce-quest-vraiment-le-couplage-temporel",[4941],{"type":36,"value":4942},"Ce qu'est vraiment le couplage temporel",{"type":30,"tag":38,"props":4944,"children":4945},{},[4946,4948,4953],{"type":36,"value":4947},"Le couplage temporel existe quand deux opérations ",{"type":30,"tag":483,"props":4949,"children":4950},{},[4951],{"type":36,"value":4952},"doivent se dérouler dans un ordre spécifique ou dans une fenêtre temporelle précise",{"type":36,"value":4954},", et que cette contrainte n'est pas rendue explicite dans le code.",{"type":30,"tag":38,"props":4956,"children":4957},{},[4958],{"type":36,"value":4959},"C'est une contrainte implicite : rien dans le code ne vous dit que A doit se terminer avant B. Vous le savez parce que vous avez écrit le code, ou parce que vous avez lu la documentation. Le prochain développeur ne le saura peut-être pas.",{"type":30,"tag":38,"props":4961,"children":4962},{},[4963,4968],{"type":30,"tag":483,"props":4964,"children":4965},{},[4966],{"type":36,"value":4967},"Exemple basique",{"type":36,"value":4969}," :",{"type":30,"tag":84,"props":4971,"children":4975},{"className":4972,"code":4973,"language":4974,"meta":8,"style":8},"language-javascript shiki shiki-themes catppuccin-frappe github-dark","// Couplage temporel implicite :\nawait initializeDatabase();   // doit s'exécuter en premier\nawait loadConfiguration();    // dépend de la DB\nawait startHttpServer();       // dépend de la configuration\n\n// Si initializeDatabase() échoue silencieusement,\n// loadConfiguration() peut \"fonctionner\" avec des données partielles\n// et startHttpServer() démarrera avec une configuration corrompue.\n// Le bug se manifeste plus tard, dans une feature spécifique.\n","javascript",[4976],{"type":30,"tag":91,"props":4977,"children":4978},{"__ignoreMap":8},[4979,4987,5014,5039,5064,5071,5079,5087,5095],{"type":30,"tag":95,"props":4980,"children":4981},{"class":97,"line":98},[4982],{"type":30,"tag":95,"props":4983,"children":4984},{"style":102},[4985],{"type":36,"value":4986},"// Couplage temporel implicite :\n",{"type":30,"tag":95,"props":4988,"children":4989},{"class":97,"line":108},[4990,4995,5000,5004,5009],{"type":30,"tag":95,"props":4991,"children":4992},{"style":121},[4993],{"type":36,"value":4994},"await",{"type":30,"tag":95,"props":4996,"children":4997},{"style":322},[4998],{"type":36,"value":4999}," initializeDatabase",{"type":30,"tag":95,"props":5001,"children":5002},{"style":185},[5003],{"type":36,"value":3229},{"type":30,"tag":95,"props":5005,"children":5006},{"style":133},[5007],{"type":36,"value":5008},";",{"type":30,"tag":95,"props":5010,"children":5011},{"style":102},[5012],{"type":36,"value":5013},"   // doit s'exécuter en premier\n",{"type":30,"tag":95,"props":5015,"children":5016},{"class":97,"line":117},[5017,5021,5026,5030,5034],{"type":30,"tag":95,"props":5018,"children":5019},{"style":121},[5020],{"type":36,"value":4994},{"type":30,"tag":95,"props":5022,"children":5023},{"style":322},[5024],{"type":36,"value":5025}," loadConfiguration",{"type":30,"tag":95,"props":5027,"children":5028},{"style":185},[5029],{"type":36,"value":3229},{"type":30,"tag":95,"props":5031,"children":5032},{"style":133},[5033],{"type":36,"value":5008},{"type":30,"tag":95,"props":5035,"children":5036},{"style":102},[5037],{"type":36,"value":5038},"    // dépend de la DB\n",{"type":30,"tag":95,"props":5040,"children":5041},{"class":97,"line":139},[5042,5046,5051,5055,5059],{"type":30,"tag":95,"props":5043,"children":5044},{"style":121},[5045],{"type":36,"value":4994},{"type":30,"tag":95,"props":5047,"children":5048},{"style":322},[5049],{"type":36,"value":5050}," startHttpServer",{"type":30,"tag":95,"props":5052,"children":5053},{"style":185},[5054],{"type":36,"value":3229},{"type":30,"tag":95,"props":5056,"children":5057},{"style":133},[5058],{"type":36,"value":5008},{"type":30,"tag":95,"props":5060,"children":5061},{"style":102},[5062],{"type":36,"value":5063},"       // dépend de la configuration\n",{"type":30,"tag":95,"props":5065,"children":5066},{"class":97,"line":170},[5067],{"type":30,"tag":95,"props":5068,"children":5069},{"emptyLinePlaceholder":13},[5070],{"type":36,"value":114},{"type":30,"tag":95,"props":5072,"children":5073},{"class":97,"line":253},[5074],{"type":30,"tag":95,"props":5075,"children":5076},{"style":102},[5077],{"type":36,"value":5078},"// Si initializeDatabase() échoue silencieusement,\n",{"type":30,"tag":95,"props":5080,"children":5081},{"class":97,"line":306},[5082],{"type":30,"tag":95,"props":5083,"children":5084},{"style":102},[5085],{"type":36,"value":5086},"// loadConfiguration() peut \"fonctionner\" avec des données partielles\n",{"type":30,"tag":95,"props":5088,"children":5089},{"class":97,"line":314},[5090],{"type":30,"tag":95,"props":5091,"children":5092},{"style":102},[5093],{"type":36,"value":5094},"// et startHttpServer() démarrera avec une configuration corrompue.\n",{"type":30,"tag":95,"props":5096,"children":5097},{"class":97,"line":350},[5098],{"type":30,"tag":95,"props":5099,"children":5100},{"style":102},[5101],{"type":36,"value":5102},"// Le bug se manifeste plus tard, dans une feature spécifique.\n",{"type":30,"tag":38,"props":5104,"children":5105},{},[5106,5108,5113],{"type":36,"value":5107},"Selon les données que j'observe dans mes missions, ",{"type":30,"tag":483,"props":5109,"children":5110},{},[5111],{"type":36,"value":5112},"les incidents intermittents en production représentent 40 à 60% du temps de debugging des équipes senior",{"type":36,"value":5114},", et le couplage temporel en est l'une des causes les plus fréquentes et les moins visibles.",{"type":30,"tag":54,"props":5116,"children":5117},{},[],{"type":30,"tag":58,"props":5119,"children":5121},{"id":5120},"les-3-formes-les-plus-courantes",[5122],{"type":36,"value":5123},"Les 3 formes les plus courantes",{"type":30,"tag":5125,"props":5126,"children":5128},"h3",{"id":5127},"forme-1-la-séquence-obligatoire-non-documentée",[5129],{"type":36,"value":5130},"Forme 1 : La séquence obligatoire non documentée",{"type":30,"tag":38,"props":5132,"children":5133},{},[5134],{"type":36,"value":5135},"Des opérations qui doivent être exécutées dans un ordre précis, sans que cet ordre soit rendu explicite ni protégé par du code.",{"type":30,"tag":38,"props":5137,"children":5138},{},[5139,5144],{"type":30,"tag":483,"props":5140,"children":5141},{},[5142],{"type":36,"value":5143},"Exemple",{"type":36,"value":5145}," : un service qui doit recevoir un événement \"UserCreated\" avant de pouvoir traiter un événement \"UserProfileUpdated\". Si les deux arrivent simultanément (race condition), le traitement échoue ou produit un état incohérent.",{"type":30,"tag":38,"props":5147,"children":5148},{},[5149],{"type":36,"value":5150},"Ce type d'incident coûte en moyenne 2 à 5 heures de debugging pour un développeur senior, et laisse un résidu de méfiance dans le système. L'équipe commence à \"monitorer manuellement\" ce flux, ce qui est un signal fort que la contrainte n'est pas correctement encodée.",{"type":30,"tag":5125,"props":5152,"children":5154},{"id":5153},"forme-2-les-appels-asynchrones-séquentiels-inutiles",[5155],{"type":36,"value":5156},"Forme 2 : Les appels asynchrones séquentiels inutiles",{"type":30,"tag":38,"props":5158,"children":5159},{},[5160],{"type":36,"value":5161},"Des appels asynchrones imbriqués où chaque niveau dépend du précédent, même quand ce n'est pas nécessaire. Même avec async/await, le pattern peut rester présent sous une forme différente.",{"type":30,"tag":84,"props":5163,"children":5165},{"className":4972,"code":5164,"language":4974,"meta":8,"style":8},"// ❌ Couplage temporel implicite même avec async/await\nasync function processOrder(orderId) {\n    const order = await getOrder(orderId);\n    const customer = await getCustomer(order.customerId); // dépend de order\n    const inventory = await checkInventory(order.items);  // pourrait être parallèle !\n    const payment = await processPayment(customer, order);\n    await sendConfirmation(customer, order);\n}\n\n// ✅ Parallélisation explicite pour les opérations indépendantes\nasync function processOrder(orderId) {\n    const order = await getOrder(orderId);\n    const [customer, inventory] = await Promise.all([\n        getCustomer(order.customerId),\n        checkInventory(order.items)    // pas de dépendance sur customer\n    ]);\n    const payment = await processPayment(customer, order);\n    await sendConfirmation(customer, order);\n}\n",[5166],{"type":30,"tag":91,"props":5167,"children":5168},{"__ignoreMap":8},[5169,5177,5211,5244,5291,5338,5380,5409,5416,5423,5431,5462,5493,5548,5572,5598,5610,5649,5676],{"type":30,"tag":95,"props":5170,"children":5171},{"class":97,"line":98},[5172],{"type":30,"tag":95,"props":5173,"children":5174},{"style":102},[5175],{"type":36,"value":5176},"// ❌ Couplage temporel implicite même avec async/await\n",{"type":30,"tag":95,"props":5178,"children":5179},{"class":97,"line":108},[5180,5185,5190,5195,5199,5203,5207],{"type":30,"tag":95,"props":5181,"children":5182},{"style":121},[5183],{"type":36,"value":5184},"async",{"type":30,"tag":95,"props":5186,"children":5187},{"style":121},[5188],{"type":36,"value":5189}," function",{"type":30,"tag":95,"props":5191,"children":5192},{"style":322},[5193],{"type":36,"value":5194}," processOrder",{"type":30,"tag":95,"props":5196,"children":5197},{"style":133},[5198],{"type":36,"value":156},{"type":30,"tag":95,"props":5200,"children":5201},{"style":207},[5202],{"type":36,"value":2325},{"type":30,"tag":95,"props":5204,"children":5205},{"style":133},[5206],{"type":36,"value":245},{"type":30,"tag":95,"props":5208,"children":5209},{"style":133},[5210],{"type":36,"value":2248},{"type":30,"tag":95,"props":5212,"children":5213},{"class":97,"line":117},[5214,5219,5223,5227,5231,5236,5240],{"type":30,"tag":95,"props":5215,"children":5216},{"style":121},[5217],{"type":36,"value":5218},"    const",{"type":30,"tag":95,"props":5220,"children":5221},{"style":638},[5222],{"type":36,"value":3543},{"type":30,"tag":95,"props":5224,"children":5225},{"style":191},[5226],{"type":36,"value":1916},{"type":30,"tag":95,"props":5228,"children":5229},{"style":121},[5230],{"type":36,"value":2697},{"type":30,"tag":95,"props":5232,"children":5233},{"style":322},[5234],{"type":36,"value":5235}," getOrder",{"type":30,"tag":95,"props":5237,"children":5238},{"style":185},[5239],{"type":36,"value":3057},{"type":30,"tag":95,"props":5241,"children":5242},{"style":133},[5243],{"type":36,"value":2308},{"type":30,"tag":95,"props":5245,"children":5246},{"class":97,"line":139},[5247,5251,5256,5260,5264,5269,5273,5277,5282,5286],{"type":30,"tag":95,"props":5248,"children":5249},{"style":121},[5250],{"type":36,"value":5218},{"type":30,"tag":95,"props":5252,"children":5253},{"style":638},[5254],{"type":36,"value":5255}," customer",{"type":30,"tag":95,"props":5257,"children":5258},{"style":191},[5259],{"type":36,"value":1916},{"type":30,"tag":95,"props":5261,"children":5262},{"style":121},[5263],{"type":36,"value":2697},{"type":30,"tag":95,"props":5265,"children":5266},{"style":322},[5267],{"type":36,"value":5268}," getCustomer",{"type":30,"tag":95,"props":5270,"children":5271},{"style":185},[5272],{"type":36,"value":3637},{"type":30,"tag":95,"props":5274,"children":5275},{"style":2706},[5276],{"type":36,"value":182},{"type":30,"tag":95,"props":5278,"children":5279},{"style":185},[5280],{"type":36,"value":5281},"customerId)",{"type":30,"tag":95,"props":5283,"children":5284},{"style":133},[5285],{"type":36,"value":5008},{"type":30,"tag":95,"props":5287,"children":5288},{"style":102},[5289],{"type":36,"value":5290}," // dépend de order\n",{"type":30,"tag":95,"props":5292,"children":5293},{"class":97,"line":170},[5294,5298,5303,5307,5311,5316,5320,5324,5329,5333],{"type":30,"tag":95,"props":5295,"children":5296},{"style":121},[5297],{"type":36,"value":5218},{"type":30,"tag":95,"props":5299,"children":5300},{"style":638},[5301],{"type":36,"value":5302}," inventory",{"type":30,"tag":95,"props":5304,"children":5305},{"style":191},[5306],{"type":36,"value":1916},{"type":30,"tag":95,"props":5308,"children":5309},{"style":121},[5310],{"type":36,"value":2697},{"type":30,"tag":95,"props":5312,"children":5313},{"style":322},[5314],{"type":36,"value":5315}," checkInventory",{"type":30,"tag":95,"props":5317,"children":5318},{"style":185},[5319],{"type":36,"value":3637},{"type":30,"tag":95,"props":5321,"children":5322},{"style":2706},[5323],{"type":36,"value":182},{"type":30,"tag":95,"props":5325,"children":5326},{"style":185},[5327],{"type":36,"value":5328},"items)",{"type":30,"tag":95,"props":5330,"children":5331},{"style":133},[5332],{"type":36,"value":5008},{"type":30,"tag":95,"props":5334,"children":5335},{"style":102},[5336],{"type":36,"value":5337},"  // pourrait être parallèle !\n",{"type":30,"tag":95,"props":5339,"children":5340},{"class":97,"line":253},[5341,5345,5349,5353,5357,5362,5367,5371,5376],{"type":30,"tag":95,"props":5342,"children":5343},{"style":121},[5344],{"type":36,"value":5218},{"type":30,"tag":95,"props":5346,"children":5347},{"style":638},[5348],{"type":36,"value":2590},{"type":30,"tag":95,"props":5350,"children":5351},{"style":191},[5352],{"type":36,"value":1916},{"type":30,"tag":95,"props":5354,"children":5355},{"style":121},[5356],{"type":36,"value":2697},{"type":30,"tag":95,"props":5358,"children":5359},{"style":322},[5360],{"type":36,"value":5361}," processPayment",{"type":30,"tag":95,"props":5363,"children":5364},{"style":185},[5365],{"type":36,"value":5366},"(customer",{"type":30,"tag":95,"props":5368,"children":5369},{"style":133},[5370],{"type":36,"value":225},{"type":30,"tag":95,"props":5372,"children":5373},{"style":185},[5374],{"type":36,"value":5375}," order)",{"type":30,"tag":95,"props":5377,"children":5378},{"style":133},[5379],{"type":36,"value":2308},{"type":30,"tag":95,"props":5381,"children":5382},{"class":97,"line":306},[5383,5388,5393,5397,5401,5405],{"type":30,"tag":95,"props":5384,"children":5385},{"style":121},[5386],{"type":36,"value":5387},"    await",{"type":30,"tag":95,"props":5389,"children":5390},{"style":322},[5391],{"type":36,"value":5392}," sendConfirmation",{"type":30,"tag":95,"props":5394,"children":5395},{"style":185},[5396],{"type":36,"value":5366},{"type":30,"tag":95,"props":5398,"children":5399},{"style":133},[5400],{"type":36,"value":225},{"type":30,"tag":95,"props":5402,"children":5403},{"style":185},[5404],{"type":36,"value":5375},{"type":30,"tag":95,"props":5406,"children":5407},{"style":133},[5408],{"type":36,"value":2308},{"type":30,"tag":95,"props":5410,"children":5411},{"class":97,"line":314},[5412],{"type":30,"tag":95,"props":5413,"children":5414},{"style":133},[5415],{"type":36,"value":2382},{"type":30,"tag":95,"props":5417,"children":5418},{"class":97,"line":350},[5419],{"type":30,"tag":95,"props":5420,"children":5421},{"emptyLinePlaceholder":13},[5422],{"type":36,"value":114},{"type":30,"tag":95,"props":5424,"children":5425},{"class":97,"line":400},[5426],{"type":30,"tag":95,"props":5427,"children":5428},{"style":102},[5429],{"type":36,"value":5430},"// ✅ Parallélisation explicite pour les opérations indépendantes\n",{"type":30,"tag":95,"props":5432,"children":5433},{"class":97,"line":467},[5434,5438,5442,5446,5450,5454,5458],{"type":30,"tag":95,"props":5435,"children":5436},{"style":121},[5437],{"type":36,"value":5184},{"type":30,"tag":95,"props":5439,"children":5440},{"style":121},[5441],{"type":36,"value":5189},{"type":30,"tag":95,"props":5443,"children":5444},{"style":322},[5445],{"type":36,"value":5194},{"type":30,"tag":95,"props":5447,"children":5448},{"style":133},[5449],{"type":36,"value":156},{"type":30,"tag":95,"props":5451,"children":5452},{"style":207},[5453],{"type":36,"value":2325},{"type":30,"tag":95,"props":5455,"children":5456},{"style":133},[5457],{"type":36,"value":245},{"type":30,"tag":95,"props":5459,"children":5460},{"style":133},[5461],{"type":36,"value":2248},{"type":30,"tag":95,"props":5463,"children":5464},{"class":97,"line":875},[5465,5469,5473,5477,5481,5485,5489],{"type":30,"tag":95,"props":5466,"children":5467},{"style":121},[5468],{"type":36,"value":5218},{"type":30,"tag":95,"props":5470,"children":5471},{"style":638},[5472],{"type":36,"value":3543},{"type":30,"tag":95,"props":5474,"children":5475},{"style":191},[5476],{"type":36,"value":1916},{"type":30,"tag":95,"props":5478,"children":5479},{"style":121},[5480],{"type":36,"value":2697},{"type":30,"tag":95,"props":5482,"children":5483},{"style":322},[5484],{"type":36,"value":5235},{"type":30,"tag":95,"props":5486,"children":5487},{"style":185},[5488],{"type":36,"value":3057},{"type":30,"tag":95,"props":5490,"children":5491},{"style":133},[5492],{"type":36,"value":2308},{"type":30,"tag":95,"props":5494,"children":5495},{"class":97,"line":883},[5496,5500,5504,5509,5513,5517,5521,5525,5529,5534,5538,5543],{"type":30,"tag":95,"props":5497,"children":5498},{"style":121},[5499],{"type":36,"value":5218},{"type":30,"tag":95,"props":5501,"children":5502},{"style":133},[5503],{"type":36,"value":2101},{"type":30,"tag":95,"props":5505,"children":5506},{"style":638},[5507],{"type":36,"value":5508},"customer",{"type":30,"tag":95,"props":5510,"children":5511},{"style":133},[5512],{"type":36,"value":225},{"type":30,"tag":95,"props":5514,"children":5515},{"style":638},[5516],{"type":36,"value":5302},{"type":30,"tag":95,"props":5518,"children":5519},{"style":133},[5520],{"type":36,"value":1911},{"type":30,"tag":95,"props":5522,"children":5523},{"style":191},[5524],{"type":36,"value":1916},{"type":30,"tag":95,"props":5526,"children":5527},{"style":121},[5528],{"type":36,"value":2697},{"type":30,"tag":95,"props":5530,"children":5532},{"style":5531},"--shiki-default:#E5C890;--shiki-default-font-style:italic;--shiki-dark:#79B8FF;--shiki-dark-font-style:inherit",[5533],{"type":36,"value":2287},{"type":30,"tag":95,"props":5535,"children":5536},{"style":2706},[5537],{"type":36,"value":182},{"type":30,"tag":95,"props":5539,"children":5540},{"style":322},[5541],{"type":36,"value":5542},"all",{"type":30,"tag":95,"props":5544,"children":5545},{"style":185},[5546],{"type":36,"value":5547},"([\n",{"type":30,"tag":95,"props":5549,"children":5550},{"class":97,"line":892},[5551,5556,5560,5564,5568],{"type":30,"tag":95,"props":5552,"children":5553},{"style":322},[5554],{"type":36,"value":5555},"        getCustomer",{"type":30,"tag":95,"props":5557,"children":5558},{"style":185},[5559],{"type":36,"value":3637},{"type":30,"tag":95,"props":5561,"children":5562},{"style":2706},[5563],{"type":36,"value":182},{"type":30,"tag":95,"props":5565,"children":5566},{"style":185},[5567],{"type":36,"value":5281},{"type":30,"tag":95,"props":5569,"children":5570},{"style":133},[5571],{"type":36,"value":2574},{"type":30,"tag":95,"props":5573,"children":5574},{"class":97,"line":908},[5575,5580,5584,5588,5593],{"type":30,"tag":95,"props":5576,"children":5577},{"style":322},[5578],{"type":36,"value":5579},"        checkInventory",{"type":30,"tag":95,"props":5581,"children":5582},{"style":185},[5583],{"type":36,"value":3637},{"type":30,"tag":95,"props":5585,"children":5586},{"style":2706},[5587],{"type":36,"value":182},{"type":30,"tag":95,"props":5589,"children":5590},{"style":185},[5591],{"type":36,"value":5592},"items)    ",{"type":30,"tag":95,"props":5594,"children":5595},{"style":102},[5596],{"type":36,"value":5597},"// pas de dépendance sur customer\n",{"type":30,"tag":95,"props":5599,"children":5600},{"class":97,"line":967},[5601,5606],{"type":30,"tag":95,"props":5602,"children":5603},{"style":185},[5604],{"type":36,"value":5605},"    ])",{"type":30,"tag":95,"props":5607,"children":5608},{"style":133},[5609],{"type":36,"value":2308},{"type":30,"tag":95,"props":5611,"children":5612},{"class":97,"line":993},[5613,5617,5621,5625,5629,5633,5637,5641,5645],{"type":30,"tag":95,"props":5614,"children":5615},{"style":121},[5616],{"type":36,"value":5218},{"type":30,"tag":95,"props":5618,"children":5619},{"style":638},[5620],{"type":36,"value":2590},{"type":30,"tag":95,"props":5622,"children":5623},{"style":191},[5624],{"type":36,"value":1916},{"type":30,"tag":95,"props":5626,"children":5627},{"style":121},[5628],{"type":36,"value":2697},{"type":30,"tag":95,"props":5630,"children":5631},{"style":322},[5632],{"type":36,"value":5361},{"type":30,"tag":95,"props":5634,"children":5635},{"style":185},[5636],{"type":36,"value":5366},{"type":30,"tag":95,"props":5638,"children":5639},{"style":133},[5640],{"type":36,"value":225},{"type":30,"tag":95,"props":5642,"children":5643},{"style":185},[5644],{"type":36,"value":5375},{"type":30,"tag":95,"props":5646,"children":5647},{"style":133},[5648],{"type":36,"value":2308},{"type":30,"tag":95,"props":5650,"children":5651},{"class":97,"line":1019},[5652,5656,5660,5664,5668,5672],{"type":30,"tag":95,"props":5653,"children":5654},{"style":121},[5655],{"type":36,"value":5387},{"type":30,"tag":95,"props":5657,"children":5658},{"style":322},[5659],{"type":36,"value":5392},{"type":30,"tag":95,"props":5661,"children":5662},{"style":185},[5663],{"type":36,"value":5366},{"type":30,"tag":95,"props":5665,"children":5666},{"style":133},[5667],{"type":36,"value":225},{"type":30,"tag":95,"props":5669,"children":5670},{"style":185},[5671],{"type":36,"value":5375},{"type":30,"tag":95,"props":5673,"children":5674},{"style":133},[5675],{"type":36,"value":2308},{"type":30,"tag":95,"props":5677,"children":5678},{"class":97,"line":1027},[5679],{"type":30,"tag":95,"props":5680,"children":5681},{"style":133},[5682],{"type":36,"value":2382},{"type":30,"tag":5125,"props":5684,"children":5686},{"id":5685},"forme-3-les-timeouts-implicites-ou-absents",[5687],{"type":36,"value":5688},"Forme 3 : Les timeouts implicites ou absents",{"type":30,"tag":38,"props":5690,"children":5691},{},[5692],{"type":36,"value":5693},"Des appels vers des services externes (API, base de données, message broker) sans timeout défini. Le comportement par défaut de la plupart des clients HTTP est d'attendre indéfiniment, ou avec un timeout système de plusieurs minutes.",{"type":30,"tag":38,"props":5695,"children":5696},{},[5697,5699,5705],{"type":36,"value":5698},"Ce qui se passe ensuite est prévisible : un service tiers commence à répondre lentement. Votre service attend. Les connexions s'accumulent. Le pool de connexions s'épuise. Votre service commence à rejeter des requêtes. La cascade se propage vers les services upstream. C'est précisément le scénario que les ",{"type":30,"tag":70,"props":5700,"children":5702},{"href":5701},"/fr/architecture-craft/patterns-resilience-circuit-breaker-retry",[5703],{"type":36,"value":5704},"patterns de résilience comme le circuit breaker et le retry",{"type":36,"value":5706}," sont conçus pour prévenir.",{"type":30,"tag":2194,"props":5708,"children":5710},{"cta":2196,"href":2197,"title":5709,"type":2199},"Vous avez des incidents de prod intermittents dont vous n'arrivez pas à identifier la cause ?",[5711],{"type":30,"tag":38,"props":5712,"children":5713},{},[5714],{"type":36,"value":5715},"Les incidents intermittents en production sont souvent la signature d'un couplage temporel mal géré. Je l'ai vu se répéter dans des organisations aussi différentes que BNP Paribas et des scale-ups de 20 développeurs. En 30 minutes, on peut identifier les patterns à risque dans votre architecture et définir les corrections prioritaires.",{"type":30,"tag":54,"props":5717,"children":5718},{},[],{"type":30,"tag":58,"props":5720,"children":5722},{"id":5721},"comment-le-détecter-dans-votre-code",[5723],{"type":36,"value":5724},"Comment le détecter dans votre code",{"type":30,"tag":38,"props":5726,"children":5727},{},[5728,5733,5735,5741],{"type":30,"tag":483,"props":5729,"children":5730},{},[5731],{"type":36,"value":5732},"Dans le code",{"type":36,"value":5734},", je cherche ces patterns comme indicateurs potentiels, et les ",{"type":30,"tag":70,"props":5736,"children":5738},{"href":5737},"/fr/dette-technique/outils-analyse-statique-2026",[5739],{"type":36,"value":5740},"outils d'analyse statique",{"type":36,"value":5742}," permettent d'automatiser une partie de cette détection à grande échelle :",{"type":30,"tag":489,"props":5744,"children":5745},{},[5746,5751,5756,5761],{"type":30,"tag":493,"props":5747,"children":5748},{},[5749],{"type":36,"value":5750},"Appels asynchrones séquentiels qui pourraient être parallèles : vérifiez si chacun dépend vraiment du précédent",{"type":30,"tag":493,"props":5752,"children":5753},{},[5754],{"type":36,"value":5755},"Absence de timeout sur les appels vers des services externes",{"type":30,"tag":493,"props":5757,"children":5758},{},[5759],{"type":36,"value":5760},"Commentaires du type \"// doit être appelé après X\" : la contrainte est documentée mais non protégée par du code",{"type":30,"tag":493,"props":5762,"children":5763},{},[5764],{"type":36,"value":5765},"Messages ou événements qui doivent être traités dans un ordre précis sans mécanisme de garantie",{"type":30,"tag":38,"props":5767,"children":5768},{},[5769,5774],{"type":30,"tag":483,"props":5770,"children":5771},{},[5772],{"type":36,"value":5773},"En production",{"type":36,"value":5775},", les signaux sont différents :",{"type":30,"tag":489,"props":5777,"children":5778},{},[5779,5784,5789],{"type":30,"tag":493,"props":5780,"children":5781},{},[5782],{"type":36,"value":5783},"Incidents intermittents qui se résolvent avec un retry → indicateur fort de race condition ou de contrainte temporelle non respectée",{"type":30,"tag":493,"props":5785,"children":5786},{},[5787],{"type":36,"value":5788},"Latence qui augmente linéairement avec la charge → indicateur d'opérations séquentielles qui pourraient être parallèles",{"type":30,"tag":493,"props":5790,"children":5791},{},[5792],{"type":36,"value":5793},"Timeouts qui se propagent en cascade → indicateur d'absence de timeout et de circuit breaker",{"type":30,"tag":54,"props":5795,"children":5796},{},[],{"type":30,"tag":58,"props":5798,"children":5800},{"id":5799},"les-3-corrections-prioritaires",[5801],{"type":36,"value":5802},"Les 3 corrections prioritaires",{"type":30,"tag":5125,"props":5804,"children":5806},{"id":5805},"idempotence-opérations-retriables-sans-effet-de-bord",[5807],{"type":36,"value":5808},"Idempotence : opérations retriables sans effet de bord",{"type":30,"tag":38,"props":5810,"children":5811},{},[5812],{"type":36,"value":5813},"Chaque opération qui peut échouer et être retentée doit être idempotente : la ré-exécuter avec le même input produit le même résultat, sans effets de bord additionnels.",{"type":30,"tag":84,"props":5815,"children":5817},{"className":3730,"code":5816,"language":3729,"meta":8,"style":8},"// ❌ Non-idempotent : chaque appel crée un enregistrement\npublic void createOrder(OrderCommand cmd) {\n    Order order = new Order(cmd);\n    orderRepository.save(order);  // crée un nouveau record à chaque appel\n}\n\n// ✅ Idempotent : même résultat quel que soit le nombre d'appels\npublic void createOrder(OrderCommand cmd) {\n    if (orderRepository.existsById(cmd.getIdempotencyKey())) {\n        return;  // déjà traité\n    }\n    Order order = new Order(cmd);\n    orderRepository.save(order);\n}\n",[5818],{"type":30,"tag":91,"props":5819,"children":5820},{"__ignoreMap":8},[5821,5829,5867,5905,5939,5946,5953,5961,5996,6048,6064,6071,6106,6133],{"type":30,"tag":95,"props":5822,"children":5823},{"class":97,"line":98},[5824],{"type":30,"tag":95,"props":5825,"children":5826},{"style":102},[5827],{"type":36,"value":5828},"// ❌ Non-idempotent : chaque appel crée un enregistrement\n",{"type":30,"tag":95,"props":5830,"children":5831},{"class":97,"line":108},[5832,5836,5840,5845,5849,5854,5859,5863],{"type":30,"tag":95,"props":5833,"children":5834},{"style":121},[5835],{"type":36,"value":3750},{"type":30,"tag":95,"props":5837,"children":5838},{"style":121},[5839],{"type":36,"value":4120},{"type":30,"tag":95,"props":5841,"children":5842},{"style":322},[5843],{"type":36,"value":5844}," createOrder",{"type":30,"tag":95,"props":5846,"children":5847},{"style":133},[5848],{"type":36,"value":156},{"type":30,"tag":95,"props":5850,"children":5851},{"style":3784},[5852],{"type":36,"value":5853},"OrderCommand",{"type":30,"tag":95,"props":5855,"children":5856},{"style":185},[5857],{"type":36,"value":5858}," cmd",{"type":30,"tag":95,"props":5860,"children":5861},{"style":133},[5862],{"type":36,"value":245},{"type":30,"tag":95,"props":5864,"children":5865},{"style":133},[5866],{"type":36,"value":2248},{"type":30,"tag":95,"props":5868,"children":5869},{"class":97,"line":117},[5870,5875,5879,5883,5887,5892,5896,5901],{"type":30,"tag":95,"props":5871,"children":5872},{"style":3784},[5873],{"type":36,"value":5874},"    Order",{"type":30,"tag":95,"props":5876,"children":5877},{"style":185},[5878],{"type":36,"value":4158},{"type":30,"tag":95,"props":5880,"children":5881},{"style":191},[5882],{"type":36,"value":194},{"type":30,"tag":95,"props":5884,"children":5885},{"style":121},[5886],{"type":36,"value":2853},{"type":30,"tag":95,"props":5888,"children":5889},{"style":322},[5890],{"type":36,"value":5891}," Order",{"type":30,"tag":95,"props":5893,"children":5894},{"style":133},[5895],{"type":36,"value":156},{"type":30,"tag":95,"props":5897,"children":5898},{"style":185},[5899],{"type":36,"value":5900},"cmd",{"type":30,"tag":95,"props":5902,"children":5903},{"style":133},[5904],{"type":36,"value":3810},{"type":30,"tag":95,"props":5906,"children":5907},{"class":97,"line":139},[5908,5913,5917,5921,5925,5929,5934],{"type":30,"tag":95,"props":5909,"children":5910},{"style":185},[5911],{"type":36,"value":5912},"    orderRepository",{"type":30,"tag":95,"props":5914,"children":5915},{"style":133},[5916],{"type":36,"value":182},{"type":30,"tag":95,"props":5918,"children":5919},{"style":322},[5920],{"type":36,"value":383},{"type":30,"tag":95,"props":5922,"children":5923},{"style":133},[5924],{"type":36,"value":156},{"type":30,"tag":95,"props":5926,"children":5927},{"style":185},[5928],{"type":36,"value":4301},{"type":30,"tag":95,"props":5930,"children":5931},{"style":133},[5932],{"type":36,"value":5933},");",{"type":30,"tag":95,"props":5935,"children":5936},{"style":102},[5937],{"type":36,"value":5938},"  // crée un nouveau record à chaque appel\n",{"type":30,"tag":95,"props":5940,"children":5941},{"class":97,"line":170},[5942],{"type":30,"tag":95,"props":5943,"children":5944},{"style":133},[5945],{"type":36,"value":2382},{"type":30,"tag":95,"props":5947,"children":5948},{"class":97,"line":253},[5949],{"type":30,"tag":95,"props":5950,"children":5951},{"emptyLinePlaceholder":13},[5952],{"type":36,"value":114},{"type":30,"tag":95,"props":5954,"children":5955},{"class":97,"line":306},[5956],{"type":30,"tag":95,"props":5957,"children":5958},{"style":102},[5959],{"type":36,"value":5960},"// ✅ Idempotent : même résultat quel que soit le nombre d'appels\n",{"type":30,"tag":95,"props":5962,"children":5963},{"class":97,"line":314},[5964,5968,5972,5976,5980,5984,5988,5992],{"type":30,"tag":95,"props":5965,"children":5966},{"style":121},[5967],{"type":36,"value":3750},{"type":30,"tag":95,"props":5969,"children":5970},{"style":121},[5971],{"type":36,"value":4120},{"type":30,"tag":95,"props":5973,"children":5974},{"style":322},[5975],{"type":36,"value":5844},{"type":30,"tag":95,"props":5977,"children":5978},{"style":133},[5979],{"type":36,"value":156},{"type":30,"tag":95,"props":5981,"children":5982},{"style":3784},[5983],{"type":36,"value":5853},{"type":30,"tag":95,"props":5985,"children":5986},{"style":185},[5987],{"type":36,"value":5858},{"type":30,"tag":95,"props":5989,"children":5990},{"style":133},[5991],{"type":36,"value":245},{"type":30,"tag":95,"props":5993,"children":5994},{"style":133},[5995],{"type":36,"value":2248},{"type":30,"tag":95,"props":5997,"children":5998},{"class":97,"line":350},[5999,6004,6008,6013,6017,6022,6026,6030,6034,6039,6044],{"type":30,"tag":95,"props":6000,"children":6001},{"style":121},[6002],{"type":36,"value":6003},"    if",{"type":30,"tag":95,"props":6005,"children":6006},{"style":133},[6007],{"type":36,"value":2815},{"type":30,"tag":95,"props":6009,"children":6010},{"style":185},[6011],{"type":36,"value":6012},"orderRepository",{"type":30,"tag":95,"props":6014,"children":6015},{"style":133},[6016],{"type":36,"value":182},{"type":30,"tag":95,"props":6018,"children":6019},{"style":322},[6020],{"type":36,"value":6021},"existsById",{"type":30,"tag":95,"props":6023,"children":6024},{"style":133},[6025],{"type":36,"value":156},{"type":30,"tag":95,"props":6027,"children":6028},{"style":185},[6029],{"type":36,"value":5900},{"type":30,"tag":95,"props":6031,"children":6032},{"style":133},[6033],{"type":36,"value":182},{"type":30,"tag":95,"props":6035,"children":6036},{"style":322},[6037],{"type":36,"value":6038},"getIdempotencyKey",{"type":30,"tag":95,"props":6040,"children":6041},{"style":133},[6042],{"type":36,"value":6043},"()))",{"type":30,"tag":95,"props":6045,"children":6046},{"style":133},[6047],{"type":36,"value":2248},{"type":30,"tag":95,"props":6049,"children":6050},{"class":97,"line":400},[6051,6055,6059],{"type":30,"tag":95,"props":6052,"children":6053},{"style":121},[6054],{"type":36,"value":473},{"type":30,"tag":95,"props":6056,"children":6057},{"style":133},[6058],{"type":36,"value":5008},{"type":30,"tag":95,"props":6060,"children":6061},{"style":102},[6062],{"type":36,"value":6063},"  // déjà traité\n",{"type":30,"tag":95,"props":6065,"children":6066},{"class":97,"line":467},[6067],{"type":30,"tag":95,"props":6068,"children":6069},{"style":133},[6070],{"type":36,"value":3069},{"type":30,"tag":95,"props":6072,"children":6073},{"class":97,"line":875},[6074,6078,6082,6086,6090,6094,6098,6102],{"type":30,"tag":95,"props":6075,"children":6076},{"style":3784},[6077],{"type":36,"value":5874},{"type":30,"tag":95,"props":6079,"children":6080},{"style":185},[6081],{"type":36,"value":4158},{"type":30,"tag":95,"props":6083,"children":6084},{"style":191},[6085],{"type":36,"value":194},{"type":30,"tag":95,"props":6087,"children":6088},{"style":121},[6089],{"type":36,"value":2853},{"type":30,"tag":95,"props":6091,"children":6092},{"style":322},[6093],{"type":36,"value":5891},{"type":30,"tag":95,"props":6095,"children":6096},{"style":133},[6097],{"type":36,"value":156},{"type":30,"tag":95,"props":6099,"children":6100},{"style":185},[6101],{"type":36,"value":5900},{"type":30,"tag":95,"props":6103,"children":6104},{"style":133},[6105],{"type":36,"value":3810},{"type":30,"tag":95,"props":6107,"children":6108},{"class":97,"line":883},[6109,6113,6117,6121,6125,6129],{"type":30,"tag":95,"props":6110,"children":6111},{"style":185},[6112],{"type":36,"value":5912},{"type":30,"tag":95,"props":6114,"children":6115},{"style":133},[6116],{"type":36,"value":182},{"type":30,"tag":95,"props":6118,"children":6119},{"style":322},[6120],{"type":36,"value":383},{"type":30,"tag":95,"props":6122,"children":6123},{"style":133},[6124],{"type":36,"value":156},{"type":30,"tag":95,"props":6126,"children":6127},{"style":185},[6128],{"type":36,"value":4301},{"type":30,"tag":95,"props":6130,"children":6131},{"style":133},[6132],{"type":36,"value":3810},{"type":30,"tag":95,"props":6134,"children":6135},{"class":97,"line":892},[6136],{"type":30,"tag":95,"props":6137,"children":6138},{"style":133},[6139],{"type":36,"value":2382},{"type":30,"tag":5125,"props":6141,"children":6143},{"id":6142},"sagas-orchestration-explicite-des-séquences-longues",[6144],{"type":36,"value":6145},"Sagas : orchestration explicite des séquences longues",{"type":30,"tag":38,"props":6147,"children":6148},{},[6149,6151,6157],{"type":36,"value":6150},"Pour les transactions distribuées qui s'étendent sur plusieurs services, le pattern Saga, décrit par Vernon Vaughn dans \"Implementing Domain-Driven Design\", rend la séquence explicite et gère les compensations en cas d'échec partiel. Réduire ce couplage est aussi un objectif à inscrire dans un ",{"type":30,"tag":70,"props":6152,"children":6154},{"href":6153},"/fr/dette-technique/programme-refactoring-approuve-business",[6155],{"type":36,"value":6156},"programme de refactoring validé par le business",{"type":36,"value":6158},", pour que ces améliorations soient planifiées et financées correctement.",{"type":30,"tag":38,"props":6160,"children":6161},{},[6162],{"type":36,"value":6163},"Chorégraphié ou orchestré, le pattern Saga transforme une contrainte implicite d'ordre en protocole explicite avec gestion des cas d'échec.",{"type":30,"tag":5125,"props":6165,"children":6167},{"id":6166},"timeouts-explicites-sur-tous-les-appels-externes",[6168],{"type":36,"value":6169},"Timeouts explicites sur tous les appels externes",{"type":30,"tag":38,"props":6171,"children":6172},{},[6173],{"type":36,"value":6174},"Tout appel vers un service externe doit avoir un timeout défini par le code, pas par la valeur par défaut du client HTTP. Ce seul changement élimine la propagation en cascade lors des dégradations de services.",{"type":30,"tag":6176,"props":6177,"children":6178},"blockquote",{},[6179],{"type":30,"tag":38,"props":6180,"children":6181},{},[6182,6184,6190],{"type":36,"value":6183},"Dans la plateforme bancaire que j'évoquais en ouverture, l'introduction de l'idempotence sur le service de virement a résolu le problème définitivement en 3 jours de développement. Le bug était présent depuis 18 mois. 18 mois de corrections manuelles, de runbooks, de post-mortems, résolus par un ",{"type":30,"tag":91,"props":6185,"children":6187},{"className":6186},[],[6188],{"type":36,"value":6189},"idempotencyKey",{"type":36,"value":6191}," et une vérification de doublon.",{"type":30,"tag":54,"props":6193,"children":6194},{},[],{"type":30,"tag":58,"props":6196,"children":6198},{"id":6197},"la-règle-dor",[6199],{"type":36,"value":6200},"La règle d'or",{"type":30,"tag":38,"props":6202,"children":6203},{},[6204,6209],{"type":30,"tag":483,"props":6205,"children":6206},{},[6207],{"type":36,"value":6208},"Chaque opération asynchrone doit être idempotente et retriable.",{"type":36,"value":6210}," Si elle ne l'est pas, la contrainte temporelle qui en découle doit être rendue explicite et protégée par du code, pas par de la documentation.",{"type":30,"tag":38,"props":6212,"children":6213},{},[6214,6216,6221],{"type":36,"value":6215},"L'introduction de l'idempotence et des timeouts explicites sur les 5 à 10 flux les plus critiques réduit de ",{"type":30,"tag":483,"props":6217,"children":6218},{},[6219],{"type":36,"value":6220},"70 à 80%",{"type":36,"value":6222}," le risque associé au couplage temporel existant dans un système.",{"type":30,"tag":54,"props":6224,"children":6225},{},[],{"type":30,"tag":58,"props":6227,"children":6229},{"id":6228},"faq-sur-le-couplage-temporel",[6230],{"type":36,"value":6231},"FAQ sur le couplage temporel",{"type":30,"tag":4758,"props":6233,"children":6234},{},[6235,6240],{"type":30,"tag":4762,"props":6236,"children":6237},{},[6238],{"type":36,"value":6239},"1. Quelle est la différence entre couplage temporel et couplage spatial ?",{"type":30,"tag":38,"props":6241,"children":6242},{},[6243],{"type":36,"value":6244},"Le couplage spatial (structural coupling) concerne la dépendance directe entre deux composants : A connaît et appelle B. Le couplage temporel concerne la dépendance sur l'ordre ou le timing : A doit s'exécuter avant B, ou A et B doivent s'exécuter dans la même fenêtre temporelle. Les deux sont des formes de couplage, mais le temporel est plus difficile à détecter car il n'apparaît pas dans les dépendances statiques du code. C'est précisément ce qui le rend dangereux.",{"type":30,"tag":4758,"props":6246,"children":6247},{},[6248,6253],{"type":30,"tag":4762,"props":6249,"children":6250},{},[6251],{"type":36,"value":6252},"2. Comment tester les problèmes de couplage temporel ?",{"type":30,"tag":38,"props":6254,"children":6255},{},[6256,6258,6264],{"type":36,"value":6257},"Le chaos engineering est la méthode la plus efficace : injecter des délais aléatoires sur les appels vers les services dépendants et observer si le système se comporte correctement. Les outils comme Chaos Monkey, Gremlin, ou Pumba permettent d'introduire des latences contrôlées en environnement de staging. Pour commencer sans outil spécifique : injecter un ",{"type":30,"tag":91,"props":6259,"children":6261},{"className":6260},[],[6262],{"type":36,"value":6263},"sleep(aléatoire)",{"type":36,"value":6265}," en environnement de test et vérifier que les timeouts et les garanties d'ordre fonctionnent comme attendu.",{"type":30,"tag":4758,"props":6267,"children":6268},{},[6269,6274],{"type":30,"tag":4762,"props":6270,"children":6271},{},[6272],{"type":36,"value":6273},"3. L'idempotence est-elle possible sur tous les types d'opérations ?",{"type":30,"tag":38,"props":6275,"children":6276},{},[6277],{"type":36,"value":6278},"Presque toujours, avec la bonne conception. La clé est l'idempotency key : un identifiant unique de la requête que le client génère et que le serveur utilise pour détecter les doublons. Les opérations financières, les envois d'emails, et les modifications d'état peuvent toutes être rendues idempotentes avec ce pattern. La seule limitation réelle concerne les opérations dont le résultat dépend de l'heure exacte, mais celles-ci peuvent être gérées avec un mécanisme de verrou temporel.",{"type":30,"tag":4758,"props":6280,"children":6281},{},[6282,6287],{"type":30,"tag":4762,"props":6283,"children":6284},{},[6285],{"type":36,"value":6286},"4. Quelle est la différence entre couplage temporel et race condition ?",{"type":30,"tag":38,"props":6288,"children":6289},{},[6290],{"type":36,"value":6291},"Une race condition est un cas particulier de couplage temporel : deux opérations concurrentes accèdent au même état partagé et le résultat dépend de l'ordre d'exécution. Le couplage temporel est plus large : il inclut aussi les séquences non-concurrentes qui doivent se dérouler dans un ordre précis. Toutes les race conditions sont des couplages temporels, mais tous les couplages temporels ne sont pas des race conditions.",{"type":30,"tag":54,"props":6293,"children":6294},{},[],{"type":30,"tag":2194,"props":6296,"children":6297},{"cta":4861,"href":4862,"title":4863,"type":4864},[6298],{"type":30,"tag":38,"props":6299,"children":6300},{},[6301],{"type":36,"value":6302},"L'Engineering Maturity Self-Assessment couvre le domaine Architecture & Résilience : évaluez votre niveau sur la gestion du couplage, les patterns asynchrones, et la robustesse de vos services. Score et recommandations en 10 minutes.",{"type":30,"tag":4872,"props":6304,"children":6305},{},[6306],{"type":36,"value":4876},{"title":8,"searchDepth":108,"depth":108,"links":6308},[6309,6310,6315,6316,6321,6322],{"id":4939,"depth":108,"text":4942},{"id":5120,"depth":108,"text":5123,"children":6311},[6312,6313,6314],{"id":5127,"depth":117,"text":5130},{"id":5153,"depth":117,"text":5156},{"id":5685,"depth":117,"text":5688},{"id":5721,"depth":108,"text":5724},{"id":5799,"depth":108,"text":5802,"children":6317},[6318,6319,6320],{"id":5805,"depth":117,"text":5808},{"id":6142,"depth":117,"text":6145},{"id":6166,"depth":117,"text":6169},{"id":6197,"depth":108,"text":6200},{"id":6228,"depth":108,"text":6231},"content:fr:architecture-craft:couplage-temporel-code-asynchrone.md","fr/architecture-craft/couplage-temporel-code-asynchrone.md","fr/architecture-craft/couplage-temporel-code-asynchrone",{"_path":6327,"_dir":6,"_draft":7,"_partial":7,"_locale":8,"title":6328,"description":6329,"id":170,"date":6330,"listed":13,"nocomments":7,"hidden":7,"categories":6331,"tags":6332,"--cover":6335,"readingTime":6336,"body":6340,"_type":4886,"_id":7115,"_source":4888,"_file":7116,"_stem":7117,"_extension":4891},"/fr/architecture-craft/adr-architecture-decision-record","Architecture décisionnelle : pourquoi les ADRs changent tout","Chaque équipe refait les mêmes débats architecturaux parce que personne ne documente les décisions passées. Les ADRs résolvent ça en 30 minutes de mise en place.","2026-01-14",[6],[6333,18,6334],"ADR","Documentation Technique","covers/articles/adr-architecture-decision.jpg",{"text":22,"minutes":6337,"time":6338,"words":6339},7.04,422400,1408,{"type":27,"children":6341,"toc":7106},[6342,6347,6352,6357,6362,6367,6370,6376,6388,6393,6398,6416,6421,6434,6437,6443,6448,6458,6468,6508,6518,6528,6743,6752,6755,6761,6766,6771,6789,6802,6805,6811,6816,6824,6829,6839,6849,6859,6872,6875,6881,6889,6894,6899,6902,6908,6988,6991,6997,7010,7031,7057,7070,7091,7094,7102],{"type":30,"tag":31,"props":6343,"children":6345},{"id":6344},"architecture-décisionnelle-pourquoi-les-adrs-changent-tout",[6346],{"type":36,"value":6328},{"type":30,"tag":38,"props":6348,"children":6349},{},[6350],{"type":36,"value":6351},"J'ai rejoint une équipe bancaire en mission où le même débat revenait toutes les deux semaines : \"Pourquoi on a choisi PostgreSQL plutôt que MongoDB ?\" La décision avait deux ans. Personne ne s'en souvenait. Et chaque fois, on reconstruisait le contexte de zéro, parfois en prenant une direction différente de la précédente.",{"type":30,"tag":38,"props":6353,"children":6354},{},[6355],{"type":36,"value":6356},"Ce n'était pas un manque d'intelligence. C'était un manque de mémoire organisationnelle.",{"type":30,"tag":38,"props":6358,"children":6359},{},[6360],{"type":36,"value":6361},"Les Architecture Decision Records (ADRs) sont la réponse à ce problème. Un document court (une à deux pages) qui répond à une seule question : \"Pourquoi avons-nous fait ce choix technique ?\" Le concept existe depuis les années 2000. La plupart des équipes ne l'utilisent toujours pas.",{"type":30,"tag":38,"props":6363,"children":6364},{},[6365],{"type":36,"value":6366},"Et ça leur coûte cher.",{"type":30,"tag":54,"props":6368,"children":6369},{},[],{"type":30,"tag":58,"props":6371,"children":6373},{"id":6372},"le-coût-réel-des-décisions-non-documentées",[6374],{"type":36,"value":6375},"Le coût réel des décisions non documentées",{"type":30,"tag":38,"props":6377,"children":6378},{},[6379,6381,6386],{"type":36,"value":6380},"Dans une équipe de 10 développeurs, si chaque développeur perd 2 heures par mois à reconstruire le contexte de décisions passées, ça représente ",{"type":30,"tag":483,"props":6382,"children":6383},{},[6384],{"type":36,"value":6385},"240 heures par an",{"type":36,"value":6387},", soit plus de 6 semaines-développeur perdues sur des débats déjà tranchés.",{"type":30,"tag":38,"props":6389,"children":6390},{},[6391],{"type":36,"value":6392},"Quand j'ai mené cet exercice chez un client dans le secteur assurance (60 développeurs, 8 équipes), les résultats étaient éloquents : 73% des développeurs n'avaient pas conscience des 3 dernières décisions architecturales majeures prises par leur propre équipe. Le coût en onboardings ratés, en refactorings inutiles, en duplications de solutions était supérieur à 400 heures par trimestre.",{"type":30,"tag":38,"props":6394,"children":6395},{},[6396],{"type":36,"value":6397},"J'ai demandé à chaque équipe de répondre par écrit à trois questions :",{"type":30,"tag":489,"props":6399,"children":6400},{},[6401,6406,6411],{"type":30,"tag":493,"props":6402,"children":6403},{},[6404],{"type":36,"value":6405},"\"Pourquoi utilisez-vous cette technologie plutôt que l'alternative ?\"",{"type":30,"tag":493,"props":6407,"children":6408},{},[6409],{"type":36,"value":6410},"\"Qui a pris la décision d'adopter ce pattern et quand ?\"",{"type":30,"tag":493,"props":6412,"children":6413},{},[6414],{"type":36,"value":6415},"\"Avez-vous des décisions en cours avec lesquelles vous n'êtes pas d'accord mais que vous n'avez jamais remises en question ?\"",{"type":30,"tag":38,"props":6417,"children":6418},{},[6419],{"type":36,"value":6420},"La diversité des réponses (et surtout les \"je ne sais pas\") a suffi à convaincre les équipes de changer leurs pratiques.",{"type":30,"tag":38,"props":6422,"children":6423},{},[6424,6426,6432],{"type":36,"value":6425},"Michael Nygard, dans son billet fondateur de 2011 sur les ADRs, posait la même exigence : capturer les décisions architecturalement significatives et leur contexte, pas seulement leur résultat. Ce qui importe, c'est de comprendre ",{"type":30,"tag":6427,"props":6428,"children":6429},"em",{},[6430],{"type":36,"value":6431},"pourquoi",{"type":36,"value":6433}," une décision a été prise, pas seulement laquelle.",{"type":30,"tag":54,"props":6435,"children":6436},{},[],{"type":30,"tag":58,"props":6438,"children":6440},{"id":6439},"le-template-adr-en-5-sections",[6441],{"type":36,"value":6442},"Le template ADR en 5 sections",{"type":30,"tag":38,"props":6444,"children":6445},{},[6446],{"type":36,"value":6447},"Un ADR bien rédigé répond à 5 questions dans l'ordre :",{"type":30,"tag":38,"props":6449,"children":6450},{},[6451,6456],{"type":30,"tag":483,"props":6452,"children":6453},{},[6454],{"type":36,"value":6455},"Contexte",{"type":36,"value":6457}," : quelle situation nécessite cette décision ? Quelles contraintes s'appliquent ? Qui est impliqué ?",{"type":30,"tag":38,"props":6459,"children":6460},{},[6461,6466],{"type":30,"tag":483,"props":6462,"children":6463},{},[6464],{"type":36,"value":6465},"Décision",{"type":36,"value":6467}," : quelle est la décision prise, formulée comme une assertion active (\"Nous utilisons PostgreSQL comme base de données principale\") plutôt que comme une question ouverte.",{"type":30,"tag":38,"props":6469,"children":6470},{},[6471,6476,6478,6484,6486,6492,6493,6499,6500,6506],{"type":30,"tag":483,"props":6472,"children":6473},{},[6474],{"type":36,"value":6475},"Statut",{"type":36,"value":6477}," : ",{"type":30,"tag":91,"props":6479,"children":6481},{"className":6480},[],[6482],{"type":36,"value":6483},"proposed",{"type":36,"value":6485}," | ",{"type":30,"tag":91,"props":6487,"children":6489},{"className":6488},[],[6490],{"type":36,"value":6491},"accepted",{"type":36,"value":6485},{"type":30,"tag":91,"props":6494,"children":6496},{"className":6495},[],[6497],{"type":36,"value":6498},"deprecated",{"type":36,"value":6485},{"type":30,"tag":91,"props":6501,"children":6503},{"className":6502},[],[6504],{"type":36,"value":6505},"superseded",{"type":36,"value":6507},". Le statut évolue dans le temps : une décision peut être remplacée par une nouvelle ADR.",{"type":30,"tag":38,"props":6509,"children":6510},{},[6511,6516],{"type":30,"tag":483,"props":6512,"children":6513},{},[6514],{"type":36,"value":6515},"Conséquences",{"type":36,"value":6517}," : implications positives et négatives. Qu'est-ce qui devient plus simple ? Qu'est-ce qui devient plus difficile ?",{"type":30,"tag":38,"props":6519,"children":6520},{},[6521,6526],{"type":30,"tag":483,"props":6522,"children":6523},{},[6524],{"type":36,"value":6525},"Alternatives considérées",{"type":36,"value":6527}," : quelles autres options ont été évaluées et pourquoi ont-elles été écartées ?",{"type":30,"tag":84,"props":6529,"children":6532},{"code":6530,"language":4886,"meta":8,"className":6531,"style":8},"# ADR-0001 : Utilisation de PostgreSQL comme base de données principale\n\n## Contexte\nNotre service de gestion des commandes nécessite une base de données relationnelle\navec support des transactions ACID. L'équipe a de l'expérience avec PostgreSQL et MySQL.\nContrainte : déploiement sur AWS, budget infrastructure limité.\n\n## Décision\nNous utilisons PostgreSQL 15 comme base de données principale pour tous les services\nqui nécessitent une persistance relationnelle.\n\n## Statut\nAccepté (2026-01-14)\n\n## Conséquences\n- Positives : ACID garanti, support JSON natif, extensions riches (PostGIS si besoin)\n- Négatives : scaling vertical nécessaire avant sharding ; expertise spécifique requise\n- Impact sur l'équipe : formation nécessaire pour 3 développeurs juniors\n\n## Alternatives considérées\n- MySQL 8.0 : écarté car support JSON moins mature et licensing Oracle\n- MongoDB : écarté car nos données sont relationnelles\n- DynamoDB : écarté car coût à l'usage imprévisible et expertise absente\n","language-markdown shiki shiki-themes catppuccin-frappe github-dark",[6533],{"type":30,"tag":91,"props":6534,"children":6535},{"__ignoreMap":8},[6536,6545,6552,6561,6569,6577,6585,6592,6600,6608,6616,6623,6631,6639,6646,6654,6668,6680,6692,6699,6707,6719,6731],{"type":30,"tag":95,"props":6537,"children":6538},{"class":97,"line":98},[6539],{"type":30,"tag":95,"props":6540,"children":6542},{"style":6541},"--shiki-default:#E78284;--shiki-default-font-weight:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold",[6543],{"type":36,"value":6544},"# ADR-0001 : Utilisation de PostgreSQL comme base de données principale\n",{"type":30,"tag":95,"props":6546,"children":6547},{"class":97,"line":108},[6548],{"type":30,"tag":95,"props":6549,"children":6550},{"emptyLinePlaceholder":13},[6551],{"type":36,"value":114},{"type":30,"tag":95,"props":6553,"children":6554},{"class":97,"line":117},[6555],{"type":30,"tag":95,"props":6556,"children":6558},{"style":6557},"--shiki-default:#EF9F76;--shiki-default-font-weight:inherit;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold",[6559],{"type":36,"value":6560},"## Contexte\n",{"type":30,"tag":95,"props":6562,"children":6563},{"class":97,"line":139},[6564],{"type":30,"tag":95,"props":6565,"children":6566},{"style":185},[6567],{"type":36,"value":6568},"Notre service de gestion des commandes nécessite une base de données relationnelle\n",{"type":30,"tag":95,"props":6570,"children":6571},{"class":97,"line":170},[6572],{"type":30,"tag":95,"props":6573,"children":6574},{"style":185},[6575],{"type":36,"value":6576},"avec support des transactions ACID. L'équipe a de l'expérience avec PostgreSQL et MySQL.\n",{"type":30,"tag":95,"props":6578,"children":6579},{"class":97,"line":253},[6580],{"type":30,"tag":95,"props":6581,"children":6582},{"style":185},[6583],{"type":36,"value":6584},"Contrainte : déploiement sur AWS, budget infrastructure limité.\n",{"type":30,"tag":95,"props":6586,"children":6587},{"class":97,"line":306},[6588],{"type":30,"tag":95,"props":6589,"children":6590},{"emptyLinePlaceholder":13},[6591],{"type":36,"value":114},{"type":30,"tag":95,"props":6593,"children":6594},{"class":97,"line":314},[6595],{"type":30,"tag":95,"props":6596,"children":6597},{"style":6557},[6598],{"type":36,"value":6599},"## Décision\n",{"type":30,"tag":95,"props":6601,"children":6602},{"class":97,"line":350},[6603],{"type":30,"tag":95,"props":6604,"children":6605},{"style":185},[6606],{"type":36,"value":6607},"Nous utilisons PostgreSQL 15 comme base de données principale pour tous les services\n",{"type":30,"tag":95,"props":6609,"children":6610},{"class":97,"line":400},[6611],{"type":30,"tag":95,"props":6612,"children":6613},{"style":185},[6614],{"type":36,"value":6615},"qui nécessitent une persistance relationnelle.\n",{"type":30,"tag":95,"props":6617,"children":6618},{"class":97,"line":467},[6619],{"type":30,"tag":95,"props":6620,"children":6621},{"emptyLinePlaceholder":13},[6622],{"type":36,"value":114},{"type":30,"tag":95,"props":6624,"children":6625},{"class":97,"line":875},[6626],{"type":30,"tag":95,"props":6627,"children":6628},{"style":6557},[6629],{"type":36,"value":6630},"## Statut\n",{"type":30,"tag":95,"props":6632,"children":6633},{"class":97,"line":883},[6634],{"type":30,"tag":95,"props":6635,"children":6636},{"style":185},[6637],{"type":36,"value":6638},"Accepté (2026-01-14)\n",{"type":30,"tag":95,"props":6640,"children":6641},{"class":97,"line":892},[6642],{"type":30,"tag":95,"props":6643,"children":6644},{"emptyLinePlaceholder":13},[6645],{"type":36,"value":114},{"type":30,"tag":95,"props":6647,"children":6648},{"class":97,"line":908},[6649],{"type":30,"tag":95,"props":6650,"children":6651},{"style":6557},[6652],{"type":36,"value":6653},"## Conséquences\n",{"type":30,"tag":95,"props":6655,"children":6656},{"class":97,"line":967},[6657,6663],{"type":30,"tag":95,"props":6658,"children":6660},{"style":6659},"--shiki-default:#81C8BE;--shiki-dark:#FFAB70",[6661],{"type":36,"value":6662},"-",{"type":30,"tag":95,"props":6664,"children":6665},{"style":185},[6666],{"type":36,"value":6667}," Positives : ACID garanti, support JSON natif, extensions riches (PostGIS si besoin)\n",{"type":30,"tag":95,"props":6669,"children":6670},{"class":97,"line":993},[6671,6675],{"type":30,"tag":95,"props":6672,"children":6673},{"style":6659},[6674],{"type":36,"value":6662},{"type":30,"tag":95,"props":6676,"children":6677},{"style":185},[6678],{"type":36,"value":6679}," Négatives : scaling vertical nécessaire avant sharding ; expertise spécifique requise\n",{"type":30,"tag":95,"props":6681,"children":6682},{"class":97,"line":1019},[6683,6687],{"type":30,"tag":95,"props":6684,"children":6685},{"style":6659},[6686],{"type":36,"value":6662},{"type":30,"tag":95,"props":6688,"children":6689},{"style":185},[6690],{"type":36,"value":6691}," Impact sur l'équipe : formation nécessaire pour 3 développeurs juniors\n",{"type":30,"tag":95,"props":6693,"children":6694},{"class":97,"line":1027},[6695],{"type":30,"tag":95,"props":6696,"children":6697},{"emptyLinePlaceholder":13},[6698],{"type":36,"value":114},{"type":30,"tag":95,"props":6700,"children":6701},{"class":97,"line":1079},[6702],{"type":30,"tag":95,"props":6703,"children":6704},{"style":6557},[6705],{"type":36,"value":6706},"## Alternatives considérées\n",{"type":30,"tag":95,"props":6708,"children":6709},{"class":97,"line":1124},[6710,6714],{"type":30,"tag":95,"props":6711,"children":6712},{"style":6659},[6713],{"type":36,"value":6662},{"type":30,"tag":95,"props":6715,"children":6716},{"style":185},[6717],{"type":36,"value":6718}," MySQL 8.0 : écarté car support JSON moins mature et licensing Oracle\n",{"type":30,"tag":95,"props":6720,"children":6721},{"class":97,"line":1185},[6722,6726],{"type":30,"tag":95,"props":6723,"children":6724},{"style":6659},[6725],{"type":36,"value":6662},{"type":30,"tag":95,"props":6727,"children":6728},{"style":185},[6729],{"type":36,"value":6730}," MongoDB : écarté car nos données sont relationnelles\n",{"type":30,"tag":95,"props":6732,"children":6733},{"class":97,"line":1197},[6734,6738],{"type":30,"tag":95,"props":6735,"children":6736},{"style":6659},[6737],{"type":36,"value":6662},{"type":30,"tag":95,"props":6739,"children":6740},{"style":185},[6741],{"type":36,"value":6742}," DynamoDB : écarté car coût à l'usage imprévisible et expertise absente\n",{"type":30,"tag":2194,"props":6744,"children":6746},{"cta":2196,"href":2197,"title":6745,"type":2199},"Votre équipe refait les mêmes débats techniques sans jamais capitaliser sur les décisions passées ?",[6747],{"type":30,"tag":38,"props":6748,"children":6749},{},[6750],{"type":36,"value":6751},"Je vois ce pattern dans toutes les équipes que j'accompagne : des heures perdues à reconstituer le contexte de décisions qui auraient dû être documentées. Un appel de 30 minutes suffit à définir la stratégie d'adoption des ADRs adaptée à votre équipe et à identifier les 10 décisions passées à documenter en priorité.",{"type":30,"tag":54,"props":6753,"children":6754},{},[],{"type":30,"tag":58,"props":6756,"children":6758},{"id":6757},"les-3-premières-adrs-à-rédiger",[6759],{"type":36,"value":6760},"Les 3 premières ADRs à rédiger",{"type":30,"tag":38,"props":6762,"children":6763},{},[6764],{"type":36,"value":6765},"Ne commencez pas par les décisions les plus anciennes ni les plus complexes. Commencez par les 3 décisions qui génèrent le plus de questions récurrentes.",{"type":30,"tag":38,"props":6767,"children":6768},{},[6769],{"type":36,"value":6770},"Pour identifier lesquelles, je pose toujours ces questions :",{"type":30,"tag":489,"props":6772,"children":6773},{},[6774,6779,6784],{"type":30,"tag":493,"props":6775,"children":6776},{},[6777],{"type":36,"value":6778},"Quelle décision technique revient en débat à chaque onboarding d'un nouveau développeur ?",{"type":30,"tag":493,"props":6780,"children":6781},{},[6782],{"type":36,"value":6783},"Quelle décision architecturale génère des \"oui mais pourquoi ?\" récurrents en code review ?",{"type":30,"tag":493,"props":6785,"children":6786},{},[6787],{"type":36,"value":6788},"Quelle décision récente mérite d'être documentée pendant que le contexte est encore frais ?",{"type":30,"tag":38,"props":6790,"children":6791},{},[6792,6794,6800],{"type":36,"value":6793},"Pour les décisions prises sans documentation, je recommande d'écrire l'ADR avec ce qu'on sait, même imparfaitement. Un ADR incomplet vaut mieux que pas d'ADR. Le statut ",{"type":30,"tag":91,"props":6795,"children":6797},{"className":6796},[],[6798],{"type":36,"value":6799},"reconstructed",{"type":36,"value":6801}," signale que le document a été rédigé après-coup.",{"type":30,"tag":54,"props":6803,"children":6804},{},[],{"type":30,"tag":58,"props":6806,"children":6808},{"id":6807},"organisation-et-rituels-de-maintenance",[6809],{"type":36,"value":6810},"Organisation et rituels de maintenance",{"type":30,"tag":38,"props":6812,"children":6813},{},[6814],{"type":36,"value":6815},"Je recommande cette structure dans le dépôt Git :",{"type":30,"tag":84,"props":6817,"children":6819},{"code":6818},"docs/\n  architecture/\n    decisions/\n      0001-postgresql-base-de-donnees.md\n      0002-event-driven-architecture.md\n      0003-monorepo-structure.md\n    README.md  ← index des ADRs avec titre et statut\n",[6820],{"type":30,"tag":91,"props":6821,"children":6822},{"__ignoreMap":8},[6823],{"type":36,"value":6818},{"type":30,"tag":38,"props":6825,"children":6826},{},[6827],{"type":36,"value":6828},"Trois règles de maintenance que j'impose à toutes les équipes que j'accompagne :",{"type":30,"tag":38,"props":6830,"children":6831},{},[6832,6837],{"type":30,"tag":483,"props":6833,"children":6834},{},[6835],{"type":36,"value":6836},"Numérotation séquentielle.",{"type":36,"value":6838}," ADR-0001, ADR-0002... La chronologie fait partie de l'information.",{"type":30,"tag":38,"props":6840,"children":6841},{},[6842,6847],{"type":30,"tag":483,"props":6843,"children":6844},{},[6845],{"type":36,"value":6846},"Ne jamais modifier ni supprimer une ADR.",{"type":36,"value":6848}," Seulement la superseder avec une nouvelle. La trace historique a de la valeur : comprendre pourquoi une décision a changé est aussi utile que la décision actuelle.",{"type":30,"tag":38,"props":6850,"children":6851},{},[6852,6857],{"type":30,"tag":483,"props":6853,"children":6854},{},[6855],{"type":36,"value":6856},"Rituel de PR.",{"type":36,"value":6858}," À chaque pull request contenant un changement architectural significatif, vérifier si une ADR doit être créée ou mise à jour. Ce check peut être intégré dans le template de PR.",{"type":30,"tag":38,"props":6860,"children":6861},{},[6862,6864,6870],{"type":36,"value":6863},"L'outil ",{"type":30,"tag":91,"props":6865,"children":6867},{"className":6866},[],[6868],{"type":36,"value":6869},"adr-tools",{"type":36,"value":6871}," (CLI open source) génère et gère les ADRs depuis le terminal. Pour les équipes sur Confluence, l'intégration est possible, mais je garde toujours le dépôt Git comme source de vérité.",{"type":30,"tag":54,"props":6873,"children":6874},{},[],{"type":30,"tag":58,"props":6876,"children":6878},{"id":6877},"le-piège-de-la-rétro-documentation-exhaustive",[6879],{"type":36,"value":6880},"Le piège de la rétro-documentation exhaustive",{"type":30,"tag":6176,"props":6882,"children":6883},{},[6884],{"type":30,"tag":38,"props":6885,"children":6886},{},[6887],{"type":36,"value":6888},"Ne pas essayer de documenter toutes les décisions passées d'un coup. La rétro-documentation exhaustive est un projet qui ne se termine pas et qui décourage l'équipe avant qu'elle prenne le pli.",{"type":30,"tag":38,"props":6890,"children":6891},{},[6892],{"type":36,"value":6893},"Ma recommandation : documenter toutes les nouvelles décisions systématiquement à partir d'aujourd'hui, et rattraper les décisions passées au fil des besoins : lors des onboardings, des débats récurrents, ou des refactorings qui remettent en question des choix passés.",{"type":30,"tag":38,"props":6895,"children":6896},{},[6897],{"type":36,"value":6898},"En 3 mois à ce rythme, les équipes que j'accompagne ont entre 15 et 25 ADRs actives. C'est suffisant pour changer la culture.",{"type":30,"tag":54,"props":6900,"children":6901},{},[],{"type":30,"tag":58,"props":6903,"children":6905},{"id":6904},"ce-que-ça-change-concrètement",[6906],{"type":36,"value":6907},"Ce que ça change concrètement",{"type":30,"tag":6909,"props":6910,"children":6911},"table",{},[6912,6931],{"type":30,"tag":6913,"props":6914,"children":6915},"thead",{},[6916],{"type":30,"tag":6917,"props":6918,"children":6919},"tr",{},[6920,6926],{"type":30,"tag":6921,"props":6922,"children":6923},"th",{},[6924],{"type":36,"value":6925},"Action",{"type":30,"tag":6921,"props":6927,"children":6928},{},[6929],{"type":36,"value":6930},"Résultat",{"type":30,"tag":6932,"props":6933,"children":6934},"tbody",{},[6935,6949,6962,6975],{"type":30,"tag":6917,"props":6936,"children":6937},{},[6938,6944],{"type":30,"tag":6939,"props":6940,"children":6941},"td",{},[6942],{"type":36,"value":6943},"Calculer le coût des décisions non documentées",{"type":30,"tag":6939,"props":6945,"children":6946},{},[6947],{"type":36,"value":6948},"Conviction de l'équipe",{"type":30,"tag":6917,"props":6950,"children":6951},{},[6952,6957],{"type":30,"tag":6939,"props":6953,"children":6954},{},[6955],{"type":36,"value":6956},"Adopter le template en 5 sections",{"type":30,"tag":6939,"props":6958,"children":6959},{},[6960],{"type":36,"value":6961},"Format standardisé",{"type":30,"tag":6917,"props":6963,"children":6964},{},[6965,6970],{"type":30,"tag":6939,"props":6966,"children":6967},{},[6968],{"type":36,"value":6969},"Rédiger les 3 premières ADRs prioritaires",{"type":30,"tag":6939,"props":6971,"children":6972},{},[6973],{"type":36,"value":6974},"Premières ADRs dans le dépôt",{"type":30,"tag":6917,"props":6976,"children":6977},{},[6978,6983],{"type":30,"tag":6939,"props":6979,"children":6980},{},[6981],{"type":36,"value":6982},"Setup le registre et les rituels de PR",{"type":30,"tag":6939,"props":6984,"children":6985},{},[6986],{"type":36,"value":6987},"Processus pérenne",{"type":30,"tag":54,"props":6989,"children":6990},{},[],{"type":30,"tag":58,"props":6992,"children":6994},{"id":6993},"faq-sur-les-adrs",[6995],{"type":36,"value":6996},"FAQ sur les ADRs",{"type":30,"tag":4758,"props":6998,"children":6999},{},[7000,7005],{"type":30,"tag":4762,"props":7001,"children":7002},{},[7003],{"type":36,"value":7004},"1. Où stocker les ADRs : dans le dépôt Git ou dans Confluence/Notion ?",{"type":30,"tag":38,"props":7006,"children":7007},{},[7008],{"type":36,"value":7009},"Dans le dépôt Git, si possible. Les ADRs sont du code de documentation : elles doivent versionner avec le code qu'elles documentent. Une ADR dans Git est visible dans les PR, peut être liée aux commits concernés, et survit aux migrations d'outils. Si votre organisation exige Confluence pour la documentation, utilisez-le en complément, mais gardez le dépôt Git comme source de vérité. J'ai vu trop d'ADRs perdues lors de migrations Confluence.",{"type":30,"tag":4758,"props":7011,"children":7012},{},[7013,7018],{"type":30,"tag":4762,"props":7014,"children":7015},{},[7016],{"type":36,"value":7017},"2. Faut-il un ADR pour chaque décision technique ou seulement les grandes décisions d'architecture ?",{"type":30,"tag":38,"props":7019,"children":7020},{},[7021,7023,7029],{"type":36,"value":7022},"Seulement les décisions significatives : choix de technologie, choix d'architecture (microservices vs monolithe, synchrone vs asynchrone), patterns de design appliqués à l'ensemble du système, décisions de sécurité ou de conformité. Pas besoin d'ADR pour les décisions de code quotidiennes : quel nom de variable, quelle structure de fichier dans un composant. La règle empirique que j'utilise : si la décision fera débat dans 6 mois, elle mérite une ADR. Par exemple, le choix d'adopter un ",{"type":30,"tag":70,"props":7024,"children":7026},{"href":7025},"/fr/architecture-craft/database-per-service-microservices",[7027],{"type":36,"value":7028},"pattern Database per Service dans une architecture microservices",{"type":36,"value":7030}," est typiquement le genre de décision qui doit être documentée dans une ADR.",{"type":30,"tag":4758,"props":7032,"children":7033},{},[7034,7039],{"type":30,"tag":4762,"props":7035,"children":7036},{},[7037],{"type":36,"value":7038},"3. Que faire quand une ADR ancienne devient obsolète ?",{"type":30,"tag":38,"props":7040,"children":7041},{},[7042,7044,7049,7051,7055],{"type":36,"value":7043},"Créer une nouvelle ADR qui supersede l'ancienne. L'ancienne garde son statut ",{"type":30,"tag":91,"props":7045,"children":7047},{"className":7046},[],[7048],{"type":36,"value":6505},{"type":36,"value":7050}," avec une référence vers la nouvelle. Jamais modifier l'ADR originale : la trace historique des décisions a de la valeur, même quand elles sont remplacées. Comprendre ",{"type":30,"tag":6427,"props":7052,"children":7053},{},[7054],{"type":36,"value":6431},{"type":36,"value":7056}," une décision a changé est souvent aussi utile que comprendre la décision actuelle.",{"type":30,"tag":4758,"props":7058,"children":7059},{},[7060,7065],{"type":30,"tag":4762,"props":7061,"children":7062},{},[7063],{"type":36,"value":7064},"4. Comment introduire les ADRs dans une équipe qui n'a jamais documenté ses décisions ?",{"type":30,"tag":38,"props":7066,"children":7067},{},[7068],{"type":36,"value":7069},"Je commence toujours par l'exemple. Je rédige les 3 premières ADRs moi-même, les présente en réunion d'équipe, et explique la valeur qu'elles auraient eue lors de situations passées concrètes, des situations que l'équipe reconnaît. Ensuite, j'invite les développeurs à rédiger les ADRs pour leurs prochaines décisions avec du support. Après 3 cycles, la pratique s'installe naturellement.",{"type":30,"tag":4758,"props":7071,"children":7072},{},[7073,7078],{"type":30,"tag":4762,"props":7074,"children":7075},{},[7076],{"type":36,"value":7077},"5. Est-ce que les ADRs ralentissent le processus de décision ?",{"type":30,"tag":38,"props":7079,"children":7080},{},[7081,7083,7089],{"type":36,"value":7082},"Non, et c'est le contrepoint que j'entends toujours. Rédiger une ADR prend 30 minutes. Refaire le même débat dans 6 mois prend 3 heures, mobilise 5 personnes, et produit parfois une décision différente de la précédente sans raison valable. Le retour sur investissement est immédiat après la première ADR utilisée pour clore un débat récurrent. C'est d'autant plus vrai pour un CTO en début de mandat : parmi les ",{"type":30,"tag":70,"props":7084,"children":7086},{"href":7085},"/fr/management/cto-premiere-annee-90-jours",[7087],{"type":36,"value":7088},"90 premiers jours d'un CTO",{"type":36,"value":7090},", poser les bases de la gouvernance architecturale (dont les ADRs) est l'une des décisions structurantes les plus durables.",{"type":30,"tag":54,"props":7092,"children":7093},{},[],{"type":30,"tag":2194,"props":7095,"children":7096},{"cta":4861,"href":4862,"title":4863,"type":4864},[7097],{"type":30,"tag":38,"props":7098,"children":7099},{},[7100],{"type":36,"value":7101},"L'Engineering Maturity Self-Assessment couvre le domaine Gouvernance & Documentation : évaluez votre maturité sur les pratiques de décision architecturale, la documentation, et la cohérence du système. Score et plan d'action en 10 minutes.",{"type":30,"tag":4872,"props":7103,"children":7104},{},[7105],{"type":36,"value":4876},{"title":8,"searchDepth":108,"depth":108,"links":7107},[7108,7109,7110,7111,7112,7113,7114],{"id":6372,"depth":108,"text":6375},{"id":6439,"depth":108,"text":6442},{"id":6757,"depth":108,"text":6760},{"id":6807,"depth":108,"text":6810},{"id":6877,"depth":108,"text":6880},{"id":6904,"depth":108,"text":6907},{"id":6993,"depth":108,"text":6996},"content:fr:architecture-craft:adr-architecture-decision-record.md","fr/architecture-craft/adr-architecture-decision-record.md","fr/architecture-craft/adr-architecture-decision-record",1775679799783]