Hello ! 👋 J’ai décidé de commencer une série de posts en Français autour de Ruby. Découverte du monde Ruby et conseils pour un code clean. Voici le premier épisode…


Aujourd’hui, on va parler arguments de méthodes et bonnes pratiques.

Pour avoir un code lisible et maintenable, il faut suivre quelques règles concernant l’ordre de ces arguments.

Conseil 1 : Les arguments optionnels

Quand on a une méthode avec plusieurs arguments, dont certains ont une valeur par défaut, pensez à les mettre en fin de chaîne :

Prenez cette définition de méthode

def foo(a, b = "val_b", c)
  # du code...
end

Tout semble correct, mais à l’usage, on se rend compte qu’il est impossible d’appeler cette méthode en spécifiant une valeur pour a et c sans nécessairement spécifier la valeur de b. On se retrouve à écrire

foo("val_a", "val_b", "val_c")

…ce qui est un peu idiot : à quoi bon définir une valeur par défaut à b si on est obligés de la re-spécifier à chaque appel ? ¯\(ツ)

Solution : placer les arguments optionnels fin de chaîne…

def foo(a, c, b = "val_b")
  # du code...
end

Ainsi, on pourra écrire

foo("val_a", "val_c")

sans problème 😎.

Conseil 2 : les keyword arguments (ou “kwargs”)

Le conseil 1 a une limite : quand on a 2 arguments optionnels, et qu’on a besoin de spécifier uniquement le 2e, il faudra alors tout de même spécifier celui qui le précède. Avec 2 arguments optionnels, la douleur est gérable, mais imaginez le bordel quand on passe à 4, 5 ou 6…

Exemple :

def foo(a, b, c = "val_c", d = "val_d", e = "val_e")
  # du code...
end

Si je veux appeler cette méthode en ne changeant que e, je dois quand même re-spécifier c et d :

foo("val_a", "val_b", "val_c", "val_d", "ma_val_e")

Quand on a un grand codebase et qu’on se retrouve avec ce genre d’appels :

foo(user.id, "DONE", true, false, 1, "always", true, post.id)`

On passe son temps à se dire “c’est quoi déjà ce false ? le 1 il fait quoi déjà ? Pourquoi "always" ? …”

Quand on a un problème complexe à régler ou une urgence à cause d’un bug en prod, c’est bon de se retirer de la charge mentale, croyez-moi.

Solution :

À partir du moment où on a deux arguments optionnels ou plus, il est bon de passer à des keyword arguments. Ça a de nombreux intérêts :

  • on s’en tape de l’ordre des arguments
  • on s’en tape des valeurs par défaut

La méthode précédente devient :

def foo(a, b, c: "val_c", d: "val_d", e: "val_e")
  # du code...
end

c, d, e ont des valeurs par défaut, mais si je ne veux modifier que e, je peux désormais faire

foo("val_a", "val_b", e: "ma_val_e")

💡BONUS: les arguments deviennent plus clairs, car ils ont un nom… Pas besoin de vérifier la déclaration de ma méthode pour se souvenir de ce qu’elle représente.

Level ninja master — le conseil du clean coder :

Si votre méthode a plus de 1 argument, passez aux keyword arguments à partir du 2e. Dans tous les cas.

Exemple

def send_message_to(recipient, confirm: true, bcc: "[email protected]", cc: "[email protected]")
  # ruby code
end

Dans cet exemple, le premier argument est clair, grâce au nom de la méthode. J’envoie un message au destinataire. Sans options, cette méthode sera appelée ainsi :

send_message_to("[email protected]")

C’est clair et concis.

Les autres arguments sont des keyword arguments. On en voit immédiatement l’intérêt en comparant un appel sur une version sans keywords :

et avec keywords :

send_message_to("[email protected]", bcc: "[email protected]", confirm: false)

J’insiste au passage sur le nommage de la méthode. Ruby se lit comme de l’anglais. Pensez à écrire du code qui se lit à voix haute.

Si vous prenez ces bonnes habitudes, votre futur vous vous remerciera quand il faudra relire le code pour le déboguer ou le modifier pour ajouter un argument supplémentaire à cette méthode.