Codice pulito: funzioni (in Javascript)
Sei stanco di lottare con funzioni complesse e difficili da capire nella tua base di codice? Vuoi scrivere funzioni più gestibili, riutilizzabili e meno soggette a errori? In tal caso, è necessario conoscere "Codice pulito: funzioni". Seguendo le migliori pratiche delineate nel libro "Clean Code" di Robert C. Martin, puoi imparare a scrivere funzioni più facili da leggere, testare e mantenere. In questo post del blog, esploreremo i concetti chiave delle funzioni di codice pulito e ti forniremo suggerimenti ed esempi pratici per aiutarti a implementare questi concetti nel tuo codice. Con il nostro aiuto, puoi portare le tue capacità di programmazione a un livello superiore e scrivere funzioni con cui è un piacere lavorare. Quindi, sei pronto per conoscere le funzioni di codice pulito? Immergiamoci!
Tabella dei contenuti
· Le funzioni piccole sono migliori di quelle grandi
· Le funzioni dovrebbero fare una cosa sola
· Le funzioni dovrebbero avere nomi descrittivi
· Le funzioni dovrebbero avere un numero limitato di argomenti
· Le funzioni non dovrebbero avere effetti collaterali
· Le funzioni non dovrebbero basarsi su variabili globali
· Le funzioni non dovrebbero essere troppo Profondamente annidato
· Usa eccezioni, non codici di errore
· Conclusione
Le piccole funzioni sono migliori di quelle grandi
Le piccole funzioni sono più facili da leggere e comprendere perché di solito fanno una cosa e hanno uno scopo chiaro. Questo li rende anche più facili da testare e mantenere perché c'è meno codice da rivedere o modificare. Le funzioni di grandi dimensioni, invece, possono essere più complesse e difficili da comprendere, il che può portare a bug o errori.
// 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()funzione accetta un array di ordini e ne restituisce il prezzo totale utilizzando la reduce()funzione per sommare il prezzo di ciascun ordine. La getOrderIds()funzione accetta un array di ordini e restituisce un array dei loro ID utilizzando la map()funzione. La getOrderCount()funzione accetta una matrice di ordini e ne restituisce il conteggio utilizzando la lengthproprietà. Infine, la generateOrderSummary()funzione prende un array di ordini e utilizza le tre funzioni più piccole per generare una stringa di riepilogo. La logOrderSummary()funzione accetta un array di ordini e registra la stringa di riepilogo nella console.
Le funzioni dovrebbero fare una cosa
Ogni funzione dovrebbe avere uno scopo chiaro e distinto. Quando una funzione fa più cose, può diventare più difficile da capire, testare e mantenere. Suddividendo un'attività più grande in funzioni più piccole, possiamo creare codice più leggibile e gestibile.
// 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()funzione prende una stringa e utilizza il split()metodo per suddividerla in un array di righe. La trimLines()funzione accetta un array di righe e utilizza il map()metodo per rimuovere eventuali spazi bianchi dall'inizio e dalla fine di ciascuna riga. La removeEmptyLines()funzione accetta un array di righe e utilizza il filter()metodo per rimuovere eventuali righe vuote. La formatLines()funzione accetta un array di righe e utilizza il map()metodo per aggiungere un >carattere all'inizio di ogni riga. La joinLines()funzione prende un array di righe e usa il join()metodo per unirle in una singola stringa, separate da newline. Infine, la processUserInput()funzione utilizza le funzioni più piccole per elaborare la stringa di input.
Le funzioni dovrebbero avere nomi descrittivi
I nomi delle funzioni dovrebbero descrivere accuratamente cosa fa la funzione e dovrebbero essere facili da capire senza dover leggere l'implementazione della funzione. Un nome di funzione descrittivo può aiutare a rendere il codice più autoesplicativo e ridurre la necessità di commenti.
// Function with a vague name
function processData(data) {
// ...
}
// --------------------------------------------------------------
// Refactored with a descriptive name
function processUserData(userData) {
// ...
}
Le funzioni dovrebbero avere un numero limitato di argomenti
Le funzioni che accettano un gran numero di argomenti possono essere più difficili da usare, comprendere e testare. Cerca di mantenere il numero di argomenti al di sotto di tre o quattro, se possibile. Un modo per ridurre il numero di argomenti è passarli come un singolo oggetto o struttura dati.
// 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);
Le funzioni non dovrebbero avere effetti collaterali
Un effetto collaterale si verifica quando una funzione modifica qualsiasi stato al di fuori del proprio ambito. Gli effetti collaterali possono rendere più difficile testare e ragionare sul comportamento della funzione e possono anche portare a comportamenti imprevisti. Le funzioni dovrebbero operare solo sui propri parametri e variabili locali e non dovrebbero modificare alcuno stato al di fuori del loro ambito.
// 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
Le funzioni non dovrebbero basarsi su variabili globali
Le variabili globali rendono più difficile la comprensione e il test delle funzioni e possono portare a comportamenti imprevisti. Le funzioni dovrebbero operare solo sui propri parametri e variabili locali e non dovrebbero fare affidamento sullo stato globale. Questo rende anche più facile riutilizzare la funzione in diversi contesti.
// 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
Le funzioni non dovrebbero essere nidificate troppo profondamente
Le funzioni annidate in profondità possono essere più difficili da leggere e comprendere, oltre a portare a strutture di controllo complesse. Le funzioni dovrebbero essere strutturate in modo da facilitare la comprensione del flusso di controllo, senza dover tenere mentalmente traccia di più livelli di funzioni nidificate.
// 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
Usa eccezioni, non codici di errore
I codici di errore possono rendere più difficile ragionare sul codice e possono portare a complesse strutture di controllo. Le eccezioni consentono un flusso di controllo più naturale e una gestione degli errori più semplice. Le funzioni dovrebbero generare eccezioni per indicare errori o comportamenti imprevisti, anziché restituire codici o valori di errore.
// 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
}
Conclusione
In conclusione, è importante seguire le migliori pratiche durante la scrittura di funzioni al fine di migliorare la qualità complessiva della nostra base di codice. In questo modo, possiamo garantire che le nostre funzioni non siano solo leggibili e riutilizzabili, ma anche gestibili a lungo termine. Questo può aiutare a ridurre il numero di bug ed errori che possono derivare da un codice scritto male, il che può far risparmiare tempo e risorse a lungo termine.
Vale la pena notare che il codice pulito non riguarda solo la scrittura di codice che funzioni; si tratta anche di scrivere codice che possa essere facilmente compreso, testato e modificato nel tempo. Pertanto, si consiglia di dedicare del tempo a considerare attentamente le migliori pratiche descritte sopra durante la scrittura di funzioni, al fine di ottimizzare la qualità e la manutenibilità del codice.

![Che cos'è un elenco collegato, comunque? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































