<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Younup</title>
    <description>The latest articles on DEV Community by Younup (@younup_it).</description>
    <link>https://dev.to/younup_it</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F352848%2F3dca5aca-68fa-4f0d-b32c-3c3e9418ef65.png</url>
      <title>DEV Community: Younup</title>
      <link>https://dev.to/younup_it</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/younup_it"/>
    <language>en</language>
    <item>
      <title>Au secours la CNIL attaque mon cloud !</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 25 May 2023 07:40:03 +0000</pubDate>
      <link>https://dev.to/younup/au-secours-la-cnil-attaque-mon-cloud--471a</link>
      <guid>https://dev.to/younup/au-secours-la-cnil-attaque-mon-cloud--471a</guid>
      <description>&lt;p&gt;&lt;em&gt;Allo docteur, j'ai un problème ! La CNIL me fait un rappel à l'ordre pour non-respect de la RGPD sur une application en cloud, qu'est-ce que je peux faire ?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Bon déjà si vous n'avez pas lu la base de la RGPD, je vous invite à le faire, &lt;a href="https://www.younup.fr/blog/rgpd-le-devoir-de-proteger-les-donnees"&gt;ça se passe ici&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La RGPD dans le cloud, ce n'est pas qu'un choix de prestataire et d'infrastructure. C'est aussi quelques autres règles génériques que nous n'avons pas encore abordées, mais rassurez-vous, on va voir tout ça !  &lt;/p&gt;

&lt;h2&gt;
  
  
  Bien commencer et bien choisir son infrastructure en conformité avec la RGPD
&lt;/h2&gt;

&lt;p&gt;Lorsque vous choisissez une infrastructure, qu'elle soit dans le cloud ou pas, il y a plusieurs points à respecter. Il y a 3 points majeurs à adresser :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Faire une analyse d'impact relative à la protection des données&lt;/li&gt;
&lt;li&gt;Définir une sécurité par défaut&lt;/li&gt;
&lt;li&gt;Mettre en place une protection de données dès la conception.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Regardons plus en détails chacun de ces points.&lt;/p&gt;

&lt;h3&gt;
  
  
  L'analyse d'impact relative à la protection des données
&lt;/h3&gt;

&lt;p&gt;Lorsque vous développez une application ou mettez en place une infrastructure logicielle, vous devez évaluer et analyser les risques que représentent vos traitements de données.&lt;/p&gt;

&lt;p&gt;Cette analyse est même obligatoire si votre traitement engendre un risque élevé, par exemple pour les données présentant un risque direct pour l'utilisateur. Cela concerne par exemple les données médicales, financières ou commerciales. Elle est aussi obligatoire si le traitement que vous réalisez est dans &lt;a href="https://www.cnil.fr/sites/default/files/atoms/files/liste-traitements-aipd-requise.pdf"&gt;la liste des types d'opérations&lt;/a&gt; pour lesquelles la CNIL estime obligatoire de réaliser une analyse d'impact.&lt;/p&gt;

&lt;p&gt;Comment faire pour déterminer si vous devez faire cette analyse ? Très simplement en vérifiant si votre traitement répond à au moins 2 des critères suivants :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evaluation ou notation ;&lt;/li&gt;
&lt;li&gt;Décision automatisée avec effet juridique ou effet similaire significatif ;&lt;/li&gt;
&lt;li&gt;Surveillance systématique ;&lt;/li&gt;
&lt;li&gt;Données sensibles ou données à caractère hautement personnel ;&lt;/li&gt;
&lt;li&gt;Données personnelles traitées à grande échelle ;&lt;/li&gt;
&lt;li&gt;Croisement d’ensembles de données ;&lt;/li&gt;
&lt;li&gt;Données concernant des personnes vulnérables ;&lt;/li&gt;
&lt;li&gt;Usage innovant ou application de nouvelles solutions technologiques ou organisationnelles ;&lt;/li&gt;
&lt;li&gt;Exclusion du bénéfice d’un droit, d’un service ou contrat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La CNIL vous met même à disposition des outils pour vous aider à &lt;a href="https://www.cnil.fr/fr/gerer-les-risques"&gt;analyser et gérer vos risques&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Une sécurité par défaut
&lt;/h3&gt;

&lt;p&gt;Ce terme de sécurité par défaut est souvent entendu par accès au matériel, qu'il soit physique ou pas. La plupart du temps, on fait le choix du &lt;a href="https://www.ssi.gouv.fr/agence/publication/le-modele-zero-trust/"&gt;zéro trust&lt;/a&gt; (aucune confiance). Il s'articule autour de plusieurs points de sécurité :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ne pas avoir d'utilisateur ayant les droits absolus sur la machine. Chaque utilisateur a un périmètre bien défini qui lui est propre.&lt;/li&gt;
&lt;li&gt;Ne pas autoriser l'accès à une machine par défaut. Les utilisateurs doivent être ajoutés unitairement en fonction de leurs besoins.&lt;/li&gt;
&lt;li&gt;Ne pas faire confiance aux connections extérieures. Il faut donc rendre la machine accessible uniquement au sein du réseau dans lequel elle est utilisée et autoriser au cas par cas les accès à cette machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;C'est là que les premières contraintes liées au cloud peuvent arriver. Lorsque vous choisirez votre hébergement, il faudra vous assurer des niveaux de sécurité. En SAAS, vous ne devriez pas rencontrer trop de problème, mais en fonction de votre fournisseur, cela pourrait être de votre responsabilité en PAAS ou en IAAS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mise en place d'une protection des données dès la conception
&lt;/h3&gt;

&lt;p&gt;Lorsque vous développez votre logiciel, vous devez dès l'étape de la conception, identifier les données à caractère personnel et décider comment vous allez les sécuriser.&lt;/p&gt;

&lt;p&gt;Le plus simple et le plus courant est le chiffrement, mais vous pouvez bien entendu aussi les anonymiser. Il est surtout important de vous demander si vous en avez réellement besoin !&lt;/p&gt;

&lt;p&gt;Là aussi, le choix de votre hébergement peut avoir des conséquences, notamment sur leur manière de chiffrer les données ou sur le stockage de vos clés de chiffrement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choisir son fournisseur Cloud
&lt;/h2&gt;

&lt;p&gt;Bon, c'est bien gentil les règles, mais comment on fait pour choisir correctement son fournisseur ? Quels sont les points clés qu'il faut vérifier ?&lt;/p&gt;

&lt;p&gt;Et bien, le premier, le plus basique, c'est que votre fournisseur propose des garanties de conformité avec la RGPD. Il faut aussi déterminer la responsabilité du fournisseur. La CNIL vous met aussi à disposition &lt;a href="https://www.cnil.fr/sites/default/files/typo/document/Recommandations_pour_les_entreprises_qui_envisagent_de_souscrire_a_des_services_de_Cloud.pdf"&gt;les éléments devant figurer sur le contrat de prestation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On y retrouve :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;L'existence d'un système de remontée de plaintes et/ou de failles de sécurité ;&lt;/li&gt;
&lt;li&gt;Les moyens de traitement ;&lt;/li&gt;
&lt;li&gt;Les destinataires des données ;&lt;/li&gt;
&lt;li&gt;L'obtention du consentement du client ;&lt;/li&gt;
&lt;li&gt;L'existence de procédures simples pour respecter les droits des personnes concernées (comme les droits d'accès, de modification ou de suppression) ;&lt;/li&gt;
&lt;li&gt;La durée de conservation limite des données ;&lt;/li&gt;
&lt;li&gt;Les moyens de destruction ou de restitution des données en cas de fin ou rupture du contrat ;&lt;/li&gt;
&lt;li&gt;Les moyens de procéder à des audits ;&lt;/li&gt;
&lt;li&gt;Les contraintes de réversibilité, portabilité et traçabilité des données ;&lt;/li&gt;
&lt;li&gt;Devoir de coopération avec les autorités ;&lt;/li&gt;
&lt;li&gt;Qui est le responsable de traitement et le sous-traitant ;&lt;/li&gt;
&lt;li&gt;La liste des pays hébergeant les centres de données ;&lt;/li&gt;
&lt;li&gt;Assurance de protection adéquate à l'étranger ;&lt;/li&gt;
&lt;li&gt;La possibilité de limiter le transfert vers un pays reconnu en conformité avec la RGPD.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vous pouvez aussi vous assurez que le fournisseur a certaines certifications comme l'&lt;a href="https://fr.wikipedia.org/wiki/ISO/CEI_27001"&gt;ISO 27001&lt;/a&gt; ou &lt;a href="https://www.entrust.com/fr/resources/hsm/faq/data-protection-security-regulations/what-fips-140-2"&gt;FIPS 140-2&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu'est-ce qu'on peut mettre sur le cloud ?
&lt;/h2&gt;

&lt;p&gt;Maintenant qu'on a déterminé comment bien choisir son fournisseur, il serait temps de se demander si on peut tout mettre sur le cloud, vous ne croyez pas ?&lt;/p&gt;

&lt;p&gt;La réponse est tout simplement oui, mais en respectant le niveau de sécurité approprié.&lt;/p&gt;

&lt;p&gt;Premièrement, vous ne devez conserver les données personnelles que pour la durée nécessaire à la réalisation des fins pour lesquelles elles ont été collectées.&lt;/p&gt;

&lt;p&gt;Ensuite, pour toutes les données médicales, financières ou commerciales, vous vous devez d'avoir un niveau de sécurité supplémentaire, en plus de respecter les points déjà évoqués. Vous pouvez bien entendu demander conseil auprès d'un spécialiste de la question si besoin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Et après ?
&lt;/h2&gt;

&lt;p&gt;Lorsque vous avez fait tout ça et que votre logiciel est enfin déployé, il reste encore des choses à faire.&lt;/p&gt;

&lt;p&gt;Vous avez plusieurs obligations, notamment en cas d'attaque ou de fuite de données.&lt;/p&gt;

&lt;p&gt;La première, la plus logique, c'est d'identifier et de résoudre ce problème de sécurité. Votre contrat devrait vous aider à vous retourner contre votre fournisseur au besoin.&lt;/p&gt;

&lt;p&gt;Ensuite, vous avez l'obligation de notifier la CNIL et les personnes pouvant être impactées par cette attaque. Un mail est généralement suffisant, sauf si la donnée ayant été visée peut porter un préjudice vital pour la personne. Le délai de prévenance est de 72 heures. Au-delà de ce délai, vous devrez justifier du motif de ce retard. Cette notification doit contenir les informations sur la nature de la violation, une description des conséquences probables de l'attaque, ainsi que les mesures prises ou envisagées pour éviter que l'incident ne se reproduise. Si vous souhaitez plus d'information ou des outils sur ce sujet, vous pouvez vous rendre sur &lt;a href="https://www.cnil.fr/fr/notifier-une-violation-de-donnees-personnelles"&gt;l'excellente documentation de la CNIL&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enfin, vous avez un devoir de formation auprès de votre personnel. Cet article ainsi que toutes &lt;a href="https://www.cnil.fr/professionnel"&gt;les ressources fournies par la CNIL&lt;/a&gt; vous permettent de remplir ce devoir de formation.&lt;/p&gt;

&lt;p&gt;Bien entendu, en cas de doute ou de question, le meilleur reflexe reste de contacter un avocat spécialisé en protection des données. Il devrait aussi pouvoir vous aider notamment dans la réalisation du contrat avec votre fournisseur.&lt;/p&gt;

</description>
      <category>rgpd</category>
      <category>cloud</category>
    </item>
    <item>
      <title>DOD et DOR : mais qui êtes-vous ?</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 27 Apr 2023 07:25:23 +0000</pubDate>
      <link>https://dev.to/younup/dod-et-dor-mais-qui-etes-vous--230i</link>
      <guid>https://dev.to/younup/dod-et-dor-mais-qui-etes-vous--230i</guid>
      <description>&lt;p&gt;Lorsque l’on travaille dans un environnement agile, on entend régulièrement parler de la « DOD » et de la « DOR ». A plusieurs reprises, je me suis aperçu que ces notions étaient parfois abstraites ou méconnues. Dans certains cas, elles sont mises en place mais finalement peu ou pas utilisées, à l’image des bonnes résolutions que l’on prend en début d’année mais que l’on ne fait jamais…. Autant de signes qui m’ont donné envie de poser quelques lignes sur le papier afin que chacun puisse alimenter sa propre réflexion.&lt;/p&gt;

&lt;p&gt;Dans cet article nous allons tout d’abord partir à la rencontre de la DOD : quel est ce concept ? comment est-ce qu’on la construit ? doit-elle être mise à jour ? puis nous partirons à la découverte de sa petite sœur, la fameuse DOR. Nous verrons qu’il existe des points communs entre les deux.&lt;/p&gt;

&lt;h2&gt;
  
  
  DOD : DEFINITION OF DONE
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Le concept du « travail terminé » : de la vie quotidienne…à l’IT.
&lt;/h3&gt;

&lt;p&gt;La Definition of Done est aussi connue sous l’acronyme « DOD » comme vous l’aurez compris. Littéralement c’est la définition de ce qui est fini / terminé… « Definition of Done ».&lt;/p&gt;

&lt;p&gt;Une fois que l’on a dit ça, il est légitime de se poser la question suivante : c’est quoi un travail terminé ? Souvent j’ai constaté que chacun peut avoir sa propre définition.&lt;/p&gt;

&lt;p&gt;Pour commencer, prenons un exemple de la vie quotidienne : une personne que l’on nommera Paul demande à ses enfants de plier leur linge et de le ranger dans leur armoire. Quelques heures plus tard, Paul s’aperçoit que seuls les chaussettes sont regroupées par paires et rangées correctement. Le reste des habits étant trié par couleur et mis en tas sur le lit. Ce n’est pas ce que Paul avait imaginé... Pour les enfants le niveau de qualité du pliage et du rangement était suffisant mais pas pour Paul. Au travers de cet exemple on commence à comprendre qu’il peut être préférable que tout le monde ait la même définition du « travail terminé » afin d’éviter les mauvaises surprises…&lt;/p&gt;

&lt;p&gt;Pour revenir au monde de l’IT, quand on est amené à travailler en différentes étapes successives, il peut être important que l’on soit d’accord sur ce qu’est le travail terminé. L’objectif est de savoir quand on peut « pousser » notre travail à une autre étape afin qu’une tierce personne puisse le récupérer. Pour illustrer ce paragraphe, prenons l’exemple suivant : comment le Product Owner, peut-il considérer que le développement d’une US est terminé ? Comment peut-il déterminer que cette US peut rentrer dans le périmètre de la prochaine démo ? Dans ce cas, la DOD peut être un outil intéressant. Continuez la lecture vous allez comprendre pourquoi...&lt;/p&gt;

&lt;h3&gt;
  
  
  La DOD : de quoi est-elle composée ?
&lt;/h3&gt;

&lt;p&gt;De manière simple la DOD peut être caractérisée comme une liste de critères faisant référence à ce qu’il faut avoir fait pour considérer le travail comme terminé.&lt;/p&gt;

&lt;p&gt;Pour revenir à notre exemple, voici quelques critères qui pourront aider le PO à déterminer si une US peut être « démontrée » :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tests unitaires réalisés : ils couvrent 70% du code.&lt;/li&gt;
&lt;li&gt;Code validé : le code produit pour l’US a été revu par 2 pairs.
&lt;/li&gt;
&lt;li&gt;Documentation à jour : la documentation associée à l’US a été écrite ou mise à jour.&lt;/li&gt;
&lt;li&gt;Suivi à jour : JIRA ou un autre board ont été actualisés&lt;/li&gt;
&lt;li&gt;Démo prête : la « démo » a été préparée avec les données à utiliser et les différents cas à démontrer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jTErEcst--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gobguy6iwg1ix5atwgbh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jTErEcst--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gobguy6iwg1ix5atwgbh.jpg" alt="Image description" width="800" height="1193"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Attention rien n’est gravé dans le marbre ! Il peut exister plusieurs autres critères en fonction du projet et du contexte de l’entreprise !&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Notons que toutes les US sur un sprint donné ont la même DOD. Il faut considérer les critères de la DOD comme une invitation à la réflexion. Ecrire de la documentation pour toutes les US du backlog a-t-elle un sens ? Est-ce pertinent pour chaque US ? Est-ce que cela apporte de la valeur ? Il faut se poser la question et si la documentation pour une US n’est pas pertinente et bien il convient de ne pas la faire ce qui n’empêchera pas l’US d’être démontrée...&lt;/p&gt;

&lt;p&gt;Autrement dit la DOD ne doit pas être un frein on doit savoir parfois « lâcher un peu la corde » pour ne pas bloquer les développements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quand et comment la construire ?
&lt;/h3&gt;

&lt;p&gt;Sur la temporalité il n’y a pas de règles précises. En générale la DOD est déterminée avant le premier sprint planning. Certaines équipes la définissent en cours de projet car elles n’ont pas pensé ou jugé nécessaire de la réaliser avant. Il existe différentes manières de créer une DOD, citons en deux….&lt;/p&gt;

&lt;p&gt;Tout d’abord, l’équipe peut s’inspirer de la DOD d’autres équipes.  Imaginons une équipe qui découvre le contexte de l’entreprise ou qui fait ses premiers pas dans un environnement agile. Elle peut dans ce cas se baser sur une DOD déjà réalisée et utilisée, lui permettant d’avoir une première base de travail et d’échange afin d’éviter le syndrome de la feuille blanche. Bien évidemment il ne faut pas reprendre aveuglement la DOD de son « voisin » mais se demander quels sont les critères exploitables pour mon projet ? Il peut s’agir aussi d’un REX intéressant.&lt;/p&gt;

&lt;p&gt;L’autre piste à exploiter est celle de l’expérience du Scrum Master. Dans ce cas le Scrum peut proposer une liste de critères pour éclairer et guider l’équipe. Les différents acteurs choisissant alors les critères leur paraissant significatifs et adaptés au projet à un moment donné.&lt;/p&gt;

&lt;p&gt;Quelle que soit la méthode cela passe par une réunion d’équipe pour que les membres puissent définir ensemble une première DOD.&lt;/p&gt;

&lt;h3&gt;
  
  
  La DOD peut-elle évoluer ?
&lt;/h3&gt;

&lt;p&gt;Une seule réponse : oui ! La DOD peut évoluer, rien ne l’oblige à être statique dans le temps ! L’équipe peut ajouter des critères ou en supprimer. Bien souvent, la DOD évolue pendant le projet. Par exemple, si les acteurs rencontrent un problème et qu’ils aimeraient qu’il ne se reproduise pas et bien ils peuvent rajouter un critère dans la DOD. Au fur et à mesure la DOD est le reflet des apprentissages de l’équipe.&lt;/p&gt;

&lt;p&gt;Il est fortement déconseillé de la faire évoluer en plein milieu de sprint. Si l’équipe rajoute un critère impactant cela peut faire « exploser les compteurs » et perturber la réalisation des développements. Cependant, si pour le bien du produit un nouveau critère doit être absolument intégré sans perturber l’objectif et la date de fin du sprint alors la situation doit s’étudier…&lt;/p&gt;

&lt;h2&gt;
  
  
  DOR : DEFINITION OF READY
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Le concept du « travail prêt »
&lt;/h3&gt;

&lt;p&gt;La Definition of Ready, connu sous l’acronyme DOR est la liste d’éléments qu’une user story doit rassembler pour être candidate au développement. Ce sont les critères qui vont permettre à la user story de passer du backlog produit au backlog sprint. Elle est considérée comme un contrat entre le PO et les développeurs.&lt;/p&gt;

&lt;p&gt;La DOR peut être un« garde-fou » pour éviter les sprints plannings qui s’éternisent et qui peuvent impacter la motivation de l’équipe. Si une US respecte la DOR, les développeurs devraient avoir tous les éléments à disposition pour l’évaluer rapidement et précisément. On peut alors éviter de multiples questions en sprint planning et on minimise le risque de sous-estimer une US.&lt;/p&gt;

&lt;h3&gt;
  
  
  Création, mise à jour et composition : des points communs avec la DOD !
&lt;/h3&gt;

&lt;p&gt;Comme pour beaucoup de décisions que prennent les équipes agiles, la DOR doit être élaborée par le biais d’une discussion ouverte à l’image de la DOD. Là encore pas de recette miracle…l’équipe peut s’appuyer sur les expériences d’autres équipes ou d’experts agiles afin d’avoir une première rampe de lancement adaptée à son projet bien sûre !&lt;/p&gt;

&lt;p&gt;Tout comme la DOD, la DOR n’est pas figée dans le temps. Elle évolue en parallèle de la progression de l’équipe en termes de confiance et de maturité. La DOR n’a pas d’obligation à changer à chaque fin de sprint. Toutefois, l’équipe doit de temps en temps prendre le temps nécessaire pour s’assurer que cette dernière est toujours en adéquation avec la maturité de l’équipe et le contexte du projet.&lt;/p&gt;

&lt;p&gt;Comme « sa petite sœur » la DOR est composée également de critères sur lesquels l’équipe va s’appuyer pour définir si l’US est prête à être développée. Ci-dessous quelques exemples de critères :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;L’US a été présentée à l’équipe par le PO. Elle a été challengée acceptée et comprise par l’ensemble des membres de l’équipe&lt;/li&gt;
&lt;li&gt;Le besoin a été spécifié : les règles de gestion sont exprimées et des exemples les illustrent&lt;/li&gt;
&lt;li&gt;Des maquettes sont disponibles pour préciser le besoin&lt;/li&gt;
&lt;li&gt;L’équipe a décliné l’US en tâches techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bV3uvCna--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i74p363livbe6h4ezaui.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bV3uvCna--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i74p363livbe6h4ezaui.jpg" alt="Image description" width="800" height="1193"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Liste non exhaustive bien évidemment !&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  DOR : Bonne ou mauvaise pratique ?
&lt;/h3&gt;

&lt;p&gt;Même si la DOR est considérée comme une bonne pratique, là encore il ne faut pas que la DOR soit un frein à l’agilité. Parfois, tout ce qui est dans le sprint planning n’est pas forcément prêt. Une US embarquée dans le sprint peut voir sa maquette IHM réalisée en cours de sprint pour différentes raisons (manque de temps du designer, adaptation de dernière minute…). Bien sûr, ce fonctionnement est à pratiquer à la marge mais il peut être utilisé.&lt;/p&gt;

&lt;h2&gt;
  
  
  En conclusion
&lt;/h2&gt;

&lt;p&gt;Nous venons de poser quelques mots sur ces deux notions fréquemment rencontrées en agilité. Comme nous le montre le schéma ci-dessous la DOD et DOR interviennent en amont et en aval du sprint.  Vous l’aurez compris la DOD et la DOR sont jumelles dans le fonctionnement même si elles ont des objectifs différents. Il n’y a pas d’obligation à les utiliser mais elles peuvent être d’une aide précieuse en particulier pour les équipes qui débutent en agilité. Si vous n’avez pas encore mis en œuvre ces notions je vous invite à les essayer car en générale quand on y goûte on les adapte !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fGI4HYVF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnnkvanjw0u2ldr4q94j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fGI4HYVF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nnnkvanjw0u2ldr4q94j.jpg" alt="Image description" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agile</category>
    </item>
    <item>
      <title>Les Artefacts Scrum : Transformer pour Avancer !</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 30 Mar 2023 07:38:31 +0000</pubDate>
      <link>https://dev.to/younup/les-artefacts-scrum-transformer-pour-avancer--4fmj</link>
      <guid>https://dev.to/younup/les-artefacts-scrum-transformer-pour-avancer--4fmj</guid>
      <description>&lt;p&gt;De nouvelles manières de travailler basées sur des principes agiles (SAFE, SCRUM…) se sont développées ces dernières années provoquant l’apparition de nouveaux métiers (Product Owner, Scrum Master…), la mise en place de nouveaux outils (Jira, Trello, Confluence...) &lt;strong&gt;mais aussi l’utilisation d’un nouveau vocabulaire&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Ce vocabulaire parfois abstrait mérite d’être appréhendé surtout lorsque l’on débute dans l’agilité. Probablement que nous avons été plusieurs à se « gratter la tête », lorsque nous avons croisé pour la première fois la notion d’Artefact Scrum. Qui sont-ils ? Quel est leur rôle et leur fonction ? En quoi sont-ils utiles durant le développement d’un produit ? C’est ce que nous allons découvrir ensemble à la lecture de cet article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un Artefact c’est quoi ?
&lt;/h2&gt;

&lt;p&gt;Il convient de comprendre que ce mot admet plusieurs significations en fonction du domaine de référence. Ainsi, en électronique un artefact est considéré comme un effet indésirable, un parasite. En biologie il désigne une altération d'une structure biologique sous l'effet de réactifs(fixateurs, colorants...). &lt;/p&gt;

&lt;p&gt;D’autre part, sous l'influence du faux-ami anglophone Artifact, le mot est aussi employé de manière générale pour nommer &lt;strong&gt;un produit ayant subi une transformation, même minime, par l’homme&lt;/strong&gt; et qui se distingue ainsi d’un autre provoqué par un phénomène naturel. &lt;/p&gt;

&lt;p&gt;Et l’informatique dans tout ça ? Pourquoi parle-t-on d’Artefact en informatique notamment quand on évoque la méthode Scrum ? &lt;/p&gt;

&lt;h2&gt;
  
  
  Les Artefacts Scrum
&lt;/h2&gt;

&lt;p&gt;Dans le domaine du développement logiciel, le terme artefact fait référence aux informations clés nécessaires à tous les acteurs, durant le développement d'un produit. &lt;/p&gt;

&lt;p&gt;En effet, les artefacts Scrum sont des informations utilisées par les équipes Scrum et les parties prenantes pour détailler le produit en cours de développement ou les actions à mettre en place pour y parvenir. On dit aussi que ce sont des outils essentiels à chaque équipe Scrum, car ils favorisent la transparence, l'inspection et l'adaptation caractéristique de ce framework. &lt;/p&gt;

&lt;p&gt;Scrum possède 3 artefacts classiques : &lt;strong&gt;Le product backlog, le sprint backlog et le product incrément&lt;/strong&gt;. En tant qu’Artefact, ces 3 éléments subissent des transformations tout au long de la vie du produit. C’est le moment de se rappeler ce que l’on a dit en introduction sur l’Artefact et sa transformation par l’homme… car nous y sommes ! &lt;/p&gt;

&lt;h3&gt;
  
  
  Le Product Backlog
&lt;/h3&gt;

&lt;p&gt;Au début du développement d’un produit Agile, on va regrouper dans un« réservoir » toutes les « spécifications » qui vont décrire le produit afin que l’équipe de développement puisse commencer à le réaliser. C’est le Product Backlog. &lt;/p&gt;

&lt;p&gt;Le Product Owner va regrouper les différents sujets du Product Backlog dans des Epic (Thèmes) elles-mêmes découpées par Feature (grosses fonctionnalités). Ces dernières seront redécoupées en User Story (US). &lt;/p&gt;

&lt;p&gt;Ce « réservoir » va permettre à l’équipe d’avoir une &lt;strong&gt;vision du produit et de son objectif&lt;/strong&gt;. Le backlog est constitué de différents Items : les user stories décrivant une fonctionnalité métier, les anomalies (bugs), les études (spike) et les user stories techniques écrites par les développeurs. &lt;/p&gt;

&lt;p&gt;Le Product Owner a l’entière responsabilité du Product Backlog et de la priorisation des US à traiter. &lt;/p&gt;

&lt;p&gt;Pour mieux comprendre, voici un exemple de ce fameux « réservoir ». &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
            &lt;thead&gt;
              &lt;tr&gt;
                &lt;th&gt;Priorité&lt;/th&gt;
                &lt;th&gt;N°&lt;/th&gt;
                &lt;th&gt;User Stories&lt;/th&gt;
              &lt;/tr&gt;
            &lt;/thead&gt;
            &lt;tbody&gt;
              &lt;tr&gt;
                &lt;td&gt;1.0&lt;/td&gt;
                &lt;td&gt;01&lt;/td&gt;
                &lt;td&gt;En tant qu'utilisateur, je veux accéder au site marchand via l'URL www.achatenligne.fr afin de me connecter à mon compte&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;2.0&lt;/td&gt;
                &lt;td&gt;02&lt;/td&gt;
                &lt;td&gt;En tant qu'utilisateur, je veux pouvoir modifier mon mot de passe afin d'augmenter la sécurité de ma connexion&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;3.0&lt;/td&gt;
                &lt;td&gt;03&lt;/td&gt;
                &lt;td&gt;En tant qu'administrateur, je veux créer un nouvel utilisateur afin de lui procurer un accès au site marchand&lt;/td&gt;
              &lt;/tr&gt;
          &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Le sprint backlog
&lt;/h3&gt;

&lt;p&gt;Dans le framework Scrum un projet est découpé en plusieurs &lt;strong&gt;cycles nommés sprints&lt;/strong&gt; qui ont une date de début et une date de fin fixe. En général, les sprints ont une durée de deux à trois semaines. &lt;/p&gt;

&lt;p&gt;Le sprint backlog peut lui aussi être considéré comme un « réservoir » contenant différents items issus du Product backlog. Le sprint backlog est construit durant le sprint planning*. &lt;/p&gt;

&lt;p&gt;Dans le sprint backlog les user stories sont en générale, découpées en petites tâches indivisibles (métier ou techniques) et elles sont souvent estimées en point d’efforts. Chaque membre de l’équipe de réalisation (développeurs et testeurs), selon son envie va décider avec les autres de ce qu’il souhaite faire au fur et à mesure. Nous comprenons ainsi que cette équipe est responsable du Sprint Backlog et des différentes tâches qui sont engagées.&lt;/p&gt;

&lt;p&gt;Pour revenir à notre exemple, nous allons voir comment est découpée &lt;em&gt;l’US N°02&lt;/em&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
            &lt;thead&gt;
                &lt;tr&gt;
                    &lt;td colspan="3"&gt;US 02 - En tant qu'utilisateur, je veux pouvoir modifier mon mot de passe afin d'augmenter la sécurité de ma connexion&lt;/td&gt;
                &lt;/tr&gt;
              &lt;tr&gt;
                &lt;th&gt;N°&lt;/th&gt;
                &lt;th&gt;Tâches&lt;/th&gt;
                &lt;th&gt;Points&lt;/th&gt;
              &lt;/tr&gt;
            &lt;/thead&gt;
            &lt;tbody&gt;
              &lt;tr&gt;
                &lt;td&gt;02-01&lt;/td&gt;
                &lt;td&gt;Créer le formulaire&lt;/td&gt;
                &lt;td&gt;2&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;02-02&lt;/td&gt;
                &lt;td&gt;Implémenter les requêtes liant le formulaire à la base de données&lt;/td&gt;
                &lt;td&gt;0.5&lt;/td&gt;
              &lt;/tr&gt;
              &lt;tr&gt;
                &lt;td&gt;02-03&lt;/td&gt;
                &lt;td&gt;Effectuer des tests unitaires&lt;/td&gt;
                &lt;td&gt;1&lt;/td&gt;
              &lt;/tr&gt;
          &lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;*Le sprint planning : cérémonie scrum qui permet d’identifier ce qui sera développé pendant le sprint et livré à la fin de celui-ci.&lt;/p&gt;

&lt;h3&gt;
  
  
  L’incrément
&lt;/h3&gt;

&lt;p&gt;Durant chaque Sprint, l’équipe de développement réalise un &lt;strong&gt;bout de produit&lt;/strong&gt; qui peut être livré « en production », c’est &lt;strong&gt;l’incrément produit&lt;/strong&gt;. L’incrément est le reflet de la valeur produite pendant le sprint. Chaque incrément s’ajoute aux incréments existants et ces derniers vont fonctionner ensemble.&lt;br&gt;
L’objectif est que l’incrément produit contienne l’ensemble des User Stories estimées par l’équipe lors de la constitution du Sprint Backlog. Il arrive que certaines User Stories ne soient pas terminées à la fin du sprint. Elles seront alors reportées dans le sprint suivant. &lt;/p&gt;

&lt;h2&gt;
  
  
  Artefacts étendus
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Les artefacts que nous avons vus sont des Artefacts officiels au sens Scrum. Toutefois, il existe des artefacts dits « non officiels ». Ils ajoutent de la valeur et il convient de ne pas les oublier !&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Le Burn Down Chart
&lt;/h3&gt;

&lt;p&gt;Cet artefact, peut être qualifié d’artefact de transparence. L’équipe l'utilise durant le sprint pour suivre l'avancement du nombre de points réalisés et comparer la réalité à un avancement idéal. Au fil de l’eau ces graphiques vont permettre à l’équipe d’évaluer sa vélocité c’est-à-dire l’effort qu’elle est capable de réaliser dans un sprint. Dans l’exemple ci-contre l’effort est mesuré en nombre de points de complexité. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NP03KrlV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twlygdumm5btqjtgxlg0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NP03KrlV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twlygdumm5btqjtgxlg0.jpg" alt="Image description" width="880" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  La Définition Of Done
&lt;/h3&gt;

&lt;p&gt;Connue sous l’acronyme DOD, c’est littéralement la définition du travail terminé. Une fois que l’on a écrit ça il est légitime de se demander ce qu’est un travail terminé… et c’est là que la DOD intervient ! &lt;/p&gt;

&lt;p&gt;En effet, la DOD est constituée de critères qu’il convient d’avoir fait pour considérer le travail comme terminé. Prenons l’exemple d’un Product Owner et des développeurs. Ces deux parties peuvent se baser sur les critères de la DOD pour définir ensemble que le développement d’une US est terminé et qu’elle peut être démontrée. Pour être concret prenons l’exemple ci-dessous. &lt;/p&gt;

&lt;p&gt;Dans notre cas, le PO et les développeurs pourront se mettre d’accord sur l’aspect terminé d’une US au travers des critères suivants : les tests unitaires couvrent 70% du code par exemple, le code a été revu par deux développeurs, les documentations sont actualisées, les cas à démontrer et leurs jeux de données associés sont identifiés. &lt;/p&gt;

&lt;p&gt;Attention rien n’est gravé dans le marbre il s’agit ici d’un exemple mais il en existe bien d’autres évidemment ! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oi7wkzjG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4kb33gasf0sxu8vs91xl.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oi7wkzjG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4kb33gasf0sxu8vs91xl.jpg" alt="Image description" width="880" height="1312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  La Définition Of Ready
&lt;/h3&gt;

&lt;p&gt;La Definition of Ready, connue sous l’acronyme DOR, est la liste des critères sur lesquels l’équipe va s’appuyer pour définir si l’US est prête à être développée. Si elle répond favorablement à tous ces critères, l’US peut passer du backlog produit au backlog sprint. La DOR est considérée comme un contrat entre le PO et les développeurs. Ci-dessous quelques exemples de critères…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ppUGUU3h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j9bd1zg0i807pa2h38fy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ppUGUU3h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j9bd1zg0i807pa2h38fy.jpg" alt="Image description" width="880" height="1312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pour finir...
&lt;/h2&gt;

&lt;p&gt;Concluons par ce schéma qui montre l’articulation entre les différents Artefacts dits officiels. Vous l’avez compris l’idée principale à retenir est la suivante : ces derniers évoluent dans leur contenu au fur et à mesure de l’avancée des développements et du projet. N’oublions pas également les artefacts non officiels qui sont tout aussi importants. En effet, ces deux types d’Artefact aident l’équipe à faire preuve de transparence et à mesurer son avancement vers l’objectif final.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3qEIHQxO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z3bbqgiiu85t2vzeclb2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3qEIHQxO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z3bbqgiiu85t2vzeclb2.jpg" alt="Image description" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrouvez l’essentiel de l’article :
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QNpnf7Ud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k2un10azxa1xeo2dezbl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QNpnf7Ud--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k2un10azxa1xeo2dezbl.png" alt="Image description" width="828" height="939"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>agile</category>
      <category>scrum</category>
    </item>
    <item>
      <title>Réaliser une transformation agile tout en douceur</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 16 Feb 2023 08:52:30 +0000</pubDate>
      <link>https://dev.to/younup/realiser-une-transformation-agile-tout-en-douceur-554d</link>
      <guid>https://dev.to/younup/realiser-une-transformation-agile-tout-en-douceur-554d</guid>
      <description>&lt;h2&gt;
  
  
  Les points clefs afin de faciliter l’application de l’agilité dans votre projet
&lt;/h2&gt;

&lt;p&gt;Ça y est, votre organisation passe en mode agile. Votre boss en a entendu parler, il parait que c’est révolutionnaire et est convaincu qu’il faut faire la transition. Pourquoi ? Pour être à jour sur ces nouvelles méthodes de gestion de projet : C’est bien plus efficace, cela contentera les voix qui montent et qui demandent cette transition et puis … et puis c’est à la mode.&lt;/p&gt;

&lt;p&gt;D’ici à la fin de l’année il faut que 80% des projets de l’entreprise soient gérés grâce à une méthode agile. Comment l’évalue-t-on ? « Hum … il faut faire des dailies, des démos et des rétros !  Et puis on fera des sprints pour mettre en place nos MVP ! »&lt;/p&gt;

&lt;p&gt;Bon j’exagère un peu, mais parfois, quand on interprète les propos de nos managers on peut avoir envie de le résumer ainsi. En général, ce genre de réflexions peut arriver quand on analyse rétrospectivement les facteurs d’échec de la transition, ou quand on est énervé après une réunion déplaisante.&lt;/p&gt;

&lt;p&gt;Car oui, le fait de passer à l’agilité pour provoquer un effet d’annonce pourra satisfaire nos managers mais pas forcément les opérationnels. Les incohérences générées vont se multiplier et les équipes ne sauront plus sur quel pied danser.&lt;/p&gt;

&lt;p&gt;Notre article liste divers facteurs clefs de succès pour une transition agile tout en douceur.&lt;/p&gt;

&lt;h3&gt;
  
  
  1 - Des parties prenantes incluses dans la transition
&lt;/h3&gt;

&lt;p&gt;La condition fondamentale du passage à l’agile dans une entreprise, sans qu’il faille sortir les rames pour recadrer le projet sans arrêt est que le management soit sensibilisé et fasse des demandes en cohérence avec la situation.&lt;br&gt;
En général, face à une initialisation de projet, le management doit se positionner sur les modalités de delivery. Grossièrement il existe 2 possibilités :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Veut-on un produit fini coute que coute à l’issu du projet ?&lt;/li&gt;
&lt;li&gt;Veut-on un « premier exemplaire » (MVP) du produit, dont le périmètre est encore flou mais à une date fixée ? Le projet se « renouvelant » sans cesse par la suite.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C’est ce choix idéologique qui va garantir la stabilité du projet ou grandement le fragiliser. Dans le cas d’une transition agile mal réalisée, c’est le premier choix qui est effectué. C’est une vision des choses qui implique la définition initiale du produit et qui va générer de nombreuses incohérences dans la partie opérationnelle du projet, puisque cela relève d’une vision traditionnelle avec une structure agile (watergile).&lt;/p&gt;

&lt;h3&gt;
  
  
  2 - Une facturation appropriée
&lt;/h3&gt;

&lt;p&gt;Conséquence donc direct du positionnement idéologique des investisseurs, le choix du mode de facturation peut être déterminant dans la transition agile en cours. En effet, la gestion de projet en général, et a fortiori des projets informatiques, reposent sur trois piliers ou leviers sur lesquels on peut jouer pour s’ajuster : le budget, le délai et le périmètre fonctionnel.&lt;/p&gt;

&lt;p&gt;On parle traditionnellement de« l’Iron triangle » dont la représentation est la suivante :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y5uea6XQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2s076alecan3dfxlufub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y5uea6XQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2s076alecan3dfxlufub.png" alt="Image description" width="870" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En gros, les méthodes traditionnelles ont tendance à fixer le périmètre fonctionnel quoi qu’il arrive et à « jouer » sur le budget et les délais. Cela se traduit le plus souvent par la rédaction d’un cahier des charges avec des spécifications détaillées au début qu’il faut développer, tester et mettre en production quitte à rallonger les délais et donc à augmenter les coûts, ou à augmenter la taille des équipes.&lt;/p&gt;

&lt;p&gt;Les méthodes agiles, si l’on simplifie, inversent ce modèle en fixant les coûts et les délais mais en« jouant » sur le périmètre fonctionnel à livrer. Et de la même manière, cela se traduit par la définition d’un MVP (et non la spécification, c’est important dans le sens où l’on en dessine les grandes lignes, et c’est tout ! – d’où le fait que l’on dit que le périmètre fonctionnel n’est pas fixé) et la fixation d’une date de première release. Donc dans les faits on dit« A telle date, vous aurez un outil opérationnel, utilisable » et basta.&lt;/p&gt;

&lt;p&gt;Quel rapport avec la facturation me direz-vous ?&lt;br&gt;
Il existe, a priori deux grandes typologies de facturation :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forfait (obligation de résultat) : vous devez proposer un livrable à une date donnée et activerez la facturation à la réception&lt;/li&gt;
&lt;li&gt;Régie (obligation de moyen) : les acteurs du projet sont facturés au TJM de leur jours effectivement travaillés.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si vous avez suivi, pour coller avec les modalités de gestion de projet, il est important de facturer au forfait en méthode traditionnelle et en régie en méthode agile.&lt;/p&gt;

&lt;p&gt;Ainsi, si on vous demande (en tant que PO par exemple) de chiffrer finement toutes les fonctionnalités du MVP (et quand il ne s’agit que du MVP …) avant de commencer afin de fixer le scope à déployer, vous savez que le mindset est mauvais.&lt;/p&gt;

&lt;p&gt;Très souvent, il est demandé la mise en place d’un périmètre fonctionnel finement défini malgré l’adoption de Scrum, SAFe, Kanban ou autre, et c’est ce dont il faut se méfier.&lt;/p&gt;

&lt;p&gt;N.B. : Il est à noter néanmoins qu’une facturation en régie fait reposer tous les risques financiers au client. Ainsi, il est intéressant malgré tout de voir quels peuvent être les compromis à proposer pour éviter le mode forfait traditionnel tout en rassurant le client sur son investissement.&lt;/p&gt;

&lt;h3&gt;
  
  
  3 - Une relation constructive entre l’équipe projet et les sponsors
&lt;/h3&gt;

&lt;p&gt;De quoi parle-t-on ici ?&lt;br&gt;
Imaginez : vous êtes dans une équipe où le Product Owner est seul maître de la conception technico-fonctionnelle. L’équipe est totalement auto-organisée. La dimension UX est prise en compte. Le PO n’est pas mis sous pression par sa propre hiérarchie pour appliquer une seule solution. Le projet a été commandité par la DSI, qui est sponsor, pour ses utilisateurs finaux.&lt;br&gt;
C’est un exemple de ce vers quoi il faudrait tendre.&lt;/p&gt;

&lt;p&gt;Mais il faut avouer, cela ne se passe jamais comme ça. Il y aura forcément un moment où cela va coincer. Par contre, il n’est pas rare de voir totalement l’inverse.&lt;/p&gt;

&lt;p&gt;Le client, qui détient les cordons de la bourse va, très souvent, juger que pour avoir un retour sur investissement profitable, il devra s’impliquer dans la conception du produit (« Je paye, donc je décide de la solution »). C’est une des grosses erreurs souvent rencontrées qui est la confusion entre l’expression du besoin métier et sa concrétisation en termes de solution. Il existe alors deux variantes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Soit le PO est directement chez le client, voire est le client (hors de l’équipe donc) et viendra simplement transmettre sa solution à l’équipe de développement. Cette dernière réalisera, testera et demandera au client de valider avant mise en production. Dans cette configuration, les feedbacks arriveront toutes les 2 ou 3 semaines (en fonction de la durée des sprints) et, surtout, la dev team sera très peu consultée.&lt;/li&gt;
&lt;li&gt;Soit le PO est bien dans l’équipe MAIS qu’il n’a pas de pouvoir décisionnel. Le client propose donc une conception technico-fonctionnelle et le PO « challenge » cette solution mais sans réel pouvoir d’action (le PO a donc un rôle réel plutôt proche de celui du Business Analyst). Le problème est, dans cette configuration, que le client n’a pas forcément les mêmes enjeux que le PO : un outil complet à proposer, un budget à  limiter, voire des contraintes structurelles (politiques, d’image …).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En tout cas, ces exemples bafouent les principes selon lesquels l’équipe de réalisation doit être auto-organisée et responsable du produit livré.&lt;/p&gt;

&lt;p&gt;La qualité intrinsèque au produit risque donc de baisser assez fortement. Mais surtout cela génère de la dette technique pour plusieurs raisons : les développeurs peuvent se sentir peu concernés par la qualité du produit ou les demandes peuvent être si peu cohérentes qu’elles ne peuvent être anticipées par une conception technique solide et structurée.&lt;/p&gt;

&lt;p&gt;Enfin, on imagine assez bien que l’aspect UX pourrait également en pâtir dans le sens où le détenteur de la solution fonctionnelle devra livrer un outil où il n’aura que très rarement été challengé, ou contredit (peu d’intelligence collective).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d0yk7vxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8572m3z8fctc2wf6vn7n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d0yk7vxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8572m3z8fctc2wf6vn7n.png" alt="Image description" width="813" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4 - Définir une vision produit compréhensible
&lt;/h3&gt;

&lt;p&gt;Problématique extrêmement importante en agilité, c’est pourtant un principe qui fait très souvent défaut. Etablir une vision produit, c’est la faculté du PO ou du PM à proposer une solution abstraite à une problématique métier. Phrase compliquée pour exprimer le fait que cette solution n’est pas inscrite dans le marbre mais qu’elle suit une sorte de« philosophie » à laquelle se rattacher sans arrêt. Elle est constituée de la réponse au besoin du métier ou des clients et peut être formulée sous diverses formes (phrases, cartes postales, tableau …)&lt;/p&gt;

&lt;p&gt;Pourquoi est-ce fondamental ?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cela permet de fixer des objectifs clairs aux sprints. Grâce à une vision produit et une roadmap agile, les PO ou PM pourront structurer leur delivery en planifiant des sprints cohérents et porteurs de valeur&lt;/li&gt;
&lt;li&gt;Cela permet de faire la part des choses entre les besoins métiers et la solution fonctionnelle (hélas bien souvent confondus). Dotés d’une ligne directrice stable, les PO pourront interpréter les besoins métiers à l’aune de la vision/roadmap et donc d’effectuer les meilleurs choix conceptuels possibles. Leur valeur ajoutée sera donc maximisée car leur connaissance technique, fonctionnelle et métier sera utilisée à bon escient.&lt;/li&gt;
&lt;li&gt;Cela permet également de cadencer les releases aux utilisateurs et en particulier de définir correctement son MVP. Le MVP représente une première tentative de solution répondant à la philosophie de la vision. Il permet de valider les orientations stratégiques et peut être un jalon de GO/NO-GO pour la suite du projet.&lt;/li&gt;
&lt;li&gt;Enfin, cela permet d’optimiser sa capacité d’adaptation, et ce dans 2 situations particulières :&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;En évitant d’effectuer un cadrage initial complet, il est possible de rebondir facilement à un imprévu métier, organisationnel voire technique.&lt;/li&gt;
&lt;li&gt;Par ailleurs, cela permet de proposer une conception technico-fonctionnelle robuste car aussi bien le PO que les développeurs gardent en tête leur objectif final&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5 - Evaluer et anticiper les risques inhérents à une transition agile
&lt;/h3&gt;

&lt;p&gt;Malgré une transition agile bien effectuée et des collaborateurs bien formés, il est indispensable de vérifier la bonne adéquation entre les pratiques réelles et la théorie. Non pas qu’il faille obligatoirement s’y conformer entièrement, mais il y a une base qu’il faut respecter, et qui prend la forme des 12 principes agiles et des 4 valeurs (voir &lt;a href="https://www.wrike.com/fr/blog/les-4-valeurs-et-12-principes-de-la-gestion-de-projet-agile/"&gt;ici &lt;/a&gt;par exemple). Or, on se rend compte rapidement qu’une formation de 2 jours ne peut permettre d’effacer des années d’expérience.&lt;/p&gt;

&lt;p&gt;En fait, il faut partir du principe qu’une équipe, même très bien organisée, ne sera pas d’emblée suffisamment mature afin de proposer des pistes d’amélioration efficaces (voir loi de &lt;a href="https://blog.trello.com/fr/modele-de-tuckman"&gt;Tuckman&lt;/a&gt;).&lt;br&gt;
Il faut pourtant lui laisser la main pour identifier et mener elle-même ces pistes d’amélioration, aidée par le Scrum Master.&lt;/p&gt;

&lt;p&gt;Ainsi, les équipes peuvent se confronter à diverses situations dans le cadre de leur amélioration continue :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trop peu matures, elles ne comprennent pas totalement les enjeux liés à la transition. Les propositions opérationnelles ne sont pas forcément bonnes mais peuvent évoluer dans le bon sens, aidées pour le coup parle Scrum-Master. (certains problèmes ne pourront pas être réglés, mais ne sont pas considérés)&lt;/li&gt;
&lt;li&gt;Suffisamment matures, elles commencent à entrapercevoir l’impact des décisions managériales sur leur quotidien mais ne voient pas comment remonter le point. Les Scrum-Masters ne s’adressant pas forcément au bon niveau hiérarchique et ne peuvent pas faire évoluer les pratiques. (blocage donc)&lt;/li&gt;
&lt;li&gt;Totalement matures, elles comprennent que ce qui leur est demandé d’un point de vue opérationnel n’est pas en phase avec le management. (Conflit induit)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dans ces 3 cas, il me semble qu’il manque un coach pouvant aussi bien se reposer sur des Scrum-Masters au niveau des équipes que de s’adresser au management et de challenger leurs choix si besoin. Cela permettra d’éviter certains de ces écueils ci-dessous (liste non-exhaustive) :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excès de contrôle et perte de confiance de la part du management envers les équipes, notant une perte de productivité ou une potentielle démotivation. C’est à ce moment que fleurissent les divers comités (COPIL, COSUI, CORUN, etc.) ainsi que les indicateurs qu’il faut y présenter.&lt;/li&gt;
&lt;li&gt;Perte de confiance de la part des équipes envers leur management, notant une incohérence dans les demandes (d’ailleurs exacerbée par une hausse du contrôle)&lt;/li&gt;
&lt;li&gt;Perte de repère des équipes nuisant à leur efficacité&lt;/li&gt;
&lt;li&gt;Etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En synthèse, il me semble très important de s’entourer d’experts méthode, au moins pour les premiers mois, et de leur laisser le bénéfice du doute sur les pratiques en train d’être mise en place. Cela permettra à tous les collaborateurs d’avoir le temps d’appréhender les nouvelles règles de travail et de gagner en autonomie et en raisonnement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Il existe encore beaucoup de situations pouvant mettre à mal une transition agile. Cela peut aller de la suppression des rétrospectives car les équipes et le management jugent que plus rien de « bon » n’en ressort, au cadrage basique spécifiant un périmètre fonctionnel à voir mis en production à une date définie. Très souvent le fait d’avoir des PO, des Scrum-Masters, des cérémonies agiles et des sprints semble suffisant pour se définir agile, or cela n’est non seulement souvent pas le cas, mais il est tout à fait possible d’effectuer une transition avec succès sans tous ce qui est cité ci-dessus. A fortiori, rien ne sert d’utiliser une méthode définie si l’on n’en comprend pas les tenants et les aboutissants.&lt;/p&gt;

&lt;p&gt;Alors, à l’occasion d’une discussion sur ce qu’est l’agilité ou d’un entretien pour une nouvelle mission, il peut être intéressant de se souvenir de ces points : Comment pense le management ? Comment est facturé le projet ? Comment se positionne l’équipe projet ? Est-ce que le PO décide de la solution ? Suit-il une vision produit ?&lt;/p&gt;

</description>
      <category>agile</category>
    </item>
    <item>
      <title>À quoi servent les solutions Azure Synapse et Azure Data Factory pour l'intégration des données ?</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 09 Feb 2023 10:56:30 +0000</pubDate>
      <link>https://dev.to/younup/a-quoi-servent-les-solutions-azure-synapse-et-azure-data-factory-pour-lintegration-des-donnees--19o7</link>
      <guid>https://dev.to/younup/a-quoi-servent-les-solutions-azure-synapse-et-azure-data-factory-pour-lintegration-des-donnees--19o7</guid>
      <description>&lt;p&gt;Avant de parler des technologies Microsoft Azure Synapse et Data Factory, il faut bien comprendre le processus ETL utilisé pour exploiter ces deux outils pour collecter, analyser et intégrer les données. Le but est de les rendre utiles et exploitables par les gens du métier ou les utilisateurs finaux, afin de les aider à prendre des décisions commerciales en connaissance de cause.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1n6oo9qzct2pyi9davw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1n6oo9qzct2pyi9davw.png" alt="Image description" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu’est-ce que le processus ETL ?
&lt;/h2&gt;

&lt;p&gt;C’est l’abréviation de Extract, Transform, Load. C’est un processus automatisé qui prend les données brutes sous forme de fichiers JSON, Excel ou plat (csv ou txt), extrait l’information nécessaire à l'analyse, la transforme en un format qui peut répondre aux besoins opérationnels et la charge dans un data warehouse. L'ETL résume généralement les données afin de réduire leur taille et d'améliorer leur performance pour des types d'analyses spécifiques.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tout ce que vous devez savoir sur le processus ETL
&lt;/h2&gt;

&lt;p&gt;Pour charger régulièrement votre entrepôt de données afin qu'il puisse servir à faciliter l'analyse commerciale, les données d'un ou plusieurs systèmes opérationnels doivent être extraites et copiées dans l'entrepôt de données. Le défi dans les environnements d'entrepôts de données consiste à intégrer, réorganiser et consolider de grands volumes de données sur de nombreux systèmes, fournissant ainsi une nouvelle base d'information unifiée pour la Business Intelligence.&lt;/p&gt;

&lt;p&gt;Le processus d'extraction des données des systèmes sources et de leur transfert dans l'entrepôt de données est communément appelé ETL. Il est à noter que l'ETL fait référence à un processus général et non à trois étapes bien définies. L'acronyme ETL est peut-être trop simpliste, car il omet la phase de transport et implique que chacune des autres phases du processus est distincte.&lt;/p&gt;

&lt;p&gt;Que se passe-t-il pendant le processus ETL ? Les tâches suivantes sont les principales actions du processus.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Extraction des données
&lt;/h3&gt;

&lt;p&gt;La première étape de l'ETL est l'extraction. Au cours de l'extraction, les données sont spécifiquement identifiées et ensuite prélevées à de nombreux endroits différents. Ces données peuvent provenir d’une variété de choses, comme des fichiers, des feuilles de calcul, des systèmes de bases de données et des applications, etc. Il n'est généralement pas possible d'identifier le sous-ensemble exact d'intérêt, de sorte que l'on extrait plus de données que nécessaire pour s'assurer qu'il couvre tous les besoins.&lt;/p&gt;

&lt;p&gt;Selon les capacités du système source (par exemple, les ressources du système d'exploitation), certaines transformations peuvent avoir lieu pendant ce processus d'extraction. La taille des données extraites varie de quelques centaines de kilo-octets à plusieurs giga-octets, selon le système source et la situation commerciale. C'est également le cas pour la période entre deux extractions ; certaines peuvent varier de jours ou d'heures à presque en temps réel.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Transport des données
&lt;/h3&gt;

&lt;p&gt;Une fois les données extraites, elles doivent être physiquement transportées vers le système cible ou vers un système intermédiaire pour traitement ultérieur. Selon le mode de transport choisi, certaines transformations peuvent également être effectuées au cours de ce processus.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Transformation des données
&lt;/h3&gt;

&lt;p&gt;La prochaine étape du processus ETL est la transformation. Une fois les données extraites, elles doivent être physiquement transportées vers la destination cible et converties dans le format approprié. Cette transformation de données peut inclure des opérations telles que le nettoyage, l'assemblage et la validation des données.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Chargement des données
&lt;/h3&gt;

&lt;p&gt;La dernière étape du processus ETL consiste à charger les données transformées dans la cible de destination. Cette cible peut être une base de données ou un data warehouse. Il existe deux méthodes principales pour charger les données dans un entrepôt : chargement complet et chargement incrémental. La méthode du chargement complet implique un déchargement complet des données qui a lieu la première fois que la source est chargée dans l'entrepôt. La charge incrémentale, en revanche, a lieu à intervalles réguliers. Ces intervalles peuvent être des incréments de flux (meilleurs pour de plus petits volumes de données) ou des incréments de lots (meilleurs pour de plus grands volumes de données).&lt;/p&gt;

&lt;p&gt;Les équipes de Business Intelligence (BI) lancent ensuite des requêtes sur ces données, qui sont enfin présentées aux utilisateurs finaux ou aux personnes chargées de prendre des décisions commerciales, ou utilisées comme entrées pour des algorithmes de Machine Learning. Un problème courant rencontré ici est que si les résumés OLAP ne peuvent pas supporter le type d'analyse que l'équipe BI veut faire, alors tout le processus doit être relancé, cette fois avec différentes transformations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pourquoi utiliser le processus ETL ?
&lt;/h2&gt;

&lt;p&gt;Dans la plupart des cas, les entreprises et les sociétés qui ont besoin de construire et de maintenir des data warehouse complexes investiront dans des outils ETL et ELT, mais d'autres organisations peuvent aussi les utiliser à une plus petite échelle.&lt;/p&gt;

&lt;p&gt;Les entreprises s'appuient sur le processus ETL depuis de nombreuses années pour obtenir une vue consolidée des données qui leur permet de prendre de meilleures décisions commerciales. Aujourd'hui, cette méthode d'intégration de données provenant de multiples systèmes et sources demeure un élément central de la boîte à outils d'intégration de données d'une organisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu'est-ce que l'environnement Azure Cloud ?
&lt;/h2&gt;

&lt;p&gt;Azure est une plateforme de Cloud faite par Microsoft qui dispose de tout ce dont une entreprise a besoin pour gérer virtuellement une partie ou la totalité de ses opérations informatiques : serveurs, stockage, bases de données, réseaux, statistiques et bien plus encore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu'est-ce qu'Azure Synapse ?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiuyfrqaaussw6jknvsw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiuyfrqaaussw6jknvsw3.png" alt="Image description" width="253" height="199"&gt;&lt;/a&gt;&lt;br&gt;
Il s'agit d'un service d'analyse qui réunit l'entreposage de données d'entreprise et l'analyse de données volumineuses. Il interroge les données selon vos besoins avec plusieurs modalités et de types des ressources même sans serveur. Il réunit ces deux mondes avec une expérience unifiée pour ingérer, préparer, gérer et servir des données pour les besoins immédiats de BI et d'apprentissage automatique.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qu'est-ce qu'Azure Data Factory ?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqfhqit3kioog7t9c9jq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqfhqit3kioog7t9c9jq.png" alt="Image description" width="225" height="225"&gt;&lt;/a&gt;&lt;br&gt;
Il s'agit d'un service qui permet aux développeurs d'intégrer des sources de données hétérogène. Il s'agit d'une plate-forme un peu comme SSIS mais dans le cloud pour gérer les données que vous avez à la fois sur site et dans le cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure Data Factory vs Azure Synapse : quelles sont les différences ?
&lt;/h2&gt;

&lt;p&gt;Les développeurs décrivent Azure Data Factory comme « un service d'intégration de données hybride qui simplifie l'ETL à grande échelle ». C’est donc un service qui permet aux développeurs d’intégrer plusieurs sources de données.&lt;/p&gt;

&lt;p&gt;Azure Synapse est décrit comme un "service d'analyse qui rassemble l'entreposage de données d'entreprise et l'analyse de données volumineuses" afin de collectionner et étudier les informations à votre guise. Il réunit ces deux mondes avec une expérience unifiée pour ingérer, préparer, gérer et servir des données pour des besoins immédiats en matière de BI et d'apprentissage automatique.&lt;/p&gt;

&lt;p&gt;Azure Data Factory et Azure Synapse appartiennent à la catégorie "Big Data Tools" de la pile technologique.&lt;/p&gt;

&lt;p&gt;Certaines des fonctionnalités offertes par Azure Data Factory sont :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intégration en temps réel&lt;/li&gt;
&lt;li&gt;Traitement parallèle&lt;/li&gt;
&lt;li&gt;Bloc de données
D'autre part, Azure Synapse fournit les fonctionnalités clés suivantes :&lt;/li&gt;
&lt;li&gt;Analyse complète basée sur T-SQL&lt;/li&gt;
&lt;li&gt;Apache Spark profondément intégré&lt;/li&gt;
&lt;li&gt;Intégration de données hybrides&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quelles sont les alternatives à Azure Data Factory et Azure Synapse ?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Azure Databrick&lt;/strong&gt; : Accélérez les solutions d'analyse de données volumineuses et d'intelligence artificielle (IA) avec Azure Databricks, un service d'analyse rapide, simple et collaboratif basé sur Apache Spark.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Talend&lt;/strong&gt; : Il s'agit d'une plate-forme d'intégration de logiciels open source qui vous aide à transformer sans effort les données en informations commerciales. Il utilise la génération de code natif qui vous permet d'exécuter vos pipelines de données de manière transparente sur tous les fournisseurs de cloud et d'obtenir des performances optimisées sur toutes les plates-formes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Data Pipeline&lt;/strong&gt; : AWS Data Pipeline est un service web qui fournit un système de gestion simple pour les workflows basés sur les données. À l'aide d'AWS Data Pipeline, vous définissez un pipeline composé des « sources de données » qui contiennent vos données, des « activités » ou de la logique métier telles que les tâches EMR ou les requêtes SQL, et de la « planification » selon laquelle votre logique métier s'exécute. Par exemple, vous pouvez définir une tâche qui, toutes les heures, exécute une analyse basée sur Amazon Elastic MapReduce (Amazon EMR) sur les données de journal Amazon Simple Storage Service (Amazon S3) de cette heure, charge les résultats dans une base de données relationnelle pour une recherche future, puis vous envoie automatiquement un e-mail récapitulatif quotidien.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Colle AWS&lt;/strong&gt; : Un service d'extraction, de transformation et de chargement (ETL) entièrement géré qui permet aux clients de préparer et de charger facilement leurs données pour l'analyse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Apache NiFi&lt;/strong&gt; : Un système facile à utiliser, puissant et fiable pour traiter et distribuer les données. Il prend en charge des graphes dirigés puissants et évolutifs de routage de données, de transformation et de logique de médiation système.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Product Owner et Product Manager, si différents ?</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 17 Nov 2022 10:24:59 +0000</pubDate>
      <link>https://dev.to/younup/product-owner-et-product-manager-si-differents--10fe</link>
      <guid>https://dev.to/younup/product-owner-et-product-manager-si-differents--10fe</guid>
      <description>&lt;p&gt;Younup m’offre la possibilité aujourd’hui de faire passer des entretiens techniques et fonctionnels à des candidats souhaitant rejoindre notre équipe. Je trouve ça super enrichissant car je découvre d’autres parcours que le mien et cet enrichissement mutuel entre le candidat et moi-même me donne aussi des idées pour écrire des articles ! Celui que vous allez lire sur le rôle de Product Owner (PO) et de Product Manager (PM) en est un exemple.&lt;/p&gt;

&lt;p&gt;Je m’explique… au cours de différents entretiens avec les candidats je me suis rendu compte que la définition du rôle de Product Manager et Product Owner était parfois confuse et interprétée de différentes manières. J’ai décidé de poser ma vision sur ce billet afin qu’elle puisse alimenter votre réflexion !&lt;/p&gt;

&lt;p&gt;Au cours de ces quelques paragraphes on évoquera les principales fonctions du Product Owner et du Product Manager. On se fera un avis sur leurs complémentarités ou différences et on abordera également quelques clichés qui selon moi ne sont pas fondés.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le Product Owner
&lt;/h2&gt;

&lt;p&gt;Commençons par le commencement… le Product Owner : qui est-il ? Nous allons répondre à cette question en décrivant son rôle, ses devoirs et en identifiant ses différentes interactions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rôle
&lt;/h3&gt;

&lt;p&gt;Le Product Owner est responsable de la Product Backlog et porte la connaissance métier au sein de l’équipe.&lt;/p&gt;

&lt;p&gt;Son objectif est de maximiser la valeur du produit résultant du travail de l’équipe Scrum (Développeurs, Product Owner, Scrum Master).&lt;/p&gt;

&lt;h3&gt;
  
  
  Devoir
&lt;/h3&gt;

&lt;p&gt;Plusieurs devoirs incombent au Product Owner. En voici quelques exemples :&lt;/p&gt;

&lt;p&gt;• Communiquer avec les Parties Prenantes,&lt;br&gt;
• Faire adhérer l’équipe à la vision du produit,&lt;br&gt;
• Assister aux cérémonies agiles qu’il peut animer,&lt;br&gt;
• Prioriser et entretenir la Product Backlog afin d’anticiper le contenu des prochains Sprints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ses interactions
&lt;/h3&gt;

&lt;p&gt;Ce dernier interagit avec différents interlocuteurs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Les parties prenantes
&lt;/h4&gt;

&lt;p&gt;Le Product Owner doit recueillir le besoin et prendre en compte les feedbacks utilisateurs sur le produit. Il expose également de manière transparente la product backlog et anticipe les demandes d’évolutions du produit.&lt;/p&gt;

&lt;h4&gt;
  
  
  Les développeurs
&lt;/h4&gt;

&lt;p&gt;Auprès des développeurs, le PO s’assure que ces derniers comprennent bien la product Backlog. Il garantit également que les sujets sur lesquels travaillent les développeurs apportent un maximum de valeur métier. Il peut partager avec eux les choix d’architecture.&lt;/p&gt;

&lt;h4&gt;
  
  
  Le Scrum master
&lt;/h4&gt;

&lt;p&gt;Le PO peut le solliciter pour : animer les ateliers/cérémonies agiles, rédiger et prioriser la Product Backlog, apporter plus de transparence aux parties prenantes durant le sprint.&lt;br&gt;
Le Scrum peut être d’une aide précieuse pour lever les obstacles lorsque c’est nécessaire.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8PUXPdEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5jdm7nd85lf33br5l1j.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8PUXPdEY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c5jdm7nd85lf33br5l1j.jpeg" alt="Image description" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Le Product Manager
&lt;/h2&gt;

&lt;p&gt;Nous allons maintenant examiner le rôle de Product Manager.&lt;/p&gt;

&lt;p&gt;Il s’appuie sur différentes équipes pour construire une vision globale du produit, orienter les décisions et orchestrer les actions. Ainsi il collabore étroitement avec :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Le marketing&lt;/strong&gt;, pour comprendre les attentes des clients, analyser leur niveau de satisfaction, remonter les demandes de nouvelles fonctions ou de corrections, faire de la veille, promouvoir le produit,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;La technique&lt;/strong&gt; pour effectuer les développements et l’exploitation,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Les ventes&lt;/strong&gt; (Business), pour appliquer le modèle d’affaires.&lt;/p&gt;

&lt;p&gt;Le Product Manager, possède une vision globale du produit. Sa perception du marché lui permet de se projeter dans le futur et de dessiner la stratégie de développement à moyen/long terme.&lt;/p&gt;

&lt;p&gt;Il doit connaitre son produit et son secteur sur le bout des doigts. Il fait de la veille sur le business la technologie, l’expérience utilisateur…&lt;/p&gt;

&lt;p&gt;Il est le référent sur la performance de son produit. Il définit les critères de succès de chaque nouveau projet en lien avec les autres équipes et utilisateurs pour prendre les meilleures décisions possibles.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qaAsrkqU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9q2809zmusl9rp1zm57f.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qaAsrkqU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9q2809zmusl9rp1zm57f.jpeg" alt="Image description" width="878" height="878"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Alors, complémentaires ou différents ?
&lt;/h2&gt;

&lt;p&gt;Passons maintenant au plat de résistance… Nous allons essayer d’apporter quelques éléments de réponse à cette question afin que vous puissiez alimenter votre réflexion…&lt;/p&gt;

&lt;h3&gt;
  
  
  Penser le produit pour pouvoir faire le produit
&lt;/h3&gt;

&lt;p&gt;Le &lt;strong&gt;Product Manager&lt;/strong&gt; a la responsabilité d'élaborer la vision globale du produit et ses grandes fonctionnalités.&lt;/p&gt;

&lt;p&gt;En parallèle, le &lt;strong&gt;Product Owner&lt;/strong&gt; travaille avec le PM sur ces mêmes fonctionnalités mais plus dans le détail des éléments et items comme les users story par exemple. Le Product Manager intervient en amont du produit pour travailler sur les objectifs futurs et le Product Owner travaille plutôt avec le métier et les développeurs sur la réalisation actuelle du produit.&lt;/p&gt;

&lt;p&gt;Le Product Manager “&lt;strong&gt;imagine le produit&lt;/strong&gt;” tandis que le Product Owner “&lt;strong&gt;fait le produit&lt;/strong&gt;.”&lt;br&gt;
Le Product Manager va imaginer le produit de la phase d’idéation (concept, besoin, marché) jusqu’à sa mise sur le marché (stratégie, distribution marketing), tandis que le Product Owner va concevoir le produit avec les développeurs.&lt;/p&gt;

&lt;p&gt;En résumé, Le Product Manager travaille sur le &lt;strong&gt;Pourquoi ? Pour qui ? Pour quand ?&lt;/strong&gt; tandis que le Product Owner travaille sur le &lt;strong&gt;Quoi ?&lt;/strong&gt; et le &lt;strong&gt;Comment ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Vous l’aurez compris chacun a son propre périmètre, ses propres activités mais un fil rouge lie ces deux acteurs : le produit ! La dimension produit est très grande dans les deux cas ! Si on « &lt;strong&gt;ne pense pas le produit&lt;/strong&gt; » alors « &lt;strong&gt;on ne fait pas le produit&lt;/strong&gt; ». Même si sur le papier se sont deux rôles distincts je suis partisan de dire que les deux sont complémentaires !&lt;/p&gt;

&lt;h3&gt;
  
  
  Alors... pourquoi confondre ces deux rôles ?
&lt;/h3&gt;

&lt;p&gt;A mon sens, cette confusion intervient souvent dans l’univers d’un produit informatique. En effet dans l’univers de la « Tech » ces deux rôles cohabitent régulièrement. Ces deux métiers peuvent coexister dans la même structure. Dans une jeune Startup par exemple, il y a fort à parier que le fondateur engendre à la fois tous les rôles clés de la stratégie et de la conception du produit. Il est alors un genre de pilote produit globale qui prend les casquettes de PO et PM. Dans les structures plus importantes avec des produits plus complexes, les rôles se séparent et sont en générales bien distinctes.&lt;/p&gt;

&lt;p&gt;L’autre source de confusion peut venir aussi de leurs ressemblances étymologiques facilitant la confusion pour les personnes non aguerries à ces deux rôles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quelques clichés à éviter... A vous de juger !
&lt;/h2&gt;

&lt;p&gt;J’ai pu remarquer au cours de mes différentes rencontres, expériences que certains clichés étaient bien ancrés mais selon moi pas toujours justifiés…J’en ai recensé quatre et vous pouvez bien sûre vous faire votre propre avis !&lt;/p&gt;

&lt;h3&gt;
  
  
  Le PO est dans une vision au quotidien du produit et le Product Manager est dans le long terme
&lt;/h3&gt;

&lt;p&gt;Selon moi les deux doivent partager une vision produit à long terme. Même si l’un pense et l’autre fait le produit au quotidien, les deux acteurs doivent partagés et co-constuire une vision long terme pour s’assurer de la cohérence du produit et de la roadmap produit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Le PM est dans la stratégie mais pas le PO
&lt;/h3&gt;

&lt;p&gt;Les deux rôles baignent dans la stratégie du produit. Ils doivent être tous les deux de fins stratèges opérant dans des problématiques différentes. L’un s’occupe principalement de la stratégie produit (PO) et l’autre de la stratégie marché (PM). Par exemple le PO doit mener sa stratégie pour prioriser les bonnes US au bon moment. Le PM quant à lui doit stratégiquement faire évoluer son produit afin qu’il ne soit pas obsolète et dépassé par la concurrence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Le PM a une position hiérarchique plus haute
&lt;/h3&gt;

&lt;p&gt;Le PM et le PO sont deux rôles complémentaires qui collaborent souvent ensemble pour couvrir l’intégralité de la réalisation du produit. Ils n’ont aucun rapport hiérarchique. Le PO peut reporter directement à un « Head of PO » par exemple.&lt;/p&gt;

&lt;h3&gt;
  
  
  Les PM des PO avec expérience
&lt;/h3&gt;

&lt;p&gt;C’est tout à fait possible qu’un P.O devienne un jour un PM. Mais attention, il ne s’agit pas d’une suite logique ou d’une promotion obligatoire. Selon moi, il s’agit juste d’un choix de carrière. Dire que les P.M sont de supers P.O est très caricatural. Encore une fois, il n’y a pas de rapport hiérarchique entre les deux.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dans cet article, nous avons dessiné le champ d’actions du Product Owner et du Product Manager. Il convient de bien distinguer leurs activités même si elles ont toutes le même but : le produit ! Différent mais complémentaire, tels seront les deux mots de la fin !  &lt;/p&gt;

</description>
      <category>agile</category>
    </item>
    <item>
      <title>Le développeur fullstack, utopie ou nécessité ?</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Mon, 03 Oct 2022 07:39:48 +0000</pubDate>
      <link>https://dev.to/younup/le-developpeur-fullstack-utopie-ou-necessite--5f2b</link>
      <guid>https://dev.to/younup/le-developpeur-fullstack-utopie-ou-necessite--5f2b</guid>
      <description>&lt;h1&gt;
  
  
  Le développeur fullstack, utopie ou nécessité ?
&lt;/h1&gt;

&lt;p&gt;Depuis quelques années, le développement web s’est très largement complexifié.&lt;/p&gt;

&lt;p&gt;Côté backend, les architectures microservices et serverless demandent une forte expertise pour concevoir des applications qui passent à l’échelle.&lt;/p&gt;

&lt;p&gt;Côté frontend, la diversité des outils et frameworks, l'arrivée des PWA, les notions de design et d'accessibilité en font un domaine très vaste où il devient de plus en plus compliqué de se maintenir à jour.&lt;/p&gt;

&lt;p&gt;Aujourd’hui, les développeurs fullstack sont très recherchés. Mais qu'entend-on par fullstack ? Où commence et termine cette fameuse "stack" ? Peut-on développer une expertise forte sur l’ensemble de ces compétences ?&lt;/p&gt;

&lt;p&gt;Après avoir défini le périmètre du développeur fullstack, on présentera ses avantages, puis, on réfléchira aux conséquences de construire une équipe autour de devs fullstack.&lt;/p&gt;

&lt;h2&gt;
  
  
  1 - Un périmètre étendu et fluctuant
&lt;/h2&gt;

&lt;p&gt;Si vous êtes développeur fullstack, vous vous êtes sûrement déjà demandé où s'arrêtait votre périmètre. Quand faire appel à un UX ? A quel moment, dans un esprit devops, faire appel à un admin système ? Tout dépend de l’équipe !&lt;/p&gt;

&lt;p&gt;Dans certaines équipes, le développeur est attendu sur une stack très large. En l’absence d’intégrateur, d’UX ou d'UI designer, on demande au développeur de porter toute la complexité de ces métiers. On retrouve le même phénomène en l’absence de profils orientés devops ou administration de base de données.&lt;/p&gt;

&lt;p&gt;Le schéma suivant synthétise les métiers connexes au métier de développeur fullstack.&lt;/p&gt;

&lt;p&gt;Au centre, les domaines au cœur du métier, aux extrémités, les compétences dépendantes de l'organisation des équipes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MK1ti3XZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mj2bypmpskum3h5u1bip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MK1ti3XZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mj2bypmpskum3h5u1bip.png" alt="schema skills" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sous chacun de ces métiers se cachent une multitude de compétences et d’outils à maîtriser pour pouvoir intervenir sans difficulté sur toute la stack. N’est-ce pas utopique d’attendre autant de connaissances ? Pourquoi les entreprises cherchent-elles à recruter ces profils ?&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - Les points forts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Flexibilité
&lt;/h3&gt;

&lt;p&gt;Le premier point fort d’un développeur fullstack est sa flexibilité.&lt;/p&gt;

&lt;p&gt;Un projet, qu’il soit composé, à part égale ou non, de backend et de frontend, peut être affecté à une des équipes disponibles sans distinction de compétences. De plus, dans le cadre d'un recrutement, d'un besoin de renfort, ou d’une réorganisation, le développeur fullstack est en capacité d'intégrer n’importe quelle équipe.&lt;/p&gt;

&lt;p&gt;Etant donné que chaque développeur intervient sur l’ensemble de la stack, il n’y a, théoriquement, pas besoin de s’assurer de la présence de profils frontend ou backend dans chaque équipe.&lt;/p&gt;

&lt;p&gt;Cette flexibilité est très appréciée des entreprises. Les équipes s’adaptent au besoin, il n'est pas nécessaire d'ajuster le contenu des sprints entre le frontend et le backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication
&lt;/h3&gt;

&lt;p&gt;Le second point fort est la simplification de la communication entre les parties prenantes du projet. Le développeur connaît chaque étape du projet et communique, plus facilement, avec les membres de l'équipe et les métiers connexes.&lt;/p&gt;

&lt;p&gt;Par exemple, en connaissant aussi bien les contraintes du modèle de données que de l’interface, le développeur aura une vision plus globale lorsqu'il s'adressera aux UX/UI ou au product owner.&lt;/p&gt;

&lt;p&gt;Le développeur fullstack est également en capacité de mener une fonctionnalité de bout en bout. Il est à même de détecter, au plus tôt, d'éventuelles incohérences métier ou limitations techniques. Il se sent plus impliqué et a une meilleure appréhension du besoin utilisateur.&lt;/p&gt;

&lt;h3&gt;
  
  
  Et le recrutement ?
&lt;/h3&gt;

&lt;p&gt;Face à la pénurie de développeurs web, rechercher un développeur fullstack tout en étant prêt à recruter un profil backend, souhaitant commencer le frontend, ou vice versa, semble augmenter le nombre de profils potentiels.&lt;/p&gt;

&lt;p&gt;Lorsqu'un recruteur cherche un profil à partir d'une fiche de poste, il identifie les outils à maîtriser et retient les profils correspondants. Après quelques expériences, le CV d'un développeur fullstack contient un bon nombre d'outils front et back. Les recruteurs sélectionnent ces profils sans pouvoir identifier quelle partie de la stack est vraiment maîtrisée. Il est donc, généralement, plus simple de passer la première étape du processus de recrutement avec un profil fullstack.&lt;/p&gt;

&lt;p&gt;Pour autant, ce fonctionnement à tendance à mettre en avant la maîtrise des outils plutôt que des concepts. Les profils sont identifiés comme "Java/Angular" ou "PHP/Vue.js" plutôt que comme "Développeur backend" ou "Développeur frontend".&lt;/p&gt;

&lt;p&gt;On se prive alors de très bon profils, qui après avoir compris les concepts sous-jacents, se sont intéressés à découvrir d'autres langages ou frameworks.&lt;/p&gt;

&lt;p&gt;La flexibilité, la communication, et, d'apparence, l’aspect recrutement, sont à l’avantage des équipes de développeurs fullstack. Mais n’y a t-il pas des limites à ce modèle ? Avec une stack aussi large, le manque d'expertise des équipes finira par poser problème.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - Une expertise souvent absente
&lt;/h2&gt;

&lt;p&gt;Accroître son expertise dans un domaine est essentiel. Cela permet aux équipes de mener à bien des projets complexes et de conserver un sentiment de progression.&lt;/p&gt;

&lt;p&gt;Devant le nombre de concepts, technologies, et outils à maîtriser, il est difficile pour un développeur fullstack de s’affirmer comme expert de toutes les composantes de son métier. Bien qu’il approfondira son expertise en fonction de ses affinités, il ne pourra pas s’y consacrer à 100%. Par exemple, un développeur fullstack, avec une affinité pour le frontend, aura une expertise limitée en comparaison à quelqu’un qui se consacre entièrement au frontend.&lt;/p&gt;

&lt;p&gt;Pour illustrer tout ça, rien de tel que quelques mèmes !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--z308SOul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s42ld6t17125wjslfbz9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--z308SOul--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s42ld6t17125wjslfbz9.png" alt="meme fullstack animals" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vCckqf9K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/axn4ft5hw6ew8868ups4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vCckqf9K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/axn4ft5hw6ew8868ups4.png" alt="fullstack horse" width="880" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Le premier représente très bien l'impossibilité de maîtriser une stack aussi étendue.&lt;/p&gt;

&lt;p&gt;Le second dépeint l'impact sur la qualité lorsque des développeurs backend deviennent fullstack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impacts sur la qualité du produit
&lt;/h3&gt;

&lt;p&gt;Le manque d’expertise diminue la qualité du produit final. Sans expert UX/UI, les interfaces ne seront pas intuitives, le coût de formation des utilisateurs sera élevé et leur adhésion moindre. Sans un expert frontend, la découpe des composants et des modules ne permettra pas une évolution flexible des interfaces. Sans un développeur backend expérimenté, le produit ne passera pas à l'échelle, ce qui limitera son expansion commerciale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impacts sur la qualité du code
&lt;/h3&gt;

&lt;p&gt;Combien de fois avez-vous entendu "C’est pas grave, c’est que du front..." quand il s’agit d’évoquer la qualité de code ou les phases de conception ?&lt;/p&gt;

&lt;p&gt;Généralement, le frontend est le premier à subir les conséquences d’une équipe composée uniquement de développeurs fullstack.&lt;/p&gt;

&lt;p&gt;Historiquement, le backend est le cœur de l’application, il est commun de lui accorder plus d’importance et de renforcer sa qualité. De plus, il n’est pas rare que les développeurs fullstack soient d’anciens développeurs backend. Ils ont donc plus de difficultés à maintenir un code source propre côté frontend. Si l’équipe comprend au moins un développeur frontend expérimenté, il pourra piloter la qualité de code frontend et avoir une exigence forte.&lt;/p&gt;

&lt;p&gt;Pour pallier ce manque d’expertise, les équipes font généralement appel à des profils spécialisés. Qu’il soit un architecte de l’entreprise ou un consultant externe, il n'est pas quotidiennement au contact de l’équipe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Une expertise externe à l’équipe
&lt;/h3&gt;

&lt;p&gt;Lorsque l’expertise est externe à l’équipe, elle engendre une perte d'autonomie. L'équipe n’est pas toujours en mesure de bien comprendre les enjeux et les décisions structurantes prises par l’architecte.&lt;/p&gt;

&lt;p&gt;La création de cette dépendance forte, envers un profil externe à l’équipe, entre en contradiction avec la flexibilité apportée par le métier de développeur fullstack. Chaque membre des équipes est interchangeable, mais aucune équipe ne se suffit à elle même.&lt;/p&gt;

&lt;p&gt;De plus, en se reposant sur un profil externe, les individus de l’équipe peinent à progresser dans un domaine précis. Ce sont pourtant eux, les futurs architectes logiciel de l’entreprise.&lt;/p&gt;

&lt;p&gt;Il est important de savoir profiter de connaissances externes pour résoudre un problème précis. Néanmoins, la déspécialisation des développeurs pousse les équipes à systématiquement avoir besoin d'une aide extérieure.&lt;/p&gt;

&lt;p&gt;L'organisation autour des développeurs fullstack n’est, évidemment, pas l’unique frein à la progression d’un développeur, mais le manque d’incitation à accroître une expertise ralentit la montée en compétences globale des équipes et leur autonomie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Derrière les avantages d'une équipe de développeurs fullstack se cachent aussi plusieurs inconvénients.&lt;/p&gt;

&lt;p&gt;Le gain de flexibilité, de communication, et la facilitation du recrutement, sont de très bon points tant que ça ne limite pas l’expertise de l’équipe, et par conséquent, la qualité du produit. Face au nombre de compétences attendues qui ne cesse de grandir, il est très difficile de maintenir un bon niveau dans chaque domaine. De plus, pour construire une équipe autonome, il est essentiel de recruter des experts frontend et des experts backends dans les équipes.&lt;/p&gt;

&lt;p&gt;L’objectif de l’article n’est pas de remettre en cause l'existence de développeurs fullstack mais de questionner son omniprésence et ses conséquences. Si les avantages sont indéniables, comprendre les difficultés que pourra rencontrer une équipe constituée uniquement de développeurs fullstack vous aidera à mieux l'accompagner et à maximiser la qualité de son travail.&lt;/p&gt;

</description>
      <category>fullstack</category>
    </item>
    <item>
      <title>RGPD - Le devoir de protéger les données</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Mon, 03 Oct 2022 07:36:16 +0000</pubDate>
      <link>https://dev.to/younup/rgpd-le-devoir-de-proteger-les-donnees-1g80</link>
      <guid>https://dev.to/younup/rgpd-le-devoir-de-proteger-les-donnees-1g80</guid>
      <description>&lt;h1&gt;
  
  
  RGPD - Le devoir de protéger les données
&lt;/h1&gt;

&lt;p&gt;Où étiez-vous début 2019 ? Personnellement je rejoignais une entreprise en pleine ébullition sur un sujet : la RGPD. &lt;/p&gt;

&lt;p&gt;On réalisait des développements en urgence, il y avait une personne déléguée à la RGPD qui mettait son nez partout et la direction craignait un peu un contrôle. Bref, c'était en quelque sorte la panique à bord.&lt;/p&gt;

&lt;p&gt;Les plus assidus d'entre vous me demanderont pourquoi 2019, puisque la première lecture du texte remonte à 2014 et que la RGPD a été publiée en 2016. C'est simplement parce que le texte était devenu applicable en mai 2018 et que les premières sanctions ont commencé à tomber à partir de là, donc les entreprises se sont mises à appliquer la loi. &lt;/p&gt;

&lt;p&gt;Je vous propose aujourd'hui, pour bien comprendre les grandes lignes de la RGPD, qu'on remonte le temps jusqu'à la genèse du projet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contexte historique
&lt;/h2&gt;

&lt;p&gt;On est en 2013, en France &lt;a href="https://www.cnil.fr/fr/la-loi-informatique-et-libertes"&gt;la loi Informatique et Libertés&lt;/a&gt; est en vigueur et la CNIL s'applique à faire respecter la loi depuis 1978, d'autres pays ont des principes similaires, mais ce n'est pas le cas partout. Mais en dehors du pays c'est le droit européen ou international qui s'applique et ça devient tout de suite plus compliqué !&lt;/p&gt;

&lt;p&gt;C'est donc dans ce tumulte que la commission européenne fait la proposition de la &lt;strong&gt;Réglementation Générale sur la Protection des Données&lt;/strong&gt; ou pour être plus exact le &lt;strong&gt;RÈGLEMENT (UE) 2016/679 DU PARLEMENT EUROPÉEN ET DU CONSEIL du 27 avril 2016 relatif à la protection des personnes physiques à l'égard du traitement des données à caractère personnel et à la libre circulation de ces données, et abrogeant la directive 95/46/CE (règlement général sur la protection des données)&lt;/strong&gt;, ou pour les intimes la RGPD.&lt;/p&gt;

&lt;p&gt;Un texte unique qu'il faut comprendre comme le "minimum" légal, car les états membres ont la possibilité d'approfondir certains points. Comme c'est le cas en France, toujours avec la loi Informatique et Libertés qui enrichie les droits et devoirs liés au numérique.&lt;/p&gt;

&lt;p&gt;A la RGPD s'ajoute un &lt;strong&gt;Comité Européen de la Protection des Données&lt;/strong&gt; (CEPD en français ou EDPB en anglais). Ce comité a plus ou moins autorité au niveau européen dans tout ce qui concerne la RGPD. &lt;a href="https://edpb.europa.eu/edpb_fr"&gt;Pour en savoir plus sur ses missions, vous trouverez le site officiel en lien.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Et surtout, chaque état membre doit désigner un organisme qui se chargera des contrôles et condamnations au niveau de l'état. En France, nous avons donc la &lt;a href="https://www.cnil.fr/fr/la-protection-des-donnees-dans-le-monde"&gt;&lt;strong&gt;CNIL&lt;/strong&gt; (Commission nationale de l'informatique et des libertés)&lt;/a&gt; ; en Allemagne, ils ont la &lt;strong&gt;BfDI&lt;/strong&gt; (die Bundesbeauftragt für den Datenschutz un die Informations freiheit Husarenstr) ; en Belgique, l'&lt;strong&gt;Autorité de protection des données&lt;/strong&gt;, etc... &lt;/p&gt;

&lt;p&gt;Cependant, un problème pointe le bout de son nez : Quelles sont les limites d'applications ? &lt;/p&gt;

&lt;h2&gt;
  
  
  Les personnes et la zone impactées
&lt;/h2&gt;

&lt;p&gt;Il est donc décidé que &lt;strong&gt;tous les citoyens et ressortissants européens&lt;/strong&gt;, quel que soit leur âge sont protégés par la RGPD, du moins tant qu'ils sont &lt;strong&gt;vivants&lt;/strong&gt; ! De toute façon, une fois mort, vous n'allez pas réclamer vos droits. &lt;/p&gt;

&lt;p&gt;Bon en réalité, la mort numérique est un vrai &lt;a href="https://www.cnil.fr/fr/mort-numerique-effacement-informations-personne-decedee"&gt;sujet juridique&lt;/a&gt;. Et un vrai sujet pour &lt;a href="https://fr.ign.com/tech/52271/news/microsoft-depose-un-brevet-pour-des-bots-de-discussion-imitant-des-personnes-decedees"&gt;les entreprises privées qui se la jouent à la Black-Mirror&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;La RGPD s'applique à toutes les entreprises présentes sur le territoire européen, ainsi qu'aux entreprises extérieures si elles traitent des données liées à des citoyens européens, &lt;a href="https://www.01net.com/actualites/meta-pourrait-il-vraiment-fermer-facebook-et-instagram-en-europe-2054423.html"&gt;ce qui pose bien problème aux entreprises dont la donnée est le business&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;D'ailleurs c'est vrai que la RGPD ça parle de données personnelles, mais est-ce que vous savez ce que c'est ? &lt;/p&gt;

&lt;h2&gt;
  
  
  Les données à caractère personnel
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Il s’agit en fait de toutes les données qui identifient ou permettent d’identifier une personne physique.&lt;/strong&gt; Un regroupement de données qui permettent d’identifier une personne est aussi considéré comme donnée à caractère personnel.&lt;/p&gt;

&lt;p&gt;Pour que ce soit plus parlant, voici une petite liste d’exemple des données que l’on considère comme à caractère personnel : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Un prénom et un nom ; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Une adresse personnelle ; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Une adresse e-mail telle que pré&lt;a href="mailto:nom.nom@entreprise.com"&gt;nom.nom@entreprise.com&lt;/a&gt;; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Un numéro de carte d’identité ; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Des données de localisation (par exemple : la fonction de localisation d’un téléphone portable) ; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Une adresse de protocole internet ; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Un cookie (les fameux de votre navigateur et pas ceux qui se mangent) ; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;L’identifiant publicitaire de votre téléphone ; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Des données détenues par un hôpital ou un médecin, qui permettraient d’identifier de manière unique une personne.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cependant, il y a moyen de se soustraire de ce contexte, si les données sont &lt;a href="https://www.cnil.fr/fr/lanonymisation-de-donnees-personnelles"&gt;anonymisées, chiffrées ou pseudonymisées&lt;/a&gt; alors elles sortent du cadre de la RGPD, si &lt;strong&gt;elles ne permettent plus d'identifier à nouveau une personne physique&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Selon le texte de réglementation, il faut "&lt;strong&gt;&lt;em&gt;prendre en compte l’ensemble des moyens utilisés par un tiers pour identifier une personne physique afin de savoir si les données sont à caractère personnel.&lt;/em&gt;&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;J'ai parlé plusieurs fois de personne physique, puisque ce sont les mots du texte, mais pourquoi physique ? &lt;/p&gt;

&lt;h2&gt;
  
  
  Personne physique ou Personne morale
&lt;/h2&gt;

&lt;p&gt;Ce que la loi dit c'est qu'&lt;strong&gt;&lt;em&gt;Une personne physique, c’est un être humain doté d’une personnalité juridique. C’est-à-dire que cet humain doit être majeur (sauf émancipation) et ne doit pas être en incapacité partielle ou totale (mise en tutelle ou curatelle).&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;En droit on parle aussi de personne morale, qui est "&lt;strong&gt;&lt;em&gt;un regroupement de personne (morale ou physique) doté d’une personnalité juridique.&lt;/em&gt;&lt;/strong&gt;" &lt;/p&gt;

&lt;p&gt;Donc, je suis une personne physique et théoriquement vous devriez l’être aussi. Votre entreprise et l’état sont eux des personnes morales. Pour votre culture l’une est dite de droit privé et l’autre de droit public.&lt;/p&gt;

&lt;p&gt;Cette définition de personne morale est importante pour comprendre la définition donnée par la RGPD de &lt;strong&gt;responsable de traitement&lt;/strong&gt;. Puisque le responsable de traitement est "&lt;strong&gt;&lt;em&gt;la personne physique ou morale [...] qui [...] détermine les finalités et les moyens du traitement.&lt;/em&gt;&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;Et est-ce que vous savez ce qu'une personne a de plus important ? Son libre arbitre ! &lt;/p&gt;

&lt;h2&gt;
  
  
  Le consentement
&lt;/h2&gt;

&lt;p&gt;Le principe le plus important de la RGPD, c'est le &lt;strong&gt;consentement&lt;/strong&gt; entre vous et le responsable de traitement. Et comme pour les relations humaines, il doit être &lt;strong&gt;libre&lt;/strong&gt;, &lt;strong&gt;explicite&lt;/strong&gt;, &lt;strong&gt;positif&lt;/strong&gt; et &lt;strong&gt;éclairé&lt;/strong&gt; !&lt;/p&gt;

&lt;p&gt;Cela se présente sous plusieurs formes comme par exemple les fameux cookies qui vous embêtent tant ! Si on s'en tient à la RGPD vous devriez en avoir sur tous les sites :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;uniquement les nécessaires&lt;/strong&gt; ou &lt;strong&gt;aucun&lt;/strong&gt;, selon que le site utilise des cookies pour fonctionner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;parametrer&lt;/strong&gt;, et lors de la sélection dans le paramétrage tout doit être à refuser par défaut et doit indiquer clairement son origine et l'utilisation qui sera faite des données&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tout accepter&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Et dans tous les cas préciser pourquoi les cookies vont être utilisés.&lt;/p&gt;

&lt;p&gt;Il en est de même pour les formulaires, normalement vous devriez voir la case &lt;strong&gt;s'inscrire à la newsletter&lt;/strong&gt; décocher par défaut.&lt;/p&gt;

&lt;p&gt;Certaines entreprises jouent avec les limites et le &lt;strong&gt;Paywall&lt;/strong&gt; est l'une des pratiques les plus utilisées pour forcer l'utilisation de traqueurs ou l'obtention d'un paiement. Bien que moralement douteuse, cette pratique est &lt;strong&gt;légale&lt;/strong&gt;. Elle constitue aux yeux de la CNIL &lt;a href="https://www.cnil.fr/fr/cookies-et-autres-traceurs/regles/cookie-walls/la-cnil-publie-des-premiers-criteres-devaluation"&gt;une alternative au financement du service&lt;/a&gt;.&lt;br&gt;
C'est pour cette raison que vous voyez une pop-up avec les boutons &lt;strong&gt;J'accepte&lt;/strong&gt; ou &lt;strong&gt;Je m'abonne&lt;/strong&gt; sur &lt;a href="https://maisouvaleweb.fr/le-cookiewall-solution-pour-continuer-a-tracer-malgre-le-rgpd/"&gt;tous les sites appartenant à Webedia, et cela bien que des alternatives existent&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mais dans le cadre de la RGPD, on donne sont consentement à quoi ? &lt;/p&gt;

&lt;h2&gt;
  
  
  Traitement automatisé et profilage
&lt;/h2&gt;

&lt;p&gt;Lorsqu'on donne son consentement, cela peut être pour des traitements de vos données ou pour du profilage. C'est même l'article 22 de la RGPD : &lt;/p&gt;

&lt;p&gt;"&lt;strong&gt;&lt;em&gt;La personne physique a le droit de ne pas faire l'objet d'une décision fondée exclusivement sur un traitement automatisé, y compris le profilage.&lt;/em&gt;&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;Très bien, mais c'est quoi un traitement ? &lt;/p&gt;

&lt;p&gt;Si on s'en tient au texte officiel alors un &lt;strong&gt;traitement&lt;/strong&gt; c’est :&lt;/p&gt;

&lt;p&gt;"&lt;strong&gt;&lt;em&gt;toute opération ou tout ensemble d'opérations effectuées ou non à l'aide de procédés automatisés sur des données.&lt;/em&gt;&lt;/strong&gt;"&lt;/p&gt;

&lt;p&gt;Ce qui implique donc la collecte, l'enregistrement, la conservation, la modification, la consultation, l'extraction, l'utilisation, l'anonymisation ou la destruction, etc. &lt;/p&gt;

&lt;p&gt;Mieux encore, puisqu'il s'agit "&lt;strong&gt;&lt;em&gt;ou non [...] de procédés automatisés&lt;/em&gt;&lt;/strong&gt;", les archives papiers avec vos informations sont soumises à la RGPD !&lt;/p&gt;

&lt;p&gt;Et quelle est la différence avec le profilage ?&lt;/p&gt;

&lt;p&gt;Lorsqu'on parle de profilage on parle de catégorisation et de prédiction de votre comportement. On pourrait ainsi parler des analyses Youtube pour prédire quelles vidéos vous pourriez aimer en se basant sur ce que vous avez regardé. Ou bien &lt;a href="https://www.ouest-france.fr/monde/chine/bons-ou-mauvais-citoyens-la-chine-compte-les-points-avec-son-credit-social-6501129"&gt;le système de "crédit social" mis en place à Pékin&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Ok c'est bien gentil tout ça, mais si je ne veux plus que google fasse du profilage sur mes données comment je fais ? Parce que normalement on doit pouvoir retirer notre consentement ! &lt;/p&gt;

&lt;h2&gt;
  
  
  Le droit à l'effacement
&lt;/h2&gt;

&lt;p&gt;Toujours en lien avec le consentement, vous pouvez retirer ce dernier et demandez à être oublié.&lt;/p&gt;

&lt;p&gt;Cela consiste simplement dans le fait que "&lt;strong&gt;&lt;em&gt;la personne physique a le droit de demander au responsable du traitement l'effacement de ses données dans les meilleurs délais&lt;/em&gt;&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;Il y a cependant certains motifs pour faire cette demande, il faut par exemple que :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;la personne physique retire son consentement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;les données ne soient plus nécessaires aux finalités pour lesquelles elles ont été collectées&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;le traitement soit illicite&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;une autre obligation légale force l'effacement&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;il s'agisse de données relatives à un mineur&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Le mot de la fin
&lt;/h2&gt;

&lt;p&gt;On n'a fait qu'effleurer la surface de ce magnifique et vaste sujet, mais vous avez déjà là les premières grandes lignes de ce qu'est la RGPD : un texte visant à faire garder le contrôle de leurs données aux utilisateurs.&lt;/p&gt;

&lt;p&gt;Il est essentiel de bien comprendre ce que représente ce texte, car il impacte sans vraiment le savoir beaucoup d'aspects de nos vies. &lt;/p&gt;

&lt;p&gt;Si vous souhaitez aller plus loin dans les explications de la réglementation, je vous conseille bien évidemment &lt;a href="https://www.cnil.fr/"&gt;le site de la CNIL&lt;/a&gt; qui contient entre autres des exemples et explications pour chacun de vos droits, le guide des bonnes pratiques, ainsi que le texte en intégralité : &lt;a href="https://www.cnil.fr/fr/reglement-europeen-protection-donnees"&gt;Le règlement général sur la protection des données - RGPD | CNIL&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Egalement accessible sur "eur-lex" le site des droits européens en différentes langues : &lt;a href="https://eur-lex.europa.eu/legal-content/FR/TXT/?uri=CELEX%3A32016R0679&amp;amp;qid=1652709414050"&gt;Texte intégral en français | EUR-Lex&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rgpd</category>
    </item>
    <item>
      <title>MkDocs : Générer un site web pour votre documentation Markdown</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 25 Nov 2021 08:29:53 +0000</pubDate>
      <link>https://dev.to/younup/mkdocs-generer-un-site-web-pour-votre-documentation-markdown-2ge9</link>
      <guid>https://dev.to/younup/mkdocs-generer-un-site-web-pour-votre-documentation-markdown-2ge9</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/N3rwaXdeNNc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>markdown</category>
    </item>
    <item>
      <title>Génération de code source C# en se basant sur des attributs</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 30 Sep 2021 07:08:40 +0000</pubDate>
      <link>https://dev.to/younup/generation-de-code-source-c-en-se-basant-sur-des-attributs-faa</link>
      <guid>https://dev.to/younup/generation-de-code-source-c-en-se-basant-sur-des-attributs-faa</guid>
      <description>&lt;h1&gt;
  
  
  Génération de code source C# en se basant sur des attributs
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Ce que l'on va découvrir
&lt;/h2&gt;

&lt;p&gt;Nous allons voir comment :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Régler son environnement pour créer et déboguer un générateur de code C#.&lt;/li&gt;
&lt;li&gt;Développer un générateur de code qui se base sur des annotations pour générer une classe pendant la phase de build.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prérequis
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Visual Studio 2019 16.10+&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Et pour le debug :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Charge de travail "Développement d'extensions pour Visual Studio"&lt;/li&gt;
&lt;li&gt;Composant individuel "SDK .NET Compiler Platform"&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Créer un projet de génération de code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Le projet
&lt;/h3&gt;

&lt;p&gt;Créer un projet de type "bibliothèque de code" (library) en .NET Standard 2.0.&lt;/p&gt;

&lt;p&gt;Ajouter les références suivantes via nuget :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Microsoft.CodeAnalysis.CSharp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Microsoft.CodeAnalysis.Analyzers&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : Les versions de ces packages sont liées à une version du SDK dotnet précise. Pour assurer le bon fonctionnement du générateur, bien vérifier que le SDK installé est la dernière version avant d'installer les packages. Une fois les packages installés, ne pas les mettre à jour sans mettre également le SDK à jour.&lt;/p&gt;

&lt;p&gt;Il faudra également éditer le fichier projet pour ajouter dans le nœud &lt;code&gt;PropertyGroup&lt;/code&gt; (celui qui contient &lt;code&gt;TargetFramework&lt;/code&gt;) une balise &lt;code&gt;IsRoslynComponent&lt;/code&gt; qui prendra la valeur &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Pour un résultat ressemblant à :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;netstandard2.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;IsRoslynComponent&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/IsRoslynComponent&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LangVersion&amp;gt;&lt;/span&gt;9.0&lt;span class="nt"&gt;&amp;lt;/LangVersion&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : La version minimum du langage nécessaire pour utiliser les générateurs de code est la version &lt;code&gt;9.0&lt;/code&gt;. Il faudra donc que tous les projets concernés (ceux exposant des générateurs ou ceux qui les consomment utilisent a minima cette version du langage).&lt;/p&gt;

&lt;h3&gt;
  
  
  Le template
&lt;/h3&gt;

&lt;p&gt;Maintenant que notre projet est configuré pour se comporter comme un projet de générateur de code, il nous reste plus qu'à en créer un exemple.&lt;/p&gt;

&lt;p&gt;Le template de base est le suivant :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis.CSharp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis.CSharp.Syntax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;MyGeneratorNameSpace&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGenerator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISourceGenerator&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GeneratorInitializationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GeneratorExecutionContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deux éléments sont particulièrement importants ici :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;L'attribut &lt;code&gt;[Generator]&lt;/code&gt; qui indique que cette classe devra être exécutée comme générateur de code&lt;/li&gt;
&lt;li&gt;L'interface implémentée &lt;code&gt;ISourceGenerator&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;La méthode &lt;code&gt;Initialize&lt;/code&gt; est exécutée pendant que le générateur parcourt le code.&lt;/p&gt;

&lt;p&gt;La méthode &lt;code&gt;Execute&lt;/code&gt; est exécutée une fois que le code a fini d'être parcouru, c'est ici que le code sera effectivement généré.&lt;/p&gt;

&lt;h3&gt;
  
  
  Référencer un générateur de code
&lt;/h3&gt;

&lt;p&gt;Pour référencer un générateur de code dans un projet, il est nécessaire d'éditer le fichier &lt;code&gt;.csproj&lt;/code&gt; manuellement.&lt;/p&gt;

&lt;p&gt;Nous allons ajouter un nœud &lt;code&gt;ItemGroup&lt;/code&gt; contenant une référence de projet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ProjectReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"path-to-sourcegenerator-project.csproj"&lt;/span&gt; 
                      &lt;span class="na"&gt;OutputItemType=&lt;/span&gt;&lt;span class="s"&gt;"Analyzer"&lt;/span&gt;
                      &lt;span class="na"&gt;ReferenceOutputAssembly=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cela ressemble à une référence de projet classique avec deux attributs supplémentaires obligatoires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;OutputTypeItem&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReferenceOutputAssembly&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Le second doit prendre la valeur &lt;code&gt;true&lt;/code&gt; si vous référencez des types qui sont compris dans l'assembly contenant le générateur de code ; sinon, &lt;code&gt;false&lt;/code&gt; permet de ne pas avoir de dépendance à l'assembly contenant le générateur de code dans les assemblys le référençant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hello World
&lt;/h2&gt;

&lt;p&gt;Maintenant que nous avons vu la théorie, passons à la pratique pour mettre en place un projet console qui référencera un projet de générateur de code qui nous affichera un HelloWorld ainsi que la liste des arbres syntaxiques connus.&lt;/p&gt;

&lt;h3&gt;
  
  
  La solution
&lt;/h3&gt;

&lt;p&gt;Nous allons nous atteler à créer notre solution &lt;code&gt;HelloWorld&lt;/code&gt;, celle-ci contiendra :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;un projet console .NET 5.0&lt;/li&gt;
&lt;li&gt;un projet de type bibliothèque ciblant .NET Standard 2.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Si l'on applique ce que l'on a précédemment évoqué, les deux fichiers projets auront un contenu similaire à :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--HelloGeneratedWorld.csproj (notre application console)--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;OutputType&amp;gt;&lt;/span&gt;Exe&lt;span class="nt"&gt;&amp;lt;/OutputType&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net5.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ProjectReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"..\SourceGenerators\SourceGenerators.csproj"&lt;/span&gt;
                      &lt;span class="na"&gt;OutputItemType=&lt;/span&gt;&lt;span class="s"&gt;"Analyzer"&lt;/span&gt;
                      &lt;span class="na"&gt;ReferenceOutputAssembly=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--SourceGEnerators.csproj (notre librairie .NET Standard)--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;netstandard2.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;IsRoslynComponent&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/IsRoslynComponent&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LangVersion&amp;gt;&lt;/span&gt;9.0&lt;span class="nt"&gt;&amp;lt;/LangVersion&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.CodeAnalysis.Analyzers"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"3.3.2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;PrivateAssets&amp;gt;&lt;/span&gt;all&lt;span class="nt"&gt;&amp;lt;/PrivateAssets&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;IncludeAssets&amp;gt;&lt;/span&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;span class="nt"&gt;&amp;lt;/IncludeAssets&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/PackageReference&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.CodeAnalysis.CSharp"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"3.11.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nous allons nous inspirer &lt;a href="https://devblogs.microsoft.com/dotnet/introducing-c-source-generators/" rel="noopener noreferrer"&gt;d'un billet de blog&lt;/a&gt; par Philippe Carter introduisant les générateurs de source.&lt;/p&gt;

&lt;p&gt;Le code de génération de notre &lt;code&gt;HelloWorld&lt;/code&gt; mis au goût du jour est donc le suivant :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// HelloWorldGenerator.cs&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;SourceGenerators&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGenerator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISourceGenerator&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GeneratorInitializationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GeneratorExecutionContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// begin creating the source we'll inject into the users compilation&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sourceBuilder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
using System;
namespace HelloWorldGenerated
{
    public static class HelloWorld
    {
        public static void SayHello() 
        {
            Console.WriteLine(""Hello from generated code!"");
            Console.WriteLine(""The following syntax trees existed in the compilation that created this program:"");
"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// using the context, get a list of syntax trees in the users compilation&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;syntaxTrees&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SyntaxTrees&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// add the filepath of each tree to the class we're building&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxTree&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;syntaxTrees&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sourceBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$@"Console.WriteLine(@"" - &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FilePath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"");"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// finish creating the source to inject&lt;/span&gt;
            &lt;span class="n"&gt;sourceBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
        }
    }
}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// inject the created source into the users compilation&lt;/span&gt;
            &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloWorldGenerator"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sourceBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Et son utilisation dans notre application console :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Program.cs&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;HelloGeneratedWorld&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;HelloWorldGenerated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HelloWorld&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SayHello&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Votre solution devrait ressembler à la capture ci-dessous :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizwk7yt4zqolvt8h05m3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizwk7yt4zqolvt8h05m3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Si vous avez appliqué les instructions, sans avoir lancé le débogage (ou la compilation) de l'application console, Visual Studio doit vous indiquer qu'il ne connait pas les types !&lt;/p&gt;

&lt;p&gt;C'est normal, même si contre-intuitif et pas forcément pratique.&lt;/p&gt;

&lt;p&gt;De ce que j'ai pu constater, la génération de code se fait à deux principaux moments :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Au chargement du projet référençant le générateur&lt;/li&gt;
&lt;li&gt;A la compilation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Ce qui veut dire... Que lancer la compilation dans cet état ne renverra pas d'erreur, et mieux que ça, vous affichera les arbres syntaxiques connus par le générateur&lt;/p&gt;

&lt;p&gt;Par exemple :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hello World!
Hello from generated code!
The following syntax trees existed in the compilation that created this program:
 - C:\SourceGenerators\Examples\HelloGeneratedWorld\Program.cs
 - C:\SourceGenerators\Examples\HelloGeneratedWorld\obj\Debug\net5.0\.NETCoreApp,Version=v5.0.AssemblyAttributes.cs
 - C:\SourceGenerators\Examples\HelloGeneratedWorld\obj\Debug\net5.0\HelloGeneratedWorld.AssemblyInfo.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La solution complète prête à être utilisée est disponible dans ce &lt;a href="https://github.com/sidewinder94/HelloSourceGenerators" rel="noopener noreferrer"&gt;dépôt Github&lt;/a&gt; dans la branche HelloWorld.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; : J'utilisais le SDK .NET 5.0.400 quand j'ai créé le projet, si vous avez une version différente, vous pourriez être amenés à devoir changer la version des packages nuget du projet &lt;code&gt;SourceGenerators&lt;/code&gt; pour que tout fonctionne correctement.&lt;/p&gt;

&lt;p&gt;Pour illustrer la note concernant la propriété &lt;code&gt;ReferenceOutputAssembly&lt;/code&gt;, une capture du dossier de sortie après un premier debug :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqrz285qm8o3j7iw3m7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqrz285qm8o3j7iw3m7h.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On ne trouve pas d'assembly &lt;code&gt;SourceGenerators&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Un cran plus loin : analysons les arbres syntaxiques
&lt;/h2&gt;

&lt;p&gt;Cette section est basée sur ma propre question/réponse disponible sur &lt;a href="https://stackoverflow.com/a/65126680/2245256" rel="noopener noreferrer"&gt;StackOverflow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nous allons dans un premier temps, introduire le problème :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomAttribute&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Attribute&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="p"&gt;[...]&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CustomAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[...]&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Custom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Class2&lt;/span&gt;&lt;span class="p"&gt;))]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Class1&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;M1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Class2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;M2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Class2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Class2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;[...]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;L'idée est d'avoir un attribut que nous allons pouvoir placer sur une classe afin de générer de générer du code pour dans une autre classe qui sera partielle et qui contiendra une instance de la &lt;code&gt;Class1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;L'idée est de générer un &lt;code&gt;partial&lt;/code&gt; qui ressemblera à :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Class2&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;M1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;M1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;M2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_wrapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;M2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maintenant que l'objectif est posé, voyons comment nous allons pouvoir :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;trouver quelles classes sont marquées par ces attributs,&lt;/li&gt;
&lt;li&gt;lister les méthodes, leurs types de retours et leurs paramètres,&lt;/li&gt;
&lt;li&gt;générer la source pour le &lt;code&gt;partial&lt;/code&gt; pour les classes identifiées.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nous allons tout rédiger dans la méthode &lt;code&gt;Execute&lt;/code&gt; du générateur.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exclure les arbres qui ne contiennent aucune classe annotée
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;treesWithlassWithAttributes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SyntaxTrees&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
            &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRoot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ClassDeclarationSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; 
                    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AttributeSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En lisant cet extrait, on se rend compte tout de suite que LinQ va être un de nos meilleurs amis et que la navigation fonctionne un peu comme LinQToXML.&lt;/p&gt;

&lt;p&gt;Par étapes :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;On recherche et parcourt les nœuds de type déclaration de classe.&lt;/li&gt;
&lt;li&gt;On recherche les nœuds qui appartiennent à la classe des nœuds de type attribut.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Et on ne retourne que les arbres syntaxiques qui ont donc des classes possédant au moins un attribut.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retirer les classes qui ne sont pas annotées
&lt;/h3&gt;

&lt;p&gt;Rien n'empêche en C# d'avoir plusieurs classes définies dans le même fichier.&lt;/p&gt;

&lt;p&gt;Cette étape consiste donc à exclure toutes les classes des arbres syntaxiques retenus qui n'ont pas d'attributs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;declaredClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRoot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ClassDeclarationSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AttributeSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ici, &lt;code&gt;tree&lt;/code&gt; correspond à un des arbres syntaxiques sélectionnés précédemment.&lt;/p&gt;

&lt;p&gt;Nous descendons une fois encore pour sélectionner les nœuds de type déclaration de classe, mais uniquement ceux qui sont décorés par des attributs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retirer les classes qui ne sont pas annotées par notre attribut
&lt;/h3&gt;

&lt;p&gt;Nous allons commencer par initialiser un modèle &lt;strong&gt;sémantique&lt;/strong&gt; correspondant à notre arbre syntaxique.&lt;/p&gt;

&lt;p&gt;Ceci va nous permettre notamment :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;de rechercher des types,&lt;/li&gt;
&lt;li&gt;d'obtenir facilement des informations sur les types sans avoir à parcourir l'arbre syntaxique.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cela se fait simplement :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;semanticModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSemanticModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maintenant que notre modèle est initialisé, retournons à nos moutons :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;declaredClass&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AttributeSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantTokens&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IdentifierToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;semanticModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTypeInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;attributeSymbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;DescendantTokens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IdentifierToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : &lt;code&gt;attributeSymbol&lt;/code&gt; est une variable définie au début de ma méthode &lt;code&gt;Execute&lt;/code&gt; qui contient le &lt;code&gt;Type&lt;/code&gt; de l'attribut qui nous intéresse.&lt;/p&gt;

&lt;p&gt;Nous repartons donc de la déclaration de notre classe dans notre arbre syntaxique, pour rechercher les attributs.&lt;/p&gt;

&lt;p&gt;On va ensuite sélectionner la première déclaration d'attribut qui a un &lt;code&gt;IdentifierToken&lt;/code&gt; dont le nœud parent est du type de l'attribut (on notera la comparaison par nom : l'API sémantique ne permet pas d'obtenir un &lt;code&gt;Type&lt;/code&gt;, d'où la comparaison par le nom).&lt;/p&gt;

&lt;p&gt;Pour l'étape suivante, nous aurons besoin des &lt;code&gt;IdentifiersToken&lt;/code&gt;. Nous allons donc nous appuyer sur l'opérateur "Elvis" (&lt;code&gt;?.&lt;/code&gt;) pour propager les valeurs nulles éventuelles, ce qui nous permettra de passer directement à l'itération suivante de notre boucle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Récupérer le type de classe utilisé comme paramètre de l'attribut
&lt;/h3&gt;

&lt;p&gt;L'étape précédente nous a permis d'obtenir, dans la variable &lt;code&gt;nodes&lt;/code&gt;, les &lt;code&gt;IdentifiersToken&lt;/code&gt; correspondant à l'utilisation de l'attribut.&lt;/p&gt;

&lt;p&gt;Un premier identifiant représentant le nom de l'attribut, puis un second qui correspond au nom de la classe passée en paramètre.&lt;/p&gt;

&lt;p&gt;Pour obtenir les détails de la classe qui nous intéresse sans avoir à reparcourir tous nos arbres syntaxiques, nous allons à nouveau nous appuyer sur le modèle sémantique que nous avons initialisé plus tôt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;relatedClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;semanticModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTypeInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Last&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Puisque nous avons maintenant obtenu le nom de la classe, il est possible de commencer a générer le code lié à cette classe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Le nom de la classe peut être obtenu avec &lt;code&gt;relatedClass.Type.Name&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lister toutes les méthodes présentes dans la classe
&lt;/h3&gt;

&lt;p&gt;Nous allons maintenant lister toutes les méthodes de la classe annotée (celle sur laquelle nous sommes en train de travailler au travers de l'arbre syntaxique, pas celle que nous venons de trouver dans le modèle syntaxique).&lt;/p&gt;

&lt;p&gt;La première étape est relativement simple : lister tous les membres de la classe qui sont de type &lt;code&gt;MethodDeclaration&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MethodDeclarationSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;classMethod&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;declaredClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Members&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodDeclaration&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MethodDeclarationSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour notre cas, il va être nécessaire de caster explicitement vers le type &lt;code&gt;MethodDeclarationSyntax&lt;/code&gt;. Le type de base stocké dans la collection &lt;code&gt;Members&lt;/code&gt; est typé moins spécifiquement et n'expose pas les propriétés dont nous aurons besoin :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Modifiers&lt;/span&gt; &lt;span class="c1"&gt;//public, static, etc...&lt;/span&gt;
&lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt; &lt;span class="c1"&gt;// Plutôt évident =&amp;gt; le nom&lt;/span&gt;
&lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParameterList&lt;/span&gt; &lt;span class="c1"&gt;// La liste des paramètres, incluant type, nom, valeurs par défaut&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Le reste de l'étape consiste juste à créer une chaine représentant la classe partielle dont j'avais besoin.&lt;/p&gt;

&lt;h3&gt;
  
  
  La solution finale
&lt;/h3&gt;

&lt;p&gt;Voici donc la solution complète après avoir suivi toutes ces étapes :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Dans le code suivant, &lt;code&gt;RelatedModelAttribute&lt;/code&gt; correspond au &lt;code&gt;CustomAttribute&lt;/code&gt; des exemples ci-dessus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : Ce code fait partie d'un de mes &lt;a href="https://github.com/sidewinder94/speedify-cli-wrapper/blob/master/SpeedifyCliWrapper.SourceGenerators/ModuleModelGenerator.cs" rel="noopener noreferrer"&gt;projets sur GitHub&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis.CSharp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis.CSharp.Syntax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.CodeAnalysis.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;SpeedifyCliWrapper.SourceGenerators.Annotations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;SpeedifyCliWrapper.SourceGenerators&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Generator&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModuleModelGenerator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ISourceGenerator&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GeneratorExecutionContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;attributeSymbol&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTypeByMetadataName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RelatedModelAttribute&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;classWithAttributes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SyntaxTrees&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRoot&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ClassDeclarationSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AttributeSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;

            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxTree&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;classWithAttributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;semanticModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compilation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSemanticModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;declaredClass&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tree&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetRoot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ClassDeclarationSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AttributeSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;declaredClass&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantNodes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AttributeSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DescendantTokens&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IdentifierToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;semanticModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTypeInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;attributeSymbol&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;DescendantTokens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IdentifierToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

                    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;

                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;relatedClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;semanticModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTypeInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Last&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;generatedClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GenerateClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;relatedClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MethodDeclarationSyntax&lt;/span&gt; &lt;span class="n"&gt;classMethod&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;declaredClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Members&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsKind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxKind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodDeclaration&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;OfType&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MethodDeclarationSyntax&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;())&lt;/span&gt;
                    &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GenerateMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;declaredClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;relatedClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;generatedClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;

                    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CloseClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generatedClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;declaredClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;relatedClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SourceText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;From&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generatedClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GeneratorInitializationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Nothing to do here&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;GenerateMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SyntaxToken&lt;/span&gt; &lt;span class="n"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeInfo&lt;/span&gt; &lt;span class="n"&gt;relatedClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MethodDeclarationSyntax&lt;/span&gt; &lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Modifiers&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;relatedClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;("&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParameterList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;")"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;methodCall&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"return this._wrapper.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;moduleName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;methodDeclaration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;(this, &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Identifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()))}&lt;/span&gt;&lt;span class="s"&gt;);"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
        "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;@"
        {
            "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;methodCall&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;@"
        }"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;StringBuilder&lt;/span&gt; &lt;span class="nf"&gt;GenerateClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypeInfo&lt;/span&gt; &lt;span class="n"&gt;relatedClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
using System;
using System.Collections.Generic;
using SpeedifyCliWrapper.Common;

namespace SpeedifyCliWrapper.ReturnTypes
{
    public partial class "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;relatedClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;@"
    {"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;CloseClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StringBuilder&lt;/span&gt; &lt;span class="n"&gt;generatedClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;generatedClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="s"&gt;@"    }
}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Astuces bonus
&lt;/h2&gt;

&lt;p&gt;Le code généré n'est pas facilement consultable ni facile à découvrir.&lt;/p&gt;

&lt;p&gt;Il est cependant possible d'expliciter le chemin de sortie des fichiers générés. Cela pose un second problème : si le chemin de la génération n'est pas ignoré, le compilateur va essayer de les compiler en plus de ceux qui sont générés à la volée par le générateur de code. Il faut donc ignorer le dossier de sortie.&lt;/p&gt;

&lt;p&gt;Ces modifications sont à effectuer dans les fichiers projets référençant le générateur de code.&lt;/p&gt;

&lt;p&gt;Pour indiquer le dossier où l'on veut que les fichiers générés soient stockés, il faut ajouter un nœud &lt;code&gt;CompilerGeneratedFilesOutputPath&lt;/code&gt; dans un &lt;code&gt;PropertyGroup&lt;/code&gt; (celui par défaut contenant les frameworks cibles fonctionne parfaitement).&lt;/p&gt;

&lt;p&gt;La valeur du nœud indique le chemin de sortie&lt;/p&gt;

&lt;p&gt;Exemple :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFrameworks&amp;gt;&lt;/span&gt;net5.0;netstandard2.1&lt;span class="nt"&gt;&amp;lt;/TargetFrameworks&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;GeneratePackageOnBuild&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/GeneratePackageOnBuild&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;EmitCompilerGeneratedFiles&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/EmitCompilerGeneratedFiles&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;CompilerGeneratedFilesOutputPath&amp;gt;&lt;/span&gt;Generated&lt;span class="nt"&gt;&amp;lt;/CompilerGeneratedFilesOutputPath&amp;gt;&lt;/span&gt;&lt;span class="c"&gt;&amp;lt;!--Ajouter cette ligne--&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pour la seconde partie du problème, ignorer ce dossier de sortie, il faut ajouter une ligne indiquant que tous les fichiers contenus dans ce dossier ne font pas partie de la compilation.&lt;/p&gt;

&lt;p&gt;Il s'agit d'un classique nœud &lt;code&gt;None&lt;/code&gt;, dans un &lt;code&gt;ItemGroup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Il suffit donc de rajouter l'extrait XML suivant dans le fichier &lt;code&gt;csproj&lt;/code&gt; pour ignorer tous les fichiers présents dans le dossier de sortie :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;None&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Generated\**"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pour aller plus loin
&lt;/h2&gt;

&lt;p&gt;Un autre exemple de générateur de codes utile serait pour la génération de tests unitaires qui peuvent être nécessaires mais extrêmement répétitifs (si votre politique de TU vous demande de tester les accesseurs par exemple). Un très bon article (en anglais) de Jonathan Allen indique comment mettre en place une telle solution : &lt;a href="https://www.infoq.com/articles/CSharp-Source-Generator/" rel="noopener noreferrer"&gt;"&lt;em&gt;Building a Source Generator for C#&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>csharp</category>
    </item>
    <item>
      <title>Pair Programming : Programmer à plusieurs et à distance</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Wed, 02 Jun 2021 15:37:00 +0000</pubDate>
      <link>https://dev.to/younup/pair-programming-programmer-a-plusieurs-et-a-distance-56i5</link>
      <guid>https://dev.to/younup/pair-programming-programmer-a-plusieurs-et-a-distance-56i5</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/OZbrkgsjHps"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>programming</category>
      <category>vscode</category>
      <category>pairprogramming</category>
      <category>liveshare</category>
    </item>
    <item>
      <title>Event Storming : Modéliser son domaine métier</title>
      <dc:creator>Younup</dc:creator>
      <pubDate>Thu, 15 Apr 2021 07:24:52 +0000</pubDate>
      <link>https://dev.to/younup/event-storming-modeliser-son-domaine-metier-254e</link>
      <guid>https://dev.to/younup/event-storming-modeliser-son-domaine-metier-254e</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/0-ppfFuGB-I"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>agile</category>
      <category>eventstorming</category>
      <category>domaindrivendesign</category>
    </item>
  </channel>
</rss>
