<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[Code-Garage]]></title>
        <description><![CDATA[Code-Garage]]></description>
        <link>https://code-garage.com</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Fri, 26 Jun 2026 03:10:12 GMT</lastBuildDate>
        <atom:link href="https://code-garage.com/blog/rss" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Générer un App Password pour utiliser Gmail en IMAP/SMTP ]]></title>
            <description><![CDATA[Découvrez comment utiliser une adresse Gmail avec IMAP et SMTP grâce aux App Passwords de Google. Une solution simple pour connecter Gmail à vos applications, serveurs et outils d'envoi d'emails.]]></description>
            <link>https://code-garage.com/blog/generer-un-app-password-pour-utiliser-gmail-en-imap-smtp</link>
            <guid isPermaLink="true">https://code-garage.com/blog/generer-un-app-password-pour-utiliser-gmail-en-imap-smtp</guid>
            <category><![CDATA[Email]]></category>
            <category><![CDATA[Google]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 23 Jun 2026 08:29:07 GMT</pubDate>
            <content:encoded><![CDATA[<p>Lorsque vous développez <strong>une application qui doit envoyer ou recevoir des emails</strong>, une idée assez naturelle consiste à utiliser directement une adresse Gmail pour faire des tests.</p>
<p>Pendant longtemps, il suffisait d'utiliser son adresse email et son mot de passe. <strong>Mais aujourd'hui, cette méthode ne fonctionne plus.</strong></p>
<blockquote>
<p>Google <strong>bloque désormais l'accès aux comptes Gmail</strong> depuis la plupart des applications utilisant simplement un mot de passe classique.</p>
</blockquote>
<p>Heureusement, Google propose une solution : les <strong>App Passwords</strong>, ou mots de passe d'application.</p>
<h2>Qu'est-ce qu'un App Password ?</h2>
<p>Un App Password est <strong>un mot de passe généré par Google</strong> spécialement pour une application.</p>
<p>Contrairement à votre mot de passe principal :</p>
<ul>
<li>il est limité à un <strong>usage précis</strong></li>
<li>il peut être <strong>révoqué à tout moment</strong></li>
<li>il n'autorise <strong>pas l'accès complet</strong> à votre compte Google</li>
</ul>
<blockquote>
<p>L'idée est de permettre à une application de se connecter à Gmail sans lui donner votre véritable mot de passe.</p>
</blockquote>
<h2>Générer un App Password</h2>
<h3>Activer l'authentification à deux facteurs</h3>
<p>Avant de pouvoir créer un App Password, vous devez activer la validation en deux étapes sur votre compte Google.</p>
<p>Rendez-vous dans les paramètres de sécurité de votre compte Google puis <strong>activez l'authentification à deux facteurs.</strong></p>
<blockquote>
<p>Sans cette étape, le menu des App Passwords <strong>n'apparaîtra pas.</strong></p>
</blockquote>
<h3>Créer un mot de passe</h3>
<p>Une fois l'authentification à deux facteurs activée :</p>
<ul>
<li>ouvrez les <strong>paramètres de sécurité Google</strong></li>
<li>recherchez la section &quot;<strong>Mots de passe des applications</strong>&quot;</li>
<li>créez un nouveau mot de passe</li>
<li>choisissez un nom comme &quot;Serveur SMTP&quot; ou &quot;Application NodeJS&quot;</li>
</ul>
<blockquote>
<p>Vous pouvez aussi cliquer sur le <strong>lien direct</strong> : https://myaccount.google.com/apppasswords</p>
</blockquote>
<p>Google génère alors une chaîne ressemblant à ceci :</p>
<pre><code>abcd efgh ijkl mnop
</code></pre>
<blockquote>
<p>C'est ce mot de passe qu'il faudra utiliser dans votre application.</p>
</blockquote>
<h2>Utiliser votre App Password</h2>
<h3>Configuration SMTP</h3>
<p>Pour envoyer des emails avec Gmail, utilisez les paramètres suivants :</p>
<pre><code>Serveur SMTP : smtp.gmail.com
Port : 587
Sécurité : TLS / STARTTLS
Utilisateur : &lt;votre-adresse@gmail.com&gt;
Mot de passe : &lt;votre_app_password&gt;
</code></pre>
<h3>Configuration IMAP</h3>
<p>Si vous souhaitez recevoir ou lire des emails, vous devrez utiliser IMAP.</p>
<p>Les paramètres sont les suivants :</p>
<pre><code>Serveur IMAP : imap.gmail.com
Port : 993
Sécurité : SSL/TLS
Utilisateur : votre-adresse@gmail.com
Mot de passe : &lt;votre_app_password&gt;
</code></pre>
<h2>Les limites de Gmail</h2>
<p>Même si Gmail fonctionne très bien pour des tests ou de petits projets, il ne remplace pas un véritable service d'envoi transactionnel.</p>
<p>Google applique notamment :</p>
<ul>
<li>des limites d'envoi quotidiennes</li>
<li>des contrôles anti-spam</li>
<li>des restrictions sur certains usages automatisés</li>
</ul>
<blockquote>
<p>Pour un projet professionnel ou une application à fort volume, des solutions comme Brevo (français), Resend, Mailgun ou SendGrid seront généralement plus adaptées.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_22_juin_2026_14_07_22_b54d98bf3f.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Interagir avec une boîte mail en Node.js avec ImapFlow et MailParser]]></title>
            <description><![CDATA[Découvrez comment lire et traiter les emails d’une boîte mail en Node.js avec ImapFlow et MailParser, en utilisant IMAP pour récupérer les messages.]]></description>
            <link>https://code-garage.com/blog/interagir-avec-une boite-mail-en-nodejs-avec-imapflow-et-mailparser</link>
            <guid isPermaLink="true">https://code-garage.com/blog/interagir-avec-une boite-mail-en-nodejs-avec-imapflow-et-mailparser</guid>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[Email]]></category>
            <category><![CDATA[IMAP]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Mon, 15 Jun 2026 07:46:04 GMT</pubDate>
            <content:encoded><![CDATA[<p>Envoyer des emails avec Node.js, c’est très simple avec des outils <strong>comme Nodemailer !</strong></p>
<blockquote>
<p><a href="https://code-garage.com/blog/tutoriel-comment-bien-envoyer-vos-emails-en-html-css-avec-nodejs">Notre article dédié</a> pour l’envoi d’email en Node.js</p>
</blockquote>
<p>Mais il existe aussi beaucoup de cas où l’on veut faire l’inverse : <strong>lire les emails reçus</strong>.</p>
<p>Par exemple, pour <strong>traiter automatiquement des demandes entrantes, récupérer des pièces jointes</strong>, analyser des réponses clients, ou déclencher une action lorsqu’un message arrive dans une boîte spécifique.</p>
<p>Pour cela, on utilise généralement un protocol dédié : <strong>IMAP (Internet Message Access Protocol).</strong></p>
<blockquote>
<p>IMAP permet à une application de se connecter à une boîte mail pour <strong>lire, parcourir et manipuler les messages.</strong></p>
</blockquote>
<p>En Node.js, deux bibliothèques sont particulièrement pratiques pour ce besoin : <code>ImapFlow</code> et <code>MailParser</code>.</p>
<p>ImapFlow est un client IMAP moderne pour Node.js, avec une API basée sur les Promises et <code>async/await</code> (<a href="https://imapflow.com/docs/">documentation officielle</a>).</p>
<p>MailParser, de son côté, permet de transformer un email brut en objet JavaScript exploitable. Sa fonction <code>simpleParser</code> est pratique pour les cas simples, tandis que la classe <code>MailParser</code> permet de traiter les gros messages sous forme de streams (<a href="https://nodemailer.com/extras/mailparser">documentation officielle</a>).</p>
<h2>Fonctionnement</h2>
<h3>Installer les dépendances</h3>
<p>On commence par installer les deux packages :</p>
<pre><code class="language-bash">npm install imapflow mailparser
</code></pre>
<p>Si vous utilisez TypeScript, ImapFlow fournit déjà ses propres types. Pour MailParser, vous pouvez ajouter :</p>
<pre><code class="language-bash">npm install -D @types/mailparser
</code></pre>
<h3>Se connecter à une boîte mail</h3>
<p>Voici un exemple avec Gmail, mais le principe est le même avec n’importe quel serveur IMAP.</p>
<pre><code class="language-jsx">import { ImapFlow } from &quot;imapflow&quot;;

const client = new ImapFlow({
  host: &quot;imap.gmail.com&quot;,
  port: 993,
  secure: true,
  auth: {
    user: &quot;votre-adresse@gmail.com&quot;,
    pass: &quot;votre-app-password&quot;,
  },
});

await client.connect();
</code></pre>
<p>Pour Gmail, il ne faut pas utiliser votre mot de passe principal.</p>
<blockquote>
<p>Il faut générer un App Password depuis votre compte Google, puis l’utiliser comme mot de passe IMAP.</p>
</blockquote>
<h3>Lire les derniers emails</h3>
<p>Une fois connecté, il faut ouvrir une boîte. La plus courante est <code>INBOX</code>.</p>
<pre><code class="language-jsx">const lock = await client.getMailboxLock(&quot;INBOX&quot;);

try {
  for await (const message of client.fetch(&quot;1:*&quot;, {
    envelope: true,
    source: true,
  })) {
    console.log(message.envelope.subject);
  }
} finally {
  lock.release();
}
</code></pre>
<p>Le <code>lock</code> évite que plusieurs opérations entrent en conflit sur la même boîte.</p>
<blockquote>
<p>C’est une bonne habitude avec ImapFlow : on verrouille, on travaille, puis on libère.</p>
</blockquote>
<p>Ici, <code>source: true</code> permet de récupérer l’email brut. C’est ce contenu que nous allons ensuite donner à MailParser.</p>
<h3>Parser un email avec MailParser</h3>
<p>Un email n’est pas un simple texte. Il peut contenir du HTML, du texte brut, des pièces jointes, des encodages différents, des headers, des destinataires, etc.</p>
<p>MailParser s’occupe de transformer tout cela en objet plus facile à manipuler :</p>
<pre><code class="language-jsx">import { simpleParser } from &quot;mailparser&quot;;

for await (const message of client.fetch(&quot;1:*&quot;, {
  envelope: true,
  source: true,
})) {
  const parsed = await simpleParser(message.source);

  console.log({
    subject: parsed.subject,
    from: parsed.from?.text,
    text: parsed.text,
    html: parsed.html,
  });
}
</code></pre>
<blockquote>
<p><code>simpleParser</code> charge le message en mémoire.</p>
</blockquote>
<p>C’est très pratique pour démarrer, mais si vous traitez de gros emails ou beaucoup de pièces jointes, il faudra plutôt utiliser l’API en streaming de MailParser.</p>
<h3>Lire uniquement les emails non lus</h3>
<p>Dans la vraie vie, vous ne voulez pas relire toute la boîte à chaque exécution.</p>
<p>Vous pouvez chercher uniquement les emails non lus :</p>
<pre><code class="language-jsx">for await (const message of client.fetch(
  { seen: false },
  { envelope: true, source: true }
)) {
  const parsed = await simpleParser(message.source);

  console.log(parsed.subject);
}
</code></pre>
<p>Ensuite, vous pouvez marquer le message comme lu :</p>
<pre><code class="language-jsx">await client.messageFlagsAdd(message.uid, [&quot;\\Seen&quot;], { uid: true });
</code></pre>
<blockquote>
<p>Cela permet de construire facilement un petit worker qui <strong>traite seulement les nouveaux emails.</strong></p>
</blockquote>
<h3>Exemple complet</h3>
<pre><code class="language-jsx">import { ImapFlow } from &quot;imapflow&quot;;
import { simpleParser } from &quot;mailparser&quot;;

const client = new ImapFlow({
  host: &quot;imap.gmail.com&quot;,
  port: 993,
  secure: true,
  auth: {
    user: process.env.MAIL_USER,
    pass: process.env.MAIL_PASSWORD,
  },
});

await client.connect();

const lock = await client.getMailboxLock(&quot;INBOX&quot;);

try {
  for await (const message of client.fetch(
    { seen: false },
    { uid: true, source: true }
  )) {
    const parsed = await simpleParser(message.source);

    console.log(&quot;Sujet :&quot;, parsed.subject);
    console.log(&quot;De :&quot;, parsed.from?.text);
    console.log(&quot;Texte :&quot;, parsed.text);

    await client.messageFlagsAdd(message.uid, [&quot;\\Seen&quot;], { uid: true });
  }
} finally {
  lock.release();
  await client.logout();
}
</code></pre>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_15_juin_2026_08_58_04_f06146f568.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Découvrir VueUse : la boîte à outils indispensable pour Vue.js]]></title>
            <description><![CDATA[Découvrez VueUse, une collection de composables ultra pratiques pour Vue.js. Géolocalisation, presse-papiers, gamepads, état du réseau… gagnez du temps avec useClipboard, useGeolocation, useNetwork et useGamepad.]]></description>
            <link>https://code-garage.com/blog/decouvrir-vueuse-la-boite-a-outils-indispensable-pour-vuejs</link>
            <guid isPermaLink="true">https://code-garage.com/blog/decouvrir-vueuse-la-boite-a-outils-indispensable-pour-vuejs</guid>
            <category><![CDATA[VueJS]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 26 May 2026 15:15:39 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand on développe une application Vue, on finit souvent par réécrire les mêmes choses :</p>
<ul>
<li>écouter des évènements du navigateur</li>
<li>gérer des états réactifs</li>
<li>accéder aux APIs Web</li>
<li>nettoyer des listeners</li>
</ul>
<blockquote>
<p>C’est précisément le problème que résout VueUse.</p>
</blockquote>
<h2>Une bibliothèque de composables</h2>
<p>VueUse est une immense bibliothèque de composables prêts à l’emploi pour Vue.js.</p>
<p>Elle propose des centaines d’utilitaires pour :</p>
<ul>
<li>le navigateur</li>
<li>les animations</li>
<li>les capteurs</li>
<li>les raccourcis clavier</li>
<li>le stockage local</li>
<li>les APIs Web modernes</li>
</ul>
<p>Et surtout tous les utilitaires sont pensés pour fonctionner naturellement avec la réactivité de Vue.</p>
<p>L’installation est très simple :</p>
<pre><code class="language-bash">npm install @vueuse/core
</code></pre>
<blockquote>
<p>Ensuite, vous pouvez importer uniquement les composables dont vous avez besoin.</p>
</blockquote>
<h3>Copier du texte avec useClipboard</h3>
<p>L’API du presse-papiers du navigateur peut être un peu pénible à utiliser directement.</p>
<p>VueUse simplifie énormément cela avec <code>useClipboard</code>.</p>
<pre><code class="language-tsx">import { useClipboard } from &quot;@vueuse/core&quot;

const { copy, copied } = useClipboard()

const copyCode = async () =&gt; {
  await copy(&quot;Hello world&quot;)
}
</code></pre>
<p>Le booléen <code>copied</code> devient automatiquement <code>true</code> pendant quelques secondes après la copie.</p>
<p>Parfait pour afficher un message :</p>
<pre><code class="language-html">&lt;p v-if=&quot;copied&quot;&gt;Texte copié !&lt;/p&gt;
</code></pre>
<p>C’est idéal pour :</p>
<ul>
<li>des boutons “Copier”</li>
<li>des snippets de code</li>
<li>des liens de partage</li>
<li>des tokens API</li>
</ul>
<h3>Récupérer la position GPS avec useGeolocation</h3>
<p>VueUse propose aussi un accès très simple à la géolocalisation du navigateur.</p>
<pre><code class="language-tsx">import { useGeolocation } from &quot;@vueuse/core&quot;

const { coords, locatedAt, error } = useGeolocation()
</code></pre>
<p>Les coordonnées deviennent automatiquement réactives :</p>
<pre><code class="language-html">&lt;p&gt;Latitude : {{ coords.latitude }}&lt;/p&gt;
&lt;p&gt;Longitude : {{ coords.longitude }}&lt;/p&gt;
</code></pre>
<p>C’est particulièrement utile pour :</p>
<ul>
<li>une carte interactive</li>
<li>une application météo</li>
<li>du contenu localisé</li>
<li>du suivi de position</li>
</ul>
<p>Et contrairement à une implémentation manuelle, VueUse gère déjà :</p>
<ul>
<li>les listeners</li>
<li>la réactivité</li>
<li>le nettoyage automatique</li>
</ul>
<h3>Détecter l’état du réseau avec useNetwork</h3>
<p>Savoir si un utilisateur est hors ligne peut améliorer énormément l’expérience utilisateur.</p>
<p>Avec <code>useNetwork</code> :</p>
<pre><code class="language-tsx">import { useNetwork } from &quot;@vueuse/core&quot;

const { isOnline, downlink, effectiveType } = useNetwork()
</code></pre>
<p>Vous pouvez facilement afficher un message :</p>
<pre><code class="language-html">&lt;p v-if=&quot;!isOnline&quot;&gt;
  Vous êtes actuellement hors ligne.
&lt;/p&gt;
</code></pre>
<p>Mais aussi adapter l’application selon la qualité du réseau.</p>
<p>Par exemple :</p>
<ul>
<li>réduire la qualité des images</li>
<li>désactiver certaines animations</li>
<li>éviter des requêtes lourdes</li>
</ul>
<h3>Utiliser une manette avec useGamepad</h3>
<p>C’est probablement l’un des composables les plus amusants.</p>
<p><code>useGamepad</code> permet d’accéder aux manettes connectées au navigateur.</p>
<pre><code class="language-tsx">import { useGamepad } from &quot;@vueuse/core&quot;

const { gamepads } = useGamepad()
</code></pre>
<p>Vous pouvez ensuite lire les boutons et axes :</p>
<pre><code class="language-html">&lt;pre&gt;{{ gamepads }}&lt;/pre&gt;
</code></pre>
<p>Cela ouvre la porte à énormément de projets :</p>
<ul>
<li>mini jeux Vue.js</li>
<li>interfaces interactives</li>
<li>bornes tactiles</li>
<li>contrôles alternatifs</li>
</ul>
<blockquote>
<p>Et tout cela avec très peu de code.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_22_mai_2026_11_47_28_6b049842fe.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Utiliser npm link pour tester un module localement]]></title>
            <description><![CDATA[Découvrez comment utiliser la commande npm link pour développer et tester un module NPM localement sans avoir à le publier à chaque modification.]]></description>
            <link>https://code-garage.com/blog/utiliser-npm-link-pour-tester-un-module-localement</link>
            <guid isPermaLink="true">https://code-garage.com/blog/utiliser-npm-link-pour-tester-un-module-localement</guid>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[NPM]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Sun, 17 May 2026 16:18:20 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand on <strong>développe un package NPM</strong>, il y a un problème très vite frustrant :</p>
<p>À chaque modification du module, il faudrait normalement :</p>
<ul>
<li>publier une nouvelle version</li>
<li>réinstaller le package dans le projet de test</li>
<li>relancer l’application</li>
</ul>
<blockquote>
<p>Heureusement, <code>npm link</code> existe justement pour éviter ça.</p>
</blockquote>
<h2>Fonctionnement</h2>
<p>Cette commande permet de <strong>créer un lien symbolique</strong> entre un package local et un autre projet.</p>
<blockquote>
<p>Autrement dit : votre projet utilise <strong>directement le code source local du module</strong>, comme s’il avait été installé depuis NPM.</p>
</blockquote>
<p>Le fonctionnement se fait en deux étapes. D’abord, dans le dossier du <strong>paquet NPM</strong> :</p>
<pre><code class="language-bash">npm link
</code></pre>
<blockquote>
<p>Cette commande enregistre le package globalement sur votre machine.</p>
</blockquote>
<p>Ensuite, dans le projet qui doit <strong>utiliser ce package</strong> :</p>
<pre><code class="language-bash">npm link nom-du-package
</code></pre>
<blockquote>
<p>À partir de ce moment-là, le dossier <code>node_modules</code> du projet pointera directement vers votre module local.</p>
</blockquote>
<h3>Un lien symbolique</h3>
<p>Le gros avantage, c’est que les modifications deviennent quasiment instantanées. Vous changez du code dans votre package… et <strong>votre projet de test utilise immédiatement la nouvelle version.</strong></p>
<p>Plus besoin de publier une version <code>0.0.1-dev-test-42</code>.</p>
<blockquote>
<p>Sous le capot, <code>npm link</code> utilise des liens symboliques (<code>symlink</code>) du système d’exploitation.</p>
</blockquote>
<h3>Un exemple concret</h3>
<p>Voici un exemple pour bien comprendre <strong>la marche à suivre</strong>. Vous avez deux projets :</p>
<pre><code>mon-package/
mon-app/
</code></pre>
<p>!!! well
Dans <code>mon-package</code> :</p>
<pre><code class="language-bash">npm link
</code></pre>
<p>!!!
!!! well
Puis dans <code>mon-app</code> :</p>
<pre><code class="language-bash">npm link mon-package
</code></pre>
<p>!!!</p>
<blockquote>
<p>Et voilà. Votre application utilise maintenant directement <strong>la version locale du package.</strong></p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/bas_van_den_eijkhof_a_Jf_Ou_We_Nzko_unsplash_fa60b1506d.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Qu’est-ce qu’un ADR (Architecture Decision Record) ?]]></title>
            <description><![CDATA[Découvrez ce qu’est un ADR (Architecture Decision Record), pourquoi il est utile dans un projet logiciel et comment documenter vos décisions techniques simplement.]]></description>
            <link>https://code-garage.com/blog/qu-est-ce-qu-un-adr-architecture-decision-record</link>
            <guid isPermaLink="true">https://code-garage.com/blog/qu-est-ce-qu-un-adr-architecture-decision-record</guid>
            <category><![CDATA[Documentation]]></category>
            <category><![CDATA[Architecture Logicielle]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Thu, 07 May 2026 07:37:03 GMT</pubDate>
            <content:encoded><![CDATA[<p>Dans beaucoup de projets, certaines décisions techniques <strong>finissent par devenir… mystérieuses.</strong></p>
<ul>
<li>Pourquoi ce framework a été choisi ?</li>
<li>Pourquoi ce calcul fonctionne de cette manière ?</li>
<li>Pourquoi utilise-t-on Redis ici, mais pas ailleurs ?</li>
</ul>
<p>Le problème, c’est qu’avec le temps, les développeurs changent, les discussions Slack disparaissent, et <strong>les décisions prises plusieurs mois auparavant deviennent difficiles à comprendre.</strong></p>
<blockquote>
<p>C’est précisément le rôle des ADR, pour <strong>Archicture Decision Record.</strong></p>
</blockquote>
<h2><strong>Architecture Decision Record</strong></h2>
<p>Un ADR est un document très simple qui sert à conserver <strong>une trace d’une décision technique</strong> importante dans un projet.</p>
<p>L’idée n’est pas de rédiger une énorme documentation, au contraire :</p>
<blockquote>
<p>Un ADR est généralement <strong>court, simple et centré sur une seule décision.</strong></p>
</blockquote>
<p>L’objectif est surtout de répondre à une question essentielle : <strong>Pourquoi cette décision a-t-elle été prise ?</strong></p>
<p>Un ADR contient souvent :</p>
<ul>
<li>le contexte ⇒ explique le problème rencontré.</li>
<li>la décision ⇒ décrit le choix effectué.</li>
<li>les conséquences ⇒ détaillent les avantages, limites ou compromis associés.</li>
</ul>
<p>Voici un exemple très simplifié :</p>
<pre><code class="language-markdown"># ADR-001 : Utilisation de PostgreSQL

## Context
Le projet nécessite des relations complexes entre les données.

## Decision
Utiliser PostgreSQL comme base principale.

## Consequences
- SQL puissant
- bonnes performances relationnelles
- infrastructure plus lourde qu’une base NoSQL
</code></pre>
<blockquote>
<p>Ce type de document peut sembler anodin… mais il devient extrêmement précieux avec le temps.</p>
</blockquote>
<h2>Pourquoi mettre en place des ADR ?</h2>
<p>Sans ADR, beaucoup de projets finissent <strong>avec des décisions “historiques”</strong> que plus personne ne comprend vraiment.</p>
<p>Et cela crée souvent des problèmes :</p>
<ul>
<li>duplication de solutions</li>
<li>remise en question permanente</li>
<li>peur de modifier certaines parties du projet</li>
<li>onboarding plus difficile</li>
</ul>
<blockquote>
<p>Et surtout cela rend encore plus <strong>critique le fameux “<a href="https://code-garage.com/blog/qu-est-ce-que-le-bus-factor-gestion-de-projet/">bus factor</a>”</strong></p>
</blockquote>
<p>Mettre en place des ADR est particulièrement utile dans :</p>
<ul>
<li>les projets longs</li>
<li>les équipes qui grandissent</li>
<li>les architectures complexes</li>
<li>les projets open source</li>
</ul>
<blockquote>
<p>La bonne nouvelle, c’est qu’<strong>on peut commencer, dès aujourd’hui, sans aucun outils</strong></p>
</blockquote>
<p>Beaucoup d’équipes stockent simplement leurs ADR dans un dossier :</p>
<pre><code>/docs/adr
</code></pre>
<p>Ou directement :</p>
<pre><code>/adr
</code></pre>
<blockquote>
<p>Le plus important n’est pas le format, mais de <strong>commencer à documenter le plus tôt possible.</strong></p>
</blockquote>
<p>Parce qu’en architecture logicielle, le problème n’est pas seulement de prendre de bonnes décisions. <strong>C’est aussi de comprendre, plusieurs années plus tard, pourquoi elles ont été prises.</strong></p>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/bruno_fernandes_a_Izs0_Pp_VXY_unsplash_25dea52ff8.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[La différence entre RUN et CMD avec Docker]]></title>
            <description><![CDATA[Découvrez la différence entre RUN et CMD dans Docker, leur rôle dans un Dockerfile et comment éviter les erreurs courantes.]]></description>
            <link>https://code-garage.com/blog/la-difference-entre-run-et-cmd-avec-docker</link>
            <guid isPermaLink="true">https://code-garage.com/blog/la-difference-entre-run-et-cmd-avec-docker</guid>
            <category><![CDATA[Docker]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 31 Mar 2026 14:43:51 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand vous écrivez votre premier Dockerfile, les instructions <code>RUN</code> et <code>CMD</code> qui prêtent souvent à confusion.</p>
<blockquote>
<p>Elles peuvent sembler similaires… mais elles n’ont <strong>absolument pas le même rôle</strong>.</p>
</blockquote>
<p>À noter que <strong>si vous ne connaissez pas Docker</strong>, cet article ne vous sera pas très utile, mais vous pouvez toujours aller écouter notre introduction à Docker dans <a href="https://code-garage.com/podcast/classic/episode-145">un épisode dédié du podcast</a> !</p>
<h2>La commande RUN</h2>
<p><code>RUN</code> est utilisé <strong>lors de la construction de l’image Docker</strong>.</p>
<p>Par exemple :</p>
<pre><code class="language-docker">RUN apt-get update &amp;&amp; apt-get install -y curl
</code></pre>
<p>Cette commande est exécutée :</p>
<ul>
<li>pendant le <code>docker build</code></li>
<li>pour modifier l’image</li>
</ul>
<blockquote>
<p><code>RUN</code> sert à <strong>préparer l’image.</strong></p>
</blockquote>
<p>Chaque instruction <code>RUN</code> crée une nouvelle couche dans l’image Docker.</p>
<p>Typiquement, vous utilisez <code>RUN</code> pour :</p>
<ul>
<li>installer des dépendances</li>
<li>copier ou générer des fichiers</li>
<li>configurer l’environnement</li>
</ul>
<h2>La commande CMD</h2>
<p><code>CMD</code> est utilisée <strong>lors du lancement du conteneur</strong>.</p>
<p>Par exemple :</p>
<pre><code class="language-docker">CMD [&quot;node&quot;, &quot;server.js&quot;]
</code></pre>
<p>Cette commande est exécutée :</p>
<ul>
<li>quand vous faites <code>docker run</code></li>
<li>au démarrage du conteneur</li>
</ul>
<blockquote>
<p><code>CMD</code> sert à dire : “voilà ce que fait ce conteneur quand il démarre”.</p>
</blockquote>
<h2>La différence clé</h2>
<p>La différence principale tient en une phrase :  <code>RUN</code> s’exécute <strong>pendant le build</strong> tandis que <code>CMD</code> s’exécute <strong>au runtime</strong>.</p>
<p>Autrement dit :</p>
<ul>
<li><code>RUN</code> modifie l’image</li>
<li><code>CMD</code> définit le comportement du conteneur</li>
</ul>
<h3>Un exemple concret</h3>
<p>Prenons un Dockerfile simple :</p>
<pre><code class="language-docker">FROM node:18
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .

CMD [&quot;node&quot;, &quot;index.js&quot;]
</code></pre>
<p>Ce qu’il se passe :</p>
<ol>
<li><code>RUN npm install</code> installe les dépendances <strong>dans l’image</strong></li>
<li><code>CMD [&quot;node&quot;, &quot;index.js&quot;]</code> lance l’application <strong>au démarrage</strong></li>
</ol>
<blockquote>
<p>Sans <code>CMD</code>, le conteneur ne ferait rien.</p>
</blockquote>
<h2>Pour aller plus loin</h2>
<h3>CMD peut être remplacé</h3>
<p>Par exemple :</p>
<pre><code class="language-bash">docker run mon-image echo &quot;Hello&quot;
</code></pre>
<p>Ici :</p>
<ul>
<li><code>CMD</code> est ignoré</li>
<li>la commande <code>echo &quot;Hello&quot;</code> est exécutée</li>
</ul>
<blockquote>
<p><code>CMD</code> est une valeur par défaut.</p>
</blockquote>
<h3>Le système de couches (layers)</h3>
<p>Chaque <code>RUN</code> ajoute une couche à votre image.</p>
<p>Par exemple :</p>
<pre><code class="language-docker">RUN apt-get update
RUN apt-get install -y curl
</code></pre>
<blockquote>
<p>Crée deux couches.</p>
</blockquote>
<p>Les différentes couches sont utilisées par Docker pour optimiser la mémoire utilisée par les images, car <strong>les couches similaires sont partagées entre les différents conteneurs !</strong></p>
<h2>Résumé de l'article</h2>
<p><code>RUN</code> et <code>CMD</code> sont complémentaires.</p>
<ul>
<li>utilisez <code>RUN</code> pour construire votre environnement (exécuté pendant le build)</li>
<li>utilisez <code>CMD</code> pour lancer votre application (exécuté au runtime)</li>
</ul>
<blockquote>
<p>Si vous les confondez, votre conteneur ne fera probablement pas ce que vous attendez.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_pixel_art_scene_of_a_bakery_kitchen_where_3880f6c2_e944_4407_b1c9_8894f91a32c5_9435666357.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Git : comment supprimer tous les fichiers en dehors de l’historique]]></title>
            <description><![CDATA[Découvrez comment supprimer les fichiers non suivis par Git après un git reset, avec git clean, les bonnes options et les précautions à connaître.]]></description>
            <link>https://code-garage.com/blog/git-comment-supprimer-tous-les-fichiers-en-dehors-de-l-historique</link>
            <guid isPermaLink="true">https://code-garage.com/blog/git-comment-supprimer-tous-les-fichiers-en-dehors-de-l-historique</guid>
            <category><![CDATA[Git]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Thu, 26 Mar 2026 09:57:15 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand on utilise Git, il y a une situation assez classique qui finit toujours par arriver.</p>
<blockquote>
<p>un <code>git reset</code>.</p>
</blockquote>
<p>Vous revenez en arrière, vous changez d’état, vous annulez un commit ou vous bougez votre branche… et là, en regardant votre projet, <strong>vous vous retrouvez avec plein de fichiers qui traînent.</strong></p>
<p>Parfois ce sont :</p>
<ul>
<li>des fichiers générés</li>
<li>des dossiers de build</li>
<li>des fichiers temporaires</li>
<li>des morceaux d’un ancien état du projet</li>
</ul>
<blockquote>
<p>Et dans <code>git status</code>, vous voyez apparaître <strong>une longue liste de fichiers “nouveaux”</strong>.</p>
</blockquote>
<p>Git ne les a pas supprimés, parce qu’ils ne font pas partie des fichiers suivis à cet instant. <strong>Mais si vous souhaitez vous en débarasser</strong> (autrement qu’en supprimant tout à la main), voilà comment faire !</p>
<h2>La bonne commande : git clean</h2>
<p>Pour supprimer les fichiers non suivis, Git propose cette commande :</p>
<pre><code class="language-bash">git clean -f
</code></pre>
<p>Cette commande supprime les fichiers non suivis du dossier courant.</p>
<p>Mais attention :</p>
<blockquote>
<p><code>git clean</code> est une commande destructive.</p>
<p>Une fois les fichiers supprimés, Git ne pourra pas les restaurer.</p>
</blockquote>
<h2>Le mode simulation</h2>
<p>Avant de lancer une suppression, le bon réflexe est d’utiliser :</p>
<pre><code class="language-bash">git clean -n
</code></pre>
<blockquote>
<p>Le <code>-n</code> signifie <em><strong>dry run</strong></em>. C’est probablement l’option la plus importante de toute la commande.</p>
</blockquote>
<p>Git affiche ce qu’il supprimerait, sans réellement le faire. Si vous avez beaucoup de fichiers apparus après un <code>git reset</code>, <strong>commencez toujours par là.</strong></p>
<h2>Supprimer les dossiers</h2>
<p>Par défaut, <code>git clean</code> ne supprime pas les dossiers non suivis.</p>
<p>Or après un reset, ce sont souvent justement des dossiers entiers qui traînent :</p>
<ul>
<li><code>dist/</code></li>
<li><code>build/</code></li>
<li><code>.cache/</code></li>
<li>anciens dossiers générés</li>
</ul>
<p>Pour inclure les dossiers, utilisez :</p>
<pre><code class="language-bash">git clean -fd
</code></pre>
<ul>
<li><code>f</code> pour forcer</li>
<li><code>d</code> pour inclure les répertoires</li>
</ul>
<blockquote>
<p>Dans beaucoup de cas, après un <code>git reset</code>, c’est cette commande qu’on cherche vraiment.</p>
</blockquote>
<h2>Inclure les fichiers ignorés par .gitignore</h2>
<p>Il y a un autre cas fréquent.</p>
<p>Vous faites un reset, puis vous voulez repartir d’un projet vraiment propre.</p>
<p>Mais certains fichiers sont ignorés par Git via <code>.gitignore</code> :</p>
<ul>
<li>dossiers de build</li>
<li>fichiers d’environnement</li>
<li>caches</li>
<li>dépendances générées</li>
</ul>
<p>Par défaut, <code>git clean</code> ne les supprime pas.</p>
<p>Si vous voulez aussi supprimer ces fichiers ignorés, il faut utiliser :</p>
<pre><code class="language-bash">git clean -fdx
</code></pre>
<p>Cette commande supprime :</p>
<ul>
<li>les fichiers non suivis</li>
<li>les dossiers non suivis</li>
<li>les fichiers ignorés par <code>.gitignore</code></li>
</ul>
<blockquote>
<p>Elle est très utile pour remettre un projet dans <strong>un état vraiment propre.</strong></p>
</blockquote>
<p>Mais elle doit être utilisée <strong>avec une grande prudence.</strong></p>
<h3>Supprimer UNIQUEMENT les fichiers ignorés</h3>
<p>Pour ne supprimer que les fichiers présents dans <code>.gitignore</code> ,on utilise le paramètre <code>-X</code> (à ne pas confondre avec <code>-x</code>) :</p>
<pre><code class="language-bash">git clean -fdX
</code></pre>
<blockquote>
<p>Supprime <strong>uniquement les fichiers ignorés</strong></p>
</blockquote>
<h2>Conclusion</h2>
<p>Retenez surtout ceci :</p>
<ul>
<li><code>git clean -n</code> permet de vérifier avant</li>
<li><code>git clean -fd</code> supprime fichiers + dossiers</li>
<li><code>git clean -fdx</code> fait le ménage complet</li>
</ul>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_pixel_art_scene_of_a_cluttered_room_being_30f18ffc_8d51_4962_85d1_b4d864a4e024_351ab3051d.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Comment ne pas exécuter les scripts tiers avec npm, pnpm et yarn]]></title>
            <description><![CDATA[Découvrez comment utiliser npm install --ignore-scripts pour empêcher l’exécution de scripts dangereux ou inutiles lors de l’installation des dépendances npm.]]></description>
            <link>https://code-garage.com/blog/comment-ne-pas-executer-les-scripts-tiers-avec-npm-pnpm-et-yarn</link>
            <guid isPermaLink="true">https://code-garage.com/blog/comment-ne-pas-executer-les-scripts-tiers-avec-npm-pnpm-et-yarn</guid>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[NPM]]></category>
            <category><![CDATA[PNPM]]></category>
            <category><![CDATA[Yarn]]></category>
            <category><![CDATA[Sécurité]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Tue, 17 Mar 2026 08:50:43 GMT</pubDate>
            <content:encoded><![CDATA[<p>Quand vous installez un projet Node.js, il y a un réflexe très courant :</p>
<pre><code class="language-bash">npm install
</code></pre>
<p>Cette commande semble anodine. Elle télécharge simplement les dépendances listées dans le <code>package.json</code>.</p>
<p>Mais en réalité, <strong>npm peut aussi exécuter du code</strong> pendant l’installation.</p>
<p>Beaucoup de développeurs l’ignorent, mais certains packages contiennent des scripts qui s’exécutent automatiquement lors de l’installation. Et dans certains cas, ces scripts peuvent poser problème : comportements inattendus, téléchargements lourds… ou pire, <strong>scripts malveillants</strong>.</p>
<p>Heureusement, npm propose une option simple pour éviter cela :</p>
<pre><code class="language-bash">npm install --ignore-scripts
</code></pre>
<blockquote>
<p>Cette option empêche npm d’exécuter les scripts définis dans les dépendances.</p>
</blockquote>
<h2>Les scripts exécutés automatiquement par npm</h2>
<p>Dans un <code>package.json</code>, un package peut définir plusieurs scripts.</p>
<p>Par exemple :</p>
<pre><code class="language-json">{
  &quot;scripts&quot;: {
    &quot;postinstall&quot;: &quot;node build.js&quot;
  }
}
</code></pre>
<blockquote>
<p>npm peut exécuter automatiquement certains scripts pendant l’installation.</p>
</blockquote>
<p>Les plus courants sont :</p>
<ul>
<li><code>preinstall</code></li>
<li><code>install</code></li>
<li><code>postinstall</code></li>
<li><code>prepare</code></li>
</ul>
<p>Ces scripts sont souvent utilisés pour compiler du code natif, télécharger des binaires, générer des fichiers nécessaires au package, préparer des assets, etc…</p>
<blockquote>
<p>Le problème, c’est que <strong>npm exécute ces scripts automatiquement</strong>, sans vous demander votre avis.</p>
</blockquote>
<h2>Le risque : exécuter du code sans le savoir</h2>
<p>L’écosystème npm est immense. On compte aujourd’hui <strong>plus de deux millions de packages</strong>.</p>
<blockquote>
<p>Et comme dans tout écosystème ouvert, il arrive que certains packages soient malveillants ou compromis.</p>
</blockquote>
<p>Plusieurs incidents ont déjà eu lieu :</p>
<ul>
<li>des packages abandonnés repris par des acteurs malveillants</li>
<li>des dépendances injectant du code espion</li>
<li>des scripts envoyant des informations système</li>
</ul>
<p>Les scripts <code>postinstall</code> sont particulièrement sensibles, car ils s’exécutent <strong>directement sur votre machine</strong> au moment de l’installation.</p>
<p>Concrètement, un script npm peut :</p>
<ul>
<li>accéder à votre système de fichiers</li>
<li>lire des variables d’environnement</li>
<li>envoyer des données vers Internet</li>
<li>modifier votre configuration</li>
</ul>
<blockquote>
<p>En d’autres termes : <strong>un simple <code>npm install</code> peut exécuter du code arbitraire</strong>.</p>
</blockquote>
<h2>Utiliser ignore-scripts pour garder le contrôle</h2>
<p>Pour éviter cela, npm propose une option très simple :</p>
<pre><code class="language-bash">npm install --ignore-scripts
</code></pre>
<p>Avec cette commande :</p>
<ul>
<li>npm télécharge les dépendances</li>
<li>npm les installe dans <code>node_modules</code></li>
<li><strong>mais aucun script n’est exécuté</strong></li>
</ul>
<p>Cela bloque :</p>
<ul>
<li><code>preinstall</code></li>
<li><code>install</code></li>
<li><code>postinstall</code></li>
<li><code>prepare</code></li>
</ul>
<p>Les packages sont installés <strong>sans exécution de code externe</strong>.</p>
<blockquote>
<p>⚠️ <strong>Attention : <code>--ignore-scripts</code> bloque absolument tous les scripts.</strong></p>
</blockquote>
<p>Il n’est pas possible de désactiver uniquement <code>postinstall</code> ou un script spécifique.</p>
<p>Si vous utilisez cette option, <strong>aucun script lifecycle ne sera exécuté</strong>, quel que soit le package.</p>
<p>Cette option est particulièrement utile dans plusieurs situations :</p>
<ul>
<li>audit de dépendances</li>
<li>analyse d’un projet inconnu</li>
<li>environnement sécurisé</li>
<li>pipeline CI/CD</li>
<li>installation de dépendances non fiables</li>
</ul>
<h2>Équivalent avec pnpm et yarn</h2>
<p>Si vous utilisez un autre gestionnaire de paquets, sachez que <strong>des options similaires existent</strong>.</p>
<h3>pnpm</h3>
<p>pnpm propose exactement la même option :</p>
<pre><code class="language-bash">pnpm install --ignore-scripts
</code></pre>
<blockquote>
<p>Le comportement est identique à npm : les dépendances sont installées mais <strong>aucun script lifecycle n’est exécuté</strong>.</p>
</blockquote>
<h3>Yarn</h3>
<p>Avec Yarn (v1 ou v3), l’option est également disponible :</p>
<pre><code class="language-bash">yarn install --ignore-scripts
</code></pre>
<blockquote>
<p>Comme pour npm et pnpm, cela bloque l’exécution des scripts <code>preinstall</code>, <code>install</code> et <code>postinstall</code>.</p>
</blockquote>
<p>Autrement dit, <strong>les trois principaux gestionnaires de paquets Node.js offrent ce mécanisme de sécurité</strong>.</p>
<h2>Réactiver les scripts si nécessaire</h2>
<p>Si un package a réellement besoin de ses scripts pour fonctionner, vous pouvez les relancer plus tard.</p>
<p>Par exemple :</p>
<pre><code class="language-bash">npm rebuild
</code></pre>
<p>Ou simplement relancer l’installation normalement :</p>
<pre><code class="language-bash">npm install
</code></pre>
<blockquote>
<p>L’avantage est que <strong>vous gardez le contrôle sur ce qui s’exécute sur votre machine</strong>.</p>
</blockquote>
<p>Dans un écosystème aussi vaste que npm, cette petite option peut éviter de nombreux problèmes.</p>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/Chat_GPT_Image_Mar_13_2026_10_48_35_AM_copy_a7e3964495.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Découvrez BullMQ, une MessageQueue simple avec NodeJS]]></title>
            <description><![CDATA[Dans une application moderne, certaines opérations peuvent être longues et bloquer l’application principale, on utilise alors souvent des files de tâches. BullMQ est une solution simple pour gérer ce type de traitement en arrière-plan.]]></description>
            <link>https://code-garage.com/blog/decouvrez-bullmq-une-message-queue-simple-avec-nodejs</link>
            <guid isPermaLink="true">https://code-garage.com/blog/decouvrez-bullmq-une-message-queue-simple-avec-nodejs</guid>
            <category><![CDATA[Asynchrone]]></category>
            <category><![CDATA[Redis]]></category>
            <category><![CDATA[NodeJS]]></category>
            <category><![CDATA[Python]]></category>
            <category><![CDATA[PHP]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Mon, 09 Mar 2026 09:20:06 GMT</pubDate>
            <content:encoded><![CDATA[<p>Imaginez une application web qui doit un exporter un zip, puis l’envoyer par e-mail, <strong>pour qu’un utilisateur puisse télécharger des données.</strong></p>
<p>Si votre serveur attend que <strong>le zip soit compressé puis envoyé</strong> avant de répondre à l’utilisateur :</p>
<ul>
<li>la requête devient lente</li>
<li>votre serveur peut bloquer</li>
<li>la requête peut échouer à cause d’un timeout</li>
</ul>
<blockquote>
<p>La solution consiste à <strong>déléguer ce travail à un système de tâches asynchrones</strong>.</p>
</blockquote>
<p>Au lieu de créer le zip directement, l’application ajoute une tâche dans une file :</p>
<pre><code class="language-plaintext">(1) Exporter données (user@example.com) -- En cours...
(2) Exporter données (user2@test.com)   -- En attente
(3) Exporter données (user3@fake.com)   -- Tâche ajoutée
</code></pre>
<p>L’utilisateur, lui, va recevoir une confirmation immédiate du traitement de sa demande, et un autre processus (parfois un autre serveur, conteneur,…) <strong>se chargera de traiter la demande et d’envoyer l’email.</strong></p>
<p>Comme ceci :</p>
<pre><code class="language-plaintext">Lire la tâche en cours
|
Récupérer les données
|
Créer l'archive zip
|
Envoyer l'email (user@example.com)
|
Valider la tâche
</code></pre>
<blockquote>
<p>Tant qu’il y a des tâches en cours, le processus les traitera les unes à la suite des autres, <strong>dans l’ordre d’arrivée (First In - First Out ou FIFO)</strong></p>
</blockquote>
<p>De cette manière, <strong>notre serveur web n’est pas bloqué par des tâches longues ou coûteuses</strong>, il peut continuer à traiter le reste de ses requêtes facilement !</p>
<h2>Qu’est-ce que BullMQ ?</h2>
<p><a href="https://bullmq.io/"><strong>BullMQ</strong></a> est une bibliothèque permettant de gérer ce type de file de tâches.</p>
<p>Elle repose sur <a href="https://code-garage.com/tags/redis"><strong>Redis</strong></a>, <strong>une base de données en mémoire très rapide</strong> qui sert à stocker et coordonner les tâches.</p>
<blockquote>
<p>Si vous ne connaissez pas Redis, on vous a préparé <a href="https://code-garage.com/blog/redis-une-base-de-donnees-rapide-comme-l-eclair">un article dédié !</a></p>
</blockquote>
<p>Le fonctionnement repose sur trois éléments :</p>
<ul>
<li><strong>La queue (file)</strong> : l’endroit où les tâches sont ajoutées</li>
<li><strong>Les workers</strong> : des processus qui exécutent les tâches</li>
<li><strong>Redis</strong> : le moteur qui stocke les jobs et leur état</li>
</ul>
<p>Le flux ressemble généralement à ceci :</p>
<ol>
<li>L’application ajoute une tâche dans la queue</li>
<li>Redis stocke cette tâche</li>
<li>Un worker récupère la tâche</li>
<li>Le worker exécute l’action (ex : envoyer un email)</li>
</ol>
<blockquote>
<p>Ce modèle permet de <strong>séparer la logique métier principale des traitements lourds</strong>.</p>
</blockquote>
<p>Attention, BullMQ n’est pas un MessageBroker, c’est simplement une file d’attente ! On va voir la différence un peu plus loin avec RabbitMQ par exemple.</p>
<h3>Un exemple simple</h3>
<p>Voici un exemple minimal avec Node.js pour <strong>ajouter une tâche dans une queue</strong> :</p>
<pre><code class="language-js">import { Queue } from &quot;bullmq&quot;;

const emailQueue = new Queue(&quot;email-queue&quot;, {
  connection: {
    host: &quot;localhost&quot;,
    port: 6379
  }
});

await emailQueue.add(&quot;send-welcome-email&quot;, {
  email: &quot;user@example.com&quot;,
  name: &quot;Alice&quot;
});
</code></pre>
<blockquote>
<p>Ce code ajoute une tâche appelée <code>send-welcome-email</code> dans Redis.</p>
</blockquote>
<p>Et voici un exemple d’un Worker qui traite les tâches :</p>
<pre><code class="language-js">import { Worker } from &quot;bullmq&quot;;

const worker = new Worker(
  &quot;email-queue&quot;,
  async job =&gt; {
    const { email, name } = job.data;

    console.log(`Envoi de l'email de bienvenue à ${name} (${email})`);

    // Ici on pourrait appeler un service SMTP
    // sendEmail(email, ...)
  },
  {
    connection: {
      host: &quot;localhost&quot;,
      port: 6379
    }
  }
);
</code></pre>
<blockquote>
<p>Dès qu’une tâche est ajoutée, le worker la récupère et exécute le traitement.</p>
</blockquote>
<h3>Cas d’usage typiques</h3>
<p>Les files de tâches comme BullMQ sont utilisées pour :</p>
<ul>
<li>envoyer des emails</li>
<li>générer des rapports ou documents</li>
<li>traiter des images ou vidéos</li>
<li>importer de grandes quantités de données</li>
<li>exécuter des tâches planifiées</li>
<li>lancer des traitements lourds en arrière-plan</li>
</ul>
<blockquote>
<p>Dès qu’une opération peut prendre du temps ou échouer temporairement, une queue devient utile.</p>
</blockquote>
<h2>Les forces et faiblesses de BullMQ</h2>
<p>BullMQ présente <strong>plusieurs avantages importants</strong> : il est performant, gèrent les “retries” en cas d’échecs, mais possède surtout une très bonne DX et <strong>n’a besoin que d’une dépendance d’infrastructure (Une base Redis).</strong></p>
<p>Mais cela reste néanmoins une solution relativement simple, avec ses limites : <strong>limité à NodeJS, Python et PHP</strong>, il est également mois adapté aux architectures très distribuées.</p>
<h2>Et RabbitMQ alors ?</h2>
<p>La différence principale entre BullMQ et RabbitMQ est leur rôle :</p>
<ul>
<li>BullMQ est une <strong>bibliothèque de gestion de tâches</strong>.</li>
<li>RabbitMQ est un <strong>message broker</strong>, conçu pour faire communiquer plusieurs services entre eux.</li>
</ul>
<p>Avec RabbitMQ, chaque service peut envoyer des messages sur la Queue, et chaque service est libre de traiter un message comme il l’entend. <strong>BullMQ permet simplement d’envoyer une tâche de manière unilatérale</strong>, et avec une seule source de vérité (même si autant de Worker peuvent écouter les tâches).</p>
<blockquote>
<p><strong>RabbitMQ est aussi plus lourd à mettre en place</strong>, avec une infrastructure dédiée, et son protocol basé sur AMQP.</p>
</blockquote>
<h2>Note supplémentaire</h2>
<p>Il est important de rappeler que BullMQ est capable de garder les tâches en mémoire à long terme, <strong>uniquement si la persistence est activée sur votre base de données Redis !</strong></p>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_A_game_of_Jenga_with_a_bull_running_towar_73661975_0c7a_463e_8028_8743ca2870b5_6d0f824c54.jpg" medium="image"/>
        </item>
        <item>
            <title><![CDATA[Comment récupérer les variables d’environnement en COBOL ?]]></title>
            <description><![CDATA[Même si COBOL est un langage ancien, il reste encore utilisé dans de nombreux systèmes critiques. Mais comment faire pour adapter son comportement selon l’environnement, par exemple, passer du mode développement au mode production ? La réponse passe par les variables d’environnement.]]></description>
            <link>https://code-garage.com/blog/comment-recuperer-les-variables-environnement-en-cobol</link>
            <guid isPermaLink="true">https://code-garage.com/blog/comment-recuperer-les-variables-environnement-en-cobol</guid>
            <category><![CDATA[Cobol]]></category>
            <dc:creator><![CDATA[NicolasBrondinBernard]]></dc:creator>
            <pubDate>Mon, 02 Mar 2026 16:42:26 GMT</pubDate>
            <content:encoded><![CDATA[<h2>Les variables d’environnement, c’est quoi ?</h2>
<p>Une <strong>variable d’environnement</strong> est une valeur stockée par le système d’exploitation et accessible par les programmes.</p>
<p>Elles servent à définir le <strong>contexte d’exécution</strong> d’une application :</p>
<ul>
<li>nom du serveur</li>
<li>chemin vers une base de données</li>
<li>mode de fonctionnement (DEV / PROD)</li>
<li>etc...</li>
</ul>
<blockquote>
<p>En COBOL, on peut y accéder grâce à l’instruction <code>ACCEPT</code>.</p>
</blockquote>
<h2>Lire une variable d’environnement en COBOL</h2>
<p>Voici un exemple simple pour <strong>récupérer la variable d’environnement</strong> <code>APP_MODE</code> :</p>
<pre><code class="language-plaintext">       IDENTIFICATION DIVISION.
       PROGRAM-ID. EnvExample.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01  APP-MODE       PIC X(10).

       PROCEDURE DIVISION.
           ACCEPT APP-MODE FROM ENVIRONMENT &quot;APP_MODE&quot;
           DISPLAY &quot;Mode d'exécution : &quot; APP-MODE
           STOP RUN.

</code></pre>
<ul>
<li><code>ACCEPT</code> permet de <strong>lire une entrée externe</strong>.</li>
<li>En précisant <code>FROM ENVIRONMENT &quot;APP_MODE&quot;</code>, on demande à COBOL de lire la variable d’environnement correspondante.</li>
<li>La valeur est stockée dans la variable <code>APP-MODE</code>.</li>
</ul>
<h3>Exemple pratique</h3>
<p>Imaginons que vous vouliez exécuter certaines instructions selon l’environnement :</p>
<pre><code class="language-plaintext">       IF APP-MODE = &quot;DEV&quot;
           DISPLAY &quot;Connexion à la base de test...&quot;
       ELSE
           DISPLAY &quot;Connexion à la base de production...&quot;
       END-IF.
</code></pre>
<blockquote>
<p>Mais avant d’exécuter votreprogramme, tu peux définir la variable selon le contexte :</p>
</blockquote>
<pre><code>Mode d'exécution : DEV
Connexion à la base de test...
</code></pre>
<h2>Gérer les cas particuliers</h2>
<h3>Les valeurs numériques</h3>
<p>Une chose à retenir, c’est qu’une variable d’environnement est toujours passée à un programme sous forme de <code>string</code>. Il est possible de la convertir automatiquement en COBOL, en la déclarant comme une valeur valeur numérique, comme ceci avec <code>port</code> qui serait égal à <code>3000</code> :</p>
<pre><code class="language-plaintext">01 PORT PIC 9(4).
ACCEPT PORT FROM ENVIRONMENT &quot;PORT&quot;
</code></pre>
<blockquote>
<p>Mais ce n’est pas conseillé.</p>
</blockquote>
<p>Si votre votre variable contient par erreur une valeur qui ne peut pas être parsée, alors il y a de fortes chances que votre programme crash (en fonction de votre environnement).</p>
<p>Il vaut mieux lire une valeur alpha-numérique, pour ensuite vérifier et convertir, comme ceci :</p>
<pre><code class="language-plaintext">01 PORT-STR PIC X(10).
01 PORT     PIC 9(4).

ACCEPT PORT-STR FROM ENVIRONMENT &quot;PORT&quot;

IF PORT-STR IS NUMERIC
    MOVE PORT-STR TO PORT
ELSE
    DISPLAY &quot;PORT invalide&quot;
END-IF
</code></pre>
<h3>Les valeurs vides</h3>
<p>Si une variable d’environnement est lue, mais quelle est vide (ou simplement non définie), alors votre programme ne recevras qu’un ensemble d’espaces équivalent à la longueur de votre variables.</p>
<p>Pour vérifier si votre variable est définie ou non, et lui assigner une valeur par défaut, il vous suffira de faire ceci :</p>
<pre><code class="language-plaintext">ACCEPT APP-MODE FROM ENVIRONMENT &quot;APP_MODE&quot;
IF APP-MODE = SPACES
    MOVE &quot;DEV&quot; TO APP-MODE
DISPLAY &quot;Mode d'exécution : &quot; APP-MODE
STOP RUN.
</code></pre>
<blockquote>
<p>La constante SPACES est une constante “figurative”, qui s’adapte au contexte, et elle correspond au nombre d’espaces nécessaires pour remplir votre variable.</p>
</blockquote>
]]></content:encoded>
            <media:content url="https://code-garage-strapi-bucket-production.cellar-c2.services.clever-cloud.com/nicolasbrondinbernard_COBOL_environment_a487796549.jpg" medium="image"/>
        </item>
    </channel>
</rss>