Clean Code : Fonctions (en Javascript)

Mar 26 2023
Êtes-vous fatigué de lutter avec des fonctions complexes et difficiles à comprendre dans votre base de code ? Voulez-vous écrire des fonctions plus maintenables, réutilisables et moins sujettes aux erreurs ? Si tel est le cas, vous devez en savoir plus sur "Clean Code: Functions". En suivant les meilleures pratiques décrites dans le livre "Clean Code" de Robert C.

Êtes-vous fatigué de lutter avec des fonctions complexes et difficiles à comprendre dans votre base de code ? Voulez-vous écrire des fonctions plus maintenables, réutilisables et moins sujettes aux erreurs ? Si tel est le cas, vous devez en savoir plus sur "Clean Code: Functions". En suivant les meilleures pratiques décrites dans le livre "Clean Code" de Robert C. Martin, vous pouvez apprendre à écrire des fonctions plus faciles à lire, à tester et à entretenir. Dans cet article de blog, nous explorerons les concepts clés des fonctions de code propre et vous fournirons des conseils pratiques et des exemples pour vous aider à implémenter ces concepts dans votre propre code. Avec notre aide, vous pouvez faire passer vos compétences en codage au niveau supérieur et écrire des fonctions avec lesquelles il est agréable de travailler. Alors, êtes-vous prêt à en savoir plus sur les fonctions de code propre ? Plongeons-nous !

Table des matières

· Les petites fonctions sont meilleures que les grandes
· Les fonctions doivent faire une chose
· Les fonctions doivent avoir des noms descriptifs
· Les fonctions doivent avoir un nombre limité d'arguments
· Les fonctions ne doivent pas avoir d'effets secondaires
· Les fonctions ne doivent pas s'appuyer sur des variables globales
· Les fonctions ne doivent pas être trop Profondément imbriqué
· Utilisez des exceptions, pas des codes d'erreur
· Conclusion

Les petites fonctions sont meilleures que les grandes

Les petites fonctions sont plus faciles à lire et à comprendre car elles font généralement une chose et ont un objectif clair. Cela facilite également leur test et leur maintenance, car il y a moins de code à réviser ou à modifier. Les grandes fonctions, en revanche, peuvent être plus complexes et plus difficiles à comprendre, ce qui peut entraîner des bogues ou des erreurs.

// Large function
function processOrders(orders) {
  const total = orders.reduce((acc, order) => acc + order.price, 0);
  const orderIds = orders.map(order => order.id);
  const orderCount = orders.length;
  const orderSummary = `You have ${orderCount} orders with IDs ${orderIds.join(', ')} for a total of $${total}.`;
  console.log(orderSummary);
  return orderSummary;
}

// --------------------------------------------------------------

// Refactored into smaller functions
function getTotalPrice(orders) {
  return orders.reduce((acc, order) => acc + order.price, 0);
}
function getOrderIds(orders) {
  return orders.map(order => order.id);
}
function getOrderCount(orders) {
  return orders.length;
}
function generateOrderSummary(orders) {
  const total = getTotalPrice(orders);
  const orderIds = getOrderIds(orders);
  const orderCount = getOrderCount(orders);
  return `You have ${orderCount} orders with IDs ${orderIds.join(', ')} for a total of $${total}.`;
}
function logOrderSummary(orders) {
  const orderSummary = generateOrderSummary(orders);
  console.log(orderSummary);
  return orderSummary;
}

La getTotalPrice()fonction prend un tableau de commandes et renvoie leur prix total en utilisant la reduce()fonction pour résumer le prix de chaque commande. La getOrderIds()fonction prend un tableau de commandes et renvoie un tableau de leurs identifiants en utilisant la map()fonction. La getOrderCount()fonction prend un tableau de commandes et renvoie leur nombre en utilisant la lengthpropriété. Enfin, la generateOrderSummary()fonction prend un tableau de commandes et utilise les trois fonctions plus petites pour générer une chaîne récapitulative. La logOrderSummary()fonction prend un tableau de commandes et enregistre la chaîne récapitulative dans la console.

Les fonctions doivent faire une chose

Chaque fonction doit avoir un objectif clair et distinct. Lorsqu'une fonction fait plusieurs choses, elle peut devenir plus difficile à comprendre, à tester et à maintenir. En décomposant une tâche plus importante en fonctions plus petites, nous pouvons créer un code plus lisible et maintenable.

// Function that performs multiple tasks
function processUserInput(input) {
  const inputLines = input.split('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
  const trimmedLines = inputLines.map(line => line.trim());
  const nonEmptyLines = trimmedLines.filter(line => line !== '');
  const formattedLines = nonEmptyLines.map(line => `> ${line}`);
  return formattedLines.join('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
// --------------------------------------------------------------
// Refactored into smaller functions
function splitInput(input) {
  return input.split('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
function trimLines(lines) {
  return lines.map(line => line.trim());
}
function removeEmptyLines(lines) {
  return lines.filter(line => line !== '');
}
function formatLines(lines) {
  return lines.map(line => `> ${line}`);
}
function joinLines(lines) {
  return lines.join('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
function processUserInput(input) {
  const lines = splitInput(input);
  const trimmedLines = trimLines(lines);
  const nonEmptyLines = removeEmptyLines(trimmedLines);
  const formattedLines = formatLines(nonEmptyLines);
  return joinLines(formattedLines);
}

La splitInput()fonction prend une chaîne et utilise la split()méthode pour la diviser en un tableau de lignes. La trimLines()fonction prend un tableau de lignes et utilise la map()méthode pour supprimer tout espace blanc au début et à la fin de chaque ligne. La removeEmptyLines()fonction prend un tableau de lignes et utilise la filter()méthode pour supprimer toutes les lignes vides. La formatLines()fonction prend un tableau de lignes et utilise la map()méthode pour ajouter un >caractère au début de chaque ligne. La joinLines()fonction prend un tableau de lignes et utilise la join()méthode pour les joindre en une seule chaîne, séparées par des retours à la ligne. Enfin, la processUserInput()fonction utilise les fonctions plus petites pour traiter la chaîne d'entrée.

Les fonctions doivent avoir des noms descriptifs

Les noms de fonction doivent décrire avec précision ce que fait la fonction et doivent être faciles à comprendre sans avoir à lire l'implémentation de la fonction. Un nom de fonction descriptif peut aider à rendre le code plus explicite et à réduire le besoin de commentaires.

// Function with a vague name
function processData(data) {
  // ...
}
// --------------------------------------------------------------
// Refactored with a descriptive name
function processUserData(userData) {
  // ...
}

Les fonctions doivent avoir un nombre limité d'arguments

Les fonctions qui prennent un grand nombre d'arguments peuvent être plus difficiles à utiliser, à comprendre et à tester. Essayez de maintenir le nombre d'arguments en dessous de trois ou quatre, si possible. Une façon de réduire le nombre d'arguments consiste à les transmettre sous la forme d'un objet ou d'une structure de données unique.

// Function with too many arguments
function createPerson(name, age, address, phone, email) {
  // ...
}

// --------------------------------------------------------------
// Refactored to use an object instead
function createPerson(personData) {
  // ...
}
// Now, we can pass an object with properties for name, age, address, phone, and email:

const personData = {
  name: 'John Doe',
  age: 30,
  address: '123 Main St',
  phone: '555-555-1234',
  email: '[email protected]'
};
const person = createPerson(personData);

Les fonctions ne devraient avoir aucun effet secondaire

Un effet secondaire se produit lorsqu'une fonction modifie un état en dehors de sa propre portée. Les effets secondaires peuvent rendre plus difficile le test et le raisonnement sur le comportement de la fonction et peuvent également conduire à un comportement inattendu. Les fonctions ne doivent fonctionner que sur leurs propres paramètres et variables locales et ne doivent modifier aucun état en dehors de leur portée.

// Example with side effects
let arr = [1, 2, 3];
function popLastElement() {
  arr.pop(); // modifies the external state of `arr`
}
popLastElement();
console.log(arr); // Output: [1, 2]

// --------------------------------------------------------------
// Example without side effects
function getLastElement(arr) {
  return arr[arr.length - 1]; // returns a new value without modifying the input
}
let arr = [1, 2, 3];
let lastElement = getLastElement(arr);
console.log(lastElement); // Output: 3

Les fonctions ne doivent pas s'appuyer sur des variables globales

Les variables globales compliquent la compréhension et le test des fonctions et peuvent entraîner un comportement inattendu. Les fonctions doivent fonctionner uniquement sur leurs propres paramètres et variables locales et ne doivent pas s'appuyer sur l'état global. Cela facilite également la réutilisation de la fonction dans différents contextes.

// Example relying on global state
let x = 0;
function increment() {
  x++;
}
increment();
console.log(x); // Output: 1

// --------------------------------------------------------------
// Example without relying on global state
function increment(x) {
  return x + 1;
}
let y = 0;
y = increment(y);
console.log(y); // Output: 1

Les fonctions ne doivent pas être trop imbriquées

Les fonctions profondément imbriquées peuvent être plus difficiles à lire et à comprendre, et conduire à des structures de contrôle complexes. Les fonctions doivent être structurées de manière à faciliter la compréhension du flux de contrôle, sans avoir à suivre mentalement plusieurs niveaux de fonctions imbriquées.

// Example with deeply nested functions
function add(a, b) {
  function increment(x) {
    return x + 1;
  }
  let c = increment(a);
  let d = increment(b);
  return c + d;
}
console.log(add(1, 2)); // Output: 5

// --------------------------------------------------------------
// Example with flatter function structure
function increment(x) {
  return x + 1;
}
function add(a, b) {
  let c = increment(a);
  let d = increment(b);
  return c + d;
}
console.log(add(1, 2)); // Output: 5

Utilisez des exceptions, pas des codes d'erreur

Les codes d'erreur peuvent rendre plus difficile le raisonnement sur le code et peuvent conduire à des structures de contrôle complexes. Les exceptions permettent un flux de contrôle plus naturel et une gestion plus facile des erreurs. Les fonctions doivent lever des exceptions pour indiquer des erreurs ou un comportement inattendu, plutôt que de renvoyer des codes d'erreur ou des valeurs.

// Example with error code
function divide(a, b) {
  if (b === 0) {
    return -1; // error code for divide by zero
  }
  return a / b;
}
let result = divide(4, 0);
if (result === -1) {
  console.log("Error: Divide by zero"); // error handling with error code
}

// --------------------------------------------------------------
// Example with exception
function divide(a, b) {
  if (b === 0) {
    throw new Error("Divide by zero"); // throws an exception
  }
  return a / b;
}
try {
  let result = divide(4, 0);
} catch (e) {
  console.log("Error: " + e.message); // error handling with exception
}

Conclusion

En conclusion, il est important de suivre les meilleures pratiques lors de l'écriture de fonctions afin d'améliorer la qualité globale de notre base de code. Ce faisant, nous pouvons nous assurer que nos fonctions sont non seulement lisibles et réutilisables, mais également maintenables à long terme. Cela peut aider à réduire le nombre de bogues et d'erreurs pouvant résulter d'un code mal écrit, ce qui peut économiser du temps et des ressources à long terme.

Il convient de noter qu'un code propre ne consiste pas seulement à écrire du code qui fonctionne ; il s'agit également d'écrire du code qui peut être facilement compris, testé et modifié au fil du temps. Par conséquent, il est recommandé de prendre le temps d'examiner attentivement les meilleures pratiques décrites ci-dessus lors de l'écriture de fonctions, afin d'optimiser la qualité et la maintenabilité de votre code.