22 points par GN⁺ 2024-09-04 | 5 commentaires | Partager sur WhatsApp
  • Lorsqu’on maintient une base de code inconnue, on passe beaucoup de temps à rechercher des chaînes de caractères
  • Même dans un projet écrit seul, il faut rechercher beaucoup d’éléments, comme les noms de fonctions, les messages d’erreur ou les noms de classes
  • Si la recherche fonctionne mal, on risque de ne pas trouver les références dans la base de code et de considérer à tort qu’elles sont inutiles
  • À partir de ce constat, l’auteur a dégagé quelques règles pour préserver la greppabilité d’une base de code

Ne pas fragmenter les identifiants

  • Fragmenter les identifiants ou les construire dynamiquement est une mauvaise idée
  • Supposons qu’il existe deux tables de base de données nommées shipping_addresses et billing_addresses ; construire dynamiquement le nom de table selon le type de commande peut sembler séduisant
const getTableName = (addressType: 'shipping' | 'billing') => {  
    return `${addressType}_addresses`  
}  
  • Cela peut sembler DRY, mais c’est mauvais pour la maintenance. Quelqu’un qui cherche le nom de table shipping_addresses dans la base de code peut passer à côté de cet endroit
  • Il vaut mieux coder les identifiants en dur
  • Code remanié pour améliorer la recherche :
const getTableName = (addressType: 'shipping' | 'billing') => {  
    if (addressType === 'shipping') {  
        return 'shipping_addresses'  
    }  
    if (addressType === 'billing') {  
        return 'billing_addresses'  
    }  
    throw new TypeError('addressType must be billing or shipping')  
}  
  • Le même principe s’applique aux noms de colonnes, aux champs d’objet et aux noms de méthodes/fonctions (en JavaScript, il est facile de construire dynamiquement des noms de méthodes)

Utiliser les mêmes noms sur toute la pile

  • Ne renommez pas les champs aux frontières de l’application simplement pour suivre une convention de nommage
  • Exemple typique : récupérer des identifiants en snake_case de style PostgreSQL dans JavaScript puis les convertir en camelCase est une mauvaise idée
  • Cela rend la recherche plus difficile. Pour tout retrouver, il faut chercher deux chaînes au lieu d’une
const getAddress = async (id: string) => {  
    const address = await getAddressById(id)  
    return {  
        streetName: address.street_name,  
        zipCode: address.zip_code,  
    }  
}  
  • Il vaut mieux retourner directement l’objet
const getAddress = async (id: string) => {  
    return await getAddressById(id)  
}  

Le plat vaut mieux que l’imbriqué

  • En s’inspirant du Zen of Python, pour gérer les espaces de noms, il est le plus souvent préférable d’aplatir les structures de dossiers/objets plutôt que de les imbriquer
  • S’il existe deux options pour configurer des fichiers de traduction :
{  
    "auth": {  
        "login": {  
            "title": "Login",  
            "emailLabel": "Email",  
            "passwordLabel": "Password",  
        },  
        "register": {  
            "title": "Register",  
            "emailLabel": "Email",  
            "passwordLabel": "Password",  
        }  
    }  
}  
{  
    "auth.login.title": "Login",  
    "auth.login.emailLabel": "Email",   
    "auth.login.passwordLabel": "Password",  
    "auth.register.title": "Login",  
    "auth.register.emailLabel": "Email",  
    "auth.register.passwordLabel": "Password",  
}  
  • Il vaut mieux choisir la seconde option. Les clés sont faciles à retrouver et peuvent être référencées comme t('auth.login.title')
  • Si l’on considère la structure de composants React :
./components/AttributeFilterCombobox.tsx  
./components/AttributeFilterDialog.tsx  
./components/AttributeFilterRating.tsx  
./components/AttributeFilterSelect.tsx  
  • Cette structure est préférable à la suivante
./components/attribute/filter/Combobox.tsx  
./components/attribute/filter/Dialog.tsx  
./components/attribute/filter/Rating.tsx  
./components/attribute/filter/Select.tsx  
  • Du point de vue de la recherche, on peut retrouver le nom complet du composant avec son espace de noms, comme AttributeFilterCombobox, au lieu d’un nom générique comme Dialog

L’avis de GN⁺

  • Ce billet de blog explique bien l’importance de la recherche d’identifiants lorsqu’on maintient une base de code
  • Construire dynamiquement des identifiants ou renommer des champs aux frontières de l’application complique la maintenance du code. Les identifiants doivent rester cohérents et clairs
  • À l’inverse, coder les identifiants en dur et garder des espaces de noms plats est préférable du point de vue de la recherche
  • Il serait utile d’appliquer ces principes dans les projets afin d’améliorer la lisibilité et la maintenabilité du code
  • Au-delà des règles proposées par l’auteur, il existe aussi d’autres moyens d’améliorer la qualité du code, comme écrire du self-documenting code ou utiliser des commentaires pertinents

5 commentaires

 
nowpark 2024-09-06

Je laisse aussi un outil qui convertit en chemin complet de json pour le rendre greppable !

https://fr.news.hada.io/topic?id=3159

 
botplaysdice 2024-09-05

C’est bien... la greppability...

 
ahwjdekf 2024-09-04

Il semble aussi utile d’écrire autant que possible les informations utiles sur une seule ligne.

 
roxie 2024-09-09

C’est bien.

 
GN⁺ 2024-09-04
Avis Hacker News
  • Rechercher des symboles comme les noms de fonctions et de classes est moins puissant que d'utiliser des outils qui comprennent la syntaxe du code

    • Les fonctions « aller à la définition » et « trouver les usages » suffisent à elles seules à réduire fortement le besoin de recherche textuelle
    • Depuis dix ans, je recherche surtout des chaînes visibles par l'utilisateur
    • Ce genre de billet signifie que son auteur devrait investir du temps pour apprendre de meilleurs outils adaptés à son langage
    • Un bon IDE peut à lui seul faire gagner beaucoup de temps
  • Ce serait utile si l'outil grep avait un mode de « super insensibilité à la casse »

    • Par exemple, étendre une recherche comme FooBar|first_name pour qu'elle puisse correspondre à toutes les variantes de casse
    • Il est difficile d'imaginer une situation où cette fonctionnalité ne devrait pas être activée par défaut
  • Je soutiens l'idée de la greppabilité

    • En suédois, des mots comme « grep-bar » ou « grep-barhet » existent réellement
    • « greppbar » signifie « compréhensible », et « greppbarhet » signifie « possibilité d'être compréhensible »
  • Lors de la conception de Hamilton, l'objectif était de rendre les définitions de fonctions et leurs usages en aval faciles à retrouver avec grep

    • Dans l'univers des transformations de données en Python, il est facile de créer des bases de code où grep n'est d'aucune aide
  • « greppable » n'est pas un mot / concept utilisé en soi

    • Je l'utilise depuis longtemps comme principe d'organisation
    • C'est l'une des meilleures façons de structurer le code
  • J'ai déjà vu des exemples complexes utilisant l'interpolation conditionnelle de chaînes

    • Quand j'ai rejoint le projet, il m'a fallu bien trop longtemps pour retrouver dans le code trois mots vus dans l'interface
    • Plus tard, j'ai tout remplacé par des chaînes faciles à retrouver avec grep
  • De nombreux styles de code et outils gardent les constantes de chaîne sur une seule ligne, quelle que soit leur longueur

    • C'est pour qu'on puisse voir une chaîne dans la sortie du programme puis rechercher exactement la même chaîne dans le code
  • Rust, Javascript et Lisp placent un mot-clé avant les définitions de fonctions, ce qui facilite la recherche

    • Le C n'a pas ce type de mot-clé, donc on ne peut rechercher que le nom de la fonction
    • Certaines règles de codage en C divisent la définition sur deux lignes pour faciliter la recherche
  • Je suis d'accord avec la greppabilité, mais opposé au fait de garder le même nom au-delà des frontières

    • Le fait qu'un symbole n'existe que dans un seul domaine réduit la charge cognitive
  • La possibilité de rechercher le code est une bonne chose, mais l'exemple augmente délibérément le risque d'erreur

    • Ajouter des conditions sur les chaînes crée un risque d'incohérence entre l'entrée et la sortie
    • Aplatir un dictionnaire augmente le risque de fautes de frappe
    • Les fautes de frappe sont courantes et, lorsqu'elles sont copiées dans plusieurs bases de code, elles sont difficiles à corriger