- 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
Je laisse aussi un outil qui convertit en chemin complet de
jsonpour le rendre greppable !https://fr.news.hada.io/topic?id=3159
C’est bien... la greppability...
Il semble aussi utile d’écrire autant que possible les informations utiles sur une seule ligne.
C’est bien.
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
Ce serait utile si l'outil
grepavait un mode de « super insensibilité à la casse »FooBar|first_namepour qu'elle puisse correspondre à toutes les variantes de casseJe soutiens l'idée de la greppabilité
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
« greppable » n'est pas un mot / concept utilisé en soi
J'ai déjà vu des exemples complexes utilisant l'interpolation conditionnelle de chaînes
De nombreux styles de code et outils gardent les constantes de chaîne sur une seule ligne, quelle que soit leur longueur
Rust, Javascript et Lisp placent un mot-clé avant les définitions de fonctions, ce qui facilite la recherche
Je suis d'accord avec la greppabilité, mais opposé au fait de garder le même nom au-delà des frontières
La possibilité de rechercher le code est une bonne chose, mais l'exemple augmente délibérément le risque d'erreur