Les pratiques tech qui peuvent aider votre équipe

Nul besoin d’avoir un passé de développeur, ou de savoir coder. Mon intention ici est de faire découvrir des pratiques tech reconnues dans l’industrie. C’est un sujet que je souhaite rendre accessible à tous, que l’on soit tech ou non, pour améliorer le quotidien des équipes, devenir meilleur dans la technique et dans le business.

J’ai été invité par Fleur Saillofest à speaker dans le meetup Beyond Scrum Mastering. Très rapidement, une trame intéressante a émergé lors de nos échanges : celle de reconnaître des problèmes au sein de l’équipe et y associer certaines pratiques tech qui pourraient aider.

Observer ce qu’il se passe dans l’équipe, entendre les râlements, les plaintes, noter les douleurs, c’est à la portée de tout le monde. J’ai pris un fil rouge avec des problèmes qu’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’existant, etc.

Est-ce que ce sont les seules possibilités ? Non. Mon but n’est pas d’être exhaustif ni sur les problèmes ni sur les solutions et les pratiques. Mais plutôt d’entrevoir des possibilités, de donner des billes pour ensuite aller creuser plus en profondeur avec l’équipe. Je dépose quelques brides de réflexion dans cet article qui m’ont permis de créer mon talk (slides ici).

Collaborer sur le besoin

  • Les refinements sont chiants.
  • 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.
  • Le PO change d’avis, on fait ce qu’il y a écrit dans la story mais il dit que ce n’était pas ça qu’il voulait.

Les premiers problèmes peuvent arriver très tôt, dès l’expression du besoin, avant même d’être purement dans la tech, dans le code. On peut noter qu’il semble y avoir de l’incompréhension, qu’il y a probablement des choses implicites, des modèles mentaux différents. Que tous les membres de l’équipe ne sont pas vraiment impliqués.

Example Mapping

Une piste d’amélioration serait de faire collaborer toute l’équipe, ensemble, sur la rédaction du besoin. Je pense naturellement à l’Example Mapping. C’est un atelier qui réunit l’ensemble de l’équipe (PO, QA, Dev front/back). Le PO vient avec ses règles métiers et toute l’équipe œuvrera à créer des exemples précis pour chaque règle.

Tout le monde est impliqué, participe, et s’approprie le besoin. Les règles sont éclaircies, les exemples sont concrets et parlent à tous. L’implicite est rendu explicite, on sort ce qu’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.

Ce n’est plus à la seule charge du PO d’é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’intelligence collective en amont pour co-créer quelque chose de meilleur.

Collaborer sur le code / Git

  • J’entends parler de branches, merge, commit, conflits, … Je suis perdu.
  • C’est quoi ce git machin chose ?

Je dédierais un article pour vulgariser l’utilisation de git qu’en ont les développeurs. Je me limiterais à quelques lignes ici pour comprendre l’origine de certains problèmes. Git est un outil pour gérer les versions du code source.

Un développeur va créer un commit avec des changements ; c’est une copie à un instant T du code. Il va travailler sur une branche ; c’est un espace indépendant, avec ses propres copies.

Au bout d’un moment, lorsqu’il aura terminé, il va vouloir merge ; il veut réunir son travail réalisé sur sa branche (dans son espace indépendant) vers la branche principale (l’espace commun). Pour cela, il va ouvrir une Pull/Merge Request et demander à quelqu’un de faire de la revue de code ; une personne va relire toutes les modifications, pour approuver ou faire des retours.

Au moment de réunir, il peut y avoir des conflits ; dans son espace, il a modifié des zones qui ont aussi été modifiées sur l’espace commun. Il faudra résoudre ces problèmes afin de pouvoir rassembler les travaux. Qu’est-ce qu’on garde ? Qu’est-ce qui n’a plus de sens ? Qu’est-ce qu’il faut adapter ?

Plus longtemps on travaille sur une branche (dans son coin) et plus on attend pour réunir avec la branche principale (avec les autres), plus on augmente les problèmes. Par exemple, la quantité de changements et le temps qui s’allonge augmentent le risque de conflits et demandent une plus longue revue de code.

Collaborer sur le code / Revue de code

  • J’en ai marre de devoir refaire plusieurs fois mon code après des aller-retours sur la code review.
  • Les développeurs se plaignent que les revues de codes sont longues à faire et pas intéressantes.
  • On attends longtemps avant qu’un autre développeur fasse la revue de code.

Ahhh, la revue de code, serait-ce le mal du siècle des développeurs après le mal de dos ? J’exagère un peu - j’avais envie d’écrire cette tournure humoristique - mais j’ai tout de même souvent observé des symptômes autour de la revue de code. Il faut dire aussi que c’est une pratique qui s’est très largement répandue dans les équipes. Pour autant, elle n’est pas toujours bien appliquée et elle vient avec son lot de contraintes.

Par nature, la revue de code via une Pull/Merge Request est asynchrone - 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’auteur. Et on sait que les changements de contexte nuisent à la productivité. On est interrompu, on sort constamment du flow (qui est long à trouver).

Le feedback est tardif. 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’ils n’ont pas le temps ou que ça ne les intéressent pas. D’autres vont pinailler, mais seulement sur des points insignifiants.

Ce peut être un goulot d’étranglement qui allonge la durée nécessaire pour livrer une fonctionnalité. C’est marquant lorsqu’il y a beaucoup de développeurs ou lorsque la responsabilité de la revue n’est donnée qu’à une poignée de personnes (par exemple, seul le lead/référent/manager).

Bien sûr, ce n’est pas tout noir. La revue de code peut être bien faite et a pour sa défense deux principaux bénéfices : c’est une occasion de donner du feedback pour améliorer le code et réduire les bugs, et c’est une façon de partager de la connaissance en lisant le code d’un autre.

Ok, on parle de feedback et d’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’open-source où les personnes ne se connaissent pas, ne travaillent pas ensemble, où il faut contrôler.

Pair Programming

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’améliorer en continu. Il y a une réflexion commune, deux cerveaux qui vont se challenger.

Ici, le feedback est immédiat. Je propose au plus tôt une autre approche de conception à mon pair. Je découvre une fonction plus performante au moment où j’écris ma ligne de code grâce au conseil de mon pair. On repère ce bug pendant qu’on développe la fonctionnalité ensemble. Maintenant tout de suite, pas après 5 jours de travail.

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’aura co-créée, je le comprendrais, mon pair n’est plus le seul de l’équipe à pouvoir y travailler. C’est très efficace pour onboarder un nouvel arrivant aussi.

C’est en ça que la pair programming est puissant et ne divise pas l’efficacité par deux, il faut voir au-delà de “deux ressources qui travaillent sur un seul problème”.

Mob Programming

Le Mob Programming se trouve un cran après le Pair Programming : c’est tout un groupe qui va collaborer, en même temps, sur un seul et même problème, avec un seul ordinateur. L’intelligence collective va mener à une meilleure compréhension du problème et à une meilleure conception de la solution. Encore une fois, ce n’est pas simplement grouper un tas de personnes pour qu’elles regardent un seul développeur tout faire.

Le problème et les solutions sont discutés et challengés. Le groupe entier s’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’est tout un groupe qui apprendra, en pratiquant, cette nouvelle technique ou cette fonctionnalité.

Note : on parle d’avoir un seul ordinateur, un seul clavier en pair et mob programming. C’est parfaitement compatible à distance avec des solutions de partage d’écran, de contrôle du clavier, de code collaboratif.

Collaborer sur le code / Conflits

  • Le dev est terminé localement mais ça met beaucoup de temps à être livré car on a plein de conflits.
  • La fonctionnalité marche sur ma branche mais maintenant que c’est mergé c’est cassé.

Intégration Continue

Parfois, quand on parle d’Intégration Continue, on entends Jenkins, gitlab-ci, pipelines, machine de builds, etc. Ce n’est pas ça, l’Intégration Continue. Tout ça, ce sont des outils. C’est du comment.

L’Intégration Continue, c’est d’abord un principe, une attitude. C’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’attendre de tout finir et de rassembler après 8 jours de travail intense.

Qu’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’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.

Pair/Mob Programming

On l’a vu précédemment, le Pair et le Mob Programming permettent une réelle collaboration de plusieurs personnes. La communication est meilleure, puisqu’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.

Écrire le code

  • 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.
  • 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é ?

Tests Unitaires

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’un scénario fonctionnel. C’est quelque chose qui vérifie que du code se comporte comme prévu, automatiquement, sans intervention humaine. C’est un programme qui lance un autre programme pour vérifier ce qu’il se passe dans différentes conditions.

On parle de comportement, de scénario fonctionnel : quand on écrit un test unitaire, on veut s’assurer de bien retranscrire le métier. C’est en ça qu’il est très important et utile pour le business, et que ce n’est pas seulement un élément technique.

Progressivement, on créé un filet de sécurité pour éviter certaines régressions. On diminue le risque d’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.

C’est au moment où l’on change le code que l’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 Refactoring, pour améliorer le code sereinement.

Test-Driven Development

Quand on écrit un test, une bonne pratique est de le faire au plus près du moment où l’on a écrit le code, et non pas bien après une fois que tout est terminé. Pourquoi ? Parce que c’est plus coûteux et difficile de le faire après ; le code n’ayant pas forcément été conçu pour être testable. Et parce qu’on passe à côté d’un bénéfice important : se faire guider par le test.

Et c’est la philosophie du Test-Driven Development. Ce n’est pas “écrire le test en premier” (c’est du comment). C’est se faire guider par les tests et par le métier. On définit le comportement que l’on veut obtenir (le test) puis on fait émerger la solution et on l’améliore.

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.

À noter que l’écriture des tests unitaires et la pratique du TDD font partie intégrante du job de développeur et que ce n’est pas forcément plus long de tester. Au contraire, ça nous aide. C’est à faire dès qu’il y en a le besoin, en continu, il n’y a pas de permission à demander, de journées à dédier.

Livrer

  • C’est douloureux de livrer, c’est long, il y a un tas de process et d’actions à faire…
  • 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.
  • 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.

Automatisation

Créer une archive de l’application et l’envoyer sur un serveur, générer le fichier de traduction à partir d’une feuille Excel, remplacer toutes les majuscules d’un fichier brut par des minuscules et le transformer en JSON, … Ce sont des exemples de tâches manuelles qui gagneraient à être automatisées.

La bonne nouvelle ? Un développeur est bien placé pour automatiser, il est capable d’écrire du code pour créer un programme qui va effectuer ces tâches. Une fois créé, il n’y a plus qu’à 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’enlève au passage le risque d’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.

Outre l’efficacité, je trouve que c’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.

Livraison Continue

Le principe est simple, chaque changement sur la branche principale est livré. C’est livré dans un environnement de staging/test/preprod, ou même de production, mais ce n’est pas déployé. Ce n’est pas encore dans les mains des utilisateurs.

Autrement dit, avec la Livraison Continue, il suffit d’un simple bouton pour déployer aux utilisateurs, il n’y a pas besoin d’autres interventions. Tout est déjà prêt, on est capable de déployer sur demande. Plusieurs fois par semaine, jour, heure, etc.

Ç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’est ça que l’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.

Pour livrer en continu, on va mettre en place certains outils, on va automatiser des tâches, et on va s’atteler à toujours avoir un code dans un état déployable.

Déploiement Continu

Ici, on va un cran plus loin : tout est automatisé, il n’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.

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’activation à distance de fonctionnalités, … 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.

Améliorer un existant

  • *On a des problèmes de qualité dont on n’a jamais le temps de s’occuper. *
  • Mon équipe veut négocier un sprint ou deux de refactoring mais je ne sais pas quelle valeur ça va apporter.
  • J’ai un développeur qui fait du refactoring depuis 3 mois, c’est pas encore fini mais il avance.

Refactoring

Faire du Refactoring, c’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.

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’arrêter à tout moment.

C’est différent de “tout refaire”, à ne pas confondre avec la réécriture. Ce n’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.

Refactoring opportuniste

On fait du refactoring quotidiennement, toutes les occasions sont bonnes. J’ouvre un fichier où je vais devoir travailler, mais le changement est difficile ? Le code est legacy ? J’en profite pour faire un petit refactoring en amont plutôt que d’empirer. On peut évoquer la règle de Boy Scout :

Toujours laisser le code dans un meilleur état que celui dans lequel vous l'avez trouvé.

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 fait partie intégrante du job de développeur. Il est important de faire du refactoring régulièrement et de se former. D’ailleurs, au lieu de bloquer des jours pour faire du refactoring, peut-être le transformer en un temps pour se former et s’améliorer dans les techniques de refactoring ?

Théorie de la vitre brisée

On veut faire du refactoring régulièrement pour améliorer le code continuellement. On veut éviter que la situation ne s’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.

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’abandon. On va alors attirer et cumuler d’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.

Il faut remédier aux problèmes au plus vite, avant qu’ils ne soient trop nombreux. Un quartier où les maisons sont constamment bien entretenues attirera moins les problèmes. C’est la même chose avec le code, on va vouloir rester dans un état d’esprit de qualité.

Méthode Mikado

La méthode mikado est très utile pour faire du refactoring. C’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.

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’il faut effectuer une autre petite étape nécessaire en amont. On dessine d’ailleurs un graphe pour visualiser notre progression et nos pré-requis.

De fait, on est toujours dans un état fonctionnel, on peut s’arrêter à tout moment. On n’aura peut-être pas atteint l’objectif, mais ce sera mieux, on sera plus proche de la fin, on aura réalisé quelques petites étapes, et ça fonctionnera toujours.

Bref

On a vu un ensemble de pratiques tech reconnues dans l’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.

On a aujourd’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’utilisateur, on a besoin de pouvoir livrer rapidement. Changer facilement le code permet de changer facilement de direction fonctionnelle.