<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Notes &amp; Réflexions</title>
  <subtitle></subtitle>
  <link href="https://notes.christophevergne.fr/feed.xml" rel="self"/>
  <link href="https://notes.christophevergne.fr/"/>
  
    <updated>2024-12-14T00:00:00Z</updated>
  
  <id>https://notes.christophevergne.fr</id>
  <author>
    <name>Christophe VERGNE</name>
    <email></email>
  </author>
  
    
    <entry>
      <title>Pourquoi ?</title>
      <link href="https://notes.christophevergne.fr/posts/2018/03/9-pourquoi/"/>
      <updated>2018-03-09T00:00:00Z</updated>
      <id>https://notes.christophevergne.fr/posts/2018/03/9-pourquoi/</id>
      <content type="html">
        <![CDATA[
      <p>La grande question: pourquoi ce blog ?</p>
<p><s>Il était une fois…</s></p>
<p>Tout a commencé en fin d'année dernière lorsque j'ai proposé un sujet pour <a href="https://www.24joursdeweb.fr">24 jours de web</a>.</p>
<p>Je m'étais imposé de l'avoir écrit au moins à 80% avant de le proposer, afin d'être sûr d'être en mesure de le publier à temps. Le fait est qu'il n'a finalement pas été retenu, j'avais alors pour objectif de le publier pour le hashtag #<a href="https://mobile.twitter.com/hashtag/nowwwel">nowwwel</a>, mais faute d'avoir trouvé la plateforme adaptée ça ne s'est pas fait.</p>
<p>En effet j'avais pensé à <a href="https://www.medium.com">Medium</a> dont j'aime beaucoup l'interface pour la lecture, mais ils ne supportent malheureusement pas les tableaux et mon article en contenait un.</p>
<p>Je me suis donc orienté vers une plateforme plus ou moins auto-hébergée en misant sur <strong>Jekyll</strong> via GitHub Pages, mais cela me semblait trop contraignant malgré la possibilité d'écrire en Markdown ce qui était un pré-requis.</p>
<p>J'ai donc finalement opté pour le classique <strong>WordPress</strong> avec lequel j'ai d'avantage l'habitude de travailler techniquement, ce qui m'a permis d'avoir exactement ce que je voulais aussi bien visuellement que techniquement. Et je peux même sans problème le gérer depuis mon iPhone et mon iPad, plateformes sur lesquelles je suis en grande majorité en dehors de mes heures de travail.</p>
<p>C'est donc par cet article que j'inaugure ce carnet de notes, en espérant que le contenu suscitera votre intérêt à le lire autant qu'il aura suscité le mien à l'écrire.</p>
<p>Pour en savoir davantage, je vous invite à lire la page &quot;<a href="https://notes.christophevergne.fr/a-propos-du-blog-et-de-lauteur/">En savoir plus…</a>&quot;.</p>
<p><strong>Mise à jour 2024 :</strong> J'ai finalement migré vers Eleventy pour plus de simplicité.</p>

    ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Les erreurs, ça arrive</title>
      <link href="https://notes.christophevergne.fr/posts/2018/03/15-les-erreurs-ca-arrive/"/>
      <updated>2018-03-15T00:00:00Z</updated>
      <id>https://notes.christophevergne.fr/posts/2018/03/15-les-erreurs-ca-arrive/</id>
      <content type="html">
        <![CDATA[
      <p>Commençons donc par un peu de contexte:</p>
<blockquote>
<p>Vous êtes dans le métro parisien, vous devez aller d’un bout à l’autre de la ligne 8.</p>
</blockquote>
<blockquote>
<p>Le réseau cellulaire est instable, il y a du Edge, de la 3G, de la 4G et votre mobile tente désespérément de rester accrocher au réseau précédent lors des changements d’antenne réguliers.</p>
</blockquote>
<blockquote>
<p>50 minutes de connexion instable…</p>
</blockquote>
<p>Ça vous donne la chair de poule ? C’est pourtant le quotidien de milliers de personnes et peut-être même le votre.</p>
<p>Cela signifie que ces personnes sont régulièrement confrontées à des pertes de connexion ou des micros coupures interrompant partiellement voir totalement le chargement d’une page.</p>
<p>Ici on ne va donc pas parler des éventuelles fautes de frappe que l’on fait tout le temps, ni du fichier que l’on a oublié d’inclure mais des erreurs inévitables dans la vie d’un site internet avec lesquelles on doit composer.[^1]</p>
<p>[^1]: Cet article est avant tout orienté « développement » mais les autres profils les plus curieux pourront s’y intéresser également puisque cela peut aussi toucher la conception et le design.</p>
<p>Bien trop souvent on développe en partant du principe que cela va fonctionner exactement comme on l’a imaginé, parce qu’après tout, c’est le but. Malheureusement il arrive que l’on soit confronté à des problèmes liés à l’environnement de l’utilisateur <em>(sa connexion)</em>, à ses actions <em>(mauvaise saisie de formulaire)</em>, aux interconnexions <em>(webservices)</em> ou encore simplement la perception des erreurs.</p>
<p>Il s’agit quasi systématiquement d’améliorer l’expérience utilisateur <em>(UX)</em>, ou tout du moins de ne pas la détériorer.</p>
<p>Avant les erreurs réelles, commençons par la perception.</p>
<p>Bien que les connexions mobiles soient de plus en plus rapides, la couverture réseau ou l’endroit où l’on se trouve <em>(metro)</em> ralentissent le chargement d’une page.</p>
<h2>Fonts</h2>
<h3>Bien: Famille de police dans CSS</h3>
<p>Admettons que vous utilisiez sur votre site une police de caractères non-système sur la totalité de vos textes.</p>
<p>Si vous chargez par exemple une police depuis Google Fonts, et que celui-ci tombe pour une raison ou pour une autre, votre navigateur va donc basculer sur une police système de façon à afficher tout de même le texte.</p>
<p>Si vous n’avez pas défini de police système ou famille de police comme solution de repli <em>(fallback)</em>, le navigateur prendra sa police par défaut, ce qui peut fortement dénaturer le design de votre site.</p>
<p>Lorsque vous choisissez une police personnalisée, faites en sorte de trouver l’alternative système la plus proche, puis la famille de police.</p>
<p>Si vous avez choisi une police personnalisée de type <em>Cursive</em> <em>(ce qui est cependant à éviter pour du long texte)</em> et que votre texte s’affiche d'abord avec une police à chasse fixe <em>(monospaced)</em>, cela va complètement dénaturer votre charte graphique.</p>
<p>Vous pouvez vous aider d’une <a href="https://www.cssfontstack.com/">liste des polices systèmes les plus déployées</a> pour trouver l’alternative la plus proche.</p>
<pre class="language-css"><code class="language-css"><span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Open Sans'</span><span class="token punctuation">,</span> Arial<span class="token punctuation">;</span></code></pre>
<p>Enfin, il reste la famille de police à mettre, qui laisse votre navigateur choisir parmi celles disponibles sur votre système (et peut donc varier d’un système à l’autre).</p>
<p>En l’occurrence, si vous choisissez délibérément de mettre « Monaco » comme police de caractères, n’oubliez pas de préciser « Monospace » comme famille de police alternative.</p>
<p><strong>Exemple</strong></p>
<p><em>Ici, avant la famille de police, on met la police Consolas comme alternative système, particulièrement répandu sur Windows.</em></p>
<pre class="language-css"><code class="language-css"><span class="token property">font-family</span><span class="token punctuation">:</span> monaco<span class="token punctuation">,</span> Consolas<span class="token punctuation">,</span> monospace<span class="token punctuation">;</span></code></pre>
<p>Vous auriez également très bien pu mettre <code>'Courier Sans'</code> comme alternative avant <code>monospace</code>.</p>
<p>Si vous incluez une police depuis Google Fonts, regardez le code CSS fourni dans la partie « Specify in CSS », ils donnent systématiquement la famille de police qui convient.</p>
<p>Avec ça, vous assurez déjà un <em>fallback</em> en cas d’échec de chargement de la votre police principale.</p>
<p>Cela ne s’applique d’ailleurs pas forcément qu’à une police personnalisée externe, vous pouvez très bien choisir de charger une police système qui n’est que sur macOS, puis en police secondaire une police qui est sur tous les sytèmes.</p>
<h3>Mieux: CSS Font Loading API</h3>
<p>Admettons maintenant que vous ayez choisi une police Google Fonts, et que vous ayez chargé celle-ci dans votre HTML accompagné des attributs <code>defer</code> et <code>async</code> :</p>
<pre class="language-html"><code class="language-html"></code></pre>
<p>Cela signifie que le contenu de votre page, et certainement votre feuille de style, seront chargés avant la police elle-même, alors que vous avez spécifié dans votre CSS de l’appliquer sur tout le texte de la page.</p>
<p>Tant qu’elle ne sera pas chargée, il y aura donc de fortes chances pour que votre texte n’apparaisse tout simplement pas jusqu’à ce que la police soit disponible, au moins jusqu’au timeout par défaut du navigateur.</p>
<p>Actuellement, le timeout des navigateurs avant de basculer sur la police <em>fallback</em> est le suivant[^2] :</p>
<p>[^2]: Tableau provenant de <a href="">https://developers.google.com/web/updates/2016/02/font-display</a></p>
<table>
<thead>
<tr>
<th style="text-align:left">Navigateur</th>
<th style="text-align:left">Timeout</th>
<th style="text-align:left">Fallback</th>
<th style="text-align:left">Swap</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">Chrome 35+</td>
<td style="text-align:left">3 secondes</td>
<td style="text-align:left">Oui</td>
<td style="text-align:left">Oui</td>
</tr>
<tr>
<td style="text-align:left">Opera</td>
<td style="text-align:left">3 secondes</td>
<td style="text-align:left">Oui</td>
<td style="text-align:left">Oui</td>
</tr>
<tr>
<td style="text-align:left">Firefox</td>
<td style="text-align:left">3 secondes</td>
<td style="text-align:left">Oui</td>
<td style="text-align:left">Oui</td>
</tr>
<tr>
<td style="text-align:left">Internet Explorer/Edge</td>
<td style="text-align:left">0 secondes</td>
<td style="text-align:left">Oui</td>
<td style="text-align:left">Oui</td>
</tr>
<tr>
<td style="text-align:left">Safari</td>
<td style="text-align:left">No timeout</td>
<td style="text-align:left"><em>N/A</em></td>
<td style="text-align:left"><em>N/A</em></td>
</tr>
</tbody>
</table>
<p>Pour tous ces navigateurs <em>(à l’exception d’IE/Edge)</em>, votre texte ne sera pas visible pendant les 3 premières secondes de chargement de la page tant qu’elle n’est pas disponible. Au delà, cela basculera sur la police <em>fallback</em>, puis cela pourra rebasculer sur la police voulue si celle-ci est finalement chargée.</p>
<p>Néanmoins, à mon sens, tous devraient se comporter comme IE/Edge. Imaginez que votre page mette 500ms à charger, mais que pour une raison obscure, la police côté Google mette plus de 3 secondes. Cela signifie que tout le contenu de votre page est quasi immédiatement disponible, mais l’utilisateur devra tout de même attendre au minimum 2,5 secondes supplémentaires pour pouvoir le lire.</p>
<p>Heureusement, une propriété CSS4 permet de modifier ce comportement : <a href="https://developer.mozilla.org/fr/docs/Web/CSS/@font-face/font-display"><code>font-display</code></a>.</p>
<p>Grace à cette méthode, vous pouvez définir comment devra se comporter le navigateur tant que la police n’est pas chargée, puis une fois qu’elle est chargée, parmi les modes disponibles.</p>
<p>L’idée ici n’est pas d’en faire un tutoriel complet, on va donc juste se pencher sur 2 valeurs possibles :</p>
<ul>
<li>
<p><code>optional</code>: <em><strong>Blocage extrêmement court, pas d’échange.</strong></em>
La valeur idéale, car vous évitez le <a href="https://css-tricks.com/fout-foit-foft/">FOUT/FOIT/FOFT</a>. À privilégier, et facile à mettre en place si c’est pour vous, ou que vous êtes le client final. Si vous êtes en agence, il vous faudra convaincre votre client, ce qui sera plus compliqué car la première fois qu’il visitera la page, si la police n’est pas chargée pendant le temps de blocage, il restera sur le <em>fallback</em> jusqu’au rechargement de la page <em>(ou le fait d’aller sur une autre page, puisque la police sera désormais en cache)</em>.</p>
</li>
<li>
<p><code>swap</code>: <em><strong>Pas de blocage, période d’échange infinie.</strong></em>
Celle-ci sera plus simple à mettre en place, puisque le fallback est immédiatement affiché, puis remplacé par la bonne police dès que celle-ci est chargée. Cela peut néanmoins déranger puisque la police peut changer à tout moment, en particulier lorsque vous lisez un long texte comme cet article.</p>
</li>
</ul>
<p>De mon point de vue, l'idéal serait finalement pas de blocage, mais une courte période d'échange. Le paramètre qui s'en rapproche le plus est alors <code>fallback</code>.</p>
<p>Le <a href="http://caniuse.com/#search=font-display">support de cette propriété n’est malheureusement pas encore géré par tous les navigateurs</a>, mais cela est arrivé il y a peu de temps en <a href="https://developer.apple.com/safari/technology-preview/">Technology Preview dans Safari</a>, et depuis la version 58 dans Firefox. J’ai donc bon espoir pour que ce soit <a href="https://developer.microsoft.com/en-us/microsoft-edge/platform/status/cssfontloadingapi/">implémenté d’ici 2018 dans Edge</a>.</p>
<p>Néanmoins, cette propriété rentrant parfaitement dans le cadre de l’amélioration progressive, je vous recommande vivement de la mettre en place dès maintenant.</p>
<p>Enfin, si vous voulez mettre en place un comportement similaire même sur les navigateurs ne prenant pas en charge cette propriété, vous pouvez coupler l’API <a href="http://caniuse.com/#feat=css-supports-api"><code>CSS.supports()</code></a>[^3] de manière à détecter le support de <code>font-display</code>, avec <a href="https://fontfaceobserver.com">FontFaceObserver</a> afin d’appliquer un comportement similaire à la propriété.</p>
<p>[^3]: Notez que si le navigateur ne prend pas en charge <code>CSS.supports()</code>, il y a peu de chance qu’il prenne en charge <code>font-display</code></p>
<h2>Images</h2>
<h3>Bien: Balise <code>alt</code> remplie</h3>
<p>Passons maintenant aux images. Vous connaissez le refrain, celui sans cesse répété mais pas encore assez appliqué: mettez un texte alternatif à vos images de contenu[^4].</p>
<p>[^4]: Specification W3C: <a href="http://w3c.github.io/html/semantics-embedded-content.html#alt-text">http://w3c.github.io/html/semantics-embedded-content.html#alt-text</a></p>
<p>Oui je précise « de contenu », car une image servant au design <em>(même si ça devrait être en CSS)</em> ne devrait pas avoir de texte alternatif. En effet, savoir que l’image contient un demi-cercle servant à la forme d’un <code>div</code> n’a aucune intérêt pour l’utilisateur se servant d’un lecteur d’écran par exemple.</p>
<p>En revanche, si votre image contient du texte pertinent pour l’utilisateur, vous devez remettre ce texte dans la balise <code>alt</code> de votre image.</p>
<p>Prenons l’exemple du site <a href="https://oui.sncf">Oui.sncf</a> et de sa bannière en haut de page[^5].</p>
<p>[^5]: Au moment de la rédaction de cet article, novembre 2017]</p>
<p>Celle-ci est chargée en <em>background</em> CSS, alors qu’il s’agit bien d’une image de contenu ici puisqu’elle contient du texte destiné à l’utilisateur. C’est pourquoi il semble y avoir à l’intérieur des balises de texte, sans doute masquées, prévues à cet effet mais qui ne sont malheureusement pas remplies.</p>
<p>Du coup, pas d’image, pas d’information.</p>
<p>Et même si ça n’a pas un impact significatif, c’est aussi utile pour le SEO.</p>
<p>Et puis, c’est même la <a href="https://checklists.opquast.com/oqs-v3/criteria/chaque-image-decorative-est-dotee-dune-alternative-textuelle-appropriee">règle nº1 des bonnes pratiques Opquast</a>.</p>
<h3>Mieux: Balise <code>alt</code> stylisée</h3>
<p>Maintenant partons du principe que votre image ne se charge pas.</p>
<p>Du coup le texte alternatif va s’afficher avec le style par défaut de votre page ou du parent, ce qui ne sera peut être pas en accord avec votre design.</p>
<p>L’idée est donc de styliser l’affichage du texte alternatif des images. Il s’agit pour cela d’appliquer quelques propriétés CSS liées au texte de manière à lui donner le style le plus approprié par rapport à la place qu’a l’image dans le contenu de votre page.</p>
<p>Si votre image contient du texte en gros caractères parce qu’il s’agit de la mise en avant d’une promo comme oui.sncf par exemple.</p>
<h2>XHR</h2>
<h3>Bien: Gérer les erreurs</h3>
<p>C’est cette partie qui m’a amené principalement à écrire sur ce sujet.</p>
<p>Bien trop souvent les requêtes XHR sont exécutées via un snippet copié-collé depuis une page ou document qui montrait un vague exemple basique et sont peu ou pas configurées.</p>
<p>Elles se contentent alors de ne gérer qu’un seul et unique cas: celui où tout va bien.</p>
<p>Entre vous et moi, on en serait pas à la 3ème section de cet article si tout se passait comme prévu. Et la requête XHR est probablement celle où l’on a le plus de contrôle ce qui est dommage de s’en passer.</p>
<p>Commençons par le <em>callback</em> de <em>success</em>: si une autre erreur survient côté serveur, et que vous l’avez géré en renvoyant une réponse appropriée, vous devez alors le prendre en compte et afficher un message d’erreur sur votre page.</p>
<p>Un utilisateur sera moins frustré par une notification d’erreur suffisamment explicite plutôt que par l’impression que rien ne s’est passé ou que ça s’est passé mais que ça n’a au final pas fonctionné correctement.</p>
<p>Il s’agit donc du cas où vous renvoyez une erreur « normale » <em>(par exemple, une inscription où le mail spécifié existe déjà en base de donnée)</em>.</p>
<p>Maintenant il y a le cas où votre serveur renvoie un code HTTP d’erreur comme 404, 500, etc.</p>
<p>Dans ce cas là, soit vous utilisez une librairie/framework/helper et vous devez appliquer un comportement spécifique dans le <em>callback</em> d’erreur, soit vous gérez le cas où le code de la réponse n’est pas 200.</p>
<p>La bonne pratique alors est déjà d’interrompre tout comportement temporaire <em>(zone masquée, affichage d’image animée de chargement, etc.)</em> puis d’indiquer qu’une erreur s’est produite.</p>
<p>Vous pouvez préciser un code d’erreur en fin de message et idéalement un lien vers la page contact. De cette façon, l’utilisateur pourra <em>peut-être</em> vous signaler l’erreur, ce qui pourra vous aider à la corriger si vous ne l’aviez pas repérée.</p>
<h3>Mieux: Annuler la requête précédente, mettre un timeout et annulation manuelle</h3>
<p>Si vous avez déjà tout fait de la section précédente, vous avez fait 90% du travail.</p>
<p>Pour la suite, prenons l’exemple d’un moteur de recherche dont les résultats sont chargés de manière asynchrone. Vous cochez un élément dans les facettes, les résultats se rafraîchissent sans rechargement complet de la page.</p>
<p>Vous cliquez alors sur un nouveau filtre, ce qui lance une requête, puis immédiatement sur le suivant puisque vous souhaitez en avoir plusieurs actifs en même temps.</p>
<p>Malheureusement dans la plupart des cas, une requête va se lancer au premier filtre, puis une autre pour le second filtre. Vous allez alors avoir deux requêtes tournant simultanément, et si la seconde se termine avant la première, vous n’aurez même pas le résultat attendu une fois tout chargé.</p>
<p>C’est pour cette raison que lorsque vous lancez une requête, il faut penser à la <em>stocker</em> de manière à pouvoir l’annuler si une autre est lancée. De cette manière, la première requête étant devenue inutile, vous évitez les risques d’erreur d’affichage et les ralentissements de traitement des requêtes.</p>
<p>Ensuite, pour des requêtes que vous savez généralement rapides, il peut être utile de mettre en place un <em>timeout</em> à la requête afin que celle-ci s’annule d’elle-même au cas où son temps de traitement est anormalement long.</p>
<p>Une autre bonne pratique qui relève plutôt du bonus: il peut être utile de mettre un bouton d’annulation manuelle de la requête pour celles que vous savez potentiellement longues et non transactionnelles <em>(sauf si vous avez correctement géré les soumissions de doublons potentiels côté serveur)</em>.</p>
<p>Enfin, parmi toutes ces bonnes pratiques, que ce soit « annuler la requête » ou « afficher un message d’erreur », cela signifie que vous allez revenir en arrière. Pensez alors à enlever votre <em>loader</em>, remettre le lien qui permet de lancer la requête ou décocher la case qui était liée au filtre qui vient d’être coché.</p>
<h2>Appels WS/API</h2>
<h3>Bien: <em>catcher</em> et <em>logger</em> les erreurs</h3>
<p>Passons maintenant à une partie qui concerne d’avantage la partie serveur <em>(car de mon point de vue, c’est de ce côté que c’est le plus simple à mettre en place)</em>.</p>
<p>Les appels de Webservices ou d’API côté serveur sont au final assez similaires aux appels XHR que vous faites en front et sont sujets aux mêmes types d’erreurs: renvoi d’une erreur « normale », coupure réseau, <em>endpoint</em> inaccessible, etc.</p>
<p>Admettons que vous vous attendiez à recevoir du JSON, et que pour une raison inconnue l’API se mette à vous renvoyer une erreur serveur en texte brut. Vous vous retrouvez alors avec une erreur de votre côté et dans l’impossibilité de continuer le traitement normal de votre script.</p>
<p>Pour peu que vous n’ayez pas géré ce cas, c’est probablement toute votre application qui risque d’être inutilisable et donne à l’utilisateur l’impression que votre application est mal développée et diminue le niveau de confiance qu’il a en celle-ci.</p>
<p>Il vaut faut alors <em>catcher</em> le cas où il y a une erreur <em>anormale</em> puis renvoyer une réponse appropriée (<em>message d’erreur</em>).</p>
<p>Ensuite, contrairement au <em>frontend</em> où c’est plus difficile à faire, vous pouvez <em>logger</em> cette erreur dans un fichier spécifique afin d’être alerté du problème, investiguer d’avantage et éventuellement améliorer votre code pour mieux répondre à ce type de cas quand il se présente.</p>
<p>Si vous utilisez une librairie comme <em><a href="http://guzzlephp.org/">Guzzle</a></em> en PHP, il est assez facile de mettre en place un <em>logging</em> automatique en cas d’erreur sur toutes vos requêtes via un <em><a href="https://michaelstivala.com/logging-guzzle-requests/">Log Middleware</a></em>.</p>
<h3>Mieux: Refaire un essai en cas d’erreur de connexion</h3>
<p>Si nous restons dans le cas où le serveur distant de l’API est injoignable au moment de la requête, plutôt que d’envoyer une réponse immédiate à l’utilisateur qui relancera la requête juste après, pourquoi ne pas refaire un essai directement coté serveur ?</p>
<p>Si vous avez la possibilité de détecter qu’il s’agit bien d’une erreur de connexion, vous pouvez sans problème refaire une tentative, ce qui fera moins perdre de temps à votre utilisateur que si il devait attendre la réponse et la relancer lui-même.</p>
<p>Toujours si vous utilisez une librairie comme <em><a href="http://guzzlephp.org/">Guzzle</a></em>, vous pouvez mettre en place un <em><a href="https://addshore.com/2015/12/guzzle-6-retry-middleware/">Retry Middleware</a></em>.</p>
<p>Vous pourrez en plus définir combien de tentatives vous allez effectuer <em>(1 ou 2 supplémentaires maximum)</em>, mais vous pouvez également définir dans <em>Guzzle</em> le <em>timeout</em> de connexion ainsi que celui d’exécution, ce qui permettra d’éviter une attente interminable si elle n’a pas lieu d’être <em>(breaking news: elle n’a jamais lieu d’être)</em></p>
<h2>Validation de formulaire</h2>
<h3>Bien : Valider le form en <em>back</em></h3>
<p>Contrairement à ce qu’on peut lire d’habitude, je ne vais pas recommander en premier une validation des formulaires côté <em>front</em>.</p>
<p>Beaucoup pensent qu’à partir du moment où ils ont empêché l’utilisateur sur leur navigateur de saisir une information incorrecte, alors tout est réglé. Sauf que ça représente déjà une grosse faille de sécurité et augmente le facteur risque de corruption des données et/ou d’exécution <em>buguée</em> de votre application.</p>
<p>Côté serveur, toute saisie effectuée par l’utilisateur doit systématiquement être contrôlée et même nettoyée.</p>
<p>Cela signifie par exemple que si un champ est obligatoire, on vérifie que sa valeur n’est pas vide après l’avoir nettoyé des espaces en début et fin de chaîne <em>(trim)</em>.</p>
<p>Si l’on attend un nombre entier, on va supprimer les espaces inutiles <em>(trim)</em>, forcer la valeur en entier, puis vérifier qu’elle n’est pas vide <em>(sauf si 0 est une valeur autorisée)</em>.</p>
<p>Beaucoup de <em>frameworks</em> et <em>CMS</em> connus intègrent une validation semi-automatique de vos formulaires <em>(Symfony, Laravel)</em>, ou a minima des fonctions de nettoyage <em>(Wordpress)</em>.</p>
<p>Il est assez simple dans l’ensemble de mettre en place ce type de système et de le rendre réutilisable facilement dans le cas de <em>Wordpress</em> par exemple.</p>
<p>Vous pouvez ensuite coupler ça à un système de <em><a href="https://mikeeverhart.net/php-flash-messages/">Flash Message</a></em>[^6].</p>
<p>[^6]: ce type de fonctionnalité est inclus par défaut dans Symfony et Laravel. Vérifiez si la fonction n’est pas déjà présente dans votre framework/CMS avant d’opter pour une librairie tierce]</p>
<h3>Mieux : Valider aussi en <em>front</em> et afficher des erreurs explicites</h3>
<p>Maintenant que vous avez assuré l’intégrité des données envoyées côté serveur, autant prévenir l’utilisateur en temps réel lorsque sa saisie ne correspond pas à ce que vous attendez et lui dire précisément ce que vous voulez.</p>
<p>L’affichage de ce qui est attendu <em>(indices de saisie)</em> ainsi que des erreurs de saisies relève de plusieurs <a href="https://checklists.opquast.com/fr/opquast-website-v3/">bonnes pratiques à appliquer</a> que vous trouverez dans le référentiel <strong>Opquast</strong>.</p>
<p>Plus votre formulaire sera facile et clair à remplir plus vite il le sera, et plus vous ferez de conversions <em>(si c’est votre formulaire de support en revanche, c’est plus embêtant)</em>.</p>
<p>Il faut d’abord veiller à ce que la saisie en <em>front</em> soit validée de la même façon qu’en <em>back</em> afin de ne pas avoir de disparité dans le processus de soumission du formulaire.</p>
<p>Valider en temps réel c’est bien, mais valider correctement c’est encore mieux:</p>
<ul>
<li>
<p>Le signe plus (<em>+</em>) dans les adresses emails, c’est valide <em>(<a href="https://gmail.googleblog.com/2008/03/2-hidden-ways-to-get-more-from-your.html">et c’est pratique</a>)</em> ;</p>
</li>
<li>
<p>Validez la robustesse d’un mot de passe par <a href="https://github.com/dropbox/zxcvbn">un algorithme adapté</a> plutôt que par la présence de certains caractères <em>(spéciaux, majuscules, etc.)</em> ou la longueur de la chaîne ;</p>
</li>
<li>
<p>Indiquez le format attendu après le champ et insérez un exemple en <em>placeholder</em> ;</p>
</li>
<li>
<p>N’utilisez pas le <em>placeholder</em> comme <em>label</em> ;</p>
</li>
</ul>
<h2>Pages d’erreur personnalisées</h2>
<h3>Bien: 404 personnalisée</h3>
<p>Une autre <a href="https://checklists.opquast.com/fr/opquast-website-v3/criteria/le-serveur-envoie-une-page-derreur-404-personnalisee">bonne pratique</a> plutôt bien adoptée désormais: renvoyer une page 404 personnalisée.</p>
<p>Cela ne signifie pas qu’il faut juste rajouter de la couleur sur « 404 » mais plutôt que l’utilisateur n’ait pas l’impression d’être sorti de votre site. Certes l’url qu’il a saisi ne correspond pas ou plus à du contenu existant, mais il ne faut pas pour autant qu’il ait l’impression que tout le site est cassé ou que le problème vient de son côté. Après tout, il vient peut être certainement du vôtre si un lien menant vers une 404 est présent sur votre site.</p>
<p>Idéalement, cela signifie <strong><a href="https://checklists.opquast.com/oqs-v3/criteria/le-menu-principal-de-navigation-figure-sur-les-pages-derreur-personnalisees">remettre la navigation principale du site</a></strong>, de façon à ce qu’il puisse retourner quelque part, <strong>le plan du site</strong>, mais aussi <strong>afficher clairement que le contenu n’existe pas ou plus</strong> sans pour autant agresser visuellement <em>(évitez l’écran rouge avec le message en blanc par exemple)</em>.</p>
<p>Enfin, dans un monde parfait, ajoutez-y <strong>un formulaire de contact</strong>.</p>
<p>Cela peut permettre à l’utilisateur de vous contacter si il souhaite savoir où est passé le contenu désiré, si par exemple il a bougé sans qu’il y ait eu de redirection en place.</p>
<p>Là encore, la plupart des CMS et Frameworks permettent de mettre en place facilement une page 404 personnalisée.</p>
<p>Côté <em>Wordpress</em> cela passe par une template <code>404.php</code>, tandis que sur Symfony cela passe par <a href="https://symfony.com/doc/current/controller/error_pages.html">une template spécifique</a>.</p>
<p>Même <a href="https://jekyllrb.com/tutorials/custom-404-page/">sur Jekyll c’est simple à mettre en place</a> si vous utilisez un générateur statique, alors pas d’excuse.</p>
<h3>Mieux: 4xx,5xx personnalisées</h3>
<p>La page 404 peut être une erreur « normale » dans la plupart des cas, mais il existe d’autres codes d’erreurs amenés à être renvoyés sur votre site.</p>
<p>Pour peu que vous ayez fait une erreur quelconque dans votre code, votre site pourrait renvoyer une erreur 500 par exemple. C’est notamment le cas par défaut chez Symfony et Laravel.</p>
<p>De la même manière que la 404, vous pouvez alors renvoyer une page personnalisée avec le même contenu, sauf le message d’erreur bien entendu.</p>
<p>De cette manière, toute page d’erreur sur votre site permet à l’utilisateur de rester dans celui-ci et d’être légèrement rassuré et un peu moins frustré.</p>
<h2>Bonus: Meta Viewport</h2>
<p>Dans cette courte section supplémentaire, l’erreur est plutôt côté conception si votre site n’a pas été conçu en responsive ou en version mobile adaptée.</p>
<p>Dans ce cas, et <strong>seulement</strong> dans ce cas, pensez à intégrer une balise meta <em>viewport</em> avec une largeur minimum et sans bloquer le zoom <em>(il ne doit <strong>jamais</strong> être bloqué)</em>.</p>
<p>Je vois encore trop souvent des sites qui n’ont pas été pensé pour le mobile et/ou responsive, mais qui ont un design fluide. Ce qui signifie que 2 colonnes à 50% de largeur sur <em>desktop</em> sont complètement écrasées sur mobile. Cela rend le site totalement inutilisable.</p>
<p>Faciliter l’utilisation au zoom est la manière la plus simple de rendre votre site utilisable sur mobile si celui-ci n’est pas responsive.</p>
<p>Pour conclure, quand vous concevez et développez votre site ou votre application, n’oubliez jamais que ce n’est pas parce que vous avez tout fait en pensant que tout se passera bien que tout se passera forcément comme prévu.</p>
<p>Pensez aux novices, aux personnes ne maîtrisant l’informatique, aux personnes âgées ou en situation de handicap. Pensez à l’environnement <em>(réseau)</em>, au matériel utilisé ou tout simplement aux personnes qui vont penser différemment de vous.</p>
<p>Cela ne veut pas forcément dire qu’il faut s’adapter à tout et à tout le monde <em>(quoique)</em>, mais limiter la frustration limitera la perte d’efficacité. De même que tous vos utilisateurs devraient pouvoir accéder au même niveau d’information quelque soit la méthode employée <em>(desktop, mobile, clavier, lecteur d’écran, connexion limitée, etc.)</em>.</p>
<p>Pour aller plus loin et élargir un peu le sujet, je vous recommande:</p>
<ul>
<li>
<p>La conférence donnée par <strong>Geoffrey Crofte</strong> à Paris Web 2017 sur le sujet « <a href="https://youtube.com/watch?v=bXzN0e0oM3E&amp;t=2h39m30s">Améliorer la performance: entre réalité et perception</a> »</p>
</li>
<li>
<p>L’article de <strong>Stéphanie Walter</strong> sur sa conférence à Smashing Conference Barcelone qui avait pour sujet « <a href="https://blog.stephaniewalter.fr/ameliorer-experience-utilisateur-perception-performance/">Améliorer l’experience utilisateur grâce à la perception de la performance</a> »</p>
</li>
</ul>

    ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Devenir développeur en 60 secondes</title>
      <link href="https://notes.christophevergne.fr/posts/2019/01/27-devenir-developpeur-en-60-secondes-60/"/>
      <updated>2019-01-27T00:00:00Z</updated>
      <id>https://notes.christophevergne.fr/posts/2019/01/27-devenir-developpeur-en-60-secondes-60/</id>
      <content type="html">
        <![CDATA[
      <p>Il y a quelques jours, je suis tombé sur cet article de Je suis un dev, intitulé &quot;<a href="https://www.jesuisundev.com/devenir-developpeur-web-full-stack-en-3-jours/">Devenir développeur web full-stack en 3 jours</a>&quot;.</p>
<p>Et étant moi-même développeur web (autodidacte), je ne peux qu'être d'accord avec car toutes ces formations surfent sur beaucoup de points concernant ce domaine, à savoir :</p>
<ul>
<li>La pénurie de développeurs par rapport à l'offre ;</li>
<li>Le taux de chômage ;</li>
<li>La reconversion facile ;</li>
<li>Le peu de moyens nécessaires pour former les intéressés ;</li>
</ul>
<p>Bien entendu, tous ces points ne sont en vrai que de petits bouts d'iceberg en surface cachant la réalité.</p>
<p>Même si il y a bien énormément d'offres dans le développement web, il s'agit très souvent d'un besoin de développeurs expérimentés. Et qu'on se le dise, vous serez à peine junior après une formation de ce type, qu'elle soit de 5 jours ou de 12 mois.
Avec maintenant 11 ans d'expérience dans le domaine, j'ai encore souvent l'impression d'être junior, non seulement parce que c'est un domaine qui évolue constamment et très vite, mais aussi parce qu'il y a toujours plus compétent que soi.</p>
<p>Mais rassurez-vous, je fais parti de ceux qui pensent qu'avoir fait 5 ans d'études dans une école très chère ne vous donnera pas pour autant un meilleur niveau. Pour moi, seule l'expérience sur le terrain est réellement formatrice, alors quitte à faire une formation, autant en faire une qui ne soit pas trop longue au point de vous dégoûter, mais suffisamment pour vous aider à démarrer correctement.</p>
<p>Comme pour tout métier, ce n'est cependant pas forcément adapté à n'importe qui. Cela peut néanmoins réveiller ou déclencher une passion chez vous, et si vous avez la motivation, vous pourrez y arriver.</p>
<p>N'allez donc pas penser qu'il s'agit de la reconversion facile et tranquille, mais si vous êtes curieux ou que vous avez envie de sauter le pas, n'hésitez pas.</p>
<p>Enfin, si vous vous lancez là dedans, réfléchissez bien à la formation à choisir. Elles se multiplient de plus en plus depuis quelques années, et la plupart ne cherchent pas nécessairement à faire les choses bien, mais simplement avoir le plus d'étudiants possibles et un taux de réussite élevé (une sombre histoire d'argent, à tous les coups…), et c'est ce qui me dérange le plus : la multiplication des appâts en tout genre pour attirer le plus de gens.</p>
<p>Si vous vous lancez, soyez prudents, renseignez-vous, discutez.</p>
<p>Pour terminer, si j'ai eu envie d'écrire cet article, un peu sur un coup de tête, c'est suite au <a href="https://threadreaderapp.com/thread/1089520360586919936.html">thread de Dario Spagnolo sur ce sujet</a>.
Même si je n'ai jamais été un grand fan de ce type de formation, je constate que la communication faite par Dario et son école est plus sérieuse et réaliste que celles que l'on peut voir ailleurs, et pour avoir déjà travaillé avec lui, je dirais que c'est sûrement en ayant appris de ses erreurs, parce que c'est ça aussi, devenir développeur.
Je ne vous dirais donc pas de foncer car je ne connais pas parfaitement les offres disponibles, mais pour le suivre, de loin, depuis le début, je dirais que <a href="https://oclock.io/">son école</a> est certainement une bonne option.</p>

    ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>PHP : How to set an array of enum values with type check and deduplication ?</title>
      <link href="https://notes.christophevergne.fr/posts/2024/09/24-php-array-enum-check-deduplication/"/>
      <updated>2024-09-24T00:00:00Z</updated>
      <id>https://notes.christophevergne.fr/posts/2024/09/24-php-array-enum-check-deduplication/</id>
      <content type="html">
        <![CDATA[
      <p>Enum is a very powerful addition to PHP in replacement of constants to be able to set defined values as an argument of a method, in a property, etc.</p>
<p>And with type check, you ensure the value given is one of the enum.</p>
<p>But what if we need to set multiple enum values to our method or property, as an array ?
PHPDoc is available to indicate what type we expect in the array, but we won't have any type check.</p>
<p>So how to do that ?
Variadic arguments to the rescue :</p>
<pre class="language-php"><code class="language-php"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span>

<span class="token keyword">enum</span> <span class="token class-name-definition class-name">Fruit</span><span class="token punctuation">:</span> <span class="token keyword type-declaration">string</span> <span class="token punctuation">{</span>
    <span class="token keyword">case</span> <span class="token constant">Apple</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'apple'</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token constant">Banana</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'banana'</span><span class="token punctuation">;</span>
    <span class="token keyword">case</span> <span class="token constant">Cherry</span> <span class="token operator">=</span> <span class="token string single-quoted-string">'cherry'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">class</span> <span class="token class-name-definition class-name">FruitBasket</span>
<span class="token punctuation">{</span>
    <span class="token keyword">protected</span> <span class="token keyword type-declaration">array</span> <span class="token variable">$fruits</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">__construct</span><span class="token punctuation">(</span><span class="token keyword type-hint">array</span> <span class="token variable">$fruits</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        <span class="token variable">$this</span><span class="token operator">-></span><span class="token function">setVariadicFruits</span><span class="token punctuation">(</span><span class="token operator">...</span><span class="token variable">$fruits</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">protected</span> <span class="token keyword">function</span> <span class="token function-definition function">setVariadicFruits</span><span class="token punctuation">(</span>Fruit <span class="token operator">...</span><span class="token variable">$fruits</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span>
    <span class="token punctuation">{</span>
        <span class="token variable">$this</span><span class="token operator">-></span><span class="token property">fruits</span> <span class="token operator">=</span> <span class="token function">array_unique</span><span class="token punctuation">(</span><span class="token variable">$fruits</span><span class="token punctuation">,</span> <span class="token constant">SORT_REGULAR</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token variable">$basket</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FruitBasket</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name static-context">Fruit</span><span class="token operator">::</span><span class="token constant">Apple</span><span class="token punctuation">,</span> <span class="token class-name static-context">Fruit</span><span class="token operator">::</span><span class="token constant">Banana</span><span class="token punctuation">,</span> <span class="token class-name static-context">Fruit</span><span class="token operator">::</span><span class="token constant">Cherry</span><span class="token punctuation">,</span> <span class="token class-name static-context">Fruit</span><span class="token operator">::</span><span class="token constant">Banana</span><span class="token punctuation">,</span> <span class="token class-name static-context">Fruit</span><span class="token operator">::</span><span class="token constant">Cherry</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></code></pre>

    ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Eleventy</title>
      <link href="https://notes.christophevergne.fr/posts/2024/11/4-eleventy/"/>
      <updated>2024-11-04T00:00:00Z</updated>
      <id>https://notes.christophevergne.fr/posts/2024/11/4-eleventy/</id>
      <content type="html">
        <![CDATA[
      <p>Il y a quelques années quand j'ai lancé ce &quot;blog&quot;, je sortais de plusieurs projets en WordPress, et je m'étais dit que ce serait une bonne idée de continuer avec, ne serait-ce que pour suivre son évolution.</p>
<p>J'avais eu la fausse bonne idée de version et le projet, ce qui bloquait alors la possibilité de mise à jour via l'admin puisque cela aurait désynchronisé le dépôt git. Le déploiement était à l'époque quelque peu artisanal, mais tout de même automatisé.</p>
<p>Avec le peu d'activité par ici, c'est donc tout naturellement que le WordPress est devenu plus qu'obsolète.</p>
<p>J'avais hésité avec un générateur de site statique, en l'occurrence Eleventy, mais je l'avais mis de côté pour des raisons que j'ai oublié depuis.</p>
<p>Plutôt que de mettre à jour le WordPress et parce qu'un site statique est sans doute ce qui se fait de mieux en terme de performances, j'ai décidé de redonner une chance à Eleventy.</p>
<p>Cela était motivé également par le fait de pouvoir écrire plus facilement en markdown, même depuis mon smartphone.</p>
<p>On verra donc comment ça évolue.</p>
<p>À suivre…</p>

    ]]>
      </content>
    </entry>
  
    
    <entry>
      <title>Conventional Commits</title>
      <link href="https://notes.christophevergne.fr/posts/2024/12/14-conventional-commits/"/>
      <updated>2024-12-14T00:00:00Z</updated>
      <id>https://notes.christophevergne.fr/posts/2024/12/14-conventional-commits/</id>
      <content type="html">
        <![CDATA[
      <p>Comme chaque année, il y la fantastique initiative &quot;<a href="https://www.24joursdeweb.fr">24 jours de Web</a>&quot; qui est un calendrier de l'avent où chaque jour un article est publié autour du web.</p>
<p>Je suis du coup tombé sur l'article &quot;<a href="https://www.24joursdeweb.fr/2024/git-lucky-jouer-en-harmonie-grace-a-conventional-commits">Git Lucky: Jouer en harmonie grâce à Conventional Commits</a>&quot; de <a href="https://clemlatz.dev">Clément Latzarus</a>.</p>
<p>J'ai tendance à préférer les conférences aux articles parfois trop longs, mais celui-ci est très bien structuré, bien ponctué d'illustrations et d'exemples, ce qui en fait un article très agréable à lire.</p>
<p>Je connaissais déjà <strong>Conventional Commits</strong>, même si je pensais (à tort) qu'il s'agissait d'un standard, d'une convention, et non d'une spécification plutôt souple de base quand à son implémentation.</p>
<p>Par le passé j'ai déjà tenté de l'utiliser dans un ou deux projets (<em>perso comme pro</em>), sans vraiment m'y tenir pour plusieurs raisons :</p>
<ul>
<li>J'étais le seul sur le projet à l'utiliser : ce n'est pas contraignant sur un projet personnel où l'on est seul, mais du coup sur un projet à plusieurs ça n'a presque aucun intérêt ;</li>
<li>Il n'y avait pas vraiment de convention déterminée à l'avance sur quels mots-clés utiliser ;</li>
<li>J'ai beau utiliser Git en <acronym title="Command Line Interface">CLI</acronym>, devoir se souvenir systématiquement de tous les mots clés et écrire à la main la structure, même si elle est extrêmement simple, c'est contraignant et peut vite décourager.</li>
</ul>
<p>J'ai donc cherché rapidement s'il existait un utilitaire permettant de faciliter l'écriture des messages en <strong>Conventional Commit</strong>, idéalement de manière interactive. Pas forcément une réelle interface puisqu'il est tout de même relativement simple d'avoir un minimum d'interactivité en <acronym title="Command Line Interface">CLI</acronym>, surtout qu'il s'agit là majoritairement de questions structurées.</p>
<p>C'est en cherchant que je me suis souvenu qu'à l'époque, j'avais alors utilisé <a href="https://commitizen-tools.github.io/commitizen/">Commitizen</a>.</p>
<p>Mais je suis tombé sur un autre utilitaire, <a href="https://github.com/cococonscious/koji">Koji</a>, qui semble proposer davantage de fonctionnalités, et en tout cas de souplesse sur la configuration sans forcément imposer ses choix.</p>
<p>À tester donc.</p>

    ]]>
      </content>
    </entry>
  
</feed>