🍪💂🏻♂️ Évite une erreur courante grâce aux guard clauses
La semaine dernière je me suis rendue compte d’une erreur dans mon code. Cette erreur peu paraître petite au premier abord, pourtant elle est assez fréquente et peut avoir de lourdes conséquences sur votre plateforme. Je vais vous la présenter et vous montrer comment l'éviter.
Au programme :
Détecter l’erreur
Les guard clauses
Bonjour et bienvenue sur la 6ème édition de Ruby Biscuit.
Vous êtes maintenant 80 abonnés 🥳 Si vous n’êtes pas déjà inscrit :
Détecter l’erreur
Récemment j’ai implémenté une fonctionnalité qui consistait à renseigner un code de parrainage valide afin de pouvoir accéder à la page d’inscription.
La logique de ce parcours utilisateur est la suivante :
Un nouvel utilisateur doit renseigner le code parrain d’un utilisateur validé sur la plateforme pour pouvoir accéder au site.
Voici mon implémentation initiale de cette spécification :
J’ai créé mon controller Users::CooptationCodesController
et dans la méthode #create
, je récupère le code parrain fourni par l'utilisateur.
S’il existe je redirige l’utilisateur à l’étape suivante, celle de l’inscription, sinon je lui affiche un message d’erreur et je le laisse sur le formulaire du code parrain.
Voici les tests qui accompagnaient ma nouvelle fonctionnalité :
Tout semblait fonctionner à merveille jusqu’à ce qu’un de mes collègues me dise “Il se passe quoi si le paramètre “code” est vide ? Tu devrais utiliser une guard clause pour éviter ce genre de problème.”
1ère réaction : “Non t'inquiète, ce cas est déjà testé !”
2ème réaction : … Je vais peut être aller re-vérifier quand même.
3ème réaction : MAIS POURQUOI MES TESTS FONCTIONNENT ALORS QUE MON CODE N’EST PAS BON ?
Ok je vous explique la situation :
Un utilisateur arrive sur la page du code de parrainage et soumet le formulaire sans avoir rempli le champ.
Que se passe t-il exactement ?
Mon params n’est pas nil
, c’est une string vide.
Voici ce qu’il se passe dans ma condition
C’est un cas qui peut arriver si je modifie un utilisateur via un formulaire de mon site, en back-office par exemple, que je ne remplis pas son code utilisateur et que j’enregistre tous les paramètres comme attributs.
Exemple de params :
Nous avons donc deux soucis :
mon code est mauvais
mes tests sont biaisés
Je commence par changer nil
par une string vide dans le contexte “given no params”
de mes tests pour tester la bonne donnée dans le cas d’un champ vide. J’ajoute un utilisateur avec une string vide pour le code de parrainage pour être sûre d’en avoir un dans ma base de données de tests.
Je lance mes tests. Spoiler, je m’attends à ce que mes tests passent au rouge, que je sois redirigé vers ma page d’inscription et que je n’ai plus un statut HTTP 200 mais une 302 pour une redirection.
Maintenant mes tests m’assurent que mon utilisateur ne passera pas à l’étape d’inscription temps qu’il n’aura pas renseigné de code. Il ne nous reste plus qu’a faire passer nos tests au vert.
Pour cela, je vais ajouter une guard clause dans ma méthode de controller.
Les guard clauses
Une guard clause est un retour prématuré (ou early return) placé en haut de votre méthode, qui empêche votre code d’être exécuté si ce n'est pas nécessaire, en fonction de conditions que vous spécifiez. La plupart du temps ces conditions servent à vérifier le type de donnée reçu dans la méthode.
Je vous conseille cet article très clair et concis pour plus de détails : https://anthonygharvey.com/guard-clauses-vs-nested-conditionals
Cette étape assurera que mon code ne s’exécute pas temps que le paramètre code est nil
ou ““
.
Je relance mes tests
Tout est bon !
Les guard clauses vous permettront de refactoriser votre code en évitant des conditions à rallonge mais aussi de réduire sa complexité en offrant une meilleure lisibilité de ce que vos méthodes sont censées faire et recevoir.
Vous pouvez en ajouter plusieurs à la suite si besoin et adapter les erreurs retournées.
Pour découvrir des nouveaux tips Ruby on Rails tous les mercredis à 16h, ne cherche plus, tu es au bon endroit !
Rendez-vous la semaine prochaine 😉
Mélanie