eZecosystem / Mirror / Damien Pobel

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS correspondant)

09/20/2018 07:07 am   pwet.fr/blog   Mirror   Link  

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS correspondant)

09/13/2018 05:42 am   pwet.fr/blog   Mirror   Link  

C'est la rentrée alors c'est reparti pour la veille hebdomadaire !

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS correspondant)

09/06/2018 06:55 am   pwet.fr/blog   Mirror   Link  
  • PHP: Never type hint on arrays (en) : array ne donne quasi aucune information et d'une manière générale (il y a toujours des exceptions…), un type hint sur un type précis spécifique au projet est mieux que l'utilisation des types primitifs du langage.
  • The First Thing That Ever Sold Online Was Pizza (en) : ahah :) et le plus génial, 24 ans plus tard, le formulaire marche probablement toujours (malheureusement le lien vers ce bout d'histoire d'Internet redirige sur le site de PizzaHut…)
  • Logging Activity With The Web Beacon API (en) : Une API web plutôt méconnue qui peut rendre service pour envoyer des messages de manière non urgente à un serveur.
  • Art of debugging with Chrome DevTool (en) : des astuces plutôt intéressantes et utiles, notamment le console.log en point d'arrêt conditionnel ou le console.log({ foo, bar }) au lieu de console.log(foo, bar) qui permet de logger à la fois la valeur et son nom. D'ailleurs, ces 2 là doivent fonctionner aussi dans Firefox.
  • How to Read an RFC (en) : quelques clarifications sur comment aborder les RFC, ces documents qui standardisent les protocoles sur Internet.
  • How to add product features without making it more complex (en) : une clé exposée dans cette article est de construire des interfaces ou des fonctionnalités utilisables par défaut.
  • The Cost Of JavaScript In 2018 (en) : Let’s design for a more resilient mobile web that doesn’t rely as heavily on large JavaScript payloads.

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

08/02/2018 06:35 am   pwet.fr/blog   Mirror   Link  

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

07/26/2018 06:25 am   pwet.fr/blog   Mirror   Link  
Un chien sous une couverture

Le code coverage ou la couverture de code par les tests en bon français est probablement l'une des métriques les plus incomprise et l'un des concepts les plus maltraité lorsqu'on parle de tests logiciels et de qualité de code en général. C'est d'ailleurs un bon sujet de conversation pour animer un open space rempli de développeur·ses un tant soit peu intéressé·es par les tests. Mais au fait qu'est-ce que c'est au juste ?

D'après Wikipédia:

En génie logiciel, la couverture de code est une mesure utilisée pour décrire le taux de code source exécuté d'un programme quand une suite de test est lancée.

Si on met de côté le fait qu'en fonction des outils, des configurations ou de qui extrait cette valeur, ce taux est un pourcentage d'instructions, de branches, de fonctions ou de lignes, il n'y a rien de très compliqué. Mais généralement, les choses se corsent dès lors qu'il s'agit d'interpréter ce nombre. Doit on absolument viser 100% ? Je plafonne à 40%, est-ce grave ? À partir de quel pourcentage mon code est il bien testé ? Pourquoi je ne parviens pas à couvrir les 2 cas qui me permettrait d'arriver à 100% ? Et bien d'autres… À ces questions relativement légitimes s'ajoute le fait que ce sujet a le pouvoir de polariser bon nombre de personnes sur des positions extrêmes avec d'un côté les partisans du il faut atteindre 100% de couverture pour bien tester et de l'autre les défenseurs du le taux couverture des tests ne sert à rien.

Assez paradoxalement, chaque camp n'a pas totalement tort. Ce paradoxe tient au fait que le taux couverture ne mesure que l'exécution d'une portion de code, ou en d'autres termes, un bout de code peut être couvert mais mal voire pas du tout testé. Par exemple, si dans un test vous appelez une fonction sans jamais vérifier directement ou indirectement sa valeur de retour, elle fera partie du code couvert mais on ne peut pas considérer qu'elle soit bien testée. À partir de là, on comprend bien la faiblesse de cette métrique. Elle est d'ailleurs d'autant plus faible qu'il est possible de gonfler artificiellement le taux de couverture. En effet, la plupart (tous ?) des outils permettent d'ignorer des morceaux de code soit grâce à des annotations dans le code, soit en se basant sur le nom des fichiers. Hormis lorsqu'il s'agit d'exclure des dépendances, j'ai toujours trouvé étrange l'utilisation de cette fonctionnalité qui transforme une métrique déjà faible en une métrique faible et fausse.

Malgré tout, le taux de couverture peut être un outil intéressant. Si sa valeur absolue à un instant t reste relativement anecdotique, mesurer son évolution dans le temps est un indicateur déjà plus pertinent. En fonction de l'historique du projet et si l'équipe a décidé de diriger des efforts sur les tests (et d'écrire de bons tests), le code coverage devrait soit rester relativement stable, soit augmenter dans le temps mais sauf exception, il ne devrait pas baisser significativement. Une autre manière de voir ce phénomène est de considérer que, passée la phase de prototypage où généralement on écrit peu de tests, toute modification du projet devrait venir avec des tests qui couvrent au maximum ces changements. Au fur et à mesure des évolutions et par refactorings successifs, le taux de couverture va donc mécaniquement et progressivement augmenter. Dans cet exercice, le rapport de couverture constitue un outil précieux en permettant de naviguer dans le code source tout en différenciant les parties couvertes du code qui ne l'est pas. D'ailleurs, viser un maximum de couverture pour chaque (petit) changement a aussi la vertu de pousser vers une certaine simplification du code pour éliminer du code inutile et donc difficilement testable.


Si on en fait pas une religion, le code coverage peut être un outil intéressant. Mais plutôt que de le considérer sur l'ensemble du projet, il me semble nettement plus pertinent de le prendre en compte sur de petites modifications où il est plus simple de vérifier que la couverture provient de tests de qualité. À noter qu'il est possible de tester l'efficacité des tests et la réalité du taux de couverture avec des tests de mutations (mutation testing) mais ce sera pour un autre billet.

07/23/2018 03:45 pm   pwet.fr/blog   Mirror   Link  
  • Objects should be constructed in one go (en) : réflexions intéressantes sur l’instanciation des objets et surtout sur comment garantir la cohérence de ceux-ci à tout moment dans une application.
  • Programming Sucks (en) : bon peut-être pas à ce point là mais on s'en approche parfois :-)
  • Defining Component APIs in React (en) : des bons conseils et en y regardant de plus près, en changeant quelques mots, ce sont pour la plupart des déclinaisons façon React de conseils de programmation qui s'appliquent partout ou presque.
  • What's So Great About OOP? (en) : Remember, OOP is about more than just a single object here or there. The benefits of OOP emerge in a community of objects, when objects begin collaborating with each other.
  • When 7 KB Equals 7 MB (en) : quelques subtilités dans la gestion du cache de ressources venant de CDN dans une Progressive Web App
  • Automating Accessibility and Performance Testing with Puppeteer and AxeCore (en) : une chouette utilisation de puppeteer pour tester sur une plateforme d'intégration continue à la fois l'accessibilité et les performances d'une application. Pour ce dernier cas, Chrome est configuré avec puppeteer pour simuler un CPU et/ou un connexion lente.
  • I Want Scalar Objects in PHP (en) : MOI AUSSI :)

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

07/19/2018 06:45 am   pwet.fr/blog   Mirror   Link  

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

07/12/2018 06:26 am   pwet.fr/blog   Mirror   Link  

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

07/05/2018 07:31 am   pwet.fr/blog   Mirror   Link  
  • I discovered a browser bug (en) : L'histoire de la découverte d'un bug de sécurité dans les navigateurs…
  • React Native at Airbnb (en) : Une série d'article expliquant pourquoi Airbnb abandonne React Native pour ses applications mobiles. Plutôt instructif même si il semble que l'abandon ne soit pas uniquement une question technique.
  • Pixels vs. Ems: Users DO Change Font Size (en) : il semble que oui certains utilisateurs changent la taille de police par défaut des navigateurs. Un argument de poids pour utiliser des unités relatives.
  • Le danger de l’élégance (fr) : et même le piège de l'élégance, comme souvent le piège se refermera quand il faudra maintenir ce code
  • Integers and Estimates (en) : de la difficulté l'impossibilité d'estimer :-)
  • Introducing the Single Element Pattern (en) : des règles et des suggestions intéressantes (et un outil pour vérifier leur application) à suivre lors de l'écriture de composant notamment React.
  • Anti-If: The missing patterns (en) : Quelques patterns pour se débarrasser des if. Tous ne sont pas à supprimer mais au delà de ça, ces conseils sont plutôt bons (surtout les 3 premiers)
  • DevTube (en) : Des vidéos pour développeur·se, encore des vidéos de pour dév…

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

06/28/2018 06:00 am   pwet.fr/blog   Mirror   Link  

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

04/05/2018 05:12 am   pwet.fr/blog   Mirror   Link   @8

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

03/29/2018 05:12 am   pwet.fr/blog   Mirror   Link   @12

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

03/22/2018 06:12 am   pwet.fr/blog   Mirror   Link   @8
  • En finir avec les bugs (fr) : non pas de recette magique dans ce billet, plutôt un plaidoyer pour regarder la vérité en face :)
  • Being in control of time in PHP (en) : Une manière élégante de rendre explicite et testable du code qui utilise une date.
  • The Practical Test Pyramid (en) : Une approche pratique et relativement pragmatique des tests automatisés (unitaires, fonctionnels, d'intégration, end-to-end, ...). C'est un peu long mais plein de bons conseils.
  • Why GitHub Won't Help You With Hiring (en) : Je serais pas aussi catégorique (et je dis pas ça parce mon compte est approximativement le 64 392 plus suivi :-)). Le profil Github est une information comme un joli CV, des recommandations sur Linkedin, un blog ou autre. Mais en effet, se baser uniquement là dessus est totalement ridicule.
  • How to write a git commit message that won't disappoint your future self (en) : sans doute discutable sur certains aspects mais trop souvent, les messages de commits ne sont assez pris au sérieux et pourtant ils sont là pour rester.
  • The Struggle (en) : tellement vrai :-)
  • Notes for new Make users (en) : pour les nouveaux utilisateurs de Make (et aussi pour les plus anciens qui auraient oublié quelques subtilités avec les années ;))

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

03/15/2018 06:12 am   pwet.fr/blog   Mirror   Link   @6

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

03/08/2018 05:12 am   pwet.fr/blog   Mirror   Link   @10

Compressing served files is a very usual trick to increase the loading performance of a website. The principle, defined in HTTP 1.1, is quite simple: when requesting a file, the browser announces the encoding it accepts in the Accept-Encoding header (for instance gzip) and thanks to it, the server knows how it can serve the file.

Typically, this is done on the fly by the web server with a dedicated module, for instance in Apache, mod_deflate does that pretty well (I've been using it for years (fr)) and nowadays this requires almost no configuration besides being activated unless you want to support the venerable most-hated browser of all time aka Internet Explorer 6 :)

Alternatively, it's possible to pre-generate compressed files along with the normal ones to serve the best one supported by the browser visiting your website. This has the advantage of requiring almost no resource on the web server while allowing you to use the highest compression level available even this takes a bit of time. And depending on the static site generator this is maybe super simple to setup.

So in this post, I'm gonna try to compress each page with Gzip and Brotli and to configure Apache to serve the best possible version.

Brotli ?

According to Wikipedia:

Brotli is a data format specification for data streams compressed with a specific combination of the general-purpose LZ77 lossless compression algorithm, Huffman coding and 2nd order context modelling. [...]

Brotli was first released in 2015 for off-line compression of web fonts. The version of Brotli released in September 2015 by the Google software engineers contained enhancements in generic lossless data compression, with particular emphasis on use for HTTP compression.

Brotli logo

If I believe caniuse.com, Brotli is now supported by most browsers. As usual, only Internet Explorer (11 and below) and Safari (before High Sierra) are a bit behind so for those and for probably tons of bots out there, Gzip compressed files or uncompressed files are still useful.

Brotli files are said to offer a higher compression rate than Gzip while remaining fast to decode. On the other hand, Brotli is also known to be slower to compress especially if you are using the highest compression level. Let's have a look at that.

Compressing files

Since I'm using Metalsmith to generate this web site, I can use metalsmith-gzip and metalsmith-brotli to compress generated documents. Both plugins are very similar and are configured to compress files matching the regular expression /\.[html|css|js|json|xml|svg|txt]/. I just had to configure metalsmith-gzip to compress at level 9 instead of 6 by default.

If you use Metalsmith, that's pretty much it! Of course, it's possible to do the same with a "simple" shell oneliner, something like:

find path/to/files -type f -a \( -name '*.html' -o -name '*.css' -o -name '*.js' \
-o -name '*.json' -o -name '*.xml' -o -name '*.svg' -o -name '*.txt' \) \
-exec brotli --best {} \+ -exec gzip --best -k {} \+

Apache configuration

This part is a bit tricky, at least it took me some time to figure it out, especially the part about preventing the double compression when you still need mod_deflate for other websites.

First, you need to make sure that mod_mime, mod_headers and mod_rewrite are enabled in Apache. Under Debian, if you are unsure just run as root:

# a2enmod mime
# a2enmod headers
# a2enmod rewrite

Then, the VirtualHost for your website requires a bit of configuration. Here is the relevant configuration excerpt for serving my pre-compressed website:

# Otherwise Content-Language: br is added
# Only needed if mod_mime configures that language
# in /etc/apache2/mods-enabled/mime.conf
RemoveLanguage .br

# Encoding for Brotli files
AddEncoding br .br

# Set gzip encoding instead of setting as a Content Type
RemoveType .gz
AddEncoding x-gzip .gz

# Mapping foo.suffix.gz or foo.suffix.br => Type
# see following repositories for recognized suffixes
# https://github.com/michel-kraemer/metalsmith-brotli
# https://github.com/ludovicofischer/metalsmith-gzip
AddType "text/html" .html.br .htm.br .html.gz .htm.gz
AddType "text/css" .css.br css.gz
AddType "text/plain" .txt.br txt.gz
AddType "text/xml" .xml.br .xml.gz
AddType "application/javascript" .js.br .js.gz
AddType "application/json" .json.br .json.gz
AddType "image/svg+xml" .svg.br .svg.gz
# Depending on what you compress, some more might be needed

# Proxy configuration
Header append Vary Accept-Encoding

RewriteEngine On

RewriteCond %{HTTP:Accept-Encoding} br
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}.br -s
RewriteRule ^(.*)$ %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}.br [E=no-gzip,L]

RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}.gz -s
RewriteRule ^(.*)$ %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}.gz [E=no-gzip,L]

So to explain it shortly:

  • this changes the configuration so that .br and .gz files have the same type for Apache as the ones without those suffixes. This has to be in sync with what is done by the static site generator or your shell script.
  • if a browser accepts Brotli compressed files and the requested file exists with a .br suffix, serve this file.
  • if a browser accepts Gzip compressed files and the requested file exists with a .gz suffix, serve this file.
  • in both cases, if the file with the suffix is served, the no-gzip environment variable is set so that mod_deflate does not try to compress again the file.

And that's it for serving pre-compressed files! You can see in the network panel that files are now served with Content-Encoding: br and maybe loading feels a bit snappier.

Screenshot of Firefox dev
    tools showing the HTTP headers

Some stats

This little experiment is a good opportunity to look at some numbers about Gzip vs. Brotli vs. no compression.

Time to compress files

At their maximum compression level, Brotli is way slower than Gzip. At the time of writing, 1452 files are matching the regular expression mentioned above. On my Macbook pro, metalsmith-gzip takes less than 400 milliseconds to compress those while for Brotli, this takes almost 6 seconds! Using the shell version, I find out that it takes almost 24 seconds to compress those files with Brotli and a bit more than 1 second for Gzip.

Even if in this setup, this does not matter much, it's interesting to note that the difference is somehow of an order of magnitude.

Resulting sizes

After all, that's the point of compressing, so let's have a look at the resulting size of some files (unless mentioned, sizes are in bytes).

File(s) Size Gzip Brotli Gzip - Brotli
Homepage 8293 239929% 199124% -408
RSS feed 57368 1963634% 1699830% -2638
Main stylesheet 10943 303428% 259124% -443
robots.txt 24 44183% 28117% -16
Posts index 6772 189228% 158723% -305
Latest post in English 13814 443732% 368127% -756
Total 11.65Mb 4Mb34% 3.4Mb29% -579Kb

Almost no surprise here, Brotli compressed files are about 5% (of the initial size) smaller than the Gzipped one. Given that most of my pages are quite small already, that's not a lot in absolute value but still an interesting gain. Only exceptions to that are very small files like my robots.txt where compressed ones are bigger than the original. So for the sake of completeness, I should not compress those but we are talking of 4 or 20 bytes depending on the algorithm :)

03/05/2018 02:10 am   pwet.fr/blog   Mirror   Link  
  • 5 Questions Every Unit Test Must Answer (en) : Une synthèse intéressante tant il est facile se perdre pendant l'écriture de tests unitaires.
  • Mutation testing with infection in big PHP projects (en) : où finalement on peut se mettre à tester les tests :-) Blague à part, il est surtout intéressant de comprendre qu'un code couvert 100% par des tests ne veut pas dire que le code est bien testé. Et dans ce cadre, ce type d'outil permet d'approcher la couverture réelle du code par les tests.
  • Using Vim to View Git Commits (en) : Vim (ou neovim) est non seulement capable d'afficher les logs git mais est aussi capable de permettre la navigation dans les commits!
  • WIP de 1, une histoire de WIP limits qui finit bien (fr) : Retour d'expérience intéressant sur la définition du paramètre WIP (Limitation du Work In Progress/Process) en Kanban.
  • Lasagna code - too many layers? (en) : Matthias Noback est comme d'habitude très pertinent avec plusieurs bons conseils dans ce billets.
  • Third party CSS is not safe (en) : Au delà du Keylogger en CSS qui a agité le petit monde du développement web dernièrement, l'inclusion d'une feuille de style externe expose à d'autres problèmes de sécurité.
  • The inception of ESLint (en) : la genèse du maintenant fameux projet ESLint
  • Genuine guide to testing React & Redux applications (en) : Un article plein de bon sens sur une stratégie de test possible d'une application React/Redux. Pour résumer, tests unitaires et tests d'intégration peuvent être complémentaires. Le paragraphe sur les snapshot tests me paraît également très pertinent.

Et un peu totalement hors-sujet :

  • Une chanson, l'addition (fr) : Une chaîne Youtube vraiment sympa qui présente chaque semaine en moins de 3 minutes l'histoire d'une chanson.

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

03/01/2018 06:57 am   pwet.fr/blog   Mirror   Link   @6

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

02/22/2018 05:16 am   pwet.fr/blog   Mirror   Link   @14

Via le Journal du Hacker, je suis tombé sur Config pour ne plus taper ses mots de passe MySQL et plus encore avec les Options file qui rappelle que le client MySQL en ligne de commande propose un fichier de configuration (~/.my.cnf) permettant de se simplifier la vie si on se connecte toujours aux mêmes machines/bases. Ce billet montre aussi l'option pager de ce fichier de configuration qui, comme son nom l'indique, permet de configurer un pager (more, less, neovim, ... ou ce que vous voulez) que l'auteur utilise pour mettre de la couleur dans le client MySQL / MariaDB avec Generic Colouriser. Bref, ce sont deux très bonnes astuces pour les utilisateurs de mysql en ligne de commande dont je fais partie.

Il se trouve qu'en plus, au travail, j'utilise une machine virtuelle. Et donc, pour accèder à MySQL, il me faut d'abord faire ouvrir un shell avec ssh pour ensuite lancer le client. Bien sûr, un bête alias permet de faire tout ça plus rapidement mais j'aime bien avoir mes outils de développement en local. En cherchant comment installer le client MySQL (et uniquement celui-ci) sur mon Mac, je suis tombé sur mycli et autant de le dire tout de suite, j'ai abandonné l'idée d'installer le client officiel :) En fait, mycli est un client MySQL (compatible avec MariaDB ou Percona) qui vient avec tout un tas de fonctionnalités vraiment pratiques et bien documentées comme la coloration syntaxique des requêtes, l'édition multi-ligne ou non, quelques commandes pratiques et surtout un complètement intelligent !

Capture d'écran de mycli dans un terminal

Il a sa propre configuration dans ~/.myclirc (qu'il génère au premier lancement avec les commentaires, encore une bonne idée) mais le plus beau, c'est qu'il utilise aussi ~/.my.cnf le fichier de configuration du client officiel et donc les 2 astuces citées plus haut fonctionnent parfaitement et directement dans cet outil !

Bref, pour le moment, mon .myclirc est celui par défaut (sauf le thème fruity) et mon .my.cnf ressemble à 

[client]
user = MONUSER
password = PASSWORD
host = vm.local

# ~/.grcat/mysql provient de https://github.com/nitso/colour-mysql-console
pager = 'grcat ~/.grcat/mysql|most'

J'utilise most comme pager mais j'hésite encore avec less qui propose une option pour ne pas paginer lorsque les données sont trop courtes ou Neovim dont j'ai vraiment l'habitude.

Dernier point, vous n'utilisez pas MySQL (ou MariaDB ou Percona) ? Pas de problème, l'auteur a écrit le même genre de clients pour d'autres serveur de base de données.

02/17/2018 11:28 am   pwet.fr/blog   Mirror   Link   @24

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

02/15/2018 06:13 am   pwet.fr/blog   Mirror   Link   @27

Ce texte est une traduction de l'excellent A Tale of Two Rooms: Understanding screen reader navigation.

Pour ceux d'entre nous qui utilisent un lecteur d'écran comme JAWS, NVDA or VoiceOver pour accéder au Web, l'expérience utilisateur peut être très différente de celle et ceux qui peuvent visualiser le contenu. J'ai donné de nombreuses formations sur l'accessibilité dont l'un des buts est d'aider les stagiaires à mieux comprendre la navigation sur le web à l'aide d'un lecteur d'écran.

Il est courant pour la plupart des gens de vouloir passer directement aux détails techniques 

  • Quelles touches du clavier presser ?
  • Avec quel lecteur d'écran devrais je tester ?
  • Quel navigateur devrais je utiliser ?

Ces considérations sont importantes mais il est préférable de prendre un peu de recul et de se demander :

À quoi ressemble cette expérience et comment puis je la simuler si je peux voir l'écran ?

À cette fin, je voudrais présenter plusieurs illustrations qui ont été efficaces pour mieux appréhender cette situation.

Une porte ouverte

Commençons par définir la scène de notre première histoire. Imaginez vous venez d'ouvrir une porte et vous regardez dans une vaste salle de conférence. Au centre de la pièce se trouve une grande table avec 10 chaises (5 de chaque côté de la table). Deux hommes et deux femmes sont installées à cette table. Ces 4 personnes se trouvent du même côté de la table (ils et elles font face à la porte où vous vous tenez). À l'autre bout de la pièce (derrière ces personnes) se trouvent 3 grandes fenêtres qui donnent sur une cour avec des bancs, des fleurs et de petits arbres. Sur la partie droite de la pièce, se trouvent un comptoir avec une cafetière et un micro-onde. Sur la gauche, une écran plat est fixé au mur.

En supposant que vous ne connaissiez pas la disposition de cette pièce, quelle est la première chose que vous feriez en ouvrant la porte ? Certains balaieraient la pièce de gauche à droite. D'autres le feraient de droite à gauche. D'autres encore regarderaient d'abord la table au centre puis parcourraient les contours de la pièce. Peu importe comment vous le feriez, la plupart balaieraient la pièce du regard pour avoir un rapide aperçu de la disposition et du contenu de la pièce. Le balayage ne prendrait que quelques secondes et la plupart d'entre vous le ferait sans même y penser. Ensuite, vous vous pourriez vous concentrer sur certains points comme les personnes assises autour de la table ou l'écran de télévision au mur.

Une pièce plongée dans le noir

Maintenant, reprenons la même scène et cette fois, quand vous ouvrez la porte, la pièce est totalement dans le noir. Aucune lumière n'est présente et par conséquent vous ne pouvez absolument rien distinguer au premier coup d'œil. On vous a donné une petite lampe de poche et en étant allumée, elle vous permet de voir une toute petite zone. Cette zone visible est un petit cercle d'environ 60 centimètres de diamètre et rien en dehors de ce cercle n'est éclairé.

Comment allez vous observer le contenu de cette pièce ?

Certains d'entre vous feraient faire des allers-retours de gauche à droite à la lampe en partant des pieds et en s'éloignant progressivement. Certains commenceraient par le fond de la pièce avec la lampe face à eux alors que d'autres pourraient pointer la lampe au hasard à différents endroits sans schéma particulier. En déplaçant la lampe, il vous faudrait construire une carte mentale ou une image de ce qui se trouve dans la pièce et de comment elle est organisée. Construire cette image mentale prendra nettement plus de temps que de balayer la pièce illuminée. En déplaçant la lampe, il vous faudra vous souvenir de chaque chose et de comment elle se positionne par rapport aux autres. Si vous oubliez l'emplacement de quelque chose, il vous faudra un certain temps pour la retrouver.

Le comptoir avec la cafetière était-il sur la droite ou au fond de la pièce ? Combien de personnes étaient assises autour de la table ? 4 ou peut-être 5 ?

Répondre à ces questions quand vous pouvez voir l'ensemble de la pièce en un coup d'œil ne demande que peu d'effort mais y répondre quand vous ne pouvez voir qu'une petite zone à la fois est beaucoup plus long.

Un scénario analogue

Ce second scénario est analogue à comment un utilisateur ou une utilisatrice d'un lecteur d'écran perçoit une page web ou un application pour smartphone.

Bien qu'une commande au clavier ou l'utilisation de l'écran tactile permette de déplacer le lecteur d'écran sur la page, il n'est toujours possible de lire qu'une chose à la fois. L'utilisateur ou l'utilisatrice malvoyante n'a aucun moyen d'avoir un aperçu rapide (disons en 1 à 3 secondes) de la page comme une personne qui peut voir l'écran.

Heureusement, des mécanismes techniques d'accessibilité comme des titres ou des régions peuvent aider l'utilisateur ou l'utilisatrice d'un lecteur d'écran à se concentrer sur certaines parties de la page.

De retour dans notre scénario avec la pièce sombre, imaginez qu'il y ait maintenant un petit point rouge lumineux sur chaque élément important de la pièce comme la table, le comptoir, la télévision et sur chaque personne autour de la table. Vous auriez toujours besoin de la lampe de poche pour explorer la zone mais les points rouges vous donneraient une idée de l'emplacement des choses importantes.

Les changements dynamiques de contenu d'une page peuvent être un autre défi pour les personnes utilisant un lecteur d'écran. Reprenons nos exemples de pièce sombre et de lampe de poche. Imaginons maintenant qu'un des hommes se lève pour se déplacer de l'autre côté de la table. Il y a maintenant 2 femmes et un homme d'un côté de cette table et un homme de l'autre. Dans le scénario de la pièce éclairée, vous remarqueriez très probablement le mouvement au moment où il se produit. Même si vous n'étiez pas en train de regarder l'homme qui s'est déplacé, vous auriez remarqué le déplacement du coin de l'œil et vous vous seriez tourné pour regarder ce qui était en train de se produire. Dans le scénario de la pièce plongée dans le noir, il serait très difficile de remarquer que quelque chose s'est produit à moins d'avoir pointé la lampe de poche sur l'homme en déplacement à au bon moment. Il est fort probable que vous n'auriez remarqué son déplacement qu'après avoir pointé la lampe sur la chaise laissée vacante.

C'est exactement ce qui se produit lorsque le contenu d'une page change sans alerter le lecteur d'écran. L'utilisateur ou l'utilisatrice peut ne jamais voir le changement à moins de se déplacer vers la nouvelle information et remarquer la différence.

Ce problème est soluble en s'assurant que les contenus dynamiques sont mis en œuvre avec des techniques d'alerte ou de zones "live" ce qui permet au lecteur d'écran d'annoncer la mise à jour à l'utilisateur ou l'utilisatrice.

Dans notre exemple de la pièce plongée dans le noir, l'homme pourrait annoncer qu'il est en train de bouger de l'autre côté de la table. Même si la lampe de poche n'était pas pointée vers lui, vous entendriez son annonce et vous pourriez comprendre la situation.

Pour terminer, regardons du côté de la fenêtre qui donne sur la cour. Dans le scénario de la pièce éclairée, vous pourriez voir rapidement que la fenêtre s'ouvre sur la cour avec des bancs, des fleurs et des arbres. Alors que dans le scénario de la pièce plongée dans le noir, même en pointant la lampe sur la fenêtre, vous ne seriez absolument pas capable de distinguer ce qui se passe dehors. Ceci illustre parfaitement ce qui se produit avec les éléments visuels comme les images lorsqu'ils n'ont pas de libellé textuel associé. Par exemple, un lecteur d'écran peut identifier qu'une image est présente dans une page mais la seule information qu'il peut communiquer sur elle est son texte alternatif. Sans ce texte, la personne utilisant le lecteur d'écran n'aura aucune idée de ce que l'image représente. Dans l'exemple de la pièce plongée dans le noir, ce texte pourrait être placé à côté de la fenêtre et pourrait décrire ce qu'il y a dehors. En localisant la fenêtre avec la lampe de poche, vous pourriez alors lire la description.

Pour une meilleure compréhension

Une des meilleures manières de comprendre l'utilisation d'un lecteur d'écran est d'essayer par vous-même. Il est probablement bénéfique d'essayer par vous même de naviguer sur le web avec un lecteur d'écran. En plus de cela, voici un exercice simple pour simuler les scénarios décris plus haut. (Je ne recommande pas visiter au hasard des salles de conférence avec des gens en éteignant les lumières !)

  1. Imprimez une page web. Prenez plutôt une page pas trop grande mais contenant une large variété d'éléments comme du texte, des liens, des menus, ...
  2. Prenez une feuille blanche et faites un petit trou en son centre. Le trou devrait être de la taille de 2 ou 3 mots (15 millimètres de diamètre environ est généralement suffisant)
  3. Placer la feuille avec le trou sur l'impression de la page de web et essayez de comprendre son contenu en déplaçant la feuille trouée.

La compréhension du contenu de la page sera probablement très compliquée et prendra du temps mais cette expérience donne une bonne idée de l'utilisation d'un lecteur d'écran (en particulier si aucune technique de navigation n'est mise en œuvre).

02/08/2018 04:59 pm   pwet.fr/blog   Mirror   Link   @8

Et un peu hors-sujet :

  • Pourquoi y a-t-il des gauchers ? (fr) : Bah en fait, on sait pas trop et en plus on n'est pas forcément 100% gaucher ou droitier... Bref, la vidéo est passionnante :-)

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

02/08/2018 05:25 am   pwet.fr/blog   Mirror   Link   @10

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

02/01/2018 05:28 am   pwet.fr/blog   Mirror   Link   @12

I've been using vim (and now neovim (fr)) for more than 15 years and I still discover new tricks regularly. This post is about one of those about vim's gf command. This command allows the user to open the file whose path is under the cursor. I guess it's clear how this can be handy to explore the source code of any application where the source contains references to others files.

These days I'm working on an application built with the popular stack composed of React, Redux, Babel and Webpack (and 2876 more friends ;-)) where quite obviously import is used to load dependencies of a given module. For those who don't know the import statement yet, as usual MDN provides a nice documentation about it. So the application source code contains code like:

// this file is src/common/mymodule.js
// Note: I always run neovim at the project root

import whatever from 'path/to/dependency';
import relative from './relative/path/to/dependency';

Depending, on your stack and in my case depending on Webpack configuration, import path resolution can be quite complicated. In my case, the first one could mean:

  • path/to/dependency.js
  • path/to/dependency/index.js
  • src/path/to/dependency.js
  • src/path/to/dependency/index.js
  • node_modules/path/to/dependency.js
  • node_modules/path/to/dependency/index.js

While the second one potentially means:

  • src/common/relative/path/to/dependency.js
  • src/common/relation/path/to/dependency/index.js

The path can also reference a CSS file (path/to/file.css) or a SVG file (path/to/file.svg) with the same resolution directories or even a node module which means the main file of that module should be imported:

import stuff from 'a-node-module'
// means importing
// node_modules/a-node-module/<path indicated in main entry of package.json>

Initially, I thought I would need a plugin so that gf is able to resolve all those paths. I even tested some but they failed for me. After a deeper look at gf documentation, it turns out that 2 lines of configuration to set path and suffixesadd allows to almost solve the issue:

set path=.,src,node_nodules
set suffixesadd=.js,/index.js

With that configuration, when hitting gf, neovim (or vim) will try to load the file in the given paths with the suffixes. The only case not fully solved by this is the one where the path refers to the main file of a node package, with the configuration above, neovim will open the directory node_modules/a-node-module which is already quite nice but for sure neovim can do better :)

This time includeexpr setting is the way out. It allows the developer to define a function to run if the editor was unable to find a file path. So by removing node_modules from the path and implementing a function, we can try to load the package.json file and build a file path with its main entry, this results in the following configuration:

set path=.,src
set suffixesadd=.js,/index.js

function! LoadMainNodeModule(fname)
    let nodeModules = "./node_modules/"
    let packageJsonPath = nodeModules . a:fname . "/package.json"

    if filereadable(packageJsonPath)
        return nodeModules . a:fname . "/" . json_decode(join(readfile(packageJsonPath))).main
    else
        return nodeModules . a:fname
    endif
endfunction

set includeexpr=LoadMainNodeModule(v:fname)

As far as I can tell, any imported module is now just a gf away from me. As a complementary tip, after using gf you can get back to the first file with Ctrl+O (as get Out) and get back again to the imported file with Ctrl+I (as get In).

The path resolution can be quite specific to the project so this configuration plays particularly well with a config by project which is also an out of the box vim feature (another trick I discovered lately ;)), in neovim just use .nvimrc instead of .vimrc.

01/30/2018 12:34 pm   pwet.fr/blog   Mirror   Link   @20

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

01/25/2018 06:58 am   pwet.fr/blog   Mirror   Link   @24

Comme je l'écrivais dans ma rétrospective 2017, j'ai pour objectif de me dégoogliser. Début janvier, j'écrivais même complètement mais plus j'y réfléchis et plus je me dis que ce sera difficile.

Mais pourquoi au fait ?

Nous, on a peur que d'une chose : que le flicage nous tombe sur l'Internet

Dégooglisons Internet l'explique bien mieux que moi. Je vois ça comme une version moderne et numérique de ne pas mettre tout ses œufs dans le même panier. J'ajoute aussi que je suis sensible aux pratiques d'optimisation d'évasion fiscale de ces grands groupes et notamment de Google et que rien ne m'oblige à l'encourager avec mes données personnelles.

Après j'ai découvert récemment l'outil My Activity de Google et y voir notamment tous les endroits où je me suis déplacé depuis plus de 5 ans fait un effet "bizarre"...

De quels services suis-je dépendant ?

Je n'utilise plus Google pour mes recherches web depuis déjà quelques années. Mon choix s'est porté vers DuckDuckGo parce que les résultats à l'époque du changement me paraissaient (et paraissent toujours) corrects et aussi parce que j'aime bien son aspect épuré... a la Google :-) Dans une optique plus européanno-patriotique, il faudrait quand même que je jette un œil à Qwant.

Mais en ce qui me concerne, le moteur de recherche web est juste la partie émergée de l'iceberg de ma google dépendance, voire même une toute petite partie. J'utilise activement pas mal de leurs services. J'ai en particulier un compte Google Apps pour mon domaine pobel.fr qui date de l'époque où l'offre était gratuite pour les particuliers. Et donc, à partir de là j'utilise les services suivants :

  • Le mail et les contacts
  • Le calendrier
  • Hangout : essentiellement pour communiquer avec ma compagne
  • Drive : pour stocker et retrouver quelques documents dont je peux avoir besoin et très occasionnellement Google Doc et Spreadsheet
  • Youtube : sans être un accro aux vidéos en ligne, j'en consulte pas mal et j'en ai publié quelques-unes soit des screencasts des fonctionnalités que je développais dans mon ancien travail, soit des vidéos des sentiers du Revermont que j'adore emprunter à VTT.
  • Je suis identifié via Google sur quelques applications/services en ligne dont certains que j'utilise activemment notamment sur le lecteur RSS Feedly qui est l'outil principal derrière ma veille techno.

Liés à mes différents sites, je suis aussi un utilisateur des plusieurs services pour webmaster :

  • Analytics : sur pwet.fr et vtt.revermont.bike des statistiques que je n'ai pas consultées depuis des mois et où un bête traitement des logs du serveur avec AWStats me serait largement suffisant.
  • Adsense : sur pwet.fr mais vu ce que ça me rapporte, je me demande pourquoi c'est encore là
  • Webmaster Tools : celui là je l'utilise de temps à autres, je trouve intéressant de voir comment Google voit mes sites (oh ironie :)) et avec quels mots-clés les utilisateurs y arrivent.

Et enfin, ce qui sera sans doute le plus compliqué à gérer, j'ai un téléphone et une tablette Android rattachées à mon compte Google. Ces deux appareils sont dans un fonctionnement classique où j'utilise le store de Google pour installer des applications (quelques-unes sont vraiment utiles) et où j'utilise aussi quelques applications Google notamment Maps ou Youtube Kids qui me semblent pour le moment assez compliquées à remplacer pour des raisons différentes ;-)

Bref, il y a plus qu'à mais ce sera pour un prochain épisode.

01/19/2018 04:58 pm   pwet.fr/blog   Mirror   Link   @18

Et un peu hors-sujet :

(En plus du flux RSS global, les billets veille et uniquement ceux là sont listés dans le flux RSS veille)

01/18/2018 05:12 am   pwet.fr/blog   Mirror   Link   @32
  • Comment différer l'exécution d'un script ? (fr) : Plusieurs techniques complémentaires pour éviter qu'une balise &lt;script&gt; ne bloque le rendu d'une page.
  • Chrome is turning into the new Internet Explorer 6 (en) : avec une différence majeure quand même: profitant de sa position dominante, Microsoft ne faisait que (lentement) corrigé les bugs de sécurité
  • How to greatly improve your React app performance (en) : Pour résumer : utiliser shouldComponentUpdate, contrôler les changements apportés au DOM et éviter les appels infinis aux callbacks avec debounce/throttle
  • Improve User Experience with Proper Webfont Loading (en) : Trois stratégies pour améliorer le chargement des polices web (web fonts). Deux d'entre elles consistent tout de même à ne pas utiliser la police sur la première page chargée par l'utilisateur. On peut donc se demander si dans ce cas là, la police est tellement indispensable...
  • I’m harvesting credit card numbers and passwords from your site. Here’s how. (en) : Une courte fiction (enfin espérons) sur comment il serait relativement facile de voler des informations confidentielles (noms d'utilisateur, mots de passe, numéros de carte bancaire, ...)  sur une grande quantité de sites web en partant d'un paquet npm. Une solution partielle pour limiter ce risque est de mettre en place une Content Security Policy. Reste que la seule vraie solution est de vérifier de quoi on dépend ou de ne dépendre de rien au moins sur les parties sensibles.
  • Ten Things I Wish I’d Known About bash (en) : 10 trucs bien utiles avec bash. Petite subtilité supplémentaire sur le point 9 pour les utilisateurs de MacOS, l'application Terminal ne lance que des shells de login, résultat ~/.bashrc n'est jamais lu par défaut.
  • This is not the DRY you are looking for (en) : Le principe DRY (Do not Repeat Yourself) est souvent mal interprété et surtout appliqué de manière dogmatique ce qui pousse à grouper/coupler plusieurs bouts de code qui n'ont rien à voir. Cet article parle de code en PHP mais s'applique en fait à n'importe quel langage.
  • Le Programme du PHP Tour 2018 à Montpellier (fr) : vraiment un chouette programme!
01/11/2018 05:12 am   pwet.fr/blog   Mirror   Link   @22
01/05/2018 06:44 am   pwet.fr/blog   Mirror   Link   @48

Aller c'est la saison des rétrospectives, voici la mienne pour 2017 :

Publications en ligne

Pas de grosse activité de ce côté, avec seulement trois billets de blog avec un peu de contenu dans l'année :

et aussi 3 photos (de Syrphes) :

La première a même eu son petit succès sur 500px :)

Sur ce blog les billets les plus lus de l'année ont été dans l'ordre :

  1. Embed a Youtube video in Github markdown
  2. Un mois avec la liseuse Touch Lux 3 Tea
  3. Passer de Vim à Neovim

Lectures

En 2017, j'ai poursuivi une bonne résolution de 2016 en lisant quelques livres :

Je n'ai pas aimé du tout Lord of the Ringards et moyennement apprécié Libérez votre cerveau ! et Ne fais confiance à personne. Tous les autres sont très bons avec des mentions spéciales pour Éloge de la différence. La génétique et les hommes, La vie secrète des arbres, Au revoir là-haut et L'Âge des low tech bien sûr.

Autre

Quoi d'autre en 2017 ? Un peu de jeu vidéo avec Battlefield 1, The Last of Us, quelques titres sur Playstation Now et maintenant Star Wars Battlefront II :-) Pas mal de jardinage dans mon potager aussi avec quelques succès notamment les pommes de terre, les carottes, les piments de Bresse, la mâche ou les concombres et quelques échecs aussi en particulier les melons.

Mais surtout 2017 restera l'année de mon départ d'eZ Systems. C'était il y'a plusieurs mois mais je suis toujours pas revenu du déroulement de toute cette affaire et du comportement de certaines personnes. Bref, c'est une grosse page qui se tourne...

Et en 2018 ?

2018 va donc commencer avec un nouveau travail chez IWD ! Après plus de trois mois de relative inactivité, j'ai vraiment hâte de commencer même si forcément ce changement s'accompagne d'un peu de stress, mais sortir (un peu) de sa zone de confort fait pas de mal de temps en temps.

Et sinon sur 2018 se reportent tous les projets et objectifs qui n'ont pas aboutis voire n'ont pas débutés en 2017 :

  • réduire mon impact sur la planète notamment la production de déchets de mon foyer
  • ouvrir un blog sur mon potager
  • refaire du VTT
  • écrire plus sur ce blog
  • prendre des photos
  • participer et parler à des conférences
  • me dégoogliser complètement
  • et sans doute plein d'autres trucs... :)

Bref, le programme est déjà bien chargé pour 2018 et sera sans doute même pas réalisé à moitié :) Il me reste à souhaiter une bonne année à toi chère/cher lectrice/lecteur qui est arrivé(e) jusqu'à ce point.

01/01/2018 10:04 am   pwet.fr/blog   Mirror   Link   @106