Le nuove e moderne applicazioni web fanno un grande affidamento su Javascript, in particolar modo le Single-page application (le famose SPA). Anche i framework emergenti come React, Angular and Vuejs sono principalmente costruiti con Javascript.
Scalare tali applicazione è un compito arduo e non privo di insidie.
Con un’impostazione iniziale mediocre, si corre il rischio di perdersi in un mare di confusione. Voglio condividere una serie di consigli che aiuteranno a scrivere un codice pulito, scalabile ed efficiente.
1) Isola il tuo codice
Una delle cose più importanti che vorrei raccomandare per mantenere una codebase pulita e leggibile, è avere blocchi logici specifici (di solito funzioni) separati per argomento e contesto. Se scriviamo una funzione, tale funzione dovrebbe avere un unico scopo e non dovrebbe fare più cose contemporaneamente. Inoltre, dovremmo evitare di causare effetti collaterali (side effect), vale a dire che, nella maggior parte dei casi, non dovremmo cambiare nulla che è dichiarato al di fuori della nostra funzione. Riceviamo i dati in una funzione attraverso i parametri; tutto il resto non dovrebbe essere accessibile. Se si necessita di estrarre dati da quella funzione, dovremmo restituirli attraverso la keyword return.
2) Modularizza
Ovviamente, possiamo raggruppare più funzioni in un modulo (e/o classi), se tali funzioni sono utilizzate per un unico scopo oppure perchè risolvono problemi similari. Ad esempio, se abbiamo bisogno di diverse funzionalità di calcolo, potremmo avere differenti funzioni indipendenti (quindi isolate) ma raggruppate in un modulo. Praticamente potremmo avere una situazione del genere:
function sum(a, b) {
return a + b
}
function subtract(a, b) {
return a - b
}
module.exports = {
sum,
subtract
}
Ipotizzando che il file del modulo risiderà in un file ‘calculations.js’:
const { add, subtract } = require('./calculations')
console.log(subtract(10, add(5, 5))
Se sei un sviluppatore frontend, sicuramente utilizzerai le esportazioni predefinite per gli oggetti più importanti e le esportazioni con nome per gli oggetti secondari.
3) Preferisci più parametri rispetto ai singoli parametri dell’oggetto
Quando dichiariamo una funzione, rispetto all’oggetto dovremmo sempre preferire più parametri piuttosto che un solo parametro.
In linee generali, il motivo è banale: tu sai esattamente cosa devi passare alla funzione quando guardi la prima riga della dichiarazione della funzione stessa. Ti richiederà, invece, un pò più di effort, se devi estrapolare le varie variabili che ti serviranno all’interno della funzione (che sono annidate all’interno di un oggetto).
Ovviamente questa non è una legge universale, nel senso che dovremmo prima analizzare quanti parametri ha bisogno la funzione e poi decidere in tal senso.
Ad esempio, se ci sono più di quattro o cinque parametri per funzione, non ha senso utilizzare una dichiarazione esplicita; in tal caso l’utilizzo di un oggetto è decisamente consigliato.
Perchè? La ragione principale è che i parametri devono essere passati in un ordine specifico. Se disponi di parametri opzionali, devi passare undefined o null. Mentre utilizzando un oggetto, l’ordine e i valori non definiti non contano.
Quindi riassumiamo tutto con un esempio:
// GOOD
function showUser(firstName, lastName, age) {
console.log(`I'm ${firstName} ${lastName}. He/She is ${age} years old.`)
}
// BAD
function displayUser(user) {
console.log(`I'm ${user.firstName} ${user.lastName}. He/She is ${user.age} years old.`)
}
4) Destrutturizza (Destructuring)
Abbiamo già parlato di questo argomento nella mini serie dedicata ad ES6.
Rappresenta uno dei più significativi tool introdotti con ES6. Ci consente di “catturare” campi specifici da un oggetto e assegnarli immediatamente ad una variabile. Prendendo in considerazione il modulo costruito al punto 2:
const { sum, subtract } = require('./calculations')
Se avessimo avuto un modulo con altre 10 funzioni con compiti diversi da sum e subtract, esse sarebbero state escluse; ha senso importare solo le funzioni che sono strettamente necessarie ai fini degli obiettivi del progetto/file invece dell’intero modulo.
5) Usa valori di default
I valori predefiniti per la destrutturazione o anche i parametri di funzione sono molto utili. In primo luogo, ti forniscono un esempio di quali valori possono essere passati alla funzione. In secondo luogo, è possibile indicare quali valori sono obbligatori e quali no.
function showUserDetails({
name = "Valerio Pisapia",
age = 33,
language = "Italian",
address
}) {
let msg = `I'm ${name}, I'm ${age} years ago. I speak ${language}.`;
if (address) msg += `I live in ${address}`;
console.log(msg);
}
showUserDetails({
name: "Mario Rossi",
age: 40,
language: "Italian",
address: "Via Roma"
});
showUserDetails({
name: "Luis",
age: 20,
language: "German"
});
6) Usa prettier
Lavorare in squadra richiede una chiara guida di stile e formattazione.
Prettier è un perfetto compagno di viaggio in tal sesno. In questo modo, gli sviluppatori non devono preoccuparsi della formattazione del codice, ma semplicemente scrivere codice di alta qualità. L’aspetto sarà coerente e la formattazione automatica.
Vi invito caldamente a dargli un occhiata.
7) Usa nomi di variabili significativi
Idealmente, una variabile dovrebbe essere nominata in base al suo contenuto. Ecco alcune linee guida che ti aiuteranno a definire nomi di variabili significative.
Funzioni
Le funzioni solitamente svolgono delle azioni ben precise. È una buona idea denominare le tue funzioni con un verbo all’inizio, ad esempio: showUser, getValues.
Arrays
Gli array, in generale, rappresentano una lista . Aggiungere una lettera “s” alla fine del nome della variabile potrebbe essere un buon pattern. Ad esempio: names, cities.
Boolean
Basta iniziare l’identificativo con is o has in modo che sia vicino al linguaggio naturale.
Ad esempio: isTeacher, hasCompleted.
8) Usa async/await dove è possibile
Le callback sono le peggiori per quanto riguarda la leggibilità, specialmente quando sono nidificate. Le promise sono state un bel miglioramento, e con async/await si raggiungere la miglior leggibilità.
Anche per chi è alla prime armi o sviluppatori con diverso background, async/await rende la vita più semplice. Tuttavia, assicurati di comprendere il concetto che sta dietro e non utilizzarlo ovunque.
9) Segui una logica nell’importazione dei moduli
Come abbiamo visto nei punt 1 e 2, mantenere la logica al posto giusto è la chiave per la manutenibilità. Di pari passo, il modo in cui importi diversi moduli può ridurre la confusione nei tuoi file. Seguendo questo semplice pattern, non dovresti aver più problemi di confusione del tuo codice:
// 3rd party packages import React from 'react' import styled from 'styled-components' // Stores (if you're using Redux or Ngrx for instance) import Store from '~/Store // Reusable components import Button from '~/components/Button' // Utility functions import { sum, subtract } from '~/utils/calculate' // Submodules import Home from './Intro' import Selector from './Selector'
10) Limitare il numero di linee di codice in un file
A chi non è mai capitato di imbattersi in file di grandi dimensioni – file decisamente grandi: oltre 3.000 righe di codice? Trovare snippet di logica è un compito davvero arduo.
Pertanto, è necessario limitare le dimensioni del file a un determinato numero di righe. Tendenzialmente bisognerebbe mantenersi al di sotto delle 100 righe di codice. A volte, è difficile suddividere i file, mantenendo un rigore logico, pertanto cresceranno fino a 200-300 righe e, in rare occasioni, fino a 400.
Al di sopra di questa soglia, il file diventa difficile da mantenere. Bisogna sentirsi liberi di creare nuovi moduli e cartelle. Il tuo progetto dovrebbe assomigliare a una foresta, composta da alberi (moduli) e rami (gruppi di moduli e file di moduli).
Spero questo articolo sia stato utile. Se si, condividilo con i tuoi amici, colleghi o con chi ritieni che possa essere interessato.
Valerio Pisapia, 34 anni, laureato in Ingegneria Informatica all’Università di Napoli Federico II. Ha esperienza decennale nello sviluppo mobile e web in ambito internazionale. Fornisce training e mentoring per progetti di svariata natura. Founder della Dreaming Lab, startup IT in Svizzera, che si occupa di consulenza specializzata in ambito Web.
Comments