[{"data":1,"prerenderedAt":1757},["ShallowReactive",2],{"blog-post-\u002Fblogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit":3,"related-\u002Fblogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit":1723},{"id":4,"title":5,"alt":6,"authors":7,"body":19,"date":1695,"description":1696,"extension":1697,"image":1698,"meta":1699,"navigation":837,"ogImage":1698,"path":1700,"published":837,"reviewers":1701,"seo":1718,"stem":1719,"tags":1720,"__hash__":1722},"blogs\u002Fblogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit\u002Findex.md","Architecture hexagonale en programmation fonctionnelle, mythe ou réalité ?","Quand l’architecture hexagonale rencontre la programmation fonctionnelle",[8,14],{"id":9,"name":10,"image":11,"linkedin":12,"x":13},"02c620f8-3576-4943-b5cf-6117f99220a2","Edouard Cattez",".\u002Fassets\u002Fauthor-edouard-cattez.webp","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fedouard-cattez-865794133\u002F","https:\u002F\u002Fx.com\u002Fecattez",{"id":15,"name":16,"image":17,"linkedin":18,"x":18},"188f4462-cd38-80d5-b9e6-ec28a94d11e5","Bastien Dufour","\u002Fdefault-author-image.webp",null,{"type":20,"value":21,"toc":1690},"minimark",[22,26,34,37,40,45,56,713,716,719,738,758,777,780,910,921,928,931,936,949,952,1072,1075,1079,1082,1165,1168,1172,1175,1669,1672,1675,1679,1686],[23,24,25],"p",{},"À mesure que les systèmes logiciels gagnent en complexité, les approches traditionnelles de conception montrent leurs limites. Couplage excessif, difficulté à tester, rigidité face au changement : autant de symptômes qui ralentissent l’évolution des applications modernes. Dans ce contexte, deux courants se distinguent par leur capacité à apporter clarté, robustesse et maintenabilité : l’architecture hexagonale et la programmation fonctionnelle.",[23,27,28,29,33],{},"L’architecture hexagonale, aussi appelée ",[30,31,32],"em",{},"Ports and Adapters",", propose de recentrer le cœur métier en le protégeant des dépendances techniques. Elle favorise une séparation nette entre la logique métier et les interactions externes, rendant les systèmes plus modulaires et testables.\nDe son côté, la programmation fonctionnelle introduit des principes comme l’immuabilité, les fonctions pures et la composition, permettant de construire des logiciels plus prévisibles et plus faciles à raisonner.",[23,35,36],{},"Bien que ces deux approches soient issues de contextes différents, elles partagent une même ambition : réduire la complexité accidentelle pour laisser place à l’essentiel. Leur combinaison ouvre la voie à des architectures élégantes, où le code devient non seulement plus fiable, mais aussi plus expressif.",[23,38,39],{},"Dans cet article, nous explorerons comment ces deux paradigmes peuvent se compléter, et en quoi leur adoption conjointe peut transformer en profondeur la manière de concevoir et de faire évoluer nos applications.",[41,42,44],"h3",{"id":43},"le-langage-ubiquitaire-au-centre-de-larchitecture","Le langage ubiquitaire au centre de l'architecture",[23,46,47,48,55],{},"Nous allons illustrer tout ça avec le calcul de package de ",[49,50,54],"a",{"href":51,"rel":52},"http:\u002F\u002Fhoppr.tech\u002F",[53],"nofollow","Hoppr",".",[57,58,61],"span",{"className":59},[60],"katex-display",[57,62,65],{"className":63},[64],"katex",[57,66,70,177,289,394,468,559,649],{"className":67,"ariaHidden":69},[68],"katex-html","true",[57,71,74,79,86,90,94,98,164,169,174],{"className":72},[73],"base",[57,75],{"className":76,"style":78},[77],"strut","height:0.9694em;vertical-align:-0.2861em;",[57,80,85],{"className":81,"style":84},[82,83],"mord","mathnormal","margin-right:0.05017em;","B",[57,87,89],{"className":88},[82,83],"o",[57,91,93],{"className":92},[82,83],"n",[57,95,97],{"className":96},[82,83],"u",[57,99,101,105],{"className":100},[82],[57,102,104],{"className":103},[82,83],"s",[57,106,109],{"className":107},[108],"msupsub",[57,110,114,155],{"className":111},[112,113],"vlist-t","vlist-t2",[57,115,118,150],{"className":116},[117],"vlist-r",[57,119,123],{"className":120,"style":122},[121],"vlist","height:0.3283em;",[57,124,126,131],{"style":125},"top:-2.55em;margin-left:0em;margin-right:0.05em;",[57,127],{"className":128,"style":130},[129],"pstrut","height:2.7em;",[57,132,138],{"className":133},[134,135,136,137],"sizing","reset-size6","size3","mtight",[57,139,141,145],{"className":140},[82,137],[57,142,144],{"className":143},[82,83,137],"Ho",[57,146,149],{"className":147,"style":148},[82,83,137],"margin-right:0.00773em;","ppR",[57,151,154],{"className":152},[153],"vlist-s","​",[57,156,158],{"className":157},[117],[57,159,162],{"className":160,"style":161},[121],"height:0.2861em;",[57,163],{},[57,165],{"className":166,"style":168},[167],"mspace","margin-right:0.2778em;",[57,170,173],{"className":171},[172],"mrel","=",[57,175],{"className":176,"style":168},[167],[57,178,180,184,192,196,200,203,206,210,214,277,281,286],{"className":179},[73],[57,181],{"className":182,"style":183},[77],"height:1.6em;vertical-align:-0.55em;",[57,185,191],{"className":186,"style":190},[187,188,189],"mop","op-symbol","large-op","position:relative;top:0em;","∑",[57,193],{"className":194,"style":195},[167],"margin-right:0.1667em;",[57,197,199],{"className":198},[82,83],"m",[57,201,89],{"className":202},[82,83],[57,204,93],{"className":205},[82,83],[57,207,209],{"className":208},[82,83],"t",[57,211,213],{"className":212},[82,83],"an",[57,215,217,220],{"className":216},[82],[57,218,209],{"className":219},[82,83],[57,221,223],{"className":222},[108],[57,224,226,269],{"className":225},[112,113],[57,227,229,266],{"className":228},[117],[57,230,233],{"className":231,"style":232},[121],"height:0.3361em;",[57,234,235,238],{"style":125},[57,236],{"className":237,"style":130},[129],[57,239,241],{"className":240},[134,135,136,137],[57,242,244,249,252,256,259,262],{"className":243},[82,137],[57,245,248],{"className":246,"style":247},[82,83,137],"margin-right:0.10764em;","f",[57,250,49],{"className":251},[82,83,137],[57,253,255],{"className":254},[82,83,137],"c",[57,257,209],{"className":258},[82,83,137],[57,260,97],{"className":261},[82,83,137],[57,263,265],{"className":264},[82,83,137],"re",[57,267,154],{"className":268},[153],[57,270,272],{"className":271},[117],[57,273,275],{"className":274,"style":161},[121],[57,276],{},[57,278],{"className":279,"style":280},[167],"margin-right:0.2222em;",[57,282,285],{"className":283},[284],"mbin","−",[57,287],{"className":288,"style":280},[167],[57,290,292,296,301,304,307,312,316,321,384,387,391],{"className":291},[73],[57,293],{"className":294,"style":295},[77],"height:1em;vertical-align:-0.25em;",[57,297,300],{"className":298},[299],"mopen","(",[57,302,104],{"className":303},[82,83],[57,305,49],{"className":306},[82,83],[57,308,311],{"className":309,"style":310},[82,83],"margin-right:0.01968em;","l",[57,313,315],{"className":314},[82,83],"ai",[57,317,320],{"className":318,"style":319},[82,83],"margin-right:0.02778em;","r",[57,322,324,328],{"className":323},[82],[57,325,327],{"className":326},[82,83],"e",[57,329,331],{"className":330},[108],[57,332,334,375],{"className":333},[112,113],[57,335,337,372],{"className":336},[117],[57,338,340],{"className":339,"style":232},[121],[57,341,342,345],{"style":125},[57,343],{"className":344,"style":130},[129],[57,346,348],{"className":347},[134,135,136,137],[57,349,351,354,357,360,363,366,369],{"className":350},[82,137],[57,352,199],{"className":353},[82,83,137],[57,355,327],{"className":356},[82,83,137],[57,358,93],{"className":359},[82,83,137],[57,361,104],{"className":362},[82,83,137],[57,364,97],{"className":365},[82,83,137],[57,367,327],{"className":368},[82,83,137],[57,370,311],{"className":371,"style":310},[82,83,137],[57,373,154],{"className":374},[153],[57,376,378],{"className":377},[117],[57,379,382],{"className":380,"style":381},[121],"height:0.15em;",[57,383],{},[57,385],{"className":386,"style":280},[167],[57,388,390],{"className":389},[284],"×",[57,392],{"className":393,"style":280},[167],[57,395,397,401,404,459,462,465],{"className":396},[73],[57,398],{"className":399,"style":400},[77],"height:0.8444em;vertical-align:-0.15em;",[57,402,93],{"className":403},[82,83],[57,405,407,411],{"className":406},[82],[57,408,410],{"className":409},[82,83],"b",[57,412,414],{"className":413},[108],[57,415,417,451],{"className":416},[112,113],[57,418,420,448],{"className":419},[117],[57,421,424],{"className":422,"style":423},[121],"height:0.3117em;",[57,425,426,429],{"style":125},[57,427],{"className":428,"style":130},[129],[57,430,432],{"className":431},[134,135,136,137],[57,433,435,438,441,445],{"className":434},[82,137],[57,436,199],{"className":437},[82,83,137],[57,439,89],{"className":440},[82,83,137],[57,442,444],{"className":443},[82,83,137],"i",[57,446,104],{"className":447},[82,83,137],[57,449,154],{"className":450},[153],[57,452,454],{"className":453},[117],[57,455,457],{"className":456,"style":381},[121],[57,458],{},[57,460],{"className":461,"style":280},[167],[57,463,390],{"className":464},[284],[57,466],{"className":467,"style":280},[167],[57,469,471,475,478,481,484,545,550,553,556],{"className":470},[73],[57,472],{"className":473,"style":474},[77],"height:1.0361em;vertical-align:-0.2861em;",[57,476,209],{"className":477},[82,83],[57,479,49],{"className":480},[82,83],[57,482,97],{"className":483},[82,83],[57,485,487,491],{"className":486},[82],[57,488,490],{"className":489},[82,83],"x",[57,492,494],{"className":493},[108],[57,495,497,537],{"className":496},[112,113],[57,498,500,534],{"className":499},[117],[57,501,503],{"className":502,"style":232},[121],[57,504,505,508],{"style":125},[57,506],{"className":507,"style":130},[129],[57,509,511],{"className":510},[134,135,136,137],[57,512,514,517,520,524,528,531],{"className":513},[82,137],[57,515,327],{"className":516},[82,83,137],[57,518,199],{"className":519},[82,83,137],[57,521,523],{"className":522,"style":310},[82,83,137],"pl",[57,525,527],{"className":526},[82,83,137],"oye",[57,529,97],{"className":530},[82,83,137],[57,532,320],{"className":533,"style":319},[82,83,137],[57,535,154],{"className":536},[153],[57,538,540],{"className":539},[117],[57,541,543],{"className":542,"style":161},[121],[57,544],{},[57,546,549],{"className":547},[548],"mclose",")",[57,551],{"className":552,"style":280},[167],[57,554,285],{"className":555},[284],[57,557],{"className":558,"style":280},[167],[57,560,562,565,568,571,574,577,580,583,640,643,646],{"className":561},[73],[57,563],{"className":564,"style":474},[77],[57,566,300],{"className":567},[299],[57,569,523],{"className":570,"style":310},[82,83],[57,572,49],{"className":573},[82,83],[57,575,248],{"className":576,"style":247},[82,83],[57,578,89],{"className":579},[82,83],[57,581,93],{"className":582},[82,83],[57,584,586,590],{"className":585},[82],[57,587,589],{"className":588},[82,83],"d",[57,591,593],{"className":592},[108],[57,594,596,632],{"className":595},[112,113],[57,597,599,629],{"className":598},[117],[57,600,603],{"className":601,"style":602},[121],"height:0.1514em;",[57,604,605,608],{"style":125},[57,606],{"className":607,"style":130},[129],[57,609,611],{"className":610},[134,135,136,137],[57,612,614,618,621,626],{"className":613},[82,137],[57,615,617],{"className":616},[82,83,137],"ma",[57,619,320],{"className":620,"style":319},[82,83,137],[57,622,625],{"className":623,"style":624},[82,83,137],"margin-right:0.03588em;","g",[57,627,327],{"className":628},[82,83,137],[57,630,154],{"className":631},[153],[57,633,635],{"className":634},[117],[57,636,638],{"className":637,"style":161},[121],[57,639],{},[57,641],{"className":642,"style":280},[167],[57,644,390],{"className":645},[284],[57,647],{"className":648,"style":280},[167],[57,650,652,655,658,710],{"className":651},[73],[57,653],{"className":654,"style":295},[77],[57,656,93],{"className":657},[82,83],[57,659,661,664],{"className":660},[82],[57,662,410],{"className":663},[82,83],[57,665,667],{"className":666},[108],[57,668,670,702],{"className":669},[112,113],[57,671,673,699],{"className":672},[117],[57,674,676],{"className":675,"style":423},[121],[57,677,678,681],{"style":125},[57,679],{"className":680,"style":130},[129],[57,682,684],{"className":683},[134,135,136,137],[57,685,687,690,693,696],{"className":686},[82,137],[57,688,199],{"className":689},[82,83,137],[57,691,89],{"className":692},[82,83,137],[57,694,444],{"className":695},[82,83,137],[57,697,104],{"className":698},[82,83,137],[57,700,154],{"className":701},[153],[57,703,705],{"className":704},[117],[57,706,708],{"className":707,"style":381},[121],[57,709],{},[57,711,549],{"className":712},[548],[23,714,715],{},"Vous y avez compris quelque chose ? Ne vous en faites pas, on va expliciter tout ça.",[23,717,718],{},"Gardons en tête que:",[720,721,722,726,729,732,735],"ul",{},[723,724,725],"li",{},"Le plafond de la marge HoppR par mois est fixe.",[723,727,728],{},"Le chiffre d'affaire est la somme du montant des factures, une facture peut être négative (note de frais par exemple).",[723,730,731],{},"Le coût employeur est un taux fixe.",[723,733,734],{},"Le package est l'addition du salaire et du bonus HoppR.",[723,736,737],{},"Si le bonus HoppR est négatif, il est considéré comme nul, autrement dit, le package sera le salaire brut.",[23,739,740,741,746,747,752,753,757],{},"Nous avons décidé de partir sur ",[49,742,745],{"href":743,"rel":744},"https:\u002F\u002Fgleam.run\u002F",[53],"Gleam",", un langage fonctionnel, strictement typé, basé sur ",[49,748,751],{"href":749,"rel":750},"https:\u002F\u002Felixir-lang.org\u002F",[53],"Elixir",". Ce langage offre la possibilité de créer des alias de type, par exemple ",[754,755,756],"code",{},"type MaString = string",". Cette mécanique est une vraie force car elle permet de mettre en évidence les mots clés du métier (ici celui du Package chez HoppR).",[23,759,760,761,764,765,764,768,764,771,764,774,55],{},"On retrouve ainsi des types comme ",[754,762,763],{},"ConsultantId",", ",[754,766,767],{},"Revenue",[754,769,770],{},"GrossSalary",[754,772,773],{},"EmployerRate",[754,775,776],{},"GrossMargin",[23,778,779],{},"Notre service métier de calcul de package va quant à lui s'exprimer sous la forme d'une fonction.",[781,782,787],"pre",{"className":783,"code":784,"language":785,"meta":786,"style":786},"language-elixir shiki shiki-themes github-dark","pub fn calculate_annual_packaging(\n  revenues: List(Revenue),\n  gross_salary: GrossSalary,\n  employer_rate: EmployerRate,\n  max_margin: GrossMargin,\n) -> Package {\n  let employer_cost = gross_salary |> to_employer_cost(employer_rate)\n\n  revenues\n  |> cumulate\n  |> to_gross_margin(employer_cost)\n  |> cap_at(max_margin)\n  |> to_bonus(employer_rate)\n  |> to_package(gross_salary)\n}\n\n\u002F\u002F Quelques exemples de ce à quoi peuvent ressembler les tests du domaine\npub fn only_one_mission_full_time_test() {...}\npub fn three_missions_during_the_year_test() {...}\npub fn package_is_the_gross_salary_when_the_company_loses_money_test() {...}\n","elixir","",[754,788,789,796,802,808,814,820,826,832,839,845,851,857,863,869,875,881,886,892,898,904],{"__ignoreMap":786},[57,790,793],{"class":791,"line":792},"line",1,[57,794,795],{},"pub fn calculate_annual_packaging(\n",[57,797,799],{"class":791,"line":798},2,[57,800,801],{},"  revenues: List(Revenue),\n",[57,803,805],{"class":791,"line":804},3,[57,806,807],{},"  gross_salary: GrossSalary,\n",[57,809,811],{"class":791,"line":810},4,[57,812,813],{},"  employer_rate: EmployerRate,\n",[57,815,817],{"class":791,"line":816},5,[57,818,819],{},"  max_margin: GrossMargin,\n",[57,821,823],{"class":791,"line":822},6,[57,824,825],{},") -> Package {\n",[57,827,829],{"class":791,"line":828},7,[57,830,831],{},"  let employer_cost = gross_salary |> to_employer_cost(employer_rate)\n",[57,833,835],{"class":791,"line":834},8,[57,836,838],{"emptyLinePlaceholder":837},true,"\n",[57,840,842],{"class":791,"line":841},9,[57,843,844],{},"  revenues\n",[57,846,848],{"class":791,"line":847},10,[57,849,850],{},"  |> cumulate\n",[57,852,854],{"class":791,"line":853},11,[57,855,856],{},"  |> to_gross_margin(employer_cost)\n",[57,858,860],{"class":791,"line":859},12,[57,861,862],{},"  |> cap_at(max_margin)\n",[57,864,866],{"class":791,"line":865},13,[57,867,868],{},"  |> to_bonus(employer_rate)\n",[57,870,872],{"class":791,"line":871},14,[57,873,874],{},"  |> to_package(gross_salary)\n",[57,876,878],{"class":791,"line":877},15,[57,879,880],{},"}\n",[57,882,884],{"class":791,"line":883},16,[57,885,838],{"emptyLinePlaceholder":837},[57,887,889],{"class":791,"line":888},17,[57,890,891],{},"\u002F\u002F Quelques exemples de ce à quoi peuvent ressembler les tests du domaine\n",[57,893,895],{"class":791,"line":894},18,[57,896,897],{},"pub fn only_one_mission_full_time_test() {...}\n",[57,899,901],{"class":791,"line":900},19,[57,902,903],{},"pub fn three_missions_during_the_year_test() {...}\n",[57,905,907],{"class":791,"line":906},20,[57,908,909],{},"pub fn package_is_the_gross_salary_when_the_company_loses_money_test() {...}\n",[23,911,912,913,916,917,920],{},"Ici la lecture de la règle de calcul se voit facilitée par l'usage du ",[30,914,915],{},"pipe operator"," ",[754,918,919],{},"|>"," qui envoie dans le premier argument de la fonction du dessous le résultat de la fonction du dessus.",[23,922,923,924,927],{},"On peut donc lire le code comme on le ferait en langage naturel: on cumule les ",[754,925,926],{},"revenues"," auquel on applique une marge brute capée à la marge max. On applique le bonus si bonus il y a et on transforme le tout en package final.",[23,929,930],{},"La logique métier est explicite, pure et déterministe.",[932,933,935],"h4",{"id":934},"aparté-sur-les-value-objects-et-le-pipe-operator","Aparté sur les value objects et le pipe operator",[23,937,938,939,944,945,55],{},"Pour éviter le ",[49,940,943],{"href":941,"rel":942},"https:\u002F\u002Frefactoring.guru\u002Ffr\u002Fsmells\u002Fprimitive-obsession",[53],"primitive obsession"," et mettre en évidence les concepts du vocabulaire métier, nous créons ce que l'on appelle des ",[946,947,948],"strong",{},"value objects",[23,950,951],{},"Dans la programmation orientée objet, nous aurions quelque chose comme:",[781,953,957],{"className":954,"code":955,"language":956,"meta":786,"style":786},"language-java shiki shiki-themes github-dark","record Revenue(BigDecimal amount) {}\n\nrecord Revenues(List\u003CRevenue> revenues) {\n    public Revenue cumulate() {\n        return new Revenue(revenues.stream()\n                .map(Revenue::amount)\n                .reduce(BigDecimal.ZERO, BigDecimal::add));\n    }\n}\n","java",[754,958,959,973,977,998,1012,1031,1048,1063,1068],{"__ignoreMap":786},[57,960,961,965,969],{"class":791,"line":792},[57,962,964],{"class":963},"snl16","record",[57,966,968],{"class":967},"svObZ"," Revenue",[57,970,972],{"class":971},"s95oV","(BigDecimal amount) {}\n",[57,974,975],{"class":791,"line":798},[57,976,838],{"emptyLinePlaceholder":837},[57,978,979,981,984,987,990,992,995],{"class":791,"line":804},[57,980,964],{"class":963},[57,982,983],{"class":967}," Revenues",[57,985,986],{"class":971},"(List",[57,988,989],{"class":963},"\u003C",[57,991,767],{"class":971},[57,993,994],{"class":963},">",[57,996,997],{"class":971}," revenues) {\n",[57,999,1000,1003,1006,1009],{"class":791,"line":810},[57,1001,1002],{"class":963},"    public",[57,1004,1005],{"class":971}," Revenue ",[57,1007,1008],{"class":967},"cumulate",[57,1010,1011],{"class":971},"() {\n",[57,1013,1014,1017,1020,1022,1025,1028],{"class":791,"line":816},[57,1015,1016],{"class":963},"        return",[57,1018,1019],{"class":963}," new",[57,1021,968],{"class":967},[57,1023,1024],{"class":971},"(revenues.",[57,1026,1027],{"class":967},"stream",[57,1029,1030],{"class":971},"()\n",[57,1032,1033,1036,1039,1042,1045],{"class":791,"line":822},[57,1034,1035],{"class":971},"                .",[57,1037,1038],{"class":967},"map",[57,1040,1041],{"class":971},"(Revenue",[57,1043,1044],{"class":963},"::",[57,1046,1047],{"class":971},"amount)\n",[57,1049,1050,1052,1055,1058,1060],{"class":791,"line":828},[57,1051,1035],{"class":971},[57,1053,1054],{"class":967},"reduce",[57,1056,1057],{"class":971},"(BigDecimal.ZERO, BigDecimal",[57,1059,1044],{"class":963},[57,1061,1062],{"class":971},"add));\n",[57,1064,1065],{"class":791,"line":834},[57,1066,1067],{"class":971},"    }\n",[57,1069,1070],{"class":791,"line":841},[57,1071,880],{"class":971},[23,1073,1074],{},"L'objet expose ses propres méthodes pour pouvoir faire des opérations métiers. Cela impose que toute nouvelle opération soit portée par le dit value object. Le pipe operator permet d'étendre les possibilités du concept sans modifier le concept lui-même.\nCeci offre une vraie flexibilité, de la lisibilité. C'est la composition fonctionnelle !",[41,1076,1078],{"id":1077},"services-purs-et-dépendances-explicites","Services purs et dépendances explicites",[23,1080,1081],{},"Le use case principal dépend de données externes (financier + paie). En programmation fonctionnelle, ces dépendances sont injectées via des fonctions :",[781,1083,1085],{"className":783,"code":1084,"language":785,"meta":786,"style":786},"pub type GetFinancialDataPort =\n  fn(ConsultantId) -> FinancialData\npub type GetCompanyPayrollDataPort =\n  fn() -> CompanyPayrollData\n\npub fn calculate_consultant_annual_packaging(\n  consultant_id: ConsultantId,\n  get_financial_data: GetFinancialDataPort,\n  get_company_payroll_data: GetCompanyPayrollDataPort,\n) {\n  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une api externe\n  let CompanyPayrollDataPort(employer_rate, max_margin) = get_company_payroll_data()\n  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une base de données\n  let FinancialDataPort(revenues, gross_salary) = get_financial_data(consultant_id)\n  calculate_annual_packaging(revenues, gross_salary, employer_rate, max_margin)\n}\n",[754,1086,1087,1092,1097,1102,1107,1111,1116,1121,1126,1131,1136,1141,1146,1151,1156,1161],{"__ignoreMap":786},[57,1088,1089],{"class":791,"line":792},[57,1090,1091],{},"pub type GetFinancialDataPort =\n",[57,1093,1094],{"class":791,"line":798},[57,1095,1096],{},"  fn(ConsultantId) -> FinancialData\n",[57,1098,1099],{"class":791,"line":804},[57,1100,1101],{},"pub type GetCompanyPayrollDataPort =\n",[57,1103,1104],{"class":791,"line":810},[57,1105,1106],{},"  fn() -> CompanyPayrollData\n",[57,1108,1109],{"class":791,"line":816},[57,1110,838],{"emptyLinePlaceholder":837},[57,1112,1113],{"class":791,"line":822},[57,1114,1115],{},"pub fn calculate_consultant_annual_packaging(\n",[57,1117,1118],{"class":791,"line":828},[57,1119,1120],{},"  consultant_id: ConsultantId,\n",[57,1122,1123],{"class":791,"line":834},[57,1124,1125],{},"  get_financial_data: GetFinancialDataPort,\n",[57,1127,1128],{"class":791,"line":841},[57,1129,1130],{},"  get_company_payroll_data: GetCompanyPayrollDataPort,\n",[57,1132,1133],{"class":791,"line":847},[57,1134,1135],{},") {\n",[57,1137,1138],{"class":791,"line":853},[57,1139,1140],{},"  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une api externe\n",[57,1142,1143],{"class":791,"line":859},[57,1144,1145],{},"  let CompanyPayrollDataPort(employer_rate, max_margin) = get_company_payroll_data()\n",[57,1147,1148],{"class":791,"line":865},[57,1149,1150],{},"  \u002F\u002F ici l'implémentation de la fonction va chercher l'info dans une base de données\n",[57,1152,1153],{"class":791,"line":871},[57,1154,1155],{},"  let FinancialDataPort(revenues, gross_salary) = get_financial_data(consultant_id)\n",[57,1157,1158],{"class":791,"line":877},[57,1159,1160],{},"  calculate_annual_packaging(revenues, gross_salary, employer_rate, max_margin)\n",[57,1162,1163],{"class":791,"line":883},[57,1164,880],{},[23,1166,1167],{},"Les ports sont des types de fonctions, et la composition des règles reste locale au domaine. Le métier ne dépend d'aucune techno (HTTP, DB, etc.).",[932,1169,1171],{"id":1170},"et-en-programmation-orientée-objet","Et en programmation orientée objet",[23,1173,1174],{},"En Java, on représente les mêmes concepts via des records, classes et interfaces. Le vocabulaire métier est identique, mais l'encapsulation se fait par objets plutôt que par des fonctions.",[781,1176,1178],{"className":954,"code":1177,"language":956,"meta":786,"style":786},"public interface FinancialDataPort {\n  FinancialData forConsultant(ConsultantId consultantId);\n}\n\npublic interface CompanyPayrollPort {\n  CompanyPayrollData get();\n}\n\npublic final class PackageCalculator {\n  private final FinancialDataPort financialDataPort;\n  private final CompanyPayrollPort payrollDataPort;\n\n  public PackageCalculator(FinancialDataPort financialDataPort,\n                           CompanyPayrollPort payrollDataPort) {\n    this.financialDataPort = financialDataPort;\n    this.payrollDataPort = payrollDataPort;\n  }\n\n  public Package calculateFor(ConsultantId consultantId) {\n    var payroll = payrollDataPort.get();\n    var financial = financialDataPort.forConsultant(consultantId);\n    return calculateAnnualPackaging(\n      financial.revenues(),\n      financial.grossSalary(),\n      payroll.employerRate(),\n      payroll.maxMargin()\n    );\n  }\n\n  private Package calculateAnnualPackaging(\n    Revenues revenues,\n    GrossSalary grossSalary,\n    EmployerRate employerRate,\n    GrossMargin maxMargin\n  ) {\n    var employerCost = grossSalary.multiply(employerRate);\n    var grossMargin = revenues.subtract(employerCost);\n    var cappedMargin = grossMargin.subtract(maxMargin);\n    var bonus = cappedMargin.apply(employerRate);\n    var total = grossSalary.add(bonus);\n\n    return new Package(\n      bonus,\n      grossSalary,\n      total\n    );\n  }\n}\n",[754,1179,1180,1194,1212,1216,1220,1231,1242,1246,1250,1265,1275,1284,1288,1304,1314,1328,1340,1345,1349,1365,1382,1400,1412,1423,1433,1444,1454,1460,1465,1470,1482,1492,1502,1512,1521,1527,1546,1565,1583,1601,1619,1624,1636,1642,1648,1654,1659,1664],{"__ignoreMap":786},[57,1181,1182,1185,1188,1191],{"class":791,"line":792},[57,1183,1184],{"class":963},"public",[57,1186,1187],{"class":963}," interface",[57,1189,1190],{"class":967}," FinancialDataPort",[57,1192,1193],{"class":971}," {\n",[57,1195,1196,1199,1202,1205,1209],{"class":791,"line":798},[57,1197,1198],{"class":971},"  FinancialData ",[57,1200,1201],{"class":967},"forConsultant",[57,1203,1204],{"class":971},"(ConsultantId ",[57,1206,1208],{"class":1207},"s9osk","consultantId",[57,1210,1211],{"class":971},");\n",[57,1213,1214],{"class":791,"line":804},[57,1215,880],{"class":971},[57,1217,1218],{"class":791,"line":810},[57,1219,838],{"emptyLinePlaceholder":837},[57,1221,1222,1224,1226,1229],{"class":791,"line":816},[57,1223,1184],{"class":963},[57,1225,1187],{"class":963},[57,1227,1228],{"class":967}," CompanyPayrollPort",[57,1230,1193],{"class":971},[57,1232,1233,1236,1239],{"class":791,"line":822},[57,1234,1235],{"class":971},"  CompanyPayrollData ",[57,1237,1238],{"class":967},"get",[57,1240,1241],{"class":971},"();\n",[57,1243,1244],{"class":791,"line":828},[57,1245,880],{"class":971},[57,1247,1248],{"class":791,"line":834},[57,1249,838],{"emptyLinePlaceholder":837},[57,1251,1252,1254,1257,1260,1263],{"class":791,"line":841},[57,1253,1184],{"class":963},[57,1255,1256],{"class":963}," final",[57,1258,1259],{"class":963}," class",[57,1261,1262],{"class":967}," PackageCalculator",[57,1264,1193],{"class":971},[57,1266,1267,1270,1272],{"class":791,"line":847},[57,1268,1269],{"class":963},"  private",[57,1271,1256],{"class":963},[57,1273,1274],{"class":971}," FinancialDataPort financialDataPort;\n",[57,1276,1277,1279,1281],{"class":791,"line":853},[57,1278,1269],{"class":963},[57,1280,1256],{"class":963},[57,1282,1283],{"class":971}," CompanyPayrollPort payrollDataPort;\n",[57,1285,1286],{"class":791,"line":859},[57,1287,838],{"emptyLinePlaceholder":837},[57,1289,1290,1293,1295,1298,1301],{"class":791,"line":865},[57,1291,1292],{"class":963},"  public",[57,1294,1262],{"class":967},[57,1296,1297],{"class":971},"(FinancialDataPort ",[57,1299,1300],{"class":1207},"financialDataPort",[57,1302,1303],{"class":971},",\n",[57,1305,1306,1309,1312],{"class":791,"line":871},[57,1307,1308],{"class":971},"                           CompanyPayrollPort ",[57,1310,1311],{"class":1207},"payrollDataPort",[57,1313,1135],{"class":971},[57,1315,1316,1320,1323,1325],{"class":791,"line":877},[57,1317,1319],{"class":1318},"sDLfK","    this",[57,1321,1322],{"class":971},".financialDataPort ",[57,1324,173],{"class":963},[57,1326,1327],{"class":971}," financialDataPort;\n",[57,1329,1330,1332,1335,1337],{"class":791,"line":883},[57,1331,1319],{"class":1318},[57,1333,1334],{"class":971},".payrollDataPort ",[57,1336,173],{"class":963},[57,1338,1339],{"class":971}," payrollDataPort;\n",[57,1341,1342],{"class":791,"line":888},[57,1343,1344],{"class":971},"  }\n",[57,1346,1347],{"class":791,"line":894},[57,1348,838],{"emptyLinePlaceholder":837},[57,1350,1351,1353,1356,1359,1361,1363],{"class":791,"line":900},[57,1352,1292],{"class":963},[57,1354,1355],{"class":971}," Package ",[57,1357,1358],{"class":967},"calculateFor",[57,1360,1204],{"class":971},[57,1362,1208],{"class":1207},[57,1364,1135],{"class":971},[57,1366,1367,1370,1373,1375,1378,1380],{"class":791,"line":906},[57,1368,1369],{"class":963},"    var",[57,1371,1372],{"class":971}," payroll ",[57,1374,173],{"class":963},[57,1376,1377],{"class":971}," payrollDataPort.",[57,1379,1238],{"class":967},[57,1381,1241],{"class":971},[57,1383,1385,1387,1390,1392,1395,1397],{"class":791,"line":1384},21,[57,1386,1369],{"class":963},[57,1388,1389],{"class":971}," financial ",[57,1391,173],{"class":963},[57,1393,1394],{"class":971}," financialDataPort.",[57,1396,1201],{"class":967},[57,1398,1399],{"class":971},"(consultantId);\n",[57,1401,1403,1406,1409],{"class":791,"line":1402},22,[57,1404,1405],{"class":963},"    return",[57,1407,1408],{"class":967}," calculateAnnualPackaging",[57,1410,1411],{"class":971},"(\n",[57,1413,1415,1418,1420],{"class":791,"line":1414},23,[57,1416,1417],{"class":971},"      financial.",[57,1419,926],{"class":967},[57,1421,1422],{"class":971},"(),\n",[57,1424,1426,1428,1431],{"class":791,"line":1425},24,[57,1427,1417],{"class":971},[57,1429,1430],{"class":967},"grossSalary",[57,1432,1422],{"class":971},[57,1434,1436,1439,1442],{"class":791,"line":1435},25,[57,1437,1438],{"class":971},"      payroll.",[57,1440,1441],{"class":967},"employerRate",[57,1443,1422],{"class":971},[57,1445,1447,1449,1452],{"class":791,"line":1446},26,[57,1448,1438],{"class":971},[57,1450,1451],{"class":967},"maxMargin",[57,1453,1030],{"class":971},[57,1455,1457],{"class":791,"line":1456},27,[57,1458,1459],{"class":971},"    );\n",[57,1461,1463],{"class":791,"line":1462},28,[57,1464,1344],{"class":971},[57,1466,1468],{"class":791,"line":1467},29,[57,1469,838],{"emptyLinePlaceholder":837},[57,1471,1473,1475,1477,1480],{"class":791,"line":1472},30,[57,1474,1269],{"class":963},[57,1476,1355],{"class":971},[57,1478,1479],{"class":967},"calculateAnnualPackaging",[57,1481,1411],{"class":971},[57,1483,1485,1488,1490],{"class":791,"line":1484},31,[57,1486,1487],{"class":971},"    Revenues ",[57,1489,926],{"class":1207},[57,1491,1303],{"class":971},[57,1493,1495,1498,1500],{"class":791,"line":1494},32,[57,1496,1497],{"class":971},"    GrossSalary ",[57,1499,1430],{"class":1207},[57,1501,1303],{"class":971},[57,1503,1505,1508,1510],{"class":791,"line":1504},33,[57,1506,1507],{"class":971},"    EmployerRate ",[57,1509,1441],{"class":1207},[57,1511,1303],{"class":971},[57,1513,1515,1518],{"class":791,"line":1514},34,[57,1516,1517],{"class":971},"    GrossMargin ",[57,1519,1520],{"class":1207},"maxMargin\n",[57,1522,1524],{"class":791,"line":1523},35,[57,1525,1526],{"class":971},"  ) {\n",[57,1528,1530,1532,1535,1537,1540,1543],{"class":791,"line":1529},36,[57,1531,1369],{"class":963},[57,1533,1534],{"class":971}," employerCost ",[57,1536,173],{"class":963},[57,1538,1539],{"class":971}," grossSalary.",[57,1541,1542],{"class":967},"multiply",[57,1544,1545],{"class":971},"(employerRate);\n",[57,1547,1549,1551,1554,1556,1559,1562],{"class":791,"line":1548},37,[57,1550,1369],{"class":963},[57,1552,1553],{"class":971}," grossMargin ",[57,1555,173],{"class":963},[57,1557,1558],{"class":971}," revenues.",[57,1560,1561],{"class":967},"subtract",[57,1563,1564],{"class":971},"(employerCost);\n",[57,1566,1568,1570,1573,1575,1578,1580],{"class":791,"line":1567},38,[57,1569,1369],{"class":963},[57,1571,1572],{"class":971}," cappedMargin ",[57,1574,173],{"class":963},[57,1576,1577],{"class":971}," grossMargin.",[57,1579,1561],{"class":967},[57,1581,1582],{"class":971},"(maxMargin);\n",[57,1584,1586,1588,1591,1593,1596,1599],{"class":791,"line":1585},39,[57,1587,1369],{"class":963},[57,1589,1590],{"class":971}," bonus ",[57,1592,173],{"class":963},[57,1594,1595],{"class":971}," cappedMargin.",[57,1597,1598],{"class":967},"apply",[57,1600,1545],{"class":971},[57,1602,1604,1606,1609,1611,1613,1616],{"class":791,"line":1603},40,[57,1605,1369],{"class":963},[57,1607,1608],{"class":971}," total ",[57,1610,173],{"class":963},[57,1612,1539],{"class":971},[57,1614,1615],{"class":967},"add",[57,1617,1618],{"class":971},"(bonus);\n",[57,1620,1622],{"class":791,"line":1621},41,[57,1623,838],{"emptyLinePlaceholder":837},[57,1625,1627,1629,1631,1634],{"class":791,"line":1626},42,[57,1628,1405],{"class":963},[57,1630,1019],{"class":963},[57,1632,1633],{"class":967}," Package",[57,1635,1411],{"class":971},[57,1637,1639],{"class":791,"line":1638},43,[57,1640,1641],{"class":971},"      bonus,\n",[57,1643,1645],{"class":791,"line":1644},44,[57,1646,1647],{"class":971},"      grossSalary,\n",[57,1649,1651],{"class":791,"line":1650},45,[57,1652,1653],{"class":971},"      total\n",[57,1655,1657],{"class":791,"line":1656},46,[57,1658,1459],{"class":971},[57,1660,1662],{"class":791,"line":1661},47,[57,1663,1344],{"class":971},[57,1665,1667],{"class":791,"line":1666},48,[57,1668,880],{"class":971},[23,1670,1671],{},"Le cœur métier reste le même : règles, vocabulaire, invariants. Les dépendances sont injectées depuis l'extérieur du domaine.",[23,1673,1674],{},"Finalement, seule la forme change.",[41,1676,1678],{"id":1677},"conclusion","Conclusion",[23,1680,1681,1682,1685],{},"En programmation fonctionnelle, les règles sont pures et les dépendances explicites.En programmation objet, elles sont encapsulées dans des objets et des interfaces.  Dans l’un comme dans l’autre, l’architecture hexagonale s’y applique de manière égale: le métier et son vocabulaire au centre de l’application. Autrement dit, c",[946,1683,1684],{},"e n'est pas parce qu'on ne fait que des fonctions qu'il n'y a pas d'architecture en couches: on peut clairement distinguer le domaine métier de l'infrastructure."," La programmation fonctionnelle n'est donc pas un obstacle à la valorisation du métier dans le code. Elle peut au contraire rendre le vocabulaire plus lisible et les règles plus testables.",[1687,1688,1689],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":786,"searchDepth":798,"depth":798,"links":1691},[1692,1693,1694],{"id":43,"depth":804,"text":44},{"id":1077,"depth":804,"text":1078},{"id":1677,"depth":804,"text":1678},"2026-04-08T07:34:28.327Z","À mesure que les systèmes logiciels gagnent en complexité, les approches traditionnelles de conception montrent leurs limites. Couplage excessif, difficulté à tester, rigidité face au changement : aut","md",".\u002Fassets\u002Fcover-image.webp",{},"\u002Fblogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit",[1702,1707,1713],{"id":1703,"name":1704,"image":1705,"linkedin":1706,"x":18},"0bb914a6-f882-4951-bee6-53e8e8abb807","Emmanuelle Gouvart","https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc88f5dfa-16db-4e6f-acf1-34dd80ee8766\u002Femma_hoppr.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466YZGE5L65%2F20260408%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260408T073428Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEC4aCXVzLXdlc3QtMiJHMEUCIQC89XiI4LV2nPeP5GwelaGxITa1i8vxE7nDPN%2FCOOIGPAIgIMuadU2XMtNuvRqanOfvVI6kHru%2B2YCLP1W9z9BRL6UqiAQI9%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDMWjV%2FO1zt1H6KDcMCrcA7q8rYPD7JArUtRE2XmtlGFi0Gb1u2jY%2B9Y3SPAbwzgUQRWQ1LEqXfyjuHcnYUj6O%2BiWWlqVuXmzWt1l7lG5Y7arPfzt6AjsXPmIzlmAvYMctlE1uESBOaThTr8QcjJR42skKrqwlIVe%2FFOfTIaN80P8yI23zbwYPGbrre3Q34lTWnE77vQ1FHlDAEnF4q6vCNLknS7i4J4vDz%2FPhtjrQMHSV1BSwg4czuhoUylgbdW1CL8HRfEeFraXH3AJ4wGhuMoxGCakNRvrw7KrF0jpzkULBEC4PwztMJcaWUnD6T2miI%2FUuL5g7ASMT7NtTPiiRFtg3beSatik6dY6JMEdSVElz5yspss5kTYq8YsIQlT8tLRejU4zgp78leO47JOHzmJnro2wd9YdGm%2BEqqiHPsku1HbLTV3oHwYEtPB9FBFqSC9V8AbocksXRXhfmXn8WnZbebEXMu7XiIp%2BiZjIcQC9Brq%2BicBi7iHaUQoAljN8RHny0jm%2FGsm4PRQNiCYbWJnmahrKNRWNkP5RiXqGZnjsXHInBSqkupWnekY9Bd9Vd11JiKSuGkj2ebN%2BuuF4KEtNARclVCjiTEQDt6jwpswqxeH4fTDflh5XXLwZvxU6RIJ1tjcQWwAxRLGRMObb184GOqUB6QApw17fi31uRcyevbEhsIVcF7cbhz5DT9rK2wxOH0%2FJF55Z%2BYpWz%2FPU%2B5b2R7H0t6SkCITFdxrerbjTKeo3ANn6Maeo3qDIWvnyFCzBZT4MaZW3wqjClgUj7X3KTeNPimG82xZWapTks839ysnOLg36HeDcQuWXHFJ73l4hJVzt84hWxgfsDVAj2LWIvdLzbEUnbJwlOUNalA4bSFXi3%2B%2BZSVGf&X-Amz-Signature=b23db6b30ffaf694e97c7283799bfd5930ff0c8de4e984d08997a4e68c32080e&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Femmanuellegouvart-182b6ab2\u002F",{"id":1708,"name":1709,"image":1710,"linkedin":1711,"x":1712},"838dec96-f9fc-404f-a302-07719225d785","Maxime Deroullers","https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002Fc69d0b59-558d-4e48-879f-bea3fec1fdef\u002FLinkedin_Profile.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466XRONKPNZ%2F20260408%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260408T073428Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEDAaCXVzLXdlc3QtMiJIMEYCIQDm83y7rflR2VODU5aP5Qz692idMY%2BBAiAN%2BSxy%2BIDx8QIhAOa4gMORM%2FaT6TWEmlAYAB1EFUTqVOd8ObAa36VRLn1ZKogECPn%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEQABoMNjM3NDIzMTgzODA1Igx2JIBqc1%2BH7MVdyPMq3AMwmiKyWYDt3nYnDnPmTWKFpHTuLOkgcCjGctfi8lEGyGwb8HnDFp3AGSj883xVmpSFG3ov9Gr0jbfhSvKTLITWxqJygrQWcaGjzsOJf2a%2BCJ1YrRQsGcOq9WQmDm%2BZhHrG5pNgk31O2f2hxAQP8kGkOC8Jxgz5i%2ByBwCv2fghEPKWCxHIu%2FnLv%2FhXKVET9jUK6L6WptG48fnveHprIygQH86y8dPYXMgAN9T0vx6kBoo%2B08NKPdTqNPAVqVyc9pqmixVE5%2FYYWUF9bJj3TbgGOM7nD84%2FvSBbwXZ6tNimPrdF1CmwsAID4sHly9nv3xvml6AWX09lwlYBpvChHrg88DKCJyzlX3fQoIJuUFMssgpP06IgkjTu%2Fnr3Xn5uGFTrIfL5rQ%2BzaYK%2FZEydEOzHikjrCo7K6xcZ52KaSP60Vn9BeslZ59%2BgDLrczqnXYc%2BKmYDxA%2BOsXObXQid1ODmY8uyRcVIogTAZZXhZ0A%2Bi4Jab9uw4tYXRJe%2BrKHn2xyU6qVUV8Yk%2BfK6ZiFWDz2V%2BwgHyegcnDoE%2BS2x1ckw6xTTeoJTZLnLrQOfKKsfbUnZhS%2Bz9vc1iZ%2BvyfWl4WCQPtFwu3AbDHGveoR2wvwgkrm1njJEU%2BkGJmdJJuszC5iNjOBjqkAYLjzrk9PZ61PMzHm%2FL6BGmd9EAJ05SyolUKGsI0gCLqm4I0mFF9BvGTn7y679fSfLS7vBM%2FDT1t2h5TD0H1yXt66PKQIFXPPMIFEQkFoMF4JwsmgNsAwbBRkURagTfGs50qrviYMBbEFKlnmiB4x%2FWI0IOonbk9v0ZBs7OlLZJHOwHgH5nN9Z1KuBEUGhdP9V%2B4zpiZTAlCThrQxBqa1eSxr%2FZb&X-Amz-Signature=ebff0fd05509337077f565c3ea9b944db6f15a3995bdd1bdfb7c90fa020e82fb&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fmaxime-deroullers-1b5791137\u002F","https:\u002F\u002Fx.com\u002Fmderoullers",{"id":1714,"name":1715,"image":1716,"linkedin":1717,"x":18},"67adfd77-4b84-4496-b55d-3391541f59c5","Michaël Bernasinski","https:\u002F\u002Fprod-files-secure.s3.us-west-2.amazonaws.com\u002F5863e833-64f2-4f13-9f7a-2c92c72b5bbf\u002F1f0a6cf7-edf2-44dc-babb-f1624e4f52b0\u002FPhoto_profil.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=ASIAZI2LB466WIK4JRTG%2F20260408%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260408T073428Z&X-Amz-Expires=3600&X-Amz-Security-Token=IQoJb3JpZ2luX2VjEC4aCXVzLXdlc3QtMiJHMEUCICuqELPi893QSyfwnyFTnMqcLUW8j4oiAxjFNZ3gFDtCAiEAgcg%2BHl1dGG5cM0uNfUCb0JlwgkzZ9eZmwtsFG5AyCuMqiAQI9%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARAAGgw2Mzc0MjMxODM4MDUiDGHa9MlsDbZfN%2FYCKircA5gcGnNJ%2FBjl5mcv6g1TMFzbf7dYZESahFgAifbuK%2BBonIuiW%2FfR%2BTBODtvfbiNDgpbOjHteJv7%2FLOgZgpSP1epkw0qahEvYFogVnIgmzLd1roYHs626IPYVOS0RunsFyTGcQwSmc6hVyS4pfODT4OKwUE7EiGUqaQWg%2Fj7j12kZ2vv1FnXda7kxpzNDmLuLzlZp70ozboHb6%2FOUf3BhqdOVAAb1Y%2BK2xHnkdYAr%2BPVJ0v5qUPazBQAtUzMVwAgYxG2JugfVSn2sofk97v9b5pcJIhED4A4Cob%2F21PV2d9RiMTHjuKP2GoO6t96A%2BwpXcyFgb4GLlGugrJ%2B40w0Joq8w3Pfd0SayKfc72LE3%2B0NgPDdD3%2BPBxX8e6RYAxjGHSwwxoqXn0rwbRoa5e94lavTTwWEGXmlhJK6vyL7oMNAh76VCuiKU8zQR9iO4PwyYCOeyYXmwY9uSsjv1Xhnl5Jm6VsP%2BKqUR%2Bm8WmG3%2FSIxpZt0kkz2aF82DYYtBr0odjMLSWzxkezG0APvFa%2F%2FG%2B05zRflCS2EHTC7c3KyVP%2FO0Oz7QkF5vuXU%2F2fPrV4W1%2FSaX6M1s4y8UbTneRMlxLoqt5JSLJAsGyo6eo50VIh%2FeKCkQymrPWjIEIkaIMO7a184GOqUBK3sKSMU%2BE8%2FdgcSKNfCHNWUjsc3Q4%2FwCLEpB3gKjjU2rM9gS1cUnM9ROHr0wmcL3WKMsNhQ0m48hnO45ibaQ7AuaY9YmTTVOucTGGtqI6%2BQ%2FzksdZtEIgKbuMSFIR4TAp0QnGLKg%2B38rtJH3GS%2FB41z21vB74NsTbOLmVnnRN7b%2BUxPfPhInd7VMo9OVUSCVgqOXPGht2WN3qTzRkojiBxAGb%2FIq&X-Amz-Signature=03e3a75c38948c108cfd727f230ff460bccfea1ad49530d77d843f9e4556e253&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fmichael-bernasinski",{"title":5,"description":1696},"blogs\u002F2026-04-08-architecture-hexagonale-en-programmation-fonctionnelle-mythe-ou-ralit\u002Findex",[1721],"craft","h9TrKendXF-dLZtHOF8U8GSllWbkJmopLp7WpNFSkx0",[1724,1733,1740,1749],{"path":1725,"title":1726,"image":1727,"date":1728,"tags":1729},"\u002Fblogs\u002F2026-02-03-le-manifeste-du-platform-craftsmanship-lengagement-hoppr","Le Manifeste du Platform Craftsmanship : L'engagement HoppR","\u002Fcontent-assets\u002F2026-02-03-le-manifeste-du-platform-craftsmanship-lengagement-hoppr\u002Fassets\u002Fcover-image.webp","3 février 2026",[1730,1731,1721,1732],"plateform engineering","cloud-platform","devops",{"path":1734,"title":1735,"image":1736,"date":1737,"tags":1738},"\u002Fblogs\u002F2026-01-14-devbox-ou-comment-enfin-onboarder-un-dev-en-5min-chrono-sur-son-projet","Devbox, ou comment (enfin) onboarder un dev en 5min chrono sur son projet","\u002Fcontent-assets\u002F2026-01-14-devbox-ou-comment-enfin-onboarder-un-dev-en-5min-chrono-sur-son-projet\u002Fassets\u002Fcover-image.webp","14 janvier 2026",[1732,1731,1721,1739],"veille tech",{"path":1741,"title":1742,"image":1743,"date":1744,"tags":1745},"\u002Fblogs\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon","Alors ? C’était comment ce premier DevFest Lyon ?","\u002Fcontent-assets\u002F2025-12-02-alors-ctait-comment-ce-premier-devfest-lyon\u002Fassets\u002Fcover-image.webp","2 décembre 2025",[1721,1746,1747,1748,1739],"ia","événement","2025",{"path":1750,"title":1751,"image":1752,"date":1753,"tags":1754},"\u002Fblogs\u002F2025-08-01-refactorer-sans-casser-le-golden-master-appliqu-un-outil-finops","Refactorer sans casser : le Golden Master appliqué à un outil FinOPS","\u002Fcontent-assets\u002F2025-08-01-refactorer-sans-casser-le-golden-master-appliqu-un-outil-finops\u002Fassets\u002Fcover-image.webp","1 août 2025",[1721,1739,1755,1756],"test","testing",1775661202788]