Programmez! 2022 09 10
Programmez! 2022 09 10
d e s
m a g a z i n e
L e
N°254
2022
09/10
3’:HIKONB=^U[^^X:?a@c@p@e@k";
M 04319 - 254 - F: 6,99 E - RD
... Gradient ... NextJS ... VPN ... Hydra ... Anthos ...
Printed in EU - Imprimé en UE - BELGIQUE 7,50 € - Canada 10,55 $ CAN - SUISSE 14,10 FS - DOM Surf 8,10 € - TOM 1100 XPF - MAROC 59 DH
EDITO
#254
L’innovation,
une question de point de vue ?
• Eh ! Rex (le dinosaure aimait donner des surnoms), as tu vu la Après il y a eu boum, boom et boum, en d’autres termes la Seconde
météorique ce matin ? Guerre Mondiale, qui a engendré une révolution sur le plan technique :
• Oui Rex (bon après on n’a jamais dit que les surnoms étaient variés), une carburant de synthèse, naissance de l’informatique au sens moderne du
de plus. terme, naissance des langages de programmation (Conrad Zuse),
Et non, celle de trop ! Bye bye Dino T-rex, hello Moby-dick. technologie de guidage et des fusées, cryptographie, naissance du métier
de hacker, projet Manhattan, Roswell (la zone 51 pas la série), …
Vers 3300 av. J.-C., invention de l’écriture avec en même temps la
phobie administrative, puis invention de l’écriture minuscule (dite Caroline) Dans les années 60, Apollo 11 permet de mieux définir le métier de
au 8e siècle sous l’école Palatine (mais non pas Palpatine, rien à voir… programmeur, on entend parler de la miniaturisation, on voit la naissance
*soupir*). d’Intel et on commence à expliquer partiellement la notion d’ordinateur
Depuis on écrit plus vite, mais les micro-ordinateurs ont mis plusieurs « portable ».
années à gérer à la fois la majuscule ET la minuscule (il fallait réécrire le
code de l’OS et beaucoup plus de mémoire) Et puis, un beau jour au XXIe siècle, arrivent l’iPhone et la
révolution mobile !
Vers 105 après J.-C. découverte en Chine de la pâte à papier et de BlackBerry, Nokia, Microsoft prédisent l’échec du “truc” d’Apple.
l’imprimerie au XVe siècle. Le résultat est sans appel, elle conduit à la Visiblement à trop critiquer, ils ont un peu loupé le coche et perdent le
grève des copistes et des fabricants de papyrus, mais pour le plus grand marché du mobile. Google va rebooter Android (une obscure start-up
bonheur de ce qu’on appellera bien plus tard les bibliophiles, cela rachetée) en OS mobile… Création de l’App Store, dématérialisation de la
enclenche la diffusion “massive” des écrits. notion de logiciels.
Au même siècle (1487-1490), visionnaire, De Vinci conçoit les plans de Une autre manière de consommer l’informatique
la vis aérienne, il faudra attendre 3 siècles pour voir les premiers hommes L’innovation est une notion complexe et difficile. Vous avez la technologie,
“voler”... En Avi…Ah pas encore…Restons à la montgolfière (les frères la technique, les utilisateurs et l’impact sociétal. Mais au cœur de ces
Montgolfier). innovations, vous avez toujours des inventeurs, créateurs, ingénieurs,
penseurs, visionnaires.
XVIIe siècle, Blaise Pascal invente la machine à calculer (dite Pascaline),
les fabricants de bouliers font grève (ils étaient déprimés, comment on le Repensez à Steve Jobs et son discours de Stanford : restez affamés, restez
sait ? Le voyage dans le temps…). dingues !
XIXe siècle, l’une des premières machines programmables voit le jour, Aujourd’hui, le développeur est un peu tout à la fois. Il est au cœur de
basée sur des cartes perforées, Jacquard a révolutionné le métier à tisser. l’innovation et le sera de plus en plus. IA, cloud computing, téléphonie
Se développent alors le langage binaire et la première calculatrice mobile, robotique, IoT, derrière, il y a du code, donc des développeurs.
universelle (oui, enfin, ne vous imaginez pas la calculatrice d’aujourd’hui) ;
Babache et Lovelace, ont travaillé en duo pour produire un des premiers Même si Ballmer s’est totalement planté avec l’iPhone en 2007,
programmes exécutables sur leur machine. reconnaissons-lui son célèbre discours (plutôt un mot) endiablé :
développeurs, développeurs, développeurs !
PROGRAMMEZ! N°255
Tensorflow, Java, Python,
Secure by Design
Disponible le 2 décembre 2022
programmez.com EDITO 3
TABLE DES MATIÈRES
��� Principales nouveautés détaillées ��� Comprendre l’UI Design avec Figma
de JavaScript de ES 2015 à ES2021 partie 2.1 Margaux Membré
Sylvain Cuenca
octobre décembre
Lun. Mar. Mer. jeu. Ven. Sam. Dim. Lun. Mar. Mer. jeu. Ven. Sam. Dim.
1 2 1 2 3 4
3 4 5 6 7 8 9 DevOps
DevFest
10 11 12 13 14 15 16 DDay /
Dijon
Marseille
Volcamp
(Clermond Ferrand) BDX I/O /
Bordeaux
Forum PHP (Paris)
5 6 7 8 9 10 11
17 18 19 20 21 22 23
12 13 14 15 16 17 18
Flow Con DevFest Nantes
API Day API Day
EveryDay Paris Paris
AI par
DevCon
24 25 26 27 28 29 30
19 20 21 22 23 21 25
Agile Tour (Bordeaux)
26 27 28 29 30
31
novembre
Lun. Mar. Mer. jeu. Ven. Sam. Dim. A VENIR
1 2 3 4 5 6
2023
Paris Game Weeks / Paris
• SnowCamp :
Programmez 25-28 janvier 2023 /
ScalaIO
DevCon
Grenoble
7 8 9 10 11 12 13
Open Source Forum
• FOSDEM : février 2023 /
Experience / Paris PHP Bruxelles
14 15 16 17 18 19 20 • Devoxx :
Codeurs en
12-14 avril / Paris
Forum DevFest /
ParisTestConf / Paris Seine / • Best of web : juin / Paris
PHP Strasbourg
Rouen
Agile Tour Toulouse GreHack / Grenoble
Capitole du Libre /
Toulouse
21 22 23 24 25 26 27
Programmez
DevCon Merci à Aurélie Vache pour la liste 2022, consultable sur son GitHub :
28 29 30 2 juil. https://github.com/scraly/developers-conferences-agenda/blob/master/README.md
6 AGENDA programmez.com
Les partenaires 2022 de
L e m a g a z i n e d e s d é v s
Niveau padawan
programmez.com 7
Node.js et la sécurité PARTIE 2
La sécurité dans les écosystèmes JavaScript et Node.js est un enjeu primordial. Pendant
la rédaction de l’article “Comment sécuriser son application JavaScript en 2022 ?”, je me
suis intéressée à Node Secure entre autres initiatives. J’ai rencontré Thomas Gentilhom-
me dans le cadre d’un atelier technique individuel qu’il proposait sur LinkedIn. À cette
occasion, j’ai rejoint le serveur Discord de l’ES Community. Interview menée par Romy Alula
R.A. : Qu’est-ce qui t’a amené à créer Node Secure ? R.A. : Quelles sont les prochaines étapes de développe-
T.G. : Sur SlimIO, on a une centaine de projets. On avait du ment pour livrer la v 1.0.0 ?
Thomas mal à comprendre les interactions entre eux. L’ancêtre de T.G. : Depuis 2 ans, rester en v.0.x a été un choix délibéré, car
Gentilhomme Node Secure, c’est le Dependency Analyzer, (https://github.com/ j’étais encore débutant en termes de sécurité. On aura une v1
Thomas est expert SlimIO/Dependency-Analyser). Il permettait d’analyser les liens très aboutie lorsqu’on aura franchi toutes ces étapes :
Node.js. Développeur entre les projets. Node Secure, lui, donne plus de visibilité sur • Reconstruction du graphe avec la lib D3.js
indépendant, il a plus de le graphe des dépendances. Figure A • Réduction des lags : actuellement, on est dans l’incapacité
300 projets en tous
genres à son actif : 50 à C’est une super idée venue de notre vécu. On était très de pousser davantage
100 en production, 5 ou confiants dans la qualité et l’intérêt du projet dès le début. Il • Améliorations sur l’UX, la lisibilité et les performances
6 gros projets répondait à des cas d’usage très précis et concrets. Son • Amélioration interface et du code Vanilla JS
représentant des milliers impact a été confirmé dès les premiers prototypes. Depuis 2 • Éventuellement passer aux web components sans
d’heures de ans, Node Secure a continué à évoluer. compromis. On a l’idée d’intégration lit-element (basé sur
développement. Il est
également le Concernant les dépendances de SlimIO, avec une centaine de le projet projet Polymer), c’est un mix entre Vanilla JS et les
mainteneur principal de projets, on a 2665 packages open source, ce qui est peu, web components
SlimIO, contributeur de grâce à une belle optimisation. Chez Myunisoft, mon client • Segmentation du projet pour la simplification et
Node-Secure, et actuel, on a 2960 dépendances pour une dizaine de projets. l’amélioration de la maintenance : la CLI est le cœur de
membre du Node.js Pour donner un ordre de grandeur, quand il y a du front, on Node Secure (5-7 packages que j’ai personnellement
Security Working Group.
peut facilement dépasser les 3000 dépendances pour un créés, spécifiquement à cet effet). Tony (_tonygo sur
projet donné. De nombreux facteurs entrent en jeu, mais c’est YouTube) est l’un des contributeurs les plus actifs.
LinkedIn : une moyenne. Généralement, le front engendre beaucoup de Aujourd’hui, les trois quarts des libs sont dédiées à la CLI,
https://www.linkedin.com/in/th
omas-gentilhomme dépendances. Ça monte très vite. Vu qu’on les installe très donc dispensables si on utilise l’API de Node Secure.
Github : facilement, on ne se rend pas compte qu’on utilise une • Amélioration globale de la qualité
https://github.com/fraxken grande variété de packages. Ce qui est assez incroyable. • Stabilisation de toutes les fonctionnalités en place (faux
SlimIO : positifs, bugs)
https://github.com/SlimIO R.A. : Comment ça fonctionne “sous le capot” ? js-x-ray (JavaScript & Node.js open source SAST - Static
Ecosystem Security T.G. : Node Secure utilise la même API que npm audit. La Application Security Testing - scanner, https://github.com/fraxken/
Working Group : commande `npm audit` va chercher les vulnérabilités js-x-ray, version actuelle 3.1.1)
https://github.com/Nodejs/secu connues dans le npm advisatory. Elle remonte la plupart du
rity-wg temps des CVE - Common Vulnerabilities Exposure. La R.A. : Est-ce que tu peux nous présenter JS X Ray dans
nSecure : fonctionnalité est disponible sur la branche principale. Mais les grandes lignes ?
https://github.com/ES-
elle n’est pas encore publiée. T.G. : C’est un outil capable de prendre un code source sans
Community/nSecure
l'exécuter et d’y trouver des patterns et codes malicieux.
Notre travail est basé sur des attaques précédentes dans
Figure A
l’écosystème pour une détection instantanée.
C’est un outil d’analyse. C’est aux devs de se documenter. Le
public visé est intermédiaire et senior.
8 programmez.com
r e , l e c t u r e , lectu
l e c t u r e, lect u
c t u r e , lecture,
cture, le r e , l e c t u r e ,
t u r e , l e c t u r e , lectu
ec t u r e , l e c t u re, lec
l
, l e c t u r e , lectu
l e c t u r e , Ul e n
c tduerres, talencding t u r e
, l e c t u r e , l e c ture,
cture Kubern, elteecsture, lecture, lectu
e , lectuv re al way
l e c t u r e , l e c t u r e , l e c t u r in a isu
cture, e , lectu
Comtpure, leclie Ku b e
tu r
rnetes, e , l e c t u r
c
re
e
d
l re n
t ure, le c t u r e , d ’A uré Vache. A
vec son
e , l e c t u r e , l e c vo ilà le d é fi
e et BD,
ct u r a p proche ludiqu
nge dans l’un
ivers
ectu
Auré lie n o u s
ee, lectu
p lo
r e , l e c t u r e , l
Kcutbeu rnr
e
s.
t u r e , l te
t u re, lect u r e ,
e c t u r e , l e c
cture, l e , l e c tu
, l e c t u r
r e , l e c t u r e , lecture
c t u r e , l e c t u r e, lectu
cture, le e , lectu
t u r e , l e c t u r
l e c t u r e , l e c t ure, lec
, l e c t u r e , l e c ture,
cture
Rapsberry Pi : t u re, lec t u r e , l e c t u r e , lectu
u r e , l e c
, l e c t u r e , l ue n
c tusreer,vel e c t u r
cture lectu
LAMP l e c t u r e, lect u r e , l e c t u r e ,
usariteà,la plraetiquec t u r e ,
l e c t u r e , l e ncptas
cture, E t si o
avec sa Pi ?
e , lectu
tu r e , l e c t u r
P ? re, lecture, lec
Come
l m ure, lec r ?
cmtent le configure
t in st a lle r L AMt u
, e n
ct u r e , l ec t u r e o m
ectu
C
d é p lo ye r son site web
?
r e , l e c t u r e , l
ctu
e n t
tc.re, lecture, le
Comm rd e la sé cu ri té,
Le livre abo d,teu
e c t u r e , Wl orde c
pret uss ,
re, lec
N e xt cl o u
c t u r e ,
cture, le e, lec9tu
c t u r e , l e c t u r
re, le
programmez.com
code statique. Comment tu t’y prends pour répertorier un de sécuriser son projet dès le début. Je considère avoir 10%
maximum de code malicieux ? Quelles sont tes sources ? des compétences. Appliquer les bonnes pratiques (cf
T.G. : Dans la sécurité, j’ai un parcours atypique. Je ne fais awesome Node security) peut permettre une sécurisation à
pas de pen testing (test d’intrusion). Je ne participe pas 99%. Pour le dernier pour cent, la consultation d’experts et
beaucoup aux concours. Pour moi, c’est un investissement un audit externe sont fortement recommandés.
personnel dans l'écosystème qui me passionne.
L’analyse statique (AST - Abstract Syntax Tree) m’a permis de R.A. : Des conseils pour monter en compétences en sécu-
faire un lien avec la sécurité. Je suis très axé sur le code, sa rité dans l’écosystème JavaScript ?
compréhension, son analyse. Ma zone de compétences est T.G. : Quelques ressources intéressantes :
bien délimitée dans la sécurité. • Awesome Node Security, la section Educational
Dans l’analyse de code, il y a peu de monde et peu • la section Sécurité de “Devenir un(e) développeur(se)
d’expertise. En France, je ne connais quasiment personne Node.js”, mon document en constante évolution
d’autre qui s’investisse dans l’analyse. Pas dans l’open • CTF (Capture The Flag), un concours d’intrusion
source, en tout cas. Tout ça, ce sont des premiers pas. Après, il faut se lancer, lire
À la lecture d’un article, j’ai découvert que des hackers et s’y intéresser. Il existe également des listes “awesome
avaient encodé du code JS en morse pour le rendre illisible. security” généralistes et leur version par langage. Les repos
Ça m’a fait ultra rire. Je me suis dit que c’était trop beau pour sont dispos en ligne.
ne pas le gérer. Ça m’a permis de me replonger dans le
morse. Aujourd’hui, JS-x-ray est capable de le détecter (en R.A. : Est-ce que tu voudrais ajouter quelque chose ?
théorie) ! Dans l’informatique, tu finis toujours par apprendre T.G. : Face à Express* et sa grande popularité, Fastify, c’est
un truc. Mes sources : l’apothéose de ce qui se fait de mieux dans l’écosystème Node.js :
• awesome Node security qui référence l’existant, en termes la sécurité y est optimale. C’est maintenu par des contributeurs
d’outils et autres ressources. core de Node, avec une communauté d’experts très actifs.
• badjs.org (https://github.com/jsoverson/badjs.org) liste des Node n’est pas dépassé. C’est aux devs d’aller chercher les
attaques de manière détaillée. En cas d’attaque, NPM modules les plus récents et optimaux. Dans 2 ou 3 ans,
retire les codes et ne les publie pas. Ce qui est Express sera déprécié. Il faudrait faire une analyse des
problématique pour l’analyse de code : impossibilité de dépendances, découper le métier pour le séparer du serveur
travailler. HTTP. Beaucoup de packages sont en train de mourir.
Snyk, avec la puissance qu’ils ont pourrait collaborer avec Souvent ce sont des middlewares. Express, c’est beaucoup de
NPM en demandant l’accès à ces codes malicieux, essayer middlewares qui ne sont plus maintenus. Le cœur d’Express
d’utiliser les post-mortem. Contrairement aux contributeurs sera maintenu, mais pas les packages spécifiques.
open source, on n’a pas la même légitimité. *Passer d’Express à Fastify n’est pas forcément très
Face à un vecteur d’attaque fort, un remède simple peut être compliqué. Ce sont tous deux des frameworks low scope. Il
préconisé : si tu peux faire un code JS avec des boucles et existe un mode de compatibilité pour migrer plus facilement.
conditions, c’est recommandé plutôt qu’une regex. Dans le cas où Un package de huit ans sans mise à jour, c’est un vecteur
une regex est indispensable, il vaudrait mieux utiliser une lib d’attaque, d’instabilité. Il faut assurer la maintenance soi-
spécialisée comme validator ou safe-regex (https://github.com/gold- même, ça demande beaucoup de travail. NSecure peut être
bergyoni/Nodebestpractices#-616-prevent-evil-regex-from-overloading-your- installé à la racine du projet pour analyser les dépendances :
single-thread-execution). est-ce qu’elles sont à jour ?
Je lutte contre les répercussions de ce framework bloqué en
R.A. : Si aujourd’hui, je me lance dans le développement 2015 avec des callbacks, un système de middlewares dépassé et
d’une application full JS, application manipulant des pourtant choisi par les entreprises et utilisé dans de nombreux
données sensibles (open banking). tutos destinés aux juniors. Il entraîne des dégâts d’image, alors
Comment est-ce que je pourrais la blinder dès le premier qu’il y a des solutions stables existant depuis des années. Notre
commit ? manière de coder dans Node.js n’a plus rien à voir avec celle d’il
T.G. : Sujet très vaste. La sécurité regroupe énormément de y cinq ou six ans. L’écosystème, c’est les packages. Les libs en
choses : coulisse sont souvent les mêmes. Comprendre l’historique
• Définition du besoin compris et maîtrisé permet d'éviter les dégâts causés par certaines libs. Le travail
• Fonctionnalités très simples : je t’envoie A, tu me retournes B d’écriture permet de toucher un autre public.
• Évolutions maîtrisées
• Architecture, qualité du code : features plus dédiées Sources
• Infrastructure Awesome Node.js security :
• Réseau https://github.com/lirantal/awesome-Nodejs-security
Tout ça représente un large scope de métiers et demande Awesome cross platform Node.js :
une rigueur d’ensemble. La sécurité, c’est aussi être https://github.com/bcoe/awesome-cross-platform-Nodejs
conscient des risques et toujours se remettre en question. Les projets open-source de Thomas :
Éventuellement, dans des entreprises comme Thalès, ils SlimIO : https://github.com/SlimIO
savent faire preuve d’une grande rigueur. Après, pour une Node.js security working group :
personne qui débute, ça va être très difficile, voire impossible, https://github.com/Nodejs/security-wg
10 programmez.com
Mise à jour “Over the Air” avec
.NET nanoFramework et Azure IoT
Over the Air (OTA) est l’équivalent de Windows Update ou des mises à jour de package Laurent Ellerbach
Principal Engineer
sous Windows ou Linux, mais dans le monde des Micro Controller Unit (MCU). Même Manager
si le terme OTA peut être utilisé dans beaucoup d’autres circonstances, il est surtout Microsoft
dans l’Internet des objets, Internet of Things (IoT). Vous trouverez également le terme [email protected]
https://github.com/Ellerbach
Field Update.
Le but est de pouvoir mettre à jour le code de façon sécuri- .NET nanoFramework (https://github.com/nanoframework) apporte
sée, sans avoir à récupérer le périphérique pour le reflasher. le support de .NET sur des petits MCU comme des ESP32,
Il peut être possible de se connecter au périphérique à distan- STM32, TI et NXP. Comme la mémoire, le stockage et l’en-
ce ou physiquement. vironnement d’exécution sont très contraints, vous pouvez
En général, OTA prend la forme de mise à jour de firmware imaginer que ce qui tourne sur ces MCU est une version allé-
et de mise à jour de code. Le firmware est souvent l’équiva- gée de .NET. Il y a une compatibilité bien entendu et il est
lent d’un Real Time OS (système d’exploitation temps réel) possible de réutiliser du code avec le grand frère. .NET
avec les couches basses permettant son fonctionnement nanoFramework est open source et un effort communautaire.
alors que le code est la partie qui fonctionne dessus. Les deux Je suis un des principaux contributeurs à .NET
peuvent être totalement indépendants. Le mécanisme en nanoFramework.
place permet de sauvegarder dans un stockage interne la À noter que ce que je vais présenter fonctionne également
nouvelle version en parallèle de l’ancienne. Ensuite, le chan- parfaitement avec Azure IoT Plug & Play (https://docs.microsoft
gement est appliqué. Si quelque chose ne fonctionne pas .com/azure/iot-develop/overview-iot-plug-and-play). Je ne l’utilise pas
bien, l’ancienne version est rechargée. Cela permet d’éviter ici pour des questions de simplification.
de bloquer complètement le périphérique en cas d’échec. Le
système fonctionne avec un watchdog (chien de garde) qui Azure IoT :
vérifie que tout fonctionne. connectivité cloud sécurisé et fiable
En termes de sécurité et d’intégrité, il faut être sûr que la Avec les MCU récents, il est désormais possible de les
nouvelle mise à jour est bien signée, qu’elle est intègre lors connecter directement à un réseau filaire ou sans fil. Ils sup-
de son téléchargement. Sans ces deux mécanismes simples, portent également les communications basées utilisant
il est impossible de garantir qu’un code non voulu soit Transport Layer Security (TLS) et équivalent garantissant des
déployé sur le périphérique. communications sécurisées. Prenez un simple ESP32 pour
Et bien sûr, il faut un mécanisme qui soit facile à mettre en quelques euros avec une connexion Wi-Fi, certains possèdent
place pour télécharger ces données de façon sûre sans avoir aussi de l’Ethernet. C’est ce que j’utiliserais dans mon
besoin de déplacer le périphérique. Quand une connectivité exemple, car ils sont simples à trouver.
réseau existe, il est possible d’utiliser celle-ci. Quand il n’y en Mais pourquoi connecter de tels périphériques directement
a pas, un réseau local Bluetooth, Wi-Fi ou même brancher un au Cloud ? Et bien, parce que l’on peut en toute sécurité
câble est alors nécessaire. maintenant ! Et dans de plus en plus de cas, il y a un réel
Dans l’exemple que je vais donner avec .NET intérêt à les connecter directement et non pas à travers une
nanoFramework, nous allons nous focaliser sur l’update du passerelle (gateway). Travaillant avec des clients dans le
code exécutable et pas celui des couches basses. Donc cela domaine de l’automobile et de l’industrie, je vois de plus en Figure A
ne couvrira pas la mise à jour du firmware, mais le code qui
s’exécute sur le périphérique et qui est écrit en C#. Pour cela,
nous allons utiliser une connectivité Wi-Fi ou Ethernet avec
Azure IoT (https://azure.microsoft.com/fr-fr/overview/iot).
L’ensemble du code est disponible dans les exemples de .NET
nanoFramweork : https://github.com/nanoframework/Samples/tree/main
/samples/AzureSDK/AzureEdgeOta.
Le modèle que je vais décrire en détail dans cet article per-
met de télécharger un nouveau code depuis un stockage
blob dans le Cloud, utilisant les avantages de Azure IoT avec
la notion de jumeaux numériques (twins) comme un méca-
nisme de distribution de l’information. Pour ajouter à la
magie, .NET nanoFramework, permet d’utiliser la réflexion et
de charger dynamiquement du code. Voilà pour les points
principaux. Fin de la théorie, regardons le code ! Figure A
programmez.com 11
plus d’opportunités de donner une vie numérique à de vieux },
instruments à un coût extrêmement réduit à travers une “$version”: 53
connexion série entre le MCU et l’ancienne machine. Pour }
prendre un autre exemple, l’utilisation sur batterie avec un }
simple panneau solaire et une connexion à travers une carte }
SIM sont aussi des scénarios que l’on voit de plus en plus.
J’ai souvent la question de pourquoi ne pas utiliser un péri- Le mécanisme des twins permet de délivrer des informations,
phérique comme un Raspberry Pi à la place. La raison est mais pas de larges fichiers. Cela doit rester dans la limite du
simple : le coût et la consommation énergétique. L’utilisation raisonnable (quelques kilo-octets). Si besoin, un pointeur sur
d’un mini ordinateur fonctionnant sur batterie a un coût de 5 un blob ou équivalent permet de charger une configuration
à 100 fois plus élevé. Ce choix doit donc être réservé à une plus large ou dans notre cas, directement un binaire.
utilisation où le calcul nécessaire est vraiment très important Nous allons donc utiliser ce modèle avec une version de
et justifie le surcoût. code, un token et une liste d’URL.
.NET nanoFramework offre la possibilité de se connecter de Une fois connecté, il est possible de demander les twins et
façon sécurisée à un réseau en utilisant TLS et des certificats aussi de souscrire à un changement de twins. La librairie dans
pour l’authentification dans Azure IoT. Quelques lignes suffi- .NET nanoFramework permet de le faire très simplement :
sent pour se connecter grâce à la librairie Azure
(https://github.com/nanoframework/nanoFramework.Azure.Devices): var twins = azure.GetTwin(new CancellationTokenSource(10000).Token);
if (twins == null)
// Nous stockons le certificat dans les ressources. {
X509Certificate azureRootCACert = new X509Certificate(Resource.GetBytes(Resource // Ceci est une erreur!
.BinaryResources.AzureRoot)); }
azure = new(Secrets.IotBrokerAddress, Secrets.DeviceID, Secrets.SasKey, MqttQoS // Souscrire aux changements de twins
Level.AtLeastOnce, azureRootCACert); azure.TwinUpated += TwinUpdated;
void TwinUpdated(object sender, TwinUpdateEventArgs e)
Dans cet exemple, nous utilisons un token SAS pour simplifier {
un peu. Si vous utilisez des certificats, il y a la possibilité de // Les twins ont été mises à jour, nous pouvons les traiter
les stocker dans un store interne sans avoir besoin de refla- }
sher le périphérique.
Quand vous utilisez la fonction GetTwins, vous obtenez à la
Azure Twins : fois les désirées et les reportées. Vous pouvez ajuster les
dis-moi ce que je dois télécharger reportées et les publier avec vos changements. Par contre,
Le concept d’Azure Twins (https://azure.microsoft.com/services/digi- vous ne pouvez pas modifier les désirées sur les périphé-
tal-twins/), jumeaux numériques, utilisé dans Azure IoT se riques. Une notion de version gérée automatiquement est
base sur des propriétés. Vous avez d’un côté les desired (dési- disponible également.
rées) et les reported (reportées). Leur représentation prend la
forme d’un JSON et vous pouvez les utiliser comme vous le Blob Storage :
souhaitez. Voici un exemple : du versioning, accès simple et sécurisé
Le stockage sous forme de blob dans Azure permet d’accé-
{ der à des données non structurées. Il y a également la possi-
“properties”: { bilité d’avoir un versioning des fichiers et de gérer les accès
“desired”: { de façon très fine. Le coût est extrêmement faible. Ce type de
“TimeToSleep”: 2, stockage est ce qui est utilisé pour les data lake par exemple.
“Files”: [ Nous allons utiliser les blobs pour y stocker notre code qui
{ sera ensuite téléchargé par notre périphérique. Lorsque vous
“FileName”: “https://blob_name.blob.core.windows.net/ créer un programme ou une librairie pour .NET
nano-containers/CountMeasurement.pe”, nanoFramework, vous utilisez la chaîne de compilation de
“Signature”: “4E-1E-12-45-C5-EB-EC-E3-86-D3-09-39-AE-E9- .NET, msbuild. Cela crée un exe ou une dll contenant ce que
E8-81-97-A9-0E-DF-EE-D0-71-27-A7-3F-26-D0-4B-4E-CF-23” l’on appelle un Intermediate Language (IL), langage inter-
} médiaire qui est ensuite compilé et exécuté. Pour .NET
], nanoFramework, nous avons un processus complémentaire
“Token”: “A SAS token to connect to the blob storage”, qui est exécuté et qui va extraire, simplifier et transformer cet
“CodeVersion”: 12, IL dans un IL capable de s’exécuter sur un MCU et qui est
“UpdateTime”: 120000, spécifique au Common Language Runtime (CLR) de .NET
“$version”: 43 nanoFramework. Tout cela s’effectue de façon transparente
}, lorsque vous utilisez l’extension pour .NET nanoFramework
“reported”: { avec Visual Studio. L’extension ainsi générée est un fichier
“CodeUpdated”: true, Platform Executable (PE).
“CodeRunning”: true, L’accès au blob requiert un token qui est généré par contai-
12 programmez.com
ner (équivalent d’un répertoire) ou par fichier. La durée de Assembly.Load : chargez votre code
validité du token peut être longue, mais on préférera des dynamiquement en .NET
durées courtes et renouveler les tokens régulièrement si Il y a quelque chose qui m’a toujours fasciné avec .NET c’est
besoin. Les tokens sont dérivés d’un des tokens principaux et la réflexion et le chargement dynamique des assemblies.
permettent de gérer l’accès en lecture seule ou en lecture et Cela a toujours été un problème complexe à résoudre dans
écriture. Cela en fait un mécanisme simple et sécurisé avec l’industrie. Cette capacité native et simple en .NET est claire-
un degré de granularité suffisant. ment un avantage comparé à beaucoup d’autres plate-
Dans notre cas, nous fournirons dans le twin, les fichiers à formes. La capacité de pouvoir appeler des méthodes, des
télécharger et le token que l’on générera du côté Cloud. propriétés, d’avoir leurs noms, est quelque chose de vraiment
Cette génération peut-être effectuée automatiquement très important.
simplement. Pour simplifier et pour tester, vous pouvez le C’est cette capacité que nous allons utiliser, la réflexion et
générer directement depuis le portail. l’appel dynamique de code. Le tout depuis le fichier que nous
L’accès à un stockage blob s’effectue avec HTTPS. Voici aurons téléchargé au préalable. Voici à quoi peut ressembler
schématiquement comment le faire avec .NET le code :
nanoFramework, pour télécharger depuis le blob et sauver le Code complet sur programmez.com & github
fichier sur une carte SD ou l’espace de stockage Internet.
L’exemple complet vous permettra d’avoir quelques éléments Dans ce code, nous allons d’abord lire l’intégralité du fichier
complémentaires : puis le passer à Assembly.Load qui va le charger en mémoire.
À ce moment, aucun code n’est encore exécuté. Comme dis-
string fileName = url.Substring(url.LastIndexOf(‘/’) + 1); cuté précédemment, nous vérifions bien sûr l’intégrité du
// Si nous sommes connectés à Azure, nous nous déconnectons, car les petits MCU ne fichier. S’il y a un problème à ce moment-là, nous le saurons
peuvent avoir qu’une seule connexion TLS à la fois ! et nous pourrons prendre une action.
if (azure.IsConnected)
{ Assembly dynamiques :
azure.Close(); trouver le bon point d’entrée
} Dans ce modèle, comme dans tout code nécessitant de char-
ger dynamiquement du code, il est important de savoir par
httpClient.DefaultRequestHeaders.Add(“x-ms-blob-type”, “BlockBlob”); quel endroit rentrer dans le code. Le fameux static void main
// Nous utilisons Tls 1.2 avec Azure est ce point d’entrée dans les programmes exécutables. Ici,
httpClient.SslProtocols = System.Net.Security.SslProtocols.Tls12; nous allons utiliser une fonction Start et utiliserons également
// Nous utilisons le certificat Azure deux autres fonctions un peu plus tard. Une première Stop
httpClient.HttpsAuthentCert = new X509Certificate(Resource.GetBytes(Resource. qui permettra d’arrêter proprement le code et une autre en
BinaryResources.azurePEMCertBaltimore)); cas d’update des twins :
HttpResponseMessage response = httpClient.Get($”{url}?{sas}”);
response.EnsureSuccessStatusCode(); namespace CountMeasurement
{
using FileStream fs = new FileStream($”{RootPath}{fileName}”, FileMode.Create, public static class OtaRunner
FileAccess.Write); {
response.Content.ReadAsStream().CopyTo(fs); public static void Start(DeviceClient azureIot)
fs.Flush(); public static void Stop()
fs.Close(); public static void TwinUpdated(TwinCollection twins)
response.Dispose(); }
}
Le code est simple, vous remarquerez au passage que .NET
nanoFramework a des classes de type HttpClient pour facili- Ici, j’ai fait le choix d’utiliser des fonctions statiques, car ce
ter la vie, des streams et bien plus encore ! La seule chose code n’est pas destiné à être instancié plusieurs fois. Cela
vraiment importante lorsque vous accéder à un stockage blob implique d’avoir également les variables privées statiques.
dans Azure, c’est de bien penser à ajouter l’en-tête x-ms-
blob-type. Pour la sauvegarde, ici, nous utilisons une simple // Nous chargeons les assemblies qui ont été sauvées sur le disque
copie de stream. Dans l’exemple complet, il sauvegarde par if (!isRunning)
morceau pour éviter de saturer la mémoire. {
Chaque fichier vient avec une signature SHA256. Cela nous LoadAssemblies();
permet de vérifier que le fichier téléchargé est bien intégré.
Nous sommes ainsi sûrs que ce qui est téléchargé est bien de isRunning = false;
ce qui est demandé, que rien n’a été modifié entre temps. if (toRun != null)
Cette vérification va s’effectuer avant de charger dynamique- {
ment le code. Type typeToRun = toRun.GetType(OtaRunnerName);
var start = typeToRun.GetMethod(“Start”);
stop = typeToRun.GetMethod(“Stop”);
programmez.com 13
twinUpated = typeToRun.GetMethod(“TwinUpdated”); Total bytes read: 2300
The nanoDevice runtime is loading the application assemblies and starting
if (start != null) execution.
{ I:\CountMeasurement.pe: 2300
try Assembly: CountMeasurement (1.0.0.0) (468 RAM - 2300 ROM - 820
{ METADATA)
// Nous appelons notre function et passons l’objet azure en paramètre
start.Invoke(null, new object[] { azure }); AssemblyRef = 12 bytes ( 3 elements)
isRunning = true; TypeRef = 60 bytes ( 15 elements)
} FieldRef = 0 bytes ( 0 elements)
catch (Exception) MethodRef = 84 bytes ( 21 elements)
{ TypeDef = 24 bytes ( 3 elements)
isRunning = false; FieldDef = 20 bytes ( 9 elements)
} MethodDef = 28 bytes ( 14 elements)
} StaticFields = 84 bytes ( 7 elements)
}
} Attributes = 0 bytes ( 0 elements)
TypeSpec = 0 bytes ( 0 elements)
Dans un premier temps, nous cherchons nos trois méthodes. Resources = 0 bytes ( 0 elements)
Si nous avons trouvé la méthode Start alors nous l’appelons Resources Files = 0 bytes ( 0 elements)
et passons l’objet azure qui est notre connexion à Azure IoT. Resources Data = 0 bytes
Cela permettra à la classe chargée dynamiquement de pou- Strings = 858 bytes
voir envoyer de la télémétrie par exemple. Signatures = 128 bytes
Pour la fonction TwinUptaded, elle sera appelée en cas de ByteCode = 496 bytes
changement des twins. L’exemple complet montre comment
récupérer des informations permettant de régler la fréquence
de publication du compteur.
En plus de ces fonctions d’autres ont été ajoutées permettant Total: (22704 RAM - 245512 ROM - 97249 METADATA)
un appel direct à travers le mécanisme des Direct Methods
(https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-direct-methods) AssemblyRef = 248 bytes ( 62 elements)
offertes par Azure IoT. TypeRef = 2236 bytes ( 559 elements)
On ajoute la ligne `_azureIot.AddMethodCallback(GetCount);` FieldRef = 60 bytes ( 15 elements)
dans notre fonction Start. Cela permet d’avoir directement un MethodRef = 3556 bytes ( 889 elements)
appel à la fonction GetCount : TypeDef = 4088 bytes ( 511 elements)
FieldDef = 1888 bytes ( 937 elements)
private static string GetCount(int rid, string payload) MethodDef = 6404 bytes ( 3190 elements)
{ StaticFields = 1284 bytes ( 107 elements)
Debug.WriteLine(“GetCount called”);
// Nous ignorons ici le payload et retournons simplement le compteur DebuggingInfo = 3232 bytes
return $”{{\”Counts\”:{_count}}}”;
} Attributes = 120 bytes ( 15 elements)
TypeSpec = 36 bytes ( 9 elements)
Ce code est ici extrêmement simple, mais il peut bien sûr être Resources Files = 24 bytes ( 1 elements)
beaucoup plus complexe. Vous pouvez accéder à des GPIO, Resources = 24 bytes ( 3 elements)
I2C, SPI, des capteurs, utiliser d’autres nugets. L’ensemble Resources Data = 1782 bytes
des fichiers nécessaires et non présents sur le périphérique Strings = 48684 bytes
seront ainsi téléchargés et chargés dynamiquement. Signatures = 13845 bytes
Le résultat ressemble à cela quand on regarde la fenêtre de ByteCode = 95062 bytes
debug de Visual Studio :
Step into: Stepping over non-user code ‘Program.’ *** No debugging symbols available for ‘CountMeasurement’. This
Program Started. assembly won’t be loaded in the current debug session. ***
Connecting to wifi. The thread ‘<No Name>’ (0xb) has exited with code 0 (0x0).
Date and time is now 02/28/2022 10:02:10 Start called
The thread ‘<No Name>’ (0x4) has exited with code 0 (0x0). Getting twins
The thread ‘<No Name>’ (0x6) has exited with code 0 (0x0). Having twins
The thread ‘<No Name>’ (0x3) has exited with code 0 (0x0). Update time: 120000
The thread ‘<No Name>’ (0x5) has exited with code 0 (0x0). Running...
Can seek: False, Lengh: 2300 In the thread
14 programmez.com
Sending telemetry... Counts: 1
(https://azure.microsoft.com/services/monitor/#overview) font des
Sending telemetry... Counts: 2
miracles dans ce domaine.
Sending telemetry... Counts: 3
J’ai implémenté ce code et testé ce code sur des ESP32 limi-
Ce qui est intéressant à voir ici c’est que lorsque le CLR char- tés en ressources mémoires. C’est la raison pour laquelle il
ge un assembly, on a le détail de ce qui est associé et qui reboote quand il a chargé une nouvelle version, se déconnec-
peut être nécessaire pour son exécution. Cela va se passer à te d’Azure IoT Hub lorsqu’il doit charger les fichiers du stoc-
chaque fois qu’une assembly sera chargée. Cela facilite la kage blob. Avec un périphérique disposant de plus de
mise au point bien entendu. Debugger ce type de solution est mémoire, il est bien sûr possible d’optimiser cette partie éga-
en effet complexe sur un MCU! lement.
Une fois que la télémétrie a commencé, vous pouvez voir les La taille compte: plus c’est petit, mieux c’est ! Comme les
messages dans le debug. Vous pouvez également utiliser assembly doivent être entièrement chargés en mémoire pour
Azure IoT Explorer (https://docs.microsoft.com/azure/iot- les charger dynamiquement, il vaut mieux créer plusieurs
fundamentals/howto-use-iot-explorer) pour vérifier que tout fonction- petits assembly qu’un seul gros. 4 assembly de 5 K bytes cha-
ne comme vous le souhaitez. Vous verrez des messages de ce cun seront mieux gérés qu’un seul de 20 K. Cela réduit la
type : pression sur la mémoire surtout pour ceux qui ont une
mémoire faible et partitionnée telle que les ESP32. Il est pos-
Mon Feb 28 2022 08:08:17 GMT+0100 (Central European Standard Time): sible aussi d’améliorer ce modèle pour ne charger qu’un seul
{ des assembly à mettre à jour. Cela sera particulièrement inté-
“body”: { ressant sur les réseaux à faible débit.
“Counts”: 2
}, Où commencer ?
“enqueuedTime”: “Mon Feb 28 2022 08:07:17 GMT+0100 (Central Il vous faut d’abord un périphérique tel qu’un ESP32, installer
European Standard Time)” une des dernières versions de Visual Studio, l’extension .NET
} nanoFramework qui va avec, flasher l’ESP32 et écrire votre
Mon Feb 28 2022 08:07:17 GMT+0100 (Central European Standard « hello world » en C#, mettre un point d’arrêt et appuyer sur
Time): F5. Le reste viendra tout seul ! Et évidemment, nous avons
{ tout prévu pour vous aider avec un guide détaillé pour com-
“body”: { mencer (https://docs.nanoframework.net/content/getting-started-guides/
“Counts”: 1 getting-started-managed.html).
}, Ensuite, pour commencer avec Azure IoT et apprendre com-
“enqueuedTime”: “Mon Feb 28 2022 08:07:17 GMT+0100 (Central ment l’utiliser avec .NET nanoFramework, suivez les instruc-
European Standard Time)” tions dans le repository GitHub de la librairie
} Azure(https://github.com/nanoframework/nanoFramework.Azure.Devices)
Et bien sûr, vous avez de très nombreux exemples dans le
Vous pouvez vérifier également les propriétés des twins et repository à cet effet (https://github.com/nanoframework/Samples ), ils
bien-sûr envoyer des messages GetCount, dans notre vous permettrons de rapidement prendre en main .NET
exemple, et recevoir la réponse. nanoFramework et d’en apprécier toute sa magie !
L’exemple complet est lui disponible également dans le repo-
Limitations et possibles améliorations sitory des exemples (https://github.com/nanoframework/Samples/tree
Avant de rentrer dans les limitations, pour récapituler, le /main/samples/AzureSDK/AzureEdgeOta ). Il comprend également un
modèle mis en place avec cette solution permet, sur un outil permettant de publier automatiquement les fichiers
microprocesseur de télécharger de façon sécurisé, intègre du nécessaires dans le stockage blob et de préparer les éléments
code, de pouvoir mettre à jour ce code, de passer dynami- du twin à copier.
quement des propriétés, de recevoir un état de ces propriétés, A vous donc la possibilité de flasher avec un minimum d’élé-
d’envoyer de la télémétrie et tout cela sans avoir besoin de ments votre MCU avec .NET nanoFramework et de bénéficier
reflasher physiquement le périphérique. Les mécanismes en de la mise à jour de code OTA de façon sécurisée, intègre et
place sont complexes, mais cette complexité est entièrement efficace.
masquée pour le développeur grâce à .NET et plus particu-
PROCHAIN NUMÉRO
lièrement .NET nanoFramework et Azure IoT.
Un des axes d’amélioration est d’implémenter un mécanisme
de sûreté. Quand nous téléchargeons le code, nous suppri-
mons les anciennes versions. Pour être plus certain, il faudrait
stocker la nouvelle version en parallèle de l’ancienne et en PROGRAMMEZ! N°255
cas de problème pouvoir retourner sur la précédente. Cela
doit se faire aussi bien sur le périphérique qui doit être
Tensorflow, Java, Python,
capable de vérifier si le code est chargé, mais aussi dans le Secure by Design
cloud pour vérifier que la télémétrie ou les twins sont corrects.
L’utilisation dans le Cloud des Azure Function (https://docs.micro- Disponible le 2 décembre 2022
soft.com/azure/azure-functions/functions-overview) et Azure Monitor
programmez.com 15
Une nouvelle approche d’analyse du code au sein
d’un environnement DevSecOps avec Checkmarx
Pour identifier, corriger et prévenir les failles de sécurité Exploit LOG4J,
sans ralentir le développement, les entreprises misent sur le exemples de variantes
DevSecOps, ou l’intégration de la sécurité au sein d’une et les mises à jour corrélées
approche DevOps à toutes les étapes du cycle de Par Alex Livshiz, chercheur Checkmarx
développement. Ce concept implique de penser la sécurité EXÉCUTION DE CODE À DISTANCE APACHE LOG4J – CVE-2021-44228
(https://checkmarx.com/blog/apache-log4j-remote-code-execution-cve-2021-44228/)
des applications et de l’infrastructure comme partie En 2021, l’exploit zero-day le plus critique de ces dernières années a affecté
intégrante du développement applicatif. Il repose sur la la plupart des plus grandes entreprises. Découvert (https://logging.
conviction que les équipes de sécurité et de développement apache.org/log4j/2.x/security.html) dans la très populaire bibliothèque de logs Java
log4j (https://mvnrepository.com/artifact/log4j/log4j), il a permis de lancer des attaques
en sont co-responsables, fédérant ensemble le
par exécution de code à distance RCE (Remote code execution) en
développement, la sécurité et les processus opérationnels. enregistrant une charge utile.
Si d’un point de vue purement fonctionnel, les organisations La vulnérabilité a reçu le surnom de « Log4Shell », obtenu un score CVSS
devront toujours effectuer une analyse incrémentielle de (Common Vulnerability Scoring System) de 10 - le risque le plus élevé - et a
été publiée par GitHub advisory (https://github.com/advisories/GHSA-jfh8-c2jp-5v3q)
code source à la recherche de vulnérabilités, la clé est
avec un niveau de sévérité critique.
d’intégrer ces fonctionnalités directement dans les outils
utilisés par les développeurs lors de l’écriture, l’extraction, PORTÉE DE L’EXPLOIT
la fusion et l’intégration de lignes de code. Log4Shell a été exploité pendant quelques jours avant sa divulgation publique.
De plus, des tentatives de scan de log4shell ont été découvertes jusqu’à deux
semaines auparavant. Les attaquants ont pu installer des cryptomineurs, créer
Dans le cas contraire, cette analyse ne pourra pas s’intégrer des botnets et voler des données sensibles et des informations d’identification
efficacement dans les initiatives DevSecOps et ralentira la système. À ce jour, on estime qu’il a affecté plus d’un million de machines.
livraison et le déploiement logiciel. L’utilisation de
composants open source et de bibliothèques tierces CVES PERTINENTS
Depuis sa divulgation, cinq CVE (Common Vulnerabilities and Exposures)
devenant courante dans les pratiques modernes, les concernant Log4j2 et Log4j1 ont été publiées :
organisations doivent également effectuer une analyse de
composition logicielle SCA pour dresser l’inventaire des LOG4J2 : CVE-2021-44228
Les versions de 2.0-beta9 à 2.15.0 de Log4j2 (excluant 2.12.x après la version
Open Source utilisés dans une application. Si cette 2.12.1) sont vulnérables à l’exécution de code à distance via l’analyseur JNDI
approche est effectuée avec l’analyse de code statique, elle LDAP (Lightweight Directory Access Protocol). Un attaquant capable de
fonctionnera mieux dans DevSecOps, car elle ne ralentira contrôler les messages de log ou les paramètres de message de logs peut
pas non plus la livraison et le déploiement. Enfin, les exécuter du code arbitraire chargé à partir de serveurs LDAP lorsque la
substitution de recherche de message est activée. La vulnérabilité initiale
organisations doivent également effectuer une analyse désignée CVE-2021-44228 (https://nvd.nist.gov/vuln/detail/CVE-2021-44228) aurait
interactive de la sécurité pendant l’exécution des builds. été corrigée dans les versions 2.12.2 et 2.15.0. Le correctif inclut la
L’approche optimale est d’appliquer cette analyse durant les désactivation de JNDI par défaut et la restriction de l’accès LDAP via le JNDI
tests fonctionnels pour éviter les délais supplémentaires dans la recherche d’objets et le gestionnaire JNDI de log4j2.
Cette vulnérabilité a reçu le score CVSS de 10 le plus élevé (https://nvd.nist.gov/
inattendus. vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H&version=3.1) et
affecte les packages suivants, disponibles via Maven Package Manager :
Pour résumer, adopter et implémenter de nouvelles • org.apache.logging.log4j:log4j-api
approches d’analyse du code adaptées aux objectifs • org.apache.logging.log4j:log4j-core
DevSecOps implique de fédérer et de comprendre les Notes - La vulnérabilité se situe dans log4j-core. Logger, utilisé pour déclencher l’exploit,
est défini dans log4j-api. Pour détecter une telle utilisation et le chemin exploité, Checkmarx a
fonctionnalités de chaque solution - SAST (analyse du code ajouté les méthodes de Logger comme vulnérables (finissant par déclencher la vulnérabilité
spécifique), SCA (analyse du code open source) et IAST selon l’étude). Cette approche est décrite dans la page Avis de Github pour cette vulnérabilité.
(analyse temps réel des applications en cours d’exécution) –
LOG4J2 : CVE-2021-45046
et de les appliquer exactement au moment et à l’endroit où Le 11 décembre 2021, Checkmarx a découvert que le correctif de CVE-2021-
elles font le plus de sens pour les développeurs. C’est 44228 était incomplet dans certaines configurations autres que celles par
l’approche DevSecOps de Checkmarx. défaut. Cela permettait aux attaquants disposant de données d’entrée
16 programmez.com
malveillantes conçues à l’aide d’un modèle de recherche JNDI d’engendrer log4j-2-17-0-arbitrary-code-execution-via-jdbcappender-datasource-element/). Cette vulnérabilité
une fuite d’informations, d’exécuter du code à distance dans certains permet l’exécution arbitraire de code (ACE) dans les versions 2.0-beta7 à
environnements ainsi que du LCE (Local Code Execution) dans l’ensemble des 2.17.0 (à l’exclusion des versions de correctifs de sécurité 2.3.2 et 2.12.4).
environnements. Le RCE était également possible dans certains Lorsqu’un attaquant prend le contrôle de la configuration de log (via une
environnements macOS. Cette vulnérabilité complémentaire a été désignée attaque MITM - https://en.wikipedia.org/wiki/Man-in-the-middle_attack - car il existe une
sous le nom de CVE-2021-45046 (https://nvd.nist.gov/vuln/detail/CVE-2021-45046) et fonctionnalité permettant de charger un fichier de configuration distant dans
corrigée dans les versions 2.12.2 et 2.16.0 en désactivant JNDI par défaut et log4j), il peut construire une configuration malveillante à l’aide de JDBC
en supprimant la recherche de message. Appender avec une source de données référençant un URI JNDI, qui peut
Comme cette vulnérabilité était initialement considérée comme n’autorisant ensuite exécuter du code distant.
que les attaques DOS (Déni de Service), le score CVSS attribué initialement Cette vulnérabilité a été corrigée dans la version 2.17.1 en limitant les noms
était de 3,7. Son impact plus menaçant qui a été découvert plus tard lui a valu de sources de données JNDI au protocole Java et le score CVSS de 6,6 lui a
le nouveau score CVSS de 9,0 (https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vec- été attribué (https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:H/PR:H/
tor=AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H&version=3.1). UI:N/S:U/C:H/I:H/A:H&version=3.1), un score de criticité légèrement inférieur, car il
Cette vulnérabilité étant une extension de CVE-2021-44228, les packages est plus complexe à exploiter que les variantes log4Shell précédentes. CVE-
affectés sont les mêmes. 2021-44832 affecte uniquement le package log4j-core.
programmez.com 17
Figure 1 Présentation SCA,
avec la liste des packages et
des risques détectés
18 programmez.com
WebAuthn :
sécurisez votre connexion
Christophe
L’authentification d’aujourd’hui ne sera pas celle de demain. Car WebAuthn va aider les Villeneuve
utilisateurs à s’identifier plus facilement aux applications et sites Web, sans nécessai- Consultant open source
pour Atos, Mozilla Rep,
rement être obligés de mémoriser des mots de passe complexes. Tout le monde est auteur publié aux
éditions Eyrolles et aux
gagnant : l’utilisateur n’a plus de mots de passe à connaître et pour le développeur, Éditions ENI, PHPère
l’implémentation et la gestion sont plus simples. des elePHPants PHP,
membre des Teams
DrupalFR, AFUP,
WebAuthn signifie Web Authentication. Il s’agit d’un standard tion ouverte qui vise à renforcer et à simplifier l’authentifica- LeMug.fr
du Web Consortium (W3C) avec la contribution de la FIDO tion à deux facteurs en utilisant des périphériques USB ou à (MySQL/MariaDB User
Group FR), Lizard...
Alliance qui propose une interface d’authentification des utili- communication en champ proche (NFC). Figure 1
sateurs aux applications Web à l’aide de clés asymétriques. L’utilisation consiste à placer cette clé sur le port USB de votre
Cela se traduit par une API Web Authentication dédiée. choix de votre ordinateur et lorsque vous souhaitez l’utiliser,
NDLR : depuis 2-3 ans, les géants de la tech parlent de la fin vous devez saisir un mot de passe que vous avez déterminé
des mots de passe. Ils travaillent avec l’alliance FIDO. Durant au préalable.
la dernière WWDC, Apple a présenté son système Passkeys
qui repose justement sur WebAuthn. Mais dans le cas Fonctionnement Figure 2
d’Apple, le matériel par défaut n’est pas une clé USB mais La mise en place d’un workshow avec WebAuthn dans une
plutôt FaceID ou TouchID. application web se déroule en plusieurs étapes.
C’est pourquoi une extension de l’API « credential La première étape consiste à enregistrer un nouvel utilisateur
Management » est prise en charge par l’ensemble des envi- qui pourra se connecter par la suite. Celui-ci envoie d’abord
ronnements (Linux, Windows, Mac), Android, navigateurs un nom d’utilisateur et un mot de passe de son choix (même
(Chrome, Edge, Firefox...). Cette API d’authentification Web si la définition d’un mot de passe n’est pas obligatoire, il est
est disponible en version stable et peut être déployée et mise recommandé d’avoir une méthode d’authentification de
en œuvre par des sites Web sous sa forme actuelle, sans secours). Ensuite, le serveur renvoie une réponse qui sera uti-
crainte de modifications futures. lisée avec l’authentificateur. Ce dernier génère une assertion
Ainsi, WebAuthn permet aux utilisateurs de s’enregistrer et de qui est ensuite reçue par le serveur. Les informations d’iden-
s’authentifier sur des sites Web ou des applications mobiles
en utilisant un “authentificateur” au lieu d’un mot de passe Figure 1
à partir d’une interface d’authentification des utilisateurs aux
applications Web à l’aide de clés asymétriques.
L’ ”authentificateur” peut être une clé de sécurité matérielle
que l’utilisateur a connecté à son ordinateur ou un ID biomé-
trique qui peut être utilisé à partir des capteurs du PC ou du
smartphone, tels que les empreintes digitales, les scans
faciaux, les scans iris et autres.
Standard
Les experts en sécurité considèrent que cette API est un sys-
tème d’authentification sans mot de passe, qui peut être
considéré comme l’avenir de la sécurité des comptes d’utili-
sateurs. C’est pourquoi ce standard viserait à éliminer la
nécessité de saisir des mots de passe lorsque les utilisateurs
se connectent à Internet.
Figure 2
Ainsi, son but va vous permettre de sécuriser l’accès aux
applications web, pour empêcher les attaques de phishing, ce
qui est utile pour les applications en B2B/B2C.
Matériel
Pour utiliser WebAuthn, il faut acquérir une clé USB sécurisée
de type FIDO U2F pour stocker l’ensemble des clés d’authen-
tification. Par exemple, une clé Winkeo FIDO U2F coûte 20 €.
U2F (second facteur universel) est une norme d’authentifica-
programmez.com 19
tification créées auparavant seront attribuées à l’assertion }
générée afin de reconnaître l’utilisateur en cas de besoin. })
Lorsqu’il s’agit de se connecter, le workflow est assez similaire. .then(res => {
L’utilisateur saisit d’abord son nom d’utilisateur et le RP var json = publicKeyCredentialToJSON(res);
(Relying Party) répond automatiquement avec un challenge
qui demande à l’utilisateur de s’authentifier. Pour cela, il doit post(“/webauthn/register”, {
utiliser l’identifiant attribué auparavant. Cela permet au ser- state: “<%= state %>”,
veur d’identifier l’utilisateur. Si l’authentification s’effectue provider: “<%= provider %>”,
avec succès, l’utilisateur peut se connecter. res: JSON.stringify(json)
L’ensemble de ces opérations peut se représenter comme });
l’image Figure 3 })
Si vous avez un authentificateur supporté, vous pouvez tester .catch(console.error);
ce processus ici.
Le code se compose de plusieurs parties avec des arguments
En pratique à prendre en compte :
Au niveau du code, l’opération d’enregistrement se décom- • PublicKey = Générer une clé aléatoire (16 caractères)
pose de la manière suivante. • RP = Nom de l’objet décrivant la partie dépendante lors de
la création
La partie création : • User = Partie utilisateur
navigator.credentials • Res = Réponse au format JSON, renvoyée par le serveur
.create({
publicKey: { La partie Authentification :
navigator.credentials
challenge: base64url.decode(“<%= challenge %>”), .get({
publicKey: {
rp: {
name: “NomCodeApplication” challenge: base64url.decode(“<%= challenge %>”),
}, allowCredentials: [
user: { {
id: base64url.decode(“<%= id %>”), id: base64url.decode(“<%= id %>”),
name: “<%= name %>”, type: “public-key”
displayName: “<%= displayName %>” }
}, ],
authenticatorSelection: { userVerification: “preferred” }, timeout: 15000,
attestation: “direct”, authenticatorSelection: { userVerification: “preferred” }
pubKeyCredParams: [ }
{ })
type: “public-key”, .then(res => {
alg: -7 // “ES256” IANA COSE Algorithms registry var json = publicKeyCredentialToJSON(res);
}
] post(“/webauthn/authenticate”, {
state: “<%= state %>”,
Figure 3 provider: “<%= provider %>”,
res: JSON.stringify(json)
});
})
.catch(err => {
alert(“Invalid FIDO device”);
});
20 programmez.com
Fichier index.html
<!DOCTYPE html>
<html>
<head>
<meta charset=”utf-8”>
<title>WebAuthn Demo</title>
<script src=”https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.
min.js”></script>
</head>
<body>
Username:
<br> Figure 4
<input type=”text” name=”username” id=”email” placeholder=”votre username = $(“#email”).val()
email”> if (username === “”) {
<br> alert(“Saisir un email”);
<br> return;
<button onclick=”registerUser()”>Register</button> }
<button onclick=”loginUser()”>Login</button>
$.get(
<script> ‘/register/begin/’ + username,
null,
$(document).ready(function () { function (data) {
// Verifie si le navigateur est compatible WebAuthn return data
if (!window.PublicKeyCredential) { },
alert(“Error: le navigateur n’est pas compatible avec WebAuthn”); ‘json’)
return; .then((credentialCreationOptions) => {
} // Execution
}); });
}
</script>
</body> </script>
</html>
Lors de la création, un appel sera effectué vers le serveur, en
Ce formulaire propose 2 boutons : création et la connexion appelant le fichier server.go contenant :
programmez.com 21
}) }
r.PathPrefix(“/”).Handler(http.FileServer(http.Dir(“./”))) db.mu.Lock()
defer db.mu.Unlock()
serverAddress := “:8080” db.users[user.name] = user
log.Println(“starting server at”, serverAddress) }
log.Fatal(http.ListenAndServe(serverAddress, r))
} L’implémentation User se fait par l’interface utilisateur de
duo-lab. :
Le fichier a pour but d’initialiser WebAuthn, nous fournissons Code complet sur programmez.com & github
une configuration avec deux champs (il y a d’autres champs
optionnels), tous sont liés à la Relying Party (RP) qui est l’ap- Après dans le fichier server.go, nous implémentons le ges-
plication/entité web qui enregistre et authentifie l’utilisateur. tionnaire BeginRegistration.
Les champs sont RPDisplayName : le nom d’affichage du site
func BeginRegistration(w http.ResponseWriter, r *http.Request) {
du RP (par exemple Foobar Corp.) et RPID : basé sur le nom
de domaine du RP (par exemple foobar.com).
// get username
Nous stockons les utilisateurs enregistrés qui seront gérés par
vars := mux.Vars(r)
le fichier userdb.go suivant :
username, ok := vars[“username”]
if !ok {
package main
jsonResponse(w, fmt.Errorf(“must supply a valid username i.e. foo@
bar.com”), http.StatusBadRequest)
import (
return
“fmt”
}
“sync”
}
)
Dans le fichier JS où se trouve la fonction registerUser(), les
type userdb struct { options de création d’accréditation retournées par le serveur,
users map[string]*User ressemblent à ceci :
mu sync.RWMutex
} {
“publicKey”: {
var db *userdb “challenge”: “FsxBWwUb1jOFRA3ILdkCsPdCZkzohvd3JrCNeDqWpJQ=”,
“rp”: {
// DB returns a userdb singleton “name”: “Foobar Corp.”,
func DB() *userdb { “id”: “localhost”
},
if db == nil { “user”: {
db = &userdb{ “name”: “[email protected]”,
users: make(map[string]*User), “displayName”: “foo”,
} “id”: “xOywiL6f3q9EAA==”
} },
“pubKeyCredParams”: [
return db {
22 programmez.com
“type”: “public-key”, L’appel de la fonction « BeginLogin » est très similaire à
“alg”: -7 « BeginRegister ». C’est à dire, nous appelons duo-
}, labs/webAuthns BeginLogin() avec un utilisateur (et des
{ LoginOptions optionnelles) et nous obtenons les options
“type”: “public-key”, retournées (implémentation de PublicKeyCredentialRequest
“alg”: -35 Options discutées ci-dessous), sessionData (utilisée pour véri-
}, fier l’assertion retournée), et une erreur si quelque chose ne
... va pas. Nous stockons les données de session et retournons
{ les options à l’utilisateur.
“type”: “public-key”, Code complet sur programmez.com & github
“alg”: -8
} Le credentialRequestOptions se présente comme suit :
], {
“authenticatorSelection”: { “credentialRequestOptions”: {
“userVerification”: “preferred” “publicKey”: {
}, “challenge”: “AZeYdiLc1hGDU0wo9NOZmZG9vu+aPnff2aPFgJEw1HI=”,
“timeout”: 60000, “timeout”: 60000,
“attestation”: “direct” “rpId”: “localhost”,
} “allowCredentials”: [
} {
“type”: “public-key”,
“id”: “ABJcniVJwrH45aueEJJsD0LFTGMUxot1sHCOttym/p7rNPF72Zc
Connexion
/NcGo05j3KzDkU5fWELqRz7h9”
La partie connexion de notre formulaire est un peu différente
}
de la partie d’enregistrement : Figure 4
]
}
� Le serveur met à disposition différentes informations,
}
exposées au JavaScript
}
� Le navigateur relaie ces informations hashées du client
� L’authentificateur vérifie l’utilisateur et confirme la clé Les autres étapes de vérifications sont traitées sur le même
� Il renvoie une attestation de signature principe.
� le JavaScript renvoie l’attestation au serveur au format
JSON Au final
� le serveur valide la réponse Comme le montre l’exemple, la mise en place de webauthn
est assez simple. L’ensemble du code est disponible sur le
Au niveau du code, l’appel est effectué à partir du bouton dépôt de l’auteur de l’extension que vous pouvez retrouver :
loginUser() de la page index.html en récupérant le nom d’utilisa- https://github.com/hbolimovsky/webauthn-example
teur et en effectuant un appel GET vers /login/begin/{username}.
Conclusion
function loginUser() {
WebAuthn fait évoluer la gestion de l’authentification, mais
est dépendant aussi du matériel, qui commence à être inté-
username = $(“#email”).val()
gré dans les différents terminaux. Même si la route peut sem-
if (username === “”) {
bler longue, son fonctionnement est plutôt simple.
alert(“please enter a username”);
return;
} Figure 4
$.get(
‘/login/begin/’ + username,
null,
function (data) {
return data
},
‘json’)
.then((credentialRequestOptions) => {
// TODO
})
}
programmez.com 23
.NET 7: nouveautés et améliorations
Dernière version en date du framework cross-platform de Microsoft, .NET 7 apporte
Pierre Bouillon son lot de nouveautés et d’améliorations à de nombreux niveaux et sur divers aspects
Ingénieur logiciel Full
de son écosystème (Minimal API, System.Text.JSON, etc.). A cela se rajoute une nou-
Stack développant
principalement des velle version de C#.
applications web avec
.NET et Angular. .Net 7 n’est pas une version LTS comme l’est .Net 6 et la charge. Dans le cadre d’un système réagissant à des événe-
https://pbouillon.github.io future v8. Si vous cherchez une version à support long, soit ments extérieurs par exemple, il n’est pas rare qu’un message
vous restez sur la 6 ou attendez la 8. soit un dérivé d’un type de base.
Prenons par exemple une entité Customer et un événement
Installation et mise à jour CustomerCreated associé à sa création :
L’installation de .NET 7 se fait de la même manière que les
record Customer(int Id, string Name);
versions précédentes, à savoir via le site de Microsoft
record CustomerCreated(int Id, string Name, DateTime CreatedOn)
https://dotnet.microsoft.com.
: Customer(Id, Name);
Plusieurs images docker sont également disponibles sur le
.NET du docker hub de Microsoft : https://hub.docker.com/_/micro- Si nous souhaitons émettre des événements relatifs aux
soft-dotnet. clients, le système peut les sérialiser et désérialiser en tant
Localement, pour utiliser la dernière version du framework, il que Customer pour ne pas réaliser une implémentation pour
vous faudra simplement changer l’attribut TargetFramework chaque classe héritant de la classe mère.
du csproj de votre projet cible pour net7.0. Dans notre cas, la sérialisation d’un événement CustomerCreated
Certaines fonctionnalités accompagnant la dernière version et sa désérialisation pourrait ressembler à ceci :
de C# ne sont pas encore immédiatement utilisables. Aussi,
Customer customer = new CustomerCreated(1, “John Doe”, DateTime.Now);
pour activer celles qui vous manqueront, vous pouvez
manuellement ajouter la propriété LangVersion et l’assigner
var serialized = JsonSerializer.Serialize(customer);
à preview.
// { “Id”: 1, “Name”: “John Doe” }
Voici un exemple du type de csproj que vous pourriez avoir
pour un projet console paramétrée pour .NET 7 :
var deserialized = JsonSerializer.Deserialize<CustomerCreated>(serialized);
<Project Sdk=”Microsoft.NET.Sdk”> // {CustomerCreated { Id = 1, Name = John Doe, CreatedOn = 01/01/0001 00:00:00 }}
<PropertyGroup>
Pourtant, avec cette approche, deux problèmes majeurs sont
<OutputType>Exe</OutputType>
immédiatement visibles. Tout d’abord, la valeur sérialisée ne
<TargetFramework>net7.0</TargetFramework>
contient aucune information qui n’est pas dans le type de base
<LangVersion>preview</LangVersion>
et la date de création est ainsi perdue. En réalité, le sérialiseur
</PropertyGroup>
ne prend pas en compte le type réel du paramètre, mais sim-
</Project>
plement le type sous lequel il est utilisé. Ici, comme notre ins-
Étant une mise à jour majeure, cette version introduit des tance de CustomerCreated est manipulée sous le type
changements qui rendent incompatibles ou obsolètes cer- Customer, tout le contexte rajouté par la classe fille est perdu.
tains appels effectués avec des versions antérieures du fra- Ensuite, cause directe du problème précédent, la désérialisa-
mework. tion en le type fille résulte en la complétion des propriétés
Par exemple, la logique de comparaison des types NaN a été manquantes par leurs valeurs par défaut.
altérée, le package Microsoft.Data.SqlClient a été mis à jour, Notre événement, une fois la sérialisation/désérialisation
certains types d’exceptions levé par certaines API ont été faite, contient ainsi des valeurs totalement erronées (1er jan-
modifié, et plus encore. vier de l’an 1 à minuit au lieu de la date courante).
Pour consulter ces dernières, Microsoft les a listées, ainsi que C’est à ce type de problème que .NET 7 apporte une solution
les éventuelles actions de remédiation à entreprendre, dans en permettant aux développeurs de définir, pour une classe
une page de documentation dédiée : https://docs.microsoft.com/fr- donnée, les types des classes héritant de cette dernière.
fr/dotnet/core/compatibility/7.0. Dans notre exemple, il suffit alors de spécifier que Customer
est héritée par CustomerCreated avec l’attribut
.NET JsonDerivedTypeAttribute :
Gestion du polymorphisme
dans System.Text.Json [JsonDerivedType(typeof(CustomerCreated))]
Jusqu’alors la sérialisation et la désérialisation d’instances record Customer(int Id, string Name);
avec System.Text.Json ne permettaient pas de gérer facile-
ment le polymorphisme et nécessitaient de coder des record CustomerCreated(int Id, string Name, DateTime CreatedOn)
contournements pour réussir à le prendre partiellement en : Customer(Id, Name);
24 programmez.com
En décorant la classe Customer de cette manière, on indique Les types de limitateurs
alors au sérialiseur qu’il doit traiter la désérialisation de notre Conscients des problématiques propres à chaque équipe et
instance en gardant le contexte associé. projet, le package NuGet System.Threading.RateLimiting
Ainsi, le même code nous donne alors les résultats suivants expose divers limitateurs, chacun fonctionnant selon une
dans lesquels le contexte a pu être préservé : logique lui étant propre.
Bien que le type de limitateur choisi puisse différer, la mise en
Customer customer = new CustomerCreated(1, “John Doe”, DateTime.Now);
place de l’un d’entre eux se fait au travers de la méthode
d’extension UseRateLimiter. Cette dernière prend en para-
var serialized = JsonSerializer.Serialize(customer);
mètre une instance de RateLimiterOption qui définira au tra-
// {“CreatedOn”:”2022-07-10T11:50:41.9534943+02:00”,”Id”:1,”Name”:”John Doe”}
vers de sa propriété Limiter le limitateur utilisé.
La structure de la mise en place d’un middleware de limitation
var deserialized = JsonSerializer.Deserialize<CustomerCreated>(serialized);
de requêtes HTTP s’articule ainsi de la manière suivante :
// {CustomerCreated { Id = 1, Name = John Doe, CreatedOn = 10/07/2022 11:50:41 }}
app.UseRateLimiter(new RateLimiterOptions
Cette approche répond à notre problème dans le cadre où
{
toutes les instances sont manipulées au sein même du runti-
Limiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
me.
{
En revanche, si l’objet sérialisé provient d’un système tiers,
return /* ... */;
System.Text.Json manquera alors de contexte pour savoir
}),
comment désérialiser le message vers le bon type.
});
Là encore, une solution est apportée au travers des autres
constructeurs disponibles : La méthode statique PartitionedRateLimiter.Create<,> per-
met de définir une lambda afin de créer ce limitateur. Via les
public JsonDerivedTypeAttribute(Type derivedType);
deux types génériques, il est possible, au sein de cette lamb-
public JsonDerivedTypeAttribute(Type derivedType, int typeDiscriminator);
da, d’accéder au HttpContext courant afin de récupérer des
public JsonDerivedTypeAttribute(Type derivedType, string typeDiscriminator);
informations relatives à la session courante.
Il est possible de spécifier un discriminateur sous forme d’un
entier ou d’une chaîne de caractère.
Concurrent
Concrètement, il s’agit d’une sorte de métadonnée ajoutée à Le premier des limitateurs est celui correspondant le plus au
l’instance sérialisée afin d’aider le sérialiseur à inférer le type comportement auquel on peut s’attendre lorsque l’on ajoute
qu’il doit traiter. ce mécanisme à son API : les requêtes HTTP entrantes sont
En spécifiant un discriminant, il apparaît alors sous la forme placées dans une file et progressivement traitées au fil du
suivante : temps.
À partir de la méthode de création vue ci-dessus, nous pou-
var serialized = JsonSerializer.Serialize(customer);
vons le définir de la manière suivante :
// {“$type”:”CustomDiscriminator”,”CreatedOn”:”2022-07-10T16:59:43.038819+02:00”,
”Id”:1,”Name”:”John Doe”} app.UseRateLimiter(new RateLimiterOptions
{
var deserialized = JsonSerializer.Deserialize<CustomerCreated>(serialized); Limiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
// {CustomerCreated { Id = 1, Name = John Doe, CreatedOn = 10/07/2022 11:50:41 }} {
return RateLimitPartition.CreateConcurrencyLimiter(
[JsonDerivedType(typeof(CustomerCreated), “CustomDiscriminator”)] “ConcurrencyLimiter”,
record Customer(int Id, string Name); _ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 0));
}),
record CustomerCreated(int Id, string Name, DateTime CreatedOn) });
: Customer(Id, Name);
Déconstruisons sa création au fil de ses paramètres. Le pre-
Le sérialiseur pourra alors, sur base de cette valeur, désériali- mier est son nom, utilisé pour nommer et définir le limitateur
ser le bon type même si la valeur sérialisée provient d’un sys- et le second est une méthode lambda de construction du
tème tiers. limitateur, définissant son comportement.
Bien que représentant déjà une avancée facilitant grande- Dans cette méthode le premier paramètre est le nombre de
ment la gestion de la sérialisation/désérialisation des mes- requêtes que le système pourra traiter à un instant donné (ici 1).
sages, on peut cependant espérer voir apparaître prochaine- Le second paramètre est l’ordre dans lequel les requêtes pla-
ment une version un peu plus claire faisant usage de la géné- cées dans la file seront traitées. Deux valeurs sont possibles,
ricité nouvellement possible avec les attributs pour pouvoir à savoir les plus anciennes ou les plus récentes d’abord (LIFO
fortement les typer au lieu d’utiliser typeof. ou FIFO).
Enfin, le dernier paramètre est le nombre de requêtes pou-
ASP.NET vant être placées dans cette file. Ces dernières seront alors
Limiter les requêtes entrantes dans un état d’attente où elles ne seront ni traitées ni reje-
Fonctionnalité attendue depuis longtemps : la limitation de tées. Dans notre exemple aucune requête ne peut être dans
requêtes HTTP entrantes arrive enfin avec .NET 7. la file ce qui se manifestera en pratique par le rejet de toutes
programmez.com 25
les requêtes dès lors que le système sera actuellement en certain nombre de jetons (5 minutes dans l’exemple)
train d’en traiter une et une seule. • Le nombre de jetons redonnés au bout de cette période (5
également)
Illimité Si le système redonne automatiquement ou non ce nombre
Le second (plus explicite) est simplement celui qui n’a aucune de jetons au bout de la période définie
action limitante et laisse passer l’entièreté des requêtes. Il n’est pas possible de récupérer plus de jetons que l’utilisa-
Sa création est également la plus directe puisqu’elle ne né- teur n’en dispose initialement. Par exemple, même s’il ne fait
cessite pas de logique spécifique du fait de sa simplicité. Le qu’une requête en 5 minutes et dispose encore de 9 jetons
seul paramètre attendu est son nom : au bout de la période où le système en redonne, il ne dispo-
sera alors que de 10 jetons à nouveau et non de 14.
app.UseRateLimiter(new RateLimiterOptions
Un cas d’utilisation particulièrement adapté à ce genre de
{
fonctionnement pourrait être la limitation du nombre d’ap-
Limiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
pels que peut réaliser un client à une API payante. Il serait
{
alors possible de donner aux utilisateurs un nombre de jetons
return RateLimitPartition.CreateNoLimiter(“NoLimiter”);
plus ou moins grand selon leur type d’abonnement.
}),
Cependant, un inconvénient majeur qu’il porte également est
});
le fait qu’il ne puisse pas être distribué. Ainsi, si vous avez
Tel quel, il peut être difficile de se représenter des cas deux instances d’une même API, alors deux limitateurs avec
d’usages où un limitateur qui ne l’est pas peut se révéler per- chacun leur propre compteur interne de jetons seront expo-
tinent. sés. Aussi, lors du traitement d’une requête, seul l’un de ces
En réalité, il est possible de multiplier les limitateurs utilisés deux limitateurs consommera un jeton de l’utilisateur.
par l’application et de les conditionner à une route spéci-
fique. De cette façon, certaines routes peuvent ne pas être Affiner la limitation
soumises à une limitation contrairement à d’autres. Nous Ces trois types de limitateurs représentent en eux-mêmes un
verrons par la suite comment définir un tel comportement. ajout particulièrement intéressant de .NET 7, mais il est éga-
lement possible d’affiner leurs utilisations en se reposant sur
A l’aide de jetons le contexte les accompagnants.
Le dernier des limitateurs est à la fois le plus complexe à
construire, mais également le plus intéressant à mon sens Selon les routes
d’un point de vue pratique et se définit comme ceci : Comme mentionné plus tôt, un limitateur qui ne jugule pas
le flux de requêtes entrantes n’est pas toujours pertinent.
app.UseRateLimiter(new RateLimiterOptions
Cependant, il n’est pas plus pertinent de brider l’accès à cer-
{
taines routes spécifiques, telles que la version par exemple.
Limiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
Grâce au contexte HTTP passé dans la lambda définissant le
{
rate limiter, il est possible de récupérer la requête, donc la
return RateLimitPartition.CreateTokenBucketLimiter(
route courante, pour agir différemment selon sa valeur et
“TokenBucketLimiter”,
ainsi implémenter ce comportement :
_ => new TokenBucketRateLimiterOptions(
10, QueueProcessingOrder.NewestFirst, 0, app.UseRateLimiter(new RateLimiterOptions
TimeSpan.FromMinutes(5), 5, true)); {
}), Limiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
}); {
if (context.Request.Path == “/version”)
Contrairement aux limitateurs précédents, le sens des para-
{
mètres de celui-ci est moins équivoque et nécessite de com-
return RateLimitPartition.CreateNoLimiter(“NoLimiter”);
prendre la logique encapsulée par le TokenBucketRate
}
Limiter. Pour se représenter son fonctionnement, il faut se
figurer une machine qui prendrait un jeton en entrée pour
return RateLimitPartition.CreateConcurrencyLimiter(
fonctionner et un utilisateur disposant d’un nombre donné de
“ConcurrencyLimiter”,
ces jetons. Chaque jeton permet de faire exécuter une requê-
_ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 0));
te HTTP par le système qui périodiquement, au bout d’une
}),
période définie, en redonne un certain nombre à l’utilisateur,
});
qui peut alors les réutiliser pour exécuter d’autres requêtes.
Chacun de ces paramètres est alors, dans l’ordre : Selon l’authentification
• Le nombre de jetons dont dispose l’utilisateur (10 dans Au-delà des routes, c’est parfois selon certains rôles qu’il est
notre cas) nécessaire d’adapter le middleware.
• L’ordre dans lequel les requêtes en attente seront traitées Par exemple, il est envisageable que les utilisateurs classiques
• Le nombre de requêtes pouvant être mises en attente (ici voient leurs requêtes limitées, là où les administrateurs ne
aucune) devraient pas l’être.
• Le temps à attendre avant que le système ne redonne un Là encore, grâce au HttpContext, récupérer les autorisations
26 programmez.com
ou le statut de l’authentification de l’utilisateur émettant la Avec .NET 7, les filtres arrivent enfin sur les endpoints définis
requête est tout à fait réalisable : pas les RouteHandlerBuilders avec plusieurs méthodes d’ex-
tensions AddFilter.
app.UseRateLimiter(new RateLimiterOptions
Ils peuvent être créés de nombreuses façons, mais retournent
{
systématiquement un RouteHandlerBuilder, permettant de
Limiter = PartitionedRateLimiter.Create<HttpContext, string>(context =>
chaîner l’appel d’AddFilter à d’autres méthodes d’extension
{
et ainsi de conserver la définition en cascade des endpoints.
var isAdmin = context.User.Claims.Any(claim => claim.Value == “admin”);
La première des manières de créer un filtre est en lui passant
directement un délégué créé à partir du RouteHandler
if (isAdmin)
InvocationContext, donnant des précisions sur les paramètres
{
et la nature de l’appel, et d’un RouteHandler FilterDelegate,
return RateLimitPartition.CreateNoLimiter(“NoLimiter”);
délégué vers l’appel suivant.
}
Comme pour les autres méthodes d’extension AddFilter, le
délégué retournera un ValueTask<object?>. Il est ainsi pos-
return RateLimitPartition.CreateConcurrencyLimiter(
sible de court-circuiter la chaîne d’appel et de renvoyer au
“ConcurrencyLimiter”,
plus tôt une valeur synchrone au lieu de continuer le flux
_ => new ConcurrencyLimiterOptions(1, QueueProcessingOrder.NewestFirst, 0));
d’exécution asynchrone en cas de condition bloquante.
}),
Voici une simple implémentation d’un filtre avec un délégué,
});
rejetant les appels pour une liste donnée de noms :
Définir les actions engendrées
var blockList = new[] { “John”, “Doe” };
Plus que le limitateur lui-même, il est parfois désirable de
réaliser certaines actions en réponse à une requête rejetée
app.MapGet(“hello/{name}”, (string name) => $”Hello {name} !”)
(journalisation, statistiques, etc.).
.AddFilter(async (routeHandlerInvocationContext, next) =>
C’est cette fois-ci au travers des propriétés OnRejected et
{
DefaultRejectionStatusCode de l’objet englobant RateLimiterOptions
var name = routeHandlerInvocationContext.GetArgument<string>(0);
qu’il sera possible d’influer sur ces cas de figure :
programmez.com 27
{ }
return Results.Problem($”{name} is not allowed”); }
}
On note alors deux points redondants qui apportent une cer-
return await next(routeHandlerInvocationContext); taine verbosité aux définitions des endpoints: la répétition du
}; préfixe de la route et la spécification du contrôle d’accès.
}); Dans .NET 7 il est possible, via la nouvelle classe
RouteGroupBuilder et sa méthode d’extension, de définir un
Enfin, il est possible de passer non pas un bloc de code, mais ensemble d’endpoint pour une route donnée et d’y spécifier
une classe spécifique, implémentant l’interface un ensemble de caractéristiques qui seront communes à tous
IRouteHandlerFilter. Cette dernière ne définit qu’une métho- les endpoints ainsi définis :
de à implémenter qui est la suivante :
var builder = WebApplication.CreateBuilder(args);
ValueTask<object?> InvokeAsync(RouteHandlerInvocationContext context, RouteHand
var app = builder.Build();
lerFilterDelegate next);
app.MapProductEndpoints();
28 programmez.com
(version, description, etc.), mais également aux endpoints qui Amélioration des types de retour
la compose (type de retour, routes, codes HTTP de retour, Amélioration de la testabilité des types
etc.) Avec OpenAPI et son intégration facilitée par des librai- retournés
ries tierces telles que Swashbuckle ou encore NSwag, leur Avec .NET 6, les endpoints retournant une réponse en plus
documentation est devenue à la fois un incontournable du de données particulières pouvaient jouir de l’interface nou-
développement d’API, mais également un standard au point vellement introduite IResponse.
que la mise en place d’un Swagger avec Swashbuckle peut Pour retourner des instances de cette dernière, la classe sta-
être générée dès la création d’un nouveau projet. tique Results exposaient un certain nombre de méthodes
Avec .NET 7, un nouvelle librairie Microsoft.AspNetCore. symbolisant tant bien la redirection, qu’un échec ou un suc-
OpenApi va être disponible afin de documenter ses end- cès de la requête.
points. Cette dernière devrait permettre de générer la spéci- Un endpoint typique avait alors la forme suivante :
fication OpenAPI d’un endpoint d’une minimal API à partir
app.MapGet(“api/products”, GetProducts);
de ses métadonnées et de la route.
L’utilisation la plus simple de la méthode exposée et un
IResult GetProducts()
simple appel à la méthode d’extension WithOpenApi() :
{
app.MapGet(“api/products/{id}”, (Guid id) => var products = new Product[] { /* ... */ };
{ return Results.Ok(products);
var product = products.SingleOrDefault(product => product.Id == id); }
return Results.Ok(product);
Pourtant, l’inconvénient majeur de IResult était que les
})
classes qui l’implémentait n’étaient pas publiques. Impossible
.WithOpenApi();
donc de manipuler le type de réponse effectivement renvoyé,
Il est cependant possible d’enrichir la description de cette opéra- ce qui est particulièrement gênant si l’on souhaite tester les
tion en précisant de nombreux aspects de l’endpoint ainsi déco- endpoints et leurs retours, car la réponse, ainsi que les don-
ré. On peut alors documenter à la fois l’opération elle-même, nées qu’elle englobe sont inaccessibles programmatique-
mais aussi ses paramètres, s’ils doivent respecter certaines condi- ment.
tions, ou bien encore les types de retour et leur format : Avec .NET 7, deux changements majeurs ont été réalisés
pour solutionner ce désagrément.
app.MapGet(“api/products/{id}”, (Guid id) =>
Dans un premier temps, les types implémentant IResult ont
{
été rendus publics. Il est donc maintenant possible d’accéder
var product = products.SingleOrDefault(product => product.Id == id);
à une instance de la classe Ok<TResponse> dans ses tests,
return Results.Ok(product);
pour s’assurer à la fois du type de retour, mais également au
})
type des données retournées.
.WithOpenApi(operation =>
Cependant, seulement avec ce changement, le type de retour
{
de notre endpoint précédemment défini n’est pas
operation.Summary = “Retrieve a specific product given its ID”;
Ok<Product[]> comme on pourrait s’y attendre, mais
Ok<object>. La raison vient du fait que Results.Ok prend en
operation.Parameters[0].Description = “The ID of the product to retrieve”;
paramètre un type object?, masquant ainsi le type d’origine
operation.Parameters[0].AllowEmptyValue = false;
de la réponse. Pour pallier à ce problème, Microsoft a publié
une nouvelle classe statique, équivalente à l’existante
return operation;
Microsoft.AspNet Core.Http.Results, mais qui, elle, préserve
});
les informations relatives au type d’origine: Microsoft.AspNet
C’est dans cette seconde utilisation que la librairie montre Core.Http. TypedResults.
son potentiel intérêt, en permettant d’apporter le même Cette dernière s’utilise sensiblement de la même manière et
degré d’information que Swashbuckle pourrait le faire via la notre endpoint ainsi modifié n’a pas besoin de changement
xlmdoc ou bien des attributs, mais cette fois-ci directement autre que le changement de Results en TypedResults :
en bénéficiant du C# dans un bloc dédié.
app.MapGet(“api/products”, GetProducts);
Reste à suivre l’évolution de ce package qui pour le moment
pourrait être perfectible en ce qui concerne l’accès à certains
IResult GetProducts()
paramètres. Par exemple, la récupération d’un paramètre
{
particulier est actuellement faite via un index sur
var products = new Product[] { /* ... */ };
Operation.Parameters et peut alors être sujet à problème si la
return TypedResults.Ok(products);
signature d’un endpoint vient à changer.
}
Une autre limitation à cette méthode d’extension précédem-
ment mentionnée est qu’elle n’est actuellement pas compa- Le type des données TResponse du retour Ok<TResponse>
tible avec les RouteGroupBuilder et il n’est donc pas possible sera alors bien Product[] et non plus object comme précé-
de l’utiliser au niveau d’un groupement d’endpoint pour le demment.
moment, bien que Microsoft ait annoncé qu’il s’agit là d’une L’avantage de cette nouvelle classe, reposant sur les mêmes
fonctionnalité déjà planifiée. définitions que .NET 6, est qu’elle permet de transitionner
programmez.com 29
vers des retours où le type est préservé et plus pertinent sans Le fait de bénéficier d’une union typée permet également de
nécessiter un remaniement immédiat de l’existant. remonter des erreurs dès la compilation d’une éventuelle dissonan-
De la même manière que les nullables pouvaient être chirur- ce dans l’implémentation de la logique par rapport à la signature:
gicalement appliqués, avec cette stratégie il est possible de
progressivement utiliser la nouvelle classe TypedResults sans C# 11 : Figure 2
risquer une régression des endpoints déjà fonctionnels. La De multiples changements sont à noter, et en particulier en
seule différence sera que d’éventuels tests, s’assurant que le ce qui concerne les patterns ainsi que la gestion des strings.
retour était bien du type Ok<object> échoueront à présent.
Prise en charge du multi-lignes pour
Amélioration de la signature des retours des les strings interpolées
endpoints Jusqu’à C# 10, l’interpolation ne prenait pas en charge plu-
Bien que par la programmation il soit maintenant possible de sieurs lignes de C# et l’entièreté devait donc être écrit en une
récupérer le type sous-jacent de la réponse grâce à seule fois sans retours. Aussi, de longues expressions (un cal-
TypedResults, le type de retour reste bien IResult et ne donne cul avec LINQ par exemple) devenaient rapidement très ver-
alors que peu d’informations sur la réponse à la seule lecture beux et peu lisible à la simple lecture du code.
de la signature de l’endpoint : Avec C# 11, il est maintenant possible de séparer en plu-
sieurs ligne ce genre d’expressions :
app.MapGet(“api/products/{id}”,
IResult (Guid id) => // Avant C# 11
{ _ = $”‘0’ in text is {Enumerable.Range(0, 10).Select(index => index + 1).Sum()}”;
var products = new Product[] { /* ... */ };
var product = products.SingleOrDefault(product => product.Id == id); // Avec C# 11
_ = $”‘0’ in text is {Enumerable.Range(0, 10)
return product is null .Select(index => index + 1)
? TypedResults.NotFound() .Sum()}”;
: TypedResults.Ok(product);
La prise en charge est d’autant plus efficace qu’il ne s’agit pas
});
juste de retour à la ligne, mais bien de prendre en charge n’im-
De la même manière, la découvrabilité de l’endpoint, dans le porte quel code C# valide, par exemple une switch expression :
but que sa documentation soit la plus précise possible dans
// Avant C# 11
un Swagger par exemple, s’en trouve limitée. Pour répondre
var binaryDigitToString = (int number) => number switch
à ce problème, une autre classe a été ajoutée : Results
{
<TResult1, TResultN>. Cette dernière permet de retourner
0 => “zero”,
un ensemble de réponses de type IResult, possiblement
1 => “one”,
retournés par l’endpoint. En bénéficiant de ce type, il nous
_ => “?”,
est alors possible d’affiner la définition de notre endpoint :
};
app.MapGet(“api/products/{id}”, _ = $”‘0’ in text is {binaryDigitToString(0)}”;
Results<NotFound, Ok<Product>> (Guid id) =>
{ // Avec C# 11
var products = new Product[] { /* ... */ }; _ = $”‘0’ in text is {0 switch
var product = products.SingleOrDefault(product => product.Id == id); {
0 => “zero”,
return product is null 1 => “one”,
? TypedResults.NotFound() _ => “?”,
: TypedResults.Ok(product); }}”;
});
Bien qu’intéressante, cette fonctionnalité laisse cependant
La documentation résultant dans la Swagger UI en est ainsi dubitatif et pourrait inciter à produire du code moins lisible.
d’autant plus précise. Il faudra donc rester vigilant à l’utiliser avec parcimonie.
Bien que déjà intéressant en soit pour la lisibilité et l’enrichis-
sement de la Swagger UI, l’affinage des retours des end- Introduction des raw strings literals
Figure 2 points ne se limite pas à ces seuls avantages. Les raw string literals sont un nouveau type de strings intro-
duites avec C# 11.
Ces dernières ont la particularité de commencer par trois
doubles quotes et de pouvoir contenir n’importe quel texte, y
compris les espaces, sauts de ligne, quotes ou encore des
caractères spéciaux, sans nécessiter de les échapper :
_ = “”“
This is a string
30 programmez.com
“literal” Toujours au sujet de la construction des structures, si une de
“”“; ces dernières ne possède que des propriétés accessibles, il est
alors possible de la créer sans l’opérateur new :
Dans le cas où l’on souhaiterait y incorporer un texte conte-
Person p;
nant autant de quotes que le délimiteur, il est possible de
p.Id = 1;
multiplier ces dernières au début et à la fin pour échapper le
p.Name = “John”;
texte :
struct Product La fonctionnalité peut donc se révéler très puissante dans cer-
{ tains cas de figure, mais également rapidement devenir cryp-
public int Id { get; set; } tique. Là encore, il faudra peut-être être vigilant quant à son
public string Name { get; set; } = “Not set”; utilisation et éventuellement la combiner à LINQ pour garder
un code lisible.
public Product(int id) => Id = id;
public Product(int id, string name) => (Id, Name) = (id, name); Généricité pour les entités mathématiques
La généricité est un concept largement couvert et utilisé au
public override string ToString() => $”#{Id}: {Name}”; sein du framework. Pourtant, bien qu’il soit possible d’ajouter
} des contraintes sur les types génériques afin de s’assurer
programmez.com 31
qu’ils respectent une certaine forme, il n’était jusqu’alors pas de manière statique des attributs particuliers d’une classe.
possible de contraindre un type générique à être un nombre.
Avant .NET 7, rendre générique une méthode mathématique Attributs génériques
nécessitait sa réécriture et résultait souvent en l’écriture de ce Dans le même contexte d’amélioration de la généricité, les
genre de code : attributs souffraient également d’un manque de prise en
charge des types génériques.
int ComputeSumInt(params int[] numbers)
Historiquement, afin de récupérer un type depuis un attribut,
{
ce dernier devait le prendre sous la forme d’un attribut de
var result = 0;
type Type :
foreach (var number in numbers) result += number;
return result; [AttributeUsage(AttributeTargets.Class)]
} class FruitAttribute : Attribute
{
double ComputeSumDouble(params double[] numbers) private readonly Type _fruitType;
{
var result = .0; public FruitAttribute(Type fruitType)
foreach (var number in numbers) result += number; => _fruitType = fruitType;
return result; }
}
[Fruit(typeof(Apple))]
Dans cette mise à jour un nouveau type INumber<T> a été
class Golden { }
ajouté, ce dernier étant implémenté par tous les types numé-
riques natifs (int, float, double, etc.). Ce qui impliquait une certaine quantité de code afin de récu-
En plus de définir le comportement des opérateurs, il expose pérer un type, et encore plus si l’on souhaitait s’assurer de sa
aussi d’autres concepts tels que la notion de 0 ou de 1 par validité par exemple, dans notre cas, vérifier que le type passé
exemple. est bien un fruit.
Ainsi, le code que l’on pouvait trouver dupliqué précédem- Dorénavant, il est possible d’utiliser la généricité avec les
ment peut être remanié de manière nettement plus claire attributs afin de fortement les typer, mais également de béné-
grâce à l’application de la généricité nouvellement possible. ficier du système de contraintes pour s’assurer qu’il convient
Au-delà de la perspective de générifier certaines méthodes à nos besoins :
mathématiques, la possibilité de pouvoir générer ses propres
[AttributeUsage(AttributeTargets.Class)]
types de nombres est également intéressante.
class FruitAttribute<T> : Attribute where T : IFruit { }
32 programmez.com
Principales nouveautés détaillées de
JavaScript de ES2015 (ES6) à ES2021
(ES12) Sylvain Cuenca
Je suis Architecte
Système basé en région
PARTIE 2.2 : LES NOUVEAUTÉS DE JAVASCRIPT 2017 toulousaine et tout
simplement passionné
d’informatique depuis
Nous allons explorer au travers de cet article les principales évolutions du langage JavaS- mon plus jeune âge,
cript de 2015 à 2021 accompagnées d’exemples illustrant les nouveautés apportées par avec bientôt une
vingtaine d’années
les différentes versions. JavaScript repose sur les standards d’ECMAScript qui lui se d’expérience dans le
monde du logiciel. Les
charge de définir un ensemble de normes concernant les langages de programmation de thématiques autour de
type script et standardisées par Ecma International dans le cadre de la spécification l’architecture logicielle
en général, les
ECMA-262. Dans cette partie, nous allons finir avec les nouveautés JavaScript 2017. performances, la
fiabilité, la robustesse, la
Ajout de la fonction Object#values(myObject) Obtention des valeurs des propriétés énumérables d’un maintenabilité,
l’amélioration continue
La fonction « Object#values() » renvoie un tableau dont les objet semblable à un tableau, mais dont les index sont or-
et l’empreinte mémoire
éléments sont les valeurs des propriétés énumérables directe- donnés de manière aléatoire des solutions logicielles
ment rattachées à l’objet passé en argument. L’ordre du sont des sujets que
const TOYOTA_GROUP = {
tableau est le même que celui obtenu lorsqu’on parcourt les j’aborde pleinement au
3: ‘Scion’, quotidien. En parallèle,
propriétés manuellement.
1: ‘Toyota’, j’effectue beaucoup de
0: ‘Lexus’, veille technologique,
• Syntaxe : m’occupe de la montée
2: ‘Daihatsu’
Object.values(myObject) en compétence des
}
• - Le paramètre « myObject » représente l’objet dont on sou- équipiers et pratique les
haite connaître les valeurs de ses propriétés énumérables. méthodes japonaises
console.log(Object.values(TOYOTA_GROUP)); Kaizen sur l’amélioration
continue autant sur le
• Exemples : Affichage dans la console : plan personnel que
Obtention des valeurs des propriétés énumérables d’un objet professionnel.
[ ‘Lexus’, ‘Toyota’, ‘Daihatsu’, ‘Scion’ ]
const MY_CAR = {
Dans cet exemple, on s’aperçoit que la fonction
brand: ‘Acura’,
« Object#values » trie par ordre croissant les propriétés selon
model: ‘NSX’,
leur index avant de retourner les valeurs associées aux pro-
color: ‘yellow’,
priétés de l’objet « TOYOTA_GROUP ».
year: 1992
};
Obtention des valeurs des propriétés d’un objet contenant à
la fois des valeurs énumérables et non énumérables
console.log(Object.values(MY_CAR));
const CAR = {
Affichage dans la console :
brand: ‘Acura’,
[ ‘Acura’, ‘NSX’, ‘yellow’, 1992 ] model: ‘NSX’,
color: ‘yellow’,
Obtention des valeurs des propriétés énumérables d’un
year: 1992
objet semblable à un tableau
};
const TOYOTA_GROUP = {
0: ‘Lexus’, Object.defineProperty(CAR, ‘wheelNumber’, { value: 4, enumerable: false });
1: ‘Toyota’,
2: ‘Daihatsu’, console.log(‘Wheel number:’, CAR.wheelNumber);
3: ‘Scion’
} console.log(‘The CAR values are:’, Object.values(CAR));
programmez.com 33
« brand », « model », « color » et « year » et une propriété non associant pour chacune d’entre elles sa description sous
énumérable « wheelNumber ». Au travers de cet exemple, on forme d’objet. Une propriété JavaScript se définit par un nom
s’aperçoit que la valeur « 4 » de la propriété non énumérable (une chaîne de caractères) ou un symbole (Symbol) et un
« wheelNumber » n’est pas listée lorsqu’on liste les valeurs descripteur. Un descripteur de propriété est un enregistre-
des propriétés définissant l’objet « CAR ». ment qui possède les attributs suivants :
• value : Valeur associée à la propriété (uniquement pour les
Un argument de type primitif, ayant des propriétés, passé à descripteurs de données).
la fonction « Object#values » sera converti en un objet avec • writable : Indicateur booléen permettant de savoir si la
des propriétés, avant extraction des valeurs des propriétés valeur associée à la propriété peut être changée (unique-
énumérables ment pour les descripteurs de données).
• get : Fonction utilisée comme accesseur pour la propriété
// Un argument de type primitif ayant
ou « undefined » s’il n’existe pas de tel accesseur (unique-
// des propriétés sera converti en un
ment pour les descripteurs d’accesseur/mutateur).
// objet via la fonction “Object#values”
• set : Fonction utilisée comme mutateur pour la propriété
console.log(Object.values(‘String example’));
ou « undefined » s’il n’existe pas de tel mutateur (unique-
Affichage dans la console : ment pour les descripteurs d’accesseur/mutateur).
• configurable : Indicateur booléen permettant de savoir si
[
le type de descripteur peut être changé et si la propriété
‘S’, ‘t’, ‘r’, ‘i’,
peut être supprimée de l’objet correspondant.
‘n’, ‘g’, ‘ ‘, ‘e’,
• enumerable : Indicateur booléen permettant de savoir si
‘x’, ‘a’, ‘m’, ‘p’,
cette propriété est listée lorsqu’on énumère les propriétés
‘l’, ‘e’
de l’objet correspondant.
]
• Syntaxe :
Un argument de type primitif, n’ayant pas de propriété, passé Object#getOwnPropertyDescriptors(myObject)
à la fonction « Object#values » sera converti en un objet vide, • - Le paramètre « myObject » définit l’objet dont on souhai-
avant extraction des valeurs des propriétés énumérables te connaître les descripteurs des propriétés
[] console.log(Object.getOwnPropertyDescriptors(CAR));
Extraction des valeurs des propriétés d’un tableau non vide Affichage dans la console :
console.log(Object.values([‘Toyota’, ‘Lexus’, ‘Daihatsu’, ‘Scion’])); {
brand: {
Affichage dans la console :
value: ‘Toyota’,
[ ‘Toyota’, ‘Lexus’, ‘Daihatsu’, ‘Scion’ ] writable: true,
enumerable: true,
Extraction des valeurs des propriétés d’un tableau vide
configurable: true
console.log(Object.values([])); },
model: {
Affichage dans la console :
value: ‘RAV4’,
[] writable: true,
Avis : C’est pratique seulement dans les cas où on souhaite extraire enumerable: true,
uniquement les valeurs des propriétés des objets. configurable: true
},
Ajout de la fonction Object#getOwnPropertyDescriptors
color: {
(myObject)
value: ‘blue’,
Cette fonction permet d’examiner de façon précise les diffé-
writable: true,
rentes propriétés directement rattachées à un objet.
enumerable: true,
Elle retourne un objet contenant les propriétés de l’objet en y
34 programmez.com
configurable: true }
},
year: { value: 2000, writable: true, enumerable: true, configurable: true }, const operand1 = 1;
displayInformation: { const operand2 = 4;
value: [Function: displayInformation],
writable: true, const mathUtils = new MathUtils();
enumerable: true,
configurable: true console.log(`The sum of ${operand1} and ${operand2} is`,
} mathUtils.add(operand1, operand2));
}
Affichage dans la console :
Avis : Fonction intéressante lorsqu’on souhaite copier ou cloner un objet.
The sum of 1 and 4 is 5
Apparitions des « Trailing commas » ou Virgules finales Dans l’exemple précédent, on constate bien que les virgules
dans la liste des paramètres d’une fonction finales présentes dans les paramètres des méthodes statiques
Les virgules finales existantes déjà dans la définition d’objets et non statiques de classe n’ont aucun effet de bord lors de
ont été étendues aux paramètres des fonctions. leurs exécutions.
Le fait de rajouter une virgule à la fin des paramètres d’une
fonction n’a aucun effet secondaire et il s’agit simplement Echecs lors de la définition de paramètres ou lors d’appels
d’un changement de style de codage qui n’ajoute pas de de fonctions qui ne contiennent qu’une seule virgule
paramètre à la fonction. Les virgules finales peuvent égale-
function myFunction(,) { } // SyntaxError: missing formal parameter
ment être utilisées lors des définitions de méthodes dans les
objets et les classes. L’intérêt de rajouter une virgule à la fin
(,) => { }; // SyntaxError: expected expression, got ‘,’
des paramètres d’une fonction est d’éviter d’oublier d’en
rajouter une lorsqu’on décide d’ajouter un nouveau para-
myFunction2(,) // SyntaxError: expected expression, got ‘,
mètre. Un autre intérêt est de pouvoir sauter des lignes après
une virgule et ainsi d’aérer le code.
function myFunction3(...p,) { } // SyntaxError: parameter after rest parameter
Restrictions : Les définitions de paramètres ou les appels de
fonctions qui ne contiennent qu’une seule virgule lèveront
(...p,) => { } // SyntaxError: expected closing parenthesis, got ‘,’
une exception « SyntaxError ». Par ailleurs, on ne peut pas
utiliser de virgule finale avec les paramètres du reste (“Rest Échec lors de l’utilisation d’une virgule finale avec les para-
parameters”). mètres du reste (« Rest parameters »)
programmez.com 35
LG AI DD :
une IA dans votre lave-linge !
Jean-Christophe Avec les assistants personnels ou la publicité ciblée sur Internet, les applications de
Riat
Passionné depuis le
l’intelligence artificielle font désormais partie de notre quotidien. Cette technologie
lycée par la n’est pas exclusive de puissants serveurs puisqu’elle peut également améliorer le fonc-
programmation,
j’enseigne l’intelligence tionnement de produits électro-ménager, comme sur les derniers lave-linges commer-
artificielle à EPSI Paris, cialisés par la marque coréenne LG.
1ère école
d’informatique créée en
France par des
professionnels [4]. Démocratisées depuis la fin des années 1950, les machines à
J’aime partager mes laver le linge équipent maintenant plus de 95 % des ménages
expériences sur les
français. Si leurs performances en bilan énergétique et qualité
résultats récents en «
machine learning », de lavage s’améliorent régulièrement des progrès restent
avec les ressources encore nécessaires sur l’expérience utilisateur. La diversité des
accessibles pour tous sur réglages possibles (multitude de cycles pré-programmés, tem-
Internet (contact : pérature de l’eau, vitesse d’essorage, option pour le linge déli-
[email protected])
cat, …) peut laisser perplexe alors que l’unique besoin est de
laver le linge placé dans le tambour !
36 programmez.com
Figure n°2: brevet
déposé en Europe par la
société LG
plus le moteur aura un couple important à fournir, surtout au pour les extraire. L’originalité de la solution développée par
démarrage. Les ingénieurs de LG ont également observé LG consiste à utiliser une technique d’intelligence artificielle
expérimentalement que le signal comporte des caractéris- à base de réseaux de neurones (Figure n°4). Cette approche
tiques associées à la nature du linge : un textile fragile, géné- est reconnue comme très efficace pour les problèmes de
ralement souple, provoquera une résistance à la rotation du classification. Ici le but n’est pas de définir précisément le
tambour différente d’un vêtement plus grossier qui sera plus poids du linge ou le pourcentage exact de répartition entre
rigide. A partir de la forme du signal, il est donc possible de les différents types de textile, mais de définir des catégories,
déduire un indicateur sur un niveau de douceur du linge. ce qui revient à faire une classification. 4 catégories sont défi-
nies pour le poids (0 à1 kg, 1 à 3 kg, 3 à 5 kg et 5 à 7kg) et
Détails sur l’utilisation de l’IA 5 groupes sont retenus pour le type de linge selon la propor-
Même si on sait qu’un signal contient certaines informations, tion de linge délicat (0 %, 25 %, 50 % 75 % et 100 %).
il n’est pas toujours facile de définir les algorithmes de calculs Ces catégories correspondent aux sorties des réseaux de neu-
programmez.com 37
rones, c’est-à-dire aux résultats calculés (Figure n°3). Les
informations utilisées en entrée proviennent du signal mesuré
sur l’intensité du courant qui alimente le moteur. Après filtra-
ge, toutes les valeurs échantillonnées ne sont pas utilisées.
Pour limiter la taille des réseaux, elles sont moyennées par
intervalles, ce qui conduit à retenir 9 valeurs pour déterminer
le poids et 5 valeurs pour le type de linge (Figure n°3).
Après la définition du réseau de neurones il est nécessaire de
procéder à une phase d’apprentissage pour obtenir le fonc-
tionnement souhaité. Cette phase nécessite de disposer
d’exemples qui correspondent ici à des formes de signal du
courant associées à des contenus de linge connus (poids et
proportion de linge délicat). Sur son site internet, LG indique
que sa solution AI DD est « basée sur plus de 20 000 expé-
riences de lavage ». On peut supposer que ces données ont
été utilisées, par les ingénieurs, pour « faire apprendre » le
réseau durant les étapes de mise au point.
Figure n°3: synoptique du système embarqué dans le lave-linge Après l’apprentissage, le réseau de neurones est entièrement
défini. Son fonctionnement, qui nécessite très peu de puis-
sance de calcul, est programmé dans le microcontrôleur qui
pilote le lave-linge. Ainsi, à chaque début de cycle, l’IA carac-
térise les vêtements présents dans le tambour. Les informa-
tions ainsi obtenues sont ensuite exploitées pour optimiser le
cycle de lavage.
Conclusion
Cet exemple illustre une mise œuvre concrète de la technique
des réseaux de neurones dans un appareil du quotidien pour
simplifier son utilisation, avec une automatisation de certains
réglages. A l’avenir, ce type d’applications, va certainement
se développer sur d’autres produits électroménagers, car il
apporte un vrai bénéfice client avec une amélioration des
performances et une simplification de l’expérience utilisateur.
Références
[1] Vidéos de la société LG, sur le fonctionnement des lave-
linges avec la technologie AI DD :
https://www.youtube.com/watch?v=6fobogcrnYM
https://www.youtube.com/watch?v=0rSHCURntv8
Figure n°4: réseaux de neurones [2] Site français sur la propriété intellectuelle (INPI) :
https://www.inpi.fr/fr
Un réseau de neurones de type perceptron multicouche, permet de modéliser un compor- [3] Recherche de brevets sur le site de Google :
tement fortement non linéaire entre un vecteur de valeurs présenté en entrées et des https://patents.google.com/
valeurs calculées en sorties. Le fonctionnement du réseau se décompose au niveau de (référence EP3617370A1 pour le brevet associé au lave-
chaque neurone qui calcule individuellement un résultat en fonction des valeurs retour- Linge de LG)
nées par la couche précédente. Ainsi les valeurs en entrées sont propagées progressive- [4] Ecole d’ingénierie informatique EPSI (membre de HEP
ment entre les couches de neurones, jusqu’à la dernière couche dont les valeurs corres- Education) : https://www.epsi.fr/
pondent aux sorties du réseau.
A chaque connexion entre neurones est associé un poids pour moduler l’importance de la
relation entre ces neurones. L’ensemble de ces poids forment les paramètres du réseau,
PROCHAIN NUMÉRO
dont les valeurs sont calculées par algorithme, à partir d’exemples de comportements
entrées/sorties souhaités. Cette capacité « d’apprentissage » permet, pour un problème PROGRAMMEZ! N°255
donné, de définir une logique de calculs entre des variables uniquement à partir
d’exemples, ce qui autorise des applications dans des domaines très variés. Tensorflow, Java, Python,
Secure by Design
Disponible le 2 décembre 2022
38 programmez.com
XGBoost : principe et implémentation
XGBoost est probablement l’une des bibliothèques les plus utilisées en science des don-
nées. De nombreux data scientists du monde entier l’utilisent. C’est un algorithme très poly-
valent qui peut être utilisé pour effectuer une classification aussi bien qu’une régression. Guillaume Saupin
Ingénieur généraliste et
Il se retrouve régulièrement en tête dans les concours de class DecisionNode: docteur en
machine learning tels que ceux proposés par Kaggle. “”“ mathématiques
XGBoost, LightGBM ou encore CatBoost sont ainsi des librai- appliquées, passionné
Node decision class.
de mathématiques et du
ries python qui implémentent le Gradient Boosting, et qui se This is a simple binary node, with potentially two children: left and right langage Lisp, Guillaume
retrouvent dans ces palmarès. Left node is returned when condition is true a travaillé une dizaine
Vous pourriez penser qu’un algorithme d’apprentissage False node is returned when condition is false d’années comme
automatique aussi performant que XGBoost utilise des “”“ chercheur au CEA . Il
mathématiques très complexes et avancées. Vous imaginez rejoint le monde de
def __init__(self, name, condition, value=None):
l’Intelligence artificielle
probablement qu’il s’agit d’un chef-d’œuvre d’ingénierie logicielle. self.name = name et des start ups en
Et vous auriez en partie raison. La bibliothèque XGBoost est self.condition = condition 2010. Il a enseigné le
assez complexe, mais si vous ne considérez que la self.value = value Computer Graphics et le
formulation mathématique du boosting de gradient self.left = None HPC en master à
appliquée aux arbres de décision, ce n’est pas si compliqué. l’Université Paris 12 et à
self.right = None
Epitech. Actuellement
Cet article vous propose d’en comprendre réellement les
CTO de Verteego, il est
principes sous-jacents. Vous verrez ci-dessous en détail def add_left_node(self, left): également auteur de
comment construire des arbres de décision pour la régression self.left = left plus d’une vingtaine
en utilisant la méthode de gradient boosting avec moins de d’articles et publie
200 lignes de code. régulièrement sur la
def add_right_node(self, right):
Data Science dans
self.right = right Toward Data Science. Il
Arbre de décision a publié un livre sur les
Avant d’entrer dans les détails mathématiques, rafraîchissons def is_leaf(self): méthodes de Gradient
notre mémoire concernant les arbres de décision. Le principe “”“ Boosting pour le
est assez simple : associer une valeur à un ensemble donné Machine Learning aux
Node is a leaf if it has no child
éditions ENI.
de caractéristiques en parcourant un arbre binaire. Chaque “”“
nœud de l’arbre binaire est attaché à une condition ; les return (not self.left) and (not self.right)
feuilles contiennent des valeurs. Si la condition est vraie, on
continue la traversée en utilisant le nœud de gauche, sinon, def next(self, data):
on utilise le nœud de droite. Une fois qu’une feuille est “”“
atteinte, nous avons notre prédiction. Comme souvent, une Return next node depending on data and node condition
image vaut mille mots : Figure 1. La figure 1 présente un “”“
arbre de décision à trois niveaux. La condition attachée à un cond = self.condition(data)
nœud peut être considérée comme une décision, d’où le if cond:
nom d’arbre de décision. return self.left
else:
Figure 1
return self.right
class DecisionTree:
“”“
A DecisionTree is a model that provides predictions depending on input.
A Prediction is the sum of the leaves’ values, for those leaves that were activated
by the input
“”“
def __init__(self, root):
“”“
A DecisionTree is defined by an objective, a number of estimators and a
max depth.
Ce type de structure est assez ancien dans l’histoire de “”“
l’informatique et est utilisé depuis des décennies avec succès. self.root = root
Une implémentation de base est donnée par les lignes
suivantes : def predict(self, data):
child = root
programmez.com 39
while child and not child.is_leaf(): XGBoost. Ici, nous nous concentrerons uniquement sur les
child = child.next(data) formules pertinentes pour cet article.
return child.value Comme toujours en apprentissage automatique, nous
voulons définir les paramètres de notre modèle de sorte que
les prédictions de celui-ci sur l’ensemble d’apprentissage
root = DecisionNode(‘root’, lambda d : d[‘A’] > 2.0) minimisent un objectif donné :
root_left = DecisionNode(‘root_left’, lambda d : d[‘B’] > 10.0, None)
root_right = DecisionNode(‘root_right’, None, 1)
left_left = DecisionNode(‘left_left’, None, 2)
left_right = DecisionNode(‘left_right’, None, 3) Veuillez noter que cet objectif est composé de deux termes :
L’un pour mesurer l’erreur faite par la prédiction. C’est la
root.add_left_node(root_left) fameuse fonction de perte l(y, y_hat).
root.add_right_node(root_right) L’autre, oméga, pour contrôler la complexité du modèle.
Comme indiqué dans la documentation de XGBoost, la
root_left.add_left_node(left_left) complexité est une partie très importante de l’objectif qui nous
root_left.add_right_node(left_right) permet d’ajuster le compromis biais/variance. De nombreuses
fonctions différentes peuvent être utilisées pour définir ce
tree = DecisionTree(root) terme de régularisation. XGBoost utilise par exemple :
print(tree.predict({‘A’ : 1, ‘B’ : 1})) # 1
print(tree.predict({‘A’ : 1, ‘B’ : 10})) # 1
print(tree.predict({‘A’ : 3, ‘B’ : 11})) # 2
print(tree.predict({‘A’ : 3, ‘B’ : 9})) # 3
Ici, T est le nombre total de feuilles, tandis que w_j sont les
Combinaison de plusieurs arbres poids attachés à chaque feuille. Cela signifie qu’un grand
Même si les arbres de décision ont été utilisés avec un certain poids et un grand nombre de feuilles seront pénalisés.
succès dans un certain nombre d’applications, comme les Comme l’erreur est souvent une fonction complexe et non
systèmes experts (avant l’hiver de l’IA), ils restent un modèle linéaire, la méthode du gradient boosting la linéarise, en
très basique qui ne peut pas gérer la complexité utilisant une expansion de Taylor du second ordre :
habituellement rencontrée dans les données du monde réel.
Nous appelons généralement ce type d’estimateurs des
modèles faibles. où :
Pour surmonter cette limitation, l’idée est apparue dans les
années 90 de combiner plusieurs modèles faibles pour créer
un modèle fort : l’approche ensembliste.
Cette méthode peut être appliquée à n’importe quel type de
modèle, mais comme les arbres décisionnels sont des Le premier terme g_i est le gradient de l’erreur, tandis que h_i
modèles simples, rapides, génériques et facilement est sa hessienne. La linéarisation est calculée par rapport au
interprétables, ils sont couramment utilisés. terme de prédiction, car nous voulons estimer comment
Diverses stratégies peuvent être déployées pour combiner les l’erreur change lorsque la prédiction change. Cette
modèles. Nous pouvons par exemple utiliser une somme linéarisation est essentielle, car elle facilite la minimisation de
pondérée de la prédiction de chaque modèle. Ou encore l’erreur. Ce que nous voulons réaliser avec l’optimisation du
mieux, utiliser une approche bayésienne pour les combiner gradient, c’est trouver le y_hat_i optimal qui minimisera la
sur la base des données d’apprentissage. fonction de perte, c’est-à-dire que nous voulons trouver
XGBoost et toutes les méthodes de boosting utilisent une comment modifier l’arbre existant pour que la modification
autre approche : chaque nouveau modèle tente de améliore la prédiction.
compenser les erreurs du modèle précédent. Il s’agit donc Lorsque l’on traite des modèles d’arbres, deux types de
bien de boosting, les nouveaux arbres venant booster les paramètres sont à prendre en compte :
performances des précédents. • Ceux qui définissent l’arbre en lui-même : la condition pour
chaque nœud, la profondeur de l’arbre.
Optimisation des arbres de décision • Les valeurs attachées à chaque feuille de l’arbre. Ces
Comme nous l’avons vu ci-dessus, faire des prédictions en valeurs sont les prédictions elles-mêmes.
utilisant un arbre de décision est simple. La tâche n’est guère L’exploration de toutes les configurations de l’arbre serait trop
plus compliquée lorsqu’on utilise l’approche ensembliste : il complexe, c’est pourquoi les méthodes de Gradient Boosting ne
suffit de faire la somme des contributions de chaque modèle. prennent en compte que la division d’un nœud en deux feuilles.
Ce qui est vraiment compliqué, c’est de construire l’arbre lui- Cela signifie que nous devons optimiser trois paramètres :
même ! Comment trouver la meilleure condition à appliquer � La valeur de séparation : à quelle condition nous
à chaque nœud de notre ensemble de données de formation ? séparons les données.
C’est là que les mathématiques nous aident. Une dérivation � La valeur attachée à la feuille de gauche
complète peut être trouvée dans la documentation de � La valeur attachée à la feuille de droite
40 programmez.com
Dans la documentation de XGBoost, nous apprenons que la Construction des arbres de décision
meilleure valeur pour une feuille j par rapport à l’objectif est Voici maintenant la partie facile. Supposons que nous disposons
donnée par : d’un arbre de décision existant qui assure des prédictions avec une
erreur donnée. Nous voulons réduire l’erreur et améliorer l’objectif
joint en scindant un nœud.
L’algorithme pour y parvenir est assez simple :
où G_j est la somme du gradient des points d’apprentissage • choisissez une caractéristique d’intérêt
attachés au nœud j, et H_j est la somme du hessian des • ordonnez les points de données attachés au nœud actuel en
points d’apprentissage attachés au nœud j. utilisant les valeurs de la caractéristique sélectionnée
La minimisation de la fonction objectif obtenue avec ce • choisissez une valeur de séparation possible
paramètre optimal est : • placez les points de données situés en dessous de cette valeur de
division dans le nœud de droite, et ceux situés au-dessus dans le
nœud de gauche.
• calculez la minimisation de l’objectif pour le nœud parent, le
nœud de droite et le nœud de gauche.
Le choix de la bonne valeur de séparation se fait par brute • si la somme des réductions d’objectif pour les nœuds de gauche
force : on calcule l’amélioration pour chaque valeur de et de droite est supérieure à celle du nœud parent, conservez la
fractionnement et on garde la meilleure. valeur de division comme la meilleure.
Nous avons maintenant toutes les informations • itérez pour chaque valeur de fractionnement
mathématiques nécessaires pour améliorer les performances • itilisez la meilleure valeur de division, le cas échéant, et ajoutez
d’un arbre initial par rapport à un objectif donné en ajoutant les deux nouveaux nœuds.
de nouvelles feuilles. • si aucun partitionnement n’améliore l’objectif, n’ajoutez pas de
Avant de le faire concrètement, prenons le temps de nœuds enfants.
comprendre la signification de ces formules. Le code résultant crée une classe DecisionTree, qui est configurée
par un objectif, un nombre d’estimateurs, c’est-à-dire le nombre
Comprendre le boosting par gradient d’arbres, et une profondeur maximale.
Essayons de comprendre comment le poids est calculé, et à Comme promis, le code prend moins de 200 lignes :
quoi correspondent G_j et H_i. Comme il s’agit Code complet sur programmez.com & github
respectivement du gradient et du hessian de la fonction de Le cœur de la construction est codé dans la fonction _find_best_split.
perte par rapport à la prédiction, nous devons choisir une Elle suit essentiellement les étapes détaillées ci-dessus. Notez que pour
fonction de perte. Nous allons nous concentrer sur l’erreur supporter tout type d’objectif, sans avoir la peine de calculer
quadratique, qui est couramment utilisée et constitue manuellement le gradient et le hessian, nous utilisons la différenciation
l’objectif par défaut de XGBoost : automatique et la bibliothèque jax pour automatiser les calculs.
Initialement, nous commençons par un arbre avec un seul nœud dont
la valeur de la feuille est nulle. Comme nous avons imité XGBoost,
C’est une formule assez simple, dont le gradient est : nous utilisons également un score de base, que nous définissons
comme étant la moyenne de la valeur à prédire. Notez également qu’à
la ligne 126, nous arrêtons la construction de l’arbre si nous atteignons
et la hessienne simplement : la profondeur maximale définie lors de l’initialisation de l’arbre. Nous
aurions pu utiliser d’autres conditions comme un nombre minimum
Par conséquent, si nous nous rappelons les formules pour le d’échantillons pour chaque feuille ou une valeur minimum pour le
poids optimal qui maximise la réduction de l’erreur : nouveau poids. Un autre point très important est le choix de la
caractéristique utilisée pour le découpage. Ici, pour des raisons de
simplicité, les caractéristiques sont choisies aléatoirement, mais nous
aurions pu utiliser des stratégies plus intelligentes, comme utiliser la
Nous nous rendons compte que le poids optimal, c’est-à-dire caractéristique ayant la plus grande variance.
la valeur que nous ajoutons à la prédiction précédente, est
l’opposé de l’erreur moyenne entre la prédiction précédente Conclusion
et la valeur réelle (lorsque la régularisation est désactivée, Dans cet article, nous avons vu comment le boosting de gradient
c’est-à-dire lambda = 0). L’utilisation de l’erreur au carré fonctionne pour former des arbres de décision. Pour améliorer
pour entraîner les arbres décisionnels avec la méthode du encore notre compréhension, nous avons écrit le nombre minimal
Gradient Bosting se résume à mettre à jour la prédiction avec de lignes nécessaires pour entraîner un ensemble d’arbres de
l’erreur moyenne dans chaque nouveau nœud. décision et les utiliser pour la prédiction. Il est absolument essentiel
Nous constatons également que lambda a l’effet escompté, de bien comprendre les algorithmes que nous utilisons pour
c’est-à-dire qu’il garantit que les poids ne sont pas trop l’apprentissage automatique. Cela nous aide non seulement à
importants, car le poids est inversement proportionnel à construire de meilleurs modèles, mais surtout à adapter ces
lambda. modèles à nos besoins. Par exemple, dans le cas du boosting de
gradient, jouer avec les fonctions de perte est un excellent moyen
d’augmenter la précision des modèles.
programmez.com 41
Abonnez-vous à Programmez! Abonnez-vous à Programmez! Abonne
L e m a g a z i n e d e s d é v s
Offres
Nos classiques spéciales 2022
1 an D 10 numéros
(6 numéros + 4 hors séries) 55€*(1) 1 an Programmez!
2 ans D 20 numéros + 1 mois d’accès à la bibliothèque numérique ENI 56€*
(12 numéros + 8 hors séries) 90€*(1) 1 mois d’accès offert à la bibliothèque numérique ENI,
la plus grande bibliothèque informatique française. Valeur : 49 €
Etudiant
1 an D 10 numéros 45€* 2 ans Programmez! 109€*
(6 numéros + 4 hors séries)
+ 1 mois d’accès à la bibliothèque numérique ENI
Option : accès aux archives 20€ + 1 an de Technosaures (2 numéros)
* Tarifs France métropolitaine 1 mois d’accès offert à la bibliothèque numérique ENI,
(1) Au lieu de 69,90 € ou 139,80 € selon l’abonnement, par la plus grande bibliothèque informatique française.
rapport au prix facial.
Valeur : 49 €. Prix abonnement Technosaure : 29,90 € * au lieu de 119,9 €
Abonnement
numérique
PDF ..............................................45€
1 an
Souscription directement sur
www.programmez.com
Sous réserve d’erreurs typographiques
Oui, je m’abonne
ABONNEMENT à retourner avec votre règlement à :
PROGRAMMEZ, Service Abonnements
57 Rue de Gisors, 95300 Pontoise
n Abonnement 1 an : 55 € n 1 an Programmez! : 56 €
n Abonnement 2 ans : 90 € + 1 mois d’accès à la bibliothèque numérique ENI PROG 254
Adresse : I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I
n Je joins mon règlement par chèque à l’ordre de Programmez ! n Je souhaite régler à réception de facture * Tarifs France métropolitaine
Boutique Boutique Boutique Boutiq
HS 02
241
242
243
HS 04 été 2021
246
249
250
HS 07
251
252
253
57 rue de Gisors
n HS2 automne 2020 : I___I ex n 250 : I___I ex n HS7 : I___I ex 95300 Pontoise
Adresse : I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I
44 programmez.com
Figure 3
� Votre box internet expose peut-être le Raspberry Pi
sur le réseau par son hostname, et ainsi vous pouvez
accéder à Gladys sur votre navigateur en tapant
“http://gladys.local”
� Si ce n’est pas le cas, il faut trouver l’adresse IP de
votre Raspberry Pi sur le réseau. Je vous conseille
d’utiliser une application comme Network Scanner
[Lien: https://play.google.com/store/apps/details?id=com.easy-
mobile.lan.scanner&hl=fr ] sur Android, ou iNet [Lien:
https://itunes.apple.com/fr/app/inet-network-scanner/id340
793353?mt=8 ] sur iOS. Ces deux applications vous per-
mettent de scanner le réseau, et vous montreront
tous les appareils disponibles sur le réseau. Cherchez
“gladys”, et gardez l’adresse IP de côté. Ensuite,
tapez “http://ADRESSE_IP_DU_RASPBERRY” dans votre
navigateur. Par exemple : “http://192.168.1.12” Figure 4
� Vous devriez arriver sur une page de bienvenue ! Si c’est
le cas, bravo ! vous avez installé Gladys avec succès.
�� Il est temps de configurer votre compte Gladys Assistant.
Créez votre compte local et configurez vos préférences et
votre logement. Cette configuration est uniquement
locale, tout est enregistré dans votre Raspberry Pi : rien
ne quitte votre machine.
�� Bravo ! Votre installation Gladys est fonctionnelle.
programmez.com 45
Si vous voulez visualiser cette photo dans votre terminal, il Maintenant que nous sommes capables de prendre une
existe un outil, très mal nommé pour les francophones, mais photo avec la caméra, il faut que nous puissions exposer un
très pratique, « cacaview ». flux RTSP sur le réseau afin que Gladys puisse récupérer ce
Pour l’installer : flux sur une autre machine :
Pour cela, vous devez installer le package « vlc » :
sudo apt-get update
sudo apt-get install caca-utils -y sudo apt-get install vlc
cacaview test.jpg
Puis vous pouvez lancer la diffusion du flux de cette manière :
Vous devriez voir l’image prise, façon ASCII-art !
sudo raspivid -o - -t 0 -n -w 600 -h 400 | cvlc -vvv stream:///dev/stdin —sout
Figure 6
‘#rtp{sdp=rtsp://:8554/}’ :demux=h264
Figure 6
Ensuite, sur un ordinateur sur le même réseau, vous pouvez
récupérer le flux de cette façon suivante, par exemple depuis
VLC, en faisant « Fichier » => « Ouvrir réseau », puis en ren-
trant comme URL de flux :
rtsp://IP_DE_VOTRE_RASPBERRY_PI_ZERO_W:8554/
Figure 7
46 programmez.com
Figure 9
rtsp://IP_DE_VOTRE_RASPBERRY_PI_ZERO_W:8554/
Cliquez sur « Enregistrer », puis sur « Tester » si vous voulez
vérifier que la caméra fonctionne bien. Figure 9
Ensuite, allez sur votre tableau de bord, et cliquez sur
« Editer » pour ajouter une box caméra. Figure 10
Choisissez la caméra que vous venez de créer et enregistrez.
Vous devriez voir votre image de caméra sur le tableau de
bord ! Figure 11 Figure 10
Maintenant que votre caméra est configurée, vous pouvez
l’utiliser partout dans Gladys.
Par exemple, il devient possible de demander à Gladys par
message :
« Montre-moi la caméra du salon », et elle vous répondra
avec une image de la caméra du salon : Figure 12
Conclusion
Ce n’est qu’un simple exemple de ce qu’il est possible de
faire avec Gladys Assistant, vous pouvez aller bien plus loin,
en ajoutant des capteurs : température, humidité, ouverture
de portes, mouvement. En connectant vos lumières avec des
Philips Hue ou des ampoules Zigbee. En automatisant des
appareils existants avec des prises télécommandées Zigbee.
N’hésitez pas à passer sur le forum Gladys
(https://community.gladysassistant.com) si vous avez des
questions/retours sur ce tutoriel !
programmez.com 47
Java 19 : quoi de neuf ?
Java 19, sorti le 20 septembre, comporte 7 JEP - JDK Enhancement Proposal dont la JEP
405 qui introduit la déconstruction en Java via les Record Patterns et la très attendue JEP
Loïc Mathieu 425 qui implémente des threads légers en Java via les Virtual Threads du projet Loom.
Consultant Formateur à
Zenika Lille.
GCP Google Developer JEP 405 : Record Patterns (Preview) JEP 425 : Virtual Threads (Preview)
Expert. Cette JEP vise à enrichir le pattern matching de Java avec les La JEP 425 introduit en preview feature les Virtual Threads
Contributeur Quarkus. record patterns qui permettent de déconstruire un record en (parfois aussi nommés green threads ou lightweight threads),
https://www.loicmathieu.fr ses attributs. Un record est un nouveau type dont le but est ce sont des threads légers, avec un coût de création et de
https://twitter.com/loicmathieu d’être un conteneur de données, il a été introduit en Java 14. scheduling faible, qui permettent de faciliter l’écriture
Avant la JEP 405, si vous vouliez faire du pattern matching d’application concurrente.
sur un record puis accéder à ses attributs, vous auriez écrit du C’est le projet Loom d’OpenJDK.
code comme celui-ci : Les threads Java classiques sont implémentés via des threads
OS, quel est le problème avec cette implémentation de
record Point(int x, int y) {} thread ?
• Créer un thread en Java implique de créer un thread OS,
static void printSum(Object o) { et donc de réaliser un appel système, ce qui est coûteux.
if (o instanceof Point p) { • Un thread a une stack de taille fixe, par défaut de 1Mo sur
int x = p.x(); Linux amd64, configurable via -Xss ou -XX:ThreadStackSize.
int y = p.y(); • Un thread sera schedulé via le scheduler de l’OS, chaque
System.out.println(x + y); changement d’exécution d’un thread entraînera un context
} switch qui est une opération coûteuse.
} Pour pallier ces problèmes, les applications concurrentes ont
eu recours à plusieurs types de construction :
La JEP 405 permet de déconstruire le record et de • Les pools de threads qui permettent de réutiliser un thread
directement accéder à ses attributs quand le pattern match, pour plusieurs requêtes (HTTP, JDBC, …). Le degré de
ce qui simplifie le code comme suit : concurrence de l’application est donc la taille du pool.
• La programmation réactive qui va ouvrir un nombre de
record Point(int x, int y) {} threads très réduit (1 ou 2 par unité de CPU), et se baser
sur un système d’event loop (boucle d’évènements) pour
void printSum(Object o) { traiter un ensemble de requêtes concurrentes sur ces
if (o instanceof Point(int x, int y)) { quelques threads.
System.out.println(x + y); Mais ces constructions impliquent de la complexité lors du
} développement des applications. L’idée des Virtual Threads
} est d’offrir des threads peu coûteux à créer, et donc de
permettre de se passer de pool de threads ou d’event loop et
Au lieu, dans le bloc de code exécuté au match du pattern, d’utiliser un thread pour chaque requête.
d’avoir accès à la variable Point p; vous avez accès directement C’est la promesse du projet Loom.
aux attributs int x, int y du record Point. C’est la première étape Le principe est de proposer des threads virtuels qui sont créés
dans la déconstruction de type en Java, on peut espérer voir et schedulés par la JVM, et utilisent un pool de thread OS, ce
prochainement la déconstruction arriver pour toutes les que l’on appelle des carrier threads (thread porteur). La JVM
classes et pas uniquement les records. Plus d’informations va alors automatiquement monter et démonter les threads
dans la JEP 405 : https://openjdk.java.net/jeps/405. virtuels des carrier threads quand nécessaire (lors des I/O par
exemple). Les stacks des threads seront stockées dans la
JEP 422 : Linux/RISC-V Port heap de la JVM, leur taille n’étant plus fixe, un gain en
RISC-V est une architecture de jeu d’instructions RISC mémoire est possible.
(Reduced Instruction Set Computer) gratuite et open source La manière la plus simple de créer des threads virtuels est via
conçue à l’origine à l’Université de Californie à Berkeley, et Executors.newVirtualThreadPerTaskExecutor(), on a alors un ExecutorService
maintenant développée en collaboration sous le parrainage qui exécutera chaque tâche dans un nouveau thread virtuel.
de RISC-V International : https://riscv.org. Là où les threads virtuels sont le plus intéressants est pour les
RISC-V définit plusieurs ISA, seul le jeu d’instruction RV64GV applications qui nécessitent une grande concurrence
(general purpose 64bit) a été porté. Ce port comprend le (plusieurs dizaines de milliers de thread) et/ou qui ne sont pas
support du JIT (C1 et C2) ainsi que de tous les GC existants CPU bound (généralement celles exécutant des I/O).
(y compris ZGZ et Shenandoah). Attention, utiliser des threads virtuels pour des applications
Plus d’informations dans la JEP 422 : CPU bound, des applications faisant des calculs intenses par
https://openjdk.java.net/jeps/422. exemple, est contre-productif, car avoir plus de threads que
48 programmez.com
de CPU pour ce type d’application impacte négativement les terminer au même endroit : scope.join(). Voici l’exemple pris de la
performances. JEP.
Il existe des limitations dans l’implémentation actuelle des
Response handle() throws ExecutionException, InterruptedException {
threads virtuels, dans certains cas un thread virtuel va
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
épingler (pinning) le carrier thread qui ne pourra pas traiter
Future<String> user = scope.fork(() -> findUser());
d’autres threads virtuels :
Future<Integer> order = scope.fork(() -> fetchOrder());
• L’utilisation du mot clé synchronized
• L’utilisation de méthode native ou de l’API Foreign
scope.join(); // Join both forks
Function de la JEP 424
scope.throwIfFailed(); // ... and propagate errors
À cause de ces limitations, les threads virtuels ne sont pas
forcément la solution à tous les problèmes de concurrence,
// Here, both forks have succeeded, so compose their results
même si des améliorations pourront être faites dans les
return new Response(user.resultNow(), order.resultNow());
prochaines versions de Java. Il faudra aussi que l’écosystème
}
devienne compatible avec les threads virtuels (par exemple
}
en évitant l’utilisation de bloc synchronisé).
Plus d’informations dans la JEP 425 : https://openjdk.java.net/jeps/425. Ici les deux sous-tâches findUser() et fetchOrder() sont démarrées
dans leur propre thread (par défaut un thread virtuel), mais sont
JEP 428 : Structured Concurrency jointes et potentiellement annulées ensemble (comme une unité
(Incubator) de traitement). Leurs exceptions et leurs résultats seront agrégés
Le but de la JEP 428 est de simplifier la programmation dans la tâche parente, et toute interruption du thread parent
multithread en introduisant une API pour la concurrence sera propagée aux threads enfants. Lors d’un thread dump, on
structurée. La concurrence structurée traite plusieurs tâches verra bien les sous-tâches comme enfants du thread parent,
s’exécutant dans différents threads comme une seule unité facilitant le debugging de code écrit de cette manière. Plus
de travail, rationalisant ainsi la gestion et l’annulation des d’informations dans la JEP 428 : https://openjdk.java.net/jeps/428.
erreurs, améliorant la fiabilité et l’observabilité. C’est un
incubator module Les fonctionnalités qui restent en preview
Même si les Virtual Threads sont les stars de cette nouvelle Les fonctionnalités suivantes restent en preview (ou en
version de Java, l’API Structured Concurrency est pour moi incubator module). Pour les détails sur celles-ci, vous pouvez
aussi intéressante, si ce n’est plus, en tout cas pour un vous référer à mes articles précédents.
développeur, car cela va impacter fortement la manière Vector API : quatrième incubation de la fonctionnalité. Vector API
d’écrire du code multi-threadé / concurrent. est une nouvelle API qui permet d’exprimer des calculs de vecteur
Le but de cette API est de pouvoir écrire un code multi- (calcul matriciel entre autres), qui seront exécutés via des instructions
threadé plus lisible et avec moins de risque d’erreur dans son machines optimales en fonction de la plateforme d’exécution.
implémentation via une meilleure gestion des erreurs. Plus d’informations dans la JEP 426 : https://openjdk.org/jeps/426.
Avant la Structured Concurrency API, pour exécuter un Foreign Function & Memory API : après deux incubations
ensemble de tâches concurrentes, puis joindre les résultats ; pour ces deux fonctionnalités rassemblées dans une même
on écrivait un code comme celui-ci (exemple pris de la JEP). JEP, celles-ci passent en preview. Foreign Memory API permet
de gérer des segments mémoire (on heap ou off heap) tandis
ExecutorService ex = Executors.newFixedThreadPool(nbCores);
que Foreign Function l’interconnexion de la JVM avec du
Response handle() throws ExecutionException, InterruptedException {
code natif (en C par exemple) de façon facile et performante.
Future<String> user = es.submit(() -> findUser());
Ces deux API sont les bases du projet Panama.
Future<Integer> order = es.submit(() -> fetchOrder());
Plus d’informations dans la JEP 424 : https://openjdk.org/jeps/424.
String theUser = user.get(); // Join findUser
Pattern Matching for switch : troisième preview avec
int theOrder = order.get(); // Join fetchOrder
l’introduction de la clause when pour les guards à la place du
return new Response(theUser, theOrder);
&&. Le support du pattern matching dans les switch permet
}
d’écrire un switch sur le type d’une variable, donc sur sa
Il y a plusieurs problèmes ici : classe / son interface. Plus d’informations dans la JEP 427 :
• Si une erreur arrive dans la méthode fetchOrder(), on va quand https://openjdk.org/jeps/427.
même attendre la fin de la tâche findUser().
• Si une erreur arrive dans la méthode findUser(), alors la Conclusion
méthode handle() va se terminer, mais le thread qui exécute La tant attendue JEP 425 Virtual Threads est enfin arrivée et
fetchOrder() va continuer à s’exécuter, c’est un thread leak. pourrait bien changer la donne dans la programmation
• Si la méthode handle() est interrompue, cette interruption concurrente en baissant le coût de création des threads en
n’est pas propagée aux sous-tâches et leurs threads vont Java. En conjonction avec la JEP 428 qui permet d’écrire du
continuer à s’exécuter, c’est un thread leak. code concurrent plus simplement et avec une meilleure
Avec la Structured Concurrency API, on peut utiliser la classe gestion des erreurs, c’est une mini révolution qui se prépare.
StructuredTaskScope qui permet de lancer un ensemble de tâches et Bien sûr, l’adoption des virtual threads se fera lentement, car
de les gérer comme une unité de traitement unique. Le principe l’écosystème devra se mettre à jour pour les supporter, mais
est de découper une tâche en sous-tâches (via fork()) qui vont se c’est une étape importante pour Java et la JVM.
programmez.com 49
Anthos :
écrire une fois, exécuter partout
Seifeddin
MANSRI Anthos a été introduit le 9 avril 2019 lors de la conférence annuelle Google Cloud Next
Seifeddin est le directeur par Sundar Pichai, le CEO de Google. Anthos permet d’exécuter les applications sur les
de l’ingénierie cloud
chez Sfeir, responsable
infrastructures existantes on-premises ou sur le cloud public, de manière simple,
des activités Cloud flexible et sécurisée.
Infrastructure et
DevOps, il gère ainsi
plusieurs équipes La promesse d’Anthos : incarner le principe « écrire une fois Kubernetes (K8S)
d’experts cloud. Il a de et exécuter partout », et cela dans le Cloud avec bien évidem- L’environnement d’exécution d’applications
multiples certifications ment Google Cloud, mais également sur d’autres cloud pro- dans Anthos s’appuie sur Google
techniques cloud (GCP, viders comme Amazon Web Services ou Microsoft Azure, Kubernetes Engine (GKE) et Anthos
AWS, Kubernetes). Il est
mais aussi on-premises où il est possible de déployer Anthos clusters (GKE On-Prem) pour gérer les
aussi formateur officiel
Google Cloud et sur du VMware ou même directement sur des serveurs phy- installations Kubernetes dans les
Kubernetes. Il est siques (bare metal). différents environnements où sont déployées les applications.
reconnu, depuis cette Anthos peut être considéré comme une offre de Pour rappel, Kubernetes est un orchestrateur de conteneurs
année, comme étant modernisation d’applications hybrides et multi-cloud, basée open source créé initialement chez Google en s’inspirant de
Google Developer Expert
principalement sur Kubernetes. Toutefois, Anthos s’appuie Borg, l’orchestrateur interne de ses datacenters. K8S a été
(GDE) sur les technos
Google Cloud Platform également sur d’autres technologies open source moderne par la suite donné à la Cloud Native Computing Foundation
(GCP). qui augmentent sa puissance telle que Istio ou Knative. Il est (CNCF) qui s’en occupe depuis 2015. Techniquement
ainsi bâti sur les fondations de Google Kubernetes Engine parlant, Kubernetes est composé principalement de deux
(GKE), qui joue le rôle de centre de commande et de parties : le plan de contrôle (control plane) qui constitue le
contrôle. Les utilisateurs peuvent ainsi gérer leur cerveau du cluster et les nœuds où seront généralement
infrastructure distribuée sur le cloud ou dans un data center déployées les applications.
sur site.
Anthos vient du grec ancien ανθος, ánthos, et signifie fleur. Google Kubernetes Engine (GKE)
La raison pour laquelle ils ont choisi ce nom est que les fleurs Il s’agit de la version gérée par Google de
poussent sur place (on-prem), mais qu’elles ont besoin de la Kubernetes qui permet de déployer en
pluie des nuages (Cloud) pour s’épanouir. production des applications sécurisées et
hautement scalables en s’appuyant sur
Les composants clés l’infrastructure de Google Cloud. Avec
Anthos est constitué de plusieurs composants qui peuvent tous GKE, Google Cloud héberge le plan de contrôle, et c’est
fonctionner ensemble pour aider les entreprises à créer et à uniquement le serveur d’API Kubernetes qui est accessible
gérer des applications hybrides et multi-cloud modernes dans aux clients pour évidemment interagir avec le cluster. Quant
Figure 1
Introduction d’Anthos par tous les environnements (Dev, Staging et Prod). Figure 2 aux nœuds, c’est sans surprise qu’ils sont dans le projet de
Sundar Pichai l’utilisateur à l’aide d’instances Google Compute Engine
(GCE), le service de provisionnement (provisioning) de
machines virtuelles de Google Cloud.
Figure 2
50 programmez.com
Anthos Config Management (ACM) Istio
Anthos Config Management est un gestionnaire de Istio est une solution de maillage (mesh) de
configuration multi-cluster qui permet d’avoir des règles services open source qui réduit la complexité des
cohérentes sur l’ensemble des clusters, qu’ils soient on-prem déploiements et la gestion des interactions de
ou dans le Cloud. Il s’appuie sur un référentiel Central Git service entre les conteneurs et les machines
pour gérer les politiques de contrôle d’accès, les quotas de virtuelles. Il permet de connecter Google Cloud,
ressources et les namespaces. C’est déclaratif et continu : d’autres fournisseurs cloud, des bases de données et d’autres
une fois que vous déclarez le nouvel état souhaité, l’outil composants dans un maillage de services unique, prenant en
vérifie en permanence les changements qui vont à l’encontre charge l’équilibrage de charge (load balancing), la
de l’état désiré. surveillance d’un grand nombre de clusters et la gestion du
ACM combine trois composants : Policy Controller, Config trafic.
Sync et Config Controller. Ensemble, ils ont la responsabilité Au niveau de l’utilisateur, il offre des fonctionnalités très
de protéger et de configurer en continu vos ressources intéressantes telles que les circuit-breakers, timeouts, retries,
Google Cloud et Kubernetes, comme illustré dans le schéma traffic splitting ou encore les health checks actifs et passifs…
suivant : (Figure 3). Istio vous permet de créer facilement des clusters et peut
prendre en charge les opérations sur des clusters déjà
Policy Controller déployés, offrant une meilleure visibilité sur le comportement
Anthos Config Management Policy des services, les performances et l’état de santé des
Controller offre une intégration entre applications.
Open Policy Agent (OPA) et Kubernetes
via un contrôleur personnalisé. OPA est Anthos Service Mesh (ASM)
une solution open source qui permet de Bâti sur les API d’Istio, Anthos Service Mesh permet de créer
mettre en place des contrôles basés sur des règles pour les facilement un réseau des services déployés (maillage de
environnements cloud natifs. Dans le contexte Kubernetes, services) et offre une télémétrie prête à l’emploi pour la
OPA transforme les politiques Rego en ressources gestion des services. Il prend également en charge des
Kubernetes, leur permettant d’être personnalisées et fonctionnalités avancées telles que l’équilibrage de charge de
déployées à l’aide de flux de travail standard. service à service, l’authentification, la collecte des métriques
Les politiques permettent à l’application de mettre en place
des règles entièrement programmables pour les clusters qui Figure 3
empêchent toute modification de la configuration de l’API
Kubernetes, de violer les contrôles de sécurité, opérationnels
ou de conformité.
Config Sync
Config Sync est un outil open source qui permet une gestion
centralisée des configurations et des politiques de sécurité qui
peuvent être déployées sur plusieurs clusters pouvant
s’étendre sur des environnements hybrides et multicloud. Ce
processus simplifie et automatise la configuration et la
gestion des politiques de sécurité à grande échelle.
Config Sync est tout simplement une boucle de réconciliation
entre les configurations déclarées (appelées configs) dans un
repo Git et l’état du ou des clusters. Il est considéré comme
un outil de Configuration-as-Code puisqu’il permet d’adopter
une approche GitOps quand il s’agit d’administrer une flotte
de clusters. Figure 4 Figure 4
Config Controller
Config Controller est un service permettant de provisionner et
d’orchestrer les ressources Anthos et Google Cloud. Ce
composant offre un point de terminaison d’API qui peut
provisionner, activer et orchestrer les ressources Google Cloud.
Il s’appuie principalement sur Config Connector qui est un
add-on open source dans Kubernetes qui permet de faire de
l’Infrastructure-as-Code pour déployer des ressources Google
cloud en utilisant la syntaxe et le flux de travail Kubernetes.
programmez.com 51
sans avoir à se soucier de la sécurité et des opérations.
Pour pouvoir tester ASM, nous avons créé un cluster GKE
programmez-gke-cluster. L’option Anthos Service Mesh a
été activée au moment de la création et la istio-
ingressgateway a été installée (https://cloud.google.com/service-
mesh/docs/gateways) qui est, en version courte, un service de
type LoadBalancer et qui permet d’exposer les services à
l’extérieur du maillage de services (mesh). Par la suite, la
fameuse application de démo Bookinfo
(https://istio.io/latest/docs/examples/bookinfo/) a été déployée.
Enfin, un stress test a été réalisé à l’aide de l’outil siege
pour envoyer du trafic vers l’application.
Le mesh peut être ainsi visualisé à travers la console
Google Cloud avec quelques métriques sur le trafic reçu
par l’application. Figure 5
52 programmez.com
d’Anthos, vous pouvez tirer parti d’Anthos Service Mesh et https://cloud.google.com/anthos/clusters/docs/multi-cloud/aws/reference
d’Anthos Configuration Management en toute transparence. /supported-regions
Vous bénéficiez également d’une visibilité opérationnelle, clé */
en main pour tous vos services. gcp_location = “europe-west1”
Cloud Run pour Anthos vous permet même d’exploiter du aws_region = “eu-west-3”
matériel avancé, tel que des types de machines subnet_availability_zones = [“eu-west-3a”, “eu-west-3b”, “eu-west-3c”]
personnalisés, des GPU, des TPU et des capacités de
mémoire élevées. Une fois les scripts terraform exécutés, il ne vous reste plus
En bref, Cloud Run pour Anthos vous permet de combiner le qu’à récupérer les informations de connexion pour la
meilleur du Serverless et de Kubernetes. configuration du contexte pour kubectl qui est l’outil ligne de
commande de Kubernetes qu’on utilisera par la suite pour
Options de déploiement d’Anthos interagir avec notre cluster Anthos sur AWS. Il est à noter qu’il
Il existe plusieurs options pour le déploiement d’Anthos qui se faut rajouter l’option “–location europe-west1” à la
répartissent globalement en deux familles : le Cloud et on- commande proposée par le script. Figure 9
premises. Pour vérifier que le contexte a été bien récupéré, il suffit
Dans le cadre de cet article, on va plutôt se concentrer sur les d’exécuter la commande kubectl get nodes pour afficher les
architectures multi-cloud. À savoir les Anthos clusters sur nœuds du cluster. Figure 10
AWS ou AZURE et les Attached Clusters avec EKS ou AKS Techniquement parlant, cinq instances EC2 ont été
qui sont respectivement les deux produits gérés autour de déployées : 3 control plane chacun dans une zone de
Kubernetes d’AWS et d’AZURE. Figure 8 disponibilité et un node pool avec 2 VM. Figure 11
On peut également observer le résultat à travers la console
Anthos clusters on AWS Google Cloud où on voit clairement la différence de type
Anthos clusters on AWS vous permet de gérer les clusters Figure 8
GKE exécutés sur l’infrastructure AWS via l’API Anthos Multi-
Cloud. Associés à Connect, les clusters Anthos sur AWS vous
permettent de gérer les clusters GKE sur Google Cloud et
AWS à partir de la console Google Cloud.
Lorsque vous créez un cluster avec des clusters Anthos sur
AWS, Google crée les ressources AWS dont vous avez besoin
et affiche un cluster en votre nom. Vous pouvez ensuite
déployer vos applications avec les outils de ligne de
commande gcloud et kubectl.
La méthode la plus simple, mais aussi qui est recommandée
pour l’installation d’un cluster Anthos est d’utiliser Terraform
l’outil d’infrastructure-as-Code (IaC). Pour cela, Google Figure 9
Cloud met à disposition un repo GitHub
(https://github.com/GoogleCloudPlatform/anthos-samples) qui contient
les scripts nécessaires (sous le répertoire /anthos-multi-
cloud/AWS/) pour le déploiement et la configuration des
ressources AWS telles que VPC, subnets, internet gateway,
iam roles, route tables et bien d’autres. Il faudra aussi Figure 10
installer et configurer, si ce n’est déjà fait, les outils de ligne
de commande gcloud et aws. Il faudra aussi personnaliser le
script en renseignant les variables dans le fichier
terraform.tfvars telles que l’id du projet Google cloud, les
types d’instances ou encore la localisation. Figure 11
gcp_project_id = “programmez-demo-2022”
#add up to 10 GCP Ids for cluster admin via connect gateway
admin_users = [“[email protected]”]
name_prefix = “programmez-aws-cluster”
/* supported instance types Figure 12
https://cloud.google.com/anthos/clusters/docs/multi-cloud/aws/reference
/supported-instance-types
*/
node_pool_instance_type = “t3.medium”
control_plane_instance_type = “t3.medium”
cluster_version = “1.22.8-gke.2100”
/* supported regions
programmez.com 53
gcp_project_id = “programmez-demo-2022”
entre un cluster GKE créé précédemment et notre cluster
#add up to 10 GCP Ids for cluster admin via connect gateway
Anthos dans AWS créé via Terraform. Figure 12
admin_users = [“[email protected]”]
name_prefix = “programmez-azure-cluster”
Anthos clusters on Azure
/* supported instance types
Les mêmes étapes que pour Anthos clusters on AWS peuvent
https://cloud.google.com/anthos/clusters/docs/multi-cloud/azure/reference
être déroulées en exécutant les scripts nécessaires (sous le
/supported-vms
répertoire /anthos-multi-cloud/AZURE/) et en personnalisant
*/
le fichier terraform.tfvars
control_plane_instance_type = “Standard_DS2_v2”
Figure 13 node_pool_instance_type = “Standard_DS2_v2”
cluster_version = “1.22.8-gke.2100”
/* supported regions
https://cloud.google.com/anthos/clusters/docs/multi-cloud/azure/reference
/supported-regions
*/
gcp_location = “europe-west1”
azure_region = “westeurope”
54 programmez.com
En plus du cluster GKE et des clusters Anthos dans AWS et Il gère non seulement les clusters Anthos GKE on-prem et
AZURE, créés via Terraform, on peut maintenant voir le dans d’autres Cloud providers, mais également tous les
cluster EKS attaché. Figure 21 clusters Kubernetes conformes à la norme CNCF, tels que
AKS, EKS, OpenShift, etc.
Bac à sable pour les développeurs Anthos est un excellent outil de gestion multicluster pour
Envie de découvrir comment vous pouvez commencer à gérer, standardiser et sécuriser vos clusters dans plusieurs
développer vos applications sur Anthos ? Sachez que Google environnements cloud et fournisseurs de distributions
met à disposition un bac à sable Anthos pour les Kubernetes.
développeurs, qui peut être utilisé gratuitement. Il suffit pour À ce stade, Anthos n’a plus de secrets pour vous. Il ne vous
en disposer de posséder un compte Google. reste plus qu’à le tester vous-même sur Google Cloud, on-
Indépendamment de votre choix de plateforme d’exécution, prem ou sur d’autres fournisseurs de Cloud.
le bac à sable Anthos vous permet d’effectuer certaines
tâches quotidiennes de développement telles que : Resources
• Le déploiement d’applications sur un cluster Kubernetes https://www.openpolicyagent.org/docs/latest/
local avec minikube ; https://istio.io/latest/docs/
• L’exécution des tests d’une application en local avec l’outil https://istio.io/latest/docs/examples/bookinfo/
de création local Cloud Build (cloud-build-local) ; https://istio.io/latest/docs/tasks/traffic-management/ingress/ingress-control/
• Le déploiement d’applications sur l’émulateur Cloud Run https://cloud.google.com/service-mesh/docs/install-anthos-service-mesh-console
local. https://cloud.google.com/service-mesh/docs/anthos-service-mesh-proxy-injection
https://cloud.google.com/blog/topics/anthos/introducing-the-anthos-develo- https://cloud.google.com/service-mesh/docs/gateways
per-sandbox https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages
https://cloud.google.com/anthos-config-management/docs/concepts/config-controller-overview
Conclusion https://cloud.google.com/config-connector/docs/overview
Vous l’avez compris, Anthos fournit une plateforme unifiée https://cloud.google.com/anthos-config-management
pour la gestion des clusters Kubernetes sur différents Clouds https://cloud.google.com/anthos/clusters/docs/attached/how-to/attach-kubernetes-clusters
et on-prem. Ces clusters peuvent être exécutés à l’intérieur de https://learn.hashicorp.com/tutorials/terraform/eks
machines virtuelles ou sur du bare metal. https://github.com/GoogleCloudPlatform/anthos-samples/
Anthos est un produit 100 % logiciel qui étend les services https://knative.dev/docs/
Google Cloud et les pratiques d’ingénierie à vos https://linux.die.net/man/1/siege
environnements afin que vous puissiez moderniser vos
applications plus rapidement et établir une cohérence
opérationnelle entre elles.
www.technosaures.fr
Le magazine
à remonter le temps !
N°1
N°2
N°7 et N°8
N°3
N°4
N°5
N°6
programmez.com 55
Les Transformers : deep dive pour
mieux comprendre les gros
Guendalina
Caldarini modèles qui sont en train de
révolutionner le Deep Learning
Guendalina est une
ingénieure linguistique et
doctorante dans le TAL,
passionnée par le Deep
Learning et les modèles
linguistiques. Sa passion Si vous êtes passionnés de Machine Learning, vous avez sûrement entendu parler des
pour les langues
(humaines et de Transformers. Il s’agit de modèles de Deep Learning très puissants, entraînés sur des
programmation) l’a
amenée à vivre et à
millions de données, qui offrent des performances exceptionnelles dans plusieurs
travailler dans plusieurs tâches. Mais d’où vient cette puissance ? Et pourquoi les Transformers sont-ils deve-
pays dans le monde. Elle
parle TAL chaque
nus si populaires ? Nous allons le découvrir ensemble.
semaine sur son blog
towardsnlp.com. Une Solution élégante pour un ultra des Transformers : l’Attention. Toutefois, avant de vous
problème de longue date parler de ce mécanisme, il convient de faire un bond dans le
Pour réaliser la plupart des tâches de Traitement passé qui nous permettra d’apprécier davantage l’arrivée des
Automatique du Langage (TAL ou NLP en anglais), nous uti- transformers. Avant l’arrivée des Transformers, pour la plu-
lisons aujourd’hui des modèles appelés Transformers. Ces part des tâches de Traitement Automatique du Langage, les
derniers prennent une séquence de mots en entrée et génè- modèles Seq2Seq composés de Recurrent Neural Networks
rent une phrase cible, selon la tâche spécifiée. (RNNs) étaient la solution la plus utilisée. Dans toutes leurs
Les Transformers sont considérés comme des modèles de formes (LSTMs et GRUs), ils présentent une structure assez
post-deep learning, à cause de leur capacité de parallélisa- simple : un encodeur (Encoder) et un décodeur (Decoder).
tion des calculs et leur capacité d’homogénéisation. Grâce à L’encodeur s’occupe, comme son nom l’indique, d’encoder
l’homogénéisation, les Transformers peuvent accomplir plu- notre phrase d’entrée mot par mot. Une fois que tous les
sieurs tâches sans besoin d’entraînement supplémentaire. Ils mots dans la phrase ont été encodés, une “contextualisation”
offrent un mode d’apprentissage auto-supervisé (self-super- de la phrase, appelée context vector (Fig. 1), est donnée au
vised learning) sur des milliards de données brutes non struc- décodeur, qui l’utilise pour générer une réponse appropriée.
turées et réalisent des calculs sur des milliards de paramètres. La sortie est encore une fois générée mot à mot. Or, face à
Pour ces raisons, ils sont aussi appelés modèles fondateurs une phrase particulièrement longue, on risque de perdre des
(foundational models). informations importantes par rapport à l’interdépendance
Des Transformers ont été entraînés pour des tâches comme entre les mots. Le modèle n’arrive pas à se souvenir correc-
la traduction, la synthèse et la paraphrase, et ils peuvent tement des premiers mots encodés lorsqu’il résume la phrase
même répondre à des questions ou décrire des images. et la séquence de sortie générée n’est pas de qualité satisfai-
Figure 0 sante.
Pour bien comprendre pourquoi les Transformers sont si Pour résoudre cette problématique, Bahdanau et al. (2015),
populaire et tellement performant, il est important de com- ont développé une solution simple et élégante : le mécanisme
prendre le mécanisme clé derrière les performances nec plus de l’Attention. Le principe est facile à comprendre : en plus du
Figure 2
Figure 0. Abstraction du
fonctionnement d’un
Transformer. Image créée
par l’auteur. Figure 1. Illustration d’un modèle Encoder (en jaune) - Decoder (en bleu). Image créée par l’auteur.
56 programmez.com
contexte, on fait générer au modèle un “poids” pour chaque
mot dans la phrase. Ce poids indique l’importance ou l’atten-
tion qu’on doit prêter au mot dans le contexte. L’ensemble des
poids est donné au décodeur avec le context vector, ce qui lui
permet de bien interpréter la phrase (Fig. 2). L’attention pèse
chaque mot de la séquence d’entrée en fonction de l’impact
qu’il a sur la génération de la séquence cible.
Figure 2. Un Modèle
L’Attention, la vraie puissance des Encoder-Decoder avec
Transformers mécanisme d’Attention
comme présenté par
Quel lien entre l’Attention et les Transformers ? En effet, c’est
Bahdanau et al., 2015.
précisément ce mécanisme qui rend les Transformers à la fois
puissants et flexibles. Les Transformers sont des modèles
basés uniquement sur ce mécanisme d’Attention : on encode Figure 3. Exemple des
poids de chaque mot dans
chaque mot selon le poids qu’il a dans la phrase et en rela-
une phrase par rapport au
tion aux autres mots, sans passer par le context vector. La mot en gris. Les nuances
notion de “contexte” est incluse dans l’encodage fait par plus foncées représentent un
l’Attention, vu que chaque mot est encodé dans un principe poids plus élevé.
d’interdépendance (Fig. 3). Visualisation créée avec
BertViz.
Ce mécanisme est appelé auto-attention (Self-Attention), car
la phrase initiale “prête attention” à elle-même. En traitant
un mot, l’auto-attention permet au modèle de se concentrer
sur d’autres mots de la séquence d’entrée qui sont étroite-
Figure 4. Exemple
ment liés à celui-ci. d’Attention - Figure créée
Pour lui permettre de traiter plus de nuances sur l’intention par l’auteur
(c’est-à-dire le sens et le ton de la phrase) et la sémantique
de la phrase, un Transformer inclut des scores de multiples
attentions pour chaque mot.
Pendant le traitement d’un mot, l’attention permet au modè-
le de se concentrer sur d’autres mots de l’entrée qui sont
étroitement liés à ce mot. que chaque mot de la séquence est représenté par un vec-
Par exemple, dans la figure suivante, le lemme “chat” est teur. On ne va pas rentrer dans les détails du calcul de la
étroitement lié aux mots “noir” et “caresse”. En revanche, matrice. Il suffit de penser à ce trois matrices et à leur utilisa-
“noir” n’est pas lié à “fille”. Figure 4. tion comme une version plus soft d’un dictionnaire(1) :
L’architecture Transformer utilise l’auto-attention en reliant
dict = { ‘a’ : 1, ‘b’ : 2, ‘c’ : 3}
chaque mot de la séquence d’entrée à tous les autres mots.
Par exemple. Considérons deux phrases : Dans le dictionnaire dict en exemple, ‘c’ est une Key, 3 est un
• Le chat a bu le lait parce qu’il avait faim. Value.
• Le chat a bu le lait parce qu’il était sucré. Pour rechercher une valeur spécifique, on peut effectuer une
Dans la première phrase, le mot “il” fait référence au “chat”, recherche dans dict : dict[‘b’] (dict[‘b’] étant la Query). Dans
tandis que dans la seconde, il fait référence au “lait”. Lorsque le mécanisme de l’Attention, Key, Query and Value sont des
le modèle traite le mot “il”, l’auto-attention lui donne plus vecteurs. Chaque clé (Key) est comparée à une requête
d’informations sur sa signification afin qu’il puisse associer (Query), et une valeur (Value) est retournée.
correctement “il” aux autres lemmes de la séquence. Vaswani et al. (2017) ont été les premiers à proposer ce nou-
Par ailleurs, pour lui permettre de traiter plus de nuances sur veau modèle, et depuis, les entreprises et les laboratoires de
l’intention et la sémantique de la phrase, les Transformers recherche ont continué à les utiliser pour accomplir diffé-
incluent des scores de multiples attentions pour chaque mot. rentes tâches de Machine Learning, dans le TAL, mais pas
Par conséquent, lors du traitement du mot “il”, le premier seulement.
score met en évidence “chat”, tandis que le deuxième score En effet, baser un modèle exclusivement sur l’Attention ne
met en évidence “avait faim”. Ainsi, lorsqu’il décode le mot donne pas seulement de meilleurs résultats en termes de
“il”, en le traduisant dans une autre langue, il va choisir le qualité de la réponse, mais permet aussi de paralléliser les
bon mot dans la langue d’arrivée en tenant compte de la calculs, ce que les anciens modèles ne permettaient pas à
relation entre “il”, “chat” et “faim”. cause de leur nature séquentielle. Avec les Transformers, on
Dans l’Attention, la séquence intégrée passe par trois ne doit plus attendre que le premier mot soit encodé pour
couches linéaires qui produisent trois matrices distinctes, encoder le deuxième, et on peut donc encoder chaque mot
appelées requête, clé et valeur. Ce sont ces trois matrices qui en parallèle, améliorant largement les performances en
sont utilisées pour calculer le score d’attention. Il est impor- termes de calculs.
tant de garder à l’esprit que chaque “ligne” de ces matrices
correspond à un mot de la séquence source, ce qui signifie (1) https://www.w3schools.com/python/python_dictionaries.asp
programmez.com 57
On peut comparer les complexités des différents modèles couches d’incorporation correspondantes pour leurs entrées
dans le tableau suivant. Table 1 - respectives. Enfin, il existe une couche de sortie pour générer
Ici, d (ou d_model) est la dimension de représentation ou la sortie finale.
dimension d’intégration d’un mot (généralement dans la Démontons donc un Transformer pour en étudier chaque
gamme 128-512), n est la longueur de la séquence (généra- composant : Figure 5
lement dans la gamme 40-70), k est la taille du noyau de la
convolution et r est la taille de la fenêtre d’attention pour Positional Encoding Figure 6.
l’auto-attention restreinte. On part de l’encodage positionnel (Positional Encodings).
À partir de ce tableau, nous pouvons déduire ce qui suit : Nous savons que les calculs d’auto-attention (Self-Attention)
• Il est clair que la complexité de calcul par couche de l’au- n’ont aucune notion d’ordre des mots parmi les séquences.
to-attention est bien inférieure à celle des autres. Ainsi que les RNN bien qu’ils soient lents, conservent l’ordre
• Ces améliorations apportées par les Transformers se révè- des mots par leur nature séquentielle. Ainsi, pour obtenir
lent être des vrais atouts. Allons voir plus dans le détail la cette notion de positionnement des mots dans la séquence,
structure de ces modèles. des encodages positionnels sont ajoutés aux poids calculés
par l’attention.
La Structure d’un Transformer La dimension des encodages positionnels est la même que
En Figure 4, vous trouverez la structure d’un Transformer celle des embeddings(2) (d_model) pour faciliter la somma-
dans son intégralité. À la base, il contient une pile de tion des deux. Dans l’article, les encodages positionnels sont
Table 1 - Comparaison des couches encodeur et décodeur. Pour éviter toute confusion, obtenus à l’aide de ces formules :
modèles basés sur le RNN, le
nous ferons référence à la couche individuelle en tant qu’en-
CNN et l’auto-attention sur la
base de paramètres d’efficacité codeur ou décodeur et utiliserons pile encodeur ou pile déco-
informatique via “Attention is all deur pour un groupe de couches encodeurs.
you need”, Vaswani et al. (2017) La pile d’encodeurs et la pile de décodeurs ont chacune leurs
Figure 7. L’utilisation de sinusoïdes pour les encodages positionnels via
“Attention is all you need”, Vaswani et al. (2017)
Masking
Figure 6. Positional
Encodings dans un Transformer (2) https://developers.google.com/machine-learning/crash-course/embed-
via “Attention is all you need”, dings/video-lecture#:~:text=An%20embedding%20is%20a%20relatively,
Vaswani et al. (2017) like%20sparse%20vectors%20representing%20words.
58 programmez.com
introduit le masque de remplissage qui indique au modèle Multi-Head Attention
de ne pas prendre en considération ces zéros pendant l’en-
codage.
• Look-ahead Mask : lors de la génération de séquences cibles
au niveau du décodeur, puisque le Transformer utilise l’auto-
attention, il a tendance à inclure tous les mots de la phrase
cible. Mais, en réalité, c’est de la triche ! C’est comme si on
regardait les réponses du test avant de le passer. Seuls les
mots précédant le mot courant peuvent contribuer à la géné-
ration du mot suivant, C’est pour cela que dans la phase de
décodage, on masque les mots qui suivent. v
programmez.com 59
Apprentissage � Nous prenons le dernier mot de la séquence de sortie
Examinons d’abord le flux de données pendant l’apprentissage. comme le mot prédit. Ce mot est maintenant rempli
Celles utilisées pour l’entraînement se composent de deux dans la deuxième position de notre séquence d’entrée
parties : du décodeur, qui contient maintenant un jeton de début
• La séquence source ou d’entrée (par exemple, “You are de phrase et le premier mot.
welcome” en anglais, pour un problème de traduction). � Retournez à l’étape 3. Comme précédemment, introdui-
• La destination ou séquence cible (par exemple “De nada” sez la nouvelle séquence du décodeur dans le modèle.
en espagnol). Ensuite, prenez le deuxième mot de la sortie et ajoutez-
L’objectif du Transformer est d’apprendre à produire la le à la séquence du décodeur. Répétez cette opération
séquence cible, en utilisant à la fois la séquence d’entrée et jusqu’à ce que le modèle prédise un mot de fin de phra-
la séquence cible. se. Notez que puisque la séquence de l’Encodeur ne
Le transformer traite les données comme suit : change pas pour chaque itération, vous n’avez pas
� La séquence d’entrée est convertie en Embeddings (avec besoin de répéter les étapes une et deux.
codage de position) et transmise à l’Encodeur.
� La pile d’encodeurs traite ces données et produit une Teacher Forcing
représentation codée de la séquence d’entrée. L’approche consistant à fournir la séquence cible au déco-
� La séquence cible est précédée d’un jeton de début de deur pendant l’apprentissage est connue sous le nom de
phrase, convertie en imbrications (avec codage de posi- Teacher Forcing. Pourquoi le faisons-nous et que signifie ce
tion) et envoyée au décodeur. terme ?
� La pile de décodeurs traite cette séquence avec la repré- Pendant l’apprentissage, nous aurions pu utiliser la même
sentation codée de la pile de codeurs pour produire une approche que celle utilisée durant l’inférence. En d’autres
représentation codée de la séquence cible. termes, faire tourner le transformer en boucle, prendre le der-
� La couche de sortie l’a convertie en probabilités de mots nier mot de la séquence de sortie, l’ajouter à l’entrée du
et en séquence de sortie finale. décodeur et le transmettre au décodeur pour l’itération sui-
� La fonction de perte du transformer compare cette vante. Enfin, lorsque le jeton de fin de phrase est prédit, la
séquence de sortie avec la séquence cible provenant des fonction de perte compare la séquence de sortie générée à la
données d’apprentissage. Cette perte est utilisée pour séquence cible afin d’entraîner le réseau.
générer des gradients afin d’entraîner le transformer Non seulement cette boucle rend l’apprentissage plus long,
pendant la rétro-propagation. mais aussi plus difficile. Le modèle devrait prédire le deuxiè-
me mot sur la base d’un premier mot prédit, potentiellement
Inférence erroné, et ainsi de suite.
Pendant l’inférence, nous n’avons que la séquence d’entrée Au lieu de cela, en fournissant la séquence cible au déco-
et nous n’avons pas la séquence cible à transmettre comme deur, nous lui donnons un indice, ainsi que le ferait un ensei-
entrée au décodeur. Le but du transformer est de produire la gnant. Même s’il a prédit un premier mot erroné, il peut uti-
séquence cible à partir de la seule séquence d’entrée. liser le mot correct pour prédire le mot suivant afin d’éviter
Ainsi, comme dans un modèle Seq2Seq, nous générons la que ces erreurs ne s’accumulent.
sortie dans une boucle et alimentons le décodeur avec la En outre, le transformer est capable de produire tous les mots
séquence de sortie de l’étape précédente dans l’étape sui- en parallèle, sans boucle, ce qui accélère considérablement
vante jusqu’à ce que nous rencontrions un jeton de fin de l’apprentissage.
phrase.
La différence avec le modèle Seq2Seq est qu’à chaque Conclusion
étape, nous réinjectons la séquence de sortie entière générée Et voilà, on a reconstruit un Transformer. Vous savez mainte-
jusqu’à présent, plutôt que le dernier mot. nant comment l’Attention est utilisée pour donner un poids à
Le flux de données pendant l’inférence est le suivant : chaque mot de la phrase d’entrée, et comment ces poids
� La séquence d’entrée est convertie en Embeddings (avec sont utilisés pour produire une sortie. Maintenant que vous
codage de position) et transmise à l’encodeur. connaissez son architecture et les fonctionnalités principales,
� La pile d’encodeurs traite ces données et produit une vous pouvez explorer davantage ces modèles si puissants et
représentation encodée de la séquence d’entrée. performants. Il y a plusieurs librairies qui vous permettent de
� Au lieu de la séquence cible, nous utilisons une séquen- faire du Fine-Tuning sur des modèles déjà entraînés et des
ce vide avec seulement un jeton de début de phrase. nombreux articles qui expliquent la structure des
Celle-ci est convertie en Embeddings (avec codage de Transformers plus populaires.
position) et envoyée au décodeur. Essayez vous-mêmes, et vous serez surpris de leurs perfor-
� La pile de décodeurs la traite avec la représentation mances et leur flexibilité !
codée de la pile de codeurs pour produire une représen-
tation codée de la séquence cible.
� La couche de sortie l’a convertie en probabilités de mots
et produit une séquence de sortie.
60 programmez.com
Cafetière Arduino
On peut facilement trouver une cafetière de type Senseo pour 50 €, neuve et entre 20
et 30 €, d’occasion. Elles sont faciles à utiliser, les dosettes ne sont pas très chères et
elles permettent de faire du café à la demande. Cette cafetière est extrêmement simple, Jean-Christophe
Quetin
elle n’a que 3 boutons. Un bouton central qui permet de l’allumer et un bouton de
J’ai débuté sur MO5
chaque côté pour choisir la taille du café (simple ou double). avec le LOGO et sa
petite tortue (un des
Mais avec le modèle de base, cela demande 3 étapes : Préparation de la cafetière seuls langages en
français). J’ai retrouvé
� Mettre la tasse, l’eau, 1 ou 2 dosettes et allumer la L’accès à la cafetière n’est pas extrêmement facile, car il faut
l’électronique et la
cafetière en appuyant sur le bouton central. déjà démonter l’arrière, qui tient avec une vis torx et qui est clip- programmation avec le
Attendre presque 1 min 30 que l’eau soit suffisamment chaude. sée, avant d’accéder aux 2 vis torx qui maintiennent la plaque Raspberry Pi et
du dessous, sur laquelle est fixée la carte de contrôle. N’hésitez l’Arduino. J’ai eu
� Sélectionner le café désiré (simple tasse ou double tasse). l’occasion de travailler
pas à consulter le guide du Repair Café, à cette adresse :
Attendre encore environ 1 min que le café coule dans la tasse. avec des élèves de
https://smogey.org/wp-content/uploads/2017/09/Guide-de-re�paration-
collège sur l’Arduino et
� Prendre le café et le boire Senseo-Version-4.1.1-fr-Be�ta-du-6-de�cembre-2015-2.pdf d’écrire en 2018 mon
Figure 1 premier livre (dont la
Ce serait quand même plus pratique si l’on pouvait supprimer Je vous conseille de faire preuve d’un minimum de délicates- seconde édition est
l’étape n°2 et sélectionner son café dès le début (comme se, si vous ne voulez pas rencontrer le même problème que parue en 2021).
avec la Senseo Viva). Et ensuite on pourrait en profiter pour moi : en insérant un gros tournevis à l’intérieur de la cafetière Arduino - Apprivoisez
ajouter de nouvelles fonctionalités... pour déclipser l’avant qui faisait un peu de résistance, j’ai pris l’électronique et le
codage pour donner vie
Ce tuto utilise une Senseo modèle 7820. Si vous possédez appui sur le bouton central, qui n’est apparemment pas à vos projets (2e
une autre cafetière, il faudra peut-être modifier un peu le prévu pour supporter ce type de traitement… Figure 2 édition) au Editions ENI.
code ou les branchements, mais le principe reste le même Heureusement, j’ai réussi sans problèmes, à le dessouder et micro:bit - Programmez
le remplacer par un autre (carré). Figure 3 la carte avec MakeCode
Préparation de la cafetière Une fois la carte de contrôle extraite, soudez les fils sur les et MicroPython
Pour contrôler la cafetière, il faut simuler l’appui sur les bou- contacts des 3 boutons (au dos). Il suffit de seulement 4 fils, twitter.com/jcquetin
tons. La première étape est donc de démonter la cafetière, car les 3 boutons sont reliés à la masse, mais si vous préférez, arduiblog.com
pour accéder à la carte de contrôle. Ensuite, il faudra repérer vous pouvez aussi utiliser 6 fils (2 x 3 boutons). youtube.com/channel/UCQXCp5
les contacts correspondant aux 3 boutons poussoirs et souder Quelques conseils : Utilisez un fer à souder de bonne qualité, srlwc8eCvOULUjrdA
des fils qui seront reliés à des relais. ne dénudez pas les fils sur une trop grande longueur et éta-
Il est évident qu’après cette manipulation, la garantie du mez-les avant la soudure. Figure 4
constructeur ne pourra plus être invoquée en cas de panne Repérez bien les fils et remontez la cafetière. Figure 5
de la cafetière. Je vous conseille donc d’utiliser une vieille Les fils seront ensuite branchés à un module 4 relais
cafetière. (Alimentation de la cafetière + 3 boutons). Figure 6
Attention l’une des bornes est reliée à l’alimentation de la
cafetière (230V).
Figure 1
Figure 3
Figure 2
Figure 4
programmez.com 61
Figure 5
Travaillez toujours hors tension et enfermez le module
relais dans un boîtier isolé.
Matériel nécessaire :
• La cafetière modifiée (avec 1 module d’au moins 4 relais)
• 1 Arduino Uno et son alimentation,
• 1 breadboard avec des câbles Dupont,
• 2 boutons poussoirs,
Figure 8 • 1 LED et 1 résistance d’environ 220 Ω (facultatives, car
vous pouvez aussi regarder la LED interne de l’Arduino qui
est reliée à la même borne). Figure 8
Vous pouvez reproduire le schéma ci-dessous : Figure 9
Et téléverser le code correspondant dans l’Arduino (en adap-
tant éventuellement le temps de chauffe à votre cafetière) :
Code complet sur programmez.com & github
62 programmez.com
Compiler du code C # avec Roslyn
Je vous propose de découvrir comment C#, et .Net, permet de compiler dynamique-
ment du code et de produire une assembly .Net qui contiendra votre code compilé. Bien
Fred Berton
sûr l’exécution ne demande pas d’avoir Visual Studio sur le poste d’exécution, mais (frederic.berton@capge
uniquement un runtime .Net Framework. mini.com)
Je pratique le
Roslyn, c’est le joli petit nom que Microsoft a donné au « Kit • Microsoft.CodeAnalysis.Common développement logiciel
SDK .NET Compiler Platform » (forcément c’est moins • Microsoft.CodeAnalysis.CSharp Figure 1 depuis plus de 35 ans,
sympa). Ce SDK open source fournit les outils permettant Il existe également un package dit « all-in-one » qui installe depuis 13 ans chez
Capgemini dans une
l’analyse, et la compilation de code exprimé avec les lan- l’ensemble des fonctionnalités y compris la prise en charge approche en phase avec
gages C# et VB.Net. Le principal objectif de cet outil est de de Visual Basic. Le package s’appelle : Microsoft.Code la mouvance des
permettre le développement d’outils d’analyse de code sta- Analysis artisans du logiciel
tique basés sur l’analyse syntaxique et sémantique qui donne Vous pouvez utiliser le Roslyn dans un projet .NET Framework “Software
les moyens de comprendre le code. à partir de la version 4.5 ou .NET Core toutes versions. Craftsmanship”.
Ma motivation : relever
Vous l’avez compris c’est donc avec cet outil que l’on peut Pour utiliser les API de Roslyn dans le code C#, il faut utiliser le niveau du
écrire des outils pour contrôler la qualité du code, ou faire de le using suivant : développement
l’IntelliSense par exemple. Roslyn fournit l’ensemble des API professionnel de logiciels
nécessaire pour : l’analyse lexicale, l’analyse sémantique, la using Microsoft.CodeAnalysis.CSharp; par la pratique et en
compilation dynamique, la génération de code, et la compi- using Microsoft.CodeAnalysis; aidant les autres à
acquérir le savoir-faire.
lation statique. Dans cet article nous allons nous intéresser
plus particulièrement à cette dernière fonctionnalité pour la Présentation des classes nécessaires
compilation de notre code. Voir tableau ci-contre
programmez.com 63
Classes utiles pour la compilation de code. void Init(string _Nom, string _Mail);
Classe Description string Nom { get; set; }
Cette classe contient les méthodes nécessaires pour faire le string Mail { get; set; }
CSharpSyntaxTree
parsing d’un code C#. }
}
Cette classe dispose des fonctions statiques qui permettent de
MetadataReference créer les métadonnées nécessaires pour référencer une
assembly pour la classe CSharpCompilation. Cette interface qui sera connue de notre application nous
Cette classe contient les méthodes nécessaires à la permettra d’utiliser la classe ClassACompiler sans avoir de
compilation d’un code contenu dans un SyntaxTree. Elle liaison statique vers l’assembly qui la contient.
CSharpCompilation permet également de définir les références à d’autres Heureusement, car justement cette assembly peut ne pas
assembly utilisées. Elle contient une méthode qui permet de exister au moment de la compilation de notre application.
générer une assembly avec le code compilé.
Cette classe permet de définir des options utilisées par la Compiler le code et produire une
CSharpCompilation
Options
classe CSharpCompilation. Par exemple le type d’assembly assembly
(exe ou dll) que l’on souhaite produire. Pour compiler notre code, la première chose à faire est de
construire un arbre de syntaxe avec la méthode ParseText de la
Classes utiles pour le chargement dynamique d’assembly. classe CSharpSyntaxTree. Cet arbre permet d’analyser le code
La classe Assembly contient les méthodes statiques source sous la forme d’un arbre qui représente les concepts
nécessaires pour le chargement d’une assembly. Il est possible
Assembly du langage. Il peut être utilisé pour la compilation de code ce
de charger une assembly soit avec son nom (Assembly.Load),
soit avec son nom de fichier (Assembly.LoadFrom). qui est notre objectif ici, mais il peut aussi être utilisé pour
analyser le code.
La classe Activator contient les méthodes statiques nécessaires
Activator
pour créer une instance d’une classe à partir de son type.
// Lecture dans un string du fichier avec le code de la classe
string sCodeSource = File.ReadAllText(@”..\..\ClassACompiler.cs”);
simplification, le compilateur utilise une chaîne de caractère
comme source. // Parsing du code, creation du syntax tree
SyntaxTree tree = CSharpSyntaxTree.ParseText(sCodeSource);
using System; Figure 2
using Interfaces; L’avantage est que cette analyse est statique, utilise le texte
de notre code source et non le code compilé. En revanche les
namespace MyCompilation fonctionnalités rendues sont les mêmes que celles offertes
{ par la réflexion de code.
public class ClassACompiler : IInterfaceAdresse Avant de pouvoir compiler notre code à partir de l’analyse
{ syntaxique, nous devons donner au compilateur la liste des
public ClassACompiler() assemblys qui sont référencées par celui-ci. Au minimum il
{ faut donner la référence sur l’assembly System du .NET
Console.WriteLine($”Execute : MyCompilation.ClassACompiler()”); Framework qui contient la définition des types de bases. Pour
} définir une référence sur une assembly on utilise la fonction
CreateFromFile de la classe MetadataReference. Cette méthode prend
public void Init(string _Nom, string _Mail) en paramètre le chemin du fichier de l’assembly pour lequel
{ nous souhaitons obtenir une référence.
Console.WriteLine($”Execute : MyCompilation.Init({_Nom},{_Mail})”);
Nom = _Nom; // Creation des references sur les assembly utilisées
Mail = _Mail; string PathAssembly_System = typeof(object).Assembly.Location;
} string PathAssembly_Interfaces = typeof(IInterfaceAdresse).Assembly.
Location;
public string Nom { get; set; } var AssemblyRef_System = MetadataReference.CreateFromFile
public string Mail { get; set; } (PathAssembly_System);
} var AssemblyRef_Interfaces = MetadataReference.CreateFromFile
} (PathAssembly_Interfaces);
Comme on peut le constater la classe ClassACompiler implémen- La mise en place de la structure de compilation du code est
te l’interface IInterfaceAdresse ci-dessous réalisée par la fonction Create de la classe CSharpCompilation. Cette
fonction prend en paramètres l’arbre de syntaxe à compiler,
namespace Interfaces un tableau des assemblys qui sont référencées, et d’éven-
{ tuelles options de compilation.
public interface IInterfaceAdresse
{ var CompilationOption = new CSharpCompilationOptions(OutputKind.
64 programmez.com
DynamicallyLinkedLibrary); Console.WriteLine(“Compilation OK”); Figure 2 - Arbre de
syntaxe dans Visual Studio
var compilation = CSharpCompilation.Create(“MyCompilation”,
syntaxTrees: new[] { tree }, // Afficher les résultats de la compilation.
references: new[] { AssemblyRef_System, Assembly // il peut s’agir d’erreur ou de warning
Ref_Interfaces }, Console.WriteLine(“Résultat de la compilation”);
options: CompilationOption); foreach (Diagnostic diagnostic in emitResult.Diagnostics)
Console.WriteLine(diagnostic.ToString());
Les options de compilation définies dans la classe
CSharpCompilationOptions permettent, entre autre, d’indiquer notre Chargement dynamique de l’assembly
souhait de produire une assembly de type DLL lors de la com- À ce stade, et s’il n’y a pas d’erreur de compilation, nous
pilation (OutputKind. DynamicallyLinkedLibrary). Beaucoup d’autres avons produit une assembly avec notre code.
options sont disponibles, par exemple le niveau de warning, L’utilisation de cette assembly peut être réalisée via un char-
la cible CPU, etc. gement dynamique, ou plus classiquement, par une référen-
La génération de l’assembly est produite par la fonction Emit ce depuis Visual Studio.
de la classe CSharpCompilation, à laquelle on donne en paramètre Dans le code suivant nous illustrons un chargement dyna-
le nom du fichier qui contiendra l’assembly. mique et la création d’une instance de la classe, enfin nous
invoquons une méthode sur cette instance.
EmitResult emitResult = compilation.Emit(“output.dll”); Le chargement de l’assembly est réalisé par la fonction
Assembly.LoadFrom
D’autres paramètres sont possibles pour spécifier, par
exemple : un fichier pdb pour les informations de debug, ou var myAssembly = Assembly.LoadFrom(“output.dll”);
un fichier xml pour la documentation.
Cette fonction renvoie une instance de la classe EmitResult qui Une fois l’assembly chargée, on peut créer une instance de
permet d’analyser le résultat de la compilation et de la pro- la classe dont on retrouve le nom via la fonction GetType. On
duction de l’assembly. Si l’opération a réussi la propriété voit également l’utilisation de notre interface pour manipuler
Success est à True. En cas d’erreur, ou de warning, elles sont dis- l’instance de la classe sans connaitre au préalable son type.
ponibles dans la propriété Diagnostics. Ceci est possible, car nous avons défini cette interface dans
Le code suivant permet d’exploiter ce retour d’informations. une assembly qui est connu à la fois du programme appelant
et également par le code et l’assembly que nous avons com-
// S’il y a des erreurs de compilation le dire pilé.
if (emitResult.Success == false)
Console.WriteLine(“Compilation KO”); Type typeMyClass = myAssembly.GetType(“MyCompilation.Class
else ACompiler”);
programmez.com 65
IInterfaceAdresse myclass = (IInterfaceAdresse)Activator.CreateInstance Console.WriteLine(“Compilation KO”);
(typeMyClass); else
Console.WriteLine(“Compilation OK”);
Nous disposons maintenant d’une instance de la classe dont
// Afficher les résultats de la compilation.
nous pouvons invoquée simplement des méthodes.
// il peut s’agir d’erreur ou de warning
Console.WriteLine(“Résultat de la compilation”);
myclass.Init(“BERTON”, “[email protected]”);
foreach (Diagnostic diagnostic in emitResult.Diagnostics)
Console.WriteLine($”Nom {myclass.Nom} Mail {myclass.Mail}”);
Console.WriteLine(diagnostic.ToString());
Voici le code complet :
Console.WriteLine(“Appuyez sur une touche pour charger l’assembly”);
Console.ReadKey();
using System;
using System.IO;
// Chargement dynamique de l’assembly que l’on viens de compiler
using System.Reflection;
Console.WriteLine(“Chargment de assembly : output.dll”);
using Microsoft.CodeAnalysis.CSharp;
var myAssembly = Assembly.LoadFrom(“output.dll”);
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Emit;
// CReation d’une instance de la classe : MyCompilation.ClassACompiler
Console.WriteLine(“Creation d’une instance de la classe : MyCompilation.
// Cet espace de nom, est défini dans une assembly qui contient
ClassACompiler”);
l’interface IInterfaceAdresse
Type typeMyClass = myAssembly.GetType(“MyCompilation.ClassA
// Cette assembly doit être référencée statiquement par le programme
Compiler”);
using Interfaces;
IInterfaceAdresse myclass = (IInterfaceAdresse)Activator.Create
Instance(typeMyClass);
namespace Roseline
{
// invocation des methodes avec l’interface contenu du programme appelant
public class CompilationExample
myclass.Init(“BERTON”, “[email protected]”);
{
Console.WriteLine($”Nom {myclass.Nom} Mail {myclass.Mail}”);
static public void Compile_And_Execute()
{
Console.WriteLine(“Appuyez sur une touche pour quitter”);
// Lecture dans un string du fichier avec le code de la classe
Console.ReadKey();
string sCodeSource = File.ReadAllText(@”..\..\ClassACompiler.cs”);
}
}
// Parsing du code, creation du syntax tree
}
SyntaxTree tree = CSharpSyntaxTree.ParseText(sCodeSource);
// Creation des references sur les assembly utilisée Liens web sur Microsoft Roslyn
string PathAssembly_System = typeof(object).Assembly.Location; Nous donnons ici des liens sur des articles ou des documen-
string PathAssembly_Interfaces = typeof(IInterfaceAdresse).Assembly. tations qui permettent une prise en main avancée du compi-
Location; lateur Microsoft Roslyn.
var AssemblyRef_System = MetadataReference.CreateFromFile
(PathAssembly_System); La documentation et les codes sources sont disponibles à
var AssemblyRef_Interfaces = MetadataReference.CreateFromFile l’adresse : https://github.com/dotnet/roslyn
(PathAssembly_Interfaces); Une partie de la documentation de Roslyn est disponible sur
le site de Microsoft à l’adresse : https://docs.microsoft.com/en-
// Compilation du code us/dotnet/api/microsoft.codeanalysis.
var CompilationOption = new CSharpCompilationOptions(Output Cette documentation couvre principalement les fonctionnalités
Kind.DynamicallyLinkedLibrary); d’analyse de code de Roslyn qui ne nous intéressent pas ici.
var compilation = CSharpCompilation.Create(“MyCompilation”, Pour trouver l’ensemble de la documentation nécessaire à
syntaxTrees: new[] { tree }, l’utilisation de Roslyn (comme le compilateur par exemple) il
references: new[] { AssemblyRef_System, faut se référer au site web : https://github.com/dotnet/roslyn/tree/
AssemblyRef_Interfaces }, master/docs qui contient la documentation complète et les
options: CompilationOption); codes sources de Roslyn.
Documentation sur l’analyseur syntaxique : https://docs.micro-
// Creation de l’assembly soft.com/fr-fr/dotnet/csharp/roslyn-sdk/get-started/syntax-analysis
Console.WriteLine(“COMPILATION”);
EmitResult emitResult = compilation.Emit(“output.dll”);
Lien sur des articles traitants de Roslyn comme compilateur :
// S’il y a des erreurs de compilation le dire https://www.tugberkugurlu.com/archive/compiling-c-sharp-code-into-memo-
if (emitResult.Success == false) ry-and-executing-it-with-roslyn
66 programmez.com
Le balisage sémantique : réconcilier
l’humain et la machine en donnant du sens.
Traditionnellement une page, un contenu écrit qu’il soit présent dans un livre ou sur une Max Antoine
BRUN
feuille volante est destiné à être lu par un humain. On écrit pour être lu par l’humain . Fort de près d’une
décennie dans le monde
du SEO ; de nombreux
Avec l’avènement d’internet, un nouveau « consommateur » l’humain ; mais qui ne l’était alors pas pour le robot. Elle succès notables pour
des sites de toutes
de contenu écrit est apparu, à savoir : le bot informatique. Un ajoute ainsi de la cohérence en revoyant la même informa-
tailles, évoluant dans
robot d’indexation est un agent logiciel automatique ou semi- tion aux deux types de visiteurs. des secteurs divers tels
automatique qui interagit avec des serveurs informatiques. Le que : l’immobilier ; la
travail du robot d’indexation consiste à « explorer » des pages Quelles sont les différentes balises cosmétique ; l’assurance
web pour récupérer les informations qui s’y trouvent. sémantiques et à quoi renvoient-elles ? ; la banque ; la
succession ; etc. ; j’ai
Une page web est donc, destinée à être « survolée » par l’hu- Les balises sémantiques peuvent donner des informations sur
décidé de me mettre à
main ET par les bots informatiques (ou robots d’indexation) ; une section d’une page, mais également sur la partie d’un mon compte il y a
c’est sans doute la différence la plus notable avec la page contenu. Elles permettent ainsi de structurer la page web : maintenant quelques
physique qui elle, n’est lue que par l’humain. • En-tête ; années et j’ai créé
Or, le robot n’étant pas encore capable de comprendre la • Menu de navigation ; Search Artisan, agence
SEO axée sur la
« nature » d’une partie d’une page (s’agit-il d’un menu ? du • Contenu principal ;
conversion dédiée aux
contenu principal de la page ? du contenu annexe ?) encore • Contenus indépendants ; indépendants et aux
moins leur signification dans un contexte (pragmatisme) ; les • Section ; Grands Comptes.
développeurs ont dû penser à des balises servant à donner • Contenus annexes ;
des informations sur le contenu qu’elle encadre. • Pied de page.
Ces balises dites sémantiques permettent ainsi de structurer Mais également le contenu présent sur la page :
les pages et de leur donner du sens pour les robots informa- • Titrage ;
tiques. Elles s’avèrent donc utiles pour le positionnement de • Liste à puce ;
ces pages. Les mots-clés compris dans certaines balises sont, • Mise en forme ;
en effet, mieux appréciés par Google. • Citations ;
• Adresse ;
Pour commencer, qu’est-ce qu’une • Etc.
balise sémantique ? Nous allons dans cet article nous concentrer sur les balises
Au début du web, avant le développement des balises sémantiques qui permettent de structurer une page web.
sémantiques, seules les balises <div> et <span> étaient uti-
lisées pour donner des informations sur la structure d’une Les balises sémantiques qui permet-
page aux robots d’indexation. tent de structurer une page
Ainsi, les balises sémantiques sont venues combler un vide Les balises sémantiques permettent de structurer une page
sémantique quant à l’appréciation des bots lors de leur visite web et ainsi de donner des informations cruciales aux robots ;
sur une page web. Il y a encore quelques années, il était notamment aux robots des moteurs de recherche. La pondé-
impossible pour un robot d’indexation de comprendre la ration des mots (poids donné à un mot par les robots des
structure d’une page web. Les balises <div> et <span> moteurs de recherche) est plus ou moins importante selon
alors utilisées ne donnant aucune information sur la nature l’emplacement auquel il se trouve.
des sections qu’elles entourent. Ainsi, un mot présent dans l’en-tête et dans la barre de navi-
En effet, la balise <div> sert à coder un bloc de page, un gation sera plus fortement pondéré qu’un mot présent dans
bloc pouvant comprendre un ou plusieurs paragraphes, une un paragraphe de milieu de page.
ou plusieurs images avec leurs légendes, etc. Les balises sémantiques ont donc deux forts intérêts :
La balise <span> est utilisée pour spécifier une ligne ; une � Donner une structure à la page ;
phrase par exemple. Le robot d’indexation des moteurs de � Accentuer la pondération du mot-clé (requête cible)
recherche avec ces seules balises n’était donc pas capable pour les robots des moteurs de recherche.
d’isoler les différentes parties d’une page ou plus précisé-
ment d’en comprendre leur sens. Quelles sont ces balises qui permet-
Il pouvait ainsi s’agir aussi bien d’un <menu>, d’une section tent de structurer une page ?
<article> annexe ou encore d’une en-tête (<header>) sans La balise d’en-tête <header>
que le robot ne les considère pas comme étant différents. Il s’agit de la partie la plus haute de la page ; celle qui sera vu
C’est de ce vide sémantique que sont venues combler les en premier par l’internaute. Communément, on y trouve le
balises sémantiques. Elles permettent de structurer une page logo, le menu de navigation (avec l’ensemble des liens qui y
et donc d’envoyer une information qui est déjà présente pour sont présents). Peuvent, également, se trouver dans cette zone :
programmez.com 67
• Le panier ;
• Le bouton de connexion ;
• Le bouton d’inscription ;
• etc.
À noter que la présence de plusieurs balises <header> n’est
pas du tout interdite, voire non pénalisante. Mais, en abuser ne
serait pas une bonne idée, car elle créerait de la confusion dans
la compréhension de la structure de votre page par les robots.
68 programmez.com
NextJS, le marketing au service
des développeurs
Ne partez pas tout de suite ! Je sais, je vais vous parler de marketing alors que nous Loïc
GUILLEBEAU
préférons tous laisser ceci de côté en tant que développeurs. Ne vous inquiétez pas, je J’ai 21 ans et pendant
vais quand même vous parler technique ! Le sujet du jour est NextJS ! mon cursus d’ingénieur
en informatique à
Les équipes de NextJS ont pensé leur framework afin de vous ge ci-dessous. Figure 1. Cette architecture va aussi vous per- EPITA, j’ai créé ASIG-
Tech que je dirige depuis
faciliter le développement et la mise en production. Cela va mettre de créer votre sitemap beaucoup plus simplement. Il
maintenant 4 ans.
passer par l’architecture de vos fichiers, l’intégration de l’API, existe des packages comme next-sitemap qui vont se baser
J’ai commencé à
la manière de récupérer vos données et la gestion de votre sur votre build pour créer le fichier sitemap.xml. Ainsi cette développer au collège
balise < head > dans chaque page ! Et cela en vue de servir phase prend en compte votre architecture du dossier page, avec Java et le fameux
l’une des choses les plus importantes d’internet : le SEO d’où la nécessité de bien le structurer. Il y a aussi une partie jeu Minecraft. Un début
(Search Engine Optimization) ! Nous appellerons notre pro- importante liée à l’api, que nous verrons plus loin. plutôt créatif ! Au fil des
jet : Mecanique Venture. Notez que si votre application n’est guère destinée à un années, j’ai appris
d’autres langages.
usage en interne et cible un large public, alors il sera très
Je lance un nouveau
En quoi l’architecture de mes fichiers important de créer ce fichier pour que Google trouve votre
projet qui s’appelle
influe sur le SEO ? site et vous référence correctement. Vous devrez aller sur Accelerio. Nous utilisons
En règle générale, quand tu es développeur, il est important Google Search Console pour leur envoyer votre nouveau site- NextJS pour créer une
d’avoir une arborescence de fichiers structurée et compré- map via l’url de votre site ! plateforme de
hensible par tous. Oui, il arrive que ton collègue en marke- réservation en ligne pour
les sports mécaniques.
ting décide de regarder à quoi ça ressemble la Comment récupérer mes données
« Programmation ». pour le SEO ? Vous retrouvez mes
projets ici :
NextJS vous oblige à avoir une structure très précise afin Maintenant que vous avez une architecture au top, il faut
https://asig-tech.com
d’être prêt à envoyer en production très rapidement. Quand maintenant penser à récupérer les données pour les mettre
https://accelerio.com
vous allez initialiser votre projet Next avec en forme sur votre site. Pour cela, il faut savoir comment vous
npx create-next-app@latest OU yarn create next-app , vous aurez allez gérer vos informations. Il se peut que cela soit géré du
déjà l’architecture construite, il vous suffira de l’enrichir. côté serveur (Server-side rendering - SSR) ou du côté client
Vous retrouverez un dossier styles/ qui regroupe tous vos (Client-side rendering - CSR). Avec SSR, l’API est “atteinte”
fichiers CSS/SCSS. Le dossier public/ qui permet de mettre à avant que votre page termine de se charger, et cela, malgré
disposition de l’utilisateur des images, des pdfs, des vidéos ou l’effet de délai qu’on peut constater avant l’affichage. Tandis
d’autres types de contenu. Il a le même but que le dossier qu’avec CSR, votre fetch sera exécuté après que la page s’est
public propre à un projet Express/Node, à savoir servir des chargée. Nous pouvons aussi gérer cela de manière statique,
fichiers statiques. Enfin, le plus important demeure le dossier c’est ce que nous appelons : Static-site generation (SSG).
pages/ avec un sous-dossier api/ et un fichier index.js. Ce Cette technique permet de récolter toutes les données au
fichier contient l’exemple de départ et constitue la page cen-
trale qui est affichée lorsqu’un utilisateur se rend à la racine
(root) de votre application.
Ce dossier est essentiel, c’est lui qui va gérer toute l’arbores-
cence de votre site web !
Dans notre projet Mecanique Venture. On aura donc plu-
sieurs pages. Notre page d’accueil pour donner envie à nos
utilisateurs d’acheter nos pièces, également une page de
blog avec tous nos articles pour attirer du monde sur notre
site par le biais de questions souvent posées. Cette page blog
sera liée à une page template d’article qui sera générée auto-
matiquement grâce à son slug. Il ne faut pas oublier, que
nous sommes un site e-commerce, nous aurons un catalogue
de tous nos produits et des catégories par produit. De la
même manière que le blog à une page template d’article, ici
nous aurons une page template d’un produit.
Il nous faut aussi un tunnel d’achat avec un panier, un for-
mulaire de paiement et un formulaire de livraison. Puis pour
rassurer nos clients, nous rajoutons une page sur notre histoire
et une page pour nous contacter.
Vous pouvez visualiser cette architecture en consultant l’ima- Figure 1
programmez.com 69
moment du build et d’afficher une donnée directement sur le dynamiques associées à votre page. Ici, nous allons récupé-
site sans appeler le serveur. Ceci est la meilleure technique rer tous les slugs de nos produits. Cela permettra au site de
pour le SEO, car Google ne laisse pas le temps à votre site reconnaître les URL qui doivent être appelées en statique.
d’appeler votre serveur. De plus, le SSG fait au moment du Elle va ensuite appeler votre API pour récupérer l’informa-
build un pré-rendu qui génère un fichier HTML avec vos don- tion. C’est ici qu’intervient la deuxième fonction, vous allez
nées pour chacune de vos pages. Puis, il reste une dernière faire votre appel API dedans puis gérer vos données pour les
technique que nous appelons : Incremental Static envoyer à votre composant react, qui recevra product
Regeneration (ISR). Certains diront qu’elle ressemble à SSG comme prop. Notons que tout cela s’exécute au moment du
et d’autres que c’est plutôt une combinaison entre SSG et « build » ce qui permet de générer une page html pour cha-
SSR ; celle-ci permet, une fois que le site est build et mis en cune des URL trouvées dans votre première fonction.
production, de rafraîchir les données au bout d’un intervalle De plus, pour trouver cette liste d’url, vous pouvez appeler
défini. Cela peut être utile lorsque vous créez une fiche pro- votre base de données, votre CMS ou votre système de
duit que vous mettez à jour à l’aide d’un back-office externe. fichiers afin de la récupérer dynamiquement. Ainsi, cela vous
Aujourd’hui, NextJS gère ces quatre façons de récupérer les permet de ne pas écrire à la main chaque url possible.
données. Pour cela, il faut appeler des fonctions spécifiques Code complet sur programmez.com & github
à ce framework. Pour la première manière, le server-side ren-
dering se fait grâce à la fonction asynchrone getServer Pour finir, nous avons la technique de la régénération statique
SideProps(). Cette fonction de vos pages (ISR). Elle vient parfaitement compléter le SSG.
s’applique, seulement, dans un fichier inclus dans le dossier Elle nous permet de privilégier la génération statique de nos
pages/. Dans les paramètres de la fonction vous allez pouvoir pages, sans avoir à reconstruire tout le site à chaque fois.
récupérer tout le contexte de votre page. Par exemple, vous C’est très pratique quand votre collègue veut changer une
allez pouvoir accéder à l’url de la page, pour récupérer des image sur la fiche produit. Cela permet de vous laisser tran-
données en fonction d’un slug. Voici un exemple de com- quille sans avoir à mettre une nouvelle fois en production tout
ment cela fonctionne : votre site. Ici, nous faisons appel aux mêmes fonctions que
nous avons vu juste avant, mais avec deux paramètres diffé-
export async function getServerSideProps({params}) {
rents. Tout d’abord, dans le getStaticProps() vous allez pou-
const result = await axios.get(‘/api/v1/product/slug/’ + params.slug)
voir retourner un paramètre revalidate. Il permettra de dire
au site de se régénérer à des intervalles réguliers lorsqu’une
return {
requête est effectuée sur la page. Dans notre exemple, la
props: {
valeur sera de 60 secondes. Ensuite, il reste la
product: result.data
fonction getStaticPaths() à laquelle nous pouvons retourner
}
le paramètre fallback. Ce dernier peut prendre trois valeurs :
}
false, true ou blocking. Cela va permettre de ne pas générer
}
toutes les pages dynamiques lors du build initial et de produire
La spécificité de CSR est qu’il peut s’exécuter au sein vos un effet sur la façon dont la fonction getStaticProps() va se
composants appelés. Cette technique est plutôt utile quand comporter. Si le paramètre est à false la fonction sera appe-
vos données sont amenées à changer assez souvent et que le lée au moment du build et une page 404 sera retournée dès
SEO ne fait pas partie de vos préoccupations. De plus, NextJS lors qu’il n’ y aura aucune correspondance avec les chemins
vous offre un React Hook qui est le SWR, il permet de récu- retournés par getStaticPaths(), ce type d’erreur permet de
pérer vos données, de les passer directement en cache, de les mieux contrôler les pages qui fonctionnent, on privilégiera ce
rafraîchir et les mettre à jour à intervalles réguliers. mode lorsque l’on souhaite générer l’ensemble de nos routes
dynamiques au moment du build. Si nous passons le fallback
const fetcher = url => axios.get(url).then(res => res.data)
à true, la fonction getStaticProps() sera exécutée en arrière-
plan pour tous les chemins qui n’auront pas été générés au
function App ({slug}) {
moment du build, une page de secours (fallback) s’affichera
const { data, error } = useSWR(`/api/v1/product/slug/${slug}`, fetcher)
le temps de la construction de la page finale, cela est très
appréciable pour un site e-commerce dans lequel vous avez
if (error) return <div>{error}</div>
généré vos 100 meilleures pages au moment du build et
if (!data) return <div>Chargement...</div>
envisagez de laisser les autres se générer lors de la première
visite. Enfin, avec la valeur blocking, aucune page de secours
//...
(fallback) n’apparaîtra, il faudra attendre l’affichage de la
}
page, ce qui sera marqué par une temporisation de quelques
Passons, maintenant, au cœur de notre sujet, à savoir la secondes à l’image d’un rendu côté serveur (SSR), ce qui
récupération des données pour le SEO. Comme nous l’évo- n’est pas forcément recherché ici.
quions précédemment, la meilleure technique reste la géné-
ration statique (SSG). Afin d’y arriver vous allez devoir appe- export async function getStaticPaths() {
ler deux fonctions dans votre fichier : getStaticPaths() et const {data: result} = await axios.get(‘/api/v1/product/slug’)
getStaticProps(). La première va permettre de récupérer une let products = []
liste d’URL possibles (de chemins) en fonction des routes
70 programmez.com
result.map(data => { Une astuce intéressante est de prévoir lors de votre architectu-
products.push({params: {slug: data.slug}}) re de la base de données des champs spécifiques à votre SEO.
}) Cela vous permettra de générer votre balise < Head > de
manière beaucoup plus simple plutôt que de devoir retra-
return { vailler chaque variable de votre produit ou article.
paths: products, Code complet sur programmez.com & github
fallback: true
} Toutes ces informations permettront à Google de vous ado-
} rer !
Vous savez tout sur la manière de gérer vos données sur Comment créer mon API sur NextJS ?
NextJS. Maintenant, c’est à vous de choisir ce que vous pré- Un petit bonus, cela ne fait jamais de mal ! Ce qui est intéressant aussi
férez selon le contexte de votre prochain projet ! avec NextJS, c’est sa gestion de l’API directement sur le framework. Il
n’est pas obligatoire de passer par un backend en NodeJS avec Express
Comment gérer ma balise < head > ? ou autres. Encore une fois, nous retrouvons dans cette partie l’importan-
La gestion de votre balise < head > n’est pas la partie la plus ce de notre architecture ! Elle est directement liée à la route de votre API.
compliquée, mais reste non négligeable en SEO. C’est ici que Dans notre exemple, nous avons une API pour récupérer toutes les
Google va lire toutes vos métadonnées et que vous allez pou- marques de voitures. Ce qui donne une architecture de dossier comme
voir mettre en place OpenGraph ! Dans le cadre de cet celle-ci « /api/v1/make/index.js ». Ensuite vous retrouverez une fonction
article, nous allons nous intéresser sur la manière d’enrichir classique comme dans NodeJS, avec en paramètres la requête et la
votre balise < head > dynamiquement. réponse à renvoyer. Dans mon exemple, j’utilise prisma pour récupérer
Dans cette partie-là, nous retrouvons les balises meta clas- mes données ! C’est un ORM très pratique. Pour finir, il vous suffira d’ap-
siques que vous pouvez avoir sur un site écrit en HTML pur. Il peler votre url : « /api/v1/make ». Cela peut se faire avec fetch() ou axios
y a la balise meta pour la description, la gestion des robots, comme vous préférez.
les mots-clés de votre site, le robot google et bien d’autres.
En plus de cela, il est important d’avoir une balise < title > et export default async function handle(req, res) {
un lien canonique pour Google. En revanche, vous n’allez pas try {
écrire à la main chaque page HTML de vos dix mille produits. const result = await prisma.vehicles.findMany()
Cela va vous amener à utiliser toutes les données que vous res.status(200).json(result)
allez récupérer, comme nous l’avons vu précédemment pour } catch (e) {
la mettre dans votre balise < Head > de NextJS. Il faut savoir res.status(500).json({ error: e })
que dans ce framework nous pouvons gérer une balise }
< Head > par fichier a contrario de React où il n’y a qu’un }
fichier HTML. Même si vous utilisez React Helmet, cela ne
permet pas une génération de votre page web en statique, Et voilà, vous savez gérer l’API sur NextJS, facile non ?
donc le référencement sera de moins bonne qualité.
Revenons sur notre balise < Head >, vous avez maintenant
toutes vos données et vous allez pouvoir les ajouter à vos Ressources
balises. Cela se gère de la même manière que si vous inté- https://github.com/LoicGuillebeau/MecaniqueVenture
grez une variable dans votre code, rien de plus simple. https://nextjs.org/docs/basic-features/data-fetching/overview
La gestion des balises pour OpenGraph est semblable, mais https://nextjs.org/docs/routing/dynamic-routes
il faut avoir les mots-clés spécifiques à cette technologie. https://nextjs.org/docs/api-routes/introduction
Nous allons retrouver les propriétés « og : type », « og : url », https://nextjs.org/docs/basic-features/pages
« og : title », « og : description » et « og : image ». Ces pro- https://www.prisma.io/docs/
priétés représentent l’une des configurations les plus simples, https://ogp.me/
il en existe d’autres. OpenGraph vous permet d’afficher des https://developers.google.com/search/docs/advanced/crawling/special-tags
informations lorsque vous partagez votre page sur différents https://developers.google.com/search/docs/advanced/sitemaps/build-sitemap
réseaux sociaux. https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props
programmez.com 71
Une gestion efficace des
configurations Python avec Hydra
Thibaud Vienne
est senior data scientist
et le fondateur de Mi-recherche, mi-dev, la réalisation d’applications, notamment machine learning, fait
Clevergence, une fintech émerger de nombreux challenges dont sa reproductibilité, son déploiement et son
spécialisée dans le
développement de suivi. Dans le cas du machine learning, une réponse à ces difficultés est le “MLOps”,
modèles de risques
financiers pour les
un ensemble de pratiques qui visent à développer, déployer et maintenir des modèles
professionnels de de machine learning de façon fiable et efficace.
l’investissement. Il est
également professeur
vacataire en machine Avec l’approche MLOps, le cycle de vie d’un projet machine Avec la ligne de commande, les différents paramètres sont passés
learning au sein de learning n’est plus linéaire, mais prend la forme d’un proces- à l’interpréteur python lors de l’exécution du script au travers de
l’université Paris- sus itératif qui comprend l’émergence de fonctionnalités, le “flags”. Ceux-ci peuvent ensuite être récupérés et retraités
Dauphine. développement de celles-ci (de la collecte de données à l’en- convenablement avec certains modules tels que argparse.
traînement du modèle) puis son déploiement en production. Dans l’exemple ci-dessous (cf. Annexe, répertoire GitHub),
Cette boucle de rétroaction permet d’obtenir rapidement un nous allons implémenter une application simple de machine
feedback pour continuer à faire évoluer l’application. Figure 1 learning comprenant la création de données aléatoires (N
Ces nombreux allers-retours entre développement et lignes et M colonnes) puis la création et l’entraînement d’un
déploiement engendrent de nombreuses expérimentations et réseau de neurones avec Keras. Cette application contient de
essais. Cela pousse ainsi bien souvent l’équipe data science nombreux paramètres tels que le format des données
Hamza Aziz à utiliser des fichiers de configuration pour paramétrer d’entrée ou l’architecture du réseau de neurones. Figure 2
est machine learning l’application. Par exemple, pour pouvoir tester une nouvelle La récupération des paramètres avec Argparse se fait de la
engineer. Actuellement, structure de modèle ou encore ajouter / supprimer une façon suivante :
il implémente des outils
variable explicative (c’est-à-dire une variable utilisée pour
MLops au sein de
Clevergence. entraîner le modèle). import argparse
Cela étant, ces fichiers de configuration échouent bien
souvent à concilier robustesse du code et flexibilité. Hydra, un parser = argparse.ArgumentParser()
module python développé par Facebook AI Research, permet parser.add_argument(“—n_rows_train”, type=int, help=”number of
de dépasser ces difficultés. rows in training set”)
parser.add_argument(“—n_rows_test”, type=int, help=”number of
Argparse et les fichiers rows in test set”)
de configuration parser.add_argument(“—n_columns”, type=int, help=”number of
Avec Python, il existe plusieurs façons de gérer ces fichiers de input features (columns)”)
configuration. Les plus communément utilisées sont le parser.add_argument(“—n_neurons_1”, type=int, help=”number of
passage d’arguments par la ligne de commande ou bien le neurons in the first layer.”)
recours à des fichiers de configuration. parser.add_argument(“—activation_1”, type=str, help=”activation
function in first layer.”)
parser.add_argument(“—n_neurons_2”, type=int, help=”number of
neurons in the second layer.”)
parser.add_argument(“—activation_2”, type=str, help=”activation in
the second layer.”)
parser.add_argument(“—learning_rate”, type=float, help=”learning
rate”)
Figure 1- Le déploiement de l’application permet le feebdack utilisateur et donc l’émergence de nouvelles actions conf = parser.parse_args()
correctives (besoin de plus de données, nouvelles variables explicatives, etc.). Passage et récupération d’arguments avec Argparse.
72 programmez.com
De plus, Argparse permet aussi de pouvoir assigner des modifier un paramètre facilement. De plus, il devient possible
valeurs par défaut ou d’introduire des arguments optionnels. de passer n’importe quel type d’objet en paramètre tel que
Malgré ces fonctionnalités, argparse rencontre plusieurs des listes, dictionnaires, voire même des fonctions ou des
limitations : classes, etc.
• Passage d’arguments laborieux, dès que l’application Bien que plus flexible qu’Argparse, chaque changement de
dépasse quelques paramètres. Il faut à la fois modifier la paramètre nécessite une modification du fichier de
ligne de commande et le parsing des arguments dans le configuration. Quand le fichier est versionné (par exemple
script. Ce qui peut vite devenir fastidieux ; avec Git) et couplé avec une approche de déploiement
• Absence de hiérarchie, qui empêche de regrouper les continu (CI/CD), chaque modification devra entraîner un
paramètres en groupe. Ce qui est pourtant utile si ceux-ci commit. Ce qui pourra se révéler peu pratique lorsque l’on
agissent sur un même composant (par exemple souhaite réaliser de nombreuses expérimentations.
l’architecture du modèle).
Peut-on faire autrement qu’avec la ligne de commande ? Hydra, une solution plus adaptée
Oui, en utilisant des fichiers de configuration. Cela consiste à Hydra permet de résoudre l’ensemble des difficultés
stocker nos paramètres dans un fichier puis à les lire dans évoquées précédemment. Il s’agit d’un module python open
l’application. Ci-dessous, un exemple réalisé avec un simple source développé par Facebook AI Research (FAIR). Avec
dictionnaire Python créé dans le fichier conf.py, puis importé Hydra, les fichiers de configuration sont écrits au format
et utilisé dans le main : yaml, puis sont chargés dans l’application. Il est également
possible d’utiliser la ligne de commande (comme pour
src conf = { Argparse) afin d’outrepasser le fichier de configuration.
├── config # data L’installation de hydra est simple pour tout système
│ └── conf.py “n_rows_train”: 1000, d’exploitation et se fait avec le gestionnaire pip :
└── main_with_conf.py “n_rows_test”: 200, > pip install hydra-core
“n_columns”: 5,
Le format yaml utilisé par Hydra offre l’avantage de pouvoir
# model hiérarchiser les paramètres, comme dans l’exemple ci-
“n_neurons_1”: 10, dessous, avec les sections “data” et “model”. Le chargement
“activation_1”: “relu”, de la configuration se fait dans le main avec l’ajout d’un
“n_neurons_2”: 5, simple décorateur hydra qui spécifie le chemin du fichier de
“activation_2”: “tanh”, configuration (avec le “config_path” et le “config_name”
“learning_rate”: 0.05 respectivement le chemin du répertoire et le point d’entrée).
} Le fichier de configuration est ensuite chargé dans un
dictionnaire qui devient alors accessible, ici avec la variable
fichier conf.py : les paramètres sont encapsulés dans un dictionnaire.
conf.
programmez.com 73
, p=[1./2, 1./2])
x_test = np.random.randn(conf.data.n_rows_train, conf.data.n_columns) # create fake data
y_test = np.random.choice([0, 1], size=(conf.data.n_rows_test,), p= print(conf)
[1./2, 1./2]) x_train = np.random.randn(conf.data.n_rows_train, conf.data.n_
columns)
____________________________________________ y_train = np.random.choice([0, 1], size=(conf.data.n_rows_train,),
… p=[1./2, 1./2])
____________________________________________ x_test = np.random.randn(conf.data.n_rows_train, conf.data.n_
columns)
if __name__ == “__main__”: y_test = np.random.choice([0, 1], size=(conf.data.n_rows_test,),
p=[1./2, 1./2])
# test 4 : hydra ____________________________________________
main()� …
____________________________________________ ____________________________________________
output
____________________________________________
if __name__ == “__main__”:
{‘data’: {‘n_rows_train’: 1000, ‘n_rows_test’: 200, ‘n_columns’: 5},
‘model’: {‘n_neurons_1’: 10, ‘activation_1’: ‘relu’, ‘n_neurons_2’: 5, # test 4 : hydra
‘activation_2’: ‘tanh’, ‘learning_rate’: 0.05}} main()
main_with_hydra.py : utilisation du décorateur Hydra pour appeller ____________________________________________
la configuration. output
____________________________________________
Avec Hydra, il devient également possible d’alterner
facilement entre plusieurs expérimentations. Nous pouvons,
{‘model’: {‘n_neurons_1’: 500, ‘activation_1’: ‘relu’, ‘n_neurons_2’:
par exemple, construire des sous-configurations pour
100, ‘activation_2’: ‘tanh’, ‘learning_rate’: 0.1}, ‘data’: {‘n_rows_train’:
représenter deux modèles différents “small” et “large”. La
1000, ‘n_rows_test’: 200, ‘n_columns’: 5}}
structure des répertoires de notre application ressemble alors
à ce qui suit : main_with_hydra.py : le modèle “large” a bien été pris en compte.
Dans le fichier principal conf.yaml, il est alors possible de
basculer facilement d’un fichier de configuration à l’autre en Hydra permet ainsi d’écrire, hiérarchiser et basculer
assignant au paramètre model, la valeur “model_small” ou facilement entre plusieurs configurations. Ce qui rend les
“model_large”. expérimentations flexibles et reproductibles. La ligne de
commande peut également être utilisée pour outrepasser le
src fichier yaml. Enfin, Hydra possède de nombreuses autres
n_neurons_1: 10 n_neurons_1: 500
├── config fonctionnalités parmi lesquelles :
activation_1: “relu” activation_1: “relu”
│ └── conf.yaml • La gestion des formats, des différents paramètres passés
n_neurons_2: 5 n_neurons_2: 100
│ ├── models en configuration ;
activation_2: “tanh” activation_2: “tanh”
│ │ └── model_small.yaml • Le multi-run, pour exécuter l’application avec plusieurs
learning_rate: 0.05 learning_rate: 0.1
│ │ └── model_large.yaml paramètres en même temps. Par exemple avec la ligne de
└── main_with_hydra.py commande : > python main_with_hydra.py —multirun
n_rows_train=1000,2000 ;
À gauche, l’architecture du projet • Et plein d’autres encore, nous vous invitons à consulter la
Au milieu - model_small.yaml : un petit réseau de neurones. documentation officielle pour plus de détails.
À droite - model_large.yaml : un réseau de neurones plus large.
Conclusion
defaults: Hydra permet d’adresser efficacement les limitations de
- model: model_large Argparse et des fichiers de configurations. Ce qui en fait un
outil de choix pour les applications data science nécessitant
data: de nombreuses expérimentations.
n_rows_train: 1000
n_rows_test: 200 Annexes
n_columns: 5 Repo GitHub : https://github.com/tvienne/demo-hydra
conf.yaml : la section “model” est maintenant composée à partir du Wikipedia : https://fr.wikipedia.org/wiki/MLOps
sous-fichier de configuration model/model_large.yaml Documentation Hydra : https://hydra.cc/docs/intro
import hydra
@hydra.main(config_path=”config”, config_name=”conf”)
def main(conf):
74 programmez.com
Comprendre l’UI Design sous Figma
Figma est LE logiciel pour faire du Design d’interface ces dernières années. Son succès
lui vient notamment d’une interface web ou logicielle qui se rapproche de plus en plus
Margaux Membré
du développement web en utilisant des notions CSS et un jargon connu : space-bet- Passionnée de
ween, containers, padding, margin, position absolute… (Presque) tout y est ! graphisme et de visuels
depuis une bonne
dizaine d’années, j’ai
commencé à
m’intéresser au Design
Vous pourriez avoir besoin de comprendre sa mécanique, notam- c’est-à-dire que je vais me focaliser sur les fonctionnalités. Il avec Photoshop. J’ai été
ment si vous envisagez d’approfondir vos connaissances dans existe aussi un benchmark inspirationnel qui consiste à Développeuse Front-End
l’UI Design. Nous verrons les bases de l’UI Design et la prise en regarder davantage les codes graphiques et à s’en inspirer. (1) pendant quelques mois
main de Figma. Il se peut que dans votre quotidien, vous puissiez Nous n’entrerons pas davantage dans les détails, je vous en 2019/2020, et je me
suis reconvertie dans
avoir besoin de comprendre sa mécanique. C’est parti ! laisse le soin de creuser si le sujet vous intéresse. Une
l’UX/UI Design fin 2020.
ressource : https://www.usabilis.com/quest-ce-que-le-design-thinking/#:
Je travaille actuellement
Revenons aux fondamentaux : l’UI ~:text=Le design thinking est une,des services ou produits à La Redoute dans le
Design innovants. cadre de mon
UI signifie User Interface. Mais ce n’est pas simplement le alternance, autant sur
fait de faire des carrés et des ronds de couleur, loin de là ! L’outil de l’UI Designer : Figma l’interface web que sur
Le rôle de l’UI Designer est de créer de la hiérarchie visuelle, Je ne suis pas neutre dans ce domaine puisque j’adore l’interface mobile, et sur
le Design System.
grâce à des rapports de proportion et l’utilisation de l’espace Figma, mais il existe aussi Sketch ainsi qu’Adobe eXperience
blanc (white space), afin d’aider l’utilisateur à remplir l’objec- Design (Adobe XD) qui permettent de concevoir des
tif qu’il s’est fixé en arrivant sur le site. Il est donc le guide de interfaces digitales.
l’utilisateur dans son parcours sur le site. Figma est un outil gratuit (dans une moindre mesure) qui
L’UI Design ne s’apprend jamais seul dans les écoles (en tout existe dans une version light et, depuis peu, dans une version
cas, à ma connaissance). Et ça se comprend ! Un bon UI dark.
Designer fait attention aux attentes, besoins et motivations C’est lorsque vous déciderez de créer des Teams que la
de l’utilisateur. Il le comprend et essaie de trouver des solu- question de payer un abonnement se posera. Les teams sont
tions à ses frustrations pour qu’il ait une expérience agréable des endroits comme des répertoires Github : seuls ceux que
durant tout son parcours sur l’interface ou le service. L’UI vous invitez peuvent contribuer aux fichiers (éditer), et vous
Designer a donc des bases en UX Design. pouvez ainsi séparer différentes teams par Features Teams ou
L’UX Designer utilise des méthodes comme les entretiens, les Business Units par exemple.
questionnaires, les cartes d’empathie, etc. Il est souvent Il ne reste plus qu’à créer un nouveau fichier ou à entrer dans
amené à tester l’ergonomie de son travail via les tests un fichier déjà existant !
utilisateurs, et il est parfois adepte du Design Thinking(1).
La structure des fichiers
Benchmark Chaque entreprise a son fonctionnement, mais ce qui reste
L’UI Designer commence souvent son travail par un commun est le fait d’utiliser plusieurs pages.
benchmark des concurrents de son entreprise, c’est-à-dire
qu’il va regarder les fonctionnalités (features) créées par
d’autres acteurs… Qu’ils soient en lien direct avec le secteur
de l’entreprise ou non !
Prenons un exemple : je travaille chez La Redoute, où nous
vendons du Prêt-à-porter, de la Maison et beaucoup d’autres
choses.
Je peux être amenée à “benchmarker” (barbarisme du
métier) un site comme Adidas et Zalando qui sont tous les
deux des e-commerces de l’habillement/sport. Je peux aussi
benchmarker des sites comme Leroy Merlin ou Castorama
**qui ne vendent pas du tout le même type de produits. Ça
reste du e-commerce, mais je pourrais même sortir de ce
domaine pour aller benchmarker Airbnb par exemple !
Tous les sites qui ont des fonctionnalités intéressantes qui
pourraient être utiles sur votre interface valent la peine d’être
creusés. Néanmoins, comme en code, ce qui marche On définit toujours une image de couverture (cover ou
quelque part ne fonctionnera peut-être pas chez vous… thumbnail) qui permet d’identifier le projet. En général, on y
Ce dont je vous parle ici, c’est du benchmark fonctionnel, fait figurer :
programmez.com 75
• Le nom du projet ou de la feature. Par exemple : panier
(basket).
• La personne qui s’en occupe ou qui en est responsable.
• Le statut du fichier : en cours, complété (côté design), prêt
pour le développement, terminé, etc.
Commencer à créer
Comme les développeurs, les designers fonctionnent avec
des composants (components). Les composants garantissent
une meilleure cohérence graphique, puisqu’ils évitent de
créer de nouveaux éléments à chaque nouveau besoin. Quand vous réutiliserez votre button, il aura un symbole
Les designers travaillent souvent avec l’Atomic Design, différent dans le panneau Layers. Ce sera à présent un
concept créé par Brad Frost, qui consiste à séparer les losange vide*(9)*.
éléments selon qu’ils sont des atomes, des molécules, des
organismes, des templates ou des pages.
Partons sur un exemple pratique : les boutons !
Commencez à écrire votre texte grâce à l’outil Texte (Text).
La logique des composants est très semblable à celle des
développeurs : l’idée est de créer le composant le plus
générique possible, et donc un composant réutilisable. Ici,
Avec le raccourci Shift + A, transformez votre texte en auto- nous avons vu un élément très basique, mais la prise en main
layout, notion sur laquelle nous reviendrons plus bas. est similaire pour les éléments plus complexes. Je vous
Remplissez le “Fill” avec une couleur et ajoutez un border- conseille de creuser dans les vidéos, qui seront sans doute un
radius si vous le souhaitez. support plus adapté qu’un article :
https://www.youtube.com/watch?v=e68PKFYWfoQ
https://www.youtube.com/watch?v=e68PKFYWfoQ&feature=emb_imp_woyt
https://www.youtube.com/watch?v=Pip1uFrB8II
https://www.youtube.com/watch?v=Pip1uFrB8II
(Pour la mise à jour)
Auto-layout et contraintes
Ces fonctionnalités sont LA grande spécificité de Figma par
rapport à Adobe XD ou Sketch, disponible nativement dans
l’outil. C’est aussi ce qui se rapproche le plus de la propriété
CSS Flexbox. Lien vers la propriété CSS Flexbox : https://css-
tricks.com/snippets/css/a-guide-to-flexbox/
Auto-layout
Il est possible de mettre à peu près tout en auto-layout. Reprenons
notre exemple de bouton. Prenez l’outil Texte (Text) en appuyant sur T
et écrivez “Button label”. Ensuite, faites le raccourci clavier Shift + A.
Dans la barre en haut, cliquez sur le losange composé de 4 Vous pouvez voir un nouveau symbole dans le panneau de gauche :
carrés*(6)* en sélectionnant votre élément. Vous avez
maintenant un composant*(7)* ! Plus qu’à le renommer
“button” et le tour est joué. Dans le panneau Assets(8), vous (Auto-layout horizontal : les éléments se mettront les uns à côté
pouvez maintenant retrouver votre button et le réutiliser où des autres. En CSS, cela équivaut à un flex-direction: row;)
vous voulez.
76 programmez.com
Il est possible de :
• Changer le sens de l’auto-layout : vertical ou horizontal.
• Ajouter, modifier ou supprimer la valeur de margin (espace Centré à gauche
entre les éléments).
• Ajouter, modifier ou supprimer la valeur de padding
(espace interne aux éléments) sur la gauche et la droite.
• Ajouter, modifier ou supprimer la valeur de padding en
haut et en bas.
• Gérer l’alignement des éléments présents dans l’auto-
layout.
Dans l’exemple de notre bouton, nous n’avons qu’un texte ;
si nous ajoutons une icône, l’alignement peut être intéressant
puisque nous pourrons centrer les deux éléments.
Essayons de construire une liste en auto-layout.
Pour ça, créez plusieurs blocs de texte. Notez qu’il est
important que ce soit bien des blocs de texte indépendants et
non des retours à la ligne. Par défaut, Figma positionnera
l’auto-layout en horizontal. Passez-le en vertical. Dans le
panneau de gauche, vous devriez avoir ça :
En bas à gauche
programmez.com 77
Figma en 2022, c’est la position absolute. Si vous cliquez sur texte, s’il est en Hug contents, il pourra être amené à
votre icône, vous devriez avoir un symbole particulier qui dépasser la width de la liste et à sortir du conteneur
apparaît en haut du panneau de droite. (container).
On laisse rarement une width en Hug contents, par contre il
est très fréquent pour avoir un comportement responsive de
laisser la height en Hug contents.
Pour la width, on va en général préférer l’option Fill container
qui n’apparaît que si le parent est lui-même en auto-layout.
Ici, mon content est en auto-layout et ma liste également.
Contraintes
Les contraintes (constraints) sont situées dans le panneau de
droite de Figma. Elles disparaissent quand l’élément est en
auto-layout, pour proposer d’autres options situées en haut
du panneau de droite sous la largeur (width) et la hauteur
(height) :
78 programmez.com
consulter des vidéos sur YouTube pour mieux comprendre et une librairie la plus exhaustive possible. Il est toujours possible
vous faire la main sur l’outil. d’ajouter de nouveaux éléments, mais il faut en général un ou
https://www.youtube.com/watch?v=floQKLsWAy4 plusieurs “garant(s)” de l’UI Kit/Design System qui valident les
https://www.youtube.com/watch?v=floQKLsWAy4&feature=emb_imp_woyt demandes et qui garantissent la bonne cohérence des
éléments de l’interface (des composants de la marque).
Les armes de l’UI Designer : l’UI Kit
et le Styles Guide ! Introduction au Design System
L’UI Kit Le Design System est la Bible du designer et de l’entreprise
L’UI Kit est l’ensemble des composants utilisés dans une en matière de design, de ton of voice et de code.
interface. En d’autres termes, l’UI Kit, c’est la bibliothèque Encore jeune, il remplace peu à peu la charte graphique PDF
de composants de votre projet ! pour s’exporter sur le web où il prend la forme d’un site
Il rassemble tous les composants au même endroit, facilitant répertoriant les lignes directrices (guidelines), les
ainsi la visualisation de l’ensemble des composants de composants, la façon d’écrire (copywritting) et également des
l’interface et leur utilisation. Il permet aussi de garder la spécifications techniques.
cohérence graphique et l’harmonie générale en utilisant des Il s’agit d’un produit qui évolue et qui contient différentes
composants dans le but d’éviter de créer sans cesse de versions pour permettre aux designers de proposer de
nouveaux éléments. nouveaux éléments, tout en permettant au reste de
L’UI Kit contient également toutes les variations d’un l’entreprise de continuer d’utiliser la version en cours. De ce
composant, ce qui permet aux designers de pouvoir changer fait, il a souvent un nom propre.
facilement certaines propriétés et d’avoir accès à toutes les Il devient de plus en plus important pour les entreprises
déclinaisons d’un composant. d’investir dans le Design System et d’y dédier des ressources
Puisque l’UI Kit est composé des composants Masters, il propres afin de permettre une meilleure évolution, autant en
permet de garder l’interface à jour et de changer très terme de design que d’expérience utilisateur.
facilement des éléments de style comme la typographie ou Je vous invite à consulter plusieurs Design Systems :
encore la couleur. • Carbon, IBM : https://carbondesignsystem.com/
L’UI Kit permet d’industrialiser le processus de design, • Spectrum, Adobe : https://spectrum.adobe.com/
puisqu’il s’agit ensuite de faire du Lego : on assemble • Mozaic, Adeo : https://mozaic.adeo.cloud/
chaque composant pour créer une page. Pour concevoir un • Vitamin, Decathlon :
UI Kit efficace, je vous conseille de vous intéresser à l’Atomic https://www.decathlon.design/726f8c765/p/71b8e3-decathlon-design-system
Design et de lire des articles sur le sujet. • Oxygen, Doctolib :
Pour autant, un UI Kit ne sert absolument à rien sans Styles https://oxygen.doctolib.design/60b411768/p/77fd2d-doctolib-design-system
Guide ! Vous pouvez aussi consulter la liste des designs systems
français sur Design Systems France :
Styles Guide https://www.designsystems.fr/liste-des-designs-systems-francais
Le Styles Guide, c’est la documentation de votre UI Kit.
Chaque composant doit avoir un rôle et doit être explicité Le Design, une philosophie
pour permettre aux designers de votre équipe de l’utiliser Tout au long de cet article, nous sommes restés dans une
facilement sans se poser de questions. vision très orientée Design visuel (UI Design). Pour autant, il
Le Styles Guide et l’UI Kit constituent un premier pas vers un ne faut pas oublier l’Expérience Utilisateur (UX Design) qui
Design System, et la meilleure documentation que je pourrais passe par beaucoup d’interactions avec les utilisateurs et de
vous conseiller pour servir d’exemple vient tout droit des la recherche pour comprendre leurs besoins, leurs attentes,
Design Systems. leurs motivations et leurs frustrations.
En général, on y explique : Il s’agit de créer des produits pour répondre aux besoins des
• Ce à quoi sert le composant ; utilisateurs et solutionner leurs problèmes. Dans le cas où le
• Quand les utiliser ou quand ne pas les utiliser ; profit serait la seule motivation, le produit risquerait de ne
• Les variants et dans quels cas les utiliser ; pas fonctionner.
• Les tailles (pour les boutons par exemple) ; Concernant l’UI Design, il s’agit d’une étape complexe qui
• Comment les utiliser (les do & don’t). est primordiale puisqu’elle peut avoir un impact émotionnel
Ce n’est jamais très drôle d’écrire une documentation, mais pour l’utilisateur et le pousser à apprécier le site et la marque.
c’est pourtant primordial pour l’entreprise. La documentation Attention néanmoins à ne pas tomber dans de mauvaises
permet à tous les designers d’avoir accès aux mêmes pratiques (Dark Patterns) qui auraient pour but de tromper
informations et de pouvoir produire des pages de la même l’utilisateur afin de le faire consommer !
qualité en garantissant l’harmonie et la cohérence Enfin, il faut de la rigueur et être à l’aise avec son logiciel
graphique. pour faciliter et accélérer le travail. Il faut également
Ce sont des lignes de conduite à adopter, des règles à suivre. beaucoup de réflexion en amont et bien construire sa base,
Il est donc important de passer du temps à les écrire pour c’est-à-dire l’UI Kit, le Styles Guide et le Design System. Le
chaque composant, et même pour les styles (couleurs, Design, c’est beaucoup plus que faire des cercles et des
typographie, grille…). rectangles de couleur !
On prévoit toutes les variations d’un composant pour avoir
programmez.com 79
Les VPN comme système de
contournement des restrictions et
Louis de Choulot
Étudiant en 2e année
d’étude de
sécurisation de vos connexions.
programmation
informatique à Le VPN, ou Virtual Private Network, est un système de chiffrement et de protection des
ALGOSUP, Vierzon
France. données né en 1996 avec comme but de donner un accès à distance sécurisé aux
[email protected] fichiers d’une entreprise par ses employés, il ne concernait pas l’internet global, mais
plutôt les intranets.
Aujourd’hui, des services VPN existent et proposent différents et ne nécessite aucune configuration extérieure.
types de protocoles. Devant cette gamme nous pouvons nous On entend souvent parler d’IPSec avec L2TP Layer 2
demander lesquels utiliser ? Tunneling Protocol, une évolution du PPTP, développé par
Microsoft et Cisco. L2TP ne contenant pas de cryptage des
Les principes de base données et n’ayant pour but que la création du tunnel entre
des protocoles VPN les appareils connectés, fait d’IPSec le parfait “partenaire”.
Si nous parlons aujourd’hui du VPN comme étant un moyen
sécurisé d’envoyer des données en les cryptant, rappelons- Remote access Vpn et Site-to-Site Vpn
nous qu’à l’époque le VPN définissait le PPTP soit Point to Le Vpn possède deux possibilités d’accès, que ce soit en
Point Tunneling Protocol. intranet [1] ou en extranet [2].
Ce système servait de “tunnel” protégé entourant la donnée Le Vpn site to site est celui que vous utilisez quand vous vous
pour empêcher son interception, elle n’était pas pour autant rendez sur internet, si vous possédez un service Vpn de bas
cryptée. Ainsi, la faille avait vite été découverte, le tunnel niveau, c’est un cryptage de la donnée entre votre appareil
était facile à décrypter pour quiconque connaissant un peu le et celui qu’il doit atteindre.
domaine. Le remote access Vpn ou Vpn avec accès à distance n’est pas
Bien que ce protocole ait connu un succès long terne dû à plus compliqué, vous gardez le principe du site to site Vpn et
son implémentation par un de ses créateurs : Windows, sur le vous ajoutez un appareil, le vôtre. Puis vous allez vous
système Windows XP. Celui-ci n’est aujourd’hui plus proposé connecter à ce réseau site to site de façon sécurisée, mais à
par les services VPN. distance
En 1998 le protocole IKEV pour internet Key Exchange fait Il n’y a pas de désavantage à se connecter en remote, le seul
son apparition, ce dernier se sert de clefs de cryptage pour mauvais point qu’on peut lui trouver est dans la surveillance
crypter la donnée elle-même. Microsoft et Cisco, ses des connexions au site to site, une brèche de sécurité peut
créateurs, venaient de créer la base du protocole VPN souvent apparaître à cause d’une négligence telle que ne pas
moderne. consulter les logs/historiques de connexions pour observer si
IKEV est devenu obsolète avec l’arrivée du nouveau IKEV2 les appareils ayant accédés au site sont bien enregistrés.
en 2005, on parle plus souvent de celui-ci comme une L’erreur viendra plutôt de l’Humain, notamment s’il accorde
amélioration et c’est pourquoi IKEV porte aussi le nom des droits d’accès aux mauvais appareils, c’est une
d’IKEV1. maladresse assez courante, elle s’est par exemple produite à
Les faiblesses majeures d’IKEV1 étaient : la NASA. En effet, un raspberry pi avait été branché dans
• Sa grande consommation de ressources ; l’enceinte de l’établissement et avait eu accès au réseau
• L’authentification symétrique, on lui préférera l’asymétrique interne. Les hackers n’avaient alors plus qu’à se connecter au
qui utilise 2 clefs de cryptage. Une par appareil, au lieu raspberry à distance, puis à collecter autant de données que
d’une seule commune à chaque appareil connecté ; possible avant que la brèche ne soit décelée, leurs identités
• Aucun accès à distance possible ; n’ont toujours pas été découvertes.
• IKEV utilise toujours le port UDP 500.
Ces faiblesses sont toutes réglées dans la version de 2005 Les protocoles VPN actuels
IKEV2. Les protocoles VPN n’ont de cesse de s’améliorer, le plus
souvent grâce à l’aide des géants de la tech comme les
Enfin, les bases autour des protocoles VPN actuels, ne GAFAM [3], nous l’avons vu précédemment avec Microsoft
sauraient être complètes sans parler d’ IPSec ou internet qui s’est impliqué dans la création de plusieurs des protocoles
Protocol Security. IPSec représente un ensemble de VPN basiques. De nos jours, ces derniers sont le plus souvent
protocoles utilisés dans la sécurisation des données qui utilisés par le biais d’un service VPN, il n’est donc pas rare
transitent sur internet, il se trouve directement sur le réseau que l’utilisateur ne sache pas que la plupart proposent les
80 programmez.com
mêmes services et protocoles avec pour seule différence la distributions Linux : Apple et mobile passez votre chemin !
qualité de ceux-ci. Avec un service VPN payant, il y aura SSTP est toujours en développement et grâce aux robustes
sûrement une connexion sécurisée à un serveur qui équipes de Microsoft, il est extrêmement efficace sur
s’occupera d’effectuer pour vous les demandes de connexion Windows. Son protocole de cryptage est le même que celui
aux pages web et renverra ce qu’il obtient à votre appareil, il utilisé par OpenVPN soit du 256 bits, celui-ci est aussi appelé
s’agit souvent de connexions en remote access. AES pour Advanced Encryption Standard. AES est réputé
pour n’avoir aucune backdoor, le seul moyen de le cracker est
Parmi les plus populaires et utilisés, on retrouve OpenVPN d’utiliser des techniques plus ou moins proches du brut force,
(2002), sécurisé et rapide, il est issu de technologies open il faudrait plusieurs millions d’années avec le meilleur
source/ libre d’accès. ordinateur du monde pour le cracker, car le nombre de
S’il n’est pas le plus rapide, il possède l’un des meilleurs possibilités pour AES est de 2 à la puissance 256 soit
alliages stabilité, sécurité et compatibilité. Il est compatible 1.157920892373162e+77 soit bien plus qu’un milliard de
sur tous les appareils avec comme seul bémol qu’il nécessite milliards de milliards.(15,792,089,237,316,195,423,570,
un tiers pour l’installer. Son support mobile laisse place à des 985,008,687,907,853,269,984,665,640,564,039,457,
améliorations. 584,007,913,129,639,936 de possibilités)
SSTP est un peu le PPTP/LT2P de notre époque.
En second, il s’agit d’un VPN beaucoup plus jeune, à savoir
SoftEther (2014). Celui-ci se base sur d’autres protocoles Ressources
VPN qui ne lui sont pas “propres”. Ce nouveau venu possède [1] Intranet : connexion entre plusieurs appareils accessibles
un haut niveau de sécurité, mais surtout une grande rapidité. dans un lieu donné en local. Il s’agit d’un réseau interne.
Il n’a aucun problème de compatibilité, quel que soit l’OS [2] Extranet : Fait souvent référence à l’internet global et
[4], car dès le départ il a été pensé multi-plate-forme. Il se toutes les connexions accessibles à distance. Il s’agit d’un
pourrait qu’il dépasse OpenVPN dans les années à venir, tant réseau externe.
en popularité qu’en efficacité. [3] Google, Apple, Facebook, Amazon et Microsoft.
Le troisième est encore plus nouveau et surtout promet d’être [4] Système d’exploitation.
plus efficace que OpenVPN sur bien des aspects :
WireGuard. Sources
15% plus rapide, une sécurité au top, avec une promesse de https://www.vpnmonde.com/levolution-des-vpn-de-1995-a-nos-jours/
multi-plate-forme, il ne date que de 2019 pour sa version la https://www.le-vpn.com/fr/histoire-des-vpn/
plus récente, mais fait déjà partie des références du VPN. Si https://www.fibre-pro.fr/vpn-ipsec/
on peut lui reprocher une chose, c’est qu’il échappe https://www.cisco.com/c/en/us/support/docs/security-vpn/ipsec-negotiation-ike-protocols/217432-understand-ipsec-ikev1-protocol.html
beaucoup plus difficilement aux filtres anti-VPN que https://nordvpn.com/fr/vpn-client/
OpenVPN et SoftEther ce qui est une donnée importante https://nordvpn.com/fr/what-is-a-vpn/#3972593d-0
dans le choix de son protocole, car les filtres anti-VPN se https://surfshark.com/fr/
popularisent et beaucoup de grandes entreprises les mettent https://surfshark.com/fr/learn/vpn-cest-quoi
en place, en vue de vous empêcher d’avoir un abonnement https://openvpn.net/
à un prix moins cher sur l’un de leurs services ou de participer https://www.softether.org/
à une bêta ouverte uniquement dans des zones https://thebestvpn.com/pptp-l2tp-openvpn-sstp-ikev2-protocols/
géographiques spécifiques. Un autre challenger anti-VPN est https://www.security.org/vpn/best/
l’état, en vous connectant en dehors du pays vous échapper https://www.journaldunet.fr/web-tech/guide-de-l-entreprise-digitale/1506369-openvpn-tout-savoir-sur-le-vpn-open-source-pour-les-pros/
à la censure appliquée sur les réseaux. https://le-routeur-wifi.com/site-bloque-vpn/
Néanmoins, WireGuard est toujours en développement et ses https://cybernews.com/what-is-vpn/wireguard-protocol/
failles pourraient être comblées lors de futures mises à jour. https://www.vpnxd.com/softether-vs-openvpn-which-one-better/
Enfin, SSTP, développé par Microsoft, ne fait aucune https://lecrabeinfo.net/vpn-les-protocoles-de-chiffrement.html#openvpn
promesse de multi-plate-forme, mais fonctionne sous certaines https://fr.vpnmentor.com/blog/les-differents-types-de-vpn-et-quand-les-utiliser/#section-5
https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#Performance
https://www.thesslstore.com/blog/what-is-256-bit-encryption/
1 an de Programmez!
ABONNEMENT PDF : 45 €
Abonnez-vous directement sur
www.programmez.com
programmez.com 81
le bon outil pour le bon projet… ou pas.
82 programmez.com