<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>tests - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</title><link>https://jordanchapuy.com/tags/tests/</link><description>tests - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</description><generator>Hugo -- gohugo.io</generator><language>fr</language><lastBuildDate>Tue, 01 Feb 2022 09:33:00 +0100</lastBuildDate><atom:link href="https://jordanchapuy.com/tags/tests/" rel="self" type="application/rss+xml"/><item><title>Les pratiques tech qui peuvent aider votre équipe</title><link>https://jordanchapuy.com/posts/2022/02/les-pratiques-tech-qui-peuvent-aider-votre-equipe/</link><pubDate>Tue, 01 Feb 2022 09:33:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2022/02/les-pratiques-tech-qui-peuvent-aider-votre-equipe/</guid><description><![CDATA[<p>Nul besoin d&rsquo;avoir un passé de développeur, ou de savoir coder. Mon intention ici est de faire découvrir des pratiques tech reconnues dans l&rsquo;industrie. C&rsquo;est un sujet que je souhaite rendre accessible à tous, que l&rsquo;on soit tech ou non, pour améliorer le quotidien des équipes, devenir meilleur dans la technique et dans le business.</p>
<p>J&rsquo;ai été invité par Fleur Saillofest à speaker dans le <a href="https://www.meetup.com/fr-FR/Beyond-Scrum-Mastering/events/282839931/" target="_blank" rel="noopener noreffer">meetup Beyond Scrum Mastering</a>. Très rapidement, une trame intéressante a émergé lors de nos échanges : celle de reconnaître des problèmes au sein de l&rsquo;équipe et y associer certaines pratiques tech qui pourraient aider.</p>
<p>Observer ce qu&rsquo;il se passe dans l&rsquo;équipe, entendre les râlements, les plaintes, noter les douleurs, c&rsquo;est à la portée de tout le monde. J&rsquo;ai pris un fil rouge avec des problèmes qu&rsquo;une équipe peut rencontrer à diverses étapes de la conception du produit pour introduire certaines pratiques techs. Autour du besoin, du code, des tests, de la livraison, de l&rsquo;existant, etc.</p>
<p>Est-ce que ce sont les seules possibilités ? Non. Mon but n&rsquo;est pas d&rsquo;être exhaustif ni sur les problèmes ni sur les solutions et les pratiques. Mais plutôt d&rsquo;entrevoir des possibilités, de donner des billes pour ensuite aller creuser plus en profondeur avec l&rsquo;équipe. Je dépose quelques brides de réflexion dans cet article qui m&rsquo;ont permis de créer mon talk (<a href="https://github.com/chapuyj/materials/blob/main/2022-01_Pratiques_tech_qui_peuvent_aider_votre_equipe/slides.pdf" target="_blank" rel="noopener noreffer">slides ici</a>).</p>
<h1 id="collaborer-sur-le-besoin">Collaborer sur le besoin</h1>
<blockquote>
<ul>
<li><em>Les refinements sont chiants.</em></li>
<li><em>On se rend compte pendant le sprint que les besoins ne sont pas clairs. Les développeurs demandent au PO des spécifications hyper détaillées avant de commencer.</em></li>
<li><em>Le PO change d’avis, on fait ce qu&rsquo;il y a écrit dans la story mais il dit que ce n&rsquo;était pas ça qu’il voulait.</em></li>
</ul>
</blockquote>
<p>Les premiers problèmes peuvent arriver très tôt, dès l&rsquo;expression du besoin, avant même d&rsquo;être purement dans la tech, dans le code. On peut noter qu&rsquo;il semble y avoir de l&rsquo;incompréhension, qu&rsquo;il y a probablement des choses implicites, des modèles mentaux différents. Que tous les membres de l&rsquo;équipe ne sont pas vraiment impliqués.</p>
<h2 id="example-mapping">Example Mapping</h2>
<p>Une piste d&rsquo;amélioration serait de faire collaborer toute l&rsquo;équipe, ensemble, sur la rédaction du besoin. Je pense naturellement à l&rsquo;Example Mapping. C&rsquo;est un atelier qui réunit l&rsquo;ensemble de l&rsquo;équipe (PO, QA, Dev front/back). Le PO vient avec ses règles métiers et toute l&rsquo;équipe œuvrera à créer des exemples précis pour chaque règle.</p>
<p>Tout le monde est impliqué, participe, et s&rsquo;approprie le besoin. Les règles sont éclaircies, les exemples sont concrets et parlent à tous. L&rsquo;implicite est rendu explicite, on sort ce qu&rsquo;il y a de la tête du PO. Des questions peuvent émerger, avec des points à éclaircir avant de commencer le développement. On peut aussi trouver un découpage plus fin de la story.</p>
<p>Ce n&rsquo;est plus à la seule charge du PO d&rsquo;écrire un immense cahier des charges qui sera de toute façon probablement imparfait et jamais satisfaisant. Les développeurs ne restent pas passifs avec des pavés à avaler. On fait jouer l&rsquo;intelligence collective en amont pour co-créer quelque chose de meilleur.</p>
<h1 id="collaborer-sur-le-code--git">Collaborer sur le code / Git</h1>
<blockquote>
<ul>
<li><em>J’entends parler de branches, merge, commit, conflits, … Je suis perdu.</em></li>
<li><em>C’est quoi ce git machin chose ?</em></li>
</ul>
</blockquote>
<p>Je dédierais un article pour vulgariser l&rsquo;utilisation de git qu&rsquo;en ont les développeurs. Je me limiterais à quelques lignes ici pour comprendre l&rsquo;origine de certains problèmes. Git est un outil pour gérer les versions du code source.</p>
<p>Un développeur va créer un <em>commit</em> avec des changements ; c&rsquo;est une copie à un instant T du code. Il va travailler sur une <em>branche</em> ; c&rsquo;est un espace indépendant, avec ses propres copies.</p>
<p>Au bout d&rsquo;un moment, lorsqu&rsquo;il aura terminé, il va vouloir <em>merge</em> ; il veut réunir son travail réalisé sur sa branche (dans son espace indépendant) vers la branche principale (l&rsquo;espace commun). Pour cela, il va ouvrir une <em>Pull/Merge Request</em> et demander à quelqu&rsquo;un de faire de la <em>revue de code</em> ; une personne va relire toutes les modifications, pour approuver ou faire des retours.</p>
<p>Au moment de réunir, il peut y avoir des <em>conflits</em> ; dans son espace, il a modifié des zones qui ont aussi été modifiées sur l&rsquo;espace commun. Il faudra résoudre ces problèmes afin de pouvoir rassembler les travaux. Qu&rsquo;est-ce qu&rsquo;on garde ? Qu&rsquo;est-ce qui n&rsquo;a plus de sens ? Qu&rsquo;est-ce qu&rsquo;il faut adapter ?</p>
<p>Plus longtemps on travaille sur une <em>branche</em> (dans son coin) et plus on attend pour réunir avec la <em>branche principale</em> (avec les autres), plus on augmente les problèmes. Par exemple, la quantité de changements et le temps qui s&rsquo;allonge augmentent le risque de <em>conflits</em> et demandent une plus longue <em>revue de code</em>.</p>
<h1 id="collaborer-sur-le-code--revue-de-code">Collaborer sur le code / Revue de code</h1>
<blockquote>
<ul>
<li><em>J’en ai marre de devoir refaire plusieurs fois mon code après des aller-retours sur la code review.</em></li>
<li><em>Les développeurs se plaignent que les revues de codes sont longues à faire et pas intéressantes.</em></li>
<li><em>On attends longtemps avant qu’un autre développeur fasse la revue de code.</em></li>
</ul>
</blockquote>
<p>Ahhh, la revue de code, serait-ce le mal du siècle des développeurs après le mal de dos ? J&rsquo;exagère un peu - j&rsquo;avais envie d&rsquo;écrire cette tournure humoristique - mais j&rsquo;ai tout de même souvent observé des symptômes autour de la revue de code. Il faut dire aussi que c&rsquo;est une pratique qui s&rsquo;est très largement répandue dans les équipes. Pour autant, elle n&rsquo;est pas toujours bien appliquée et elle vient avec son lot de contraintes.</p>
<p>Par nature, <a href="https://jordanchapuy.com/posts/2021/02/et-si-on-arretait-les-revues-de-code/" rel="">la revue de code via une Pull/Merge Request est asynchrone</a> - la relecture arrivera un temps après la demande, qui nécessitera des changements qui seront faits un autre temps après, et ainsi de suite. Il y aura des changements de contexte, de la part du relecteur et de l&rsquo;auteur. Et on sait que les changements de contexte nuisent à la productivité. On est interrompu, on sort constamment du flow (qui est long à trouver).</p>
<p><a href="https://jordanchapuy.com/posts/2021/02/et-si-on-arretait-les-revues-de-code/" rel="">Le feedback est tardif</a>. La revue est très souvent ouverte lorsque la story est entièrement terminée (rappel git : quand on veut réunir nos changements avec la branche principale). Les changements seront plus coûteux. La revue est parfois bâclée. Certains lisent rapidement en diagonal parce qu&rsquo;ils n&rsquo;ont pas le temps ou que ça ne les intéressent pas. D&rsquo;autres vont pinailler, mais seulement sur des points insignifiants.</p>
<p>Ce peut être un goulot d&rsquo;étranglement qui allonge la durée nécessaire pour livrer une fonctionnalité. C&rsquo;est marquant lorsqu&rsquo;il y a beaucoup de développeurs ou lorsque la responsabilité de la revue n&rsquo;est donnée qu&rsquo;à une poignée de personnes (par exemple, seul le lead/référent/manager).</p>
<p>Bien sûr, ce n&rsquo;est pas tout noir. La revue de code peut être bien faite et a pour sa défense deux principaux bénéfices : c&rsquo;est une occasion de donner du feedback pour améliorer le code et réduire les bugs, et c&rsquo;est une façon de partager de la connaissance en lisant le code d&rsquo;un autre.</p>
<p>Ok, on parle de feedback et d&rsquo;apprentissage, comment pourrait-on faire mieux ? Avec un échange direct, temps réel. Avec de la mise en pratique plutôt que de la lecture passive. Avec du Pair Programming et du Mob Programming. On forme une équipe, on est ensemble, on peut faire mieux sur la collaboration. Les process de Pull/Merge Request ont davantage de sens dans le monde de l&rsquo;open-source où les personnes ne se connaissent pas, ne travaillent pas ensemble, où il faut contrôler.</p>
<h2 id="pair-programming">Pair Programming</h2>
<p>Le Pair Programming est une pratique qui va permettre une réelle collaboration de deux personnes. On se met ensemble, sur un même problème, avec un seul ordinateur, en même temps. On échange pour trouver la solution et écrire du code. On échange pour s&rsquo;améliorer en continu. Il y a une réflexion commune, deux cerveaux qui vont se challenger.</p>
<p>Ici, <a href="https://jordanchapuy.com/posts/2021/02/et-si-on-arretait-les-revues-de-code/" rel="">le feedback est immédiat</a>. Je propose au plus tôt une autre approche de conception à mon pair. Je découvre une fonction plus performante au moment où j&rsquo;écris ma ligne de code grâce au conseil de mon pair. On repère ce bug pendant qu&rsquo;on développe la fonctionnalité ensemble. Maintenant tout de suite, pas après 5 jours de travail.</p>
<p>La transmission de connaissances, autant technique que fonctionnelle, est forte. Les deux développeurs travaillent ensemble au même moment. Ce meilleur pattern pour faire le traitement, je le découvre en direct voire je le mets en place moi-même. On donne en effet le clavier au non-sachant, afin de le faire pratiquer tout en le guidant. Ce scope fonctionnel, on l&rsquo;aura co-créée, je le comprendrais, mon pair n&rsquo;est plus le seul de l&rsquo;équipe à pouvoir y travailler. C&rsquo;est très efficace pour onboarder un nouvel arrivant aussi.</p>
<p>C&rsquo;est en ça que la pair programming est puissant et ne divise pas l&rsquo;efficacité par deux, il faut voir au-delà de &ldquo;deux ressources qui travaillent sur un seul problème&rdquo;.</p>
<h2 id="mob-programming">Mob Programming</h2>
<p>Le Mob Programming se trouve un cran après le Pair Programming : c&rsquo;est tout un groupe qui va collaborer, en même temps, sur un seul et même problème, avec un seul ordinateur. L&rsquo;intelligence collective va mener à une meilleure compréhension du problème et à une meilleure conception de la solution. Encore une fois, ce n&rsquo;est pas simplement grouper un tas de personnes pour qu&rsquo;elles regardent un seul développeur tout faire.</p>
<p>Le problème et les solutions sont discutés et challengés. Le groupe entier s&rsquo;approprie le code et la fonctionnalité, tout le monde avance ensemble. On peut arriver à tacler des problèmes très complexes. Il y a une très forte transmission de connaissances et de compétences. C&rsquo;est tout un groupe qui apprendra, en pratiquant, cette nouvelle technique ou cette fonctionnalité.</p>
<p>Note : on parle d&rsquo;avoir un seul ordinateur, un seul clavier en pair et mob programming. C&rsquo;est parfaitement compatible à distance avec des solutions de partage d&rsquo;écran, de contrôle du clavier, de code collaboratif.</p>
<h1 id="collaborer-sur-le-code--conflits">Collaborer sur le code / Conflits</h1>
<blockquote>
<ul>
<li><em>Le dev est terminé localement mais ça met beaucoup de temps à être livré car on a plein de conflits.</em></li>
<li><em>La fonctionnalité marche sur ma branche mais maintenant que c’est mergé c’est cassé.</em></li>
</ul>
</blockquote>
<h2 id="intégration-continue">Intégration Continue</h2>
<p>Parfois, quand on parle d&rsquo;Intégration Continue, on entends Jenkins, gitlab-ci, pipelines, machine de builds, etc. Ce n&rsquo;est pas ça, l&rsquo;Intégration Continue. Tout ça, ce sont des outils. C&rsquo;est du comment.</p>
<p>L&rsquo;Intégration Continue, c&rsquo;est d&rsquo;abord un principe, une attitude. C&rsquo;est rassembler très souvent les changements sur la branche principale (intégrer continuellement). On partage à tous nos changements plusieurs fois par jour ; plutôt que d&rsquo;attendre de tout finir et de rassembler après 8 jours de travail intense.</p>
<p>Qu&rsquo;est-ce que ça apporte ? Un cercle vertueux. On va faire de plus petites étapes pour rassembler plus souvent. On va faire de meilleurs tests automatisés pour s&rsquo;assurer que tout est bon. Naturellement, on aura moins de conflits et de problèmes avec de petites modifications ayant une durée de vie courte.</p>
<h2 id="pairmob-programming">Pair/Mob Programming</h2>
<p>On l&rsquo;a vu précédemment, le Pair et le Mob Programming permettent une réelle collaboration de plusieurs personnes. La communication est meilleure, puisqu&rsquo;elle est immédiate et continue. Il y a moins de travaux simultanés en cours, puisque les développeurs se réunissent pour travailler sur le même sujet. Tout ça contribue à diminuer les risques de conflits et de problèmes de merge.</p>
<h1 id="écrire-le-code">Écrire le code</h1>
<blockquote>
<ul>
<li><em>On a fait évolué l’écran recherche, et on a vu plus tard en prod que la logique métier du compte est complètement KO.</em></li>
<li><em>On planifie de passer une après midi sur l’écriture de tests, on fait comment pour le prendre en compte dans la vélocité ?</em></li>
</ul>
</blockquote>
<h2 id="tests-unitaires">Tests Unitaires</h2>
<p>Il est important de clarifier ce que sont les tests unitaires et pourquoi on en écrit. Très simplement, un test unitaire est un test automatisé d&rsquo;un scénario fonctionnel. C&rsquo;est quelque chose qui vérifie que du code se comporte comme prévu, automatiquement, sans intervention humaine. C&rsquo;est un programme qui lance un autre programme pour vérifier ce qu&rsquo;il se passe dans différentes conditions.</p>
<p>On parle de comportement, de scénario fonctionnel : quand on écrit un test unitaire, on veut s&rsquo;assurer de bien retranscrire le métier. C&rsquo;est en ça qu&rsquo;il est très important et utile pour le business, et que ce n&rsquo;est pas seulement un élément technique.</p>
<p>Progressivement, on créé un filet de sécurité pour éviter certaines régressions. On diminue le risque d&rsquo;avoir des bugs en production : on aura un feedback immédiat, pendant le développement, si une règle métier est cassée après un changement dans le code.</p>
<p>C&rsquo;est au moment où l&rsquo;on change le code que l&rsquo;on sait si on altère involontairement le comportement, pas plusieurs jours après. Ce qui fait que les tests unitaires jouent un rôle essentiel au <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">Refactoring</a>, pour améliorer le code sereinement.</p>
<h2 id="test-driven-development">Test-Driven Development</h2>
<p>Quand on écrit un test, une bonne pratique est de le faire au plus près du moment où l&rsquo;on a écrit le code, et non pas bien après une fois que tout est terminé. Pourquoi ? Parce que c&rsquo;est plus coûteux et difficile de le faire après ; le code n&rsquo;ayant pas forcément été conçu pour être testable. Et parce qu&rsquo;on passe à côté d&rsquo;un bénéfice important : se faire guider par le test.</p>
<p>Et c&rsquo;est la philosophie du Test-Driven Development. Ce n&rsquo;est pas &ldquo;écrire le test en premier&rdquo; (c&rsquo;est du comment). C&rsquo;est se faire guider par les tests et par le métier. On définit le comportement que l&rsquo;on veut obtenir (le test) puis on fait émerger la solution et on l&rsquo;améliore.</p>
<p>On a une boucle de feedback extrêmement rapide. Quand on développe la solution, le test nous indique en quelques millisecondes si le comportement voulu est bien retranscrit.</p>
<p>À noter que <a href="https://jordanchapuy.com/posts/2022/01/permis-de-developper/" rel="">l&rsquo;écriture des tests unitaires et la pratique du TDD font partie intégrante du job de développeur</a> et que <a href="https://jordanchapuy.com/posts/2021/12/ce-nest-pas-plus-long-de-pratiquer-le-tdd/" rel="">ce n&rsquo;est pas forcément plus long de tester</a>. Au contraire, ça nous aide. C&rsquo;est à faire dès qu&rsquo;il y en a le besoin, en continu, il n&rsquo;y a pas de permission à demander, de journées à dédier.</p>
<h1 id="livrer">Livrer</h1>
<blockquote>
<ul>
<li><em>C’est douloureux de livrer, c’est long, il y a un tas de process et d’actions à faire…</em></li>
<li><em>On va s’assurer d’avoir suffisamment de choses dans la release pour livrer. C’est long alors il faut que ça vaille le coup.</em></li>
<li><em>On ne livre pas le vendredi. On ne peut rien modifier en août et fin décembre. On a un code freeze pendant les périodes avec beaucoup de vacances.</em></li>
</ul>
</blockquote>
<h2 id="automatisation">Automatisation</h2>
<p>Créer une archive de l&rsquo;application et l&rsquo;envoyer sur un serveur, générer le fichier de traduction à partir d&rsquo;une feuille Excel, remplacer toutes les majuscules d&rsquo;un fichier brut par des minuscules et le transformer en JSON, &hellip; Ce sont des exemples de tâches manuelles qui gagneraient à être automatisées.</p>
<p>La bonne nouvelle ? Un développeur est bien placé pour automatiser, il est capable d&rsquo;écrire du code pour créer un programme qui va effectuer ces tâches. Une fois créé, il n&rsquo;y a plus qu&rsquo;à exécuter ce programme et la tâche sera réalisée (souvent) immédiatement plutôt que de prendre trop de temps à une personne. On s&rsquo;enlève au passage le risque d&rsquo;erreur humaine : le programme fera toujours la même chose, il ne va pas oublier une ligne, il ne va pas se tromper de caractère, etc.</p>
<p>Outre l&rsquo;efficacité, je trouve que c&rsquo;est bien plus intéressant à faire. On conçoit un programme, on réfléchit plutôt que de répéter des tâches rébarbatives.</p>
<h2 id="livraison-continue">Livraison Continue</h2>
<p>Le principe est simple, chaque changement sur la branche principale est livré. C&rsquo;est livré dans un environnement de staging/test/preprod, ou même de production, mais ce n&rsquo;est pas déployé. Ce n&rsquo;est pas encore dans les mains des utilisateurs.</p>
<p>Autrement dit, avec la Livraison Continue, il suffit d&rsquo;un simple bouton pour déployer aux utilisateurs, il n&rsquo;y a pas besoin d&rsquo;autres interventions. Tout est déjà prêt, on est capable de déployer sur demande. Plusieurs fois par semaine, jour, heure, etc.</p>
<p>Ça ne veut pas dire qu’on va forcément livrer chaque heure. Si on est capable de livrer toutes les heures, on est capable de livrer quand on veut. Et c&rsquo;est ça que l&rsquo;on recherche. Le déploiement devient un non-sujet. On pourra bénéficier des avantages de livrer souvent et rapidement de petits incréments, dès que cela fait sens.</p>
<p>Pour livrer en continu, on va mettre en place certains outils, on va automatiser des tâches, et on va s&rsquo;atteler à toujours avoir un code dans un état déployable.</p>
<h2 id="déploiement-continu">Déploiement Continu</h2>
<p>Ici, on va un cran plus loin : tout est automatisé, il n&rsquo;y a plus aucune intervention humaine. Chaque modification sur la branche principale est déployée en production et arrive directement dans les mains des utilisateurs.</p>
<p>En mettant en place la Livraison Continue ou le Déploiement Continu, on entre dans un cercle vertueux de pratiques. On se concentrera davantage sur la qualité, sur les tests automatisés, sur la création de petits incréments, sur l&rsquo;activation à distance de fonctionnalités, &hellip; plutôt que sur des pratiques contraignantes comme mettre un freeze de code, avoir une semaine de tests de non-régression, avoir 4 niveaux de validations de chefferie, etc. Ce qui fera livrer moins souvent, donc il faudra faire encore plus attention, donc livrer moins donc faire plus attention, et ainsi de suite, un cercle vicieux de peur et de contrôle.</p>
<h1 id="améliorer-un-existant">Améliorer un existant</h1>
<blockquote>
<ul>
<li>*On a des problèmes de qualité dont on n’a jamais le temps de s’occuper. *</li>
<li><em>Mon équipe veut négocier un sprint ou deux de refactoring mais je ne sais pas quelle valeur ça va apporter.</em></li>
<li><em>J’ai un développeur qui fait du refactoring depuis 3 mois, c’est pas encore fini mais il avance.</em></li>
</ul>
</blockquote>
<h2 id="refactoring">Refactoring</h2>
<p>Faire du <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">Refactoring</a>, c&rsquo;est changer le code sans casser son comportement observable. On améliore le code dans le but de mieux le comprendre ou de faciliter le changement, par exemple. Le code fera toujours la même chose. Si je fais du refactoring sur une fonctionnalité de recherche, elle fera toujours de la recherche, ni plus, ni moins.</p>
<p>Autre aspect très important du refactoring : on avance par petites étapes. On enchaîne une série d’améliorations, de petites étapes que l’on peut partager régulièrement. Le projet est toujours dans un bon état, on peut s&rsquo;arrêter à tout moment.</p>
<p>C&rsquo;est différent de &ldquo;tout refaire&rdquo;, à ne pas confondre avec la réécriture. Ce n&rsquo;est pas ce fameux chantier de 3 mois en tunnel où rien ne fonctionne entre temps. Le refactoring demande de la discipline et des compétences.</p>
<h3 id="refactoring-opportuniste">Refactoring opportuniste</h3>
<p>On fait du refactoring quotidiennement, <a href="https://jordanchapuy.com/posts/2020/09/profiter-de-chaque-occasion-pour-ameliorer-le-code-legacy/" rel="">toutes les occasions sont bonnes</a>. J&rsquo;ouvre un fichier où je vais devoir travailler, mais le changement est difficile ? Le code est legacy ? J&rsquo;en profite pour faire un petit refactoring en amont plutôt que d&rsquo;empirer. On peut évoquer la règle de Boy Scout :</p>
<p><code>Toujours laisser le code dans un meilleur état que celui dans lequel vous l'avez trouvé.</code></p>
<p>On préférera agir régulièrement et de manière opportuniste plutôt que de bloquer des jours/semaines dédiés au refactoring. Tout comme les tests, <a href="https://jordanchapuy.com/posts/2022/01/permis-de-developper/" rel="">ça fait partie intégrante du job de développeur</a>. Il est important de faire du refactoring régulièrement et de se former. D&rsquo;ailleurs, au lieu de bloquer des jours pour faire du refactoring, peut-être le transformer en un temps pour se former et s&rsquo;améliorer dans les techniques de refactoring ?</p>
<h3 id="théorie-de-la-vitre-brisée">Théorie de la vitre brisée</h3>
<p>On veut faire du refactoring régulièrement pour améliorer le code continuellement. On veut éviter que la situation ne s&rsquo;empire, on veut y remédier au plus tôt. La théorie de la vitre brisée est intéressante pour expliquer pourquoi on veut agir vite et régulièrement.</p>
<p>Prenons par exemple une maison avec une fenêtre brisée. La théorie nous indique que si on ne fait rien, on laisse penser que la maison est à l&rsquo;abandon. On va alors attirer et cumuler d&rsquo;autres problèmes, des graffitis, de nouvelles fenêtres brisées, etc. Un cercle vicieux démarre et qui ira au-delà de la maison, apportant plus de criminalités dans le quartier.</p>
<p>Il faut remédier aux problèmes au plus vite, avant qu&rsquo;ils ne soient trop nombreux. Un quartier où les maisons sont constamment bien entretenues attirera moins les problèmes. C&rsquo;est la même chose avec le code, on va vouloir rester dans un état d&rsquo;esprit de qualité.</p>
<h3 id="méthode-mikado">Méthode Mikado</h3>
<p><a href="https://jordanchapuy.com/posts/2021/07/la-methode-mikado-de-grands-changements-avec-de-petites-etapes/" rel="">La méthode mikado</a> est très utile pour faire du refactoring. C&rsquo;est une méthode pour effectuer de grands changements avec de petites étapes. On veut atteindre un objectif, qui peut être ambitieux, on ne sait pas encore comment y aller, mais on va construire ce chemin progressivement.</p>
<p>On va effectuer une suite de petites expérimentations. Quand une expérimentation réussie, on a avancé vers notre objectif, avec une petite étape. Quand une expérimentation échoue, on revient en arrière, on a appris quelque chose, et on découvre qu&rsquo;il faut effectuer une autre petite étape nécessaire en amont. On dessine d&rsquo;ailleurs un graphe pour visualiser notre progression et nos pré-requis.</p>
<p>De fait, on est toujours dans un état fonctionnel, on peut s&rsquo;arrêter à tout moment. On n&rsquo;aura peut-être pas atteint l&rsquo;objectif, mais ce sera mieux, on sera plus proche de la fin, on aura réalisé quelques petites étapes, et ça fonctionnera toujours.</p>
<h1 id="bref">Bref</h1>
<p>On a vu un ensemble de pratiques tech reconnues dans l&rsquo;industrie. On a vu comment elles peuvent aider dans certains problèmes. Et même au-delà. Ce sont des pratiques pour améliorer le quotidien de l’équipe et devenir meilleur dans la technique et dans le business.</p>
<p>On a aujourd&rsquo;hui le recul nécessaire et les études pour voir la corrélation entre la performance technique et business. Pour répondre rapidement aux besoins de l&rsquo;utilisateur, on a besoin de pouvoir livrer rapidement. Changer facilement le code permet de changer facilement de direction fonctionnelle.</p>
]]></description></item><item><title>Permis de développer</title><link>https://jordanchapuy.com/posts/2022/01/permis-de-developper/</link><pubDate>Thu, 06 Jan 2022 15:30:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2022/01/permis-de-developper/</guid><description><![CDATA[<p>Un développeur a-t-il besoin d&rsquo;une permission pour écrire des tests ? Pratiquer le Test-Driven Development ? Faire du <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">refactoring</a> ? Travailler en Pair Programming ? Faut-il un permis à l&rsquo;image de la légendaire <em>licence to kill</em> de James Bond ?</p>
<p>Ma réponse est <strong>NON</strong> (sans surprise, comme la plupart des articles qui commencent avec une grande question fermée). Un développeur doit être autonome et décider de lui-même pour ce genre de pratiques. Il n&rsquo;a pas à demander l&rsquo;autorisation à un manager, ni un chef, ni un PO, ni un SM, ni même à un tech lead ou un autre développeur.</p>
<p>Encore moins se voir interdire (anecdote récente lors d&rsquo;un entretien technique, un développeur m&rsquo;a indiqué que son client lui interdisait d&rsquo;écrire des tests parce que ça prenait du temps). Au contraire, il faut promouvoir et pousser ces pratiques aux développeurs et aux équipes.</p>
<h1 id="ça-fait-partie-du-job">Ça fait partie du job</h1>
<p>L&rsquo;écriture de tests, le TDD, le Refactoring, le Pair Programming, et j&rsquo;en passe, ce sont des pratiques répandues dans l&rsquo;industrie. Elles sont reconnues et proviennent de mouvements comme le Software Craftsmanship, l&rsquo;eXtreme programming, ou le Domain Driven Design. Ce n&rsquo;est pas le n-ième <em>nouveau super framework</em> à la mode.</p>
<p>On parle ici de pratiques qui améliorent la qualité du code et du produit, qui facilite le changement, qui permettent de mieux collaborer, de mieux retranscrire le métier. Elles font partie intégrante du métier de développeur.</p>
<p>Un développeur n&rsquo;est pas un exécutant. Il n&rsquo;est pas là juste pour pisser du code. Il a un (grand) rôle à jouer pour concevoir un produit de qualité. Il existe de nombreux ouvrages sur ces pratiques et également sur la posture de développeur. Pour en citer un, <em>Sandro Mancuso</em> en parle très bien dans son livre <em>The Software Craftsman</em>.</p>
<h1 id="just-do-it">Just do it</h1>
<p>Je donnerais comme conseil aux développeurs de faire, de passer à l&rsquo;action, d&rsquo;utiliser ces pratiques. Sans attendre une permission officielle, sans aller chercher une approbation quelconque. Faites-le, tout simplement.</p>
<p>Il y a un proverbe qui dit <code>Il vaut mieux demander pardon que demander la permission</code>. Je l&rsquo;aime bien, et je trouve qu&rsquo;il a du sens dans cette situation. Vous êtes développeur et vous hésitez ? Lancez-vous, essayez, montrez par l&rsquo;exemple. Probablement, quelque chose de bon en sortira et on ne viendra pas vous taper sur les doigts. Ce n&rsquo;est pas parfait ? Vous deviendrez meilleur en continuant d&rsquo;essayer et de vous améliorer.</p>
<p>Rappelons que le développeur a l&rsquo;expertise. Il sait comment travailler, il connaît sa boîte à outils. Mon propos n&rsquo;est pas d&rsquo;enfermer le développeur dans sa vision - il doit rester ouvert, comme tout le monde - mais de lui faire confiance et de lui donner de l&rsquo;autonomie.</p>
<p>Ce qui n&rsquo;empêche pas de le challenger. Et quand on touche à ses limites, à sa zone où il ne maîtrise pas, on se penchera plutôt sur comment former, comment apprendre, comment expérimenter, plutôt que d&rsquo;empêcher.</p>
<h1 id="former-les-équipes">Former les équipes</h1>
<p>Ça fait partie du job, d&rsquo;utiliser ces pratiques, ça fait également partie du job de se former. Elles ne tomberont pas soudainement du ciel. Avis aux développeurs qui doivent faire l&rsquo;effort autant qu&rsquo;aux managers qui doivent investir ;)</p>
<p>On se forme, on forme les équipes, on expérimente, on s&rsquo;améliore en continue. Le retour sur l&rsquo;investissement est positif, on ira plus vite, on délivrera mieux. On veut démarrer un cercle vertueux (on apprend, on améliore le code, on change plus facilement, on livre plus vite, on satisfait davantage l&rsquo;utilisateur) plutôt que vicieux (on empêche, on n&rsquo;apprend pas, le code se détériore, les évolutions deviennent difficiles, on cumule des problèmes, on met du temps à livrer à l&rsquo;utilisateur).</p>
<p>Il y a un tas de moyens pour apprendre. Quelques idées : inviter des personnes à faire un BBL, l&rsquo;intervention de coachs, faire des katas seul ou en groupe, du mob-programming sur le projet, assister à des conférences, lire des livres, etc.</p>
<h1 id="casser-les-idées-reçues">Casser les idées reçues</h1>
<p>Et s&rsquo;il y a du blocage, des interdictions, des permissions à demander pour utiliser ces pratiques ? J&rsquo;essaierais de comprendre pourquoi, de challenger, de rappeler que ça fait partie du job, et de casser certaines idées reçues.</p>
<p>En rappelant la vision, la philosophie de certaines pratiques. Le <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">refactoring</a>, ce n&rsquo;est pas un chantier de 3 mois en tunnel. Ce sont des petites étapes, ce sont des améliorations que l&rsquo;on fait au quotidien, qui facilitent le changement, qui améliorent la qualité.</p>
<p><a href="https://jordanchapuy.com/posts/2021/12/ce-nest-pas-plus-long-de-pratiquer-le-tdd/" rel="">L&rsquo;écriture de tests et le TDD, ce n&rsquo;est pas plus long</a>. C&rsquo;est une aide pour le développeur, un guide pour bien retranscrire le métier, le comportement. On obtient en plus de la sérénité quand il faut effectuer des changements. On entre dans des situations où l&rsquo;on ira plus vite.</p>
<p>Le Pair-Programming, ce n&rsquo;est pas juste deux ressources humaines qui se mettent sur un poste pour travailler sur un seul problème à la fois. C&rsquo;est une collaboration poussée, c&rsquo;est un feedback rapide, c&rsquo;est une transmission de connaissances, d&rsquo;informations, c&rsquo;est de l&rsquo;amélioration en continue. Là aussi on entre dans des situations où l&rsquo;on ira plus vite.</p>
<p>On améliore la qualité, on gagne du temps, on gagne de l&rsquo;argent. Trois arguments que l&rsquo;on peut aligner en fonction de l&rsquo;interlocuteur. On pourrait citer en touche finale  <em>Accelerate</em>, un livre qui montre, via une étude sur plusieurs années incluant de très nombreuses entreprises, qu&rsquo;il y a une corrélation entre la performance technique et la performance business.</p>
]]></description></item><item><title>Ce n'est pas plus long de pratiquer le TDD</title><link>https://jordanchapuy.com/posts/2021/12/ce-nest-pas-plus-long-de-pratiquer-le-tdd/</link><pubDate>Sat, 11 Dec 2021 14:35:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2021/12/ce-nest-pas-plus-long-de-pratiquer-le-tdd/</guid><description><![CDATA[<p>J&rsquo;entends et lis parfois que ça prend du temps d&rsquo;écrire des tests unitaires et de pratiquer le Test-Driven Development. Que c&rsquo;est bien plus long que de ne pas en faire. Je ne suis pas en phase.</p>
<p>J&rsquo;ai la conviction que ça ne prend pas forcément plus de temps de travailler en TDD. On est sensiblement sur la même longueur, parfois même plus rapide parce que ça nous guide. On est très loin du laïus <em>&ldquo;c&rsquo;est une perte de temps&rdquo;</em>, surtout lorsque l&rsquo;on regarde sur différents horizons de temps.</p>
<p>Il n&rsquo;y a d&rsquo;ailleurs pas que le temps qui entre en jeu, d&rsquo;autres bénéfices gravitent autour de l&rsquo;écriture des tests et de la pratique du TDD. Pour étayer mes affirmations, j&rsquo;ai envie d&rsquo;en parler à travers plusieurs prismes.</p>
<h2 id="jai-une-mauvaise-utilisation-du-tdd">J&rsquo;ai une mauvaise utilisation du TDD</h2>
<p>Pour le premier prisme, je prends un développeur qui pratique le TDD mais qui l&rsquo;utilise mal, qui ne le maîtrise pas. Je commence par ce postulat parce que c&rsquo;est sûrement là qu&rsquo;il y a le plus de confusion et de mécompréhension. Les personnes qui ne maîtrisent pas l&rsquo;art de tester et du TDD se forgent un avis sur la base d&rsquo;une expérience incomplète.</p>
<p>Qu&rsquo;est-ce que c&rsquo;est, <em>ne pas maîtriser</em> ? Penser que ça se résume à <em>écrire un test en premier</em>, que c&rsquo;est purement de la <em>technique</em> (versus métier), ou que ça se limite à suivre le <em>Red-Green-Refactor</em>, par exemple.</p>
<p>En adoptant une mauvaise pratique, on va se mettre des bâtons dans les roues. On va vouloir tout mocker, on va tester l&rsquo;implémentation, on ne va pas faire de petites étapes, etc. Résultat, on va trouver ça plus long. On va peut-être préférer ne pas faire de TDD, finalement. C&rsquo;est plus long et il y a un tas de trucs chiants à faire, pourquoi s&rsquo;emmerder.</p>
<p>Dans ce contexte, la méthode est mal comprise et mal appliquée. C&rsquo;est probablement plus long de pratiquer le TDD, oui. Mais peut-on juger la méthode dans ces conditions ? J&rsquo;y répondrais par une autre question. Est-ce qu&rsquo;une voiture est lente parce qu&rsquo;on roule avec le frein à main ? Ou parce qu&rsquo;on ne sait pas comment passer les vitesses ? Non.</p>
<p>=&gt; Oui, une mauvaise application du TDD peut demander davantage de temps. Non, dans ce contexte, c&rsquo;est inexact de déduire qu&rsquo;une bonne pratique du TDD prend du temps.</p>
<h2 id="japprends-le-tdd">J&rsquo;apprends le TDD</h2>
<p>Dans ce second prisme, j&rsquo;introduis une nuance : un développeur qui s&rsquo;exerce à pratiquer le TDD mais qui ne le maîtrise pas encore parce qu&rsquo;il est en phase d&rsquo;apprentissage. La différence avec le premier prisme ? Il a conscience de la bonne pratique du TDD et il s&rsquo;améliore pour y arriver. Il ne va pas mal faire tout en supposant qu&rsquo;il maîtrise la méthode.</p>
<p>Disons les choses. Le TDD, c&rsquo;est difficile. Ça demande du temps pour le maîtriser. Ça demande de s&rsquo;entraîner, de répéter, de s&rsquo;améliorer. Mais pour autant, c&rsquo;est la phase d&rsquo;apprentissage qui requiert du temps. Ce n&rsquo;est pas l&rsquo;application de la méthode elle-même. Encore une fois, juge-t-on la vitesse d&rsquo;une voiture avec un pilote qui apprend à passer les vitesses ? Non.</p>
<p>Ok. Et durant cet apprentissage alors, à quel point ça prends du temps de faire du TDD ? Ça dépend. Ça dépend du contexte, ça dépend du niveau de compétence que l&rsquo;on a acquis à cet instant.</p>
<p>Il y a des situations où l&rsquo;on ne sera pas encore à l&rsquo;aise, on devra ralentir pour bien faire, on prendra davantage de temps sur le moment. À l&rsquo;inverse, il y a des situations où l&rsquo;on sera guidé par le TDD et où l&rsquo;on obtiendra plus rapidement un bon résultat. On va commencer à bénéficier des effets positifs (j&rsquo;en parlerais après).</p>
<p>=&gt; Oui, l&rsquo;apprentissage du TDD demande du temps. Non, on ne peut pas dire que la pratique elle-même, une fois maîtrisée, prend du temps.</p>
<h2 id="jécris-mes-tests-après">J&rsquo;écris mes tests après</h2>
<p>Je me mets maintenant dans le prisme d&rsquo;un développeur qui écrit ses tests après coup. Que se passe-t-il si je me mets à faire du TDD ? On pourrait se dire que l&rsquo;on va prendre davantage de temps, on écrit déjà des tests, pourquoi se compliquer la vie à s&rsquo;ajouter une méthode ?</p>
<p>Eh bien, dans ce contexte, pratiquer le TDD sera probablement plus efficace et plus rapide. Le TDD va guider l&rsquo;écriture de l&rsquo;implémentation. On obtiendra une meilleure conception, on avancera par petites étapes et on sera guidé par le comportement métier. Ce sera une aide pour écrire de meilleurs tests et un meilleur code.</p>
<p>De fait, on s&rsquo;évitera les pièges d&rsquo;écrire du code non-testable, d&rsquo;en faire trop, ou de ne pas correctement retranscrire le métier, comme on pourrait le faire en écrivant les tests a posteriori.</p>
<p>En écrivant les tests après, on subit l&rsquo;implémentation. Et plus on attend pour tester, plus on subit. Il y aura davantage de changements à effectuer, le coût va augmenter. Le refactoring sera d&rsquo;ailleurs difficile ; les tests ne sont pas écrits, on n&rsquo;a pas encore notre filet de sécurité en place.</p>
<p>=&gt; Non, ce n&rsquo;est pas plus long de pratiquer le TDD lorsque l&rsquo;on écrit déjà des tests a posteriori. C&rsquo;est un gain de temps, et en plus, un gain de qualité.</p>
<h2 id="je-ne-teste-pas">Je ne teste pas</h2>
<p>Je termine avec un dernier prisme qui n&rsquo;en ait pas moins intéressant : celui du développeur qui ne teste pas. Alors là, réflexe, on va se dire que c&rsquo;est bien plus long. Non seulement, il faut écrire du code supplémentaire (les tests), et en plus, il faut se coltiner une discipline stricte. On va perdre du temps, non ? Je propose de regarder sous deux horizons de temps.</p>
<h3 id="court-terme">Court terme</h3>
<p>À court terme, sur l&rsquo;instant, le TDD va nous guider. C&rsquo;est une de ses principales forces. Il nous guide pour concevoir le code de production, l&rsquo;implémentation. Il nous guide pour retranscrire le métier. Il nous offre une boucle de feedback extrêmement rapide pour créer et améliorer.</p>
<p>On prends le temps de bien faire et de réfléchir, mais pour autant, ce n&rsquo;est pas forcément plus long. Parce qu&rsquo;on se concentre sur l&rsquo;essentiel en progressant par petites étapes, parce qu&rsquo;on est guidé pour coder l&rsquo;implémentation, parce qu&rsquo;on a un feedback rapide contrairement aux tests manuels.</p>
<p>La pratique du TDD ne va pas seulement nous faire écrire des tests avant de coder, elle va nous aider à coder, à concevoir. Au final, on ralentit tout en gagnant du temps, pour mieux faire. On passe sensiblement le même temps à développer notre fonctionnalité.</p>
<p>Dans certains contextes, on est plus rapide, parce qu&rsquo;on se serait perdu en chemin sans le TDD, parce qu&rsquo;on aurait fait trop compliqué ou parce qu&rsquo;il y a beaucoup de logique. On perd vite du temps à explorer sans test et sans guide. Dans quelques autres contextes, ça peut être plus long de pratiquer le TDD, mais c&rsquo;est sans compter les effets obtenus à plus long terme.</p>
<h3 id="moyen-et-long-terme">Moyen et Long terme</h3>
<p>À moyen et long terme, on va obtenir de nouveaux bénéfices grâce à la pratique du TDD. Les tests vont couvrir notre code et vont faciliter le <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" rel="">refactoring</a> et réduire les régressions. On va gagner du temps.</p>
<p>La facilité de faire du refactoring va aider à améliorer continuellement le système. On va le maintenir et le faire évoluer plus facilement. On va le changer facilement. On va gagner du temps.</p>
<p>On aura du code et des tests qui reflètent mieux le métier et les cas d&rsquo;utilisations. On va mieux comprendre notre système. On va mieux échanger avec les autres. On va gagner du temps.</p>
<hr>
<h1 id="bref">Bref</h1>
<p>Au final, en regardant à travers ces différents prismes, on peut observer que les situations où un développeur trouve que c&rsquo;est plus long de pratiquer le TDD est peut-être à décorréler de la méthode elle-même. Souvent parce qu&rsquo;elle n&rsquo;est pas encore maîtrisée.</p>
<p>Dès lors qu&rsquo;on a une bonne pratique du TDD, des bénéfices apparaissent immédiatement, à court terme. La force que le TDD propose pour guider et donner du feedback rapide est assez puissante pour être d&rsquo;une grande aide pour le développeur tout en ne faisant pas <em>perdre de temps</em>.</p>
<p>Ces effets s&rsquo;accentuent à plus long terme, et d&rsquo;autres viennent s&rsquo;ajouter. On y voit un cercle vertueux d&rsquo;amélioration continue. Ce n&rsquo;est plus juste une question de temps, on y gagne sur plusieurs niveaux.</p>
]]></description></item><item><title>Pourquoi veut-on rendre un test unitaire indépendant ?</title><link>https://jordanchapuy.com/posts/2021/09/pourquoi-veut-on-rendre-un-test-unitaire-independant/</link><pubDate>Wed, 29 Sep 2021 08:50:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2021/09/pourquoi-veut-on-rendre-un-test-unitaire-independant/</guid><description><![CDATA[<p>L&rsquo;indépendance n&rsquo;existe pas uniquement dans certaines régions de France ou dans un film avec Will Smith. Il se trouve aussi dans les tests unitaires. Lorsque vous écrivez des tests, il y a un moment qui arrive où vous souhaitez être indépendant de quelque chose. Vous allez naturellement casser cette dépendance et injecter autre chose pour remplacer ce qui gêne.</p>
<p>Ce n&rsquo;est cependant pas une décision à prendre à la légère. Certaines raisons sont parfaitement justifiées, alors que d&rsquo;autres peuvent nuire au projet. Pourquoi a-t-on besoin de casser une dépendance dans certains tests ? Et de quoi veut-on être indépendant ? À quoi faut-il faire attention ? C&rsquo;est de tout ça dont j&rsquo;ai envie de parler aujourd&rsquo;hui.</p>
<figure>
</figure>

<h1 id="quest-ce-qui-nous-pose-problème-">Qu&rsquo;est-ce qui nous pose problème ?</h1>
<p>Commençons par le commencement. On veut savoir pourquoi rendre un test indépendant, regardons du côté des problèmes auxquels cette envie d&rsquo;indépendantisme répond.</p>
<h2 id="test-déterministe">Test déterministe</h2>
<p>Avoir des tests qui échouent sans raison apparente à première vue, c&rsquo;est embêtant. Encore plus lorsque ça semble être aléatoire. Et parfois, on a un passage au rouge du jour au lendemain, ce qui nous vaut la célèbre phrase &ldquo;ça marchait avant&rdquo;. Un test devrait avoir une intention claire et n&rsquo;avoir qu&rsquo;une seule raison d&rsquo;échouer. On n&rsquo;a pas envie de se lancer dans une session de debug pour comprendre ce qu&rsquo;il se passe.</p>
<p>Alors qu&rsquo;est-ce qui peut bien causer ces problèmes ? Un autre test. Ce bienfaiteur qu&rsquo;est le test peut en effet être une source d&rsquo;ennuis pour d&rsquo;autres tests. Lorsqu&rsquo;on lance un ensemble de tests, l&rsquo;environnement et la mémoire sont partagés entre eux. Si deux tests lisent et écrivent dans un même endroit, ils vont éventuellement affecter le résultat de l&rsquo;autre. Vous voyez où je veux en venir ? Base de données, fichiers, singletons, variables globales, &hellip; Tout ça représente une zone partagée et peut créer un lien de dépendance entre deux tests.</p>
<p>On arrive donc à notre première et principale raison. <strong>Pourquoi rendre un test indépendant ? Pour éviter un effet de bord venant d&rsquo;un autre test.</strong> C&rsquo;est dans ce but que l&rsquo;on va casser une dépendance envers une base de données, un système de fichiers ou un singleton. Et que l&rsquo;on mettra une fausse implémentation, avec un base de données en mémoire par exemple, pour avoir un état déterministe.</p>
<p>C&rsquo;est d&rsquo;ailleurs une autre raison, être déterministe. <strong>On veut rendre un test indépendant pour obtenir toujours le même résultat.</strong> Du côté des causes, on retrouvera celles vues précédemment et on peut notamment y ajouter d&rsquo;autres éléments perturbateurs comme les requêtes HTTP, la date du jour, les fonctions aléatoires (quoi de mieux qu&rsquo;un bon <code>random()</code> pour avoir un résultat imprévisible ? :p). Ce sont des sources qu&rsquo;on ne contrôle pas. Mais pour être déterministe, il faut les contrôler : on cassera alors les dépendances afin de les remplacer. Ou peut-être que l&rsquo;on s&rsquo;orientera vers la création de fonctions pures.</p>
<h2 id="test-rapide">Test rapide</h2>
<p>Ajoutons un autre problème, sinon ce n&rsquo;est pas marrant. Une suite de tests lente à exécuter est assez fâcheux. Les tests unitaires nous guident dans la conception et parfois nous rattrapent lors de sorties de route. On a besoin d&rsquo;un feedback rapide, et encore plus lorsque l&rsquo;on pratique le TDD.</p>
<p>On aura une nouvelle fois les mêmes fautifs. Feraient-ils preuve d&rsquo;intelligence ? On se le demande, mais en tout cas ça nous arrange puisqu&rsquo;il n&rsquo;y a pas de centaines de causes différentes. Principalement, tout ce qui accède au réseau, aux internets, ralentira fortement vos tests. On peut rester dans la centaine de millisecondes comme dépasser aisément la barre des secondes. C&rsquo;est sûrement la source la plus lente. Viennent ensuite les bases de données et le système de fichiers. Unitairement, le temps est peut-être faible, mais quand on dézoom et qu&rsquo;on regarde le cumul sur l&rsquo;ensemble des tests, ça devient (trop) long.</p>
<p>On en vient à notre dernière raison. <strong>On veut rendre un test indépendant pour qu&rsquo;il soit rapidement exécuté.</strong> Là encore, on cassera éventuellement des dépendances qu&rsquo;on substituera par quelque chose répondant immédiatement.</p>
<h2 id="couper-les-ponts">Couper les ponts</h2>
<p>Si on résume en une phrase, on souhaite rendre un test indépendant afin d&rsquo;éviter qu&rsquo;il soit affecté par les autres tests, pour être déterministe, et pour être rapide. Voilà. Ce sont les raisons principales. Pas besoin d&rsquo;aller chercher plus loin et d&rsquo;isoler complètement un test.</p>
<p>Un autre moyen d&rsquo;entrevoir ces raisons est de regarder du côté des <a href="https://jordanchapuy.com/posts/2020/04/first-5-principes-pour-guider-l-ecriture-des-tests-unitaires/" rel="">principes FIRST</a>. Ce sont des principes pour guider l&rsquo;écriture des tests, et je trouve qu&rsquo;ils reflètent bien les besoins d&rsquo;indépendance. On parle de rapidité d&rsquo;exécution (F pour Fast), de test indépendant des autres tests (I pour Independent) et de résultat déterministe (R pour Repeatable).</p>
<h1 id="quelques-mauvaises-compréhensions">Quelques mauvaises compréhensions</h1>
<p>Maintenant que nous avons bien en tête les raisons qui motivent les tests à devenir indépendant, revenons sur quelques mauvaises compréhensions. C&rsquo;est essentiel d&rsquo;en parler, car il peut y avoir un impact fort : tests fragiles, maintenance lourde, démotivation des développeurs.</p>
<h2 id="system-under-test">System Under Test</h2>
<p>Quand on parle de <em>SUT</em>, on parle de <em>SYSTEM Under Test</em>. Ce n&rsquo;est ni <em>Class Under Test</em> ni <em>Fonction Under Test</em>. C&rsquo;est très important. Le système, ce peut être une fonction, ou une classe, ou un ensemble de classes et de fonctions. Peu importe, on va tester l&rsquo;ensemble et tout ce qu&rsquo;il y a derrière. On peut voir ça comme un module, ou une boîte noire - <strong>on teste toute la boîte depuis notre point d&rsquo;entrée</strong>.</p>
<p>On ne cherche pas à isoler le système que l&rsquo;on teste des autres classes et fonctions qu&rsquo;il utilise. On rend le test indépendant, oui, mais pas la classe. On s&rsquo;en tiendra aux raisons évoquées plus haut pour casser des dépendances. C&rsquo;est parfaitement ok qu&rsquo;une méthode que l&rsquo;on teste appelle d&rsquo;autres classes, qui appelleront aussi d&rsquo;autres classes.</p>
<h2 id="heavy-mocking">Heavy mocking</h2>
<p>En comprenant bien ce qu&rsquo;est le <em>SUT</em> et ce qu&rsquo;il faut rendre indépendant, on s&rsquo;évite au passage la sur-utilisation de mocks. On ne va pas essayer de tout isoler et donc de tout mocker.</p>
<p><strong>Le problème avec les mocks, c&rsquo;est qu&rsquo;ils connaissent trop les détails de l&rsquo;implémentation</strong>. Si on change notre implémentation (on a une meilleure idée, on fait du refactoring), on va casser les tests. Les assertions vont être fausses et c&rsquo;est normal, le mock vérifie la mécanique interne.</p>
<p>La sur-utilisation des mocks va entraîner des problèmes en cascade : on couple les tests à l&rsquo;implémentation, on a du mal à faire du refactoring, le code devient difficile à changer, le développeur se démotive, il y a moins de tests, moins de qualité, fin. Vraiment, on ne veut pas coupler les tests à l&rsquo;implémentation :)</p>
<h1 id="comportement">Comportement</h1>
<p>Ça me fait une bonne ouverture pour terminer. Ce que l&rsquo;on veut tester, c&rsquo;est le comportement. Quand on fait des applications, c&rsquo;est pour répondre à un besoin métier. C&rsquo;est ça que l&rsquo;on veut tester. On se limitera à enlever les dépendances gênantes pour les tests unitaires. <strong>Testez le comportement plutôt que les détails de l&rsquo;implémentation</strong>.</p>
<figure>
</figure>

<p><em>Crédits photos : Anne Nygård, Richard Lee.</em></p>
]]></description></item><item><title>Apprendre en pratiquant avec des katas de code</title><link>https://jordanchapuy.com/posts/2021/08/apprendre-en-pratiquant-avec-des-katas-de-code/</link><pubDate>Mon, 23 Aug 2021 15:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2021/08/apprendre-en-pratiquant-avec-des-katas-de-code/</guid><description><![CDATA[<p>Lorsque j&rsquo;ai appris à faire du vélo, j&rsquo;ai commencé à en faire dans mon jardin, dans la Drôme. Mon vélo avait deux petites roulettes sur la roue arrière, ça m&rsquo;aidait beaucoup. On peut dire que j&rsquo;étais dans un cadre sécurisant : à l&rsquo;intérieur de mon jardin, avec peu de risque de chute et sans circulation de véhicules. J&rsquo;ai pédalé des heures et des heures pour améliorer ma maîtrise. J&rsquo;ai appris par la pratique, en répétant, en essayant, en m&rsquo;améliorant. J&rsquo;étais à l&rsquo;aise, bien plus qu&rsquo;à Paris lorsque j&rsquo;utilisais les anciens Vélib - les tanks.</p>
<p>Les katas de code forment un moyen très intéressant pour apprendre par la pratique. On découvre, on explore, on essaie, on répète, on améliore. Bref, on apprend. Et à l&rsquo;image du vélo à roulette, on est dans un cadre sécurisé et simplifié.</p>
<p><strong>Je fais des katas pour apprendre de nouvelles choses.</strong> Ces <em>choses</em> peuvent être très variées. Des langages par exemple. Je me suis amusé avec Kotlin, Typescript, Clojure, Elixir, Elm ainsi que F# récemment. Des langages très <strong>hétérogènes</strong>. Ça me permet d&rsquo;agrandir ma vision, d&rsquo;obtenir de nouvelles connaissances et d&rsquo;être moins lié à un éco-système ou à une façon de faire. Via les katas de code, j&rsquo;apprends aussi des concepts comme CQRS et Event-Sourcing, ou le Mutation Testing. Je m&rsquo;entraîne à toujours mieux concevoir mon code, le rendre plus simple, plus compréhensible, à mieux retranscrire le métier.</p>
<p>Avec les katas, <strong>je répète des gestes pour parfaire ma maîtrise</strong>. Le mot kata est d&rsquo;ailleurs un terme japonnais qui vient des arts martiaux. Le but est de travailler des techniques en toute sécurité en répétant des gestes. On apprend par la répétition dans un environnement dédié à l&rsquo;apprentissage (ce n&rsquo;est pas un vrai combat). J&rsquo;utilise les katas de code pour répéter l&rsquo;écriture de tests, le TDD, le <a href="https://jordanchapuy.com/posts/2021/06/le-refactoring/" target="_blank" rel="noopener noreffer">Refactoring</a>. <strong>C&rsquo;est par une longue pratique et des contextes différents que l&rsquo;expérience vient.</strong> On n&rsquo;acquiert pas une maîtrise après avoir lu un article et une vidéo sur YouTube. Je vais parfois faire plusieurs fois le même kata de manière différente, et parfois répéter la même manière mais sur des katas différents.</p>
<p><strong>La nature éphémère et simple d&rsquo;un kata de code apporte un cadre favorisant l&rsquo;apprentissage</strong> (à opposer avec un projet perso ou la production en entreprise). Je peux expérimenter comme bon me semble, je peux recommencer autant que je veux, je peux prendre le temps que je veux. Je choisis mes contraintes. Il n&rsquo;y a pas de mise en danger ni d&rsquo;impératif.</p>
<p><strong>Il n&rsquo;y a pas d&rsquo;âge pour faire des katas de code</strong>. <em>Je suis Junior, je suis Senior, je sors d&rsquo;école, j&rsquo;ai 12 années d&rsquo;expériences&hellip;</em> En fait, la bonne affirmation serait plutôt <strong>j&rsquo;ai toujours à apprendre et à approfondir</strong>. Que ce soit dans notre domaine de prédilection ou dans d&rsquo;autres qui restent à explorer. Je fais partie d&rsquo;un groupe de kata pour coder et réfléchir ensemble, composé de développeurs expérimentés. Malgré tout, on continue d&rsquo;apprendre et de se casser quelques dents. Et on aime ça.</p>
<p>Je fais des katas seul, pour explorer ce que je veux, quand je le veux. Et je fais également <strong>des katas en groupe pour démultiplier mon apprentissage</strong>. En mob-programming, nous partageons, nous discutons, nous confrontons des visions, nous essayons différentes solutions. Nous nous ouvrons et nous apprenons les uns des autres.</p>
<p>C&rsquo;est tout ça, pour moi, la magie des katas. C&rsquo;est un très bon levier d&rsquo;apprentissage et terrain de jeu. Bien sûr, ce n&rsquo;est ni le seul moyen d&rsquo;apprendre, ni suffisant. Je vais aussi lire des livres pour obtenir plus de théorie et de profondeur, assister à des conférences, pratiquer sur des projets réels, etc.</p>
<h2 id="votre-prochain-kata">Votre prochain kata</h2>
<p>J&rsquo;en arrive à la fin de ce que je voulais raconter. Il me reste à vous partager des liens pour trouver vos futurs katas de code ainsi qu&rsquo;une petite sélection de ceux que j&rsquo;apprécie, puis je retournerais m&rsquo;amuser.</p>
<p>Je ne peux parler de kata sans mentionner Emily Bache. Coach et auteur du livre <em>Coding Dojo Handbook</em>, Emily possède <a href="https://github.com/emilybache" target="_blank" rel="noopener noreffer">un compte GitHub</a> qui fourmille de katas (un grand merci à elle). Elle les prépare et les utilise pour accompagner des équipes; vous en aurez pour tous les goûts.</p>
<p>Certains sites et pages GitHub recensent également des katas. En voici trois que j&rsquo;utilise régulièrement pour piocher des sujets : <a href="https://codingdojo.org/kata/" target="_blank" rel="noopener noreffer">Coding Dojo</a>, <a href="https://kata-log.rocks/" target="_blank" rel="noopener noreffer">Kata-log</a> et <a href="https://github.com/gamontal/awesome-katas" target="_blank" rel="noopener noreffer">Awesome Katas</a>. Et n&rsquo;oubliez pas votre moteur de recherche préféré, il se fera un plaisir de vous en faire découvrir d&rsquo;autres.</p>
<p>En ce moment, je suis sur un kata bien sympa qui reprend les mécaniques d&rsquo;un jeu de carte dans le style de Hearthstone, le <a href="https://github.com/bkimminich/kata-tcg" target="_blank" rel="noopener noreffer">Trading Card Game</a>. J&rsquo;aime également le Bank Account, le Mars Rover, le Game of Life et le GildedRose. Ils font partie de mes classiques. Ils sont simples et très efficaces. Ils permettent de s&rsquo;amuser avec de multiples concepts différents et d&rsquo;expérimenter plusieurs solutions.</p>
<p>Vous voilà avec de nombreuses raisons de vous lancer, et toute une liste de katas potentiels. Bon apprentissage !</p>
]]></description></item><item><title>Démarrer avec Kotlin</title><link>https://jordanchapuy.com/posts/2021/04/demarrer-avec-kotlin/</link><pubDate>Sun, 18 Apr 2021 20:20:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2021/04/demarrer-avec-kotlin/</guid><description><![CDATA[<p>J’ai remarqué que peu de développeurs savaient bootstrap un nouveau projet. La preuve en est pour Kotlin, où j’ai dû demander à plusieurs développeurs avant d’obtenir l’aide de Cédric pour régler une broutille. Vu que j’aime faire des petits ateliers de code et également en animer, des katas par exemple, je me suis dit que ce serait pratique d’avoir un guide de démarrage rapide, avec l’essentiel pour m’en rappeler ou pour le donner aux participants d’un atelier. Des choses comme la création du projet, l’ajout de dépendances, les différents tests, et quelques liens utiles.</p>
<p>Voici donc un premier guide pour Kotlin. Je le partage pour m’aider moi ou quiconque voudra se lancer rapidement dans un petit projet de code avec des tests. C’est un essentiel à l’instant T, je le mettrais possiblement à jour dans le temps avec de nouvelles choses. Si vous avez des remarques, je suis preneur.</p>
<h1 id="création-dun-projet">Création d’un projet</h1>
<p>Il existe d’autres solutions, mais je ne parlerais que de Gradle qui est plus récent et qui est recommandé.</p>
<h2 id="via-intellij-idea">Via Intellij IDEA</h2>
<p>JetBrains a créé le langage et l’outillage. La création d’un projet Kotlin est simple et rapide. On passe par le menu : File &gt; New &gt; Project.</p>
<p>Les possibilités changent ensuite selon l’édition de Intellij et/ou du système d’exploitation je suppose.</p>
<p>Si vous avez la possibilité, sélectionnez Kotlin puis Console Application. Gradle y sera ajouté par défaut. La documentation officielle va dans ce sens. Sinon, si vous êtes comme moi sur macOS avec l’édition Intellij IDEA CE, sélectionnez Gradle puis cochez Kotlin/JVM.</p>
<p>Plus d’informations : <a href="https://kotlinlang.org/docs/jvm-get-started.html" target="_blank" rel="noopener noreffer">https://kotlinlang.org/docs/jvm-get-started.html</a></p>
<h2 id="en-ligne-de-commande">En ligne de commande</h2>
<p>La simplicité est également présente en ligne de commande. Il suffit d’exécuter <code>gradle init</code> puis de se laisser guider. Ce que je choisis en général :</p>
<ul>
<li>Type of project : application.</li>
<li>Implementation language : Kotlin.</li>
<li>Script DSL : Groovy ou Kotlin.</li>
</ul>
<h1 id="exécution-du-projet-et-des-tests">Exécution du projet et des tests</h1>
<h2 id="via-intellij-idea-1">Via Intellij IDEA</h2>
<p>D’un clic-droit sur un module ou un fichier dans l’arborescence, il est possible de compiler le projet, lancer le projet, et lancer les tests.</p>
<p>Les résultats des tests sont visibles dans un des onglets du bas d’Intellij IDEA. Il est possible de voir tous les tests, ou de filtrer selon le succès ou l’échec.</p>
<p>⚠️ Kotest : Parfois, il faut aller sur le menu latéral « Gradle » et cliquer sur Tasks &gt; verification &gt; test. Lancer la tâche « test » manuellement pour voir tous les tests se lancer. Problème dû à kotest ou à la présence de plusieurs frameworks de tests ?</p>
<h2 id="en-ligne-de-commande-1">En ligne de commande</h2>
<p>Le projet étant créé avec Gradle, on passera toujours par la commande <code>gradle</code> pour effectuer des actions.</p>
<ul>
<li>Lancer les tests : <code>gradle test</code></li>
<li>Lancer les tests automatiquement (watch mode) : <code>gradle test —continuous</code></li>
<li>Lancer l’application : <code>gradle run</code></li>
</ul>
<h1 id="choix-de-lide">Choix de l’IDE</h1>
<h2 id="intellij-idea">Intellij IDEA</h2>
<p>Sans hésiter, je dirais d’utiliser Intellij IDEA. JetBrains a un très bon savoir-faire. L’IDE est très complet en termes de fonctionnalités, les possibilités de refactoring sont nombreuses, et l’écosystème Kotlin est très bien intégré. La version communautaire est en plus gratuite.</p>
<p>On trouve toutes les options de refactoring à l’aide du raccourci <code>Ctrl + T</code>.</p>
<h1 id="gestion-des-dépendances">Gestion des dépendances</h1>
<p>Le fichier de configuration principal est <code>build.gradle</code> (Groovy) ou <code>build.gradle.kts</code> (Kotlin).</p>
<p>Pour ajouter des dépendances, on est souvent amené à insérer des lignes dans l’étape nommée <code>dependencies</code>. Par exemple :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Groovy" data-lang="Groovy"><span class="line"><span class="cl"><span class="n">dependencies</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">testImplementation</span> <span class="s1">&#39;org.jetbrains.kotlin:kotlin-test-junit5&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">testImplementation</span> <span class="s1">&#39;org.junit.jupiter:junit-jupiter-api:5.6.0&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">testRuntimeOnly</span> <span class="s1">&#39;org.junit.jupiter:junit-jupiter-engine:5.6.0&#39;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></div><p>⚠️ Lorsque l’on ajoute une nouvelle dépendance, il faut vérifier que celle-ci ne va pas entrer en conflit ou n’est pas en double (sous une autre version). Ce peut être le cas lorsque l’on initialise le projet en ligne de commande et que l’on ajoute les dépendances de JUnit. L’erreur est difficilement visible : au lancement des tests, aucun d’eux n’est trouvé.</p>
<p>⚠️ Il existe plusieurs sources pour récupérer les dépendances : les <code>repositories</code>. Il peut être nécessaire de changer ou d’ajouter une source pour résoudre les dépendances.</p>
<p>⚠️ Après un changement dans le fichier de configuration, il peut être nécessaire de recharger Gradle dans Intellij IDEA. Une petite icône Gradle est peut-être apparue par-dessus le contenu du fichier.</p>
<h2 id="variables">Variables</h2>
<p>On peut définir des variables dans le fichier de configuration. Exemple en Groovy :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Groovy" data-lang="Groovy"><span class="line"><span class="cl"><span class="kt">def</span> <span class="n">kotestversion</span> <span class="o">=</span> <span class="s1">&#39;4.4.3&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">dependencies</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">testImplementation</span> <span class="s1">&#39;org.jetbrains.kotlin:kotlin-test-junit5&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">testImplementation</span> <span class="s1">&#39;org.junit.jupiter:junit-jupiter-api:5.6.0&#39;</span>
</span></span><span class="line"><span class="cl">    <span class="n">testRuntimeOnly</span> <span class="s1">&#39;org.junit.jupiter:junit-jupiter-engine:5.6.0&#39;</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></div><p>⚠️ Les variables ne peuvent pas figurer dès le début du fichier.</p>
<p>⚠️ Il faut faire attention à bien utiliser les double quotes. Certaines documentations comme celle de kotest donnent des instructions qui ne compilent pas.</p>
<h1 id="écrire-des-tests-unitaires">Écrire des tests unitaires</h1>
<h2 id="tests-unitaires-classiques">Tests unitaires classiques</h2>
<p>JUnit fonctionne très bien avec Kotlin sur JVM. Il suffit d’annoter la fonction avec <code>@Test</code> et d’utiliser un des <code>assert</code>. Voir <a href="https://kotlinlang.org/docs/jvm-test-using-junit.html" target="_blank" rel="noopener noreffer">documentation officielle</a> pour ajouter la dépendance.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl"><span class="nd">@Test</span>
</span></span><span class="line"><span class="cl"><span class="k">fun</span> <span class="nf">testSum</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">val</span> <span class="py">expected</span> <span class="p">=</span> <span class="m">43</span>
</span></span><span class="line"><span class="cl">    <span class="n">assertEquals</span><span class="p">(</span><span class="n">expected</span><span class="p">,</span> <span class="n">classForTesting</span><span class="p">.</span><span class="n">sum</span><span class="p">(</span><span class="m">40</span><span class="p">,</span> <span class="m">2</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="assertions-et-matchers">Assertions et matchers</h2>
<p>JUnit propose quelques <code>assert</code> classiques. On peut y ajouter les matchers de Kotest (une des <a href="https://kotest.io/docs/assertions/assertions.html" target="_blank" rel="noopener noreffer">sous-dépendances</a>) pour avoir davantage de possibilités.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl"><span class="n">name</span> <span class="n">shouldBe</span> <span class="s2">&#34;sam&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="s2">&#34;substring&#34;</span><span class="p">.</span><span class="n">shouldContain</span><span class="p">(</span><span class="s2">&#34;str&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">           <span class="p">.</span><span class="n">shouldBeLowerCase</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">mylist</span><span class="p">.</span><span class="n">forExactly</span><span class="p">(</span><span class="m">3</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">it</span><span class="p">.</span><span class="n">city</span> <span class="n">shouldBe</span> <span class="s2">&#34;Chicago&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="parameterized-tests">Parameterized tests</h2>
<p>JUnit propose un moyen de rendre une fonction de test paramétrable grâce aux annotations <code>@ParameterizedTest</code> et <code>@MethodSource</code>. La fonction de test acceptera alors des paramètres en entrée pour jouer le scénario avec différentes valeurs. Kotest le permet également à sa façon.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl"><span class="k">internal</span> <span class="k">class</span> <span class="nc">MarsRoverTest</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">companion</span> <span class="k">object</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nd">@JvmStatic</span>
</span></span><span class="line"><span class="cl">        <span class="k">fun</span> <span class="nf">leftCommands</span><span class="p">()</span> <span class="p">=</span> <span class="n">listOf</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">Arguments</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="s2">&#34;N&#34;</span><span class="p">,</span> <span class="s2">&#34;W&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">Arguments</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="s2">&#34;W&#34;</span><span class="p">,</span> <span class="s2">&#34;S&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">Arguments</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="s2">&#34;E&#34;</span><span class="p">,</span> <span class="s2">&#34;N&#34;</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="n">Arguments</span><span class="p">.</span><span class="n">of</span><span class="p">(</span><span class="s2">&#34;S&#34;</span><span class="p">,</span> <span class="s2">&#34;E&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nd">@ParameterizedTest</span><span class="p">(</span><span class="n">name</span> <span class="p">=</span> <span class="s2">&#34;The new direction is {1} with initial direction {0}&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="nd">@MethodSource</span><span class="p">(</span><span class="n">value</span> <span class="p">=</span> <span class="p">[</span><span class="s2">&#34;leftCommands&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">    <span class="k">internal</span> <span class="k">fun</span> <span class="nf">`Should turn left`</span><span class="p">(</span><span class="n">initialDirection</span><span class="p">:</span> <span class="n">String</span><span class="p">,</span> <span class="n">newDirection</span><span class="p">:</span> <span class="n">String</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">world</span> <span class="p">=</span> <span class="n">World</span><span class="p">(</span><span class="m">3</span><span class="p">,</span><span class="m">3</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">val</span> <span class="py">marsRover</span> <span class="p">=</span> <span class="n">MarsRover</span><span class="p">(</span><span class="n">position</span><span class="p">,</span> <span class="n">initialDirection</span><span class="p">,</span> <span class="n">world</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">marsRover</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span><span class="n">listOf</span><span class="p">(</span><span class="s2">&#34;L&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">marsRover</span><span class="p">.</span><span class="n">direction</span> <span class="n">shouldBe</span> <span class="n">newDirection</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="property-based-testing">Property-based Testing</h2>
<p>Kotest permet de faire du Property-based Testing via de nombreux générateurs et apporte plusieurs fonctionnalités (shrinking, repeatable random seeds, …). Ajout de la dépendance et utilisations sur <a href="https://kotest.io/docs/proptest/property-based-testing.html" target="_blank" rel="noopener noreffer">la documentation officielle</a>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Kotlin" data-lang="Kotlin"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">PropertyExample</span><span class="p">:</span> <span class="n">StringSpec</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">   <span class="s2">&#34;String size&#34;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">checkAll</span><span class="p">&lt;</span><span class="n">String</span><span class="p">,</span> <span class="n">String</span><span class="p">&gt;</span> <span class="p">{</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span> <span class="o">-&gt;</span>
</span></span><span class="line"><span class="cl">         <span class="p">(</span><span class="n">a</span> <span class="p">+</span> <span class="n">b</span><span class="p">).</span><span class="n">length</span> <span class="n">shouldHaveLength</span> <span class="n">a</span><span class="p">.</span><span class="n">length</span> <span class="p">+</span> <span class="n">b</span><span class="p">.</span><span class="n">length</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">})</span>
</span></span></code></pre></div><h2 id="code-coverage">Code Coverage</h2>
<p>Plus tard :)</p>
<h2 id="mutation-testing">Mutation Testing</h2>
<p>Plus tard :)</p>
<h1 id="apprendre-le-langage">Apprendre le langage</h1>
<p>Selon les goûts et les couleurs, voici plusieurs moyen d’apprendre Kotlin.</p>
<ul>
<li>
<p>La <a href="https://kotlinlang.org/docs/home.html" target="_blank" rel="noopener noreffer">documentation officielle</a>. On y trouve un tas d&rsquo;explications, d&rsquo;exercices et de ressources autour du langage.</p>
</li>
<li>
<p>Les <a href="https://kotlinlang.org/docs/koans.html" target="_blank" rel="noopener noreffer">Koans</a>. De petits exercices pour apprendre par petites étapes, en étant guidé dans différents thèmes.</p>
</li>
<li>
<p><a href="https://learnxinyminutes.com/docs/kotlin/" target="_blank" rel="noopener noreffer">Learn X in Y minutes sur Kotlin</a>. Un condensé de ce qu’il faut savoir sur n’importe quel langage.</p>
</li>
<li>
<p>La <a href="https://kotlinlang.org/docs/coding-conventions.html" target="_blank" rel="noopener noreffer">convention de code officielle</a>. Afin de ne pas se faire taper dessus par les puristes.</p>
</li>
</ul>
<h1 id="repl">REPL</h1>
<p>Plus tard :)</p>
]]></description></item><item><title>Automatically run tests when a change occurs</title><link>https://jordanchapuy.com/posts/2020/06/automatically-run-tests-when-a-change-occurs/</link><pubDate>Thu, 04 Jun 2020 09:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2020/06/automatically-run-tests-when-a-change-occurs/</guid><description><![CDATA[<p>I would like to talk to you about unit tests and how you can automatically run them as soon as you modify code. I regularly use the Test-Driven Development approach when I write code for a project or when doing a code kata. Sometimes I write a little bit too much before running tests again, and when tests turn red, I’m telling myself “Oh! But since when was I wrong?”.</p>
<p>I am jealous of the experience Visual Studio offers with C# and the <a href="https://docs.microsoft.com/en-us/visualstudio/test/live-unit-testing" target="_blank" rel="noopener noreffer">Live Unit Testing</a> feature. Each line of the code is decorated with a symbol indicating if it is covered by passing tests or failing tests, in real-time. Awesome. I need something like that.</p>
<p>I started by searching a similar tool for the languages I use. Then I created a simple script, which runs a command after each file change. Finally, I found a really nice tool for file change monitoring. It is powerful, cross-platform, and open-source. And that’s what I want to talk to you about.</p>
<figure>
</figure>

<hr>
<h1 id="watch-my-changes-">Watch my changes! 🔍</h1>
<p>One way to improve the feedback given by our tests is to know immediately if a change breaks a test. To achieve this goal, we have to continually run tests. The more often we run the tests, the smaller the failing piece of code will be. Ideally, tests should be run after each change. But we can easily forget, or it can be cumbersome.</p>
<p>So we need a way to monitor files and automatically execute a command if there is a change. Some languages and tools offer a built-in way to do that. For example:</p>
<ul>
<li>Kotlin through Gradle &gt; <code>gradle test —-continuous</code></li>
<li>Elm with elm-test &gt; <code>elm-test --watch</code></li>
</ul>
<p>But what if the programming language and tool we are using do not have a watch option? This is where <em>fswatch</em> comes in.</p>
<hr>
<h1 id="fswatch-">fswatch 📡</h1>
<p>Open-source and cross-platform, <em>fswatch</em> is a great tool to monitor file change. It provides recursive directory monitoring, filtering, and supports many OS-specific APIs such as <em>kevent</em>, <em>inotify</em>, and <em>FSEvents</em>.</p>
<p>By using these low-level APIs, <em>fswatch</em> is able to detect any changes in your specified paths and to send informations to another command. The tool is good enough to throttle the execution of the command: it will wait for the user to stop editing the code.</p>
<p>For more information about features or how to install it, please take a look at the GitHub repository.</p>
<p><a href="https://github.com/emcrisostomo/fswatch" target="_blank" rel="noopener noreffer">https://github.com/emcrisostomo/fswatch</a></p>
<h2 id="usage">Usage</h2>
<p>In most cases, you simply want to fire a command as soon as a change is detected in a folder. It’s as simple as this line:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or YOUR_PATHS <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> YOUR_COMMAND
</span></span></code></pre></div><p><em>fswatch</em> accepts a list of paths to monitor. The <code>o</code> option asks the tool to group changes by batch, and the <code>r</code> option stands for watching subdirectories recursively. Events are then sent through <code>xargs</code> to your command. Here is an example for swift, observing one folder:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or ./Project <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> swift <span class="nb">test</span>
</span></span></code></pre></div><p>Note that <em>fswatch</em> will run until you stop it, by pressing <code>Control + Z</code> on macOS or <code>Control + C</code> on Linux for example. But that’s what we want, run indefinitely regardless of the test results.</p>
<figure><figcaption>
            <p><em>Screenshot from a terminal executing fswatch.</em></p>
        </figcaption>
</figure>

<hr>
<h1 id="going-further-">Going further 🚀</h1>
<p>So, you got the basics. Now we will see how to improve it.</p>
<h2 id="choose-carefully-the-files-to-monitor">Choose carefully the files to monitor</h2>
<p>You may want to not run your tests for every kind of file changed. A change in an image or in a <em>temp</em> folder probably does not interest you. Observing the right files allows you to run tests only if an impacting change occurs. It can also prevent you from going into an infinite loop.</p>
<p>I had a case where build files were generated after each test, so that triggered the watch, and run tests again, and changes appear, and… this story will never end. The easiest solution for me was to specify multiple sub-directories as input to fswatch` instead of the whole project folder. Remember that you can set multiple paths.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or ./Sources ./Tests <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> swift <span class="nb">test</span>
</span></span></code></pre></div><p>The other way is to include or exclude paths matching a regex. According to the <em>fswatch</em> manual, you can set options like <code>-i, --include</code> and <code>-e, --exclude</code> for that.</p>
<h2 id="create-a-script">Create a script</h2>
<p>Sometimes, the command you want to fire for each change is long and requires a lot of parameters. It may even be composed of multiple commands. In that case, I recommend you to decompose this step and to create a script to run your tests.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-Bash" data-lang="Bash"><span class="line"><span class="cl">fswatch -or ./Sources ./Tests <span class="p">|</span> xargs -n1 -I<span class="o">{}</span> run-tests.sh
</span></span></code></pre></div><p>Better, isn’t it? But we can still improve that. We can avoid typing that long line every time we start working. You see me coming, we’ll make a second script that will do it.</p>
<p><code>live-tests.sh</code></p>
<h2 id="keep-it-visible">Keep it visible</h2>
<p>Now that we have a real-time feedback, we want to see it. It would be a shame to have it hidden in the background. Good news, it is quite easy to keep a terminal in the foreground. Perhaps your favorite editor has already a panel with a terminal, and you just have to show it. Visual Studio Code, for instance.</p>
<p>Some editors like Sublime Text do not have a terminal panel by default, but you can add it with a plugin or extension. And if that’s not possible, you still have the option to put the terminal on a second screen, if you have one, or to reduce your editor window and put a terminal at the left, right, or bottom of it.</p>
<figure><figcaption>
            <p><em>Screenshot from Visual Studio Code with a terminal panel at the bottom.</em></p>
        </figcaption>
</figure>

<hr>
<p>You have everything you need to get started. Monitoring files is at your hands. Enjoy the continuous and real-time feedback of your unit tests.</p>
]]></description></item><item><title>Playgrounds: Speed up your tests feedback in Swift</title><link>https://jordanchapuy.com/posts/2020/05/playgrounds-speed-up-your-tests-feedback-in-swift/</link><pubDate>Mon, 04 May 2020 09:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2020/05/playgrounds-speed-up-your-tests-feedback-in-swift/</guid><description><![CDATA[<p>Playgrounds was released in September, 2016. It’s a powerful environment integrated in Xcode to code in real-time in Swift. Using Playgrounds is a great way to learn, experiment, and quickly prototype.</p>
<p>This is particularly interesting when comparing its speed with an iOS or macOS project. Compiling such a project takes tens of seconds or even several minutes. Running tests is therefore also slowed down.</p>
<p>Test-Driven Development is about getting feedback quickly. Wouldn’t it be interesting to get real-time results? Let’s see how we can leverage Playgrounds to write and run unit tests in Swift.</p>
<figure>
</figure>

<hr>
<h1 id="writing-unit-tests">Writing unit tests</h1>
<p><a href="https://developer.apple.com/documentation/xctest" target="_blank" rel="noopener noreffer">XCTest</a>, the Apple framework for unit testing, is available through Playgrounds. Writing unit tests in Playgrounds is exactly similar to writing them inside a project with a unit test target. You just have to import <code>XCTest</code> and to write unit tests inside a test case class:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">import</span> <span class="nc">XCTest</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">HelloServiceTests</span><span class="p">:</span> <span class="n">XCTestCase</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">testMakeMessage</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Arrange</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">now</span> <span class="p">=</span> <span class="mi">1587301244</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">dateProvider</span> <span class="p">=</span> <span class="n">FakeDateProvider</span><span class="p">(</span><span class="n">now</span><span class="p">:</span> <span class="n">now</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">service</span> <span class="p">=</span> <span class="n">HelloService</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">:</span> <span class="n">dateProvider</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Act</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">message</span> <span class="p">=</span> <span class="n">service</span><span class="p">.</span><span class="n">makeMessage</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Assert</span>
</span></span><span class="line"><span class="cl">        <span class="n">XCTAssertEqual</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="s">&#34;1587301244 - Hello.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>It does not change your habits. You write a unit test, instantiate a class, call a method and assert a result as you are used to. You can add as many tests and test cases as you want. See? Simple.</p>
<hr>
<h1 id="running-unit-tests">Running unit tests</h1>
<p>The difference with a classic unit test target starts here, but that does not mean it will be complicated. Rather, it’s very simple. The solution fits in one line of code. Here it is:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="n">HelloServiceTests</span><span class="p">.</span><span class="n">defaultTestSuite</span><span class="p">.</span><span class="n">run</span><span class="p">()</span>
</span></span></code></pre></div><p>Results of unit tests will appear in the console. These are the same logs you can find in Xcode. Each time you are changing the code, unit tests will be automatically launched again and new logs will be printed.</p>
<div class="details admonition info open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-info-circle fa-fw"></i>Console<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><p>Test Suite ‘HelloServiceTests’ started at 2020–04–30 16:31:24.776</p>
<p>Test Case ‘-[HelloServiceTests testMakeMessage]’ started.</p>
<p>Test Case ‘-[HelloServiceTests testMakeMessage]’ passed (0.017 seconds).</p>
<p>Test Suite ‘HelloServiceTests’ passed at 2020–04–30 16:31:24.794.</p>
<p>Executed 1 test, with 0 failures (0 unexpected) in 0.017 (0.018) seconds</p>
</div>
        </div>
    </div>
<p>But, why do we need this line? With an Xcode project, to run a test, we are usually pressing <code>Cmd + U</code> or choosing <code>Product &gt; Test</code> from the menu. Behind the scene, the test target gathers every test case and test method while we are creating them. This list is then given to the test runner which will execute every test listed.</p>
<p>In a playground, this process does not exist really. We have to manually create a test suite (something containing all of the tests) and run it. If you want to know more about the behaviors of unit testing frameworks, I recommend you to take a look at <a href="http://xunitpatterns.com/XUnit%20Basics.html" target="_blank" rel="noopener noreffer">xUnitPatterns.com</a>.</p>
<h2 id="having-multiple-xctestcase">Having multiple XCTestCase</h2>
<p>Previously, I told you that you can write as many test cases as you want. So if you want to run all of thems, you will have to create and run all test suites. One way to do that is to call the <code>run</code> method on each default test suite. But there is a better way:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">globalSuite</span> <span class="p">=</span> <span class="n">XCTestSuite</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="s">&#34;Global - All tests&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">globalSuite</span><span class="p">.</span><span class="n">addTest</span><span class="p">(</span><span class="n">HelloServiceTests</span><span class="p">.</span><span class="n">defaultTestSuite</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">globalSuite</span><span class="p">.</span><span class="n">addTest</span><span class="p">(</span><span class="n">FooTests</span><span class="p">.</span><span class="n">defaultTestSuite</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">globalSuite</span><span class="p">.</span><span class="n">run</span><span class="p">()</span>
</span></span></code></pre></div><p>The main advantage of creating a global test suite is to have numbers that aggregate all the cases. You will have results and failures for each test suite, and at the end, the global count.</p>
<div class="details admonition info open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-info-circle fa-fw"></i>Console<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><p>Test Suite ‘Global — All tests’ passed at 2020–04–30 16:31:24.794.</p>
<p>Executed 3 tests, with 0 failures (0 unexpected) in 0.018 (0.028) seconds</p>
</div>
        </div>
    </div>
<p>Adding a suite to a suite is possible because everything is <code>XCTest</code>: <code>XCTestCase</code> and <code>XCTestSuite</code> inherit from <code>XCTest</code>. If you have multiple unit test targets in your project, you will see that your tests are grouped per class and target.</p>
<h2 id="improving-errors">Improving errors</h2>
<p>Reading errors through a long log isn’t the most attractive way to work in Test-Driven Development. There aren’t those little red or green badges next to every test. To improve our experience, we can use <code>XCTestObservationCenter</code> to observe the progression of test runs through an object implementing <code>XCTestObservation</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">TestObserver</span><span class="p">:</span> <span class="n">NSObject</span><span class="p">,</span> <span class="n">XCTestObservation</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">testCase</span><span class="p">(</span><span class="kc">_</span> <span class="n">testCase</span><span class="p">:</span> <span class="n">XCTestCase</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                  <span class="n">didFailWithDescription</span> <span class="n">description</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">                  <span class="n">inFile</span> <span class="n">filePath</span><span class="p">:</span> <span class="nb">String</span><span class="p">?,</span> 
</span></span><span class="line"><span class="cl">                  <span class="n">atLine</span> <span class="n">lineNumber</span><span class="p">:</span> <span class="nb">Int</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Do something here.</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">let</span> <span class="nv">testObserver</span> <span class="p">=</span> <span class="n">TestObserver</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="n">XCTestObservationCenter</span><span class="p">.</span><span class="n">shared</span><span class="p">.</span><span class="n">addTestObserver</span><span class="p">(</span><span class="n">testObserver</span><span class="p">)</span>
</span></span></code></pre></div><p>Multiple methods are responding to different events. The one in the example is called when a test case reports a failure. This is an opportunity to improve feedback.</p>
<p>We can add an <code>assertionFailure</code>, for example. In a playground, this statement will stop the execution. Because the log is written progressively, the last message will be our error message.</p>
<div class="details admonition info open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-info-circle fa-fw"></i>Console<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><p>Test Case ‘-[HelloServiceTests testMakeMessage]’ started.</p>
<p>MyPlayground.playground:26: error: -[HelloServiceTests testMakeMessage] : XCTAssertEqual failed: (“15873012445 — Hello.”) is not equal to (“1587301244 — Hello.”)</p>
<p>Fatal error: XCTAssertEqual failed: (“15873012445 — Hello.”) is not equal to (“1587301244 — Hello.”): file MyPlayground.playground, line 26</p>
</div>
        </div>
    </div>
<p>We can also code our data structure and have a better print, or whatever other behavior we want. And why not a live view?</p>
<hr>
<h1 id="organizing-files">Organizing files</h1>
<p>As I see Playgrounds, it’s meant for easily and quickly prototype and try things. It can be difficult to make a big project with it, mainly because of the file management and the tree structure. However, we don’t have to do everything in one file.</p>
<h2 id="having-multiple-files">Having multiple files</h2>
<p>The Navigator, the left panel of Xcode and Playgrounds, is often hidden. Well, it’s understandable: we code almost all the time only in the main window and file. If you take a look at the Navigator, you can see a <code>Sources</code> folder.</p>
<p>Here, you can add every file we want. The <code>Sources</code> folder is considered as a different module by Playgrounds. It means two things. First, you need to explicitly set access levels to <code>public</code> on every object, method, or property you want to access. In a Swift module, the default access level is <code>internal</code>.</p>
<p>Second, the module is compiled when a change occurs in it, and only inside it. It’s a big gain of time. Editing code in the main file of the Playgrounds does not affect the module. It is why we can keep a really quick feedback.</p>
<hr>
<h1 id="conclusion">Conclusion</h1>
<p>It is easy to write unit tests and to run them in Playgrounds, and we are using tools that we already know. Playgrounds adds a very appreciable real-time execution for doing Test-Driven Development. The responsiveness of the feedback is really great, it’s a big advantage for the red-green-refactor cycle.</p>
<p>This is not perfect for handling multiple files of a big project, or displaying errors, but we have solutions to improve our experience. It’s not a big problem to work, to prototype, to explore.</p>
<p>In future articles, I will tell you about other ways to speed-up Test-Driven Development in Swift. We will see how we can use Swift Package or frameworks to help us. Keep in touch :)</p>
]]></description></item><item><title>FIRST : 5 principes pour guider l’écriture des tests unitaires</title><link>https://jordanchapuy.com/posts/2020/04/first-5-principes-pour-guider-l-ecriture-des-tests-unitaires/</link><pubDate>Mon, 20 Apr 2020 09:00:00 +0200</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2020/04/first-5-principes-pour-guider-l-ecriture-des-tests-unitaires/</guid><description><![CDATA[<p>Écrire du code propre est essentiel, et écrire des tests propres l’est tout autant, si ce n’est plus. Design émergent, aide pour retranscrire le métier, documentation, maintenabilité et évolution du code, les tests jouent de multiples rôles au sein d’un projet. C’est pourquoi il est important d’avoir des tests de qualité.</p>
<p>Dans cet article, je vous propose d’explorer 5 principes qui pourront vous guider et vous challenger pour l’écriture de vos tests unitaires. Ces principes sont connus sous l’acronyme FIRST, signifiant avoir des tests :</p>
<ul>
<li>Fast 🚅</li>
<li>Independent 📦</li>
<li>Repeatable ♻️</li>
<li>Self-validating ✅</li>
<li>Timely ⏱</li>
</ul>
<p>En s’inspirant de ces bonnes pratiques, la qualité de vos tests s’améliorera et la qualité du projet et du code de production suivra. Pour mieux comprendre ces principes, faisons le tour de chacun d’eux en explorant leurs raisons d’être, les possibles problèmes en cause et des pistes de solutions.</p>
<figure>
</figure>

<hr>
<h1 id="f--fast-">F : Fast 🚅</h1>
<p>Exécuter un test doit être rapide, et surtout, lancer l’ensemble des tests doit être rapide. Cela inclut le temps des <em>setup</em> et <em>teardown</em>, et même de la compilation. Un test unitaire rapide mais avec une longue compilation ou un long setup est un test long. <strong>Si vous hésitez pour lancer vos tests après une modification, c’est que vos tests sont probablement trop longs</strong>.</p>
<p>Lorsque les tests sont longs, les workflow de développement et de déploiement sont ralentis. Par ailleurs, un des bénéfices des tests unitaires est d’obtenir un feedback rapide. Pour conserver cet aspect, il faut que les tests soient rapides.</p>
<p>C’est encore plus important lorsque vous utilisez un outil qui exécute automatiquement les tests unitaires impactés par vos modifications. C’est le cas en C# par exemple, avec Visual Studio et le <a href="https://docs.microsoft.com/fr-fr/visualstudio/test/live-unit-testing?view=vs-2019" target="_blank" rel="noopener noreffer">Live Unit Testing</a>.</p>
<p>Mais alors, qu’est-ce qu’un test long ? Prenons 150ms. Ça n’a l’air de rien, mais si chaque test prend 150ms, le cumul peut devenir bien plus long. Sur un projet ayant 2000 tests, et cela peut vite augmenter si l’équipe en ajoute régulièrement, on arrive à un total de 5 minutes ! Cumulé sur une journée, c’est énorme et c’est sans compter le temps de compilation ou de setup.</p>
<p>Un temps aussi grand va créer un point de douleur qui va démotiver le développeur, ce qui aura pour conséquence de diminuer la fréquence à laquelle il lance les tests. Dans le pire des cas, il pourrait même ne plus du tout lancer les tests.</p>
<p>Pour avoir un feedback rapide, il est nécessaire de lancer très souvent les tests pendant que l’on développe. En perdant le feedback rapide, on perd aussi du temps. On obtient bien plus tard l’information que quelque chose a cassé. De nombreuses modifications ont pu être ajoutées et il faut identifier laquelle est responsable de l’erreur.</p>
<h2 id="causes">Causes</h2>
<p>Les dépendances lourdes comme les accès à une base de données, les appels réseaux, ou les lectures de fichiers sont souvent les responsables d’un test long. Ces opérations durent des centaines de millisecondes, voire plusieurs secondes.</p>
<p>Parfois, les traitements asynchrones ralentissent les tests par le traitement lourd qu’ils peuvent faire, et possiblement aussi par la manière dont les tests gèrent l’asynchronisme (le test étant bloqué tant qu’une réponse n’est pas arrivée). Le multithreading peut poser le même problème.</p>
<h2 id="solutions">Solutions</h2>
<p>L’injection de dépendance, ou le principe d’inversion de contrôle, est un moyen efficace de s’abstraire des dépendances. Les implémentations réelles sont remplacées par des simulacres, comme des <a href="https://martinfowler.com/bliki/TestDouble.html" target="_blank" rel="noopener noreffer">Test Double</a>, qui permettent de simuler des comportements.</p>
<p>En créant une classe qui agira à la place d’un service effectuant une requête HTTP, par exemple, on obtient la flexibilité d’avoir la valeur que l’on souhaite immédiatement. Retourner des objets prédéfinis dans une fonction est une instruction instantanée contrairement à un appel réseau.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">TimeoutArticlesProvider</span><span class="p">:</span> <span class="n">ArticlesProvider</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">fetchAllArticles</span><span class="p">(</span><span class="n">completion</span><span class="p">:</span> <span class="p">((</span><span class="n">Result</span><span class="p">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="n">ApiError</span><span class="p">&gt;)</span> <span class="p">-&gt;</span> <span class="nb">Void</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">completion</span><span class="p">(.</span><span class="n">failure</span><span class="p">(.</span><span class="n">timeout</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><hr>
<h1 id="i--independent-">I : Independent 📦</h1>
<p>Un test ne doit pas dépendre d’un autre test. Le résultat d’un test ne doit pas non plus affecter un autre test. Cela peut causer des faux positifs ou cacher un problème. On perdrait du temps à parcourir plusieurs tests pour découvrir l’origine d’une erreur.</p>
<p>On devrait pouvoir lancer les tests dans n’importe quel ordre. De même, on devrait pouvoir lancer n’importe quel sous-ensemble de tests : un seul, une suite de plusieurs tests, ou tous. Si ce n’est pas le cas, c’est une indication que certains tests dépendent les uns des autres.</p>
<p>Tendre vers des tests indépendants permet de focaliser chaque test sur un comportement précis, ce qui donne davantage de sens au mot <em>unitaire</em>. <strong>Un test ne devrait avoir qu’une seule raison d’échouer</strong>. Cela permet d’identifier rapidement la cause d’une erreur, on comprend tout de suite pourquoi le test a échoué. On évite ainsi une longue session de debug.</p>
<p>On veut donc se rendre indépendant d&rsquo;une base de données par exemple, pour éviter que l&rsquo;écriture dans un test A affecte le résultat d&rsquo;un test B. Ce peut être la même chose pour des singletons, des fichiers. Eventuellement, on va vouloir devenir indépendant de choses lourdes comme les appels réseaux, notamment pour respecter les principes <em>Fast</em> et <em>Repeatable</em>.</p>
<p>Attention à ne pas tomber dans l&rsquo;extrême. On ne veut pas que le SUT (System Under Test) soit isolé de tout. Non. On veut seulement rendre le test indépendant. Le SUT peut être une classe comme un ensemble de classes, un module. Tout mocker posera des problèmes et rendra le test fragile.</p>
<h2 id="causes-1">Causes</h2>
<p>Compter sur un enchaînement de plusieurs tests afin d’effectuer des actions prérequises à l’exécution d’un autre test va créer un lien de dépendance. De même que partager un état avec d’autres tests. On peut par exemple retrouver ces états dans des propriétés de la classe de test, dans des singletons, dans des bases de données, dans la lecture et l&rsquo;écriture de fichiers&hellip; Bref, tout ce qui est partagé.</p>
<h2 id="solutions-1">Solutions</h2>
<p>Ici aussi l&rsquo;injection de dépendance aidera à remplacer les dépendances gênantes pour le test. A celà, on peut ajouter le modèle <strong>Arrange-Act-Assert</strong> afin de structurer l’écriture d’un test en trois grandes parties en plus d’apporter de la rigueur et de la cohérence entre les tests.</p>
<ul>
<li><em>Arrange</em> : on prépare toutes les données requises pour le test, ainsi que l’état dans lequel le test doit se trouver. On s’abstrait des autres tests et de l’environnement, ainsi que des dépendances en créant les <a href="https://martinfowler.com/bliki/TestDouble.html" target="_blank" rel="noopener noreffer">Test Double</a> nécessaires.</li>
<li><em>Act</em> : la méthode testée est appelée. Les données requises ont été initialisées dans l’étape précédente, et les dépendances injectées.</li>
<li><em>Assert</em> : on vérifie que le résultat est bien celui qu’on attend grâce aux différentes méthodes <em>Assert</em> du framework de test. Un test doit tendre à n’avoir qu’un seul assert pour n’avoir qu’une seule raison d’échouer. Dans certains cas, on peut avoir plusieurs assert lorsqu’ils se regroupent sous une même logique.</li>
</ul>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">HelloServiceTests</span><span class="p">:</span> <span class="n">XCTestCase</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">testMakeMessage</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Arrange</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">now</span> <span class="p">=</span> <span class="mi">1587301244</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">dateProvider</span> <span class="p">=</span> <span class="n">FakeDateProvider</span><span class="p">(</span><span class="n">now</span><span class="p">:</span> <span class="n">now</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">service</span> <span class="p">=</span> <span class="n">HelloService</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">:</span> <span class="n">dateProvider</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Act</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">message</span> <span class="p">=</span> <span class="n">service</span><span class="p">.</span><span class="n">makeMessage</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1">// Assert</span>
</span></span><span class="line"><span class="cl">        <span class="n">XCTAssertEqual</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="s">&#34;1587301244 - Hello.&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>Un autre moyen de donner de l’indépendance aux tests est d’utiliser les méthodes de <em>setup</em> et de <em>teardown</em>. Ces méthodes sont respectivement appelées avant et après l’exécution de chaque test. Le teardown est très utile pour effectuer un nettoyage après chaque test, par exemple.</p>
<p>Le nommage des tests a son importance et peut aider à rendre des tests indépendants. Chercher à mettre en valeur l’intention du test à travers son nom force à tester un comportement plus précis. Et par la même occasion, cela facilite la compréhension pour déterminer pourquoi le test a échoué.</p>
<p>Certains frameworks ou IDEs proposent d’exécuter les tests dans un ordre aléatoire. Activez cette option. Vous aurez rapidement une idée quels tests ont un problème, et cela vous empêchera peut-être d&rsquo;ajouter un nouveau test dépendant.</p>
<hr>
<h1 id="r--repeatable-">R : Repeatable ♻️</h1>
<p>Un test doit toujours produire le même résultat. Toujours. Peu importe le nombre de fois où il est exécuté, la date ou le lieu. Si un test ne réagit parfois pas de la même manière, on ne peut pas lui faire confiance.</p>
<p>Comment savoir si la raison d’un échec est “normale” ou réellement problématique ? À quel point les erreurs sont bien détectées ? <strong>En se posant sans cesse des questions sur les tests, on perd en sérénité</strong>, rendant alors les changements dans le code plus difficiles et plus hésitants.</p>
<p>Pour un état de départ donné et une action exécutée, on doit pouvoir prédire la réponse. Sans résultat déterministe, les sessions de debug seront plus compliquées lorsque des erreurs surviendront (et idéalement, on n&rsquo;a pas besoin de debugguer). Certains problèmes pourraient être difficiles, voire impossibles à reproduire à l’identique.</p>
<p>Un test doit éviter de dépendre de sources de données non-prévisibles. Des sources changeantes, pouvant être indisponibles, des états extérieurs ou des environnements sont des dépendances empêchant d’obtenir continuellement le même résultat.</p>
<h2 id="causes-2">Causes</h2>
<p>Les bases de données sont des sources de données changeantes. Elles pourraient être modifiées par d’autres tests ou d’autres lancements. Les APIs web peuvent également exposer des données différentes à chaque appel, en plus d’être potentiellement indisponible (serveur en maintenance) ou inaccessible (panne de réseau).</p>
<p>Tester du code utilisant ces types de dépendances donnera un résultat incertain. Les singletons, les configurations et les environnements peuvent aussi être responsables d’un test ayant une sortie non garantie. Plus souvent oubliés : l’utilisation des dates et des fonctions aléatoires.</p>
<h2 id="solutions-2">Solutions</h2>
<p>On veut toujours avoir le même résultat, donc on veut contrôler entièrement le test, donc on doit rendre contrôlable certaines dépendances. L’injection de dépendance permettra de s’abstraire des sources de données non-prévisibles en ayant le contrôle sur les réponses générées. Par exemple, on peut simuler une requête échouant suite à un timeout pour les besoins d’un test, et par ailleurs simuler un succès pour un autre test.</p>
<p>Cette même solution peut être utilisée pour gérer les dates et les fonctions aléatoires. Pour cela, on transforme l’accès à la date en le rendant indirect, via une interface, afin d’ajouter une abstraction qui permettra de remplacer la valeur réelle par un Test Double dans les tests.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-swift" data-lang="swift"><span class="line"><span class="cl"><span class="kd">protocol</span> <span class="nc">DateProvider</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nv">now</span><span class="p">:</span> <span class="n">Date</span> <span class="p">{</span> <span class="kr">get</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">DeviceDateProvider</span><span class="p">:</span> <span class="n">DateProvider</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">var</span> <span class="nv">now</span><span class="p">:</span> <span class="n">Date</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Date</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">HelloService</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">private</span> <span class="kd">let</span> <span class="nv">dateProvider</span><span class="p">:</span> <span class="n">DateProvider</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">init</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">:</span> <span class="n">DateProvider</span> <span class="p">=</span> <span class="n">DeviceDateProvider</span><span class="p">())</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kc">self</span><span class="p">.</span><span class="n">dateProvider</span> <span class="p">=</span> <span class="n">dateProvider</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="kd">func</span> <span class="nf">makeMessage</span><span class="p">()</span> <span class="p">-&gt;</span> <span class="nb">String</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kd">let</span> <span class="nv">now</span> <span class="p">=</span> <span class="nb">Int</span><span class="p">(</span><span class="n">dateProvider</span><span class="p">.</span><span class="n">now</span><span class="p">.</span><span class="n">timeIntervalSince1970</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s">&#34;</span><span class="si">\(</span><span class="n">now</span><span class="si">)</span><span class="s"> - Hello.&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>En complément, le modèle <em>Arrange-Act-Assert</em> apporte la structure pour définir la valeur des Test Double et l’état initial. On peut aussi s’appuyer sur les méthodes de <em>teardown</em> pour faire un nettoyage après chaque test.</p>
<hr>
<h1 id="s--self-validating-">S : Self-validating ✅</h1>
<p>Chaque test doit être autonome pour déterminer si le résultat correspond aux attentes. <strong>Personne ne devrait intervenir.</strong> Sa sortie est simple : un test a réussi ou a échoué.</p>
<p>Il ne devrait pas y avoir besoin d’interprétation manuelle. Si on est amené à lire un fichier, à comparer des résultats, à chercher des informations, il y a un risque de faire une erreur humaine. C’est aussi plus long et rébarbatif, ce qui pourrait décourager les développeurs de lancer les tests.</p>
<p>Un test ne devrait pas non plus nécessiter d’action manuelle, ni avant le lancement, ni après. Il ne faut pas avoir à intervenir pour préparer un environnement ou nettoyer des artefacts, par exemple. Si un tel besoin est présent, il faut l’automatiser ou l’intégrer dans le test.</p>
<h2 id="solutions-3">Solutions</h2>
<p>Avec les outils actuels, les tests respectent globalement déjà ce principe. Il suffit d&rsquo;ajouter une assertion dans un test pour qu&rsquo;il puisse valider lui-même le résultat ; le framework et l&rsquo;outillage s&rsquo;occupe du reste. L’assertion la plus basique est une déclaration indiquant que quelque chose doit être vrai.</p>
<p>Les frameworks de tests proposent en général plusieurs méthodes d’assertion : <em>assert true</em>, <em>assert not null</em>, <em>assert equal</em>, <em>assert throw exception</em>, etc. Au moins l’une de ces instructions doit être présente dans un test.</p>
<p>L’interprétation du résultat des tests peut s’améliorer avec des solutions plus visuelles. Certains frameworks et IDE proposent des interfaces graphiques listant les tests et mettant en valeur les succès et les échecs.</p>
<p>En ce qui concerne l’automatisation pour éviter une intervention manuelle, là encore l’injection de dépendance et la structure <em>Arrange-Act-Assert</em> sont utiles. En préparant et simulant un environnement spécifique pour un test, par exemple.</p>
<hr>
<h1 id="t--timely-">T : Timely ⏱</h1>
<p>Un test doit être écrit au bon moment. Idéalement, <strong>le test est écrit juste avant le code de production qui fera réussir le test</strong>. Ce mode opératoire apporte de réels bénéfices et fait la différence. De cette manière, on avance par plus petits bouts et on se concentre sur l’essentiel. Les tests, déjà écrits, nous aident et nous guident. On voit émerger le design du code.</p>
<p>À l’opposé, écrire les tests après le code de production comporte des risques. L’ajout de tests a posteriori est plus long et plus difficile. Cela nécessite un travail supplémentaire : il faut souvent adapter le code de production qui n’est pas testable. Ce travail est parfois conséquent et coûteux. Plus on éloigne l’écriture des tests, plus ce risque sera grand.</p>
<p>Outre la difficulté, la motivation peut baisser lorsqu’il s’agit d’écrire des tests lorsque l’on a terminé. Un sentiment de culpabilité peut également naître en pensant au temps supplémentaire à passer pour ajouter des tests et adapter le code de production alors que tout est déjà prêt.</p>
<h2 id="solutions-4">Solutions</h2>
<p>Commencer par écrire un test fait partie de l&rsquo;approche Test-Driven Development (TDD). Le développement est guidé par les tests. On est guidé pour implémenter le comportement par petites étapes. Suivre cette pratique, c’est suivre un cycle précis : <em>RED, GREEN, REFACTOR</em>.</p>
<p>Pour faire simple, on écrit d’abord un test qui échoue ou ne compile pas : c’est <em>rouge</em>. On cherche ensuite à passer au <em>vert</em> en écrivant le minimum de code de production, en allant au plus simple. Puis on <em>refactorise</em>, on améliore le code de production et le code des tests. La boucle est bouclée, alors on recommence. On itère jusqu’à ce qu’on ait répondu au besoin et qu’on soit satisfait du code.</p>
]]></description></item></channel></rss>