0% ont trouvé ce document utile (0 vote)
216 vues84 pages

Programmez 249

Le magazine aborde des sujets variés pour les développeurs, notamment l'éco-conception et la responsabilité écologique dans le développement logiciel. Il présente également des nouveautés sur .NET 6 et Java 17, ainsi que des articles sur des techniques de programmation comme le TDD et la programmation dynamique. Le numéro inclut des événements à venir et des brèves sur des incidents récents dans le secteur technologique.

Transféré par

jdsa
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
216 vues84 pages

Programmez 249

Le magazine aborde des sujets variés pour les développeurs, notamment l'éco-conception et la responsabilité écologique dans le développement logiciel. Il présente également des nouveautés sur .NET 6 et Java 17, ainsi que des articles sur des techniques de programmation comme le TDD et la programmation dynamique. Le numéro inclut des événements à venir et des brèves sur des incidents récents dans le secteur technologique.

Transféré par

jdsa
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

L e m a g a z i n e d e s d é v e l o p p e u r s

.NET 6
JAVA 17
N°249
11/12
2021

Le
développeur
va sauver
© source : yogysic

la TerrE ! M 04319 - 249 - F: 6,99 E - RD


Le seul magazine écrit par et pour les développeurs
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
3’:HIKONB=^U[^^X:?k@c@o@j@a";
002.qxp_249 18/10/2021 15:54 Page2
003_004.qxp_249 18/10/2021 18:50 Page3

TABLE DES MATIÈRES

Contenus
⊦≰ Agenda ⊦≺⊔ Coder Fibonacci en Java avec des tests
Les événements pour les développeurs Codons le calcul des termes de la suite de Fibonacci en Java
La rédaction grâce au TDD.
Thierry Leriche

⊦≲ Quelques brèves du mois


Louis Adam ([Link]) ⊦≺⊛ Python et la tortue
Ce n’est pas une fable de la Fontaine mais de la programmation
python en dessinant.
⊦≵⊒ Dossier spécial .Net 6 Malika More & Pascal Lafourcad
En novembre, .Net 6 sera disponible pour tous les développeurs.
Nos experts .Net vous proposent un tour d’horizon
de la plateforme + Visual Studio 2022. ⊦≻⊔ Programmation dynamique
Pierre Gascoin, Jérémy Jeanson, Baptiste Bazureau, Python est un langage surpuissant mais pas toujours simple
François Lefebvre, Sébastien Bernard, Florian Pouchelet, à maîtriser quand il faut typer. La programmation dynamique
Clément Sannier, Gatien Montreuil est lâ pour nous aider.
Philippe Boulanger

⊦≷⊗ Java 17
Java 17 vient de sortir. ⊦≻⊘ Interopérabilité Kotlin et Java partie 2
Quelles nouveautés pour les développeurs ? Revenons sur l’interopérabilité entre Kotlin et Java.
Loïc Mathieu Sallah Kokaina

⊦≷⊙ Le développeur va sauver la Terre ! ⊦≼⊓ Par les deux bouts de la lorgnette
Partie 1 : posons les fondamentaux Question sur l’observabilité !
L’éco-conception doit permettre de mieux utiliser les ressources Jean-Baptiste Bron
technologiques, réduire l’impact de l’informatique et optimiser les
codes, le binaire, le poids des pages web, etc; Dossier complet
sur les bonnes pratiques et pourquoi les utiliser.
Mathieu Touchard, Pierre Lagarde, Raphaël Lemaire,
Benoit Petit, Vincent Frattaroli, François Rézenthel

⊦≹⊖ Refactorer le legacy intestable avec les

Divers
Approval Tests
Quoi ? Vous ne connaissez les Approval Tests ?
Il est temps de combler vos lacunes.
Sepehr Namdar
⊦≮ Edito
⊦≹⊚ Superviser votre Linux avec un écran LCD !
Le développeur est comme Chuck Norris,
il va nous sauver (ou nous défoncer)
Un peu de code, des libs, un écran LCD. Ce projet permet
monitorer son système Linux très simplement avec lcd4linux.
Sébastien Colas
≸⊔ ≸⊕ Abonnement & Boutique

Abonnement numérique L’abonnement à Programmez! est


(format PDF) de 49 € pour 1 an, 79 € pour 2 ans.
directement sur [Link] Abonnements et boutiques en pages 42-43

Programmez! est une publication bimestrielle de Nefer-IT.


Adresse : 57, rue de Gisors 95300 Pontoise – France. Pour nous contacter : redaction@[Link]

[Link] TABLE DES MATIÈRES 3


003_004.qxp_249 18/10/2021 18:50 Page4

ÉDITO

SAISON 24 ÉPISODE 249 (OU 253)

Le développeur est comme

© Excelsior, 17 février 2021. Tournage du Project X


Chuck Norris, il va nous
sauver (ou nous défoncer)

Q uel développeur n’a jamais rêvé d’être


le Chuck Norris du code ? Notre Chuck
est capable de maîtriser toutes les
situations : injection de codes, attaques par
L’informatique, le cloud computing, les
smartphones, le web sont de plus en plus
dénoncés par les écologistes de tout bord, sans
forcément tout comprendre de quoi on parle.
QUAND LES
NOUVEAUTÉS SONT
BONNES, FAUT EN
DoS, erreurs de compilation, débordement On entend tout et n’importe quoi sur le PROFITER !
mémoire, etc. Rien ne lui résiste. gaspillage de l’informatique en général et le % Soyons honnêtes, toute nouvelle version ne fait
des infrastructures serveurs dans la pas frémir les claviers. Même des adorateurs de
Pour faire maigrir les applications, la solution consommation électrique mondiale. Un constat Java reconnaissent que la JDK 17 apporte peu
Chuck n’est peut-être pas la plus appropriée. s’impose : oui la technologie consomme des de nouveautés majeures mais des petites
Nous vous proposons fitness et zumba tous les ressources et pèse sur les infrastructures. Le features sympathiques. Nous trouvons toujours
matins et terminé les pizzas ! Ouais, c’est dur. recyclage n’est pas assez étendu. L’obsolescence le « plus » qui fait toujours plaisir. Pour notre
Fini aussi de reprendre du code ici et là ou de est un autre problème qui est tout sauf simple à part, une des fonctions qui nous a le plus
coder rapidement sans trop respecter les règles résoudre. intéressé est la détection automatique du
d’un bon code, car ce soir vous avez soirée langage utilisé dans l’éditeur de Visual Studio
battle royale. L’obésité logicielle est un réel problème. Au Code et l’IDE nous dit s’il faut, ou non, installer
début du web, une page web pesait quelques des plug-ins pour supporter le langage. Essayer
Dans ce numéro, nous vous proposons de dizaines de Ko, aujourd’hui, c’est près 2 Mo ! c’est l'adopter.
plonger au cœur de l’éco-conception et de la En 10 ans, le poids moyen d’une page web a
notion de responsabilité écologique de été multiplié par 4. Une installation complète de Bref, cherchez le petit détail.
l’informatique et donc du développeur. Soyons Visual Studio, c’est 40 Go, XCode, 7 Go, etc.
clairs, le développeur doit jouer un rôle actif Une mise à jour de Pokémon Go ou Fortnite, François Tonic
dans l’utilisation des ressources. L’utilisateur, que 300-500 Mo, etc. Nous voyons qu’il y a là une Chuck Norris à Programmez!
nous sommes tous, doit lui aussi jouer son rôle. marge énorme d’améliorations. Ne parlons
Les constructeurs et éditeurs, les géants de la même pas des outils de bureautique.
tech, les startups, etc. ont leur rôle à jouer.

LES PROCHAINS NUMÉROS

HORS SÉRIE #5
AUTOMNE
PROGRAMMEZ!
N°250
100% Red Hat
Disponible
Disponible le 3 janvier 2022
dès le 26 novembre 2021

4 ÉDITO [Link]
005_promoHS05.qxp_249 20/10/2021 08:59 Page43

i b l e bre
p o n em
Di 6 nov
s
l e 2
dè s

Couverture

100 % Red Hat


provisoire

100 % Développeur
006.qxp_249 18/10/2021 18:52 Page6

AGENDA

novembre Les événements Programmez!


Lun. Mar. Mer. jeu. Ven. Sam. Dim.

Meetups Programmez!
1 2 3 4 5 6 7

2 novembre : spécial Clojure


Meetup

7 décembre : sujet à venir !


Programmez!
8 9 10 11 12 13 14
Où : WeWorks, 33 rue Lafayette / Paris
Métros : Notre-Dame de Lorette (l12), Le Peletier (l7)
Devoxx Belgique

A partir de 18h30
Open Source
Experience (Paris)
DevFest
DevCon
16 décembre : conférence Cybersécurité
Strasbourg

+ Secure by Design. 6 sessions + 2 keynotes.


15 16 17 18 19 20 21

Où : campus EFREI Paris


Codeurs
DevFest
A partir de 13h30
Hack in Paris (virtuel) en Seine
Lille
(virtuel)
DevOps
D-Day Informations & inscription : [Link]
(Marseille)
22 23 24 25 26 27 28
Directives de compilation
29 30 31 30 30 30 30

décembre Programmez! n°249 - Novembre - Décembre 2021


1 2 3 4 5 Directeur de la publication & rédacteur en chef : François Tonic - ftonic@[Link]
6 7 8 9 10 11 12 Contacter la rédaction : redaction@[Link]
GophorCon (en ligne) Expert en brèves : Louis Adam ([Link])
Code review : Dorra Bartaguiz
Meetup Les contributeurs techniques
Programmez! Pierre Gascoin Gatien Montreuil François Rézenthel
13 14 15 16 17 18 19 Jérémy Jeanson Loïc Mathieu Sepehr Nadmar
Baptiste Bazureau Mathieu Touchard Sébastien Colas
DevCon
François Lefebvre Pierre Lagarde Pascal Lafourcade,
Programmez : Sébastien Bernard Raphael Lemaire Maloika More
Sortie de
secure by Florian Pouchelet Benoit Petit Sallah Kokaina
Matrix 4 design Clément Sannier Vincent Frattaroli Jean-Baptiste Bron
(EFREI) Maquette : Pierre Sandré
20 21 22 23 24 25 26 Marketing – promotion des ventes : Agence BOCONSEIL - Analyse Media Etude
27 28 29 30 31 Directeur : Otto BORSCHA - oborscha@[Link]
Responsable titre : Terry MATTARD - Téléphone : 09 67 32 09 34

janvier 2022
Publicité
1 2 Nefer-IT : Tél. : 09 86 73 61 08 - ftonic@[Link]
Impression : SIB Imprimerie, France
3 4 5 6 7 8 9
Dépôt légal : A parution
10 11 12 13 14 15 16 Commission paritaire : 1225K78366
17 18 19 20 21 22 23 ISSN : 1627-0908
Abonnement
Abonnement (tarifs France) : 49 € pour 1 an, 79 € pour 2 ans.
Touraine
Etudiants : 39 €. Europe et Suisse : 55,82 € - Algérie, Maroc, Tunisie : 59,89 € -
Tech
Canada : 68,36 € - Tom : 83,65 € - Dom : 66,82 €.
(Tours)
24 25 26 27 28 29 30 Autres pays : consultez les tarifs sur [Link].
31 Pour toute question sur l’abonnement :
abonnements@[Link]
février 2022 Abonnement PDF
monde entier : 39 € pour 1 an.
1 2 3 4 5 6 Accès aux archives : 19 €.
Nefer-IT
SnowCamp (Grenoble)
57 rue de Gisors, 95300 Pontoise France
7 8 9 10 11 12 13 redaction@[Link]
14 15 16 17 18 19 20 Tél. : 09 86 73 61 08
Toute reproduction intégrale ou partielle est interdite sans accord des auteurs et du
21 22 23 24 25 26 27 directeur de la publication. © Nefer-IT / Programmez!, octobre 2021.
28 29 30 1 juil. 2 juil.
Merci à Aurélie Vache pour la liste 2021, consultable sur son GitHub : [Link]

6 AGENDA [Link]
007.qxp_249 18/10/2021 18:59 Page7

N°7+8
60 pages
NOUVEAU !

14,99 € (+frais de port) 60 pages


Commandez directement sur [Link]

Abonnement 1 an : 29 €
008.qxp_249 18/10/2021 16:05 Page8

BRÈVES
par la rédaction de

Facebook, un serveur mal configuré et c’est le grand plongeon


C’est suffisamment rare pour être noté : pendant
un peu plus de six heures lundi 4 octobre, l’en-
semble des services de Facebook était
complètement inaccessible. Ni Whatsapp, ni
Instagram, ni Facebook, rien. Une cyberattaque ?
Non : Facebook a expliqué par la suite que la
panne était due à une erreur humaine à l’occa-
sion d’une maintenance de routine. Résultat des
courses : une infrastructure hors service, des sites
hors ligne et des ingénieurs qui s’arrachent les
cheveux parce que le système d’accès au data-
center a également été affecté, les empêchant de
rentrer. Finalement tout est rentré dans l’ordre,
mais Facebook promet de revoir ses procédures
pour éviter que l’incident ne se reproduise.

Twitch, en Pénurie de semi-conducteurs : l’industrie Let’s Encrypt avait pourtant averti les
open automobile trinque utilisateurs concernés et les avait invi-
source… La pénurie de semi-conducteurs se poursuit et les fondeurs ont du mal à
tés à renouveler les certificats
contre faire face à la demande croissante de microprocesseurs et de semi-
potentiellement affectés avant la date
sa volonté conducteurs. Ils ont visiblement décidé de privilégier leurs clients
fatidique, mais ça n’a pas suffi. Le 30
Une autre histoire de serveur mal septembre, de nombreux services ont
historiques au détriment des nouveaux venus, notamment l’industrie auto-
configuré a eu des conséquences donc connu des problèmes liés à
mobile qui est devenue au cours des dernières années particulièrement
désagréables pour Twitch, la plate- leurs certificats : on peut ainsi citer
gourmande en semi-conducteurs. Résultat, plusieurs constructeurs ont été
forme de streaming live détenue par Bluecoat, Ovhcloud, Shopify, Ledger
contraints d’annoncer un ralentissement sur leurs usines de productions, à
Amazon. Dans la nuit du 6 octobre, ou encore Cloudflare parmi de nom-
l’instar de Stellantis, issu de la fusion de PSA et FCA, qui a annoncé la fer-
un internaute a publié sur 4chan un breux autres. La rançon du succès
meture de plusieurs de ses usines européennes jusqu’à la fin de l’année.
lien menant vers une archive d’envi- pour Let’s Encrypt, qui est devenu en
ron 128Go de données, l’espace de dix ans un acteur central
apparemment dérobées sur les ser- de l’écosystème des autorités de cer-
veurs de Twitch. On y retrouvait tification et par la même un SPOF
notamment le code source de plu- (Single Point of Failure, point de dé-
sieurs applications développées par faillance unique en français).
la plateforme, mais aussi des projets
internes tels que Vapor, un potentiel Braquage à l’APHP
concurrent de Steam développé par Les hôpitaux de Paris ont annoncé
les équipes de Twitch. Et pour ajou- début septembre avoir été victime
ter au drame, les attaquants ont d’un vol de données record : les don-
également publié une liste des reve- nées de test Covid appartenant à 1,4
nus perçus par les streamers les plus ment propose de labelliser des solu- Let’s Encrypt, un million de Franciliens ont été déro-
en vue de la plateforme. Rude se- tions étrangères opérées par des certificat vous manque bées dans le courant de l’été.
maine pour Twitch donc, qui acteurs français. Depuis, les an- et SPOF, tout est cassé L’attaquant a exploité une faille zero
continue ses investigations sur l’ori- nonces se multiplient : Capgemini, Quand vous devenez un acteur cen- day dans un logiciel utilisé par l’AP-
gine exacte de la fuite. Orange et Microsoft s’acoquinent tral de l’écosystème web, le moindre HP pour transférer ces données vers
sur « bleu », OvhCloud propose un dysfonctionnement peut avoir des les serveurs de l’Assurance Maladie.
Cloud de confiance : partenariat avec Whaller et Thales conséquences en cascades. C’est ce Un suspect a rapidement été arrêté
le temps presse et les avancera de son côté avec Google qui est arrivé aux utilisateurs de Let’s par les enquêteurs : il s’agit d’un étu-
acteurs s’organisent Cloud. Pour l’instant, ce ne sont que Encrypt à la fin du mois de sep- diant en informatique de 22 ans, qui
Les annonces de partenariats entre des annonces, mais les offres sont tembre : un certificat racine utilisé reconnaît être à l’origine du vol et
acteurs américains et européens se attendues avec une certaine impa- pour valider des certificats SSL fournis clame avoir voulu prouver les failles
multiplient dans le cadre du label tience, surtout du côté de par l’ONG est arrivé à expiration. de la sécurité du système de santé
Cloud de Confiance. Petit rappel l’administration et des ministères, à français. Des failles démontrées de
pour ceux qui s’y perdraient : afin de qui on a gentiment rappelé que manière un peu trop convaincante,
permettre aux entreprises de bénéfi- souscrire à des offres Office 365 hé- qui lui valent donc aujourd’hui d’at-
cier de solutions sans s’exposer aux bergées sur Azure n’était pas tendre un procès suite aux plaintes
risques juridiques liés à des lois vraiment en accord avec la politique déposées par l’AP-HP et les diffé-
comme le Cloud Act, le gouverne- de cloud de l’Etat. rentes victimes du vol de données.

8 [Link]
007.qxp_249 18/10/2021 17:38 Page9

Les partenaires 2021 de

Niveau maître Jedi

Niveau padawan

Vous voulez soutenir activement Programmez! ?


Devenir partenaires de nos dossiers en ligne et de nos événements ?

Contactez-nous dès maintenant :


ftonic@[Link]

[Link] 9
010_013.qxp_249 18/10/2021 16:08 Page10

À la rencontre de .NET 6
Après 1 an d’attente, plusieurs previews et les multiples posts des équipes dévelop-
peurs, Microsoft lance .Net 6. Pierre Gascoin (expert technique, SQLI) nous présente la
Pierre Gascoin nouvelle version. Bonne découverte. La Rédaction.
Expert technique, SQLI

Vue d’ensemble • Développement d'applications cloud-native


Lors de la planification de .NET 6 fin 2020, Microsoft s'est • - [Link] Core Minimal web API
appuyé sur 8 thèmes : chaque thème regroupant des fonc- • Évolution du SDK
tionnalités correspondant à un concept cible auquel le frame- • - Logique de workloads optionnels
work doit répondre (cf. [Link] : • Amélioration des performances du runtime
• ".NET doit être attrayant pour les nouveaux dévelop- .NET 6 sera accompagné de la nouvelle version de C# 10 de
peurs/étudiants". Visual Studio 2022. Cette dernière sera d’ailleurs requise
• ".NET propose une bonne expérience de développement pour espérer travailler avec .NET 6.
d'applications clientes".
• ".NET est reconnu comme un framework convaincant Plateformes supportées
pour créer des applications cloud natives". Pour Windows, peu de changement : .NET 6 supporte exac-
• "Entreprise et LTS". tement les mêmes versions que .NET 5, mais introduit le sup-
• "Faire grossir l'écosystème .NET à l'aide d'une qualité, port de Windows Arm64 (spécifique à Windows Desktop). En
d'une confiance renforcée et d'un support amélioré". ce qui concerne Linux, quelques modifications sont à noter :
• "Améliorer la productivité des développeurs". la disparition de Linux Mint de la liste des distributions sup-
• "Améliorer les performances en utilisant les informations portées et la montée de version pour d’autres (Alpine Linux :
d'exécution du runtime (PGO)". 3.11+ > 3.13+ et support d’ARM32, Debian : 9+ > 10+,
• "Répondre au mieux aux attentes des développeurs". support d’Arm64 pour Red Hat). Au tour de macOS qui voit
Le contenu de cette nouvelle release met l'accent sur plusieurs sa version passer de 10.13+ à la 10.14+, mais aussi (et sur-
axes. Tout d'abord, la continuité de l'unification de la platefor- tout) le support de l’architecture Arm64 (et donc la prise en
me (entrepris avec l'arrivée de .NET 5) qui vise le développe- charge des processeurs Apple Silicon). Pour finir, on note bien
ment multiplateforme mobile, bureau et web tout en minimi- sûr l’apparition des versions Android et iOS/tvOS. Plus d’in-
sant l'effort de cibler plusieurs plateformes. Autre sujet très formations ici :
important pour Microsoft, le cloud ! .NET 6 apporte de nou- [Link]
velles fonctionnalités native-cloud afin d'améliorer la valeur du
framework dans les cas d'utilisation cloud. Les développeurs ne .NET MAUI (write-one run-everywhere)
sont pas en reste : Microsoft prévoit d'améliorer la productivité Nous reviendrons dessus dans les prochains mois. Sortie pré-
du cycle de développement des applications .NET 6 ainsi vue : 1ere moitié de 2022.
qu’une meilleure prise en compte des retours utilisateurs afin
que le framework réponde au mieux à leurs attentes. Pour finir, .NET 6 & Arm64
Microsoft continue de s'ouvrir à la communauté open source : L’architecture Arm64 reste un sujet très important pour la
c'est dans cette optique qu'une attention particulière est portée firme de Redmond. De nombreux efforts ont été accomplis sur
sur l'évolution de la communauté .NET. En effet, la firme de la dernière release du framework afin d’améliorer la gestion de
Redmond vise à élargir le nombre de développeurs qui utilisent cette architecture. Dans cette nouvelle version, Microsoft conti-
.NET 6 en simplifiant/accélérant la mise en place de certains nue d’investir sur les aspects performances et fonctionnalités.
cas d’utilisation (qui pouvait rebuter certaines personnes venant Sur Windows, .NET 6 ajoute le support pour Windows Forms et
d’autres langages) et en accueillant au mieux les “nouveaux Windows Presentation Foundation (WPF) par-dessus les capa-
arrivants” autour d’un écosystème simple et accessible. Cette cités Windows Arm64 poussées en .NET 5. Il est prévu que ces
nouvelle version du framework est prévue pour novembre 2021 fonctionnalités soient redescendues sur .NET 5 par la suite.
avec un support long terme (Long Term Support) de 3 ans. Sur Mac, les puces Apple Silicon sont désormais supportées.
Ces puces ont deux modes de fonctionnements : natif et
Nouveautés majeures émulé (x64). L’émulation est implémentée par l’intermédiaire
Dans les faits, .NET 6 apporte de nombreuses nouveautés : du composant Rosetta 2. Cette émulation entraîne bien sûr
• Développement multiplateforme une répercussion sur les performances par rapport à une exé-
• - .NET MAUI (Multi-platform App UI) : décalé à 2022 cution native.
• - Application Blazor desktop .NET 6 fournira des builds Arm64 et x64 là où les anciennes
• - Amélioration du support des processeurs Arm64 versions de .NET et .NET Core ne fournissent que des builds
• Amélioration de la productivité x64 (qui se basent sur Rosetta 2 afin de tourner sur les
• - Nouvelle fonctionnalité de "Hot reload" ("rechargement à machines équipées d’Apple Silicon). A priori, le support des
chaud") puces Apple Silicon n’est pas prévu d’être porté sur .NET 5
• - Amélioration des performances du build ou les versions plus anciennes de .NET Core.

10 [Link]
010_013.qxp_249 18/10/2021 16:08 Page11

Hot reload
Un des grands piliers poussés par Microsoft est l'optimisation
du cycle de développement des applications autour de son
framework. C'est dans cette optique qu'une nouvelle fonction-
nalité appelée « Hot reload » fait son apparition (ou « rechar-
gement à chaud » pour les puristes de la langue française).
Initialement mis en place par les équipes en charge de
Xamarin pour le rechargement à chaud du XAML, il a été
décidé de généraliser ce concept à l'ensemble du framework.
Avec cette fonctionnalité, le développeur peut modifier le
code de ses applications (code managé uniquement) pen-
dant que celles-ci sont en cours d'exécution. Les modifica-
tions sont alors directement prises en compte et propagées
sur l'application déjà lancée.
Pour cela, il suffit de réaliser une modification dans le code
et de cliquer sur le nouveau bouton « Apply Code Changes »
(« appliquer les changements ») dans Visual Studio afin d’ap- Figure 1
pliquer ces modifications. • Aux déclarations top-level dans le [Link] (pas d’espace Initialisation en [Link]
Microsoft mentionne que le Hot reload est supporté pour de de nom, de classe ou de déclaration de méthode) Core WebAPI .NET 5
Source : Microsoft
nombreux types de projets tels que les applications WPF, • Au nouveau modèle d’hébergement [Link]
[Link] Core (code-behind), console, WinUI3… Il est aussi • Et à la mise en place des usings implicites
disponible sur l’ensemble des applications qui sont basées sur Ci-dessous, voici un exemple (provenant du devblogs de
les runtimes du Framework .NET et CoreCLR. Microsoft) qui compare la quantité de code à écrire afin de
Avec .NET 6, le rechargement à chaud est disponible à partir mettre en place un service avec l’initialisation de
de la ligne de commande dotnet watch. Pour rappel, l’utilitaire Swagger/OpenAPI entre les versions [Link] Core web API
dotnet watch permet de surveiller les fichiers du projet pendant en .NET 5 et [Link] Core web API en .NET 6 : Figure1
l’exécution afin de redémarrer celui-ci si une modification est
apportée à un fichier. Désormais, les modifications seront Initialisation en [Link] Core WebAPI en .NET 6
rechargées à chaud sans redémarrage : à noter que dans le
var builder = [Link](args);
cadre de modifications nécessitant obligatoirement un redé-
marrage dotnet watch devrait demander une confirmation préa-
[Link]();
lable du développeur.
[Link](c =>
{
Minimal web API & native-cloud [Link]("v1", new() { Title = "WebApplication22", Version = "v1" });
Microsoft souhaite faire du framework .NET un produit de
});
premier choix lorsqu’il s’agit de produire une application
cloud-native. Et cela passe forcément par une méthode de
var app = [Link]();
création simple et rapide de service. Jusqu’ici, la création des
services nécessitait un certain nombre de codes d’initialisa-
if ([Link]())
tion : même pour la plus simple des API. Avec .NET 6, c’est
{
désormais du passé avec l’arrivée des “minimal web API”. Le
[Link]();
concept est simple : avoir la possibilité de créer des services
[Link](c => [Link]("/swagger/v1/[Link]", "Web
rapidement avec un minimum de code. Cela est particulière-
Application22 v1"));
ment pratique pour les applications de type micro-services
}
qui exposent de nombreuses API au scope limité.
Désormais la création d’un projet web :
[Link]();
dotnet new web
[Link]();
Génère le fichier unique suivant :

var builder = [Link](args); [Link]();


var app = [Link]();
[Link]();
[Link]("/hello", () => "Hello, World!");
À noter que l’ancien modèle d’hébergement ainsi que le pat-
tern Startup continueront d’être supportés.
[Link]();

Cette nouvelle fonctionnalité permet d’éviter une initialisation Bibliothèques


fastidieuse grâce notamment : La bibliothèque de fonctionnalités du framework a été elle aussi
• À la disparition du fichier [Link] enrichie pour cette nouvelle version. En voici un florilège :

[Link] 11
010_013.qxp_249 18/10/2021 16:08 Page12

Math mum à partir d'un même sélecteur de clé. La méthode Chunck


Un nouvel ensemble API mathématique fait son apparition permet de diviser un énumérable en tableau d'une taille fixe
dans [Link] (SinCos, ReciprocalEstimate...). Ces API sont orien- passée en paramètre :
tées performance et seront accélérées par le hardware (si IEnumerable<int[]> chunks = [Link](0, 10).Chunk(size: 3);
celui-ci le supporte). Le parsing des formats numériques stan- // { {0,1,2}, {3,4,5}, {6,7,8}, {9} }
dard et des BigInteger a, quant à lui, été amélioré.
Jusqu'alors les méthodes FirstOrDefault/LastOrDefault/SingleOrDefault
JSON retournaient un default(T) si l'énumérable ne contenait aucune
.NET 6 agrémente la gestion du JSON de quelques fonction- valeur. En .NET 6, il est possible de définir cette valeur de
nalités. Une nouvelle option [Link] permet retour par défaut qui sera retourné si la source est vide. Pour
d’ignorer les références cycliques lors de la sérialisation. Une terminer sur les Enumerable, [Link] rend possible la fusion
fois activée, les références cycliques seront remplacées par le des trois énumérables en une série de tuple.
token JSON null (contrairement à [Link] qui ignore
la référence dans ce cas). Autres
Il est désormais possible de (dé)sérialiser avec un On note aussi pêle-mêle :
IAsyncEnumerable<T> et d’utiliser des notifications exposées par le • Une nouvelle implémentation du FileStream
sérialiseur (au travers de l’implémentation des interfaces • Une meilleure gestion des Date, Time et TimeZone et une
IJsonOnDeserialized, IJsonOnDeserializing, IJsonOnSerialized ou meilleure gestion des struct en tant que valeur dans les dic-
IJsonOnSerializing). Les propriétés d’un objet peuvent, dès à pré- tionnaires
sent, être ordonnées lors de la sérialisation à l’aide de l’attri- • L’amélioration de la vérification et du cast des interfaces
but [Link]. • Le support des nint/uint pour Vector<T>
La nouvelle API « writable JSON DOM feature » offre la pos- • Une nouvelle structure PriorityQueue
sibilité de modifier/requêter et transformer de grands arbres • L’apparition de nouveaux algorithmes de cryptage
de données JSON et ce de manière performante. L’API pro- (ChaCha20 et Poly1305)
pose aussi une syntaxe plus élégante et plus naturelle pour • Le support d’OpenSSL3 et d’OpenTelemetry Metrics API
définir des objets JSON. À l’aide de celle-ci, il est aussi pos- • Une nouvelle implémentation du .NET thread pool
sible d’utiliser le mot clé dynamic qui permet l’utilisation de
modèles faiblement couplés. SDK
Pour finir, .NET 6 intègre une génération de source pour le Avec l'arrivée de nouvelles plateformes supportées et l'ajout
JsonSerializer : l’idée est de générer le code source lors de la de nombreuses nouvelles fonctionnalités, on peut se poser la
compilation afin d’éviter le processus d’analyse par réflexion question de la taille du SDK qui ne cesse de grossir, notam-
qui a lieu au lancement de l’applicatif. Cela a pour effet de ment avec les nouveaux workloads mobiles.
réduire le temps de lancement, d’améliorer les débits de Microsoft y a pensé et a introduit dans .NET 6 la notion de
sérialisation, de réduire l’empreinte mémoire et de supprimer « workload optionnel ». L’idée est de passer d’un SDK mono-
l’utilisation de la réflexion au runtime. lithique vers de la composition de SDK. Il est ainsi possible
d’ajouter de façon plus granulaire les éléments supplémen-
LINQ taires que chaque développeur souhaite installer dans son
[Link] introduit, lui aussi, des améliorations. SDK. Cette fonctionnalité s’accompagne d’une ligne de com-
[Link] peut désormais prendre en paramètre un mande dédiée :
index partant de la fin de l'énumérable :
dotnet workload
[Link](1, 10).ElementAt(^2)
Cette ligne de commande permet d’installer, de désinstaller,
Dans la même veine, [Link] accepte un Range en de lister les workloads installés ou encore de les mettre à jour.
entrée : Les workloads pourront aussi être manipulés par l’intermé-
[Link](..3) pour [Link](3) diaire de l’installeur Visual Studio ou encore du gestionnaire
[Link](3.) pour [Link](3) de paquet de Linux. Le SDK devrait d'ailleurs à terme perdre
[Link](2. 7) pour [Link](7).Skip(2) du poids, car certains workloads déjà existants passeront
[Link](^3..) pour [Link](3) dans un futur proche eux aussi optionnels. La firme de
[Link](..^3) pour [Link](3) Redmond indique que cette nouvelle expérience "workloads
[Link](^7..^3) pour [Link](7).SkipLast(3) SDK optionnels" sera présente dans .NET 6 et finalisée dans
la prochaine version, .NET 7. Dans la même optique, un outil
La nouvelle méthode TryGetNonEnumeratedCount tente de récupérer permettra désormais de vérifier si une nouvelle version du
le nombre d'éléments d'un énumérable sans réaliser d’énu- SDK et des runtimes est disponible. Pour cela, rien de plus
mération. Cette méthode vérifie si la source implémente simple, il suffit d’utiliser la commande suivante :
ICollection/ICollection<T> ou tire avantage des optimisations
dotnet sdk check
internes propres à LINQ.
DistinctBy/UnionBy/IntersectBy/ExceptBy offrent de nouvelles variantes Pour chacune des plages de fonctionnalités, il indique la der-
autorisant de spécifier une égalité en utilisant un sélecteur de nière du SDK/runtime disponible et si les versions installées
clé et MinBy/MaxBy permettent de trouver le maximum/mini- sont à jour.

12 [Link]
010_013.qxp_249 18/10/2021 16:08 Page13

Passer à .NET 6 function receivesByteArray (data) {


Modification avec rupture // data est désormais un Uint8Array > plus besoin de décoder la Base64
Avant de passer sur .NET 6, il est prudent d'analyser les chan- }
gements qui créent une rupture avec les versions précédentes
et qui nécessitent des modifications dans le code. Voici une • Le LongPolling n’est plus utilisé en solution de repli si les
sélection des modifications de ruptures marquantes (brea- WebSockets ne sont pas disponibles (problèmes réseau ou
king changes) : non-compatibilité par exemple). Le client et le serveur sup-
portent désormais uniquement les WebSockets : un messa-
Réseau ge d’erreur est renvoyé dans les cas où au moins l’un des
Les classes WebRequest, WebClient et ServicePoint sont désormais deux parties ne supporte pas les WebSocket.
dépréciées.
Bibliothèque Core .NET
[Link] Core • L’équipe .NET abandonne le support des frameworks plus
• Les noms d’espace [Link] et anciens que .NET Framework 4.6.1, .NET Core 3.1 et
[Link] ont été retirés des packs de ciblage et du .NET Standard 2.0. Si un projet référence un paquet d’un
runtime [Link] Core. Les noms d’espace framework antérieur, il ne sera plus possible de mettre à
[Link] et [Link] ont, quant à eux, jour ce paquet vers une version ultérieure.
été supprimés du pack runtime d’[Link] Core, dans un but • Le comportement de la propriété [Link] sur
de réduire la taille du framework partagé d’[Link] Core. Windows (qui fournit le nombre de processeurs disponibles
• Le package permettant le support de MsgPack pour pour le processus courant) est désormais aligné avec le com-
SignalR sur [Link] Core change de version. La dépen- portement sur Linux. Auparavant celui-ci retournait le nombre
dance du package npm @microsoft/signalr-protocol-msgpack passe de processeurs logiques sans prendre en compte l’affinité des
de msgpack5 vers @msgpack/msgpack. De plus, l’interface processus ni les limitations d’utilisation des CPUs. Le code
MsgPackOptions voit ses champs disableTimestampEncoding et dépendant de cette propriété sera donc peut-être à revoir.
forceFloat64 supprimés. • La propriété [Link] est mise à jour une fois que les
• L’intergiciel de redirection HTTPS renvoie une exception opérations de ReadAsync/WriteAsync sont terminées contraire-
s’il existe plusieurs ports définis dans la configuration : ceci ment à avant où elle était mise à jour une fois les opéra-
pour éviter de possibles envois de données sensibles en tions démarrées.
HTTP lorsque HTTPS est disponible. • Microsoft informe qu’avec les surcharges ajoutées à la
• Une nouvelle surcharge de [Link] a été ajoutée à la classe [Link], il peut y avoir un impact sur du
release. Si le code de l’application appelle [Link] sans que code utilisant la réflexion si celui-ci n’est pas assez robuste.
l’intergiciel correspondant n’appelle l’intergiciel suivant (en Par exemple :
utilisant await next()) alors une erreur de compilation sera
typeof([Link])
levée. Dans ce cas, il sera nécessaire de le remplacer par
.GetMethods([Link] | [Link])
[Link]. Exemple de code nécessitant une modification :
.Where(m => [Link] == "ElementAt")
[Link](async (context, next) => .Single();
{
Pour consulter la liste exhaustive des modifications avec rup-
await SomeAsyncWork();
tures, c’est par ici : [Link]
// next n'est pas appelé...
patibility/6.0.
});

Razor Migration vers .NET 6


• Le compilateur Razor ne crée plus d’assembly séparée Voir article dédié à la migration vers .Net 6.
[Link] contenant les vues CSHTML de l’application.
Désormais, une seule assembly contenant les types de l’ap- Conclusion
plication ainsi que les vues est générée (par défaut les vues .NET 6 s'inscrit dans la lignée directe du travail d'unification
générées ont les modificateurs d’accès internal ou sealed et initié dans .NET 5. De nombreuses améliorations ont été
sont placées sous le nom d’espace AspNetCoreGenerated apportées d’un point de vue fonctionnalités, mais aussi au
Document). niveau des performances. Des efforts ont été faits afin de
• Les types relatifs au type RazorEngine sont désormais obso- rendre l’expérience autour du framework plus accessible.
lètes. Microsoft souhaite attirer de nouveaux développeurs et ainsi
étoffer la communauté .NET. Cela a pour objectif de placer
Blazor .NET comme un concurrent légitime et polyvalent ! Reste à
• Modification d’une coquille résiduelle dans le nom du voir l’impact qu’auront les apports de cette nouvelle version
champ maxWith qui passe à maxWidth. sur la communauté. L'adoption sera-t-elle au rendez-vous ?
• L’interopérabilité avec les tableaux d’octet a été revue : il .NET Conf 2021 du 9 au 11 novembre 2021 pour le lance-
n’est désormais plus nécessaire de décoder l’entrée à partir ment officiel de .NET 6 ([Link] !
de la Base64 :

[Link] 13
014_016.qxp_249 18/10/2021 16:07 Page14

Préparer une application avant


sa migration vers .net 6
Jérémy Jeanson
Ingénieur d’Études et
Migrer une application vers la dernière version de .net n’est jamais une mince affaire.
Développement Heureusement, Microsoft a documenté bon nombre de procédures de migration, et
Inetum Software breaking changes. Pour vous aider, vous pourrez aussi compter sur la communauté des
développeurs et Programmez!.
Mais avant de partir pour un long périple : évolutions de .net de ces dernières années, fragiliser votre application et creuser votre
• Votre application est-elle prête ? ou que vous n’êtes pas passé à .net core, il dette technologique. Il faut donc savoir
• Votre dette technologique actuelle vous est possible que vous mainteniez aujour- prendre le temps d’identifier les portions de
permet d’envisager sereinement une mi- d’hui des codes « datés ». Si en plus vous codes et les marquer avec l’attribut
gration ? avez gardé du code créé pour .net 1 ou 2, [Obsolete]. Quand la migration débutera, il
• Votre roadmap prévoit une migration dès vous avez certainement une dette technolo- sera alors plus facile de les remplacer.
la publication de .net 6 ? gique importante.
N’ayez pas peur de dire non. Vous ne serez Dans les applications .net on peut trouver : Moderniser
pas seul dans ce cas. Cet article va vous des web services Asmx, du Remoting, WCF, son architecture
aider à préparer votre application, et vous Workflow Foundation, Authentication basic, En voulant solder sa dette technologique, il
assurez que la migration vers .net 6 ne sera BinaryFormatter, Code Access Security, peut sembler plus aisé de réécrire certains
pas un cauchemar. AppDomain, SecureString, Edmx pour composants. Pourquoi ne pas en profiter
Entity Framework, Silverlight… pour utiliser .net 6 dès à présent ?
Anticiper les API Ces éléments novateurs à leurs sorties sont Dans le cas où votre application est consti-
dépréciées aujourd’hui très compliqués et coûteux à tuée de plusieurs tiers distincts, cela est tout
Dès qu’une nouvelle version de .net pointe maintenir. Même s’il peut sembler plus faci- à fait possible.
le bout de son nez, j’ai l’habitude d’aller sur le de rester sous .net 4.8, il ne peut s’agir Exemple : Le frontend continue d’utiliser
[Link] pour consulter la liste que d’une situation temporaire. Plus cette votre version actuelle de .net alors que votre
des breaking changes. Je ne peux que vous situation durera et plus votre dette techno- backend exploite .net 6.
encourager à en faire de même afin d’iden- logique augmentera. Dans le contexte d’une application monoli-
tifier les classes et méthodes pour lesquelles Plutôt que de subir, il faut donc commencer thique, vous pourriez être tenté d’utiliser
il vous faudra trouver une alternative. à chercher des solutions de notre temps : .net standard. Même si l’idée peut sembler
Je vous conseille de rechercher la page des Web API, Dapper, Open Auth, Entity séduisante, elle n’est pas adaptée à toutes
nouveautés. Les API dépréciées y sont tou- Framework via code First (le tooling d’EF les situations. En fonction de la version de
jours indiquées. peut aussi permettre de créer un .net standard exploitable avec votre version
Mais avant cela, il existe une solution plus DataContext à partir d’une base de don- actuelle de .net vous ne disposez pas des
rapide : il suffit de consulter la liste des war- nées existante). mêmes API. Un projet .net standard est
nings (vous savez : la liste que certains Exemple : Si votre application expose un donc soumis à des contraintes qui peuvent
masquent après une première compilation). service SOAP. Celui-ci sera impossible à mi- compliquer les développements. Cette ap-
Parmi les warnings se cachent des mes- grer tel qu’il est aujourd’hui. Plutôt que de proche peut être très chronophage (surtout
sages liés aux API obsolètes. Bien souvent, chercher une nouvelle solution pour SOAP, il avec les versions de 1.0 à 1.6). Il est forte-
les classes et méthodes sont marquées est préférable d’exposer dès à présent une ment recommandé de vérifier vos
comme étant obsolètes par Microsoft pour version REST/XML ou JSON. Cette version dépendances avant de vous lancer.
anticiper des changements profonds à venir. deviendra la version recommandée. Si des
Ceux-ci n’auront peut-être pas lieu lors de tiers doivent utiliser vos services, il convient Identifier et sécuriser
la prochaine itération de .net. Mais il ne de les prévenir que la version SOAP est ob- les chemins critiques
faut pas se leurrer, ils auront lieu un jour. solète et ne sera plus supportée après votre Aujourd’hui nos applications sont de plus
Si vous prenez l’habitude de traiter les élé- migration. en plus complexes et évoluées. Migrer
ments obsolètes comme s’il s’agissait Ne vous leurrez pas, si vous utilisez au- celles-ci ne se limite donc plus simplement
d’erreurs, vous ne devriez pas avoir trop de jourd’hui .net core 1 votre situation n’est à effectuer une mise à jour, recompiler puis
difficultés lors de la migration. pas forcément plus enviable. Pour pallier exécuter.
aux manques de .Net core 1, nombre de Plus une application à de fonctionnalités et
Solder développeurs ont été dans l’obligation de plus il y aura d’éléments à vérifier. Avec le
sa dette technologique réimplémenter des fonctionnalités du .net temps, il n’est pas rare que seuls quelques
L’apparition et la disparition d’API ont sou- Framework. Certains se sont retrouvés à uti- développeurs aient connaissance de l’en-
vent pour vocation de maintenir .net dans liser des librairies du .net Framework dans semble des scénarios possibles. Même
l’air du temps. Si vous n’avez pas suivi les leurs applications .net core. Ce code peut quand on travaille seul, il arrive que l’on ou-

14 [Link]
014_016.qxp_249 18/10/2021 16:07 Page15

blie l’existence de fonctionnalités dévelop- lée avant la méthode Close(). Ce problè- Gestion des dépendances
pées quelques années auparavant. me était indétectable si je n’avais pas eu La gestion des dépendances est une étape
Pour ne rien oublier, l’idéal serait d’avoir un un test qui vérifiait le contenu du fichier critique de la migration. Il existe deux ma-
cahier de recettes couvrant la totalité des généré. nières de référencer des librairies externes :
cas. • Lors d’une migration vers ASP .net core 3, • L’approche manuelle, qui consiste à ajou-
Malheureusement, ce type de document il est devenu impossible de manipuler les ter une référence en allant chercher une
évolue souvent moins vite que nos applica- Request et Response dans un DLL sur son PC.
tions et rares sont les développeurs qui y Middlerware sans utiliser leurs méthodes • L’approche automatisée via un gestion-
prêtent attention. Ce qui se traduit souvent asynchrones. Les méthodes synchrones naire de paquets comme NuGet.
par de nombreux aller-retour entre les existant toujours, la compilation se pro- La première approche est celle qui présente
équipes de développement et les testeurs. duisait sans problème. Les tests unitaires le plus d’inconvénients :
Ceux-ci conduisent inévitablement à une d’intégration étaient la seule solution • Les DLL doivent être déployées sur le PC
perte de temps et d’énergie. Avec le temps, pour anticiper les problèmes et leur trou- de développement (via le repository,
ce phénomène ne fera que s’accentuer et ver une solution. XCopy, ou MSI)
amènera vos équipes à résister face au • La mise à jour d’une même DLL pour plu-
changement. La migration pouvant impli- Réduire la voilure sieurs projets est plus laborieuse.
quer de grands changements, il faut trouver Parmi les nombreuses fonctionnalités de nos • Les dépendances indirectes ne sont pas
une réponse au problème dès aujourd’hui. applications, il n’est pas rare que certaines facilement identifiables.
Par chance, il existe une solution spéciale- ne soient plus utilisées. Il n’est pas rare non • Les dépendances indirectes ne sont pas
ment adaptée pour les développeurs. Il plus que l’on garde du code mort (des mé- référencées automatiquement.
s’agit des tests unitaires. Mais là encore, il thodes, ou classes qui ne servent plus). Ces • Il n’est pas possible de référencer les va-
est rare qu’une application soit intégrale- situations peuvent sembler bénignes. Mais riantes x86 et x64 d’une même DLL dans
ment couverte par des tests unitaires. que se passera-t-il si après le passage à .net un projet.
Pour éviter des drames lors de la migration, 6 on découvre qu’elles produisent une er- A contrario, NuGet :
il faut trouver le moyen d’optimiser l’usage reur de compilation. Faudra-t-il les • Télécharge, référence automatiquement
du cahier de recette et des tests unitaires corriger ou les abandonner ? Que se passe- les DLL, et leurs références indirectes.
codés. ra-t-il si l’on découvre au dernier moment • Permet la mise à jour en un clic de tous
Présenter de la sorte, le chantier peut sem- que ces codes dépendent de librairies qui ne les projets d’une solution.
bler colossal. Si vous partez de zéro, il ne supportent pas .net 6 ? • Permet de gérer facilement des profils de
faut pas s’inquiéter. L’approche la plus effi- Pour ne pas avoir à prendre des décisions à compilation x86, x64 ou autres.
cace consiste à procéder par itérations. la hâte, et ne pas perdre de temps, il De plus, Nuget a un grand intérêt dans le
Chaque itération consistant en : convient d’identifier très vite ces fonctionna- contexte d’une migration : il permet de
• L’identification d'un petit nombre de fonc- lités et codes morts. S’ils ne sont plus utiles, connaître les dépendances indirectes d’un
tionnalités importantes pour les autant les supprimer tout de suite. paquet en fonction de la version de .net ci-
utilisateurs. Bien évidemment, je ne vous encourage pas blée. La liste de dépendances d’un paquet
• La documentation des scénarios d’usages à supprimer votre code de manière barbare. est consultable via l’interface de gestion
de ces fonctionnalités pour le cahier de L’idée ici est de vous faire prendre conscien- NuGet de Visual Studio.
recette. ce qu’il faut savoir réduire la voilure de son Même si l’interface de Visual Studio est
• Le codage de tests unitaires relatifs à ces application plutôt que de subir. Parmi ces agréable, je ne la trouve pas adaptée dans
fonctionnalités. fonctionnalités, il est aussi probable que le cadre d’une migration. Je vous conseille
Progressivement, vos applications seront certaines n’auront plus de raison d’être plutôt d’aller sur le site [Link]
davantage couvertes par des tests unitaires. après la migration. Si la suppression ne et d’y rechercher les librairies que vous utili-
Lors des publications pour les testeurs, peut pas avoir lieu actuellement, il faut pen- sez.
ceux-ci vous remontrent moins de bugs. Ce ser à parquer le code concerné avec Exemple : Pour Open-XML-SDK Figure 1
que l’on appelle couramment le chemin cri- l'attribut [Obsolete]. Le grand intérêt du site Nuget par rapport à
tique finira par être entièrement sécurisé. Exemple : je maintiens seul depuis 2011 Visual Studio est qu’il permet de consulter
Avant même d’avoir commencé la migra- une application qui a débuté sur Windows la page du paquet d’une dépendance indi-
tion, votre application aura gagné en en WPF, puis Windows Phone 7 en recte pour valider ses propres dépendances.
qualité. Quand le projet de migration débu- SilverLight, et Windows 8, pour finir sur De la sorte, il est possible de vérifier l’en-
tera, vous pourrez rapidement vérifier son Windows 10 avec UWP. Dans le temps, j’ai semble des dépendances directes ou
impact et éviter tout effet de bord avant été obligé de supprimer des fonctionnali- indirectes, et de valider leur compatibilité
même de publier vos premières versions en tés telles que le support de l’API de avec .net 6. Dans le cas contraire, il faudra
tests. recherche de Windows 8. Pour supporter rechercher une librairie de substitution com-
Par le passé, cette démarche m’a permis Windows 11, il est évident que je vais me sé- patible.
d’éviter de nombreux problèmes. Voici parer du code dédié à la gestion des tuiles En lisant ces quelques lignes, je pense que
quelques cas concrets : dynamiques. vous aurez compris que l’adoption de
• Lors du passage de .net 1.0 à 1.1 j’ai été NuGet est indispensable. Continuer à réfé-
confronté à des erreurs du fait de Stream rencer manuellement ses dépendances
dont la méthode Flush() n’était pas appe- n’est pas raisonnable et s’avérera extrême-

[Link] 15
014_016.qxp_249 18/10/2021 16:07 Page16

me : l’identification des dépendances di- contre l’usage abusif d’objets intrinsèques


rectes et indirectes. Ceci facilitera et autres éléments statiques (singletons, et
grandement la recherche de versions com- variables statiques). Ceux-ci rendent sou-
patibles avec .net 6 et la mise à jour. Mais vent la découverte des dépendances
contrairement à NuGet et sa gestion via difficiles. Depuis .net core, nombre d’entre
PackageReference, il n’est pas exclu que eux n’existent plus (exemple :
vous ayez à effectuer quelques opérations [Link]). Il est donc très impor-
manuelles pour que Visual Studio prenne tant de considérer l’injection pour la gestion
en charge vos dépendances. du cycle de vie de ses objets dès aujour-
d’hui, plutôt que de reposer sur des
Note : Il est fréquent d’enregistrer manuellement variables statiques.
les DLL des librairies que l’on achète auprès de four-
nisseurs tel que DevExpress, Infragistics, SyncFusion,
etc. … Historiquement, il n'y avait pas d’autres solu- Revoir sa configuration
tions. Aujourd’hui, nombre de fournisseurs mettent à Si vous utilisez toujours le .net Framework, il
disposition des paquets pour NuGet ainsi que des
serveurs Nuget pour faciliter les mises à jour. Si vous est fort probable que vous utilisiez des fi-
ne le saviez pas, je vous encourage vivement à chiers de configuration XML ([Link] ou
consulter la documentation de votre fournisseur afin [Link]) pour définir la configuration de
de migrer vos références vers Nuget avant de passer
à .net 6. vos applications. Depuis .net core, ceux-ci
ont disparu au profit de fichiers *.json plus
Lors de l’installation, Infragistics a ajouté un souples à manipuler.
répertoire pour permettre aux développeurs Même si rien ne vous oblige vous pouvez
Figure 1 ment contraignant dans le futur (sans d’utiliser Nuget plus facilement. déjà utiliser des fichiers de configuration
compter le nombre d’erreurs humaines qui *.json. Le .net Framework contient tout ce
peuvent en découler). Les bienfaits qu’il faut pour charger ce type de fichiers, et
Si vous n’utilisez pas encore NuGet, com- de l’injection de dépen- injecter des paramètres dans vos applica-
mencez dès à présent. Ceci facilitera dances tions. Cerise sur le gâteau, vous pouvez dès
grandement votre migration. Le pattern d’injection de dépendance est à présent profiter de cette approche pour
NuGet a en plus l’avantage de fournir des l'alliée incontournable d’une migration utiliser des classes fortement typées.
informations chiffrées sur la popularité réussie. Si vous ne l’avez jamais utilisé jus- Fini les conversions effectuées manuelle-
d’une librairie et sur le fait qu’elle soit acti- qu’ici, il est temps de changer d’habitude. ment, les tests sur le ConfigurationManager
vement maintenue ou non. Avant d’installer Dans le cadre d’une application qui doit mi- et les questions existentielles sur les noms
un paquet, prenez le temps de vérifier le grer vers .net 6, l’intérêt est double : des paramètres ou leurs types.
nombre de téléchargements ainsi que la • Le fait de découpler les différents élé- Il est aussi très important de noter que la
fréquence à laquelle celui-ci est mis à jour. ments de l’application rend facilement notion de « section custom » disparaît avec
Un paquet qui n’a pas eu de mise à jour de- remplaçables ceux-ci. L’objectif est de les fichiers XML. Après votre passage à .net 6,
puis de nombreuses années est à éviter. pouvoir disposer de classes qui n’ont pas la configuration se fera exclusivement via
besoin de savoir comment sont instan- votre code. Si vous utilisez déjà l’injection
Pour les irréductibles des ciées les classes dont elles dépendent. de dépendance, il peut être intéressant de
références manuelles Dans le cas d’une migration, cela permet l’utiliser pour injecter les classes qui rempla-
Si vous n’avez pas le choix et devez conti- de limiter les modifications à opérer du ceront les sections.
nuer à référencer manuellement vos fait d’un changement d’API (ou dans le Si vous ne souhaitez pas vous passer tout de
dépendances, il y a cependant une ap- cas où celui-ci disparaîtrait). suite de vos fichiers de configuration XML, il
proche qui peut vous permettre de préparer • Dans le cas d’une application ASP .net, il faut cependant prendre le temps de les exa-
votre migration tout en limitant les risques est impossible de ne pas l’utiliser. miner avant la migration. Ceux-ci peuvent
de rencontrer un problème. L’injection est à la base de .net MVC de- cacher des dépendances à des fonctionnalités
Celle-ci réside dans la procédure suivante : puis .net core. L’utiliser dès aujourd’hui du .net Framework (sécurité, authentifica-
• Stocker toutes vos dépendances directes permet donc d’être paré pour ASP .net 6. tion, log…). Ils peuvent aussi faire référence
et indirectes dans un répertoire unique. Si vous utilisez déjà .net core, je vous à des dépendances tiers qui seraient dé-
Ce répertoire doit être géré par votre ges- conseille vivement d’utiliser le Microsoft. ployées dans le Global Assembly Cache
tionnaire de code source (Git, TFVC, [Link] pour vos applications (GAC) ou qui ne seraient pas référencées
Subversion…). desktop et mobiles. Celui-ci offre de très dans votre liste de package NuGet.
• Dans la liste des références de chaque bonnes performances. Il a aussi l’avantage Découvrir celles-ci au dernier moment pour-
projet, il ne faut pas que l’option « utiliser de partager les mêmes interfaces que l’hôte rait être catastrophique et ruiner votre
cette version spécifique » soit cochée. d’injection d’ASP .net. planning. J’ai déjà raté cette étape lors de
Lors de la migration, les DLL présentes dans Cerise sur le gâteau, cette librairie peut être l’étude « un peu trop rapide » d’une appli-
ce répertoire pourront être remplacées par utilisée avec .net Framework 4.6.1. L’utiliser cation à migrer. Je m’en suis mordu les
leurs versions .net 6. dès à présent dans tous vos développe- doigts.
Gardez tout de même à l’esprit que cette ments vous fera gagner un temps d’avance.
solution ne résout qu’une partie du problè- Attention : L’injection sert aussi à lutter

16 [Link]
017_020.qxp_249 20/10/2021 18:52 Page17

Les nouveautés de C# 10
Depuis la version .NET Core 3.1 en 2019, Microsoft a planifié de mettre à jour la ver-
sion de son framework .NET chaque mois de novembre. 2020 a marqué la sortie de
.NET 5, ainsi que de son langage phare C# en version 9. Cette année, Microsoft conti- Baptiste Bazureau
Expert technique
nue sur sa lancée et annonce la sortie de .NET 6 accompagnée de C# 10 dont nous SQLI
vous proposons de décortiquer les nouveautés et améliorations.
Nous vous précisons qu’au moment où nous rédigeons ces public Point(int x, int y)
lignes, C# 10 n’est pas encore sorti dans sa version définitive. {
Certaines fonctionnalités pourraient encore évoluer, voire ne X = x;
pas être embarquées. Y = y;
}
Les structures d’enregistrement François Lefebvre
En 2020, C# 9 a introduit le mot clé record qui permet de Expert technique
public int X { get; init; }
définir un type référence fournissant des fonctionnalités inté- SQLI
grées pour l’encapsulation des données. Il était jusqu’ici public int Y { get; init; }
possible de l’affecter uniquement à des classes, ce que C# }
10 étend désormais aux structures. Les structures d’enregis-
trement sont de type valeur tout comme le sont les structures Ensuite, nous remarquons la présence du mot clé struct qui
classiques. Cela signifie qu’elles répondent à des règles com- spécifie qu’il s’agit bien d’une structure d’enregistrement, et
munes. À noter que C# 10 va lever certaines restrictions sur non une classe d’enregistrement. En C# 9 les classes d’enre-
les structures. Il rend possible la création d’un constructeur gistrement étaient déclarées sans le mot clé class:
sans paramètre, ainsi que l’initialisation des propriétés dès
public record Person(string FirstName, string LastName);
leur déclaration, comme le montre l’exemple suivant :
Cela reste possible, mais C# 10 a rendu faisable l’ajout
public struct Point
optionnel du mot clé class afin d’éviter les confusions.
{
public Point() // constructeur sans paramètre public record class Person(string FirstName, string LastName);
{
Les expressions with
X = 5;
Tout comme avec les classes d’enregistrement, les structures
}
d’enregistrement peuvent être instanciées à l’aide des
expressions with. Celles-ci permettent de créer une copie
public int X { get; set; }
d’une structure d’enregistrement tout en lui spécifiant une ou
plusieurs données différentes. Prenons l’exemple suivant :
public int Y { get; set; } = 3; // initialisation à la déclaration
} var firstPoint = new Point(1, 2);
var secondPoint = firstPoint with { Y = 3 };
La déclaration d’une structure d’enregistrement
Il devient dès lors possible de déclarer une structure d’enre-
[Link](secondPoint);
gistrement sur une seule ligne :
// sortie : Point { X = 1, Y = 3 }
public readonly record struct Point(int X, int Y);
La propriété X de secondPoint est issue de l’instance de
Notons plusieurs points dans cette déclaration : tout d’abord firstPoint tandis que la propriété Y est définie grâce à l’utilisa-
la présence du mot clé readonly qui n’est pas disponible pour tion de l’expression with.
les classes d’enregistrement. Son ajout optionnel permet de
spécifier que les propriétés de la structure d’enregistrement La comparaison d’égalité
sont immuables. En effet, elles ne le sont pas par défaut, ce L’égalité entre deux structures d’enregistrement s’effectue en
qui constitue l’une des différences majeures avec les classes fonction de leurs valeurs. Nous pouvons donc utiliser le mot clé
d’enregistrement. De plus, les différents paramètres déclarés Equals afin de les comparer comme nous le ferions pour les struc-
seront convertis en propriétés par le compilateur, et le tures classiques, mais également les opérateurs == et != qui
constructeur ainsi généré les renseignera à l’initialisation sont utilisables uniquement pour les structures d’enregistrement :
d’une nouvelle instance. Cette syntaxe est donc équivalente
var firstPoint = new Point(1, 2);
à celle ci-dessous, qui utilise le mot clé init introduit en C# 9
var secondPoint = new Point(1, 2);
rendant les propriétés immuables :

public record struct Point [Link]([Link](secondPoint));


{ // sortie : true

[Link] 17
017_020.qxp_249 20/10/2021 18:52 Page18

[Link](firstPoint == secondPoint); public void Main()


// sortie : true {
Person person = new("John", "Doe");
Afficher les membres avec la méthode ToString
[Link](person);
C# 9 a introduit la possibilité d’afficher facilement les
// sortie: John
membres d’une classe d’enregistrement grâce à la substitu-
tion automatique de la méthode ToString. Cette fonctionnali-
Employee employee = new("John", "Doe", 1);
té a également été introduite avec C# 10 pour les structures
[Link](employee);
d’enregistrement :
// sortie: Employee { FirstName = John, LastName = Doe, Grade = 1 }
public readonly struct record Point(int X, int Y); }
public void Main()
C# 10 résout cela en permettant de sceller la méthode
{
ToString d’une classe mère grâce au mot clé sealed, afin de
Point point = new (1, 2);
prévenir la substitution automatique de la méthode ToString
[Link](point);
pour les classes qui en héritent et ne pas avoir à modifier leur
// sortie: Person { X = 1, Y = 2 }
implémentation. Voici le résultat obtenu avec l’utilisation du
}
mot clé sealed :
La valeur de sortie est obtenue grâce à la substitution automa- Code complet sur [Link] & github
tique de la méthode ToString du type Point. La méthode itère
sur chaque membre de la structure et indique sa valeur grâce Assignation et déclaration dans une
à une méthode interne nommée PrintMembers et implémentée même déconstruction
automatiquement. Nous verrons dans la section suivante, un Déconstruire un objet en C# permet d’assigner facilement les membres
autre ajout de C# 10 qui concerne la possibilité de sceller cette d’un objet à des variables. Pour cela, il faut tout d’abord implémenter
méthode ToString pour le cas des classes d’enregistrement. une ou plusieurs méthodes Deconstruct dans une classe :

public class Person


Les types d’enregistrements peuvent {
sceller ToString public string FirstName { get; set; }
Les classes d’enregistrement supportent l’héritage, ce qui est
public string LastName { get; set; }
pris en compte par la substitution de la méthode ToString.
Dans ce cas, la méthode itère sur l’ensemble des membres
public void Deconstruct(out string firstName, out string lastName)
de la classe mère, puis de la classe fille :
{
public record Person(string FirstName, string LastName); firstName = FirstName;
public record Employee(string FirstName, string LastName, int Grade) lastName = LastName;
: Person(FirstName, LastName); }
}
public void Main()
Sans C# 10, il faut choisir exclusivement entre deux syntaxes
{
différentes pour déconstruire l’objet. La première syntaxe
Employee employee = new("John", "Doe", 1);
consiste à initialiser les variables puis déconstruire l’objet sur
[Link](employee);
une seule et même ligne de code, ce qui a l’avantage d’être
// sortie: Employee { FirstName = John, LastName = Doe, Grade = 1 }
simple et concis :
}
(string firstName, string LastName) = person;
Considérons désormais que dans l’exemple précédent, nous
souhaitions uniquement afficher la propriété FirstName des La seconde syntaxe permet d’instancier au préalable les
objets de type Person et des classes qui en héritent. Pour cela, variables assignées lors de la déconstruction. Néanmoins
nous allons modifier l’implémentation de la méthode cette seconde syntaxe est plus longue que la première :
ToString de la classe Person grâce au mot clé override.
string firstName = "Jane", LastName;
Cependant, cela n’aura pas d’impact sur les variables de type
Employee. En effet, la méthode ToString de la classe fille sera
(firstName, LastName) = person;
tout de même automatiquement substituée et ne prendra pas
en compte la modification apportée : Il n’était jusqu’ici pas possible de mélanger ces deux syn-
taxes. Cela signifie que si nous avions besoin d’avoir la main
public record Person(string FirstName, string LastName)
sur la déclaration d’une seule des variables dédiées à la
{
déconstruction d’une classe, nous étions tout de même obli-
public override string ToString() => FirstName;
gés de déclarer chacune d’entre elles. C# 10 permet doré-
}
navant de mixer ces deux syntaxes en fonction des besoins :

public record Employee(string FirstName, string LastName, int Grade) string firstName = "Jane";
: Person(FirstName, LastName);
(firstName, string LastName) = person;

18 [Link]
017_020.qxp_249 20/10/2021 18:52 Page19

class Employee { }
Les directives global using
}
Dans un projet C#, il est fréquent d’utiliser les mêmes types
issus des mêmes espaces de noms, ce qui provoque la multi-
namespace [Link]
plication de directives using similaires à travers les fichiers.
{
Pour éviter cette répétition, C# 10 permet de rendre dispo-
class Bill { }
nible des namespaces à l’ensemble des fichiers de code d’un
}
projet. Pour cela, il suffit d’ajouter le mot clé global précé-
dant une instruction using et l’espace de noms devient dispo- Dans la plupart des projets, les fichiers de code ne contiennent
nible globalement. qu’un seul namespace. Une nouvelle syntaxe introduite avec
Par exemple, si l’on crée une application web à partir du C# 10 permet de déclarer un espace de nom en haut de fichier,
modèle [Link] Core avec authentification, le et dont la portée s’étend à l’ensemble du fichier. Pour cela il
HomeController généré ressemble à cela, sachant que le suffit d’utiliser le mot clé namespace sans les accolades :
contenu de la classe est omis :
namespace [Link];
using [Link];
Cette syntaxe améliore la lisibilité horizontale du code en
using [Link];
réduisant l’indentation d’un niveau.
using [Link];
using [Link];
Patterns de propriétés étendus
Historiquement, le mot clé “is” était un opérateur pour tester
namespace [Link];
uniquement le type et convertir une donnée. C# 7 a introduit
[Authorize]
le pattern matching – se traduisant par « critères spéciaux » –
public class HomeController : Controller {}
qui permet de tester si une donnée correspond à un pattern.
// Le contenu de la classe est omis
Le pattern matching a systématiquement continué à être
Il y a de fortes chances pour que les autres contrôleurs du pro- amélioré depuis, et cette version ne déroge pas à la règle.
jet utilisent aussi les namespaces [Link] Jusqu’alors, pour faire un test de correspondance envers des
et [Link]. propriétés imbriquées, il nous fallait utiliser un modèle avec
Avec C# 10, nous pouvons créer un fichier [Link] des objets imbriqués. Prenons l’exemple suivant : une voiture
à la racine du projet avec le code suivant : est composée d’une roue, et la roue possède une taille. Nous
devons effectuer une action spéciale si l’on traite une voiture
global using [Link];
avec une roue de 17 pouces. Voici l’utilisation d’un pattern
global using [Link];
matching en C# 9 :
Nous pouvons ainsi retirer ces usings dans le fichier
record Car(Wheel Wheel);
[Link], qui devient donc :
record Wheel(int Size);
using [Link]; if (vehicule is Car { Wheel: { Size: 17 } })
using [Link]; DoSomething();

Avec C# 10, la syntaxe pour accéder à une propriété dans un


namespace [Link];
pattern a été simplifiée. Nous pouvons désormais référencer
[Authorize]
directement une propriété imbriquée.
public class HomeController : Controller {}
// Le contenu de la classe est omis if (vehicule is Car { [Link]: 17 })
DoSomething();
S’il est possible d’utiliser des global using à travers différents
fichiers, peu importe l’endroit dans la structure du projet, la La concaténation de constantes avec
portée restera globale à l’ensemble du projet. Il est néanmoins des chaînes interpolées
préférable de regrouper tous les global using dans un même Avec C# 9, s’il est possible de concaténer des constantes
fichier pour en faciliter la lecture. [Link] n’est pas un pour former une autre constante en utilisant l’opérateur +. A
nom obligatoire, mais la communauté semble avoir adopté en contrario, le compilateur ne permet pas d’utiliser une expres-
partie cette convention. Il est aussi fréquent de voir ce fichier sion d’interpolation pour effectuer cette opération.
se nommer [Link] ou plus rarement [Link]. À noter que
const string firstname = "toto";
Visual Studio indiquera si une instruction devient facultative si
const string helloPlus = "Hello " + firstname;
l’espace de nom est déjà importé via un global using.

const string hello = $"hello {firstname}";


La déclaration d’espace de nom de // error CS0133: The expression being assigned to 'hello' must be constant
portée de fichier // Cette erreur intervient, car une chaîne interpolée ne peut être assignée à une
En C#, il est possible d’utiliser plusieurs namespaces dans un
constante
même fichier :

namespace [Link] static readonly string helloStatic = $"Hello {firstname}";


{ // cette syntaxe est valide dans une variable – ici une propriété statique

[Link] 19
017_020.qxp_249 20/10/2021 18:52 Page20

C# 10 nous permet aujourd’hui d’assembler des chaînes de Quel avenir pour C# ?


caractères via une chaîne interpolée et de stocker le résultat Si la fonctionnalité de vérification de paramètres null, qui
dans une constante. La valeur est définie à l’exécution, et était l’une des plus attendues par la communauté, a pu être
non pas à la compilation. Mais il n’y a pas d’inquiétude à évoquée comme faisant partie de C# 10 par de nombreux
avoir pour l’influence de la culture, car seules des concaténa- articles, elle est pour le moment toujours en cours de déve-
tions de chaînes sont autorisées. loppement. Elle est actuellement identifiée comme une fonc-
tionnalité faisant partie de la version suivante (voir C# vNext)
const string hello = $"hello {firstname}"; // Valide avec C# 10
et non pas dans C# 10. La prise en charge par le compila-
teur de cette fonctionnalité étant presque terminée, l’usage
const float ratioMilesInKilometers = 1.60934f;
ne devrait plus évoluer. C’est pourquoi nous nous permettons
const string mile = $"One mile is {ratioMilesInKilometers} km";
de vous la présenter dès maintenant :
// error CS0133: The expression being assigned to '[Link]' must
be constant // Vérification de la nullité du paramètre en C# 9
void Foo(string bar)
Nous obtenons ainsi un code plus lisible. L’autre avantage est
{
de pouvoir utiliser l’interpolation de string à des emplace-
if (bar == null) throw new ArgumentNullException(nameof(bar));
ments où seules des constantes sont acceptées, comme dans
}
un attribut.

const string PRODUCT_VERSION = "Hirsute Hippo"; // Equivalent avec la fonctionnalité de vérification de la nullité
void Foo(string bar!!) { }
[Osolete($"This method will be removed after version {PRODUCT_VERSION}")]
L’opérateur !! permettra de s’assurer que le paramètre de la
void Foo() { }
fonction est non null. Attention toutefois à ne pas confondre
Les améliorations cette fonctionnalité avec la notion de types références nul-
des fonctions lambda lables introduite avec C# 8. Pour rester concis, les types réfé-
C# 10 apporte quelques améliorations autour des expres- rences nullables donnent des avertissements à la compilation
sions lambda. L’inférence de type a été améliorée. Il n’est sur des déréférencements qui pourraient potentiellement pro-
dorénavant plus nécessaire de préciser le type d’une variable voquer des NullRerefenceException. Ici l’opérateur !! n’a
contenant une fonction lambda. Nous pouvons simplement aucune incidence à la compilation, mais uniquement à l’exé-
la déclarer avec le mot clé var. cution. Il simplifie la vérification de la nullité des paramètres,
ce qui allège le code et facilite le travail des adeptes de la
var returnOne = () => 1;
programmation défensive.
Jusqu’à C# 9, cela aurait produit une erreur de compilation La fonctionnalité de propriétés obligatoires – propriétés pré-
(CS0815: Cannot assign 'expression' to an implicitly typed fixées par le mot clé required – a également pu être annon-
local). Pour faciliter le travail du compilateur ou modifier le cée comme faisant partie des nouveautés de C#. Or, il n’en
type de retour d’une expression lambda, celui-ci peut être est rien. Cette fonctionnalité est toujours envisagée, mais il
précisé. Pour se faire, il faut préfixer la fonction lambda par n’y a pas encore de spécifications abouties sur les usages de
le type de retour souhaité. cette fonctionnalité.
Une autre fonctionnalité évoquée, et finalement absente est
Func<int, float> incrementAsFloat = float (int x) => x + 1;
le mot clé field pour accéder au champ privé d’une propriété
Dans l’exemple précédent, la fonction lambda prend en sans avoir besoin de le déclarer :
paramètre un entier qu’elle additionne avec la valeur 1 qui
public Datetime Birthday { get; init => field = [Link](); }
est aussi un entier. Le résultat de la fonction lambda est donc
lui-même un entier. Mais comme le type de retour est précisé, C# 10 nous apporte un lot de nouveautés intéressantes. Il
le résultat du calcul est retourné après avoir été converti en continue en effet d’évoluer en intégrant de nouvelles fonc-
float. Il faut également noter que si la fonction lambda n’a tionnalités utiles comme l’extension des types d’enregistre-
qu’un seul paramètre, il est quand même obligatoire d’utili- ments aux structures tout en s’efforçant d’améliorer conti-
ser les parenthèses. nuellement sa syntaxe grâce notamment à la déclaration
Les attributs peuvent désormais être ajoutés aux fonctions d’espace de nom de portée de fichier. Cela s’intègre dans la
lambda et à leurs paramètres. Comme précédemment, l’uti- continuité des mises à jour .NET récentes qui diminuent la
lisation d’attributs imposera l’utilisation des parenthèses pour quantité de code nécessaire et améliorent sa lisibilité.
les paramètres. Sans cela, il y aurait une confusion pour D’autres nouveautés n’ont pas été présentées dans cet article
savoir si l’attribut s’applique sur la fonction ou sur un para- - comme l’amélioration de l’analyse de nullabilité et du déter-
mètre. L’exemple suivant illustre la création d’une fonction minisme des assignations, la directive #line, ou les améliora-
lambda avec l’attribut CustomDiagnostic appliqué au niveau tions de générations de code - car nous trouvions qu’elles
de la fonction, et l’attribut CustomFormatter appliqué au apportent trop peu de changements ou couvrent des cas
paramètre msg. d’utilisations trop spécifiques.
Microsoft continue donc d’enrichir son langage d’année en
var lambda = [CustomDiagnostic] ([CustomFormatter]string msg) => Console.
année et nous sommes enthousiastes à l’idée de pouvoir l’uti-
WriteLine(msg);
liser dans nos développements futurs.

20 [Link]
021_027.qxp_249 20/10/2021 08:54 Page21

Blazor .NET 6 : un bon lot de


nouveautés nous attend
La feuille de route de Microsoft prévoit une sortie de version majeure de .NET tous les Sébastien Bernard
Concepteur développeur
ans. .NET 6 est une version LTS (Long Term Support). Cependant, un des paramètres SQLI
essentiels à anticiper concerne la nécessité d’utiliser Visual Studio 2022 pour coder avec
.NET 6 puisququ’il n’y aura pas de rétrocompatibilité pour VS 2019. Cette nouvelle ver-
sion possède son lot de nouveautés, celles dédiées à Blazor nous intéressent plus parti-
culièrement dans cet article qui ambitionne d’en faire un tour d’horizon.
Hot reload puisque cette gestion est supprimée dans le traitement des Florian Pouchelet
Pour utiliser le Hot Relaod avec Blazor de manière efficace et blocs finally dans mono. Concepteur développeur
transparente, il va falloir lancer le projet sans passer par le debug- Une grosse avancée a été faite en ce qui concerne les SQLI
ger de Visual Studio. Nous allons à la place utiliser une invite de Hardware intrinsics qui ont été introduits par .NET Core 3.0.
commande et lancer le projet à l’aide de dotnet watch. Figure 1 Mono supporte désormais LLVM pour la génération du code
Cette commande va démarrer le navigateur et afficher le pro- et le support de l’architecture ARM64 est implémenté grâce
jet Blazor en cours. On peut suivre les étapes de démarrage aux API ARM64 AdvSimd. Dans le même registre, les sup-
dans l’invite de commande. Figure 2 ports de SHA1, SHA256 et AES sont complétés.
À partir de là, on peut modifier le code dans la solution. On notera l’apparition des Vector64 et Vector 128 ce qui
Dès lors que le fichier modifié est sauvegardé, le changement seront nécessairement utiles pour les futures applications
est détecté et automatiquement appliqué, ce qui permet de Blazor wasm qui utiliseront AOT.
visualiser presque en temps réel ses modifications (en effet Oh ? AOT !? Eh bien oui, sachez que les applications Blazor
cela prend environ 2 à 3 secondes). Figure 3 wasm pourront être entièrement compilées en AOT (ce qui
Il devient possible d’ajouter, par exemple, un nouveau com- éliminera l’utilisation du JIT).
posant comme le counter sur la page d’accueil et de visuali-
ser ce changement dans le navigateur. Dans ce cas, l’appli- Webassembly AOT
cation va se reconstruire et afficher la nouvelle page. Blazor WebAssembly supporte maintenant la compilation
L’utilisation de dotnet watch pour le hot reload permet de « ahead-of-time » (AOT). Cela signifie que vous pouvez com-
modifier à la fois les pages Razor comme le code C#. Nous piler votre code .NET directement en WebAssembly ce qui
pouvons donc changer une fonction et constater en temps améliore grandement les performances d’exécution.
réel le nouveau fonctionnement. Actuellement, une application Blazor WebAssembly s’exécute
en utilisant un interpréteur .NET IL implémenté dans le Figure 1
Les performances .NET 6 dans Blazor
Dans les applications communes en .NET, on considère très
généralement un seul runtime, le coreclr (parfois même sans
se poser la question). Or, en utilisant Blazor, il devient intéres-
Figure 2
sant de se pencher sur la question ; en effet, Blazor
WebAssembly (Blazor wasm) utilise un runtime différent,
nommé mono. Il est pertinent d’indiquer qu’avec Blazor
wasm, le runtime est compilé dans l’application. Il faut savoir
que mono n’effectue pas que des opérations en Just In Time
(JIT), mais qu’il interprète également l’Intermediate
Language. Cela apporte une certaine sécurité supplémentai-
re puisqu’il n’interprète plus le code à la volée. Alors,
pourquoi parlons-nous de cela ? Parce qu’il s’agit du premier
sujet à propos des performances de Blazor avec .NET 6.
L’interpréteur de mono a bénéficié d’une refonte, améliorant
son « ability to inline » et notamment pour les méthodes qui
sont marquées par le tag [MethodImpl([Link] Figure 3
siveInlining)] qui est très utilisé dans les bibliothèques de bas
niveau du runtime (pour rappel, le inlining consiste à ce que
le compilateur remplace l’appel à une fonction par le corps
de la fonction).
Pour mémoire, la gestion d’abandon des threads a disparu
avec .NET 5 ; Blazor en bénéficie avec l’arrivée de .NET 6

[Link] 21
021_027.qxp_249 20/10/2021 08:54 Page22

<ErrorBoundary>
WebAssembly. Le code .NET étant interprété, cela signifie
<ChildContent>
qu’il s’exécute plus lentement que lors d’une exécution .NET
<MyComponent />
classique. La compilation .NET WebAssembly AOT corrige
</ChildContent>
ces problèmes de performance en compilant directement le
<ErrorContent>
code .NET en WebAssembly.
<p class="my-error">Voici une erreur personnalisée.</p>
Pour profiter de la compilation .NET WebAssembly AOT, il est
</ErrorContent>
nécessaire d’installer un outil de compilation additionnel dis-
</ErrorBoundary>
ponible en option dans le SDK .NET. Pour l’installer, il suffit
de taper dans une invite de commande : Il s’agit d’un moyen efficace pour gérer et personnaliser l’af-
fichage des erreurs au sein de Blazor.
dotnet workload install microsoft-net-sdk-blazorwebassembly-aot

Et dans le projet, il faut activer la compilation WebAssembly Persistance de l'état


AOT en ajoutant la propriété : pendant le pré-rendu
Une application Blazor peut être pré-rendue à partir du ser-
<RunAOTCompilation>true</RunAOTCompilation>
veur afin d’accélérer le temps de chargement perçu lors de la
La compilation WebAssembly AOT ne fonctionne que lorsque première utilisation. Le HTML est ainsi affiché directement
le projet est publié. Il faut donc publier le projet en mode pendant que le reste de la configuration se fait en arrière-
release pour en profiter. plan. Malheureusement, l’état utilisé pendant ce pré-rendu
est perdu et doit être recréé lorsque l’application est complè-
dotnet publish -c Release
tement chargée. Si un état est configuré de manière asyn-
Il faut noter malgré tout que l’utilisation de la compilation chrone, l’interface peut alors clignoter lorsque le pré-rendu
WebAssembly AOT a une conséquence sur le poids. est remplacé par l’affichage final.
L’application sera plus grosse et cela peut aller jusqu’à 2 fois Pour régler ce problème, une nouvelle balise <preserve-component-
le poids de l’application utilisant .NET IL. state /> a été ajoutée. Il faut ensuite ajouter le service
Ainsi, l’utilisation de cette option dépendra aussi du type ComponentApplicationState dans son composant pour préserver son état.
d’application déployée et sera surtout pertinente pour les L’évènement [Link] est déclenché
applications faisant une utilisation intensive du CPU. quand un état doit être conservé dans la page pré-rendue.
Voici un exemple montrant comment le composant
Error boundaries FetchData peut être persisté. Dans le fichier _Host.cshtml :
Il s’agit d’un nouvel élément qui offre une façon pratique de
<body>
gérer les exceptions au sein de la hiérarchie des composants.
<component type="typeof(App)" render-mode="ServerPrerendered" />
Pour l’utiliser, il suffit d’utiliser le nouveau composant
...
ErrorBoundary pour envelopper le contenu pour lequel vous
@* Persist the component state after all component invocations *@
souhaitez avoir une personnalisation de l’exception.
<persist-component-state />
<div class="content px-4"> </body>
<ErrorBoundary>
Et dans le fichier [Link] :
<MyComponent />
Code complet sur [Link] & github
</ErrorBoundary>
</div>
Réduction de la taille
Tant qu’aucune exception n’est levée, le composant affichera de téléchargement
son contenu enfant. Mais dès qu’une exception arrive, il SignalR, MessagePack, et Blazor Server scripts sont significa-
affiche une erreur spécifique. Par défaut, le composant tivement plus petits. Figure 4
affiche une div vide avec la classe CSS blazor-error-boundary. Par ailleurs, la taille d’une application Blazor WebAssembly a
Il est possible de personnaliser l’erreur en utilisant la proprié- été considérablement réduite. Figure 5
té ErrorContent.
Paramètres requis
Il est possible de spécifier qu’un composant Blazor a des
paramètres requis en utilisant l’attribut [EditorRequired].
Exemple :
Figure 4
[EditorRequired]
[Parameter]
public string Title { get; set; }

Si l’utilisateur ne précise pas le paramètre, il aura un avertis-


sement et le composant sera souligné. Attention toutefois, il
s’agit d’un attribut apportant une aide lors de la conception
et il ne garantit pas à l’exécution que la valeur du paramètre
Figure 5 sera non nulle.

22 [Link]
021_027.qxp_249 20/10/2021 08:54 Page23

Support du SVG Cela est utile pour notamment transférer des fichiers comme
Il est maintenant possible d’utiliser la syntaxe Razor, dont les détaillé dans la section suivante.
composants Blazor, dans un élément SVG foreignObject.
Téléversement plus rapide de fichiers
<svg width="200" height="200" xmlns="[Link]
plus lourds
<rect x="0" y="0" rx="10" ry="10" width="200" height="200" stroke="black"
En utilisant la nouvelle façon de diffuser des données entre
fill="none" />
JavaScript et .NET, il est désormais possible de téléverser des
<foreignObject x="20" y="20" width="160" height="160">
fichiers d’une taille supérieure à 2GB avec le composant InputFile.
<p>@message</p>
Le transfert est également plus rapide grâce à l’utilisation d’un flux
</foreignObject>
de byte[] directement sans utiliser un encodage Base64.
</svg>

Arguments d'évènement personnalisés


@code {
En plus du support d'évènements personnalisés dans Blazor,
string message = "Wow, it's so nice that this text wraps like it's HTML...because
il est aussi possible de passer des données au gestionnaire
that's what it is!";
d’évènements pour les évènements personnalisés. Par
}
exemple, il est possible de faire un évènement lorsque l’on
Modifier le contenu <head> HTML colle le contenu du presse-papier avec le texte collé par l’uti-
Blazor prend désormais en charge la modification de l’élé- lisateur. Pour ce faire, il faut déclarer un évènement avec un
ment <head> depuis un composant. Il devient possible de nom personnalisé et une classe .NET qui contiendra les argu-
modifier le titre et d’ajouter des éléments <meta>. ments pour cet évènement.
Pour modifier le titre d’une page, il faut utiliser le composant
[EventHandler("oncustompaste", typeof(CustomPasteEventArgs), enableStopPropagation:
PageTitle. Le composant HeadContent permet quant à lui d’in-
true, enablePreventDefault: true)]
teragir avec les autres éléments de <head>.
public static class EventHandlers
<PageTitle>@title</PageTitle> {
// This static class doesn't need to contain any members. It's just a place where we can put
<HeadContent> // [EventHandler] attributes to configure event types on the Razor compiler. This affects the
<meta name="description" content="@description"> // compiler output as well as code completions in the editor.
</HeadContent> }

@code { public class CustomPasteEventArgs : EventArgs


private string description = "Description set by component"; {
private string title = "Title set by component"; // Data for these properties will be supplied by custom JavaScript logic
} public DateTime EventTimestamp { get; set; }
public string PastedData { get; set; }
Pour activer cette fonctionnalité, il est nécessaire d’ajouter le
}
composant HeadOutlet.
Une fois cela fait, IntelliSense proposera un nouvel évène-
[Link]<HeadOutlet>("head::after");
ment appelé @oncustompaste.
Diffusion de données de @page "/"
JavaScript vers .NET
Blazor peut maintenant diffuser des données directement
<p>Try pasting into the following text box:</p>
depuis JavaScript vers .NET. Les flux sont appelés avec la
<input @oncustompaste="HandleCustomPaste" />
nouvelle interface IJSStreamReference.
<p>@message</p>
JavaScript :

function jsToDotNetStreamReturnValue() { @code {


return new Uint8Array(10000000); string message;
}
void HandleCustomPaste(CustomPasteEventArgs eventArgs)
C# :
{
var dataReference = await [Link]<IJSStreamReference>("jsToDot message = $"At {[Link]()}, you pasted: {event
NetStreamReturnValue"); [Link]}";
using var dataReferenceStream = await [Link](max }
AllowedSize: 10_000_000); }

Cependant, cela ne suffit pas pour déclencher l’évènement,


// Write JS Stream to disk
il faut également ajouter un peu de JavaScript dans le fichier
var outputPath = [Link]([Link](), "[Link]");
[Link] ou _Host.cshtml.
using var outputFileStream = [Link](outputPath);
Code complet sur [Link] & github
await [Link](outputFileStream);

[Link] 23
021_027.qxp_249 20/10/2021 08:54 Page24

Cela dira au navigateur que chaque fois qu’un évènement d’objets de météo, une liste de personnes, etc. Cependant, il
“coller” a lieu, il doit aussi déclencher un évènement custom- peut arriver que l’on souhaite définir un type plus précis pour
paste et passer les arguments définis. notre paramètre. Une contrainte sur un type d’objet permet
à la classe générique d’utiliser des paramètres ou méthodes
Génération automatique du type contraint.
de composant Blazor Avec .NET 6, il est maintenant possible d’ajouter une
Il est possible de générer un composant Blazor en créant le contrainte en utilisant la syntaxe C# classique :
tag dans une page puis faire un clic droit et générer le com-
@typeparam TEntity where TEntity : IEntity
posant.
Rendu de composant dynamique
.NET6 permet de créer des composants Blazor dynamiques
de la même manière que l’on utilise une variable de type
dynamique en .NET.

<DynamicComponent Type="@someType" />

Les paramètres peuvent être transmis au composant en utili-


Il est également possible de créer automatiquement la classe sant un tableau.
partielle à partir de la balise code du fichier Razor.
<DynamicComponent Type="@someType" Parameters="@myDictionaryOfParameters" />

@code {
Type someType = ...
IDictionary<string, object> myDictionaryOfParameters = ...
}

Blazor peut désormais déduire des Récupération de paramètres depuis


paramètres de type générique à partir une query string
de composants parents Depuis la preview 7 de .NET6, il est possible de spécifier que
Avec Blazor, il est possible d’utiliser des composants imbri- certains paramètres sont à récupérer dans la query string. Il
qués. Nous avons alors un composant parent qui possède faut ajouter l’attribut [SupplyParameterFromQuery] en plus de l’attri-
des composants enfants. Lors de l’utilisation d’un paramètre but classique [Parameter].
générique, il était jusqu’à présent obligatoire de préciser pour Exemple :
chaque composant ce paramètre générique. Par exemple lors
[Parameter]
de son utilisation dans une grid, il fallait spécifier
[SupplyParameterFromQuery]
Grid<TItem> puis spécifier à nouveau dans les colonnes
public int? Page { get; set; }
Column<TItem>, ce qui donnait en termes de code :
Code complet sur [Link] & github Avec l’url suivante [Link] la valeur 3 sera
alors affectée à Page.
Nous conviendrons que c’est un peu fastidieux de devoir spé- Il est possible d’utiliser cet attribut avec les types String, bool,
cifier pour chaque colonne les paramètres génériques de la DateTime, decimal, double, float, Guid, int, long et leur
grid. Il est maintenant possible de transmettre le paramètre variant nullable à l’exception de string. Les tableaux de ces
générique aux composants enfants en le cascadant. Il faut différents types sont également autorisés.
que les paramètres parents et enfants portent le même nom.
Support de la sélection multiple
@attribute [CascadingTypeParameter(nameof(TItem))]
dans l’élément select.
Nous pouvons dès lors simplifier l’écriture de la grid en ne spé- Il s’agit d’une fonctionnalité très appréciée et qui manquait
cifiant plus le paramètre générique au niveau des enfants : lors des précédentes releases. Lors de l’utilisation d’un com-
Code complet sur [Link] & github posant <select>, nous pouvons désormais spécifier l’attribut
multiple. Cela permet de choisir plusieurs éléments dans la
La version 5 de ma Datagrid pour Blazor (actuellement en liste. Dans ces conditions, l’évènement onchange va alors
bêta) utilise d’ailleurs ce nouveau mécanisme pour simplifier fournir un tableau avec les éléments sélectionnés via
son écriture. ([Link] ChangeEventArgs. En conséquence, il est possible d’utiliser
un tableau comme valeur pour la liaison lorsque l’attribut
Contraintes de type générique multiple est spécifié.
Dans une page Razor, il est possible de définir un paramètre Et lors de l’utilisation de <InputSelect>, l’attribut multiple est
générique avec la directive @typeparam.C’est très utile quand automatiquement déduit lorsque la valeur liée est un tableau.
on doit recevoir un paramètre dans un composant
Blazor dont on ne connaît pas le type. Par exemple, dans MAUI & Blazor
la datagrid, on reçoit en entrée une collection dont le conte- Pour commencer, qu’est-ce qu’une hybrid app ? Il s’agit de faire
nue varie en fonction des usages ; Ça peut être une liste une utilisation du code Blazor pour des applications natives :

24 [Link]
021_027.qxp_249 20/10/2021 08:54 Page25

• Réutilisation du développement web (code et compé- en standalone de manière native et nécessite Edge Canary et
tences) le SDK .NET Core 3.1. De même, il faut installer le template
• Accès à toutes les fonctionnalités natives de l’appareil grâce à une commande dotnet.
• Mélange de d’interface native et de web La solution se présente sous cette forme, on y retrouve bien
• Réduit le temps de développement des applications les différents projets selon la plateforme visée.
Le code .Net est exécuté directement dans l’application nati-
ve et exécute des composants Blazor localement. Le rendu
du DOM est envoyé dans un contrôleur de vue web. Tous les
évènements qui se déclenchent dans cette vue sont envoyés
dans le code .NET puis les modifications sont retournées
dans le contrôleur qui affiche la vue. Tout s’exécute dans
l’application.
.NET Multi-platform App UI (MAUI) est une évolution de
Xamarin Form, mais étendue à plus de plateformes (comme
le desktop par exemple).
Ces principales caractéristiques sont :
• Cross platform
• Utilisation des interfaces natives de chaque plateforme
• Un seul projet système, une seule base de code Cependant, on constate la présence d’un projet Blazor.
• Déploiement sur plusieurs appareils, mobiles et desktop Voyons ce que contient la page principale : Figure 6
• Disponibilité avec .NET 6 C’est bien un fichier Razor classique qui contient un counter !
C’est le principe des Blazor hybrid apps qui sont utilisées au Connaissant l’engouement et la montée en puissance de
sein de .NET MAUI. Blazor, ce projet reste donc à surveiller de près !
Le contrôleur BlazorWebView est intégré dans MAUI. On
retrouve donc : Micro FrontEnd avec Blazor
• Réutilisation des composants UI entre native et web Tout d’abord, définissons ensemble ce que nous appellerons
• Mix & match web and native UI le micro-frontend. Le micro-frontend est une architecture
• Accès direct aux fonctionnalités natives des appareils dans laquelle plusieurs composants coopèrent tout en étant
• Applications cross-platform mobile & desktop (à la sortie hautement indépendants. Il est facile de faire le parallèle
de .NET 6, le focus sera mis sur le desktop) avec l’architecture micro-services. Chacun des composants a
On peut donc utiliser des composants Blazor tels quels au sa propre logique, ils sont tous isolés les uns des autres et
sein d’une application .NET MAUI. Tous les composants déjà peuvent être développés par des équipes différentes.
développés dans le cadre d’autres projets peuvent donc faci- Pour que cette architecture fonctionne, il faut envisager une
lement être réutilisés. application principale, nommée la “App Shell” qui appellera
.NET MAUI possède le composant natif BlazorWebView qui tous les composants indépendants. Ainsi, pour récupérer les
permet de faire le rendu des composants Blazor. Cela repré- composants faisant partie de l’application, il faut utiliser ce
sente un vrai gain de productivité. que l’on nomme un compositeur. En .NET, il est par exemple
BlazorWebView est également disponible pour Winforms & possible d’utiliser la bibliothèque Piral.
WPF, ce qui permettra d’utiliser aussi les composants Blazor Dans notre exemple, nous utiliserons des composants Razor
avec ces technologies. sous forme de Razor Class Library (RCL) qui représenteront
les composantes du micro-frontend, l’app shell sera un projet
Mobile Blazor Bindings Blazor wasm, et le compositeur sera fait grâce aux dépen-
Vous connaissez certainement Blazor pour la création d’ap- dances internes de C#. Puis nous mettrons en place le lazy
plications web, avec toute la puissance qui lui incombe. Mais loading, afin de rendre l’expérience plus réaliste.
Blazor ne s’arrête pas là ; en effet, il existe un projet expéri-
mental dans le dépôt dotnet, nommé MobileBlazorBindings. Figure 6
Mais alors, késako ?
Il s’agit tout simplement de donner la possibilité aux dévelop-
peurs de créer des applications lourdes ou mobiles en utilisant
C# et .NET. Ça doit vous parler ça, C# et .NET pour des appli-
cations lourdes ou mobiles ? C’est normal puisque c’est ce que
fait Xamarin, et c’est là toute la subtilité : Mobile Blazor
Bindings se présente comme une abstraction de haut niveau
de Xamarin. Il utilise la syntaxe des pages Razor pour définir
les composants, autant sur le front, que sur le back-end.
On y retrouve ainsi tous les composants de [Link],
que l’on peut utiliser à sa guise, le rendu étant lui toujours
laissé à la charge de Xamarin.
En tant que projet expérimental, il n’est pas encore disponible

[Link] 25
021_027.qxp_249 20/10/2021 08:54 Page26

• AdditionalAssemblies qui contiendra les assemblies des compo-


sants que l’on chargera à la volée.
• OnNavigateAsync qui exécutera une fonction lorsque l’on sou-
haite naviguer dans l’application.
Dans notre cas, on cherchera à vérifier si l’on veut naviguer
vers nos composants et si tel est le cas, on ajoutera l’assem-
bly correspondante.
Et voilà ! Vous avez une application qui respecte les principes
du micro-frontend, et tout ça avec Blazor ! On constate bien
que chacune des Features est strictement isolée, et qu’elle
peut être modifiée indépendamment de l’application com-
plète et sans impacter le reste.
Il existe bien entendu des manières bien plus efficaces et
pragmatiques d’implémenter cette architecture, et vous en
trouverez pléthore sur internet. Sachez toutefois que le micro
Figure 7 -frontend ne se contente pas d’utiliser une seule technologie,
Il est important de préciser que l’implémentation de la démo vous pouvez tout à fait mixer les frameworks et utiliser chaque
qui vous est faite servira d’introduction et ne représente pas brique dans votre app shell, cependant cela requiert notam-
une solution efficace en production. ment un CI plus complexe.
Voici donc l’architecture de notre solution :
Tester Blazor avec bUnit
Contrairement à ce que le célèbre adage nous dit, non, tes-
ter, ce n’est pas douter. Et plus encore, la certitude n’évite pas
le danger. Alors, dans Blazor, comment fait-on ?
Comme Microsoft ne propose pas de framework de test offi-
Chacune des features possède un ou plusieurs composants, ciel pour Blazor, il nous faut nous tourner vers des projets
qui seront utilisés dans l’app shell. Rien d’extravagant, seule- open source. Dans le cas de Blazor, on trouve assez vite bUnit
ment les composants basiques qui sont créés avec Blazor. qui est placée sous licence MIT.
Intéressons-nous donc à l’import de ces composants dans BUnit fonctionne avec les frameworks de tests classiques, tels
l’app shell. Comme nous l’avons précisé, nous utilisons les que nUnit ou bien xUnit (ne les citons pas tous, nous n’en
références internes de la solution comme compositeur pour finirons pas) et c’est pour cette raison qu’il faut envisager
cet exemple. Vous devez donc ajouter les références de vos bUnit comme un fournisseur de contexte aux tests.
RCL dans l’app shell : ajoutez-les à la main dans le csproj, ou Allons un peu plus loin dans notre analyse : en utilisant bUnit
bien via la GUI. Une fois que vos références sont ajoutées, pour le rendu des composants, vous pourrez aisément passer
vous pourrez bénéficier des composants en les important à des paramètres, injecter un service et avoir accès simple au
votre guise : DOM du composant. Le rendu d’un composant se fait à par-
AppShell / _Imports.razor tir de la classe TestContext de bUnit, il en résulte un objet
IRenderedComponent qu’il sera facile de manipuler.
Pour écrire vos tests, vous aurez le choix entre le faire dans
Mais souvenez-vous, nous allons utiliser le lazy loading pour un fichier classique “.cs” ou bien dans un fichier Razor
cela, il faut commencer par indiquer quelle ressource sera à “.razor” ce qui facilite l’écriture du code HTML à tester ;
exécuter en lazy loading, pour cela, ajoutez la référence dans cependant l’éditeur Razor de Visual Studio 2019 n’intègre
votre csproj. pas encore toutes les fonctionnalités disponibles dans un
fichier C# classique, et quelques bugs de formatage sont à
prévoir.
Tout d’abord, il vous faut :
• Créer un projet de tests, avec le framework qui vous
Importez ensuite le package de gestion des assemblies, et conviendra le mieux (pour ma part j’utilise xUnit)
ajoutez donc “@using [Link]. • Installer le package NuGet bUnit. Attention, il faut penser
[Link]” dans votre _Imports.razor. à changer le SDK dans son nouveau projet, pointer vers
[Link].
• Penser à ajouter la dépendance vers le RCL que vous sou-
Le Lazy Loading servira également de compositeur, en vous haitez tester.
donnant la possibilité de ne charger vos composants qu’au Vous devez obtenir un fichier csproj proche de cela : Figure 8
moment où ils sont nécessaires, mais surtout il vous abroge
de l’import de vos composants dans votre _Imports.razor ! À noter qu’il est possible d'installer le projet de test via le template bUnit,
mais cela fonctionne à l’heure actuelle exclusivement avec xUnit.
Illustrons la solution dans l’[Link] : Figure 7
On ajoute deux nouvelles lignes à notre router : Prenons l’approche d’un test écrit dans un fichier C#, nous
testons un composant qui n’intègre pas de logique : Figure 9

26 [Link]
021_027.qxp_249 20/10/2021 08:54 Page27

Le fait d’étendre la classe TestContext de bUnit nous donne essentiellement dans l’utilisation de bibliothèques JavaScript,
accès au contexte de test de bUnit. ou bien de frameworks CSS tels que jQuery, Bootstrap ou
Maintenant, voyons si l’on ajoute un peu de logique à un encore Materialize. Mais on peut en retrouver une certaine
composant. Pour cela nous utiliserons le composant Counter utilité pour l’utilisation plus poussée de framework JavaScript,
qui est automatiquement généré lors de la création d’un pro- comme React.
jet Blazor.
On constate que l’on a cliqué une fois sur le bouton et qu’en Conclusion
effet le composant affiche bien la bonne valeur. .NET 6 apporte son lot de nouveautés en améliorant et sim-
Bien entendu, vous pourrez aller bien plus loin dans vos tests, plifiant l’utilisation de Blazor. L’optimisation est toujours un
comme précisé plus haut dans l’article grâce à notre intro- fer de lance des nouvelles versions de .NET et nous consta-
duction sur le sujet. tons une nouvelle fois son efficacité tant par la réduction des
Vous pourrez par exemple donner une valeur précise à un données à télécharger que par l’amélioration du rendu et des
paramètre, injecter des services, mocker vos données ou vitesses de traitements. Ces nouveaux ajouts sont les bienve-
encore gérer les retours asynchrones. nus et raviront à la fois des utilisateurs finaux comme les
En bref, cette bibliothèque est très complète, et son utilisation développeurs. Si Blazor continue sur cette même lancée, il est
est sans appel bénéfique à nos développements ! à prévoir qu’il s’impose relativement vite au sein des techno-
logies web, et en premier lieu chez les développeurs .NET. Si
JSInterop demain vous voyez Blazor truster le haut du classement des
Une fonctionnalité de .NET (arrivée avec .NET Core 3.1) très technos web, vous ne pourrez pas dire qu’on ne vous
intéressante dans l’utilisation de Blazor est le JSInterop. aura pas prévenus ! Figure 8
JSinterop est le mécanisme permettant d’interagir entre C#
et JavaScript. En effet, il offre la possibilité d’appeler des
fonctions C# dans le JavaScript et vice-versa.
Attention toutefois à ne pas commettre deux erreurs impor-
tantes :
• Utiliser la balise <script> dans un composant Razor
(.razor), car cette balise ne peut pas être mise à jour dyna-
miquement par Blazor.
• Modifier un composant dont le rendu a été fait par Blazor
avec du JavaScript. Blazor garde en mémoire un arbre du
DOM de ce qu’il a rendu, et si ce dernier est modifié sans
passer par Blazor, cela peut poser des problèmes à l’usage.
En ce qui concerne l’isolation JavaScript, Blazor intègre le
standard des modules JavaScript. On retrouve donc nos
fichiers JavaScript dans la partie wwwroot du projet Blazor.
L’intérêt de cette fonctionnalité au sein de Blazor se retrouve

Figure 9

Abonnement FAITES VOTRE VEILLE Abonnement


numérique TECHNOLOGIQUE AVEC papier
1 an ........ 39 € 1 an ........ 49 €
Abonnez-vous sur : Voir page 42
[Link] LE MAGAZINE DES DÉVELOPPEURS
27
028_031.qxp_249 20/10/2021 08:52 Page28

Performance .Net 6 & EfCore 6,


qu’en est-il ?
Clément Sannier
Leader Technique MS
La sortie de .Net 5 en 2020 a mis en avant un certain nombre de gains de performance
SQLI par rapport à .Net Core 3.1. La nouvelle version .Net 6 continue sur cette lancée, avec
pas moins de 500 pull requests pouvant être associés à un gain de performance sur les
6500 de la release. Les ambitions sont également grandes pour EF Core 6.0 : rattraper
les performances du Micro ORM qu’est Dapper. Je vous propose donc de décortiquer
quelques fonctionnalités et d’essayer de percevoir comment les changements de cer-
taines parties du code peuvent avoir un impact fort sur les performances du runtime.

La recherche de performance peut s’acquérir de deux ma- En .Net 6, de nombreuses améliorations ont été ajoutées par
nières. D’abord, il y a la recherche de la performance pure la communauté. L’une d’elles porte sur la gestion des mé-
du code. On essaye de trouver des raisonnements et une lo- thodes dites inline. L’Inlinning est le processus d’optimisation
gique différente permettant d’augmenter significativement d’un compilateur permettant de remplacer l’appel d’une
les traitements. Puis, il y a les avancées du langage et les per- fonction par son code. Bien que par définition, une méthode
formances qu'elles peuvent apporter. Ce que j’apprécie avec inline augmente la taille du programme, son principal avan-
cette version de .Net 6, c’est que les développeurs ont utilisé tage est d’offrir la possibilité d’améliorations qui ne peuvent
tantôt l’une et tantôt l’autre, et parfois même les deux. être accessibles par l’appel de la fonction (code mort, optimi-
sation d’invariant, élimination de variables d’induction, etc.).
Les tests de performance avec Benchmark .Net Pour certaines raisons, l’inlinning est à double tranchant côté
Avant toute chose, l’utilisation d’une librairie de benchmark performance : utilisé à mauvais escient, il peut réduire drasti-
est nécessaire. Benchmark .Net est une librairie destinée aux quement les performances. Toutefois, utilisé correctement, il
benchmarks et à la mesure de performance. Sa modularité lui est peut-être extrêmement puissant.
octroie la possibilité de mesurer différents frameworks à la fois Finalement, c’est un ensemble d’améliorations qui ont été ef-
du .Net Core ou du Framework. Ainsi c’est le partenaire idéal fectuées sur la partie JIT afin de mieux comprendre le code
pour tester les gains de performance entre .Net 5 et .Net 6, et faisant appel à la fonction inline. Pour tester les gains de per-
c’est ce que nous utiliserons tout au long de l’article. formance, prenons l’exemple de la classe Utf8Formatter. Si
nous regardons plus en détail le code, voici la signature de la
JIT méthode TryFormatInt64 : Figure 1
Le code source écrit en C# est compilé dans un langage in- Nous pouvons observer que la méthode est taguée pour être
termédiaire (il) conforme à la spécification CLI. Le code de en mode inline. En effectuant un test avec Benchmark .NET,
langage intermédiaire et les ressources, telles que les bit- nous remarquons d’après le ratio que les performances ont
maps et les chaînes, sont stockés dans une assembly, en plus que doublé par rapport à .Net Core 3 .1, et que la diffé-
général, avec une extension .dll. rence est aussi significative avec .NET 5.0. Figure 2
Lorsque le programme C# est exécuté, l’assembly est chargé La communauté a travaillé sur des améliorations concernant
dans le CLR. Le CLR effectue une compilation just-in-time la dévirtualisation, le PGO Dynamique ou encore la vérifica-
(JIT) pour convertir le code de langage intermédiaire en ins- tion des limites.
tructions machine natives. C’est donc naturellement que si
l’on veut augmenter les performances du runtime .Net, la Crossgen et AOT
gestion de la partie Jit est un bon candidat. Crossgen est arrivé très tôt dans le runtime de .Net
Framework. Au fur et à mesure de l’avancée du framework
Figure 1 .Net Core, le besoin s’est fait sentir de réécrire l’outil.
Crossgen est un outil permettant la compilation AOT (ahead-
of-time). Son but est de réduire les besoins de la compilation
JIT au moment de l’exécution. La compilation AOT s’ap-
plique au moment de publication de l’application, Crossgen
applique alors une pré-compilation JIT sur l’ensemble des dll
et stocke le code ainsi créé dans une nouvelle section pou-
vant être récupérée rapidement par le runtime.
Crossgen 2 a été complètement réécrit avec une nouvelle ar-
chitecture pour coller aux usages de .Net 6. En effet, ceux-ci
Figure 2 diffèrent totalement suivant les besoins. Il peut être utilisé sur

28 [Link]
028_031.qxp_249 20/10/2021 08:52 Page29

du Windows ou du Linux, dans des web app Azure ou dans


des « containers », pour du web ou du desktop. La nouvelle
version de Crossgen prend en compte toutes les spécifiés de
projet analyser et optimiser le code in fine.

System Types
System Types étant utilisé à tout moment et dans chaque ap- Figure 3
plication .NET, on ne peut augmenter les performances de
.Net sans passer par l’optimisation des types de la librairie
« System ». Des modifications ont été apportées à certains
types moins habituels comme le type version, et d’autres re-
touches concernent des types plus « couramment utilisés »,
comme Random qui a été totalement refondu. L’histoire est
simple, l’algorithme utilisé jusqu’à .Net 6 était le même de-
puis 20 ans. Il a donc été réécrit pour améliorer les Figure 4
performances de la génération d’une chaîne pseudo-aléatoi-
re sans empiéter sur la qualité dont nous avons besoin en
tant que développeur. Je pense que cette refonte de l’algo-
rithme devrait sûrement avoir un article à lui tout seul ; c’est
pour cela que j’ai préféré me pencher sur un autre type que
l’on utilise tous les jours et qui au cœur des applications
.NET : le Guid. Ce type est présent pour fournir un identifiant Figure 5
unique et universel dans une application.
Étant donné son caractère unique et universel, l’utilisation est
répandue dans les applications et l’une de ses méthodes les
plus utilisées reste le « parsing » (utilisé dans la désérialisation
de Json par exemple). En .Net il existe plusieurs formats de
Guid, avec ou sans parenthèse, accolade, séparée par un Figure 6
hypen. L’algorithme a été simplifié et l’utilisation de méthode
inline permet de mieux gérer les cas d’extraction d’un Guid [Link]. D’abord optimisé pour les
d’une chaîne de caractères. byte[], une deuxième pull request est venue compléter le
Si on lance un test en comparant à partir de la version .Net code pour n’importe quel type. Au lieu de comparer les sé-
Framework 4.8, voici ce que nous obtenons : Figure 3 quences directement, celle-ci se base sur la « value type »
Un bond en avant a été fait entre .Net Framework 4.8 et .Net [Link]<T>. Ainsi le traitement est délégué à la mé-
Core 3.1, puis de petites avancées jusqu’à .Net 6. Toutefois, thode span ajoutant une vectorisation de la comparaison
quand on pense que le parsing de string en Guid est inévi- sans utiliser plus de ressource. Le seul inconvénient est que le
table dans la réception de Json par une API, nous nous type T doit s’y prêter correctement :
rendons compte qu’après 1 million de parsing la maigre dif- Code complet sur [Link] & github
férence entre .Net 5 et 6 devient bien plus importante :
Figure 4 Le résultat est bluffant et nous rappelle le bienfait de la librai-
rie [Link] sur les performances lors des traitements :
String, Collections et Linq Figure 6
Les tableaux, les collections et Linq ont une place importante Les autres améliorations concernent la partie Distinct, Min,
au cœur de .Net. La communauté a donc travaillé à réduire Max ainsi que l’ajout de nouvelles API telles que
l’impact des traitements sur les performances du code. [Link] (acceptation de 3 sources au lieu de 2).
Prenons le cas d’une copie d’un dictionnaire. Étant utilisé à Enfin, intéressons-nous au String. Une optimisation intéres-
longueur de temps, rien de plus banal que de cloner un dic- sante a été réalisée au niveau de la méthode
tionnaire pour effectuer certains traitements. Si le « [Link](String, String) ». Certes, ce n’est pas la mé-
dictionnaire source et le dictionnaire de destination partagent thode en elle-même qui a été optimisée, mais plutôt le
le même comparateur de clé, l’astuce a consisté à copier les traitement des différents cas de Distinct. En effet, trois cas
objets sans les hacher par la suite : ont tiré leur épingle du jeu afin d’être optimisés dans cette
Code complet sur [Link] & github version de .Net 6 :
Le cas le plus évident est lorsque nous souhaitons remplacer
En vérifiant par un test, nous remarquons un gain de perfor- un caractère par un autre, souvent des caractères spéciaux
mance depuis .Net Framework 4.8 : Figure 5 comme “\n”. Ainsi la rapidité d’un [Link]("\n", " ") est ac-
Sur les collections, d’autres changements ont été effectués crue pour la simple et bonne raison qu’elle fait directement
pour améliorer un peu plus les performances. appel à la méthode [Link](char, char) :
Côté Linq, une amélioration m’a interpellé concernant les Code complet sur [Link] & github
tests d’équivalence entre deux énumérables avec Le deuxième cas réside lors du remplacement d’un caractère

[Link] 29
028_031.qxp_249 20/10/2021 08:52 Page30

unique par une valeur (unique ou non). Dans ce cas, c’est d’ailleurs une problématique connue depuis de nombreuses
indexOf(char) qui est utilisée : années.
Code complet sur [Link] & github Les modifications apportées dans .Net 6 contourne ce pro-
Le dernier cas survient lors du remplacement de plusieurs ca- blème en suivant l’offset plutôt en mémoire quand cela est
ractères avec l’utilisation d’un équivalent de IndexOf(string, possible ce qui accélère le traitement. Par la même occasion,
[Link]). les appels système ne sont effectués que lorsqu’ils sont expli-
Si nous testons les performances de chaque cas, nous retrou- citement requis.
vons une augmentation de performance significative dans le Voici les résultats de ce long travail : Figure 8
cas 1. L’augmentation reste tout de même honorable dans le D’autres améliorations de performance ont été introduites
cas 2 et 3 : Figure 7 dans cette réécriture, nous avons par exemple un travail sur
Les autres modifications de la librairie String ont porté sur la fonction de Lenght, avec pour elle aussi un accès en mé-
l’API [Link] avec là aussi l’introduction de la fonctionna- moire tant qu’il n’y a pas d’accès Write sur le fichier. Les
lité « ReadOnlySpan<string ?> », mais également parties Aync file IO, comme nous l’avons vu, ont bénéficié
[Link] avec des changements surtout issues de C#10 des avancées de FileStream, mais également d’autres amé-
et la string interpolation. liorations comme une meilleure gestion des allocations
mémoire et de la libération.
IO
La librairie FileStream est l’une des plus vieilles librairies de EF core 6.0 sur le banc des gains de
.Net. Elle a donc connu de nombreuses modifications année performance
après année et était donc l’une des candidates les plus im- C’est au tour de EF Core 6.0 de passer sur le banc des gains
portantes à une mise à jour, sachant que l’accès au fichier est de performance. Comme évoqué, l’ambition était grande
utilisé dans d'innombrables scénarios. Pour cette version pour cette nouvelle version, à savoir rattraper le « micro
.NET 6 la librairie FileStream a été complètement réécrite ORM » Dapper dans les scores de performance Tech
pour d’une part séparer les fonctionnalités en donnant plus Empower Fortunes. Les équipes d’EF Core ont annoncé être
de visibilité au code, et d’autre part faciliter les changements passées de 55% à environ 5% d’écart de performance. Si on
affectant la performance. considère les différences de feature entre Dapper et EF Core,
Deux méthodes ont été principalement revues pour offrir des c’est une avancée remarquable. Toutefois, il faut bien garder
gains de performance : [Link] et FileStream. à l’esprit que les tests de performance concernent un scéna-
Position. Le constat de départ, fait par la communauté, porte rio particulier utilisant du « no-tracking » et sans update. Il est
sur l’observation que les méthodes [Link] et donc possible que dans nos applications de production les
[Link] synchronisent l’offset du ficher de ma- performances soient différentes. Regardons, néanmoins en-
nière récurrente à chaque opération asynchrone. C’est semble, les résultats et quelques modifications qui ont été
apportées à EF Core.

Tech Empower Benchmark


Les tests Tech Empower ([Link]
comparent des performances de nombreux frameworks d'ap-
plications web exécutant des tâches fondamentales telles que
la sérialisation JSON, l'accès aux bases de données et la
composition de modèles côté serveur. Chaque framework
Figure 7 fonctionne dans une configuration de production réaliste. Les
Figure 8 résultats sont capturés sur des instances dans le cloud et sur
du matériel physique. Les implémentations des tests sont réa-
lisées par la communauté et toutes les sources sont
disponibles sur le dépôt GitHub : [Link]
FrameworkBenchmarks.
Nous avons donc accès au code produit par chaque commu-
nauté sur les différents Frameworks et le C# (CSharp sur le
repository) n’échappe pas à la règle.
Trois scénarios ont été retenus par l’équipe d’EF Core :
• Une implémentation qui utilise directement [Link]. Il
s'agit de l'implémentation la plus rapide parmi les trois énu-
mérées ici et se classe 12ième :
• Une implémentation qui utilise Dapper. Elle est plus lente
que l'utilisation directe d'[Link], mais reste rapide.
• Une implémentation qui utilise EF Core. C'est actuellement
l'implémentation la plus lente des trois.
Pour l’heure voici les derniers résultats, malheureusement, il
Figure 9 faudra attendre un nouveau round pour que les bénéfices

30 [Link]
028_031.qxp_249 20/10/2021 08:52 Page31

des optimisations soient pris en compte. Figure 9 listner » ou la journalisation activé(e), le code vérifie toujours
Je vous invite donc à guetter les annonces du prochain round à chaque instant l’activation ou non de ces derniers.
pour vérifier les gains. Afin d’offrir de meilleure performance et garder toujours cette
grande flexibilité, l’astuce a été de vérifier si la journalisation
Regroupement et recyclage des DbContext ou l’interception n’était pas activé et dans ce cas supprimer la
Arrivé avec EF Core 2.0, le regroupement de contextes offre journalisation pendant 1 seconde. Par conséquent, l’activa-
au développeur la possibilité de réutiliser un DbContext en le tion de la journalisation peut prendre jusqu’à 1 seconde, là où
réinitialisant plutôt que de le supprimer purement et simple- elle était instantanée. L’équipe a calculé que ce processus per-
ment. Dans cette gestion, un pool de contexte trop grand ou mettait d’améliorer le débit de référence de 7%.
illimité aurait tendance à créer des objets DbContext au fur et
à mesure des besoins, sans jamais les supprimer. La consé- Désactivation des contrôles
quence serait une gestion des ressources catastrophique. de sécurité des threads
Ainsi, jusqu’à la version EF Core 6.0, le pool par défaut était En espérant ne rien vous apprendre, EF Core n’est pas
de 128, ce qui est déjà un nombre important. Pour les be- « thread safe ». Une des raisons est qu’il encapsule une
soins du benchmark Tech Empower, la valeur a été mise par connexion à une base de données qui n’autorise presque ja-
défaut à 1024. D’après les tests réalisés par l’équipe EF Core, mais l’utilisation simultanée. Étant donné que les accès
les performances seraient augmentées de 23%. concurrents sont surtout dus à un problème de développe-
Il faut toutefois relativiser cette amélioration, d’une part car il ment, EF Core inclut un mécanisme de sécurité interne
était déjà possible de spécifier une valeur pour la taille du essayant de détecter tant bien que mal (en mode best effort)
pool, et d’autre part, car les scénarios qui auraient besoin les accès concurrents et lève une exception informative.
d’autant de Dbcontext sont limités. Il s’est avéré que ce mécanisme n’est pas aussi performant que
Une autre amélioration touche quant à elle la manière dont EF l’équipe le souhaite notamment lors des requêtes asynchrones.
Core interagit avec les objets [Link] (par exemple La problématique réside dans le fait qu’il n’y a pas réellement
DbConnection, DBCommand, DBDatareader, etc.). De base, le d’amélioration à apporter à ce mécanisme à part le désactiver
profilage de la mémoire a révélé un nombre élevé d’instances totalement. Étant donné les erreurs que cela provoquera,
de ces objets. L’une des améliorations a donc consisté à réécrire l’équipe a donc opté pour un indicateur de désactivation of-
les interactions pour que chaque DbContext dispose de ses frant à ceux qui le souhaitent la possibilité d’augmenter les
propres instances dédiées qu’il réutilisera à chaque fois. performances (d’environ 7% d’après les tests) s’ils sont
convaincus qu’aucun bug de concurrence n’existe.
Suppression de la journalisation
Les logs peuvent être importants pour comprendre d’éven- Que retenir ?
tuelles problématiques sur nos applications. Dans EF Core, il Que ce soit pour .Net 6 ou EF Core 6, les performances ont
est possible de voir les instructions SQL avant leur exécution été au centre des actions de la communauté, et je dois dire
ainsi que leur temps d’exécution. L’utilisateur a la possibilité que j’ai été séduit par celles-ci. Même si pour EfCore 6 cer-
de s’appuyer sur les événements grâce à classe taines améliorations sont difficilement transposables pour
DiagnosticSource et la gestion des instructions avec un inter- une application en production, les gains de performance sont
cepteur. Bien que cela puisse être puissant, des pertes de appréciables. Personnellement, j’ai hâte de pouvoir migrer
performance peuvent apparaître, car une fois le « diagnostic mes applications et voir les gains que je peux tirer de .Net 6 !

OÙ RÉCUPÉRER LES CODES SOURCES DES ARTICLES ?


J [Link]

[Link]/francoistonicD
[Link] 31
032_034.qxp_249 18/10/2021 16:11 Page32

LE TOUR D’HORIZON DE VS 2022


Nous vous proposons de passer en revue tout ce que Microsoft a révélé en avant-pre-
Gatien Montreuil mière de Visual Studio 2022. Suivez le guide !
Concepteur Développeur
Pour commencer, Microsoft a porté son attention sur l’esthé- particulier .NET 6 dont la mise en production est prévue en
tique. Parmi les changements qui ne manqueront pas de novembre. Blazor, quant à lui, reste bien entendu de la par-
vous sauter aux yeux, les équipes de Microsoft ont redessiné tie, de même que le framework .NET Multi-platform App UI
certaines icônes, les aplats de couleurs cédant leur place à (.NET MAUI) qui remplacera Xamarin.
des remplissages semi-transparents et des traits globalement Les développeurs C++ disposeront de la version 20 et de ses
affinés. Figure 1 outils de génération en version 143.
La police utilisée sera Cascadia. Cette police open-source de Les profils orientés frontend y trouveront également leur bon-
Microsoft, que l’on retrouve d’ailleurs dans le nouveau heur grâce à de nouveaux modèles de projets basés sur les
Windows Terminal, voit son intérêt au sein de Visual Studio frameworks front JavaScript / TypeScript les plus répandus, à
grâce à sa déclinaison Cascadia Code, qui apporte les liga- savoir Angular, React et [Link]. Ces nouveaux modèles sont
tures pour une bonne partie des opérateurs et décorations déclinés dans une version autonome (standalone) et une ver-
courantes dans du code. On gagne en lisibilité dans l’éditeur. sion liée à un backend [Link] Core.
Le thème sombre a également subi quelques modifications Enfin, un point d’honneur semble avoir été mis pour faciliter
dans la troisième prévisualisation pour limiter le risque de le développement d’applications multiplateformes, en
fatigue oculaire. En ce sens, la couleur d’accent bleu cyan témoignent la prise en charge de projets Linux basés sur
tire sa révérence pour devenir violette, plus proche de l’iden- CMake ou MSBuild, ainsi que la possibilité de générer voire
tité visuelle de Visual Studio. Figure 2 déboguer des applications à travers une machine virtuelle
Windows Subsystem for Linux (WSL), sans avoir recours à une
Nouvelles technos et autres bonnes connexion SSH.
nouvelles
Avec cette nouvelle interface légèrement remaniée, les utili- Le concepteur de projet fait peau
sateurs pourront s‘essayer à de nouvelles technologies, en neuve
Visual Studio a entièrement revu le concepteur de projet.
Également accessible via les propriétés du projet, ce nouveau
Figure 1 concepteur s’organise désormais autour d’une seule colon-
ne, cette fois-ci subdivisée en sections repliables et le tout
intégré dans la charte graphique de Visual Studio. De
même, cette nouvelle mise en page accueille un module de
recherche, utile pour modifier une propriété précise sans
avoir à naviguer pour retrouver son emplacement. Enfin, les
néophytes apprécieront la présence de descriptions autour
de chaque propriété afin de les guider au mieux. Figure 3
Figure 2

Hot reload, everywhere !


Tel est le credo choisi lors de l’annonce de cette nouveauté.
En effet, depuis la présentation de la deuxième préversion, le
Hot Reload a fait son apparition dans Visual Studio. Ce
mécanisme simplifie les sessions de débogage en poussant
VS2019 VS2022 preview 3 du nouveau code à la volée lorsqu’une modification est
détectée. Dès à présent, nul besoin d’arrêter puis relancer
une nouvelle session à chaque changement ! Ce mécanisme
se révèle d’autant plus appréciable, sachant le temps que
peut demander l’opération sur des projets de grande enver-
gure.
A ce jour, le Hot Reload ne supporte que les projets MSBuild
en C++, mais le support devrait s’élargir à minima aux
applications Blazor, .NET MAUI, WebAssembly, et s’appliquer
en CSS le cas échéant. Microsoft a également annoncé vou-
loir étendre ce principe de Hot Reload au processus de publi-
cation / déploiement du code, ce qui permettrait aux applica-
tions en production d’être mises à jour sans d’interruption.
Figure 3

32 [Link]
032_034.qxp_249 18/10/2021 16:11 Page33

Live Preview Des points d’arrêts en tout genre Figure 4


Peut-être avez-vous déjà utilisé l’extension Web Live Preview Avec les points d’arrêts seront plus complets que jamais :
de Microsoft ? Cette extension propose, pour les projets comme sur Rider ; Visual Studio 2022 permettra de créer des
[Link], de refléter le code source de la vue dans le HTML liens de dépendance entre différents points d’arrêts (rendre
rendu en temps réel, sans même attendre le rafraîchisse- un point d’arrêt B actif uniquement si le point d’arrêt A a été
ment de la page. atteint), et ajoutera également la notion de point d’arrêt
Avec Visual Studio 2022, une mise à jour de l’extension a temporaire (supprimé après avoir été atteint).
déjà été déployée pour prendre en charge les champs liés à Pour rendre plus intuitive la manipulation de ces points d’ar-
une source de données ; mais surtout, cette notion de rendu rêts, les lignes éligibles à les accueillir seront indiquées au
en direct est étendue aux applications WPF grâce à XAML survol de la souris par l’apparition de l’icône de manière
Live Preview. semi-transparente. Ensuite, un clic droit permettra de créer
Actuellement, XAML Live Preview propose déjà, durant une au choix : un point d’arrêt conditionnel, temporaire, ou un
session de débogage, d’inspecter chaque fenêtre en défilant point de trace en un clic. Enfin, les points créés pourront être
ou zoomant sur l’aperçu, mais également de positionner des déplacés à la manière du curseur, en les glissant d’une ligne
règles afin de vérifier les espacements et / ou positions des à une autre. Figure 5
différents contrôles. Ces derniers sont également sélection-
nables, afin d’inspecter leurs propriétés. Pour les applications Des petites nouveautés çà et là pour
utilisant plusieurs fenêtres simultanément, une liste déroulan- une meilleure expérience
te est disponible afin de forcer l’aperçu sur l’une d’elles (par Similaire à dotPeeks, un autre produit de JetBrains, l’EDI de
défaut, le rendu sera celui de la fenêtre principale). Microsoft serait désormais capable de décompiler des librai-
ries en l’absence de code source afin de donner un aperçu
Du mieux pour l’accessibilité de vos de l’implémentation, par exemple dans le cas où votre code
développements reposerait sur une librairie externe. Plus simplement, si ladite
Pour aider les développeurs à rendre leurs applications acces- libraire est open-source, Visual Studio prendra l’initiative de
sibles, la firme de Redmond disposait d’un outil en interne télécharger le code source afin de donner un aperçu sans
nommé Accessibility Insights, dont le but est d’analyser des passer par cette phase de décompilation. Ces sources
interfaces afin de signaler les problèmes d’accessibilité. externes seront regroupées dans l’explorateur de solution,
Après l’avoir rendu disponible à tous en tant que standalone directement sous la solution dans une section intitulée
Figure 4
en 2019 (extension Chromium pour les pages web, applicatif “Sources Externes”.
lourd pour interfaces desktop et Android, code source sur Autre évolution, cette fois-ci concernant la recherche de code
GitHub), Accessibility Insights devrait être intégré dans avec l’ajout d’une nouvelle portée. Celle-ci permet de recher-
Visual Studio 2022, même si Microsoft n’a pas encore appor- cher au-delà de la solution actuelle, le but étant de retrouver
té de détails sur cette intégration. l’extrait de code recherché, peu importe la solution dans
En intégrant le moteur d’Accessibility Insights au cœur de laquelle il se trouve.
Visual Studio, vos différentes interfaces graphiques pourront D’autres nouveautés visent à simplifier la surveillance de Figure 5
être analysées en temps réel afin de signaler les probléma- votre application et délimiter les parties sensibles de votre
tiques d’accessibilité de manière proactive et ainsi éviter leur code, avec notamment le flame chart, un nouveau graphique
apparition en production. In fine, si les recommandations dont le but est de mettre en évidence les chemins de code
sont effectivement suivies et les erreurs corrigées, vos appli- dits réactif (ou à chaud), c’est-à-dire les plus régulièrement
cations devraient être éligibles au standard WCAG proposé utilisés et / ou les plus demandeurs en ressources.
par le W3C. Visual Studio 2022 dote l’explorateur de tests d’une nouvelle
liste déroulante afin de choisir l’environnement d’exécution.
Des applications hébergées dans le Ainsi les développeurs d’applications multiplateformes peu-
cloud plus attrayantes vent valider la bonne exécution de ces tests, non seulement
Afin de promouvoir son offre cloud, Microsoft compte pro- dans leur environnement local, mais également dans des
mouvoir la mise en place d’applications basées sur Azure containers Linux avec le SDK .NET correspondant, dans des
dans Visual Studio. A destination des non-initiés, cela pren- machines virtuelles Linux grâce à WSL ou dans toute autre
dra la forme d’exemples validés par la communauté dont le machine connectée par SSH, couvrant ainsi plus de configu-
code source est disponible, exemples dont l’architecture ser- rations différentes, et surtout bien plus simplement qu’aupa-
vira de modèle. ravant. Figure 6
Ainsi, quiconque désire créer une application similaire aura à
Figure 6
disposition une solution clé en main, contenant tous les élé-
ments infrastructure-as-code permettant de provisionner
toutes les ressources nécessaires dans Azure, la définition de
la stratégie d’intégration et de déploiement continus. Ainsi,
à la création du projet, celui-ci est déjà prêt à être déployé, et
les développeurs peuvent se focaliser sur son développement.

[Link] 33
032_034.qxp_249 18/10/2021 16:11 Page34

De son côté, IntelliCode, la version assistée par l’IA patibilité Windows on Windows64 (WoW64). Rassurez-vous,
d’IntelliSense, s’est déjà démarquée depuis son intégration même si l’EDI fonctionne désormais sur 64-bits, vos applica-
dans les précédentes éditions de Visual Studio par sa capaci- tions resteront, malgré tout, compilables pour des plate-
té à prédire l’intention des développeurs à travers son systè- formes 32-bits.
me d’auto-complétion. Pour la version 2022 de l’EDI made Microsoft a annoncé des temps de chargement 2,5 fois plus
in Microsoft, IntelliCode s’est encore amélioré afin de propo- rapides. Pour valider le gain annoncé bien que la solution uti-
ser, à partir d’un simple mot-clé, de construire le reste de la lisée par l’éditeur pour sa propre démonstration ne soit pas
ligne de code. A terme, l’objectif pour IntelliCode est de sug- disponible, nous avons réalisé quelques essais avec le code
gérer, à l’instar de GitHub Copilot, des implémentations source du framework aspnetcore disponible sur GitHub.
complètes. La finalité pour Microsoft est multiple : proposer Composé de 518 projets pour un poids total de 2Go, l’am-
une expérience dans laquelle moins de temps est perdu sur pleur de la solution devrait nous permettre de mettre en
des particularité syntaxiques propres à chaque langage de exergue le gain potentiel. Pour cela, nous avons procédé
programmation au profit de la conception générale de vos ainsi : sur une même machine, nous avons tout d’abord
algorithmes, et guider les profils les moins expérimentés en lancé la dernière version en date de Visual Studio 2019, puis
leur proposant des extraits de code “propre” pour in fine éra- chronométré plusieurs actions comme le chargement com-
diquer les code smells. Figure 7 plet de la solution et son déchargement. Après un redémar-
Si toutefois IntelliCode ne suffit pas et que vous cherchez à rage complet, nous avons répété la séquence cette fois-ci
solliciter l’aide de quelqu’un, vous aurez sans doute recours avec VS 2022 (preview 3.1 au moment du test).
à Live Share. Cet outil, intégré à Visual Studio, sert à créer Quelques précisions sur l’environnement de test : il s’agit
des sessions de développement collaboratif en temps réel. d’un ordinateur exécutant Windows 10 Pro en 64 bits qui est
Avec Visual Studio 2022, Live Share se dote de nouvelles équipé de 16Go de RAM dont au moins 10 de libres, et les
fonctionnalités parmi lesquelles un chat textuel afin d’échan- différentes versions de Visual Studio ainsi que la solution ont
ger au sein de la session et éviter d’avoir à changer de été installées sur un disque dur type NVMe pour limiter le
contexte en basculant sur une application tierce, ou encore risque de goulot d’étranglement.
la possibilité de mettre en place des sessions récurrentes
grâce à la génération de liens réutilisables. Opération Visual Studio
Enfin, les organisations pourront mettre en place leur 2019 2022 (pre 3.1)
Chargement 67s 30s
propre politique de sécurité sur les sessions de partage,
Déchargement 18s 7s
notamment pour bloquer le partage du terminal avec accès
Compilation* 5.450s 5.650s*
d’écriture sur des machines dites sensibles.
*fera office de témoin, car géré par le SDK et non pas par VS
Devenv passe au 64-bits A l’issue de ces quelques tests, nous validons d’ores et déjà
Visual Studio 2022 fait un bond en avant, puisque son pro- la démonstration de Microsoft puisque lors du chargement
cessus principal ([Link]) devient un processus 64-bits. de la solution, le processus [Link] a volontiers utilisé plus
Ainsi, il pourra exploiter plus de 4Go de RAM, et éviter les de 5.1Go de RAM, prouvant l’intérêt pour Visual Studio de
erreurs Out-Of-Memory lors du chargement de solutions passer au 64-bits. De plus, certains chargements ont effec-
volumineuses. tivement été réduits drastiquement avec Visual Studio 2022
De plus, les performances devraient s’accroître pour les ordi- (~2.3x plus rapide pour le chargement, ~2.5x plus rapide au
nateurs possédant une architecture 64-bits puisque VS 2022 déchargement). Figure 8
n’aura plus besoin d’être exécuté à travers la couche de com-
Côté pomme
Enfin, les utilisateurs de Visual Studio for Mac ne sont pas en
reste, puisque Microsoft a réservé plusieurs nouveautés à
cette déclinaison. La nouveauté majeure est la migration
d’une bonne partie du code de l’interface de Visual Studio
for Mac sur du code natif. Ce changement permettra notam-
ment de prendre en compte les options d’accessibilité sélec-
tionnées au niveau du système d’exploitation, et globalement
d’améliorer les performances et la stabilité de l’EDI. L’autre
priorité est de réduire le delta entre l’expérience Visual Studio
sur Mac par rapport à Windows. En ce sens, la terminologie
et certains menus ont déjà été unifiés, et l’intégration de Git
Figure 7 serait à terme entièrement disponible dans Visual Studio for
Mac. Dans cette preview, nous pouvons d’ores et déjà utiliser
la fenêtre « Git Changes » pour inclure / exclure des modifi-
cations avant de commit, et d’autres fonctionnalités
devraient apparaître au fil des versions.
Figure 8

34 [Link]
035_036.qxp_249 18/10/2021 16:12 Page35

Java 17 : quoi de neuf ?


Java 17 est sortie le 14 Septembre dernier. Cette release ne contient pas beaucoup de
JEP, et donc pas beaucoup de nouveautés importantes. Par contre, elle apporte
quelques petites fonctionalités sympathiques, et, son statut de LTS (Long Term Sup- Loïc Mathieu
Consultant & formateur
port), en fait une release importante. Zenika Lille

JEP 406: Pattern Matching for switch (Preview) Le grand intérêt est que cela évite de devoir faire un test défen-
C’est sans doute la plus importante nouveauté de cette relea- sif avant le switch, et permet d’inclure dans celui-ci la valeur
se, le pattern matching arrive dans les switchs, en preview. nulle comme toute autre valeur possible de notre variable. Et
On peut désormais faire un switch sur le type d’une variable ça ne s’arrête pas là, le switch a été enrichi de guards qui per-
(y compris enum, record et tableau), et en extraire une mettent d’inclure une condition au case. L’exemple suivant issu
variable locale au case qui sera du type correspondant. La de la JEP montre son utilisation. En ajoutant un guard au case
JEP donne l’exemple suivant avec une chaîne de if/else : Triangle : case Triangle t && ([Link]() > 100), on peut créer deux
cases : un pour les grands triangles, et un autre pour les petits.
static String formatter(Object o) {
String formatted = "unknown"; static void testTriangle(Shape s) {
if (o instanceof Integer i) { switch (s) {
formatted = [Link]("int %d", i); case Triangle t && ([Link]() > 100) -> {
} else if (o instanceof Long l) { [Link]("Large triangle");
formatted = [Link]("long %d", l); }
} else if (o instanceof Double d) { case Triangle t -> [Link]("Small triangle");
formatted = [Link]("double %f", d); default -> [Link]("Non-triangle");
} else if (o instanceof String s) { }
formatted = [Link]("String %s", s); }
}
Plus d’informations dans la JEP-406 : [Link]
return formatted;
}
JEP 356: Enhanced Pseudo-Random
Qui peut maintenant être ré-écrit avec une switch expression : Number Generators
La JEP-356 fournit une nouvelle interface RandomGenerator, et une
static String formatterPatternSwitch(Object o) {
factory RandomGeneratorFactory, qui permettent d’accéder à une implé-
return switch (o) {
mentation de générateur de nombre aléatoire. Les générateurs
case Integer i -> [Link]("int %d", i);
existant : Random, SecureRandom, SplittableRandom et ThreadLocalRandom;
case Long l -> [Link]("long %d", l);
implémentent maintenant cette interface qui ajoute, entre autre,
case Double d -> [Link]("double %f", d);
l’accès à un stream de nombre aléatoire (RandomGenerator::doubles(),
case String s -> [Link]("String %s", s);
RandomGenerator::ints(), …). De nouveaux algorithmes de génération
default -> [Link]();
de nombre aléatoires ont été implémentés, plus sécurisés et plus
};
performant (mais ils ne sont plus thread-safe), ils ont vocation à
}
remplacer les anciens. Voici quelques exemples d’instanciation de
En plus de supporter du pattern matching, le switch permet générateur de nombres aléatoires :
maintenant de définir un case spécial null (dans ses deux
// the old Random generator
formes : statement ou expression). Auparavant, une variable
RandomGenerator rng1 = [Link]("Random").create(42);
de switch nulle entraînait une NullPointerException. Dans sa nou-
// the default random generator, currently L32X64MixRandom
velle forme, on peut ajouter un case null pour gérer les nulls au
// but this can change
sein du switch. Sans case null, l’ancien comportement est
RandomGenerator rng2 = [Link]().create(42);
gardé, et une NullPointerException sera levée.
// shortcut for the default
Si on reprend l’exemple précédent, cela nous donne :
RandomGenerator rng3 = [Link]();
static String formatterPatternSwitch(Object o) { // stream all available generators and display their names
return switch (o) { [Link]().forEach(generator ->
case null -> "null"; [Link]([Link]());
case Integer i -> [Link]("int %d", i);
Plus d’informations dans la JEP-356 : [Link]
case Long l -> [Link]("long %d", l);
case Double d -> [Link]("double %f", d);
Les fonctionnalités qui passent de
case String s -> [Link]("String %s", s);
preview à standard
default -> [Link]();
Dans Java 17, une seule fonctionnalité passe de preview à
};
standard : les Sealed Classes qui permettent de limiter le
}

[Link] 35
035_036.qxp_249 18/10/2021 16:12 Page36

nombre d’implémentations d’une classe ou d’une interface à [Link](), et en test via [Link](LocaDateTime.
une liste prédéfinie. La hiérarchie de cette classe/interface est of(//the hardcoded date time)).
donc close (scellée / sealed). Celles-ci existent depuis Java 15.
Plus d’informations sur la JEP-409 : [Link] Divers
Divers ajouts au JDK :
Les fonctionnalités qui restent en preview • [Link]([Link]) : permet de créer une copie d’une
Les fonctionnalités suivantes restent en preview (ou en incu- entrée de Map qui ne soit pas connectée à la Map existante.
bator module) : • [Link](), [Link](), [Link]() : per-
• Vector API : seconde incubation de la fonctionnalité. Vector met d’accéder aux entrée/sortie standard et sortie erreur
API est une nouvelle API qui permet d’exprimer des calculs d’un process via un Reader ou un Writer.
de vecteur (calcul matriciel entre autres), qui seront exécutés
via des instructions machines optimales en fonction de la pla- Dépréciation et encapsulation
teforme d’exécution. Java 17 voit la dépréciation pour suppression de l’API des
Plus d’informations dans la JEP-414 : [Link] Applets via la JEP-398, celle-ci n’étant plus utilisée depuis de
• Foreign Function & Memory API : nouvel incubator pour nombreuses années, elle n’a pas fait couler beaucoup d’encre.
ces deux fonctionnalités qui sont maintenant liées (l’une uti- Java 17 voit aussi la dépréciation du Security Manager pour
lisation l’autre) au sein d’un même incubator. suppression via la JEP-411. Il y a eu beaucoup de débat
• Foreign Memory API permet de gérer des segments autour de cette annonce, avec, il faut l’avouer un peu de
mémoire (on heap ou off heap) tandis que Foreign Function drama, comme quand Apache Netbeans a annoncé qu’il ne
l’interconnexion de la JVM avec du code natif (en C par pourrait pas supporter Java 17 alors qu’il fallait juste changer
exemple) de façon facile et performante. Ces deux API sont quelques lignes de code…
les bases du projet Panama. La suppression du Security Manager a été annoncée, car
Plus d’informations dans la JEP-412 [Link] celui-ci est complexe à maintenir, coûteux en termes de per-
formance, et n’apporte pas la sécurité nécessaire face aux
Un nouveau port de la JVM enjeux actuels. Il a été créé pour sécuriser les applets qui, par
Java 17 ajoute le support de l’architecture macOS/AArch64 définition, exécutent du code untrusted, et n’a donc plus de
(aka Apple Silicon). Plus d’informations dans la JEP-412 sens dans une JVM qui ne contiendrait plus l’API Applet.
[Link] Pour finir, la JEP 403: Strongly Encapsulate JDK Internals a
basculé le JDK vers une encapsulation stricte de ses classes
HexFormat internes. C’est la fin de ce qui avait été commencé avec Java
La class [Link] permet la conversion de type primitif, 9 et la modularisation du JDK.
tableau de byte, ou tableau de char en chaîne de caractère Concrètement, le mode d’encapsulation était passé de --ille-
hexadécimal et vice versa. gal-access=permit en Java 15 à --illegal-access=deny en Java 16 avec
la possibilité de changer l’option de configuration. Avec Java
[Link]().toHexDigits(127); // "7f"
17, --illegal-access disparaît et l’accès aux classes internes du
[Link]().fromHexDigits("7f"); // 127
JDK (hors Unsafe) n’est plus possible.
InstantSource
Tester du code contenant de la manipulation de date a tou- Conclusion
jours été un challenge, surtout si celui-ci use et abuse de Même si cette version de Java ne comporte pas beaucoup de
[Link](), [Link](), et autre initialisation de JEP, elle propose un grand nombre de nouveautés, et semble
date avec la date en cours. paver le chemin pour l’aboutissement du projet Panama dans
Pour faciliter la testabilité de ce genre de code, une nouvelle une future version.
interface a été ajoutée au JDK : InstantSource, avec une seule En dépréciant les Applets et le Security Manager, le JDK va
implémentation : Clock. Le but de l’interface InstantSource est aussi se séparer de pas mal de code historique plus utilisé, ou
d’être une fabrique d’Instant. Au lieu de créer un Instant avec la plus adapté au monde actuel. Même si cela induit quelques
date du jour, vous le créez depuis l’InstantSource. Un test pou- petits désagréments évidents, et complexifie le support de
vant alors utiliser une InstantSource à une date fixe au lieu de la cette version dans de nombreux framework, c’est un mal
date du jour. Imaginez le code suivant : pour un bien. Cela permettra de faciliter la maintenance du
JDK, et aux équipes de celui-ci à se focaliser sur l’apport de
public class MyBean {
nouveautés, le Security Manager étant une source d’impor-
private InstantSource source; // dependency inject
tante complexité au sein du JDK.
...
Pour finir, le statut Long Term Support (LTS) de cette release
public void process(Instant endInstant) {
va en faire la release de choix pour de nombreux dévelop-
if ([Link]().isAfter(endInstant) {
peurs, et il faut s’attendre à ce que beaucoup de dévelop-
...
peurs migrent directement de Java 11 à Java 17 (plus que de
}
migration de Java 16 à Java 17). De plus, l’annonce faite à
}
Spring One de baser sur Java 17 minimum les futurs Spring
}
Framework 6 et Spring Boot 3 (GA fin 2022) va définitive-
En fonctionnement normal, l’InstanSource est initialisé via ment entériner Java 17 comme version à privilégier en 2022.

36 [Link]
037_039.qxp_249 20/10/2021 08:49 Page37

Le développeur
va sauver la Terre !
PARTIE 1 : POSONS LES FONDAMENTAUX
Le développeur est le Chuck Norris de l’éco- pourrions plusieurs Mo en optimisant les ressources et
conception. Sans lui, on ne peut pas réduire la taille le poids de chaque page. Il faut revenir à un principe
des applications, réduire l’usage des ressources IT ou simple : 1 Ko est un 1 Ko utile. Dans les années 1980,
encore améliorer l’utilisation réseau. On peut chaque Ko était une ressource précieuse qu’il fallait
appliquer l’éco-responsabilité dans les apps mobiles, utiliser avec rigueur. Nous avons perdu cette obsession
le cloud, le desktop. Le développeur peut cibler le des contraintes matérielles. Comme le sujet est
code, les piles techniques, tous les assets techniques énorme, nous avons décidé de publier un dossier sur
et graphiques. Rien que sur les sites web, nous deux numéros. La partie 2 sera publié dans le n°251.

Le Green Software dans tous ses états


Au sein de la Direction de l’Innovation du Groupe ALTEN, nous sommes convaincus de l’im-
portance des considérations environnementales et de l’opportunité qu’elles constituent. Mathieu
TOUCHARD
En effet, l’impact environnemental, qu’on le mesure en W, en gCO2, en %CPU ou en ko est Pilote Innovation
une métrique supplémentaire du système que l’on conçoit, et une métrique fortement liée Direction de l’Innovation
Groupe ALTEN
à des considérations de performances.

Figure 1

Dans un software, travailler l’obésité du code permet de ga- intelligent destiné à l’industrie, ces gains sont directement liés
gner « facilement » 30% de performance, qui se traduisent au coût total de possession du capteur, car la maintenance
souvent par des temps de chargement plus courts, et donc destinée à remplacer la batterie est souvent coûteuse.
une expérience utilisateur améliorée. Lorsqu’enfin on passe à l’échelle d’un système complexe as-
Si ce logiciel est embarqué sur un smartphone, ces 30% sont semblant de multiples logiciels & intelligences, le coût
autant d’autonomie, et donc de temps d’utilisation de l’appli- énergétique de la performance devient crucial. Ainsi qui vou-
cation avant une recharge sur le secteur, ou avant un drait d’une voiture électrique et autonome dont la batterie ne
changement de batterie. Lors de la conception d’un capteur permettrait pas de parcourir plus de 13 km entre 2 bornes ?
Figure 1
[Link] 37
037_039.qxp_249 20/10/2021 08:49 Page38

Nous découpons nos travaux en trois projets, d’ampleur et de nome, ou encore l’avion de chasse. Dans ces systèmes, les
complexité croissante : intelligences sont en réseaux communicants, et la perfor-
• Le projet Green Code porte sur le code, notamment dans mance du système global repose non seulement sur les
les usages mobiles & web, et a pour objectifs d’en maîtriser performances des sous-systèmes, mais aussi sur l’intelli-
les outils de mesure de l’impact environnemental et de la gence de la communication et les choix d’architectures
consommation énergétique, ainsi que les leviers d’actions. (distribuée, centralisée, hétérarchique). L’enjeu « Green »
Ici le TRL est élevé, des outils existent, et notre effort se devient alors un enjeu de performances de systèmes intelli-
situe dans l’agrégation de ces outils et l’analyse des résul- gents. Au travers de ce projet, notre objectif est de
tats pour en établir des leviers d’amélioration. s’inspirer de la consommation énergétique du cerveau hu-
• Le projet Green Smart Objects s’intéresse aux objets intelli- main à 40 watts. En comparaison, le système d'intelligence
gents, objets connectés et autres IOT & IIOT, dans lequel artificielle Watson d'IBM qui a remporté le jeu « Jeopardy! »
on doit mesurer et maîtriser à la fois la consommation du en 2011 avait besoin de 80.000 watts et AlphaGo de
code, celle du hardware, et celle de la communication DeepMind qui a battu le meilleur joueur de go en 2016 fai-
(wifi, Bluetooth, Lora,…). Dans ce projet, notre démarche sait à peine mieux avec 20.000 watts. Nous nous
de mesure de la performance « green » des objets intelli- attaquons ainsi à l’efficacité énergétique d’une intelligence
gents et communicants devra nous permettre d’aller vers artificielle en inventant une nouvelle échelle de mesure de
une modélisation green MBSE de ces systèmes en phase de l’efficacité d’une IA pour permettre de mieux les comparer
conception. et espérer ainsi s’approcher de l’efficacité énergétique de
• Enfin, le projet Green Smart System passe à l’échelle des l’intelligence humaine…
systèmes complexes tels l’usine du futur, le véhicule auto-

Qu’est-ce que la
Pierre LAGARDE
« Green Software Foundation » ?
Principal Program La « Green Software Foundation » est une organisation à but non lucratif créée en 2021
Manager
Windows & Devices - basée sur la Linux Foundation. Elle est née d'un désir et d'un besoin mutuel de collabo-
Microsoft Corp ration au sein des équipes de développement. Elle regroupe des organisations qui par-
tagent un engagement envers le développement « green » autour de principes qui ont
pris naissance il y a un an ici : [Link]

La mission de la « Green Software Foundation » est de  Innovation


construire un écosystème de confiance composé de per- Orienter la recherche universitaire, les innovations sur le dé-
sonnes, de normes, d'outils et de meilleures pratiques pour la veloppement et sur les données pour faire progresser le
création et le développement d’applications « green » ou du- développement « green ».
rables afin de contribuer à la réduction des émissions de Sponsoriser les principaux projets open source autour du dé-
carbone. Le choix intrinsèque qui a été défini par la fondation veloppement « green » afin de garantir leur pérennité.
est bien de réduire les émissions et non de les compenser.
Elle a pour vision de changer la culture du développement lo-  Marque
giciel dans l'ensemble de l'industrie technologique, afin que S'assurer que les marques de la Fondation sont utilisées cor-
le développement « green » devienne une priorité pour les rectement et dans un contexte respectant les valeurs de la
équipes projet, au même titre que la performance, la sécuri- Fondation. Définir des directives concernant quand, com-
té, ou les coûts aujourd’hui. ment et dans quel contexte les marques de la Fondation
Tous les documents produits par la fondation sont en open peuvent être utilisées.
source sur GitHub. [Link]
La fondation est constituée de 4 groupes de travail.  Communauté
Faciliter une large adoption des normes et des meilleures
 Les standards pratiques en matière de développement « green » par la créa-
Le périmètre de ce groupe de travail est de développer une tion de partenariats, de contenus, la participation à des
série de spécifications de base pour les logiciels « green ». événements. Assurer une participation diversifiée des contri-
S'assurer que les spécifications peuvent être mises en œuvre buteurs.
de manière interopérable sur les différentes plates-formes les
plus utilisées et dans toutes les régions.

38 [Link]
037_039.qxp_249 20/10/2021 08:49 Page39

LES PRINCIPES
DE DÉVELOPPEMENT
« GREEN »
Écrire des principes de développement « green » est un exer-
cice qui nécessite des connaissances scientifiques, sur le
climat, sur la production électrique, le matériel électronique
et bien sûr les principes de fonctionnement des data centers Figure A
qui sont avec l’Intelligence Artificielle au centre des débats du
développement « Green », car ils représentent une large par-
tie des émissions de carbone pour le secteur du numérique.
Pour prendre ces 2 exemples, les premiers datacenters ont
été conçus pour répondre à une forte demande en termes de
ressources et de haute disponibilité, quant aux architectures
d’IA, elles étaient basées sur de très grandes quantités de
données et des algorithmes extrêmement gourmands en
puissance de calcul. Dans l’élaboration de ces architectures,
l’environnement n’entrait pas dans l’équation. Le défi qu’il
faut relever maintenant c’est de redéfinir ces architectures lo-
gicielles en prenant en compte les différents aspects
environnementaux liés au domaine du numérique. Figure B
C’est pourquoi une initiative lancée par Asim Hussain a vu le
jour pour mettre par écrit ces « grands » principes de dévelop-
pement qui permettront de définir ce qu’est une application  Valoriser l’impact CO2 global : en créant des applica-
ou un service numérique « green ». Aussi bien au niveau du tions qui sont capables de s’exécuter sur du matériel
code source, mais aussi pendant l’exécution des applications plus ancien pour allonger la durée de vie du matériel,
et des services, et ce, indépendamment du domaine d’appli- ordinateurs, tablettes, téléphones ou serveurs.
cation, de l’industrie, de la taille ou du type de l’organisation, Proportionnalité énergétique : utiliser des serveurs avec
du fournisseur de cloud ou même du langage. un taux d’utilisation élevé, car la relation entre la puis-
sance et l'utilisation n'est pas exactement proportionnel-
Ces principes de développement sont au nombre de 8 aujour- le, car un ordinateur inactif n’a pas une puissance à 0.
d’hui, mais ils sont amenés à évoluer à travers la Green Figure B
Software Foundation et ses contributions open source.  Mise en réseau : réduire la quantité de données et la
Voici un résumé de ces 8 principes que vous pouvez retrouver distance à parcourir sur le réseau. Les différents fac-
en français sur le site : [Link] teurs d’émissions sont par exemple : la distance, le
 Minimiser l’empreinte carbone : cela paraît simple, nombre d’appareils réseau traversés, ou encore le pro-
mais penser son application pour avoir une empreinte tocole réseau utilisé.
carbone faible doit être prise en compte dès la phase  Formuler au mieux la demande : au lieu de façonner
de conception et en tenant compte du maximum de l’offre pour répondre à la demande, essayez de façon-
paramètres : l’usage, le nombre d’utilisateurs, le temps ner la demande pour qu’elle corresponde à l’offre.
d’utilisation, etc. Pour donner un exemple, les logiciels de vidéoconféren-
 Économiser l’électricité : la consommation électrique ce vont réduire la qualité vidéo pour donner la priorité
des composants d’un ordinateur n’est pas égale et doit à l'audio en cas de forte affluence.
être prise en compte pour venir optimiser sa consom-  Mesure et optimisation : concentrez-vous sur les optimi-
mation électrique. Par exemple, un GPU pourra faire le sations de bout en bout qui augmente l’efficacité glo-
même travail qu’un CPU, mais avec beaucoup moins bale en empreinte carbone et utilisez des outils de
de cycles. Par exemple, le décodage d’un codex vidéo. mesure précis qui vous permettront de concentrer vos
[Link] efforts au bon endroit.
 Prendre en compte l’intensité en CO2 : l'intensité carbo- - Sous Windows il y a la ligne de commande : [Link]
ne de l'électricité est une mesure de la quantité d'émis- /srumutil qui vous donne le détail exact de la consommation
sions de carbone (CO2éq) produite par kilowatt-heure électrique par process au format CSV ou XML si vous ajou-
d'électricité consommée. Chaque pays ou région va avoir tez le paramètre /XML.
une intensité carbone différente à un instant t en fonc- - Il y a aussi un projet Open source [Link]
tion de son type de production. Cette information peut
être prise en compte dans une application pour venir Je suis convaincu que respecter ces 8 principes peut aussi
réduire son émission de carbone et aussi éviter les émis- bien sensibiliser les développeurs que les utilisateurs dans
sions marginales en déplaçant la consommation élec- cette transition vers une meilleure sobriété numérique.
trique, par exemple, en différant une sauvegarde ou une
indexation de données. Figure A

[Link] 39
040_046.qxp_249 18/10/2021 16:13 Page40

Optimiser son site web pour réduire


son impact environnemental
Raphaël Lemaire Les crises écologiques (climat, biodiversité, épuisement des ressources naturelles, …),
Directeur technique chez
Zenika, consultant et sont de plus en plus présentes dans notre quotidien, et plus seulement comme des
formateur, spécialisé
dans le numérique
problèmes d’un futur plus ou moins lointain mais bien comme une actualité brûlante.
responsable Dans ce contexte, le numérique n’est plus vu comme neutre ou même automatiquement
bénéfique mais comme ce qu’il est : un des secteurs économiques et industriels qui a
un impact écologique, et qui comme les autres doit réduire cet impact.
Cet article expose des pistes d’actions possibles pour réduire On note que l’extension fournit une estimation des émissions
l'impact environnemental du numérique dans le cadre du déve- de gaz à effet de serre associés à la page, exprimée en
loppement web. Il ne couvre pas l’ensemble de l’écoconception grammes équivalent CO2 ainsi qu’une estimation de la
d’un service numérique qui est un travail qui implique toute consommation d’eau, exprimée en centilitre. D’où viennent
l’équipe autour du projet. Nous y verrons comment évaluer ces chiffres ? Ils sont calculés à partir d’une analyse de cycle
l’impact d’une page, quelles pratiques mettre en œuvre, com- de vie d’un site sur lequel ont travaillé les concepteurs de l’ex-
ment concevoir des applications web plus vertueuses. tension. Une analyse de cycle de vie est une analyse des
impacts environnementaux d’un produit, en tenant compte
Comment mesurer l’impact d’une de toutes les étapes de sa vie (fabrication, utilisation, fin de
page web d’un point de vue environ- vie) et en s’intéressant à plusieurs facteurs d’impacts, pas
nemental ? seulement les émissions de gaz à effet de serre comme pour
Pour améliorer, il faut mesurer, analyser. Une chance : il exis- un bilan carbone. L’extension GreenIT-analysis est donc
te une extension de navigateur, appelée GreenIT-Analysis, d’abord un outil pédagogique permettant de sensibiliser à
disponible pour Chrome1 et Firefox2, permettant d’analyser l’impact environnemental d’une page.
une page web d’un point de vue impact environnemental. Il Individuellement, ces 2,46 centilitres et 3,69 grammes n’ont
s’agit d’un projet open source, dont le code est sur github3. pas l’air très importants, mais si on multiplie par le nombre
Voyons ce qu’elle nous dit par exemple pour [Link] d’affichages, on peut arriver à des gros chiffres. Pour un site
[Link]/. ayant des millions de vues, cela donne des tonnes équivalent
Pour l’utiliser il faut, après avoir installé l’extension, ouvrir les CO2 par exemple. En tant que développeurs web, nous avons
outils des développement du navigateur, aller dans l’onglet la chance, en pouvant optimiser ces pages, de réduire cet im-
« GreenIT », ouvrir la page, puis lancer l’analyse. On peut op- pact. Si on a un fort trafic, même un petit gain peut faire une
tionnellement cocher la case « Activer l’analyse des bonnes grosse différence, par le pouvoir de la multiplication.
pratiques » pour avoir plus d'informations. Figure 1
Analysons cette capture d’écran. On y trouve une note de E, D’où viennent ces impacts environne-
déterminée à partir d’un score « EcoIndex » de 26,85. mentaux associés au web ?
L’EcoIndex ici affiché, est inspiré de l’éco-index visible par Quand on pense à l’impact environnemental du numérique,
exemple sur les appareils électroménagers. Les notes vont de on pense souvent aux data centers. On a l’image d’une salle
A à G, et l’index de 0 à 100, 100 étant la meilleure note pos- serveur pleine de machines, qui consomment beaucoup
sible. La note est ici plutôt moyenne mais pas du tout d’électricité, qui nécessitent de la climatisation , etc… Or,
surprenante pour une page d'accueil, qui est typiquement contrairement à ce qu’on pense souvent, ce ne sont pas les
assez chargée. centres de données qui sont responsables de l’essentiel de
l’impact environnemental du numérique, mais les terminaux
(1) [Link] des utilisateurs, et en particulier leur fabrication. Les chiffres
feklkbebfclfaiifefjflcpad?hl=fr de l’étude de [Link] le montrent clairement.
(2) [Link]
Émissions de gaz à effet de serre du numérique mondial ré-
(3) [Link]
Figure 1 parties par phase du cycle de vie et segment de terminaux

Production Utilisation Total


Utilisateurs 40% 26% 66%
Réseaux 3% 16% 19%
Centres informatiques 1% 14% 15%
44% 56%

40 [Link]
040_046.qxp_249 18/10/2021 16:13 Page41

Utilisation des ressources naturelles du numérique


mondial réparties par phase du cycle de vie et segment
de terminaux

Production Utilisation Total


Utilisateurs 76% 0% 76%
Réseaux 16% 0% 16%
Centres informatiques 8% 0% 8%
100% 0%
Source : Empreinte environnementale du numérique mondial, [Link], 20194
Cela s’explique simplement parce qu’il y a beaucoup plus de
terminaux clients que de serveurs. 34 milliards contre 700
millions. Mais aussi parce que fabriquer un appareil high-
tech est quelque chose de complexe et coûteux.
Un smartphone contient par exemple plusieurs dizaines de Figure 2
matériaux différents. Il faut extraire les minerais des métaux On a tous, c’est humain, envie de travailler avec les dernières
des mines, les concasser, les chauffer, les purifier avec des évolutions du web, que ce soit des éléments html 5 ou des
produits chimiques, pour pouvoir créer des alliages avec les- propriétés CSS. Mais les utilisateurs du site ne sont pas
quels on peut créer des composants électroniques que l’on forcément maîtres du navigateur qu’ils utilisent, par exemple
assemble, il faut aussi du sable pour le verre des écrans, du s’ils sont sur un ordinateur d’entreprise, ou sur une machine
pétrole pour le plastique, et aussi transporter ces matières et ancienne où ils ne peuvent pas installer de logiciels trop
ces composants, ainsi que les appareils jusqu’au magasin. récents qui la ralentiraient. Ils peuvent même ne pas savoir
90% des émissions de gaz à effet de serre émises dans toute qu’il est possible d’utiliser un autre navigateur que celui qu’ils
la vie d’un smartphone le sont à sa fabrication. possèdent déjà. On peut aussi prolonger la vie d’ordinateurs
Sachant cela, on peut en déduire que les actions clefs pour anciens en y installant une distribution linux légère et un
réduire l’impact du numérique sont d’abord d’utiliser moins navigateur minimal.
de terminaux et de les faire durer le plus longtemps Le site [Link] permet de valider si une
possible. Puis de réduire les ressources informatiques fonctionnalité particulière peut être utilisée : Figure 2
utilisées par les programmes.
Construire des applications web qui se comportent mal sur Comment optimiser son site ?
les appareils des utilisateurs encourage ceux-ci à renouveler La note EcoIndex sur 100 donnée par l’extension est calculée
leurs appareils. « Je ne peux même plus surfer sur le web à partir de trois indicateurs : le poids de la page
avec cette bécanne, il m’en faut une autre ». L’application (décompressée), le nombre de requêtes http et la taille du
contribue à pousser vers l’obsolescence le terminal de DOM, dont les valeurs sont affichées. L’idée est qu’une page
l’utilisateur alors que celui-ci fonctionne toujours très bien. avec beaucoup d’éléments et beaucoup de requêtes a des
De plus, une application web peu performante utilisera plus chances d’être difficile à afficher pour l’appareil, et que si elle
les composants de la machine. La batterie se videra plus vite est lourde en ko et en nombre de requêtes, elle utilise
par exemple dans le cas d’un smartphone, ce qui l'amènera potentiellement trop de charge serveur et réseau.
plus rapidement à la fin de sa vie, qui se compte en nombre Et si on y réfléchit un peu, nos pages web sont souvent très
de cycles décharge/recharge. lourdes par rapport à ce qu’elles font.
Enfin utiliser plus de bande passante que nécessaire, utiliser Super Mario Bros, jeu iconique avec de nombreux niveaux et
plus de ressources serveur que nécessaire, implique de interactions ne pesait que 40 Ko, moins que beaucoup de
dimensionner les architectures réseaux et serveur pour fichiers servis par les sites webs aujourd’hui, que l’on parle de
encaisser ce trafic. Sur une application à forte audience, une css, de js ou d’images. Depuis 2016, une page web est
optimisation de quelques centaines de ko par page peut faire même en moyenne plus grosse que le jeu Doom, qui était un
une grosse différence en volume si on multiplie par le jeu en 3D avec plusieurs niveaux et des effets sonores.
nombre d’utilisateurs et de téléchargements. Quand on pense qu’un site se base sur le navigateur et sur
Pour ne pas pousser au renouvellement des appareils et ses API pour s’afficher et exécuter ses comportements et
économiser des ressources, on va donc chercher à créer des intéractions alors que ces programmes étaient autosuffisants
sites légers et efficients. et que parfois, quand on scrolle une page, on la voit ramer,
la différence est encore plus impressionnante. Cela laisse une
Avant d’être performant il faut être impression d’imparfait. On doit pouvoir mieux faire.
compatible Il existe de nombreuses ressources pour améliorer la
Dans le cadre du développement web, cela veut dire être performance de nos sites web. On peut par exemple citer les
compatible avec les navigateurs dont les utilisateurs checklist d’opquast5, ou les outils de google comme Google
disposent, même s’ils sont un peu anciens ou n'implémentent PageSpeed Insights. En plus d’afficher un EcoIndex et une
pas les normes les plus récentes. estimation d’impacts environnementaux, l’extension GreenIT

(4) [Link] (5) [Link]

[Link] 41
042.qxp_249 18/10/2021 16:15 Page42

Abonnez-vous à Programmez! Abonnez-vous à Programmez! Abonnez-

Offres 2021
Profitez dès aujourd’hui de nos offres spéciales !*
1Programmez!
an + Pack maker/IoT 59€
Nos classiques

49€* 1Programmez!
an + Tous les numéros de Technosaures
79€
1 an D 10 numéros
(6 numéros + 4 hors séries)

79€*
+ accès aux archives + Pack maker/IoT
2 ans D 20 numéros
2 ans 89€
(12 numéros + 8 hors séries)

39€*
2 ans
Etudiant Programmez! + Pack maker/IoT

99€
1 an D 10 numéros
(6 numéros + 4 hors séries)

19€
Programmez! + Tous les numéros de Technosaures
Option : accès aux archives + accès aux archives + Pack maker/IoT

Contenu du
* Tarifs France métropolitaine

Abonnement Pack maker / IoT


numérique automne 2021
PDF ..............................................39€ • 1 0i narB-D atch à Olimes (en oit)
• 1 écran O97x ’dk, pWuce
1 an D 10 numéros • 1 mini-planche E pain
(6 numéros + 4 hors séries)
• 1 capteur humiàité ( Wl)
Souscription uniquement sur
[Link] (*) Valable uniquement en France métropolitaine.
Dans les limites des stocks disponibles. Ces offres peuvent s’arrêter à tout moment. Pas de documentation.

Toutes nos offres sur [Link]


ABONNEMENT à retourner avec votre règlement à :

Oui, je m’abonne PROGRAMMEZ, Service Abonnements


57 Rue de Gisors, 95300 Pontoise
n Abonnement 1 an : 49 € n Abonnement 1 an : 59 € n Abonnement 2 ans : 89 €
n Abonnement 2 ans : 79 € Programmez! + Pack maker/IoT Programmez! + Pack maker/IoT
n Abonnement 1 an : 79 € n Abonnement 2 ans : 99 €
PROG 249

n Abonnement 1 an Etudiant : 39 € Programmez! + Tous les numéros Programmez! + Tous les numéros

n Option : accès aux archives 19 €


Photocopie de la carte d'étudiant à joindre de Technosaures + accès aux archives
Offres pouvant s'arrêter à tout moment, sans préavis

de Technosaures + accès aux archives


+ Pack maker/IoT + Pack maker/IoT

n Mme n M. Entreprise : I___I___I___I___I___I___I___I___I___I___I Fonction : I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I

Prénom : I___I___I___I___I___I___I___I___I___I___I___I___I___I Nom : I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I

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

Code postal : I___I___I___I___I___I Ville : 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

Adresse email indispensable pour la gestion de votre abonnement


E-mail : 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
043.qxp_249 18/10/2021 16:17 Page43

tique Boutique Boutique Boutique Bou


Les anciens numéros de
Le magazine
à remonter
le temps !

N°1

N°2

N°3
235

236

238

239
HS 01 été 2020

N°4

N°5
240

241

242

N°6
N°7
+
HS 04 été 2021

N°8

Commandez
directement sur
246

247

248

Tarif unitaire 6,5 € (frais postaux inclus)


[Link]

n 235 : I___I ex n 240 : I___I ex n 246 : I___I ex Commande à envoyer à :


n 236 : I___I ex n 241 : I___I ex n 247 : I___I ex Programmez!
n 238 n HS1 été 2020 n HS4 été 2021
PROG 249

: I___I ex : I___I ex : I___I ex 57 rue de Gisors


n 239 : I___I ex n 242 : I___I ex n 248 : I___I ex 95300 Pontoise

€ = I___I___I___I___I € .............................I___I___I___I___I € €
Offres pouvant s'arrêter à tout moment, sans préavis

soit I___I___I exemplaires x 6,50 soit au TOTAL = I___I___I___I___I___I

n M. n Mme n Mlle Entreprise : I___I___I___I___I___I___I___I___I Fonction : I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I

Prénom : I___I___I___I___I___I___I___I___I___I___I___I___I___I Nom : I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I___I

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

Code postal : I___I___I___I___I___I Ville : 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

Règlement par chèque à l’ordre de Programmez ! I Disponible sur [Link]


040_046.qxp_249 18/10/2021 16:14 Page44

Analysis propose des pistes d’améliorations à travers la chose. Dans cette optique, séparer les fichiers js et css du
fonction analyse des bonnes pratiques. Voyons par exemple html permet de mettre ceux-ci en cache. Optimiser en taille
la liste pour [Link] : Figure 3 les fichiers, images, pdf ou autres, et également minifier et
Ce type de checklist est utile. Car si tout le monde bien sûr compresser les fichiers qui peuvent l’être (css, js, html),
veut des pages performantes et teste que celles-ci s’affichent permet d’avoir moins de données à transférer.
bien, on ne parcourt pas systématiquement une liste d’idées Pour les cookies : comme ils sont transférés à chaque
d’améliorations. requête, leur poids s’ajoute à chaque fois. Il faut donc faire
Si on regarde dans le détail, on peut les classer selon trois attention à les conserver de petite taille. De plus les cookies,
axes, qui correspondent aux variables qui font la note. prévus pour conserver l'identité d’un utilisateur et gérer une
session de connexion, ne sont pas utiles pour récupérer des
Réduire le nombre de requêtes http fichiers statiques (images, css, js, documents PDF, …), il
Il y a une ligne dédiée « Limiter le nombre de requêtes » qui serait donc contre productif de les ajouter aux requêtes pour
s'affiche en rouge au-delà d’un certain seuil. Mais l’extension ceux-ci. On peut l’éviter en créant un sous-domaine différent,
nous suggère également d’éviter les redirections, de limiter le par exemple [Link]. En revanche, un grand nombre
nombre fichiers CSS, de ne pas télécharger des images non de noms de domaines est un signe que le site est
affichées ou d’utiliser des polices de caractères standard (déjà probablement trop complexe.
présentes sur la machine de l’utilisateur). L’utilisation des
mécanismes de cache permet également d’éviter des Économiser du temps de calcul
requêtes, en fixant une date de validité du fichier par exemple. sur le navigateur
On pourrait rétorquer qu’avec la généralisation d’http2, Enfin, certaines pratiques visent directement à limiter la
limiter le nombre de requêtes devient moins pertinent, car charge de calcul imposée au navigateur pour l’affichage de
avec cette mise à jour, il n’y a pas de surcoût à faire une la page. Des fichiers html, css ou js non valides nécessitent
requête http supplémentaire plutôt que regrouper les fichiers. plus de calcul pour que le navigateur devine ce qu’il doit
Mais un trop grand nombre de requêtes reste un indice qu’il faire. Retraiter les images côté client nécessite également des
y a peut être des améliorations possibles sur la page. ressources. Les plugins comme Flash ou Java sont aussi
plutôt lents et gourmands, mais dans le web d’aujourd’hui,
Réduire la bande passante utilisée leur utilisation est devenue très rare.
Réduire la quantité d’octets transmis permet de réduire la Cette liste est très incomplète et ne liste pas tout ce qui est
charge serveur et réseau. On pourrait se dire qu’un site web possible pour améliorer une page ou un site. Il s’agit d’un
est très petit par rapport à d’autres choses qui transitent sous ensemble des 115 bonnes pratiques d’éco conception
aujourd’hui sur internet, en particulier la vidéo ou les jeux en web6 fournies par le collectif numérique responsable, parmi
streaming. C’est vrai, mais comme on visite beaucoup de celles que l’on peut tester automatiquement. N’hésitez pas à
pages web, cela constitue tout de même une part importante aller lire le référentiel en entier, ainsi que d’autres comme la
du trafic et contribue à augmenter les besoins en checklist d’opquast ou les conseils de Google PageSpeed.
infrastructures. De plus, les actions réduisant la bande Notez aussi que satisfaire l’extension pour tout avoir en vert
passante utilisée vont aussi permettre d’avoir un site plus n’est pas le but. Il s’agit d’un outil alliant un objectif de
léger et rapide, ce qui réduira la pression au renouvellement sensibilisation et la fourniture de quelques idées
des appareils. Les mécanismes de cache du navigateur d’améliorations. Par exemple, si votre page ne sera jamais
permettent d’éviter de télécharger plusieurs fois la même imprimée par personne, passer du temps sur une CSS print
Figure 3
est sans doute inutile. Ce sera en revanche apprécié dans le
cas d’un contenu textuel.

Mobile first
Il existe une stratégie de conception et de test permettant de
valider qu’un site se comporte bien sur tous les appareils :
mobile first. L’idée est de concevoir d’abord les pages pour
des téléphones mobiles les plus contraignants en taille
d’écran ou en puissance, et aussi de concevoir pour un
réseau mobile faible, 3G voire 2G. Dans ces conditions, on
est obligé de travailler sur le poids et les performances du site
pour qu’il puisse être utilisable. On doit également se poser
des questions difficiles sur les contenus qui sont importants à
mettre en valeur et ceux qui le sont moins.
Une fois qu’on a une application qui fonctionne bien dans
ces conditions extrêmes, elle sera forcément confortable à
utiliser sur des machines plus puissantes, des écrans plus
grands, des réseaux plus performants.

(6) [Link]

44 [Link]
040_046.qxp_249 18/10/2021 16:14 Page45

Dans la pratique on peut tester avec des terminaux réels, des


téléphones anciens conservés ou achetés d’occasion par
exemple. On peut aussi utiliser des machines virtuelles,
comme les simulateurs fournis pour les développements natif
sur Android ou iOS.
Plus pratique, mais moins complet, on peut aussi utiliser le
menu dédié des outils de développement navigateur
permettant de redimensionner la page à la taille d’un écran
de téléphone mobile et de simuler une bande passante
limitée : Figure 4

Bien choisir les technologies


en fonction du contexte
Les technologies aujourd’hui à la mode dans le web sont
souvent basées sur une architecture particulière appelée
Single Page Application (SPA). On sert au client une seule
page, ainsi que du code javascript qui construira à la volée
toute l’application web à partir de requêtes AJAX, en Figure 4
modifiant le DOM. Cela se fait avec des frameworks années 90 peuvent recevoir des SMS, et ce protocole est très
javascript connus comme Angular, React ou [Link]. efficace en termes d’utilisation de ressources numériques.
Cette architecture a des avantages mais n’est pas forcément Le Low Tech Mag, magazine dédié au low-tech s’est posé la
adaptée à tous les projets. Pour une application qui sera question de ce que pourrait être un site web low-tech11. Ils
utilisée exclusivement sur des ordinateurs de bureau, qui ont construit un site web statique, c’est à dire que les pages
nécessitera beaucoup d’interactions, affichera du contenu ne sont pas générées dynamiquement par le serveur à
riche, c’est certainement un bon choix. Pour un site qui est chaque requête comme le ferait des CMS comme Wordpress
surtout composé de texte, et qui est destiné à être visualisé mais seulement une fois à la création ou mise à jour du site,
partout dans le monde, sur tout type d’appareils et de et sont de simples fichiers html sur le disque du serveur. Ils
réseaux, cela se discute. Dans la pratique, la limite entre un ont choisi de ne pas inclure de police de caractère
site web et une application web n’est pas forcément aussi additionnelle, de ne pas afficher de logo, et d’optimiser
claire, mais trancher est un choix structurant. Une agressivement leurs images avec une technique appelée
application sera toujours plus lourde qu’un site. dithering. De plus, le site n’a pas de tracking, pas de
L’utilisation de javascript a un prix : il faut du temps pour publicité, pas de cookies. Le résultat est une page
charger les scripts, et les interactions avec l’utilisateur ne sont minimaliste, plus sobre que beaucoup de pages web
possibles qu’une fois le fichier lu par le navigateur et les actuelles, mais où le contenu intéressant, l’article publié, est
scripts de départ exécutés. Il y a même des pages qui nous toujours parfaitement lisible. Et cela fonctionne sans latence
expliquent comment se passer de bibliothèques populaires sur tous les appareils.
comme moment.js7, underscore.js8, jquery9, voir même de Il y a d’autres exemples de sites internet minimalistes, qui le
javascript tout court10. sont pour différentes raisons. On peut citer Craigslist12, site
de petites annonces américain, qui a gardé le minimalisme
Le low tech web, le charme de ses premiers jours, à l’époque vital du fait des connections
du minimalisme limitées, mais aussi Wikipédia13, un des projets les plus cool
Le terme low-tech désigne des inventions et technologies de l’histoire du web et peut -être de l’humanité, dont
sobres en matériaux et en énergie, faciles à construire et à l’interface a toujours été sobre et orientée sur le contenu, ou
réparer pour n’importe qui, par exemple un four solaire ou un encore Hacker News14, que beaucoup d’entre nous utilisent.
frigo en terre cuite. Le terme a été construit par opposition à Figure 5
la high-tech, il peut donc sembler étrange de les associer.
Pour construire n’importe quel appareil high-tech, il faut des Offline first ?
alliages complexes de métaux purs, des salles blanches et Plus radical encore qu’un site minimaliste, on peut imaginer
beaucoup de savoir et de rigueur. du contenu conçu pour être consommé d’abord hors ligne.
Pourtant, on peut voir certaines technologies numériques L'utilisateur accède à une page, la télécharge, puis la lit,
comme low-tech : elles paraissent désuètes ou obsolètes, l’utilise une fois déconnecté, par exemple en situation de
mais elles fonctionnent partout depuis longtemps, et mobilité, dans un train, ou encore pendant un week-end de
nécessitent peu de ressources. C’est le cas par exemple du camping, comme un livre.
SMS : tous les téléphones, même ceux fabriqués dans les Ce modèle implique des pages plus grandes en termes de

(7) [Link] (11) [Link]


(8) [Link] (12) [Link]
(9) [Link] (13) [Link]
(10) [Link] (14) [Link]

[Link] 45
040_046.qxp_249 18/10/2021 16:14 Page46

Figure 5
Hacker News -
site de partage implique toute l’équipe : les designers qui vont penser les
de liens centrés écrans et leurs enchaînements, les graphistes qui vont réaliser
autour de la
technologie peut les maquettes et surtout les décideurs qui choisiront les
être considéré fonctionnalités, lesquelles inclure, leur nature, les modes
comme minima- d’interactions.
liste et low-tech
avec ses 7 N’hésitons pas à parler avec le reste de notre équipe de ces
requêtes http et problématiques : l’impact du numérique sur le monde,
moins de 20ko l’intérêt de faire léger et simple.
transférés.
Exemples de sites éco conçus
Avec la popularité croissante de l’écoconception web depuis
quelques années, des développeurs et designers ont déjà
construit des sites explicitement éco conçus. On y trouve le
site du Low Tech Magazine déjà évoqué,ou encore le portail
des services du gouvernement du royaume uni,
[Link] , volontairement minimaliste, mais aussi des
sites plus esthétiques, où rien ne laisse penser qu’ils sont low
tech, comme celui de la fabrik à vrac, épicerie bio. Figure 6
On peut donc parfaitement construire un site léger, beau et
très fréquenté.

Conclusion : de l'écoconception web


vous en faites déjà, et vous pouvez en
faire plus !
Vous vous êtes peut-être fait la réflexion en lisant cet article
que l’on énumère en fait beaucoup de bonnes pratiques que
vous connaissez déjà. L’écoconception web n’est pas quelque
chose de radicalement nouveau, mais une autre façon de
voir et de promouvoir un web léger, largement compatible et
accessible, centré sur l'utilisateur et ses besoins.
En fait les bonnes pratiques convergent :
• En construisant des applications plus légères, on fait des
économies de ressources serveur et réseaux et donc des
économies d’argent.
• Les utilisateurs seront plus satisfaits d’utiliser un site léger
et performant, simple et ergonomique, et reviendrons
volontiers sur le service.
• En se focalisant sur le contenu, en priorisant le texte, en
faisant plus simple, on améliore l’accessibilité.
• La mise en avant du texte est aussi bonne pour le SEO
(Search Engine Optimisation, l'optimisation de la position
du site dans les moteurs de recherche). La performance du
Figure 6 site fait également partie des aspects pris en compte par les
moteurs pour choisir les sites qu’ils vont mettre en avant.
contenu, mais moins de pages et d’interactions, donc moins Toutes ces pratiques permettent aussi de réduire les
de requêtes, de charge serveur, et aussi une plus forte fractures numériques.
incitation à l’optimisation et à se limiter au contenu utile. En effet, tout le monde n’a pas accès au web dans les mêmes
conditions, pour différentes raisons. Cela peut-être à cause de la
La nécessité d’un design adapté géographie : il y a des endroits en France et dans le monde où
Il est difficile, pour un développeur, de construire un site léger les réseaux, mobiles ou fixes, ne sont pas très bons. Cela peut-
et performant, si ses collègues ont conçu une application être aussi une question de génération, les gens plus âgés étant
web chargée d’un grand nombre d’images, d’animations, souvent moins à l’aise avec la technologie, ou bien une question
avec une expérience utilisateur laborieuse impliquant sociale, avec des personnes qui ont du mal avec des tâches
beaucoup d’écrans, avec beaucoup de fonctionnalités dont complexes comme déclarer ses impôts et pour qui cela sera
certaines sont peu utiles. Même très optimisée, une encore plus difficile en ligne. Typiquement, les gens peu à l’aise
application web trop grosse sera toujours trop grosse. avec le numérique ne vont pas se procurer des appareils dernier
L’écoconception web est d’abord la conception d’un service cri, qui représentent un certain investissement. Donc pour eux ce
rendu à des utilisateurs via un site web, et ne s’arrête pas à sera encore plus lent. En construisant des sites plus légers et
appliquer des bonnes pratiques de performances web. Elle ergonomiques, nous contribuons à réduire ces fractures.

46 [Link]
047_051.qxp_249 18/10/2021 16:38 Page47

Mesurer la consommation
d’énergie d’une application en
développement avec Scaphandre Benoit Petit
bpetit@[Link]
J’ai travaillé comme
Ingénieur systèmes et
Les conséquences du réchauffement climatique sont de plus en plus perceptibles cloud avant de créer
(inondations en Allemagne, records de chaleurs…). Plusieurs secteurs de l’économie Hubblo : pour aider les
entreprises à mesurer,
entament leur introspection afin de réduire leurs émissions de gaz à effet de serre. L’IT comprendre et réduire
ne fait pas exception, ce qui est heureux. On s’entend assez facilement l’impact de leurs services
numériques sur le
sur le fait qu’il faut mesurer son impact et le comprendre pour pouvoir le climat. Hubblo est à la
fois un éditeur de
réduire. Mais comment mesurer l’impact de ses applications et services, logiciels libres d’aide à la
quand on est impliqué dans une équipe de développement ? Comment mesure d’impact et un
intégrateur. Je suis
être plus sobre dans nos métiers ? Nous allons vous donner des élé- membre de Boavizta, un
ments de réponses avec Scaphandre. groupe de professionnels
qui œuvrent pour des
Scaphandre est un agent de monitoring dédié aux métriques Documentation : [Link] méthodes et des
données ouvertes pour
de consommation d’énergie. Il permet de mesurer la Site web d’Hubblo : [Link] aider à la mesure de
consommation d’électricité d’un serveur et des services qui y Projet Vegeta : [Link] l’impact des services IT
sont hébergés. La consommation de chaque processus systè- sur l’environnement. Je
me est mesurée, ce qui permet d’identifier des axes Le cas d’usage suis également
d’amélioration au niveau applicatif. Prenons l’exemple d’une API qui est sollicitée par un grand formateur pour la
sobriété numérique des
L’outil fonctionne pour le moment sur les plateformes sui- nombre d’utilisateurs sur des périodes clés. Le code serveur de infrastructures chez The
vantes : cette API sera vraisemblablement distribué sur plusieurs Green Compagnon.
• les serveurs bare metal sous GNU/Linux (le test pour cet ar- machines, voire dans des conteneurs répartis sur plusieurs
ticle est lancé sur un laptop sous GNU/Linux) machines à l’aide d’un scheduler, de manière à pouvoir
• des machines virtuelles lorsque l’agent est également ins- déployer ou retirer des conteneurs et éteindre ou allumer des
tallé sur l’hyperviseur (Qemu/KVM pour le moment) machines en fonction des pics de charge. On peut donc absor-
• Docker/Kubernetes ber des pics de charge et limiter la consommation de ressource
Figure 1 lorsque les besoins sont moindres (ce qui est une excellente pra-
L’outil, sous licence Apache 2.0, est extensible. Son architec- tique). Cependant, la consommation de ressources peut être
ture permet d’y ajouter des modules pour s’adapter à de nou- importante lors d’un pic de charge, ce qui n’est ni bon pour le
velles solutions de monitoring ou de traitement de données. porte-monnaie (surtout dans le cloud) ni pour la planète.
La philosophie de l’outil est de s’adapter à l’existant et non Quoi de mieux pour s’assurer que l’impact de l’application
l’inverse. On peut aujourd'hui associer scaphandre à une lors des pics de charge ne sera pas de plus en plus important
base de données orientée temps de type Prometheus ou de version en version, que de mesurer sa consommation
Warp10, ou une solution de stream comme Riemann. Il est d’énergie pendant un test de charge, avant le déploiement ?
également possible de récupérer les données dans des
fichiers JSON pour un post-traitement ou pour utiliser les Outillage
données de Scaphandre pour une application avancée Nous allons prendre le cas d’une application Python/Flask
(qualscan en est un exemple en permettant de mesurer la (très basique), que nous allons solliciter à l’aide de l’outil de
consommation d’énergie de l’installation des dépendances test de charge Vegeta. Nous mesurerons les effets de ces tirs
d’un projet NodeJS). Figure 2 de charge avec Scaphandre, stockerons les données dans
Code : [Link] Prometheus et afficherons les données avec Grafana pour
Figure 2

Figure 1
[Link] 47
047_051.qxp_249 18/10/2021 16:38 Page48

analyse. Pour une plus grande simplicité nous utiliserons doc- [Link] :
ker-compose pour piloter ces outils et jouer le scénario. apiVersion: 1

Le setup providers:
Voici à quoi ressemble le dossier courant :
├── app
. # <string> an unique provider name. Required

│ ├── [Link]
- name: 'Scaphandre examples'

│ └── Dockerfile
# <int> Org id. Default to 1

├── [Link]
orgId: 1

├── grafana
# <string> name of the dashboard folder.

│ ├── [Link]
folder: 'scaphandre'

│ ├── [Link]
# <string> provider type. Default to 'file'

│ ├── Dockerfile
type: file

│ └── [Link]
# <bool> disable dashboard deletion

├── prom
disableDeletion: true

│ ├── Dockerfile
# <bool> allow updating provisioned dashboards from the UI

│ └── [Link]
allowUiUpdates: false

├── [Link]
options:

└── vegeta
# <string, required> path to dashboard files on disk. Required when

└── Dockerfile
using the 'file' type
path: /var/lib/grafana/dashboards
Le dossier app contient l’application [Link] # <bool> use folder names from filesystem to create folders in Grafana
foldersFromFilesStructure: true
# save this as [Link]
from flask import Flask [Link]
# config file version
app = Flask(__name__) apiVersion: 1

@[Link]("/")
def fibo(): datasources:
response = "\n la suite fibonacci est : " # <string, required> name of the datasource. Required
response += str(fibonacci(30)) - name: Prometheus-scaph
return response # <string, required> datasource type. Required
type: prometheus
def fibonacci(n): # <string, required> access mode. direct or proxy. Required
if(n <= 1): access: proxy
return n # <int> org id. will default to orgId 1 if not specified
else: orgId: 1
return (fibonacci(n-1) + fibonacci(n-2)) # <string> url
response = "" url: [Link]
for i in range(n): isDefault: true
response += str(fibonacci(i)) version: 1
return response+", " # <bool> allows users to edit datasources from the UI.
et un Dockerfile, que voici : editable: true

FROM python
Dockerfile :
FROM grafana/grafana
RUN pip3 install -U Flask

COPY . .
COPY /[Link] /etc/grafana/provisioning/datasources/
COPY /[Link] /etc/grafana/provisioning/dashboards/
CMD ["flask", "run", "-h", "[Link]"]
COPY /[Link] /var/lib/grafana/dashboards/
On affiche donc la suite de Fibonacci à chaque nouvelle
Le dossier prom contient la configuration prometheus, pro-
requête, jusqu’à 30. Rien de plus simple, on se contente d’une
[Link] :
application web sans connexion à une base de données ou
# my global config
autre (mais l’exercice peut très bien se répéter avec quelque
global:
chose de plus complexe). Le dossier grafana contient un
scrape_interval: 10s # Set the scrape interval to every 15 seconds.
Dockerfile et des configurations de base pour installer le dash-
Default is every 1 minute.
board par défaut et se connecter à la datasource Prometheus.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default

48 [Link]
047_051.qxp_249 18/10/2021 16:38 Page49

is every 1 minute. l’on souhaite utiliser, ici prometheus (Une section dédiée aux
# scrape_timeout is set to the global default (10s). sensors et aux exporters scaphandre est présente dans la
documentation).
# Attach these labels to any time series or alerts when communicating with L’option --containers indique à scaphandre que l’on veut sur-
# external systems (federation, remote storage, Alertmanager). veiller les conteneurs présents sur la machine et appliquer des
external_labels: labels en rapport sur les métriques de consommation d’éner-
monitor: 'scaphandre-monitor' gie. Nous y reviendrons. Comme nous l’avons évoqué plus
haut, scaphandre peut adopter un comportement différent
# Load rules once and periodically evaluate them according to the global en fonction de la base de données de série temporelle ou de
'evaluation_interval'. la solution de monitoring que l’on adresse. Ici, on utilise l’ex-
rule_files: porter prometheus. Tous les conteneurs peuvent discuter à
# - "[Link]" travers le réseau “lab-network”. Tous les fichiers pour ce test
# - "[Link]" sont disponibles sur github : [Link]
tions/tree/master/article-programmez-09-2021
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself. Premier test
scrape_configs: Grâce au docker-compose, nous allons pouvoir jouer le scé-
# The job name is added as a label `job=<job_name>` to any timeseries nario de test très simplement :
scraped from this config. docker-compose up -d
- job_name: 'prometheus'
Une fois lancé nous devrions avoir les conteneurs suivants :
# metrics_path defaults to '/metrics' CONTAINER ID IMAGE COMMAND
# scheme defaults to 'http'. CREATED STATUS PORTS NAMES
0de3ec310881 article-programmez-09-2021_vegeta
static_configs: "/bin/bash -c 'sleep…" 2 seconds ago Up Less than a second
- targets: ['localhost:9090'] article-programmez-09-2021_vegeta_1
3afaa56604dc article-programmez-09-2021_app "flask run -h
- job_name: 'scaphandre' [Link]" About an hour ago Up About an hour [Link]:5000-
# metrics_path defaults to '/metrics' >5000/tcp article-programmez-09-2021_app_1
# scheme defaults to 'http'. 71ada46d0bcf article-programmez-09-2021_prometheus
"/bin/prometheus --c…" 2 hours ago Up 2 hours
static_configs: [Link]:9090->9090/tcp article-programmez-09-2021_prometheus_1
- targets: ['scaphandre:8080'] 57573fa6e388 hubblo/scaphandre:build-PR_84-docker-labels-9
"/usr/local/bin/scap…" 2 hours ago Up 2 hours
Nous voyons à la dernière ligne de la configuration que sca-
[Link]:8080->8080/tcp article-programmez-09-2021_scaphandre_1
phandre fournit les données à prometheus en pull mode
1cf7a95368e2 article-programmez-09-2021_grafana "/[Link]"
(c’est prometheus qui vient “scraper” les données pour les
8 hours ago Up 8 hours [Link]:3000->3000/tcp
stocker en base), soit le mode classique. Dans le langage
article-programmez-09-2021_grafana_1
Prometheus, scaphandre est un exporter.
Le dossier prom contient aussi le Dockerfile suivant : Grafana est alors accessible sur [Link] Les identi-
fiants sont admin / secret. Figure 3
FROM prom/prometheus
Le premier graphe en haut à gauche représente la consom-
mation d’énergie instantanée de puissance de la machine (en
Watts), celui à sa droite représente la consommation d’éner-
COPY /[Link] /etc/prometheus/[Link]
gie sur la période de temps sélectionnée (en Watts-heure). Le
Pour finir, voici le docker-compose qui nous permet de mettre graphe du dessous est la consommation par socket CPU. Figure 3
tout ce petit monde à l’unisson :
Code complet sur [Link] & github
Attardons-nous sur la ligne de commande du conteneur
vegeta : /bin/bash -c 'sleep 10 && echo "GET [Link] |
vegeta attack -duration=200s -rate=500 | tee [Link] | vegeta report'
On demande à “vegeta” de jouer la requête GET pendant
200 secondes, à un rythme de 500 requêtes par seconde,
puis de nous afficher le résultat du test. La ligne de comman-
de du conteneur scaphandre (["prometheus", "--containers"])
ressemblerait à celle-ci si l’on lançait scaphandre directe-
ment dans le terminal : scaphandre prometheus --containers
Le premier verbe est l’exporter choisi, soit le connecteur spé-
cifique à la solution de stockage et d’analyse de données que

[Link] 49
047_051.qxp_249 18/10/2021 16:38 Page50

Puisque je n’ai qu’une socket CPU sur la machine qui me per- Voyons ce que change en termes de consommation d’éner-
met de lancer le test, c’est exactement le même graphe qu'au- gie le fait de passer à une boucle simple :
dessus. Le dernier étage donne la consommation d’énergie Code complet sur [Link] & github
par processus, avec à gauche, un top des processus les plus Une fois le code remplacé, on peut reconstruire l’image du
gourmands en énergie en ce moment et à droite l’historique conteneur de l’app :
de consommation de puissance par processus, sur la fenêtre
docker-compose build app
de temps. Lorsque l’on arrive la première fois sur le dash-
board, le graphe en bas à droite donne la consommation de
Puis relancer le test :
tous les processus collectés. On peut alors filtrer pour obtenir
docker-compose up -d
uniquement la consommation de notre application en saisis-
sant un mot clef dans la case “process_filter” en haut. En sai- Et constater l’effet de ce nouveau tir de charge : Figure 5
sissant “flask”, on va avoir la consommation des processus On relève maintenant comme maximum 4,34W et en valeur
qui contiennent “flask” dans leur ligne de commande et ainsi moyenne 2,27W. Cette version du code est donc à priori
isoler la consommation de notre application durant le test. moins énergivore que la précédente. Notons tout de même
Une fois le test terminé on peut sélectionner la fenêtre de que ce test est extrêmement rudimentaire et qu’il faudrait
temps exact du test en cliquant et en faisant glisser le curseur valider cette affirmation avec des scénarios de tir de charge
au niveau du graphe de consommation. Figure 4 différents (et valider ça avec un serveur d’application bon
Grafana nous donne gentiment quelques stats sur cette pour de la production, comme gunicorn).
fenêtre. L’application a consommé au maximum 5,16W et en
moyenne 3,01W. Ces chiffres permettent un premier exemple Relever la consommation de conte-
de comparaison avec des versions ultérieures de l’application. neurs appartenant à un même service
Nous avons vu dans cet article l’option --containers. Voyons
Mise à jour de l’application et second test dans la pratique à quoi elle sert.
Vous aurez certainement reconnu dans le code de notre Lorsque notre application passera en production, nous aurons
application une recursion : certainement un nombre important de conteneurs, derrière
un load balancer, pour tenir la charge. Si l’on souhaite mesu-
# save this as [Link]
rer la consommation d’énergie de l’application dans ce
from flask import Flask
contexte, il faudra accéder à cette information pour chaque
conteneur participant au service. C’est là que l’option est
utile, Scaphandre va alors appliquer des labels spécifiques aux
app = Flask(__name__)
métriques de consommation de chaque processus, lorsque
celui-ci est conteneurisé. Voici à quoi ressemble la métrique
@[Link]("/")
de consommation de notre application vu par prometheus (et
def fibo():
visible sur [Link] dans notre exemple) :
response = "\n la suite fibonacci est : "
response += str(fibonacci(30)) scaph_process_power_consumption_microwatts{container_docker_version="20.
return response 10.2",container_label_com_docker_compose_service="app",container_lab
el_com_docker_compose_config_hash="a2cc6462a0ba2ab59f230d5ea16fe54c38
def fibonacci(n): 666124dfc27f56f5789f0cf314a2bf",container_names="article-programmez-09-
if(n <= 1): 2021_app_1",container_label_com_docker_compose_oneoff="False",container
return n _id="27f3159ee70707d74f5da09468c1076abba719ca3b97bb1f60907f184
else: 8569df9",container_label_com_docker_compose_version="1.25.0",exe="flask",
return (fibonacci(n-1) + fibonacci(n-2)) container_scheduler="docker",pid="851283",container_label_com_docker
response = "" _compose_container_number="1",container_label_com_docker_compose_project
for i in range(n): _working_dir="/home/bpetit/git/hubblo/formations/article-programmez-09-
response += str(fibonacci(i)) 2021",container_label_com_docker_compose_project_config_files="docker-
return response+", " [Link]",container_label_com_docker_compose_project="article-programmez
Figure 4
-09-2021",cmdline="/usr/local/bin/python/usr/local/bin/flaskrun-h0.0.0.0"} 0

Les éléments en gras sont les labels appliqués par Scaphandre


à la métrique de manière à simplifier son exploitation dans un
contexte plus complexe, comprenant par exemple plus de
conteneurs pour le même service. Container_label_com_docker_
compose_service nous permet de filtrer les données de cette série
Figure 5
temporelle (scaph_process_power_consumption_microwatts,
donc la consommation d’un processus) par nom de service
docker-compose. Avec ce label on peut récupérer dans le
même résultat la consommation de tous les conteneurs qui
appartiennent à un service, ici “app”.
Container_scheduler nous montre que Scaphandre a bien détec-

50 [Link]
047_051.qxp_249 18/10/2021 16:38 Page51

té le démon docker et donc est capable d’aller chercher des d’autres éléments qui parfois pèsent encore plus lourd dans
informations supplémentaires sur chaque processus associé le bilan carbone. La consommation d’électricité est indirecte-
à un conteneur. Kubernetes devrait être également supporté ment responsable d’émissions de Gaz à Effet de Serre (GES),
à la fin de l’été 2021. Ajoutons un panel dans le dashboard car c’est une énergie dite secondaire, ou finale, par opposi-
grafana pour illustrer, soit en cliquant sur le bouton “Add tion aux énergies primaires (charbon, vent, rayons du soleil,
Panel”, soit en dupliquant le panel qui montre la consomma- pétrole, éléments radioactifs…) qui sont consommées pour la
tion de flask, avec “Duplicate” : Figure 6 fabriquer. On peut effectuer la conversion en émissions de
Une fois fait, il faut changer la formule utilisée avec Edit, sur GES, grâce aux données présentées sur un service comme
le nouveau panel. Figure 7 ElectricityMap. Ces émissions sont classées dans le “scope 2”
Notre requête est constituée de : des émissions, celui des émissions indirectes.
• scaph_process_power_consumption_microwatts : le nom Le “scope 1” représente les émissions directes. Dans le cas
de la métrique qui nous intéresse d’un service IT, peu de choses sont classées dans le scope 1.
• container_label_com_docker_compose_service : le label Une exception, dans le cas d’un exploitant de datacenter, serait
qui nous permet d’identifier les données qui nous intéres- le fioul brûlé lors d’une coupure générale d’électricité malgré la
sent, ici ce sont celles avec la valeur “app” redondance des arrivées électriques (ou lorsque ce fioul est
Notons que l’on divise le résultat par 1 000 000, car la considéré périmé et qu’il est brûlé pour être remplacé…).
métrique nous retourne des microwatts. Une valeur en micro- Le troisième et dernier scope, le “scope 3”, représente les
watts n’est pas très explicite pour ma part, je préfère lire les autres émissions, notamment celles qui sont liées à la fabri-
données en watts pour mieux me représenter les choses. cation des équipements, à leur transport et à leur fin de vie.
Les informations nécessaires pour calculer ce dernier scope
Conclusion sont souvent plus compliquées à obtenir et même parfois dé-
Cet article est une première approche de l’utilisation de libérément écartées (ce qui arrange bien les entreprises qui
Scaphandre, pour mesurer la consommation d’énergie d’un affirment être “neutre en carbone”).
service. Il est possible de décliner l’usage de cet outil à de Mesurer la consommation d’énergie est donc une bonne
nombreux autres cas. Les seuls pré-requis au moment où chose pour un service plutôt gourmand sur sa phase de run
j’écris ces lignes, sont d’ tre sur une machine physique, sous (web à haute volumétrie, machine learning, recherche,
GNU/Linux, ou bien sur une machine virtuelle, si Scaphandre média, etc.). C’est un indicateur qui permet d’orienter ses
est également installé sur l’hyperviseur et que l’on utilise l’op- efforts de sobriété dans le développement d’une application
tion --vm (voir la documentation). ou l’évolution d’une infrastructure IT. Il reste cependant indis-
Notre exemple est imparfait, car on lance les tirs de charge pensable, si l’on souhaite réduire efficacement et durable-
depuis la même machine que celle qui fait tourner l’applica- ment les émissions d’une entreprise, d’adopter une
tion. Pour obtenir des métriques plus “propres”, il serait démarche plus globale et de prendre en compte le scope 3
mieux d’utiliser deux machines différentes. Il serait égale- des émissions dans la stratégie et dans les calculs.
ment intéressant d’intégrer cette suite dans la chaîne de CI,
pour garantir un suivi de l'appétit du service en énergie et ça
de version en version, systématiquement, pour chaque contri-
bution de l’équipe de développement.
Enfin il faut prendre un peu de recul pour préciser que ces
métriques de consommation d’énergie ne sont qu’une partie
des informations nécessaires pour connaître l’impact d’un
service numérique sur le climat. C’est certainement la partie
la plus accessible pour un profil technique en termes de res-
ponsabilités, mais une analyse d’impact complète comprend
Figure 6

Figure 7

[Link] 51
052_053.qxp_249 18/10/2021 16:38 Page52

L’éco-conception au service d’un


numérique plus responsable
Vincent L’objectif de cet article est de présenter les principaux enjeux et leviers théoriques d'une
FRATTAROLI
CEO, Inside|app
démarche d’éco-conception technique, que nous illustrerons avec un retour d’expérience
concret mené chez Meetic. Nous allons faire un focus particulier sur les apps mobiles.
L’éco-conception technique consiste à concevoir son archi- Règle #4 : utiliser de préférence les API et composants
tecture technique et produire des codes les moins natifs de l’OS
consommateurs d’énergie possibles, ce sur l’ensemble de la Apple et Google font évoluer les API et composants UI
chaîne technique : Serveurs & datacenter - Réseau Télécom - fournis aux développeurs. ils sont moins consommateurs de
Terminal de l’utilisateur. Pour des développeurs frontend (web / CPU et mémoire que les librairies tierces ou composants
François app), il s’agit de jouer sur trois leviers : développés spécifiquement.
RÉZENTHEL Règle #5 : favoriser le dark mode
Directeur de production,  Optimisation de la chaîne complète Il permet de réduire la consommation de batterie 5 à de 42%
Meetic L’optimisation des échanges clients / serveurs va concerner selon la luminosité paramétrée.
aussi bien les applications web et les applications mobiles. Règle #6 : préférez le développement natif
Elle sera de plus bénéfique pour toute la chaîne technique Les technologies Cross-Platform mobiles React Native,
(serveur - réseau - terminal). Flutter sont plus consommatrices d’énergies (surtout Cordova
Réduire les volumes de données et le nombre de requêtes et React Native) que les développements natifs Kotlin et
échangées entre les clients et les serveurs est la principale source Swift. Sur ce sujet, vous pouvez lire ce post très inéressant :
de réduction de l’empreinte carbone d’un service numérique. [Link]
Règle #1 : une conception des web services Front et Back ce-comparison-990b90c11433
Une application sobre requiert une conception des web services
par les Front et Back : découpage des appels, chargement des  Réduire la taille du package des
données utiles uniquement, règles de cache : la vision “Front” est Applications
primordiale pour optimiser l’API. Les Apps mobiles (et dans une moindre mesure les Web App)
Règle #2 : Ne pas négliger les briques tierces fonctionnent avec des mises à jour régulières, qui génèrent
Dans le cas de Meetic, nous avons constaté que les des volumes de données sur le réseau.
partenaires tiers (publicité, tracking) généraient parfois plus Là encore il existe plusieurs leviers pour 1) réduire au
de 30% des volumes de données. Il faut ainsi intégrer cette maximum la taille des Apps et 2) réduire le volume des
dimension de sobriété dans le choix d’un éditeur et prendre données téléchargées lors des mises à jour.
soin de l’intégration des leurs SDK/API. Règles #7 - Optimiser le packaging de son Application
Les autres actions possibles pour minimiser les échanges Le téléchargement des mises à jour se fait en différentiel d’une
serveur - terminal version à l’autre. En organisant bien son App et en ne modifiant
• utiliser graphQL qui permet de limiter les échanges client- que les fichiers et assets graphiques nécessaires, on réduit
serveurs couplé à une bonne gestion du cache HTTP sensiblement le volume téléchargé lors d’une mise à jour.
• utiliser des formats d’images ou vidéos optimisés pour Règles #8 - Limiter les dépendances tierces
chaque OS/plateforme (par exemple HEIC pour les iPhone, Les dépendances concentrent une part importante du poids
deux fois plus performants que JPEG) d’une App. Il faut se demander si l’on tire pleinement partie
• si votre app doit régulièrement télécharger des contenus de chaque dépendance ou si, tout simplement, on en a
volumineux, il est préférable que ceux-ci soient téléchargés vraiment besoin. Exemple sur iOS : si votre application
lorsque le smartphone est connecté en WiFi et non 3/4/5 G (les effectue peu d’appels réseaux GET, il n’est probablement pas
réseaux mobiles sont plus énergivores que les réseaux fixes/Wifi) utile d’intégrer une librairie réseau, iOS fournissant
suffisamment de solutions.
 Minimiser la consommation de Règles #9 - Utiliser le bitcode sur iOS
CPU/mémoire sur le terminal Le bitcode est une représentation intermédiaire d’un
Cet aspect est important pour les smartphones : au-delà de programme compilé. C’est un format à mi-chemin entre le
la consommation d’électricité pour recharger une batterie code source et le code machine. Les applications iOS qui
trop sollicitée par une app, on va réduire l’espérance de vie activent le bitcode vont être recompilées par l’App Store, une
de la batterie. Or la batterie est dans 40% des cas le premier fois l’upload effectué.
motif pour changer de smartphone. À l’instar du slicing, qui va supprimer les assets qui ne sont
Règle #3 : limiter le fonctionnement en background pas destinés à notre appareil, le bitcode va permettre de
Le fonctionnement en arrière-plan peut présenter des bénéfices supprimer le code compilé qui n’est pas utile pour
utilisateurs forts, mais aussi générer une surconsommation l’architecture de notre appareil.
inutile. L’utilisation du GPS doit être limitée au strict nécessaire. On peut ainsi espérer gagner jusqu’à 50%, sur la taille du binaire.

52 [Link]
052_053.qxp_249 18/10/2021 16:38 Page53

Rex : les services Meetic


Actions
Dans une démarche responsable entamée depuis plusieurs années, entreprises par
Meetic, le leader de la rencontre en ligne, s’est engagé à réduire Meetic afin de
son empreinte carbone de 10% tous les ans. Un plan d’actions est mesurer et
améliorer le bilan
déjà lancé pour réduire l’impact écologique de son infrastructure carbone de
informatique. Meetic souhaitait aller plus loin, en évaluant l’impact l’entreprise
global de ses services web et apps sur son bilan carbone et
optimiser celui-ci. Meetic, accompagnée d’inside|app, a donc
lancé un plan en quatre phases pour mesurer et optimiser le
bilan carbone de ses services année après année.

Phase 1 : Compter et évaluer


Nous avons tout d’abord établi le bilan carbone des services
Meetic (site web, site web mobile, app iOS, app Android) en
se basant sur les données d’usages.
Schématiquement, nous avons calculé l’ensemble des Go Piste #4 : Aligner certains appels WS
générés par les utilisateurs sur toute la chaîne (du terminal au Nous avons constaté que deux applications utilisaient une API
serveur) et donné un équivalent en tonnes de CO2 à ce trafic. ancienne, plus verbeuse et génératrice d’appels que la version
Nous avons ainsi constaté que 90% des impacts étaient liés plus récente. En migrant sur la nouvelle API on pouvait ainsi
sur la partie ”Sessions utilisateurs”, 10% sur la partie réduire les volumes et faciliter la maintenance des applications.
téléchargement des applications et mises à jour. Nos efforts Ces quatre premières pistes, pouvant être rapidement
se sont donc concentrés sur la partie “Sessions”. mises en œuvre, nous permettent une baisse de près de
20% de l’empreinte carbone de ces services.
Phase 2 : Amélioration des requêtes Dix autres actions à plus ou moins long terme ont été
Meetic appliquait déjà la majorité des bonnes pratiques listées identifiées et seront évaluées dans les mois à venir.
précédemment pour des enjeux de qualité de services et
d’optimisation des coûts d’infrastructure. Nous avons donc Phase 3 : Compensation carbone
voulu valider l’impact de ces bonnes pratiques, et corriger les Les collaborateurs volontaires ont pû participer en mai 2021
éventuels défauts d’implémentation. Nous avons observé les à une première action de reboisement en région parisienne,
requêtes et données transitant sur le réseau sur les quatre afin d’absorber une partie des émissions de carbone
applications (2 Web et 2 mobiles) avec Charles Proxy, et générées par l’activité de l’entreprise et de ses utilisateurs.
cherché à comparer les appels réseaux et volumes de données
transitant sur trois parcours types. Notre idée était simple : Phase 4 : Sensibilisation interne et plan à
• iOS et Android devaient présenter des volumes de données long terme
et requêtes très proches Une grande partie de notre travail a consisté à sensibiliser les
• le web mobile devait être moins gourmand que le web desktop équipes sur ces enjeux de sobriété numérique, via des
• nous voulions détecter des éventuels problèmes de présentations, un hackathon dédié sur le sujet et l’intégration
surconsommation, évaluer leurs impacts et traiter les plus de la sobriété numérique dans les indicateurs de la société et
importants dans les processus projets.

Ce que nous avons trouvé Conclusion


Piste #1 : Keep-alive sur iOS En estimant l’impact de ses services sur toute la chaîne
Le HTTP keep-alive (durée de la connexion avec le serveur) technique et pas uniquement sur ses serveurs et datacenter,
était trop court sur iOS, ce qui générait 1 Mo de Meetic s’engage dans une démarche volontariste et
surconsommation pour un type de session (overhead http). ambitieuse de réduction de son empreinte carbone.
En augmentant le keep-alive sur iOS cette surconsommation Des premières actions permettront une baisse d’environ 20%
était ainsi facilement supprimée. de l’empreinte carbone des applications sur 2021. De plus,
Piste #2 : Optimiser les appels à des tiers cette amélioration de l’impact environnemental se traduit
Le caching et l’intégration des services tiers (publicité et tracking) souvent par une amélioration des performances applicatives,
généraient trop de données, notamment sur le web mobile. ce qui est un argument de poids pour convaincre les
Piste #3 : Chargement en doublon directions métiers et améliorer l’expérience perçue par les
Sur une plateforme, une image haute résolution était utilisateurs. Ces premiers résultats sont encourageants, et
chargée en doublon par erreur, ce qui augmentait de plus de s’inscrivent dans un processus pluriannuel, sponsorisé par la
30% les données échangées sur un type de parcours. N’étant direction de l’entreprise, avec notamment la préparation de
pas un bug en soi, cette erreur avait jusque là passé tous les la certification ISO14001, permettant de valider un processus
tests qualité en interne. Ils ont depuis évolué afin de prendre d’amélioration continue dans le domaine de l’impact
en compte ce cas de figure. écologique.

[Link] 53
054_057.qxp_249 18/10/2021 16:39 Page54

Refactorer le Legacy intestable


avec les Approval Tests
Sepehr Namdar
Développeur Dans son livre, Working Effectively with Legacy Code, Michael Feathers définit un code
Techno-Agnostic legacy comme un code “non testé”. Vous connaissez les conséquences que peut être
chez Shodo
De la maintenance au avoir un code legacy. En tout bon crafter que vous êtes, vous souhaitez refactorer ce
suivi complet d’un
projet, Sepehr a une
code legacy et lui appliquer une couche de [Link] que vous êtes face à un code que
forte expertise sur toutes vous ne connaissez pas, illisible, incompréhensible et vous n’avez même pas d’expert
les phases du
développement logiciel. métier pour vous expliquer le domaine...
L’Agilité, le
Pragmatic-Driven Les Approval Tests sont là pour vous aider ! Grâce à cette li- alors cela signifie que nos modifications n’ont rien changé à
Design/Development et brairie multi-plate-forme, sécurisez la refonte de votre la logique de notre programme. Rien n’a été cassé dans
le Clean Code sont la clé
de la réussite de la application grâce à un code couvert par des tests, plus fiable notre code, on peut avancer !
réalisation d'un produit et plus sûr. La cerise sur le gâteau c’est que tout ça, c’est ra- Si le résultat diffère de l’image de départ, il faut alors revenir
logiciel. pide, très facile à apprendre et à utiliser. en arrière pour retomber sur des tests verts.
Refactorer, c’est changer la structure du code sans changer “Approval Tests” est un projet open source et une librairie qui
son comportement afin de l’améliorer et de le rendre plus facilite grandement la mise en place du Golden Master. Avec
performant et durable. Ceci peut passer par le fait de renom- les Approval Tests vous pouvez générer plusieurs cas de tests
mer un attribut, déplacer une ligne de code, extraire une afin de bien couvrir le code de production et éviter des mau-
méthode, etc. vaises surprises et tout ça en une seule ligne de code. Allez, il
Le Refactoring n’est pas une tâche dans votre “tableau de est temps de passer aux choses concrètes, avec une démons-
Scrum”, mais une pratique de développement qu’il faut faire tration !
de manière systématique. Comme dit Uncle Bob, le
Refactoring c’est comme se laver les mains. On le fait de ma- Comment ajouter Approval Tests à
nière récurrente sans le planifier ou sans y penser. notre projet ?
Refactorer un code n’a pas vraiment besoin d’outil en parti- L’ajout d’Approval Test à votre projet est très simple, il suffit
culier, mais il y a des IDE qui nous proposent des outils afin de choisir la plateforme qui vous intéresse parmi .Net, C++,
de rendre cette tâche importante plus facile. Java, Lua, NodeJS, Objective-C, Perl ou Python en passant
Mais refactorer le code nécessite un pré-requis qui est par un gestionnaire de dépendances ou en téléchargeant les
d’abord de le faire couvrir par des tests. Si on commence à packages nécessaires.
refactorer un code sans le couvrir par les tests, on n’est pas à Par exemple pour un projet Java vous pouvez utiliser Maven
l’abri de le casser et de créer des bugs. C’est malheureuse- ou Gradle pour ajouter la dépendance comme ci-après :
ment une mauvaise pratique chez beaucoup de
développeurs. Si vous voulez en savoir plus sur les différentes Maven
méthodes de Refactoring je vous conseille de lire le livre de <dependency>
Martin Fowler qui porte le même nom. <groupId>[Link]</groupId>
Écrire des tests avant de refactorer c’est bien beau, mais lors- <artifactId>approvaltests</artifactId>
qu’on ne comprend pas le code, c’est quasiment mission <version>11.2.3</version>
impossible. Pour atteindre cet objectif, on peut utiliser une </dependency>
technique qui s’appelle Golden Master.
Gradle
Qu’est-ce que la technique du Golden dependencies {
Master ? testImplementation("[Link]:approvaltests:11.2.3")
Le Golden Master consiste à envoyer des données en entrée }
(input) d'une méthode, peu importe sa taille, ses paramètres
et ses dépendances, et de collecter les réponses qu’on reçoit Mise en place du premier Approval Tests ?
(output). Pour apprendre à utiliser Approval tests, essayons d’écrire un
Après avoir collecté assez de données (lorsque le code est to- test classique en utilisant JUint et AssertJ :
talement couvert par les tests), il est temps de prendre une
image de ces résultats pour pouvoir commencer à “refacto- @Test
rer” le code. void find_first_available_recruiter_who_can_test_candidate() {
Après chaque changement de structure dans le code, on re- // Given
lance les tests avec les mêmes inputs que nous avons var interview = new PlanInterview(
collectés. Si les outputs sont identiques à l’image de départ, candidates, recruiters, interviews);

54 [Link]
054_057.qxp_249 18/10/2021 16:39 Page55

Figure 1

Maintenant il suffit d’appeler la méthode


// When “verifyAllCombinations“ d’Approval Tests pour avoir
Interview plannedInterview = [Link]("123", of(2021, 2, 21)); l'équivalent du premier test classique que nous avons écrit
plus haut.
// Then Avant de faire ça, si on regarde la signature de cette
assertThat(plannedInterview).isEqualTo(expectedInterview()); méthode, on voit qu’elle prend comme attribut une fonction
} (extracted) et un ensemble d’inputs sous forme de tableau :

La première étape sera pour nous de trouver les inputs et les public static <IN1, IN2, OUT> void verifyAllCombinations(Function2<IN1, IN2, OUT>
séparer du code. C’est facile : call, IN1[] parameters1, IN2[] parameters2) {
...
@Test }
void find_first_available_recruiter_who_can_test_candidate() {
String candidateId = "123"; Ce qui signifie que nous devons transformer nos inputs en
LocalDate interviewDate = of(2021, 2, 21); tableau pour pouvoir les utiliser. Ce qui nous donne le code
suivant :
// Given
var interview = new PlanInterview( @Test
candidates, recruiters, interviews); void find_first_available_recruiter_who_can_test_candidate() {
String[] candidateId = {"123"};
// When LocalDate[] interviewDate = {of(2021, 2, 21)};
Interview plannedInterview =
[Link](candidateId, interviewDate); verifyAllCombinations(this::extracted, candidateId, interviewDate);
}
// Then
assertThat(plannedInterview).isEqualTo(expectedInterview()); Vous allez me dire “ mais pourquoi se donner autant de mal
} pour écrire l'équivalent d’un test qui fonctionnait ? “
La réponse c’est qu'avec Approval Tests on peut lancer plein
Avec Approval Tests je n’ai pas besoin de la partie “Then”. d’inputs sur un seul test. Je vous rappelle que nos inputs sont
C’est lui qui fera ça pour moi. Je peux donc supprimer cette maintenant des tableaux de données et c’est exactement ce
partie. dont nous avons besoin pour utiliser la technique Golden
Ensuite, je vais extraire les parties “Given” et “When” pour Master.
créer une fonction à tester :
Lancement d’Approval Tests :
@Test Le première fois qu’on lance les Approvals Tests, c’est
void find_first_available_recruiter_who_can_test_candidate() { toujours rouge. C’est parce qu’on a besoin de lancer les tests
String candidateId = "123"; au moins une fois pour récolter les outputs dont on a parlé
LocalDate interviewDate = of(2021, 2, 21); pour le Golden Master.
En clair, pas d’image de comparaison = tests rouges
extracted(candidateId, interviewDate); Figure 1
} Si vous regardez dans l’arborescence de votre projet vous
allez voir que 2 nouveaux fichiers ont été générés :
private Interview extracted(String candidateId, LocalDate interviewDate) { • Un fichier nommé “received“
// Given • Un fichier nommé “approved”
var interview = new PlanInterview( Ce sont vos Golden Master : Figure 2
candidates, recruiters, interviews); Maintenant il suffit de copier le contenu du fichier “received”
dans le fichier “approved” pour passer les tests au vert. Vous
// When pouvez aussi supprimer le fichier “approved” et renommer le
return [Link](candidateId, interviewDate); fichier “received” pour “approved”. Figure 3
} Voyons voir à quel point ce premier test était efficace. Pour

[Link] 55
054_057.qxp_249 18/10/2021 16:39 Page56

cela, nous allons regarder la couverture des tests à l’aide données ou encore bien lire le code. Si ce n’est pas possible,
d’IntelliJ. Il suffit de lancer les tests avec ce bouton : essayez de mettre des données aléatoires qui vous semblent
pertinentes par exemple “null”, chaîne de caractère vide, des
Et voici le résultat : Figure 4 chiffres -1, 0, 1, etc.
On peut constater que le seul test qu’on a écrit ne couvre pas Notre test va donc ressembler à ça :
toutes les lignes de notre code, car il faut plus d’inputs. Nous
devons donc trouver plus de données. Pour ça, on peut @Test
demander l’aide d’un expert métier, ou regarder la base de void find_first_available_recruiter_who_can_test_candidate() {
String[] candidateId = {"123", "456", "789", null, ""};
Figure 2 LocalDate[] interviewDate = {
of(2021, 2, 21),
of(2021, 2, 20),
of(2021, 2, 22),
of(1300, 2, 21),
of(3200, 2, 21),
null
};

verifyAllCombinations(this::extracted, candidateId, interviewDate);


}

Lorsque vous lancez de nouveau les tests, ils apparaissent


rouges. C’est tout à fait normal ! En effet, vous venez
d’ajouter de nouveaux inputs.
On va alors copier les nouvelles données que nous avons
reçues dans le fichier “received” et les coller dans
“approved”. Les tests passeront de nouveau au vert.
Regardons maintenant la couverture du code par nos
nouveaux tests :
Parfait, le code est bien couvert par nos tests. On peut
commencer à refactorer notre code !
Maintenant, regardons un peu ce qu’on a obtenu dans le
fichier "approved" :
Figure 4
Code complet sur [Link] & github

Trop fort cet outil ! Avec 1 test et 1 ligne de code j’ai obtenu
30 tests d’un coup. Cela correspond à la combinaison de
toutes les données que je lui ai passée en input.

Prérequis de mise en place d’Approval Tests :


• Il est conseillé d’avoir l’outil WinMerge (ou un autre
comme Kdiff) pour faciliter le passage entre les fichiers
“received” et “approved” et aussi pour comparer la
différence entre les données si jamais on fait une
régression en faisant notre Refactoring : Figure 5
• Il faut implémenter la méthode toString dans tous les objets
qui vont être testés par Approval Tests. Sinon on obtient des
références à des objets et nos tests sont toujours faux :

Figure 3

56 [Link]
054_057.qxp_249 18/10/2021 16:39 Page57

@Override une journée complète de travail. Les tests sont donc utiles et
public String toString() { ne sont en aucun cas négligeables. Passer du temps à écrire
return "Candidate{" + des tests est un gain de temps pour le maintien de mes
"skills=" + skills + produits sur le long terme.
", name='" + name + '\'' +
'}'; Conseils :
} • Les Approvals Tests ne sont pas autosuffisants. Il faut créer
des tests unitaires, d’intégration, etc. pour obtenir un
REX :
résultat vraiment fiable.
Personnellement je ne m’amuse pas à refactorer du code • Il ne faut pas se fier à un code qui est couvert à 100 % par
pour me faire plaisir. Si une partie du code fonctionne les tests. Pour cela, essayez d’ajouter du “Mutation
correctement, même s’il est illisible, pas testé ou long, tant Testing”. Vous pouvez le faire à la main, en modifiant des
que je n’ai pas à le modifier, je ne vais pas le refactorer. Il faut conditions ou des valeurs dans votre code. Si après avoir
toujours garder en mémoire que le refactoring a un coût et modifié certaines logiques du code, les tests sont toujours
celui-ci n’est pas négligeable surtout lorsqu'on est face à une verts, c’est que vous n’avez pas de tests fiables.
longue méthode, par exemple. • Ne pas refactorer un code qui fonctionne correctement si
Par contre, si jamais je dois modifier ou améliorer une partie on ne doit pas lui ajouter/supprimer une fonctionnalité.
du code et que celle-ci n’est pas couverte (ou pas
complètement) par des tests j’en profite pour utiliser les FAQ :
Approval Tests. Une fois, cette partie du code couverte par • Peut-on tester une méthode qui renvoi void ? Oui, mais
des tests, je peux ensuite commencer à le refactorer, à le cela ne va pas vraiment nous aider à faire un Golden
casser en plus petits morceaux, afin de le rendre plus Master, car on n’obtient rien en output.
maîtrisable. Je vais aussi mettre en place des nouvelles • Peut-on moquer les dépendances externes ? Oui vous
classes, des méthodes et de nouveaux tests. pouvez très bien utiliser une librairie de bouchon par
Mon refactoring est terminé. Grâce à mes Approval Tests, je exemple Mockito pour Java.
sais que je n’ai rien cassé dans mon code. Je peux
maintenant commencer à les supprimer, puisque j’ai couvert Repos GIT :
mon code par d’autres types de tests (unitaires, d’intégration, • Java :
d’acceptance, etc.) [Link]
Cette procédure peut sembler coûteuse au niveau du temps. tion-1/approval_tests
Cependant, il m’est arrivé plusieurs fois de refactorer un code • C# :
non testé et de créer des bugs, voire des problèmes de prod. [Link]
J’ai donc dû revenir en arrière, ce qui m’a parfois fait perdre tree/solution-1/approval_tests

Figure 5

disponible 24/7 et partout sur Terre !

Facebook : [Link] Github : [Link]

Site officiel : [Link]


Twitter : @progmag
Newsletter chaque semaine (inscription) :
Chaîne Youtube : [Link] [Link]

[Link] 57
058_061.qxp_249 18/10/2021 19:02 Page58

Superviser votre Linux à l’aide


d’un écran LCD
Sébastien Colas Il peut s’avérer utile de pouvoir accéder à des informations de son Linux sans avoir à
Je suis formateur en
informatique depuis changer de fenêtre surtout si, par exemple, vous êtes dans une partie de jeu. Dans cet
bientôt 20 ans. Au cours
de ma carrière j’ai pu
article je vous propose donc dans un premier temps de réaliser un montage électro-
dispenser des cours sur nique très simple permettant l’affichage de tout type d’information sur un écran LCD
de nombreuses
technologies : Serveur
16x2 caractères. Ensuite nous utiliserons lcd4linux pour afficher les données qui nous
d’applications JavaEE, intéressent. Figure 1
SOA, Services Web,
Linux, Virtualisation, API Hardware
led Connectivty et
Voici les différents composants qui composeront notre projet : Par chance, le programme existe sur la plupart des distribu-
Application Network.
Sans oublier les • écran LCD 16x2 caractères Figure 2 tions. Sous Ubuntu l’installation est très simple :
langages : Java, PHP, • 1602 LCD USB Mini Drive Board Figure 3
Python, JavaScript... Je • cordon USB vers micro-USB sudo apt-get update -y
suis aussi auteur pour L’assemblage de l’écran LCD vers le convertisseur USB est sudo apt-get install -y lcd4linux
« Linux Pratique » et
extrêmement simple, à chaque PIN de l’écran LCD corres-
« Hackable » autour des
sujets Raspberry Pi, pond une PIN du convertisseur USB. Lors de l’installation un fichier de configuration a été créé
Arduino, IoT, Le gros avantage de ce montage est que l’on pourra au choix : pour nous /etc/[Link]. À des fins didactiques nous
électronique digitale et • déporter l’affichage sur le bureau à l’aide du cordon USB allons créer nous-mêmes le fichier à partir de zéro. Le but
bien sûr Linux. • Intégrer l’afficheur directement à la tour de son PC étant de couvrir les principales fonctionnalités de lcd4linux.
[Link] On pourra aussi opter pour un LCD retro-éclairé couleur. Pour ce faire nous allons afficher :
• Un simple texte
Software • La date et l’heure
Il existe différentes manières de contrôler notre LCD, ici • L’utilisation du CPU
comme nous voulons principalement afficher des informa- • La température extérieure stockée dans une base MySQL
tions systèmes en temps réel nous allons utiliser lcd4linux. accessible dans notre réseau local
• La bande passante en upload et en download de notre
Freebox à l’aide d’un script shell

Affichage d’un texte


Pour commencer créons quelques variables dans notre fichier
/etc/[Link]. Je rappelle que la modification du fichier
doit se faire en tant que root :

Variables {
Figure 1 seconde 1000
five_secs 5000
minute 60000
}

Comme on peut le constater l’unité de base est la millisecon-


de, d’où la définition de variables pour plus de simplicité.
Figure 2 Définissons maintenant la configuration de notre afficheur :

Display LCD2USB {
Driver 'LCD2USB'
Size '16x2'
Backlight 0
Icons 1
}

En l’occurrence nous avons un composant LCD2USB avec un


afficheur LCD 16x2 caractères sans rétro-éclairage. On acti-
Figure 3

58 [Link]
058_061.qxp_249 18/10/2021 19:02 Page59

ve aussi la possibilité de se créer nos propres icônes. Nous définissons donc pour chaque Widget le fait que nous
Une fois défini il faut demander à LCD4Linux d’utiliser le display : allons afficher du texte de longueur 5, qu’il faudra aligner le
texte à gauche (L : Left) et qu’il faudra mettre à jour l’infor-
Display 'LCD2USB' mation toutes les minutes pour la date et toutes les secondes
pour l’heure. Le plus important est ce que nous voulons affi-
Maintenant nous allons devoir définir ce que nous voulons cher c’est-à-dire l’expression. LCD4Linux nous permet d’uti-
afficher, cela se fait à l’aide de composant appelé Widgets : liser la fonction strftime() pour afficher la date courante
time() avec un format spécifique. '%d/%m' pour la date et
Widget Hello { '%H:%M' pour l’heure. Mettons à jour notre Layout :
class 'Text'
expression 'Hello LCD' Layout MyLayout {
width 9 Row1 {
} Col12 'Date'
}
Ici notre Widget texte affichera « Hello LCD ». La longueur du Row2 {
texte est importante, elle servira lors de l'alignement du texte Col12 'Time'
à droite par exemple. }
Nous allons maintenant pouvoir positionner notre Widget au }
sein d’un Layout :
Affichage de l’utilisation du CPU
Layout MyLayout { L’utilisation du CPU sur notre machine est aussi une informa-
Row1 { tion importante, nous allons afficher cette information au
Col1 'Hello' début de la première ligne. Comme précédemment il va nous
} falloir ajouter un Widget qui sera ensuite intégré à notre
Row2 { Layout :
Col2 'Hello'
} Widget Busy {
} class 'Text'
expression proc_stat::cpu('busy', second)
Un Layout se compose donc de lignes (row) et de colonnes postfix '%'
(col) sur lesquelles on va pouvoir afficher des Widgets. Notre width 5
texte sera donc affiché sur la première colonne de la premiè- precision 0
re ligne et la deuxième colonne de la deuxième ligne. align 'R'
Notre fichier de configuration étant complété il ne nous reste update second
plus qu’à tester le résultat en redémarrant le service : }
Layout MyLayout {
sudo systemctl restart lcd4linux
Row1 {
N. B. : Par la suite, il faudra exécuter à nouveau la commande pour Col1 'Busy'
tenir compte de chaque modification.
Col12 'Date'
Affichage de la date et l’heure }
Nous allons afficher la date et l’heure sur les dernières Row2 {
colonnes de nos 2 lignes d’écran LCD. Il faut donc créer 2 Col12 'Time'
Widgets : une pour la date et une pour l’heure : }
}
Widget Date {
class 'Text' Concentrons-nous sur les paramètres importants du Widget.
expression strftime('%d/%m',time()) Nous utilisons postfix pour afficher le caractère % après la
width 5 consommation de notre CPU. Nous alignons notre texte à
align 'L' droite et nous ne voulons aucun chiffre après la virgule : pré-
update minute cision 0. L’expression nous permet de récupérer l’utilisation
} du CPU avec une périodicité de 1 seconde.

Widget Time { Affichage de la température extérieure


class 'Text' L’accès aux données du système local s’avère donc simple.
expression strftime('%H:%M',time()) Intéressons-nous maintenant à une source de données dis-
width 5 tante. Nous voulons connaître la température extérieure.
align 'L' Dans notre exemple, le relevé de température est stocké dans
update second une base de données MySQL accessible depuis le réseau
} local. LCD4Linux propose la connexion à MySQL sous forme

[Link] 59
058_061.qxp_249 18/10/2021 19:02 Page60

Row7 '.....'
Row8 '.....'
}
}

Il ne nous reste plus qu’à afficher nos deux widgets au début


de la seconde ligne :

Layout MyLayout {
Row1 {
Col1 'Busy'
Col12 'Date'
}
Row2 {
Col1 'MySQLTemp'
Col5 'Degree'
Col12 'Time'
}
}

Figure 4 Affichage d’informations réseau issues


d’un plugin, il suffit donc de le configurer pour avoir l’accès d’une Freebox
à la base de données : La dernière chose que nous voulons afficher sur notre écran
est l’état de notre réseau. Il est bien sûr très facile de récupé-
Plugin MySQL { rer les informations de notre Linux en terme de débit réseau,
server '[Link]' mais sur un réseau local il est plus utile d’avoir une idée des
port 3306 débits réseau internet au niveau de la box internet elle-
user 'user' même. Ici nous allons récupérer ces informations d’une
password 'password' Freebox, car Free met à disposition une API de contrôle et
database 'meteo' supervision : [Link]
}
Création des scripts de supervision
Une fois l’accès à la base configuré, nous pouvons créer un Inutile de ré-inventer la roue, on trouve facilement sur GitHub
nouveau Widget qui contiendra la requête SQL d’accès aux du code prêt à l’emploi pour simplifier l’accès à l’API Free. Ici
données : nous allons récupérer les informations grâce à un script
shell :
Widget MySQLTemp {
class 'Text' git clone [Link]
expression MySQL::query('SELECT temperature FROM meteo.sensor_
data WHERE sensor_id=1 order by date DESC limit 1;') Avant de pouvoir utiliser le script shell, il faut tout d’abord
width 4 s’assurer que la Freebox accepte de nouvelles demandes
update minute d’association d’application. Il faut donc se connecter sur l’in-
} terface de la Freebox via l’URL [Link]
Il faudra cliquer sur Paramètre de la Freebox, ensuite sélec-
Malheureusement le symbole degré n’est pas supporté par tionner le mode avancé et cliquer sur Gestion des accès.
lcd4Linux, il est donc impossible d’utiliser postfix dans le wid- Ensuite dans le cadre Application, il faudra bien vérifier que
get comme nous l’avons fait précédemment. Nous allons la case “permettre les nouvelles demandes d'association“ est
donc créer à la main notre symbole degré dans un nouveau cochée. Pour des raisons de sécurité, une fois notre applica-
widget. Attention celui-ci aura pour classe Icon : tion enregistrée, il est fortement conseillé de décocher la
case. Figure 4
Widget Degree { Enregistrons notre application pour obtenir un jeton d’accès :
class 'Icon'
Bitmap { cd freeboxos-bash-api
Row1 '.**..' source ./freeboxos_bash_api.sh
Row2 '*..*.' authorize_application '[Link]' 'Network Monitoring
Row3 '*..*.' Application' '1.0.0' 'Linux'
Row4 '.**..'
Row5 '.....'
Row6 '.....'

60 [Link]
058_061.qxp_249 18/10/2021 19:02 Page61

Figure 5

Il faudra ensuite confirmer la création du jeton en appuyant Widget UpRate {


sur le bouton OK de la Freebox. class 'Text'
Récupérons le jeton que nous allons utiliser par la suite : expression exec('/home/seb/freeboxos-bash-api/rate_up.sh', five_secs)
prefix 'U'
MY_APP_ID="[Link]" width 4
MY_APP_TOKEN="4uZTLMMwSyiPB42tSCWLpSSZbXIYi+d+F32tVMx2 align 'R'
j1p8oSUUk4Awr/OMZne4RRlY" update five_secs
}
Dans le menu gestion des accès de la Freebox notre applica-
tion doit apparaître. Figure 5 Layout MyLayout {
Nous pouvons désormais écrire un script pour accéder au Row1 {
débit internet en download. Ici l’unité sera exprimée en Col1 'Busy'
Mo/s : rate_down.sh Col7 'UpRate'
Col12 'Date'
#!/bin/bash }
MY_APP_ID="[Link]" Row2 {
MY_APP_TOKEN="4uZTLMMwSyiPB42tSCWLpSSZbXIYi+d+F32tVMx2 Col1 'MySQLTemp'
j1p8oSUUk4Awr/OMZne4RRlY" Col5 'Degree'
. /home/seb/freeboxos-bash-api/freeboxos_bash_api.sh Col7 'DownRate'
login_freebox "$MY_APP_ID" "$MY_APP_TOKEN" Col12 'Time'
answer=$(call_freebox_api '/connection/') }
rate_down=$(get_json_value_for_key "$answer" 'result.rate_down') }
echo "$rate_down 1048576" | awk '{printf "%.1f", $1 / $2}' | tr , .
Conclusion
De même le script pour l’updload, ici l’unité sera exprimée en Nous avons vu, dans cet article, que grâce à LCD4Linux nous
ko/s : rate_up.sh pouvons afficher facilement tout type de données sur un
écran LCD connecté en USB.
#!/bin/bash Voici quelques idées pour aller plus loin :
MY_APP_ID="[Link]" • Remplacer LCD4Linux par LCDProc
MY_APP_TOKEN="4uZTLMMwSyiPB42tSCWLpSSZbXIYi+d+F32tVMx2 • Créer un programme Python pour piloter l’écran LCD
j1p8oSUUk4Awr/OMZne4RRlY" • Déporter les boutons Key-A et Key-B pour une utilisation
. /home/seb/freeboxos-bash-api/freeboxos_bash_api.sh plus simple et bien sûr associer une fonction à chacun de
login_freebox "$MY_APP_ID" "$MY_APP_TOKEN" ces boutons
answer=$(call_freebox_api '/connection/') • Câbler le Reset sur un bouton, en effet parfois le LCD2USB
rate_up=$(get_json_value_for_key "$answer" 'result.rate_up') ne démarre pas correctement
echo "$rate_up 1024" | awk '{printf "%d", $1 / $2}' | tr , . • Démarrer/redémarrer LCD4Linux lorsque l’on branche ou
rebranche l’écran LCD grâce à udev
Affichage des données A vous de jouer !
Une fois les scripts prêts, il ne reste plus qu'à créer un Widget
pour eux et de mettre à jour notre Layout.
LES PROCHAINS NUMÉROS
Widget DownRate {
class 'Text' HORS SÉRIE #5 PROGRAMMEZ!
expression exec('/home/seb/freeboxos-bash-api/rate_down.sh', five_secs) AUTOMNE n°250
prefix 'D'
width 4 100% Red Hat
align 'R'
Disponible Disponible
update five_secs dès le 26 novembre 2021 le 3 janvier 2022
}

[Link] 61
062_068.qxp_249 18/10/2021 16:54 Page62

Coder Fibonacci
en Java avec des tests
Thierry LERICHE Dans cet article, on se propose de coder le calcul des termes de la Suite de Fibonacci
Architecte et Tech lead
@ThierryLeriche
ainsi que de quelques variantes, comme Tribonacci, le tout en Java, et en écrivant des
tests. L'idée est d'écrire les tests avant, pendant et après le processus d'implémentation
des fonctionnalités.

Écrire un bloc qui compile


Pour coder, l'idée va être de décomposer le travail en trois
étapes : définition, test et implémentation. Et on boucle.
La plus grosse partie de l'intelligence est utilisée pour définir
le contrat de service. On peut le faire dans une interface,
comme ci-dessous, mais ce n'est pas obligatoire.

public interface Fibonacci {

/**
* Calcule la valeur du terme de la suite de Fibonacci pour le rang indiqué.
Il existe de nombreuses façons de coder Fibonacci, dépen-
*
dant du langage de programmation utilisé, mais également
* REGLE #0 f(0) = 0
des concepts mis en œuvre. Dans ce billet, qui se veut assez
* REGLE #1 f(1) = 1
simple, on va se limiter à de la programmation récursive.
* REGLE #2 f(n) = f(n-1) + f(n-2) si 2 < n
D'autres versions sont disponibles sur le Web. Et dans tous les
* REGLE #3 f(n) = Exception si n < 0
cas, c'est un basique que les étudiants en informatique doi-
*
vent connaître par cœur1.
* Premiers termes : 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597
On va donc employer des tests tout au long du processus, en
*
s'inspirant de TDD (Test Driven Development), sans en faire
* cf. [Link]
au sens pur, et de 3T (Tests en Trois Temps). Les tests permet-
*
tent de structurer la pensée, et donc l'architecture du code.
* @param n le rang
On admet généralement qu'un code non testable est mal
* @return la valeur du terme pour le rang indiqué
conçu, alors qu'un code testable est mécaniquement de
* @throws IllegalArgumentException si le rang indiqué est négatif
meilleure qualité. Les tests vont aider à programmer, mais
*/
également à réfactorer le code, c’est-à-dire à revenir dessus
int calculate(int n);
pour l'améliorer (bugs, performances, beauté, etc.) en ayant
une situation stable au départ, garantie par les tests, pour Si on prévoit d'écrire un peu de doc, l'interface est sans aucun
contrôler l’avancement. doute l'endroit le plus adapté. On peut mettre la doc dans un
fichier séparé, sur le réseau de l'entreprise par exemple, mais
Fibonacci les développeurs préfèrent généralement avoir la doc sous les
En mathématiques, la suite de Fibonacci est une suite d'en- yeux et disponible dans l’éditeur.
tiers dans laquelle chaque terme est la somme des deux À ce stade, on a juste besoin d'une implémentation qui com-
termes qui le précèdent. Elle est très utile, par exemple pour pile. Les IDE, comme Eclipse ou Intellij, savent générer le
calculer le nombre d’or, et on la retrouve largement dans la code à partir de l'interface. Ils retournent habituellement zéro
nature. Bla-bla-bla. On sait déjà ça et c'est très bien expliqué comme valeur par défaut. C'est ce qu'on appelle un nombre
sur la page Wikipedia dédiée2, vers laquelle je vais donc vous magique et c'est quelque chose qu'on veut absolument éviter.
renvoyer pour la longue explication. En effet, cette valeur pourrait correspondre à quelque chose
Dans les grandes lignes, la suite est définie par : de réel pour la fonctionnalité, ce qui est d'ailleurs le cas pour
• f(0) = 0 Fibonacci. Et choisir une autre valeur n'est pas forcément
• f(1) = 1 mieux. Cela porte à confusion. Ici, on va plutôt lancer une
• f(n) = f(n-1) +f(n-2) si 1 < n exception spécialisée, indiquant que le code n'a pas encore
Les premiers termes de cette suite sont donc 0, 1, 1, 2, 3, 5, été écrit. Pour les développeurs, qui liront ce code, le message
8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597… sera clair.

(1) C’est le type d’exercice simple qu’on peut demander aux juniors en public class RecursiveFibonacci implements Fibonacci {
entretien.
(2) [Link] @Override

62 [Link]
062_068.qxp_249 18/10/2021 16:54 Page63

public int calculate(int n) {


throw new UnsopportedOperationException("bientôt");
}

Note : En Kotlin, on aurait tout simplement utilisé la méthode TODO


dont le message est encore plus clair. Il s'agit d'une méthode spéciale qui
compile correctement, mais qui lance une exception indiquant que le
code n'est pas prêt, quand on passe dessus. Ça revient au même, avec
quelques petites améliorations. Figure 1
class RecursiveFibonacciTest extends AbstractFibonacciTest {
Écrire des tests
On prévoit d'avoir plusieurs implémentations pour le calcul de public RecursiveFibonacciTest() {
la suite. Et on prévoit donc d'avoir tout autant de versions à fibonacci = new RecursiveFibonacci();
tester. Mais les valeurs des termes de la suite ne vont pas }
changer, tout comme les cas d'utilisation. On veut voir ce cal-
cul comme une boîte noire. C'est pourquoi on peut écrire les C'est la classe fille qui identifie l'implémentation cible. Elle est
tests dans une classe abstraite. hyper simple.
On peut la lancer dès maintenant ; il n'y a qu'un test et il est
public abstract class AbstractFibonacciTest {
bien rouge, ce qui est ce qu'on souhaite. En effet, l’idée est
de commencer avec des tests qui échouent puis d’écrire le
protected Fibonacci fibonacci;
code nécessaire pour les valider, dans cet ordre. Figure 1
Pour le test suivant, c'est exactement la même chose, en
@Test
changeant juste les valeurs en entrée et les valeurs attendues.
public void testCalculateIndex0() {
// Arrange @Test
final int n = 0; public void testCalculateIndex1() {
final int expected = 0; // Arrange
final int n = 1;
// Act final int expected = 0;
final int result = [Link](n);
// Act
// Assert final int result = [Link](n);
[Link](expected, result);
} // Assert
[Link](expected, result);
Il existe plusieurs systèmes de nommage pour les méthodes de
}
test. Certains préféreront le Snake-Case : should_do_some-
thing_when_case. Certains préféreront le formalisme Camel- En TDD pur, on aurait écrit un peu de test, puis un peu de
Case, plus classique en Java : testSomethingCase. Dans tous code, puis un peu de test, puis un peu de code, etc. jusqu'à
les cas, il n'y a rien d'obligatoire. avoir tout traité. Dans la mesure où on a un cahier des
À l'intérieur de la méthode, j’aime utiliser l'organisation AAA charges bien fait, et un cerveau, l'écriture des tests n'est
(Arrange Act Assert) qui permet de bien séparer et identifier qu'une simple traduction du français vers du Java, et on peut
les blocs, et qui ressemble beaucoup à GWT (Given When écrire tous les cas triviaux d'un seul coup.
Then). On veut ainsi séparer le cas de test avec ses données Et c'est aussi pareil pour toutes les autres valeurs. Les blocs
d'entrée et les résultats attendus, de l'appel à proprement Act et Assert sont toujours les mêmes, et à juste titre. Il suffit
parlé du calcul, et enfin des tests. On notera que la partie la de les factoriser dans une méthode privée. Chaque méthode
plus intéressante est la première, les deux autres n'étant rien de test n'est alors plus qu'un cas de test.
de plus que du code purement technique. Je trouve que
@Test
cette organisation est beaucoup plus lisible que de tout écri-
public void testCalculateIndex2() {
re en un seul bloc, et permet d’identifier beaucoup plus faci-
// Arrange
lement le cas de test, puisque les données fonctionnelles ne
final int n = 2;
sont pas mélangées avec le code technique. Dites-moi ce
final int expected = 2;
que vous en pensez. En utilisant cette organisation, il sera
d'autant plus simple de switcher sur des tests paramétrés (cf.
// Act and assert
plus bas).
doTestCalculate(n, expected);
Il faut bien commencer quelque part. Faute de mieux, on
}
peut choisir les cas de test dans l'ordre où ils ont été décrits
dans le cahier des charges (pour nous la page Wikipédia, ou
@Test
l'interface). D'expérience, cet ordre est généralement perti-
public void testCalculateIndex3() {
nent.
// Arrange

[Link] 63
062_068.qxp_249 18/10/2021 16:54 Page64

final int n = 3; @ParameterizedTest


final int expected = 3; @CsvFileSource(resources = "/fibonaccicsv", delimiter = ':', numLinesTo
Skip = 1)
// Act and assert public void testCalculate(final int n, final int expected) {
doTestCalculate(n, expected); doTestCalculate(n, expected);
} }
Reste encore le cas où le rang est négatif, qu'on n'avait pas
@Test
encore traité.
public void testCalculateIndex4() {
// Arrange @Test
final int n = 4; public void testCalculateNegative() {
final int expected = 5; // Arrange
final int n = -1;
// Act and assert
doTestCalculate(n, expected); // Act
} [Link]([Link], () -> {
[Link](n);
Dans l’outil (Eclipse, Intellij, Maven, etc.), les tests sont
}
rouges (ie. échouent), ce qui est encore ce qu’on veut à ce
}
stade. Par contre, il y a encore de très nombreuses duplica-
tions de code. La classe de test semble énorme alors qu'il n'y
a qu'une petite dizaine de cas. Pour simplifier, on peut itérer Selon les IDE, les tests paramétrés pourront être regroupés et
sur une liste de valeurs. séparés des tests classiques.

@Test Note : avec JUnit 4, on pouvait indiquer l'exception attendue directe-


public void testCalculate() { ment au niveau de l'annotation.
// Arrange @Test(expected = [Link])
final int[] expecteds = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987}; public void testCalculateNegative() {
// Arrange
// Act and assert final int n = -1;
for (int n = 0; n < [Link]; n++) {
doTestCalculate(n, expected[n]); // Act
} [Link](n);
} }
Le souci est que cela n'apparaît plus que comme un seul Pour l'instant, on en a fini avec les tests. Mais on y reviendra
(gros) test dans l'IDE (ici Intellij) et que les tests s'arrêtent dès plus tard.
qu'une des valeurs est incorrecte. On peut envoyer le code des tests au client (ou à l'équipe)
Avec JUnit 5 (Jupiter), il est possible de définir des tests para- pour validation. Cela permet de valider qu'on est bien sur la
métrés. Il y a plein de façons de le faire, la plus simple étant même longueur d'onde.
de passer les valeurs comme du CSV (Coma Separated
Values) dans l'annotation. Remarque : Cela pose toutefois question. Si on commit/push dans Git,
même dans une branche à part, on envoie du code qui compile, mais qui
@ParameterizedTest plante au niveau des tests (ce qui est d’ailleurs bien ce qu’on veut). En TDD
@CsvSource(value = {"0:0", "1:1", "2:1", "3:2", "4:3", "5:5", "6:7", "7:13", "8:21"}, pur, on aurait codé un test, puis le code pour le faire passer, puis un test,
delimiter = ':') puis… La question ne se serait donc pas posée dans les mêmes termes
public void testCalculate(final int n, final int expected) { (sans jeu de mot). Mais on n’aurait pas pu faire valider de la même manière.
doTestCalculate(n, expected); Un choix d’organisation devra donc être effectué en amont.
Figure 2
}

Dans l’IDE, les différents cas sont bien identifiés et séparés.


Figure 2
Le souci de cette approche est que ça devient illisible dès
qu'on augmente le nombre de cas de test, car la taille du
contenu de l'annotation explose.
Or, et on ouvre un nouveau paragraphe pour le dire, si quel-
qu'un, disons un expert, s'est embêté à fournir des cas fonc-
tionnels dans le cahier des charges, il faut tous les avoir, à
minima, dans les tests. Et cela n'empêche pas d'en ajouter et
de compléter le cahier des charges. Tout en restant sur un
format CSV, on peut utiliser un fichier, moins limitant en taille,
dans lequel on peut mettre de très nombreux cas de test.

64 [Link]
062_068.qxp_249 18/10/2021 16:54 Page65

Accessoirement, ces tests, en plus de l’interface, sont relati-


vement simples à lire par un développeur, qui sera bien plus
à l’aise avec du code qu’avec un long fichier Word. En ce
sens, les tests permettent également de documenter le pro-
gramme.

Écrire le code du calcul


Cette fois encore, si on n’a pas d'idée par où commencer, le
plus simple est de commencer par le début en prenant les
règles et les tests dans l'ordre d'où ils viennent. La première
règle n’est qu’une formalité.

public class RecursiveFibonacci implements Fibonacci {

@Override
public int calculate(int n) { Figure 3
// REGLE 1
if (n == 0) {
return 0;
}

throw new UnsupportedOperationException("bientôt");


}

On lance (tous) les tests dès qu'on est content d'un bloc de
code. Ce n'est pas la peine d'attendre, car il n'y a aucune éco-
nomie intéressante à espérer. Figure 3
Et puis on continue avec le deuxième test…

@Override
public int calculate(int n) {
// REGLE 1
if (n == 0) { Figure 4
return 0;
}
Le calcul final, quant à lui, n'est pas super compliqué. C'est
un simple, enfin double, appel récursif.
if (n == 1) {
return 1; @Override
} public int calculate(int n) {
...
throw new UnsupportedOperationException("bientôt");
} return calculate(n – 1) + calculate(n – 2);
}
Ce qui nous permet déjà d'avoir deux cas de test au vert (ie.
passant). Figure 4 On voit que tous les cas des tests paramétrés deviennent verts
On a donc une (petite) situation stable. Et on peut en profiter d'un coup, sauf un... Flute de zut alors !... Hummm... c'est
pour se lancer dans un (petit) refactoring. L'idée est que ça bizarre. Il faut analyser.
marchait avant le refacto, avec rapport de test à l'appui, et En y regardant bien, on voit que ce n'est pas le code qui plan-
que ça doit marcher (en mieux) après. Si des tests verts te, mais que c'est le jeu de test qui est mauvais. Ça arrive. Ici,
deviennent rouges, cela indique qu'on a raté une étape. Dans on s'est trompé en recopiant les valeurs dans le fichier CSV.
ce cas, on pose le stylo et on corrige. Ici le refactoring propo- En effet, on attendait la valeur 7, mais on obtient bien 8 qui
sé est trivial, mais il illustre bien le processus. est la bonne valeur pour le rang 6.
Des fois, c'est le cahier des charges qui contient des erreurs.
@Override
En travaillant en mode Agile, on accepte que ça arrive. Il suf-
public int calculate(int n) {
fit de passer un coup de fil au rédacteur pour clarifier la situa-
// REGLE 1
tion. Ce genre de chose est plus fréquent qu'on ne le pense.
if (n == 0 || n == 1) {
Il ne reste plus qu'à vérifier le cas des rangs négatifs.
return n;
} @Override
public int calculate(int n) {
throw new UnsupportedOperationException("bientôt"); // REGLE 4
} if (n < 0) {

[Link] 65
062_068.qxp_249 18/10/2021 16:54 Page66

throw new IllegalArgumentException("The parameter n can not be negative!");


Note, la méthode de test assertTimeout() patiente jusqu'à la
}
fin du calcul (et donc pour un temps infini) pour en mesurer
la durée, ce qui n'est évidemment pas ce qu'on veut ici. C'est
...
pourquoi on utilise plutôt assertTimeoutPreemptively() qui
}
s'arrête dès que le timeout est atteint.
Tout est bon... On est légitimement en droit de penser qu'on Le test échoue donc pour cause de timeout. Figure 5
a fini. On peut envoyer le produit au client. Concrètement, effectuer le calcul de cette suite de manière
récursive est hyper long. Et on revient sans cesse sur des
Trop lent ? termes pourtant déjà calculés. La solution la plus simple
Mais quelques jours plus tard, après avoir bien tout vérifié, le consiste donc à les stocker au fur et à mesure, ce qui permet
client nous appelle. Il dit que c'est super long, en fournissant d'améliorer les performances au niveau d'une complexité
la valeur 50 comme référence. Dans ce genre de situation, le algorithmique linéaire. On parlera de mémoïzation. Le calcul
mieux est de revenir à nos tests et d'ajouter un nouveau cas. devient quasi instantané.
Ça va nous servir pour constater le problème, en conserver
private Map<Integer, Integer> memo = new HashMap<>();
une trace, et enrichir la base de test.

@Test @Override
public void testCalculateVeryLong() { public int calculate(int n) {
// Arrange ...
final int n = 50;
final Integer memorized = [Link](n);
// Act if (memorized != null) {
[Link](n); return memorized;
} }

Effectivement, quand on lance ce test, on a l'impression qu’il ne


// REGLE 3
va jamais arriver jusqu'à la fin du calcul, et on est bien obligé
final int result = calculate(n – 1) + calculate(n – 2);
de l'arrêter manuellement. Et pour cause, il peut durer très très
[Link](n, result);
longtemps… On doit donc introduire une gestion du timeout.
Exercice : calculer précisément la complexité algorithmique
return result;
de ce calcul.
}
@Test
On envoie donc ce nouveau code au client.
public void testCalculateVeryLong() {
// Arrange
Ça boucle ?
final int n = 50;
Le client appelle à nouveau pour dire que les valeurs sont
mauvaises dès le rang 62. Zut alors3... Mais c'est l'opportu-
// Act
nité d'enrichir à nouveau la base de test. Dans un premier
// [Link]([Link](500), () -> ...
temps, mettons un log temporaire (ou un point d’arrêt) pour
[Link]([Link](500), () -> {
comprendre ce qui se passe.
[Link](n);
}); @Test
Figure 5 } public void testCalculateBigCalue() {
// Arrange
final int n = 62;

// Act
final int result = [Link](n);
[Link](result);
}

À l'exécution, on voit que ça donne une valeur négative (-


1709589543). C'est ennuyeux pour une somme d’entiers posi-
tifs. Pour ce rang, le terme prend une valeur qui dépasse la
capacité des ints. Du coup, ça boucle (binairement) et les
valeurs positives finissent par devenir négatives. Bon, c’est un
classique… Cela oblige à faire évoluer le contrat, ce qui est une
grosse évolution. On pourrait utiliser des longs à la place des
ints mais c'est reculer pour mieux sauter. On va plutôt utiliser un

(3) Kraftos ne va vraiment pas être content, cf. Programmez n°246

66 [Link]
062_068.qxp_249 18/10/2021 16:54 Page67

BigInteger dont le nom permet d’en comprendre l'utilité. tionne du premier coup. On peut donc envoyer ce nouveau
code au client. Et ainsi de suite…
public interface Fibonacci {

Tribonacci
BigInteger calculate(int n);
La suite de Tribonacci est une suite d'entiers dans laquelle
Ça se change dans l'interface, et donc dans les tests en chaque terme est la somme des trois termes qui le précèdent.
conséquence. Et, là aussi, c'est très bien expliqué sur la page Wikipedia
dédiée4. Dans les grandes lignes, la suite est définie par :
private void doTestCalculate(fina int n, final BigInteger expected) {
• f(0) = 0
...
• f(1) = f(2) = 1
}
• f(n) = f(n-1) +f(n-2) + f(n-3) si 2 < n
Les premiers termes de cette suite sont donc 0, 0, 1, 1, 2, 4, 7, 13, 24,
@ParameterizedTest
44, 81, 149, 274, 504, 927, 1705, 3136, 5768, 10609, 19513, 35890,
@CsvFileSource(...)
66012, 121415, 223317, 410744, 755476, 1389537, 2555757…
public void testCalculate(final int n, final BigInteger expected) {
doTestCalculate(n, expected);
K-bonacci
}
Ce sont des suites dont la relation de récurrence est d'ordre
k. Un terme est la somme des k termes qui le précèdent
@Test
Dans les grandes lignes, la suite est définie par :
public void testCalculateBigValue() {
• f(0) = 0
// Arrange
• f(n) = 1 si 0 < n < p
final int n = 62;
• f(n) = f(n-1) + f(n-2) + ... + f(n-p) si p <= n
Et donc, Fibonacci est de récurrence p=2 et Tribonacci est de
// Act
récurrence p=3. D'une certaine manière, on pourra considé-
final BigInteger result = [Link](n);
rer, d'un point de vue programmation, que ce sont des cas
particuliers de K-Bonacci. Après avoir codé Fibonacci, c'est
// Assert
donc une formalité de proposer une interface pour K-
[Link](0 < [Link]([Link]));
Bonacci. En plus du rang n, il suffit d'ajouter la récurrence p.
}
public interface KBonacci {
Et donc aussi dans l'implémentation, où l’utilisation de
BigInteger à la place du type primitif int est tout de même
/**
moins lisible.
* Calcule la valeur du terme de la suite de K-Bonacci pour le rang n et la récurrence p indiqués.
private Map<Integer, BigInteger> memo = new HashMap<>(); *
* REGLE #0 f(0) = 0
@Override * REGLE #1 f(n) = 1 si 0 < n < p
public BigInteger calculate(int n) { * REGLE #2 f(n) = f(n-1) + f(n-2) + ... + f(n-p-1) si p < n
// REGLE 4 * REGLE #3 f(n) = Exception si n < 0 ou si p < 0
if (n < 0) { *
throw new IllegalArgumentException("The parameter n can not be negative!"); * Premiers termes pour p=3 : 0, 1, 1, 2, 4, 7, 13, 24, 44, 81...
} *
* cf. Tribonacci [Link]
// REGLE 1, 2 *
if (n == 0 || n == 1) { * @param n le rang
return [Link](n); * @param p la récurrence
} * @return la valeur du terme pour le rang et la récurrence indiqués
* @throws IllegalArgumentException si le rang ou la récurrence indiqués sont négatifs
final BigInteger memorized = [Link](n); */
if (memorized != null) { BigInteger calculate(int n, int p);
return memorized;
Comme toujours, on part d'une implémentation vide.
}
public class RecursiveKBonacci implements KBonacci {
// REGLE 3
final BigInteger result = calculate(n – 1).add(calculate(n – 2)); @Override
[Link](n, result); public BigInteger calculate(int n, int p) {
throw new UnsupportedOperationException("bientôt");
return result; }
}

Il n'y a pas de difficulté majeure. Et en toute logique, ça fonc- (4) [Link]

[Link] 67
062_068.qxp_249 18/10/2021 16:54 Page68

@Override
public BigInteger calculate(int n, int p) {
// REGLE 0
if (n == 0) {
return [Link];
}

// REGLE 1
if (n < p) {
return [Link];
}

throw new UnsupportedOperationException("bientôt");


}
Et elles passent au vert sans difficulté.
Pour le calcul, c'est un poil plus coton. On garde le principe
de mémoïzation qu'on doit retranscrire sur une multimap5. Et
Figure 6
il faut compulser la somme des termes. Il y a d'ailleurs très
Et évidemment, on enchaîne directement sur les tests. sûrement plus subtil que la version proposée ci-dessous, ce
qui donnera l'occasion d'une nouvelle itération de refacto-
public abstract class AbstractTribonacciTest {
ring. Code complet sur [Link] & github

protected KBonacci kbonacci;


Fibonacci via K
protected int p;
Cela nous donne l'occasion de coder une nouvelle version de
Fibonacci en assemblant les briques déjà écrites, puisqu'on a
private void doTestCalculate(final int n, final BigInteger expected) {
redéfini Fibonacci comme une récurrence de 2 de K-Bonacci,
// Act
pour plus simplement 2-Bonacci. Et oui, en fait, k = p.
final BigInteger result = [Link](n, p);
public class RecursiveKFibonacci
// Assert extends RecursiveKBonacci
[Link](expected, result); implements Fibonacci, KBonacci {
}
private final static int RECURRENCE = 2;
@parameterizedTest
@CsvFileSource(resources = "/[Link]", delimiter = ':', numLinesTo @Override
Skip = 1) public BigInteger calculate(int n) {
public void testCalculate(final int n, final BigInteger expected) { return calculate(n, RECURRENCE);
doTestCalculate(n, expected); }
}
Avoir écrit les tests de manière abstraite prend donc tout son
Il faut également écrire le CSV correspondant. C'est un sens, puisqu'il suffit de l'étendre.
simple copié-collé des valeurs.
public class RecursiveKFibonacciTest extends AbstractFibonacciTest {
Pour cet article, on s'épargne les autres méthodes de test
qu'on avait écrites plus haut, mais il faudrait les écrire aussi,
@BeforeEach
en adaptant les valeurs. On va de toute manière les réutiliser
public void before() {
quand on fera une nouvelle implémentation de Fibonacci.
fibonacci = new RecursiveKFibonacci();
public class RecursiveTribonacciTest extends AbstractTribonacciTest { }

Et c'est magique ; il n'y a rien à faire. Ça marche tout seul.


@BeforeEach
Figure 6
public void before() {
On est parti d'un exemple finalement assez simple avec la
kbonacci = new RecursiveKbonacci();
suite de Fibonacci. Il n'y a pas de difficulté particulière. Mais
p = 3;
cela permet de s'initier à quelques pratiques de test. Facile,
}
non ? Pour s’amuser, on pourra coder d’autres implémenta-
Et sans surprise, tous les tests sont bien rouges à ce stade. On tions, en réutilisant les tests déjà écrits, par exemple en itératif
peut donc continuer. ou par calcul direct en profitant du fait que le ratio de deux
Les deux premières règles sont triviales. membres consécutifs de la suite tend vers le nombre d’or, etc.

public class RecursiveKBonacci implements KBonacci {


(5) Une map de collection

68 [Link]
069_071.qxp_249 18/10/2021 16:54 Page69

Python et la tortue : découvrir la


programmation en dessinant
Pascal
Deux activités de découverte de la programmation utilisant la bibliothèque turtle de Lafourcade
python pour dessiner sur l’écran sont présentées ici. La première consiste à tracer des Maître de conférences à
l'IUT d'informatique de
courbes de Bézier, et la seconde une courbe fractale. Bien qu’elles ne nécessitent pas de l'Université Clermont
Auvergne et membre du
très nombreuses lignes de code, il ne s’agit cependant pas d’activités de niveau débu- Laboratoire
tant, car elles ont pour but d’illustrer la notion de récursivité. d'Informatique,
Modélisation et
Optimisation des
LA BIBLIOTHÈQUE TURTLE Systèmes. Il est
Python possède une bibliothèque à vocation pédagogique spécialiste en sécurité
informatique et
appelée « turtle ». Elle offre la possibilité de créer des pro-
cryptographie.
grammes à l’aide d’instructions proches du LOGO, un
célèbre langage de programmation éducatif inventé par
Wally Feurzig et Seymout Papert en 1967 au Massachusetts
Institute of Technology.
La documentation de la bibliothèque se trouve ici :
[Link]
Comme toute bibliothèque python, les lignes import turtle ou from turtle import *
from turtle import * en début de programme permettent de
Malika More
l’utiliser. Elle fait appel au module tkinter pour sa partie gra- longueur = 30 Maîtresse de
conférences à l'IUT
phique. for i in range(10): d'informatique de
Les commandes ont pour objectif de contrôler sur l’écran un forward(longueur) l'Université Clermont
objet appelé « tortue », qui permet de dessiner avec un left(90) Auvergne et membre du
ensemble de commandes simples dans une fenêtre gra- longueur = longueur+10*i Laboratoire
phique. Le nom vient de la « tortue logo », un véritable robot d'Informatique,
Modélisation et
piloté à l’aide du langage logo, utilisé dans certaines écoles COURBES DE BÉZIER Optimisation des
dans les années 1970 et 1980. Il est à noter que le rôle de la Les courbes de Bézier ont été inventées en 1962 par Pierre Systèmes. Elle est
tortue était aussi parfois joué par un enfant (ou un adulte) à Bézier, un ingénieur travaillant chez Renault. Elles sont responsable du groupe
quatre pattes, dans une démarche annonciatrice du courant aujourd’hui à la base des images vectorielles, et très utilisées Informatique Sans
de l’informatique débranchée, formalisé au début des en CAO, en synthèse d’image et pour le rendu des polices de Ordinateur de l'IREM de
Clermont-Ferrand.
années 2000 par Tim Bell et ses collègues en Nouvelle- caractères.
Zélande. [Link] La définition mathématique des courbes de Bézier fait appel
Pour déplacer la tortue et dessiner avec, nous pouvons utiliser à des polynômes. Les plus utilisées sont celles qui correspon-
les commandes suivantes : dent à des polynômes de degré 3, mais ce ne sont pas celles
• forward() permet d’avancer d’une distance donnée présentées ici, par souci de simplicité.
• backward() permet de reculer d’une distance donnée Les courbes de Bézier présentées ici sont dites « quadra-
• right() permet de tourner à droite d’un angle donné (en tiques » (elles sont définies par des polynômes de degré 2) et
degrés) ont été proposées par Paul de Faget de Casteljau, un ingénieur
• left() permet de tourner à gauche d’un angle donné (en travaillant chez Citroën). Elles utilisent trois paramètres : le
degrés) point de départ A, le point d'arrivée C et un point de contrôle
• goto() permet d’aller à une position définie par deux coor- B. Pour comprendre le fonctionnement d'une telle courbe, il
données (à noter que le point (0,0) est au centre de la faut imaginer que notre segment [A;C] est un fil de métal
fenêtre) souple, qui est attiré par l'aimant qu'est le point de contrôle
• pendown() met le stylo en position d’écriture B. Plus une partie du fil se trouve près de l'aimant, plus elle
• penup() lève le stylo est attirée et se déforme.
• clear() efface tout ce qui est dessiné La courbe de Bézier de point de départ A, de point d'arrivée
Il existe beaucoup d’autres commandes, mais les huit qui C et de point de contrôle B, est la limite d'une suite de lignes
sont listées ci-dessus permettent de réaliser de nombreuses brisées, obtenues à l’aide d’un algorithme également inventé
activités pour découvrir divers aspects de la programmation. par Paul de Casteljau.
Voici un exemple permettant de tracer une spirale rectangu- La ligne initiale est formée des segments [AB] et [BC].
laire. Bien qu’il ne contienne que cinq lignes de code, il À l'étape suivante, les trois points suivants sont construits :
contient deux notions importantes pour les débutants : la • D milieu de [AB]
boucle for et la réutilisation des variables. • E milieu de [BC]

[Link] 69
069_071.qxp_249 18/10/2021 16:54 Page70

segment(x2,y2,x3,y3)
else :
(a,b)=milieu(x1,y1,x2,y2)
(c,d)=milieu(x2,y2,x3,y3)
(e,f)=milieu(a,b,c,d)
bezier(x1,y1,a,b,e,f,n-1)
bezier(e,f,c,d,x3,y3,n-1)

Le résultat de la fonction bezier pour les points trois-points


(0,0), (100,200) et (200,100) et une profondeur de 3 donne
le graphique suivant (en appelant bezier(0,0,100,200,
200,100,3)) : Figure 2
L’algorithme de Casteljau est ici présenté pour construire des
Figure 1 courbes de Bézier quadratiques, mais la construction se
généralise assez facilement pour les courbes de Bézier de
degré supérieur.

FLOCON DE VON KOCH


Le flocon de von Koch est une courbe fractale simple à tracer.
Il s’agit d’un d’un polygone « creux » (non convexe). La figure
de départ est un triangle équilatéral, et l’algorithme de
construction s’applique à chaque côté du triangle. La
Figure 2 construction est présentée étape par étape : pour passer
d’une étape à la suivante, il faut diviser chaque segment en
• F milieu de [DE] trois segments égaux. Ensuite, il faut remplacer le segment
Il faut noter que D et E sont des points auxiliaires, tandis que du milieu par les deux côtés d’un triangle équilatéral dont la
F est un point de la courbe finale. base est ce segment du milieu, et orienté vers l'extérieur. À
Ensuite, il faut recommencer en remplaçant les points A, B, l’étape suivante, ce processus est réitéré sur les quatre nou-
C par les deux triplets de points A, D, F et F, E, C. Après plu- veaux segments obtenus.
sieurs itérations, le résultat est une courbe lisse, passant par Cette construction correspond naturellement à un algorithme
A et C et tangente à [AB] et [BC]. Le résultat est déjà recon- récursif, comme celui écrit ci-dessous.
naissable après 3 ou 4 itérations. Figure 1
Pour implémenter cet algorithme, une solution est de com- from turtle import *
mencer par écrire une fonction nommée segment, qui trace
un segment à partir des coordonnées de deux points. def Trait(n, L) :
# Etat initial : plume baissée, direction trait, à gauche
from turtle import * # Etat final : plume baissée, direction trait, à droite
if n == 1 : forward(L)
def segment(x1,y1,x2,y2) : else :
up() Trait(n-1, L / 3.0)
goto(x1,y1) left(60)
down() Trait(n-1, L / 3.0)
goto(x2,y2) right(120)
up() Trait(n-1, L / 3.0)
return left(60)
Trait(n-1, L / 3.0)
Ensuite une autre fonction utile est le calcul des coordonnées
du milieu de deux points à partir de deux points. N = int(input("Nombre de niveaux (entre 1 et 6) : "))
if (type(N) != int) or (N < 1) or (N > 6) :
def milieu(x1,y1,x2,y2) : print ("Le nombre de niveaux ne correspond pas a la demande")
return ((x1+x2)/2.0,(y1+y2)/2.0) else :
Long = 550 # Longueur du trait
À partir de ces deux fonctions, une des manières naturelles up()
de coder cet algorithme est de réaliser une fonction récursive goto(-300, -180)
pour tracer la courbe de Bézier. down()
width(2) # épaisseur du stylo
def bezier(x1,y1,x2,y2,x3,y3,n) : left(60)
if n==0 : for k in range(3) :
segment(x1,y1,x2,y2) Trait(N, Long)

70 [Link]
069_071.qxp_249 18/10/2021 16:54 Page71

Figure 4

Figure 5

FLOCON DE VON KOCH


Figure 3

right(120) chacun dans un sens, de façon que les ouvertures soient vers
up() l’extérieur. Il ne reste plus qu’à relier de proche en proche les
goto(0, 0) extrémités des motifs pour obtenir la courbe suivante :
Figure 4
En théorie, la construction devrait être répétée indéfiniment
pour obtenir une courbe fractale, car par définition, il s’agit La courbe fractale obtenue après une infinité d’itérations pos-
de la courbe « limite », obtenue après une infinité d’étapes. sède la propriété de passer par chacun des points du carré
Concrètement, on fixe préalablement la profondeur des bâti à partir du motif initial.
appels récursifs. Dans le programme ci-dessous elle est limi-
tée à 6, car d’une part le temps d’exécution est déjà long, et Courbe du dragon
d’autre part, il n’y aurait plus beaucoup de différence visuelle La courbe du dragon a été inventée par J.E. Heighway. Cette
en ajoutant des étapes. Figure 3 courbe fractale ne se recoupe jamais. En 1967, Martin
Il existe des variantes du flocon de von Koch, obtenues en Gardner l'a présentée dans sa chronique de jeux mathéma-
modifiant les valeurs des angles du triangle ou bien la figure tiques du Scientific American, car sa construction est simple.
géométrique de base, et même en 2D (surfaces de von À chaque étape, la courbe obtenue est composée de seg-
Koch). ments de droites qui suivent à angle droit. Au départ, il n’y a
qu’un seul segment. Pour passer d’une étape à la suivante,
POUR ALLER PLUS LOIN en suivant la courbe, il s’agit de remplacer chaque segment
Voici deux exemples supplémentaires de courbes fractales, la rencontré par deux segments à angle droit en effectuant une
courbe de Hilbert et la courbe du dragon, dont il est possible rotation de 45° alternativement à droite puis à gauche.
de tracer des approximations à l’aide de la bibliothèque turtle. Figure 5

Courbe de Hilbert CONCLUSION


Cette courbe, inventée par le mathématicien allemand David Nous espérons vous avoir convaincu de l’intérêt de la biblio-
Hilbert en 1891, est une ligne brisée, obtenue à partir de seg- thèque turtle de python pour la découverte de la programma-
ments de droites orthogonaux. Le motif de base est composé tion par le dessin, y compris pour des notions avancées
de trois côtés d’un carré. À chaque étape, la longueur des comme la récursivité. Les codes Python pour les courbes de
côtés est divisée par 3. Chaque « coin » d’un motif de l’étape Hilbert et du dragon sont laissés en exercices au lecteur, pour
précédente est remplacé par le nouveau motif, selon la qu’il puisse vérifier s’il a compris le fonctionnement de cette
même orientation, et chaque « extrémité » est aussi rempla- bibliothèque et la récursivité.
cée par le nouveau motif, mais tourné d’un quart de tour,

1 an de Programmez!
ABONNEMENT PDF : 39 €
Abonnez-vous directement sur
[Link]
[Link] 71
072_075.qxp_248 18/10/2021 16:55 Page72

PROGRAMMATION DYNAMIQUE
Python est un langage fortement dynamique. Mais, dans les faits, qu’est-ce que cela
signifie ? Qu’est-ce que cela peut nous apporter ? Grâce à ce dynamisme, Python per-
Philippe met de résoudre des problèmes de manière élégante et compacte là où les langages
BOULANGER
Manager des expertises classiques nécessiteraient beaucoup de codes.
C/C++ et Python
[Link] DÉFINITION détectés à la compilation plutôt qu’à l’exécution.
Si on se réfère à Wikipédia ([Link] En effet dans les langages statiques (Java, C ou C++ par
Langage_de_programmation_dynamique), la programmation dyna- exemple), les variables sont déclarées et typées avant d’être
mique est définie par : utilisées permettant au compilateur de faire nombre de tests
• On utilise le terme langage de programmation dyna- avant de générer le binaire. Par exemple si on prend le petit
mique en informatique pour décrire une classe de langage programme suivant :
de haut niveau qui exécute au moment de l'exécution des
double linear_interpolation( double a, double b, double x )
actions que d'autres langages ne peuvent exécuter que
{
durant la compilation. Ces actions peuvent inclure des
double v = ( 1 - x ) * a + x * b;
extensions du programme, en ajoutant du code nouveau,
return v;
en étendant des structures de données et en modifiant le
}
système de types, cela pendant l'exécution du programme.
Ces comportements peuvent être émulés dans pratique-
ment tous les langages de complexité suffisante, mais les
int main()
langages dynamiques ne comportent pas de barrière, tel
{
que le typage statique, empêchant d'obtenir directement
// appel correct qui compilera
ces comportements.
double r1 = linear_interpolation( 10, 20, 0.5 ); // appel correct

L’un des premiers langages dynamiques fut LISP. Basé sur la


// ne compilera pas
théorie du l-calcul, ce langage a été un des outils prépondé-
std::string s1( "toto" ), s2( "tata" );
rants sur l’amélioration des techniques et langages de pro-
double r2 = linear_interpolation( s1, s2, 2 ); // erreur de type
grammation : le premier langage-objet qui a eu du succès
return 0;
« Smalltalk » a été écrit en LISP. L’une des particularités du LISP
}
est qu’un programme est une donnée et qu’une donnée peut
devenir un programme : c’est une des raisons pour laquelle il Il générera comme erreur de compilation :
a été à la base des recherches en intelligence artificielle.
C:\personnel\private\tests\essai\[Link]:39: error: cannot convert 'std::__cxx11
Nombre de langages sont aujourd’hui dynamiques à divers
::string' {aka 'std::__cxx11::basic_string<char>'} to 'double'
degrés ; voici certains parmi les plus connus et les plus utilisés :
double r2 = linear_interpolation( s1, s2, 2 ); // erreur de type
• JavaScript : pour le web dynamique
^~
• C# (en version 4.0 ou supérieure)
• Erlang En Python, par défaut, le type des variables n’est défini qu’au
• Python : qui est utilisé aussi bien dans les classes de secon- moment de l’affectation. Et de ce fait les problèmes ne sont
de que dans les entreprises de pointe comme Google ou vus qu’à l’exécution… En reprenant l’exemple développé en
Dropbox C++ et en le portant en Python on obtient :
• Lua : utilisé dans les moteurs de jeux vidéo
def linear_interpolation( a, b, x ):
Si le LISP reste un langage que j’apprécie notamment grâce
r=(1-x)*a+x*b
à sa forme préfixée pour le calcul formel ; Python l’a rempla-
return r
cé, dans les faits, pour les tâches quotidiennes nécessitant
des solutions rapides à mettre en œuvre.
r1 = linear_interpolation( 10, 20, 0.5 )
print( type(r1), r1, sep=' : ' )
LES VARIABLES r2 = linear_interpolation( "toto", "tata", 2 )
Les variables sont des éléments essentiels d’un programme :
print( type(r2), r2, sep=' : ' )
elles servent à stocker les états. La notion de « dynamisme »
pour les variables peut prendre différentes formes : Le code s’exécute sans erreur et affiche les valeurs suivantes :
• Typage dynamique • <class 'float'> : 15.0
• Création de variables à la volée • <class 'str'> : tatatata
En Python on peut multiplier un entier par une chaîne de
Typage dynamique vs typage statique caractères… Le code s’exécute, mais, dans le cas présent, le
Les détracteurs de Python avancent souvent le fait que le résultat n’est pas celui attendu !
typage statique est plus sûr : les problèmes de type sont L’autre avantage du typage statique est la performance : les

72 [Link]
072_075.qxp_248 18/10/2021 16:55 Page73

variables sont associées à un espace mémoire par une adres- Cela peut sembler peu de chose, mais c’est extrêmement
se et une taille dépendant du type. L’accès à la donnée est utile : le module argparse en fait usage pour retourner args :
donc direct. Dans le cadre du typage dynamique, on doit
import argparse
passer par un « dictionnaire » qui lie le nom de la variable à
un espace mémoire alloué (dynamiquement) : l’accès est
parser = [Link]( description = 'Process some integers.' )
donc le coût d’une recherche dans cette structure de donnée.
parser.add_argument( 'integers',
metavar = 'N',
Création dynamique de variables type = int,
Python ne dispose pas que d’un typage dynamique, il permet
nargs = '+',
aussi de créer des variables à la volée. En effet, nous avons
help = 'an integer for the accumulator' )
un accès direct aux dictionnaires des variables globales ou
parser.add_argument( '--sum',
locales :
dest = 'accumulate',
• globals() : retourne le dictionnaire des variables globales
action = 'store_const',
• locals() : retourne le dictionnaire des variables locales
const = sum,
Avec le code suivant :
default = max,
names = "xyz" help = 'sum the integers (default: find the max)' )
values = [ 1, "toto", [ 1, 2, 3 ] ]
d = globals() args = parser.parse_args()

‘args’ est initialisé en utilisant setattr à l’intérieur de la fonc-


for name, value in zip( names, values ):
tion parse_args. Cette façon de programmer permet de créer
d[ name ] = value
à la volée des variables.
on obtient la liste des variables suivante dans Spyder : Ce mécanisme permet de mettre en place un système qui
chargerait une configuration à partir d’un fichier et créerait
des variables. Nous avons une application qui s’exécute sur
plusieurs environnements (production, intégration, dévelop-
pement). Pour chaque environnement nous avons un fichier
« [Link] » contenant les paramètres utiles (connexion au
serveur, à la base de données, les répertoires utiles, etc.) :

# connexion
[Link]=[Link]
[Link]=8080
[Link]=zeus
[Link]=jupiter
[Link]=MY_DB
Ajout de variables à un objet [Link]=aphrodite
En python, tout est objet. Et les objets peuvent être étendu
[Link]=venus
par ajout d’attributs. Nous disposons des fonctions suivantes
pour manipuler la structure interne des objets Python :
# directories
• def hasattr( obj, attr_name )
[Link]=C\Temp\log
Le résultat est True si la chaîne attr_name est le nom d’un
[Link]=C:\Temp\input
des attributs de l’objet, sinon False. L’implémentation
[Link]=C:\Temp\output
appelle getattr(object, name) et regarde si une exception
AttributeError a été levée. Avec le programme suivant, nous allons pouvoir lire ce fichier
• def getattr( obj, attr_name [, default ] ) et nous servir des valeurs lues :
Retourne la valeur de l’attribut associé au nom dans Code complet sur [Link] & github
attr_name de l’objet obj. attr_name doit être une chaîne de La fonction « load_file » lit le fichier ligne par ligne et la fonction
caractères. Si la chaîne est le nom d’un des attributs de « add_variable » crée les variables et les attributs à la volée.
l’objet, le résultat est la valeur de cet attribut. Par exemple,
getattr(x, 'foobar') est équivalent à [Link]. Si l’attribut EVALUATION DYNAMIQUE
n’existe pas, et que default est fourni, il est renvoyé, sinon Nous avons appris à créer des variables et des attributs dyna-
l’exception AttributeError est levée. miquement. Mais est-on capable d’évaluer des formules ou
• def setattr( obj, attr_name, attr_value ) du code dynamiquement ? Si j’ai une formule récupérée
C’est la fonction complémentaire de getattr. Les arguments dans un formulaire, puis-je en évaluer la valeur en fonction ?
sont : un objet Python, une chaîne de caractères, et une
valeur à associer à l’attribut. La chaîne peut nommer un Évaluation de formule
attribut existant ou un nouvel attribut. La fonction assigne C’est en 2000 que j’ai eu la première fois besoin d’évaluer
la valeur à l’attribut, si l’objet l’autorise. Par exemple, setat- dynamiquement des formules. Je travaillais sur un logiciel de
tr(x, 'foobar', 123) équivaut à [Link] = 123. CAO et je créais un plug-in en C++ qui allait permettre de

[Link] 73
072_075.qxp_248 18/10/2021 16:55 Page74

créer des objets 3D à partir d’équations paramétriques saisies tions. Cela permet de construire dynamiquement des fonc-
par un utilisateur dans une fenêtre de l’application. Créer une tions spécialisées ou des fonctions permettant de modifier
telle fonctionnalité m’avait demandé beaucoup de codes, des fonctions existantes via le mécanisme des décorateurs.
mais en Python cela s’avère beaucoup plus facile ; en effet, Supposons que nous souhaitions rajouter une fonctionnalité
il existe une fonction « eval » qui facilite la tâche : de logging :

from math import * def log( func ):


def wrapper( *args, **kwargs ):
formula = input( "formule?" ) print( F"enter in {func.__name__}" )
a = float( input( "a?" ) ) res = func( *args, **kwargs )
b = float( input( "b?" ) ) print( F"exit from {func.__name__}" )
nb = int( input( "nb?" ) ) return res

h = ( b - a ) / nb return wrapper
for i in range( nb + 1 ):
x=a+i*h @log
print( "f(", x, ") =", eval( formula ) ) def compute( x ):
En l’exécutant, on obtient : return x*x*x
formule?x*x
a?0 print( compute(3) )
b?1
Dans ce cas-là, « wrapper » dépend de la fonction passé en
nb?10
paramètre de la fonction « log » et la fonction paramétrique
f( 0.0 ) = 0.0
est créée en appliquant « @log » à la fonction « compute ».
f( 0.1 ) = 0.010000000000000002
f( 0.2 ) = 0.04000000000000001
Création de module
f( 0.30000000000000004 ) = 0.09000000000000002
Un module peut être un simple fichier Python. Et la comman-
f( 0.4 ) = 0.16000000000000003
de « import » permet de charger un module. La question que
f( 0.5 ) = 0.25
l’on peut se poser est : peut-on créer dynamiquement un
f( 0.6000000000000001 ) = 0.3600000000000001
module et le charger ?
f( 0.7000000000000001 ) = 0.4900000000000001
À quoi pourrait servir ce type de fonctionnalité me direz-
f( 0.8 ) = 0.6400000000000001
vous ? Plaçons-nous dans un contexte embarqué avec des
f( 0.9 ) = 0.81
ressources limitées comme un petit robot piloté par un pro-
f( 1.0 ) = 1.0
gramme Python. Notre seul moyen de communication avec
Les fonctions paramétriques notre robot est via un réseau non-filaire (un wifi par
En Python, une fonction est un objet comme un autre : nous exemple). La tâche que doit accomplir notre robot est pro-
pouvons créer des alias à des fonctions et nous pouvons grammée dans un module appelé « mission ». Sa tâche ter-
retourner une fonction d’une fonction. Cette fonctionnalité minée le robot a encore de l’autonomie. Il nous faut donc
peut sembler obscure, au premier abord, et peu utile, mais mettre à jour sa mission :
c’est, en fait, une fonctionnalité extrêmement utile de • envoyer un fichier texte contenant la nouvelle mission
Python : elle est notamment à la base des décorateurs. • recharger le module via un appel à [Link]
Prenons l’exemple suivant : • exécuter la fonction principale du module « mission »
Essayons le code suivant :
def f( a ):
def _f( x ):
import importlib
return x + a
return _f
while True:
formula = input( "f(x)=" )
h = f(3)
if len(formula) == 0:
print( h, end='\n\n' )
break

for i in range(5):
texte = F"""
print( h(i) )
from math import *
Lorsque l’on fait « h=f(3) », h est une fonction : <function
f.<locals>._f at 0x0000023C1B386DC0>. Et dans la def f(x):
boucle, le programme affiche bien la valeur i+3 à chaque return {formula}
itération. « f » est une fonction qui crée une nouvelle fonction """
(que l’on stocke dans « h ») qui dépend des paramètres de
« f ». Certes c’est moins dynamique que la fonction « eval », with open( "my_module.py", "w" ) as file:
mais cela permet d’adapter du code en fonction de condi- [Link]( texte )

74 [Link]
072_075.qxp_248 18/10/2021 16:55 Page75

• complexe : les nombres complexes


try:
• str : chaînes de caractères
[Link]( my_module )
• list : listes
except:
• dict : dictionnaires
import my_module
• tuple : tuple
print( my_module.f(3) )
• set : ensemble
Si je l’exécute et, qu’à la question « f(x)= » je rentre « x*x » Il permet de sauvegarder et/ou restaurer des données.
comme formule, j’obtiens l’affichage de 9 ce qui est la bonne
réponse. Si, à l’itération suivante, je rentre « x*sin(x) » dill
comme formule j’obtiens 0.4233600241796016 comme « dill » est une extension que l’on peut télécharger sur PyPI
résultat (ce qui est bien 3*sin(3)). via la commande : « pip install -U dill ». C’est une version
améliorée de pickle car elle permet de sérialiser/désérialiser
Compilation : convertir un texte en des types de données supplémentaires :
code exécutable • des instances de classes
Python fournit différentes fonctions permettant d’accéder • fonctions avec yield
directement à l’exécution ou à la compilation (en byte-code) • fonctions lambda
d’un répertoire, d’un fichier ou d’une chaîne de caractères. • nested functions : fonctions paramétriques
Nous allons nous concentrer uniquement sur la fonction • un objet « code »
« exec ». Voici un exemple de sérialisation de fonction :

from math import * import dill as pickle


from math import *
fct = input( "g(x)? " )
code = F""" def f(x):
def g(x): return x*sin(x)
return {fct} with open( "c:/temp/[Link]", "wb" ) as file:
""" [Link]( f, file )

Et voici la désérialisation associée :


exec( code )
for i in range( 10 ): import dill as pickle
print( "g(", i, ")=", g( i ) )
with open( "c:/temp/[Link]", "rb" ) as file:
En tapant « 5*x*x » à la question « g(x)? », nous créons dyna-
f = [Link]( file )
miquement la fonction g grâce au code contenu par la chaî-
ne de caractères « code », puis nous évaluons la fonction g
for i in range( 11 ):
avec des arguments comme si c’était une fonction Python
x = 0.1 * i
normale. La fonction « exec » se base sur le contenu de « glo-
print( F"f({x}) = {f(x)}" )
bals() » et « locals() ». Il existe une fonction « compile » qui
permet de compiler du code avec des options d’optimisation Cette méthode est intéressante car elle permet de transmettre
(voir [Link] pour plus du code sous un format binaire entre un client et un serveur.
de détails). Le résultat étant un objet « code » qui peut ensui- Prenons le cas d’une application client lourd de type CAO
te être exécuté via « exec »… (modélisation mécanique 3D) qui contient des fonctionnalités
gratuites et d’autres payantes. Les fonctionnalités sont trop
SÉRIALISATION/DESERIALISATION lourdes en données à transférer ou en calculs pour les exécu-
Sauvegarder et restaurer les données est une nécessité pour ter du côté serveur : on souhaite les exécuter côté client. Afin
toute application. Mais cela devient aussi un impératif si l’on de réduire le risque de piratage des fonctions payantes, nous
doit échanger des données via un réseau. Convertir une don- pouvons mettre en place la mécanique suivante :
née en un flux de bytes est appelé marshalling en anglais • clic sur la fonctionnalité payante
(sérialisation) et l’action inverse est appelé unmarshalling • connexion au serveur
(désérialisation). Avoir ce type de fonctionnalité disponible • vérification de la licence ou du paiement
participe aux créations dynamiques. • téléchargement de la fonctionnalité via un fichier « dill »
• exécution de la fonctionnalité
pickle • suppression du fichier téléchargé
Python propose le module pickle qui est le plus simple à
mettre en œuvre tout en restant efficace pour sauvegarder CONCLUSION
les combinaisons des types simples suivants : Python se rapproche du LISP pour sa capacité à faire évoluer
• NoneType son code et ses données. Cela permet de développer en
• bool : les booléens à valeur True ou False Python des fonctionnalités avancées qui nécessiterait d’inter-
• int : les entiers longs facer un interpréteur dans des programmes écrits dans
• float : nombres flottants en double précision d’autres langages.

[Link] 75
076_080.qxp_249 18/10/2021 16:55 Page76

Zoom sur l’interopérabilité


Kotlin et Java PARTIE 2
Sallah Kokaina Depuis l'officialisation de Kotlin en tant que langage de développement pour les apps
Ingénieur en
informatique et auteur Android en 2019, ce langage, créé en 2011 par Jetbrains, a gagné en popularité et en
du livre « Software
Craftsmanship : L’art du
adoption au sein de la communauté des développeurs pro-JVM.
code et de l’agilité
Conçu pour être totalement interopérable avec Java, il apporte peut relever que la création d'une nouvelle instance de
technique en
entreprise » (Éditions un ensemble d'avantages en productivité de développement. [Link] ne nécessite pas l'opérateur new. En effet,
ENI 2019). Sur ces 12 Ainsi, il est possible d'appeler autant du code Java depuis Kotlin ne dispose pas de l'opérateur new. Ainsi, pour créer
dernières années, il a Kotlin que du code Kotlin depuis Java. Cela en fait donc un une instance de classe, il suffit d'appeler le constructeur
tenu différents rôles atout pour la programmation fonctionnelle et orientée objet comme on le ferait avec toute autre fonction.
(Développeur, CTO,
en entreprise. On y retrouve une gestion avancée de null- • Intégration syntaxique: Les “syntaxics sugar” de Kotlin, tels
Qualiticien, Manager
Technique…) au sein de safety, l'intégration d'extension de classes ou encore des opti- que l'opérateur d'indexation [], s'intègrent de façon naturel-
différentes structures et misations en temps de compilation avantageux par rapport à le avec les classes de Java. Ainsi, l'opérateur d'indexation
y a mis en place des langages JVM similaires tels que Scala. Aujourd'hui, à sa encapsule respectivement les méthodes set et get quand il
différentes solutions version 1.5+, Kotlin fournit une interopérabilité totale avec s'agit d'affecter et d'accéder aux valeurs de la liste.
basées notamment sur
Java 6+, toutefois la compilation en 1.6 est désormais obso- • Intégration Librairies Java tierces: Les libraires tierces, telles que
Scala, Kotlin et Java.
Twitter (@koksbox). lète, privilégiant la version 1.8 par défaut. Sans plus attendre, Google Guava n'échappent pas à la règle. Elles s'intègrent et
explorons-en les caractéristiques qui expliquent l'intérêt de peuvent être invoquées à l'image de la librairie Standard Java.
migrer de Java vers Kotlin tout en gardant le meilleur des Dans l'exemple ci-dessus, on a pu instancier une liste avec la
deux mondes. classe Lists de Guava et en enrichir les fonctionnalités avec la
fonction sum. Ceci est possible grâce à la notion d'extension que
Du code Java depuis du code Kotlin l'on abordera plus tard dans l'article. À ce stade, on notera que
C'est le sens le plus naturel et qui permet de bénéficier de la la fonction sum est un rajout de Kotlin à l'interface Iterable, implé-
modernité syntaxique de Kotlin tout en réutilisant l'ensemble mentée par la classe ArrayList. Magique, non ? 😉
du capital de librairies et fonctions écrites en Java (JUnit,
Guava, Spring ou encore la SDK Android). Nous allons illus- Gestion de setters et getters
trer différentes propriétés mettant en lumière l'invocation de Une autre force de Kotlin est la gestion implicite des asses-
Java au sein d'un code Kotlin. seurs (getters) et mutateurs (setters). En effet, au sein de Kotlin,
il n'est pas nécessaire d'appeler le getter ou setter pour modi-
Invoquation de librairies fier une propriété telle que la bonne pratique d'encapsulation
Il est possible d'appeler des librairies écrites en Java depuis le recommande en Java. Et en passant, c'est l'une des pra-
Kotlin. Prenez par exemple le code ci-dessous. tiques qui rend le code java particulièrement verbeux.
Ainsi, la modification ou la lecture de la valeur d'un attribut
import [Link]
de classe mutable (var) se fait directement en manipulant la
import [Link]
propriété en question, hello dans l'exemple ci-dessous.

fun main(args: Array<String>) {


//Kotlin
class GetSet(var hello: String)
// 1. Libraries standard
val months = ArrayList<String>() // [Link]
fun main(args: Array<String>) {
[Link](arrayOf("Janvier", "Février", "Mars"))
// Kotlin
val gs = GetSet("Hello !")
//2. Altération & Itération sur ArrayList via iterator()
print([Link]) // hello !
arrayList[2] = arrayList[0] // Equivalent en Java à [Link](2, array
[Link](0))
[Link] = "toto"
for (item in arrayList) { println(item) } // ("Janvier", "Février", "Janvier")
print([Link]) // toto
}
//3. Librairie tierce (Google Guava)
val numbers = [Link](4, 2, 22, 43)
// Equivalent à GetSet(var hello: String)
println([Link]()) // 71
class GetSetEq(hello: String) {
}
var hello : String = hello // hello représente un backing field
On retrouve les illustrations suivantes: get() { return field } // méthode redondante
• Intégration Librairie Standard Java: On peut voir qu'il est set(value) { field = value } // méthode redondante
aisé d'appeler la librairie standard Java depuis Kotlin. On }

76 [Link]
076_080.qxp_249 18/10/2021 16:55 Page77

println(nullable2?.length) // null
En effet, pas besoin de déclarer les setteurs et getteurs, ils sont générés
automatiquement grâce aux mot-clés val et var. Et comme illustré
//2. Pas Nullsafe: Infération avec NullPointerException (NPE)
précédemment, les propriétés de classe sont publiques par défaut.
val infTest = test() // Inferred type: String (by default)
/ Java println([Link]) // 15
public class GetSet {
private String readOnly = "Only getter defined"; val infTestNull = testNull() // Inferred type: String (by default)
private String writeOnly = "Only setter defined"; println([Link]) // NullPointerException
private String readWrite = "Both defined";
Toutefois, l'interopérabilité entre les deux langages introduit des
problèmes de mapping et de gestion de null pour les objets prove-
public String getReadOnly() { return readOnly; }
nant de code Java.
En règle générale, les types primitifs (int, boolean, long,..) sont
public void setWriteOnly(String writeOnly) { [Link] = writeOnly; }
associés par le compilateur au type Kotlin non null, en l'occurrence
([Link], [Link], [Link],...), définis au sein de la
public String getReadWrite() { return readWrite; }
librairie standard de Kotlin. Mais les types non-primitifs (Integer,
public void setReadWrite(String readWrite) { [Link] = readWrite; }
Boolean, Long, String..), seront traduits, sans déclaration explicite,
}
en leur équivalent Kotlin non-null. Chose qui peut créer un NPE tel
qu'illustré par l'infération par le compilateur du type String, au lieu du
// Kotlin
type null-safe : String?. Il est ainsi fortement recommandé d'expliciter
private val gs = GetSet()
le type retourné à l'invocation d'une méthode Java. Cependant,
println([Link]) // Read-only attribute acts like a val property
avoir à expliciter le type ou encore traiter toutes les valeurs comme
éventuellement nullable avec l'opérateur ? peut rapidement encom-
[Link] = "I have both" // Read-write attribute acts like a var propertyprintln
brer le code avec des vérifications inutiles. Pour réduire ce besoin,
([Link])
Kotlin supporte les annotations @Nullable et @NotNull prévenant
de la JSR 305, ou encore @NonNull de la JSR 308 pour les types
[Link]("No getter") // Write-only properties not supported in Kotlin
génériques.
Cette conversion automatique vers une propriété de classe Kotlin
// Java
fonctionne du moment que la classe Java fournit une méthode sans
public static @Nullable String nullable() { return null; }
paramètres commençant par get et éventuellement une méthode à
public static @NotNull String nonNull() { return "Could be null, but with warning"; }
paramètre unique commençant par set. Cela fonctionne également
pour les expressions Boolean où le getter commence par it au lieu
// Kotlin
de get, mais il n'y a actuellement aucun mécanisme de ce type si
val s1 = nullable() // Inferred type: String?
elles commencent par has ou d'autres préfixes. Les propriétés de
val s2 = nonNull() // Inferred type: String
type WriteOnly (écriture seule) ne sont actuellement pas supportées
par Kotlin, raison pour laquelle setWriteOnly ne peut être appelée Point important: Les objets annotés @NotNull en Java et qui contien-
avec une propriété de syntaxe comme étant un WriteOnly. nent une référence nulle par erreur pourront toujours causer des
NullPointerException en Kotlin. C'est pour cette raison qu'il est néces-
Gestion de null saire de redoubler de vigilance sur les inférences de type en intégrant
Kotlin a pour avantage une gestion avancée des valeurs nulles. les deux langages. Pour finir, on notera que les IDE tels qu’Android
Ceci offre aux programmes implémentés dans ce langage la carac- Studio et IntelliJ peuvent afficher des warnings dès lors que les anno-
téristique de null-safety. Cette caractéristique est l'une des raisons tations JSR 305/308 sont utilisées dans le code Java intégré. Cela per-
principales pour laquelle Kotlin est devenu à ce jour le langage pré- met d'anticiper les risques, voire les besoins de gestion de null-safety.
féré pour la réalisation de solutions mobiles, offrant par ailleurs le
même avantage qu'en programmation iOS via Swift. Vous l'aurez Conflits d'identifiant syntaxiques
compris, moins de NullPointerException, moins de crashs ! Les mot-clés réservés sont un autre point clé à garder dans le viseur.
Par exemple, l'opérateur ? permet d'indiquer qu'une valeur peut être Comme on a pu le voir dans les précédents exemples, Kotlin possède
éventuellement nulle et ainsi en sécuriser l'accès. un ensemble de keywords syntaxiques: val, var, when, fun... Ces mot-clés
déclaratifs en Kotlin ne le sont pas en Java, du moins pas dans cer-
// Java taines versions. Il est ainsi possible en Java, par exemple dans la ver-
public static String test() { return "Je peux être null"; } sion 8, de déclarer une variable portant le même nom. L'exemple ci-
public static String testNull() { return null; } dessous l'illustre :

//Kotlin // Java
class KeywordsAsIdentifiers {
//1. Nullsafe: Gestion explicit de null, public int val = 100;
val test: String? = test() // Explicit type: String? public Object object = new Object();
println(nullable?.length) // 15 public boolean in(List<Integer> list) { return true; }
public void fun() { [Link]("This is fun."); }
val testNull: String? = testNull() // Explicit type: String? }

[Link] 77
076_080.qxp_249 18/10/2021 16:55 Page78

Pour les invoquer en Kotlin, il est nécessaire d'utiliser des backticks (`).
val result = value1 + value2 - value3 // Uses ‘plus’ and ‘minus’ as operators
// Kotlin println([Link]) // 42
val kai = KeywordsAsIdentifiers()
Du code Kotlin depuis du code Java
println(kai.`val`) // 100
Il est tout aussi possible d'embarquer une librairie de code Kotlin au
println(kai.`object`) // [Link]
sein d'un projet Java. Bien que ce sens soit moins conventionnel, il
println(kai.`in`(listOf(1, 2, 3))) // true
n'en est cependant pas dénué d'intérêt. Vous pouvez par exemple
println(kai.`fun`()) // This is fun.
avoir un projet Legacy Android écrit en Java dans lequel vous vou-
Pas de panique, dans la mesure où ce cas de figure devrait se pro- lez réutiliser un module écrit pour un projet plus récent réalisé en
duire, certains IDEs, tels qu'Intellij, intègrent une gestion de ces Kotlin, chose qui vous permet de capitaliser sur une base de code
mots-clés. Ainsi, les backsticks seront rajoutés automatiquement. existante.
Le compilateur de Kotlin traduit toutes les instructions en Java
Gestion de SAM avant de les compiler en bytecode JVM. Au sein de l'IDE Intellij
En Java, on définit depuis la version 8, une interface fonctionnelle IDEA, Il est possible de voir comment un fichier Kotlin sera traduit
comme une interface contenant une seule méthode abstraite. Les en Java. Pour le faire, il suffit d'ouvrir le raccourci de commande
interfaces fonctionnelles sont la base des expressions lambda. On (Shift+Shift) et de saisir 'skb' (Show Kotlin Bytecode), puis de cli-
peut énumérer différentes interfaces dans la librairie standard de quer sur “Décomplier”.
Java : Comparator, Consumer, Collector. Code complet sur [Link] & github
Une simple déclaration data class Personne(...) en Kotlin va ainsi être tra-
// Java
duite en une classe Java intégrant:
interface Producer<T> { // SAM interface (single abstract method)
• Les getters et setters des propriétés de classe : On y verra la créa-
T produce();
tion de getters et setters pour les propriétés en var (i.e age), et que
}
des getters pour les propriétés déclarées en val. En plus, le com-
pilateur rajoute le modificateur final pour les propriétés immuables
// Kotlin
nom et adresse.
private val creator = Producer { BigDecimal(9000) }
• La gestion de hashcode, equals, copy et toString, offrant ainsi
// Inferred type: Producer<BigDecimal>
une implémentation par défaut de ces fonctions.
L'instrumentalisation de ce type d'interface depuis un code Kotlin, • Les annotations de la JSR 305 illustrant la gestion des nulls, tel
ne nécessite pas la création d'une inner-classe ou encore d'un objet. que décrit dans la section précédente.
Il suffit simplement d'invoquer une Lambda telle qu'illustrée dans • Les appels à Intrinsics, insérés par le compilateur Kotlin et per-
l'exemple ci-dessus. Et comme on le constate, la syntaxe est plus mettant de faire des vérifications supplémentaires au runtime.
légère avec l'inférence de type en prime. • La création de méthodes dites synthétiques. Celles-ci permettent de
gérer les invocations depuis Kotlin, tel que l'appel du constructeur
Operators functions Personne sans fournir l'âge qui prend 10 comme valeur par défaut,
Par conception, la surcharge d'opérateurs arithmétiques en Java chose qui n'est pas supportée par Java.
n'est pas supportée. Il n'est pas possible de soustraire ou bien d'ad- Ceci est un aperçu du nombre de lignes de code que l'on peut écono-
ditionner des Objets. Mais dans les langages JVM modernes tels miser à l'aide de Kotlin. On peut désormais comprendre que certains
que Scala ou Kotlin, c'est une pratique courante. Le plus amusant concepts propres à Kotlin n'ont pas nativement leur pareil en Java (i.e
dans tout ça, est que dans le cadre de l'interopérabilité entre Java extensions, file-level functions, file-level class, reified inline func-
et Kotlin, on peut conserver la même richesse syntaxique en mani- tions...), que le code Java généré peut parfois s'avérer faiblement opti-
pulant des Objets Java depuis Kotlin. Par exemple, Il suffit de définir misé, et malheureusement engendrer des collisions de noms.
au sein de la classe Java les méthodes dites operator telles que plus, Dans ce dernier cas, quand on passe d'un univers Kotlin où il est
minus, inc ou div. Cela permet ainsi d'appliquer depuis Kotlin des opé- possible de créer plusieurs classes dans un même fichier, à un uni-
rateurs arithmétiques aux instances de l'objet Java. vers Java dénué de cette flexibilité, on constatera en fonction des
cas que des classes sont générées avec des noms par défaut.
// Java
public class Box { // [Link]
private final int value; package [Link]

public Box(int value) { [Link] = value; } class FileLevelClass // génère la classe [Link]
public Box plus(Box other) { return new Box([Link] + [Link]); } object FileLevelObject // génère [Link] en tant
public Box minus(Box other) { return new Box([Link] - [Link]); } que Singleton
public int getValue() { return value; } fun fileLevelFunction() {} // s'insère dans la classe générée
} SampleNameKt
val fileLevelVariable = "Usable from Java" // s'insère dans la classe
// Kotlin générée SampleNameKt
val value1 = Box(19)
Mais pour notre plus grand bonheur, Kotlin vient avec un ensemble
val value2 = Box(37)
de moyens et d'annotations pour contribuer à influencer le code
val value3 = Box(14)
Java généré.

78 [Link]
076_080.qxp_249 18/10/2021 16:55 Page79

valent Java. Et contrairement aux fonctions déclarées au niveau


file-level, les méthodes déclarées au sein d'un object ne seront pas
Annotations par défaut converties en méthodes static. Par conséquent, il sera
Kotlin fournit un ensemble d'annotations pour ajuster le comportement nécessaire d'accéder à l'instance pour les invoquer.
du compilateur et ainsi maîtriser le bytecode JVM qui sera généré. Dans
// Au sein d'une méthode Java
cette section, nous allons en illustrer quelques-unes:
[Link]("car", new Coin()); // Pas joli
(new Coin()).produceCoin(); // Pas joli
@JvmField
Par défaut, Kotlin expose les propriétés de classe via des getters et
[Link](); // Pas possible
setters publics, ajustant à private la visibilité des propriétés concer-
[Link]("supercar", new Coin()); // Pas possible
nées.
Code complet sur [Link] & github En intégrant l'annotation JvmStatic, on peut instruire au compila-
Comme l'exemple ci-dessus le montre, l'annotation JvmField per- teur de permettre un accès dit static à ces fonctions, comme on s'at-
met d'exposer la propriété en tant que champ public. La génération tendait à pouvoir le faire en Java. L'exemple ci-dessous en est une
d'assesseurs d'encapsulation est ainsi évitée pour la propriété expo- illustration:
sed.
// Kotlin
class Coin {
@file:JvmName & @file:JvmMultifileClass
companion object Factory { // Companion level
Par défaut, tout fichier Kotlin est transcrit en au moins une classe
@JvmStatic fun produceCoin() { … }
Java contenant le suffixe Kt. Un fichier [Link] donnera lieu à la
}
création d'un fichier Java nommé [Link]. Si le fichier
}
[Link] contient des classes et des objets avec un nom distinct,
Kotlin produira autant que fichier de classe que nécessaire. (ref.
// Inside a Java method
section intro). Mais dans le cas où le projet Java contient déjà une
[Link](); // désormais possible
classe portant le même nom (Exemple), l'annotation file:JvmName
[Link](); // possible aussi
offre la possibilité de contrôler le nom final que portera la classe,
réduisant ainsi le risque de collision. @JvmName
Comme on a pu le voir précédemment, il n'est pas nécessaire de
// [Link]
créer les getters et setters en Kotlin. Ceux-ci sont automatiquement
@file:JvmName('Utils')
générés. En plus, ils deviennent de facto le point d'entrée principal
pour modifier un attribut de classe depuis Java. Par effet de bord,
package [Link]
les attributs de classe de type Boolean génèrent aussi des assesseurs
avec le préfixe get. Toutefois, si le préfixe d'un champ est is, le getter
class FileLevelClass // Génère la classe [Link]
généré garde is comme préfixe, que ce soit pour un type Boolean ou
object FileLevelObject // Génère [Link] en
autre. Concernant le setter, le préfixe is sera remplacé par un set.
Singleton
Code complet sur [Link] & github
fun fileLevelFunction() {} // Membre de la classe Utils
Cependant, cette génération automatique de setters et getters peut
val fileLevelVariable = "Usable from Java" // Membre de la classe Utils
avoir des effets indésirables. Elle pousse à adapter les conventions
En complément, l'annotation file:JvmMultifileClass permet de de nommage côté Java et dans le pire des cas, à briser la compila-
donner le même nom Java à plusieurs fichiers Kotlin. Cette tion dans les projets en dépendance. Pour réduire cet effet, il est
approche n'est toutefois pas recommandée, dans la mesure où elle possible d'utiliser l'annotation JvmName.
ouvre la porte à des collisions de noms.
// Kotlin
Code complet sur [Link] & github
class KotlinClass {
var mutable: Boolean = false
@JvmStatic
@JvmName("isMutable") get // Spécifie le nom du getter côté Java bytecode
Cette annotation est spécifique aux instances de type object. Au sein
@JvmName("mutable") set // Spécifie le nom du setter côté Java bytecode
de Kotlin, ceux-ci peuvent être de type top-level ou companion.
}
// Kotlin
object Cache { // Top level // Java
fun cache(key: String, obj: Any) { … } boolean value = [Link](); // Le getter est accessible en
} tant que ‘isMutable’
boolean newValue = [Link](true); // Le setter est accessible
class Coin { en tant ‘mutable’
companion object Factory { // Companion level
Comme illustré dans l'exemple ci-dessus, grâce à l'annotation
fun produceCoin() { … }
JvmName, il est possible de maîtriser le nom des setters et getters
}
qui seront générés. Ainsi, même si la variable mutable est amenée à
}
changer de nom dans le code Kotlin, il n'y aura pas d'impact sur le
Un objet, censé contenir les membres statiques, sera transcrit en un code Java vu que les getters (i.e isMutable) et setters (i.e mutable) gar-
singleton contenant une propriété INSTANCE au sein de son équi- deront le même nom.

[Link] 79
076_080.qxp_249 18/10/2021 16:55 Page80

@Throws • Les autres visibilités ne peuvent pas être mappées directement, mais
En Kotlin, les exceptions rejetées par une méthode ne sont pas décla- sont plutôt compilées selon la correspondance la plus proche :
rables au niveau de la signature. Contrairement à java, il n'y pas de • Les déclarations privées de haut niveau restent également pri-
clause Throws. Le bytecode JVM généré ne contient pas d'informa- vées. Cependant, pour autoriser les appels depuis le même fichier
tion permettant de gérer les exceptions côté Java de façon pro-acti- Kotlin (qui peut être une classe différente en Java), des méthodes
ve. Ce qui pourrait créer quelques effets indésirables pour le code synthétiques sont générées sur la JVM. De telles méthodes ne
appelant côté Java. C'est là que l'annotation Throws entre en jeu. peuvent pas être appelées directement, mais sont générées pour
Code complet sur [Link] & github transférer des appels qui ne seraient pas autrement possibles.
Comme illustré dans l'exemple ci-dessus, l'intégration de l'annota- Toutes les déclarations internal de Kotlin deviennent publiques, car
tion Throws, permet de rajouter la clause Throws au niveau de la package-private serait trop restrictif. Celles qui sont déclarées à l'in-
signature de la méthode dans le bytecode Java. Ainsi, côté java, il térieur d'une classe subissent une modification des noms pour éviter
devient obligatoire de gérer l'exception déclarée. Dans l'exemple ci- les appels accidentels de Java. Par exemple, une méthode interne
dessus, nous avons déclaré une seule exception, toutefois l'annota- [Link] apparaîtra comme [Link]$module() dans le bytecode, mais
tion peut recevoir une liste d'exceptions si nécessaire. elles ne sont pas invocables en tant que telles. Il est nécessaire
d’utiliser @JvmName pour modifier le nom dans le bytecode Java
Inline Functions et ainsi rendre l’appel possible.
Il est possible d'appeler des inline functions à partir de Java comme
n'importe quelle autre fonction, mais bien sûr, elles ne sont pas réel- Considérations supplémentaires
lement intégrées - une telle fonctionnalité n'existe pas dans Java. Les méthodes qui émettent une exception vérifiée en Java peuvent
L'exemple ci-dessous montre l'inlining lorsqu'il est utilisé depuis être appelées depuis Kotlin sans avoir à gérer l'exception. Ce
Kotlin. Il faut savoir que les inline functions avec des paramètres de concept (throws) n'existe pas en Kotlin et nécessite de redoubler de
type réifié ne peuvent pas du tout être appelées à partir de Java, car vigilance lors de l'intégration d'une librairie Java où certaines
elles ne prennent pas en charge l'inlining. Ainsi, il n'est pas possible méthodes déclarent dans leur signature des exceptions faisant par-
d'utiliser de paramètres de type réifié dans des méthodes qui tie ainsi du contrat d'API.
devraient être utilisables à partir de Java. Vous pouvez récupérer la classe Java d'un objet comme ceci
Code complet sur [Link] & github UnObjet::[Link] ou encore [Link]
Vous pouvez utiliser la réflexion sur les classes Java depuis Kotlin et
KClass Kotlin utiliser une référence à la classe Java comme point d'entrée. Par
KClass est la représentation Kotlin de l'objet Class Java. Elle fournit exemple, UnObjet::[Link] renvoie les
des capacités de réflexion. Pour une fonction Kotlin que l'on souhai- méthodes déclarées de la classe UnObjet.
terait appeler depuis Java et acceptant une Kclass, il sera possible L'héritage fonctionne de façon similaire entre Kotlin et Java; les
d'utiliser la classe prédéfinie [Link] comme deux ne prennent en charge qu'une seule superclass (abstraite ou
illustré dans l'exemple ci-dessous. Depuis Kotlin, on peut accéder non), mais n'importe quel nombre d'interfaces à implémenter.
plus facilement tant à l'objet Kclass que Class. Nothing: il n'y a pas d'équivalent au type Nothing de Kotlin en Java,
car même [Link] accepte null comme valeur. Comme il
// Java
s'agit toujours de la représentation la plus proche de Nothing dis-
import [Link];
ponible en Java, les types et paramètres de retour Nothing sont
import [Link];
mappés à Void. L'utilisation de Nothing comme argument de type
générique génère un type brut en Java pour au moins provoquer
KClass<A> clazz = [Link]([Link]);
des avertissements d'appel non contrôlés. Par exemple,
List<Nothing> devient une liste brute (List) en Java.
// Kotlin
Kotlin mappe non seulement les tableaux primitifs à leurs types
import [Link]
mappés correspondants (IntArray, LongArray, CharArray, etc.) et
vice versa, il n'encourt également aucun coût de performance par
private val kclass: KClass<A> = A::class
rapport à Java lorsque vous les utilisez. Certains des exemples de
private val jclass: Class<A> = A::[Link]
code référencés dans cet article ont été récupérés de l'excellent livre
Visibilité de Peter Sommerhoff, Kotlin for Android App Development. Un livre
Les déclarations de visibilité (private, protected, public) ne corres- qui aidera les lecteurs plus avancés à explorer plus de détails sur l'in-
pondent pas exactement entre Kotlin et Java, et en plus il existe des teropérabilité entre ces deux langages, qui à ce jour, est la plus
déclarations de niveau supérieur au sein Kotlin. Voyons donc com- grande force de Kotlin par rapport aux autres langages JVM.
ment les visibilités sont présentées sur Java. Premièrement, cer-
taines visibilités peuvent être mappées comme ci-dessous : Références
• Les membres privés restent privés et accessibles qu’au niveau de [Link]
la classe qui les déclare [Link]
• Les membres protégés restent protégés, au-delà de la classe [Link]
déclarante, ne sont accessibles que par les classes héritants et [Link]
présentes dans le même package. [Link]
• Les éléments à visibilité publique restent publiques sont acces- java-interoperability
sibles sans restriction. [Link]

80 [Link]
081_082.qxp_249 19/10/2021 17:12 Page81

Par les deux bouts de la lorgnette


Les apps changent, pas seulement parce qu’elles migrent vers le cloud avec ses ser-
vices de nouvelles générations, mais aussi par la manière dont elles sont créées et
déployées. Les pipelines CI/CD permettent aux développeurs de déployer de nouvelles Jean-Baptiste Bron
applications ou de nouvelles fonctionnalités plusieurs fois par jour. Mais quelle est la Chief Architect pour l'avant
vente "Cloud Infrastructures
place des ops dans cette chaîne ? Certains parlent même de « no ops ». Services" France chez
Capgemini, je conçois des
solutions d'infrastructure en
Mais qui sont les ops ? cialisés pour superviser leur partie de la chaîne de l’informa-
relation avec mes collègues
Selon que l’on s’adresse à un développeur ou à un respon- tion. Il y avait des manques, certaines informations pouvaient des apps, du testing et de la
sable d’exploitation, la réponse peut changer. provenir de sources différentes, la consistance de l’informa- Cyber sécurité. Ces solutions
Le responsable d’exploitation répondra instantanément que tion pouvait varier en fonction du point de vue. On a alors se composent de blocs
les ops sont le travail de l’IT et des architectes et gestion- inventé les hyperviseurs ! Ceux pour viser, pas pour virtualiser. techniques mais aussi de
processus de support
naires de l’infrastructure (une petite voix dissonante me Le concept de « single source of truth » naissait.
innovants et agiles. Les
murmure que le responsable des services managés n’est pas Avec l’arrivée des applications modernes (new apps ici), les solutions se doivent d'être
d’accord à 100 %). hyperviseurs ont montré leurs limites et le public intéressé par globales et non isolées par
Le développeur me répondra lui, que les ops c’est le travail de les différents états de l’IT s’est diversifié. Les outils ont évolué silos. Elles se doivent avant
son PO (Product Owner) qui discute avec les métiers des avec les besoins, les applications (et le vocable) d’observabi- tout d'être opérables par
l'ensemble des parties
fonctionnalités livrées et à livrer et qui finalement, alimente lité sont apparues. Observabilité… Observabilité, subst.
prenantes autour de l'IT.
son backlog. On a donc en face de nous une chaîne de partie fém. : caractère de ce qui est observable.
Architect | Presales
prenante qui se répartit le travail autour d’un outillage de dé- [Link]
ploiement automatique. Notons que nous n’avons encore On observe quoi ?
interrogé que deux personnes. Une réponse partagée par l’ensemble des éditeurs se résume
La chaîne de responsabilité semble parcourir le chemin, de en trois points :
l’utilisateur de l’application jusqu’à l’infrastructure sous-ja- • Des logs
cente. Ce faisant, elle implique les « product owners » (PO), • Des traces
les développeurs, les concepteurs du pipeline de déploiement • Des métriques
et les concepteurs de la plateforme. (En lisant cette chaîne, Mais il peut en aller autrement si on s’intéresse aux motiva-
l’urbaniste ou Architecte d’entreprise me signifie qu’il ajoute- tions des observateurs. On peut par exemple observer les
rait quelques éléments). performances d’une application, d’un service, d’une infra-
Finalement, cette chaîne peut être perçue différemment sui- structure. On peut observer la disponibilité d’un serveur, d’un
vant notre interlocuteur et on se rend compte que les cluster, d’une base de données, d’un container.
responsabilités sont partagées au sein d’un groupe d’acteurs On peut observer aussi les coûts d’une plateforme, d’un ser-
qui doivent communiquer plus que jamais. vice cloud. Ce coût est souvent corrélé à l’utilisation réelle des
Les développeurs souhaitent plus que jamais être autonomes ressources réservées, on parle alors de FinOps.
dans le choix des technologies à mettre en œuvre. Les exploi- On peut observer la consommation électrique (la consomma-
tants souhaitent conserver la maîtrise des plateformes pour tion d’énergie en général) d’un datacenter, d’une plateforme,
répondre aux demandes qui leur sont faites. Les RSSI souhai- d’un serveur, d’une application.
tent plus de contrôle sur la nature des déploiements effectués On peut observer l’accès aux plateformes et aux données
et assurer la protection des données et des services de leur pour s’assurer de la confidentialité et du respect des régle-
entreprise. Les utilisateurs métier, ne demandent rien, si ce mentations (PCI DSS, Export Control, GDPR…).
n’est des applications et des plateformes qui leur permettent On peut observer l’expérience utilisateur en temps réel
de pratiquer leur métier. Ils ne souhaitent en aucun cas choi- (RUM), la durée d’exécution d’un processus, le nombre de
sir entre le cloud ou le Datacenter, entre OpenShift et Docker, transactions d’un même type, le nombre d’exemples dans le
entre Oracle et MongoDB. présent article…
Le seul souhait des métiers vis-à-vis de l’IT, c’est d’obtenir Bref ! On peut tout observer.
une plateforme applicative fonctionnelle, performante et Encore faut-il le consolider et le présenter aux parties pre-
sûre. Bref de pouvoir l’oublier une bonne fois pour toutes ! nantes intéressées.

L’observabilité Qui observe ?


Jusqu’à présent, les différents interlocuteurs impliqués dans La liste des indicateurs pouvant être observés donne le tour-
la gestion des systèmes informatiques utilisaient la supervi- nis. Aujourd’hui, les gestionnaires de service ne sont plus les
sion. Très vite, il s’est avéré qu’en fonction de ce qui devait seuls intéressés et les besoins des uns sont intimement liés,
être géré (applications, systèmes, stockage, réseau…) cer- voire subordonnés aux besoins des autres.
tains outils spécialisés mettaient en évidence les Essayons ensemble de remonter la chaîne alimentaire ou de
caractéristiques propres de l’objet supervisé. Les différentes la descendre, après tout, on n’est pas des saumons.
parties prenantes se sont donc mises à utiliser des outils spé- Les métiers sont intéressés par les indicateurs relatifs à leurs

[Link] 81
081_082.qxp_249 19/10/2021 17:12 Page82

services. Un responsable de secteur souhaitera savoir le On fait quoi de ces informations ?


nombre de produits vendus durant une opération promotion- Comme nous l’avons vu précédemment, ces informations
nelle. Un gestionnaire de services back office bancaire sont stockées dans un datalake afin d’être analysées et ex-
voudra être informé de la durée de ses traitements et du res- ploitées. La chaîne d’exploitation de ces données pour les
pect de ses cut off. Un logisticien souhaitera connaître les applications et les plateformes permettent aux développeurs
volumes transportés et les éventuels retards. de vérifier le comportement de leur code et aux Ops de véri-
Tous ces indicateurs sont disponibles dans les résultats d’ob- fier le fonctionnement de leur service métier.
servation des applications. En parlant d’applications, les En ce qui concerne le traitement des informations, les données
développeurs voudront connaître le bon fonctionnement de recueillies sont analysées par une intelligence artificielle (AIOps)
leur code, l’adéquation des technologies fournies à l’utilisa- afin de réduire la durée de résolution des incidents et problèmes.
tion qu’il en fait. Les performances réelles de l’application La chaîne de traitement des données liées à l’infrastructure
qu’il a développée. permet d’optimiser le fonctionnement des services gérés.
Les administrateurs seront intéressés par les performances de Ces deux chaînes doivent être compatibles, et être conçues
la plateforme en général, par la disponibilité des ressources parallèlement. Elles utilisent des composants hébergés sur
afin d’établir un plan de capacité, par les incidents et pro- site et d’autres services hébergés dans le cloud. On peut ima-
blèmes générés par le fonctionnement du système giner une telle plateforme totalement hébergée dans le
informatique. Un responsable de la sécurité sera lui plus ab- cloud. En effet, la volumétrie de systèmes à mettre en œuvre
sorbé par l’observation des flux et des accès, par les fuites de et à gérer pour réaliser des analyses en temps réel est bien
données et les usurpations. Tous ces interlocuteurs ont de souvent disproportionnée face à la volumétrie du parc IT du
bonnes raisons d’observer et ils ont besoin d’informations, client. De telles solutions sont proposées en SaaS par les dif-
voire, d’informations en temps réel. Les prestataires ont be- férents éditeurs et permettent de ne pas avoir à investir dans
soin de justifier de la qualité de leur service. une plateforme dédiée ni de materner depuis la phase em-
En prenant en compte l’ensemble de ces besoins, on se rend bryonnaire une intelligence qui reste artificielle, quoi qu’on
compte que le format des rapports équivalents est difficile à en dise. Ces outils ne sont en général pas une fin en soi, mais
produire, parfois même impossible à lire. Il faut donc diviser des moyens dédiés à l’amélioration des services proposés aux
les lecteurs de ces rapports en différents rôles et leur proposer clients. Les incidents sont automatiquement regroupés en
une vue du rapport focalisée sur leur profil. On peut parler de fonction de leur source, la résolution automatique de certains
Role Based Reporting. d’entre eux est appliquée et les autres préanalysés et trans-
La mise en œuvre des moyens d’observabilité assure l’ali- mis aux équipes les plus qualifiées. C’est le processus
mentation par les sources de données, le reporting, leur d’optimisation des services gérés. Cette optimisation est pro-
consommation par les intéressés. posée au client final pour améliorer la compétitivité du
service. Le but est d’anticiper les appels des utilisateurs et de
On observe avec quoi ? réduire le nombre d’incidents à résoudre manuellement. Il
En général, on observe avec les moyens habituels pour la su- s’agit enfin d’éviter les incidents prévisibles sans intervention
pervision des objets traditionnels, complétés par des outils humaine et sans émission de ticket de résolution.
capables d’observer le comportement des applications mo- Les prestataires peuvent aussi aider leurs clients à se doter de
dernes. Les éditeurs de telles applications sont présents leur propre chaîne d’observabilité et de résolution. Il s’agit
depuis l’apparition de ces applications cloud natives. alors de travailler en bonne intelligence et de coordonner les
Tous ces outils génèrent une quantité importante de données besoins des différentes parties prenantes en fonction de leur
qu’il faut canaliser dans un bus de données adapté à sa sour- maturité et de leurs besoins. Une telle chaîne d’observabilité
ce. Chaque source de données est plus ou moins compatible n’est pas un ensemble fini. Elle va croître avec le temps et les
avec les logiciels d’observabilité, mais une mise en forme de besoins émergents. Il est important de la concevoir évolutive
leur structure, à commencer par la référence temporelle, est et de s’assurer que ses nouvelles capacités ne perturbent pas
souvent nécessaire. Afin de préserver la possibilité de faire celles qui rendent le service existant.
évoluer les différents composants sans mettre en péril la sta- Les outils sont une chose, les processus, une autre. Une coordi-
bilité de l’ensemble de l’édifice, le bus de données est nation de bout en bout, depuis les métiers jusqu’aux
segmenté en différents conteneurs indépendants qui ont pour infrastructures est nécessaire à l’obtention de résultats tangibles.
but de canaliser les données d’une source vers un datalake. C’est un effort quotidien qui permet de faire bénéficier aux clients
Eh oui, les outils d’observabilité des applications modernes de méthodes agiles. Les frameworks (Scaled Agile Framework
sont modernes ! (SAFe), Large Scale Scrum, Disciplined Agile, Nexus…) permet-
Ce bus de données composite est appelé IPaaS. Le datalake tent, pour peu qu’on en choisisse (ou adapte) un, de travailler
utilisé pour stocker l’ensemble de ces données est adapté au ensemble à l’amélioration du service d’information dans sa glo-
contexte du client, de nombreux éditeurs proposent des outils balité. Un nouveau genre de spécialiste a même vu le jour : le
de captation, de transfert ou de stockage des données d’ob- SRE. Le SRE (voir la définition sur votre référentiel préféré) est le
servation, mais aussi des solutions d’analyse et de reporting mortier entre les briques de responsabilités au sein de l’entrepri-
adaptées. Ce qui était confidentiel et réservé aux aficionados se, le médiateur de la fiabilité, bref le spécialiste qui va vous
de l’open source est désormais convoité et promu par les édi- sauver la vie ! Oui, le DevOps est compatible avec la maîtrise des
teurs de solutions d’entreprise. infrastructures ! Oui, la gestion des infrastructures peut être un
peu plus agile qu’une poutre en titane !

82 [Link]
083.qxp_249 18/10/2021 16:56 Page83
084.qxp_249 18/10/2021 16:56 Page84

Vous aimerez peut-être aussi