Il 0% ha trovato utile questo documento (0 voti)
10 visualizzazioni53 pagine

Codice Pulito - JavaScript

Il documento presenta i principi dell'ingegneria del software adattati per JavaScript, ispirati al libro 'Codice Pulito' di Robert C. Martin. Si concentra su come scrivere codice leggibile, riutilizzabile e manutenibile, fornendo linee guida su variabili, funzioni e strutture dati. Viene enfatizzata l'importanza di nomi significativi, funzioni con un solo scopo e l'evitare la duplicazione del codice.

Tradotto da

ScribdTranslations
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd
Il 0% ha trovato utile questo documento (0 voti)
10 visualizzazioni53 pagine

Codice Pulito - JavaScript

Il documento presenta i principi dell'ingegneria del software adattati per JavaScript, ispirati al libro 'Codice Pulito' di Robert C. Martin. Si concentra su come scrivere codice leggibile, riutilizzabile e manutenibile, fornendo linee guida su variabili, funzioni e strutture dati. Viene enfatizzata l'importanza di nomi significativi, funzioni con un solo scopo e l'evitare la duplicazione del codice.

Tradotto da

ScribdTranslations
Copyright
© All Rights Reserved
Per noi i diritti sui contenuti sono una cosa seria. Se sospetti che questo contenuto sia tuo, rivendicalo qui.
Formati disponibili
Scarica in formato PDF, TXT o leggi online su Scribd

1

Codice Pulito, versione JavaScript!


Principi dell'Ingegneria del Software adattati per JavaScript.

Se sei nello sviluppo software, questo è uno dei libri che devi leggere!
2

Indice
1. Introdução

2. Variabili

3. Funções

4. Oggetti e Strutture di Dati

5. Classi

6. SOLIDO

7. Testicoli

8. Concorrente

9. Trattamento degli Errori

10. Formattazione

11. Comentários

12. Crediti

. . .

1. Introdução
3

Immagine umoristica della stima della qualità del software basata sul conteggio di quanti
parolacce hai urlato mentre leggevo il codice.

Principi dell'Ingegneria del Software, del libro di Robert C. Martin


Codice Pulito, adattato per JavaScript. Questo non è una guida di
stili. È una guida per produrre codice leggibile, riutilizzabile e
refattorizzabile in JavaScript.

Non tutti i principi dimostrati devono essere seguiti rigorosamente, e


ancora meno sono quelli che possiedono consenso universale. Sono orientamenti
e niente di più, tuttavia, sono state utilizzate nel codice per lungo tempo

anni di esperienza collettiva degli autori di Codice pulito.

Il nostro mestiere di ingegneria del software ha poco più di 50 anni e


stiamo ancora imparando molto. Quando l'architettura del software
per tanto vecchia quanto l'architettura stessa, forse allora avremo
regole più rigide da seguire. Per ora, lascia che queste
le indicazioni servono come criterio per valutare la qualità di
codice JavaScript che sia tu che il tuo team producono.

Ma un'altra cosa: imparare questo non ti trasformerà immediatamente.


diventare un migliore sviluppatore software e lavorare con loro per
molti anni non significa che non commetterai errori. Tutta la porzione
il codice inizia con una bozza, come argilla bagnata che
modellata nella sua forma finale. Infine, abbiamo scolpito le imperfezioni
4

quando rivediamo con i nostri colleghi. Non batterti per i primi


rascunhos que ainda precisam de melhorias. Ao invés, bata em seu
codice.

. . .

2. Variabili

Usa nomi di variabili che abbiano significato e siano


pronunciabili
Ruim:

const yyyymmdstr = moment().format('YYYY/MM/DD');

Bom:

const currentDate = moment().format('YYYY/MM/DD');

Usa lo stesso vocabolario per lo stesso tipo di variabile


Ruim:

getUserInfo();
ottieniDatiCliente();
ottieniRecordCliente();

Buono

ottieniUtente();
5

Usa nomi ricercabili


Leggeremo più codice di quanto ne scriveremo. È importante che il codice
ciò che scriviamo deve essere leggibile e [Link] dando nomi in
variabili che siano significative per capire il nostro programma,
facciamo del male ai nostri lettori. Rendi i loro nomi ricercabili.
Ferramentas como [Link] e ESLint podem ajudar a identi car
costanti senza nome.

Spazio

// A cosa diavolo serve 86400000?


setTimeout(blastOff, 86400000);

Bene:

// Dichiara come `const` globale in maiuscolo.


const MILLISECONDI_IN_UN_GIORNO = 86400000;

setTimeout(blastOff, MILLISECOND_IN_UN_GIORNO);

Usa variabili esplicative


Ruim:

const address = 'One Infinite Loop, Cupertino 95014';


const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode([Link](cityZipCodeRegex)[1],
[Link](cityZipCodeRegex)[2]);

Bom:

const address = 'One Infinite Loop, Cupertino 95014';


const cityZipCodeRegex = /^[^,\]+[,\a0]+(.+?)\s*(\d{5})?$/;
const [, città, codicePostale] = [Link](cityZipCodeRegex) ||
[];
6

saveCityZipCode(city, zipCode);

Evita la Mappatura Mentale


Esplicito è meglio che implicito.

Ampio:

const locations = ['Austin', 'New York', 'San Francisco'];


[Link]((l) => {
doStuff();
faAltreCose();
// ...
// ...
// ...
// Aspetta, a cosa serve `l` di nuovo?
invio(l);
});

Bom:

const locations = ['Austin', 'New York', 'San Francisco'];


[Link]((location) => {
fareCose();
doSomeOtherStuff();
// ...
// ...
// ...
invio(location);
});

Non aggiungere contesti non necessari


Se il nome della tua classe/oggetto ti dice qualcosa, non ripeterlo
nei nomi delle tue variabili.

Ruim:

const Car = {
carMake: 'Honda',
carModel: 'Accord',
7

carColor: 'Blue'
};

funzione dipingiAuto(auto) {
[Link] = 'Red';
}

Bom:

const Car = {
make: 'Honda',
model: 'Accord',
color: 'Blue'
};

function dipingiAuto(auto) {
[Link] = 'Red';
}

Usa argomenti standard invece di cortocircuitare o


usare i condizionali
Gli argomenti standard sono generalmente più puliti rispetto a breve
circuiti. Sii consapevole che se li usi, la tua funzione funzionerà solo
fornire valori predefiniti per gli argomentiundefined . Altri valori
falsi come'' , "" , falso, null , 0, eNaN, non saranno
sostituiti con valori predefiniti.

Ruim:

function createMicrobrewery(name) {
const breweryName = name || 'Hipster Brew Co.';
// ...
}

Bom:

function createMicrobrewery(breweryName = 'Hipster Brew Co.')


8

{
// ...
}

. . .

.•213 3. Funções

Argomenti di funzioni (idealmente 2 o meno)


Limitare la quantità di parametri di una funzione è incredibilmente
importante perché rende più facile testarla. Avere più di tre porta a
un'esplosione combinatoria dove devi testare molti casi
diversi con ogni argomento separatamente.

Uno o due argomenti sono il caso ideale, e tre devono essere evitati se
possibile. Qualsiasi cosa in più deve essere consolidata.
Geralmente, se hai più di due argomenti, allora la tua funzione
stai tentando fare molte cose. Nei casi in cui non lo sei, nella
La maggior parte delle volte un oggetto è consapevole come argomento.

Jaque JavaScript ti permette di creare oggetti istantaneamente, senza avere


che scrive molte cose, puoi usare un oggetto se lo prendi
precisando usare molti argomenti.

Per rendere più ovvie quali sono le proprietà che le funzioni


Aspettiamo, puoi usare la sintassi di destrutturazione
(destrutturazione) in ES2015/ES6. Ha alcuni vantaggi:

Quando qualcuno guarda la firma di una funzione, è


Immediatamente chiaro quali proprietà sono utilizzate.

2. La destrutturazione clona anche i valori primitivi specifici


l'oggetto passato come argomento per la funzione. Questo può
aiutare a evitare effetti collaterali. Nota: oggetti e vettori che sono
desestrutturati a partire dall'oggetto passato come argomento NO
sono clonati.

3. I linters possono avvisarti delle proprietà non utilizzate, il


che sarebbe impossibile senza usare la destrutturazione.

Ruim
9

function createMenu(title, body, buttonText, cancellable) {


// ...
}

Bom:

function createMenu({ title, body, buttonText, cancellable })


{
// ...
}

creaMenu({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true
});

Funções devem fazer uma coisa


Esséde è lontano dalla regola più importante nell'ingegneria del software.
Quando le funzioni fanno più di una cosa, diventano difficili da
saranno composte, testate e razionalizzate. Quando puoi isolare
una funzione per eseguire solo un'azione, possono essere
refattorizzate facilmente e il tuo codice sarà molto più pulito. Se tu
non portare più nulla di questa guida oltre a questo, sarai già avanti a
molti sviluppatori.

Stretto:

funzione emailClients(clients) {
[Link]((cliente) => {
const clientRecord = [Link](client);
se ([Link]()) {
email(cliente);
}
});
}

Bom:
10

funzione emailClientAttivi(clienti) {
clienti
.filtra(èClientAttivo)
.forEach(email);
}

function isActiveClient(client) {
const clientRecord = [Link](client);
return [Link]();
}

I nomi delle funzioni devono dire cosa fanno


Ruim

funzione aggiungiAllaData(data, mese) {


// ...
}

const data = new Date();

// È difficile dire dal nome della funzione cosa viene aggiunto


aggiungiAData(data, 1);

Buono:

function aggiungiMeseAData(mese, data) {


// ...
}

const date = new Date();


aggiungiMeseAllaData(1, data);

Le funzioni devono avere solo un livello di astrazione


Quando hai più di un livello di astrazione, la tua funzione
probabilmente stai facendo troppe cose. Dividere le tue funzioni porta
una rielaborazione e test più facili.

Ampio:
11

function parseBetterJSAlternative(code) {
const REGEXES = [
// ...
];

const dichiarazioni = [Link](' ');


const tokens = [];
[Link]((REGEX) => {
[Link]((statement) => {
// ...
});
});

const ast = [];


[Link]((token) => {
// lex...
});

[Link]((nodo) => {
// analizza...
});
}

Buono

function tokenize(code) {
const REGEXES = [
// ...
];

const dichiarazioni = [Link](' ');


const tokens = [];
[Link]((REGEX) => {
[Link]((statement) => {
[Link]( /* ... */ );
});
});

restituisci i token;
}

funzione lexer(tokens) {
const ast = [];
[Link]((token) => {
[Link]( /* ... */ );
});

return ast;
}

funzione parseBetterJSAlternative(codice) {
12

const tokens = tokenizza(codice);


const ast = lexer(tokens);
[Link]((nodo) => {
// analizzare...
});
}

Rimuovere codice duplicato


Fai assolutamente del tuo meglio per evitare codice duplicato. Codice
duplicato significa che ci sono più di un posto dove dovrai
modificare qualcosa se è necessario cambiare qualche logica.

Immagina di essere il proprietario di un ristorante e di gestirlo.


inventario: tutti i tuoi pomodori, cipolle, aglio, spezie, ecc. Se tu
Hai più elenchi dove conservi queste informazioni, quindi avrai
che aggiornare tutte quando si serve un piatto che contiene pomodori.
Se avessi solo un elenco, avresti solo un posto per
aggiornare!

Frequentemente, hai codice duplicato perché hai due


ou più cose leggermente diverse, che hanno molto in comune,
ma le sue differenze lo costringono ad avere altre due o tre funzioni che
fanno molto delle stesse cose. Rimuovere codice duplicato significa
creare un'astrazione che sia in grado di gestire questo insieme di
cose diverse con solo una funzione/modulo/classe.

Ottenere l'astrazione corretta è fondamentale, per questo dovresti


seguire i principi SOLID descritti nella sezione Classi. Astrazioni
le rovine possono essere peggiori del codice duplicato, quindi prendi
Attenzione! Detto ciò, se puoi fare una buona astrazione, fallo!
Non ripeterti, altrimenti ti troverai ad aggiornarti.
molti luoghi ogni volta che hai bisogno di cambiare qualsiasi cosa.

Ampio:

function showDeveloperList(developers) {
[Link]((sviluppatore) => {
const expectedSalary =
[Link]();
const experience = [Link]();
const githubLink = [Link]();
const data = {
expectedSalary,
13

esperienza
githubLink
};

rendere(dati);
});
}

funzione mostraListaManager(manager) {
[Link]((manager) => {
const expectedSalary = [Link]();
const experience = [Link]();
const portfolio = [Link]();
const data = {
expectedSalary,
esperienza
portafoglio
};

render(data);
});
}

Bom:

function showEmployeeList(employees) {
[Link]((employee) => {
const expectedSalary =
[Link]();
const experience = [Link]();

const data = {
expectedSalary,
esperienza
};

switch([Link]){
caso 'manager':
[Link] = [Link]();
break;
caso 'sviluppatore':
[Link] = [Link]();
interrompere;
}

render(data);
});
}

Definisci (set) oggetti standard con [Link]


14

Ruim:

const menuConfig = {
title: null,
body: 'Bar',
buttonText: null,
cancellable: true
};

funzione creaMenu(config) {
[Link] = [Link] || 'Foo';
[Link] = [Link] || 'Bar';
[Link] = [Link] || 'Baz';
[Link] = [Link] !== undefined ?
[Link] : true;
}

createMenu(menuConfig);

Bom:

const menuConfig = {
title: 'Order',
// L'utente non ha incluso la chiave 'body'
buttonText: 'Send',
cancellable: true
};

function createMenu(config) {
config = [Link]({
title: 'Foo',
body: 'Bar',
buttonText: 'Baz',
cancellable: true
}, config);

// configuração agora é: {title: "Order", body: "Bar",


buttonText: "Send", cancellable: true}
// ...
}

creaMenu(menuConfig);

Non utilizzare le etichette come parametri delle funzioni


Le flag comunicano all'utente che la sua funzione fa più di una cosa.
Le funzioni devono fare solo una cosa. Dividi le tue funzioni se esse
15

stanno seguendo percorsi di codice diversi basati su un valore


boleano.

Ruim:

funzione creaFile(nome, temp) {


se (temp) {
[Link](`./temp/${name}`);
} else {
[Link](nome);
}
}

Buono:

funzione creaFile(nome) {
[Link](nome);
}

funzione creaFileTemp(nome) {
createFile(`./temp/${name}`);
}

Evita Effetti Collaterali (parte 1)


Una funzione produce un effetto collaterale se fa qualcosa che
non deve essere ricevere un valore di ingresso e restituire un altro(o) valore(i).
Un effetto collaterale può essere scrivere in un file, modificare una
variabile globale, o trasferire accidentalmente tutti i tuoi soldi a
un estraneo.

Ora, hai bisogno di effetti collaterali occasionalmente nel tuo


programma. Come nell'esempio precedente, potresti dover scrivere
in un file. Quello che vuoi fare è centralizzare dove si trova
facendo questo. Non avere diverse funzioni e classi che scrivano per
un file in particolare. Avere un servizio che faccia questo. Un e
solo uno.

Il punto principale è evitare trappole come condividere lo stato


tra oggetti senza alcuna struttura, utilizzando tipi di dati
mutabili che possono essere scritti da qualsiasi cosa, e non
16

centralizzando dove il suo effetto collaterale si verifica. Se riesci


fare questo, sarai molto più felice della grande maggioranza degli altri
programmatori.

Benessere

// Variabile globale referenziata dalla seguente funzione


// Se avessimo un'altra funzione che usa quel nome, allora sarebbe
un vettore (array) e potrebbe rompere il tuo codice
let name = 'Ryan McDermott';

funzione dividiInNomeEbero() {
name = [Link](' ');
}

dividiInNomeEFamiglia();

[Link](name); // ['Ryan', 'McDermott'];

Buono:

function splitIntoFirstAndLastName(name) {
return [Link](' ');
}

const name = 'Ryan McDermott';


const newName = splitIntoFirstAndLastName(name);

[Link](name); // 'Ryan McDermott';


[Link](newName); // ['Ryan', 'McDermott'];

Evita Effetti Collaterali (parte 2)


In JavaScript, i tipi primitivi sono passati per valore e
objetos/vetores são passados por referência. No caso de objetos e
vettori, se la sua funzione apporta una modifica a un vettore di un carrello
di acquisti, per esempio, aggiungendo un articolo da acquistare,
então qualquer outra função que use o vetor carrellosarà anche
affettata da questa aggiunta. Questo può essere ottimo, ma potrebbe anche essere

Brutto. Immaginiamo una situazione brutta:

O usuário clica no botão “Comprar”, botão que invoca a função


17

acquistoche innesca una serie di richieste e invia il vettore


per il server. A causa di una connessione internet scadente, la
carrello

funzioneacquistoè necessario rifare la richiesta. Adesso,


immagina che nel frattempo l'utente clicchi accidentalmente su
pulsanteAggiungi al carrelloin un prodotto che non voleva
prima che la richiesta inizi. Se ciò accade e la richiesta è
inviata nuovamente, quindi la funzioneacquistoinviare
accidentalmente il vettore con il nuovo prodotto aggiunto perché esiste
una referenza per il vettorecarrelloche la funzioneaggiungiArticoloAlCarrello
modificato aggiungendo un prodotto indesiderato.

Una soluzione ottimale sarebbe che la funzioneaggiungiCarrelloAElementosempre

clonasse o vettorecart , lo modificasse e poi restituisse il suo clone. Questo


garantisci che nessun'altra funzione che possieda un riferimento per il
il carrello degli acquisti deve essere influenzato da qualsiasi modifica apportata.

Due riserve su questo approccio:

Potrebbero esserci casi in cui vuoi davvero cambiare l'oggetto di


entrata, ma quando adotti questo tipo di programmazione, tu
vai scoprire che questi casi sono piuttosto rari. La maggior parte delle
le cose possono essere refattorizzate per non avere effetti collaterali.

Clonare oggetti grandi può essere piuttosto costoso in termini di


prestazioni. Con un po' di fortuna, nella pratica ciò non è un problema,

perché esistono ottime biblioteche che permettono che questo tipo di


la programmazione sia rapida e non sia così intensa nell'uso di
{"italian":"memoria quanto sarebbe se clonassi manualmente oggetti e"}
vettori.

Ruim:

const addItemToCart = (cart, item) => {


[Link]({ item, date: [Link]() });
};

Buono:

const addItemToCart = (cart, item) => {


18

return [...cart, { item, date: [Link]() }];


};

Non scrivere in funzioni globali


Poluir globaiséuma pratica ruim em JavaScript porque vocêpode
causare conflitto con un'altra libreria e l'utente della tua API non farebbe la
minore idea fino a che non fosse un'eccezione sollevata in
produzione. Pensiamo a un esempio: e se volessi estendere
Il metodo nativo Array di JavaScript per avere un metododifferenzache
Potresti mostrare la differenza tra due vettori? Potresti scrivere
sua nuova funzione [Link], ma potrebbe scontrarsi con un'altra
biblioteca che ha cercato di fare la stessa cosa. E se quest'altra biblioteca
stavo solo usandodifferenzaper trovare la differenza tra il primo e
ultimo elemento di un vettore? È per questo che sarebbe molto meglio usare
le classi standard di ES2015/ES6 e solo estendere ilArray globale.

Ruim:

[Link] = function diff(comparisonArray) {


const hash = new Set(comparisonArray);
return [Link](elem => ![Link](elem));
};

Bom:

class SuperArray extends Array {


diff(comparisonArray) {
const hash = new Set(comparisonArray);
return [Link](elem => ![Link](elem));
}
}

Favorire la programmazione funzionale rispetto alla programmazione


imperativa
JavaScript non è un linguaggio funzionale allo stesso modo di
Haskellé, ma ha un tocco di funzionale in sé. Linguaggi
Le funzioni sono più pulite e facili da testare. Favorisci questo tipo di
programmazione quando puoi.
19

Ruim

const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];

let totalOutput = 0;

per (let i = 0; i < [Link]; i++) {


totalOutput += programmerOutput[i].linesOfCode;
}

Buono

const programmerOutput = [
{
name: 'Uncle Bobby',
linesOfCode: 500
}, {
name: 'Suzie Q',
linesOfCode: 1500
}, {
name: 'Jimmy Gosling',
linesOfCode: 150
}, {
name: 'Gracie Hopper',
linesOfCode: 1000
}
];

const INITIAL_VALUE = 0;

const totalOutput = programmerOutput


.map((programmer) => [Link])
.reduce((acc, righeDiCodice) => acc + righeDiCodice,
VALORE_INIZIALE);
20

Incapsula condizioni
Ruim:

se ([Link] === 'fetching' && èVuoto(listNode)) {


// ...
}

Bom:

la funzione dovrebbeMostrareSpinner(fsm, nodoLista) {


ritorna [Link] === 'fetching' && isEmpty(listNode);
}

se (dovrebbeMostrareSpinner(fsmInstance, listNodeInstance)) {
// ...
}

Evitare le negazioni di condizionali


Ruim:

funzione isDOMNodeNotPresent(node) {
// ...
}

se (!isDOMNodeNotPresent(node)) {
// ...
}

Bom:

function isDOMNodePresent(node) {
// ...
}

se (èPresenteNodoDOM(nodo)) {
// ...
21

Evita condizionali
Questa sembra essere un compito impossibile. La prima volta che le persone
ascoltate questo, la maggior parte dice, “come dovrei in teoria fare qualcosa

cosa senza usarese? La risposta è che puoi usare il polimorfismo


per svolgere la stessa attività in diversi casi. La seconda questione è
generalmente, “bene, questo è ottimo, ma perché dovrei farlo?” A
risposta è un concetto di codice pulito appreso in precedenza: una
una funzione deve fare solo una cosa. Quando hai classi e
funzioni che hanno dichiarazionise, stai dicendo al tuo utente
che la tua funzione fa più di una cosa. Ricordati, solo una
cosa.

Ruim:

classe Aeroplano {
// ...
getCruisingAltitude() {
switch ([Link]) {
caso '777':
restituisci [Link]() -
[Link]();
caso 'Air Force One':
restituisce [Link]();
caso 'Cessna':
restituisce [Link]() -
[Link]();
}
}
}

Bom:

classe Aereo {
// ...
}

classe Boeing777 estende Aereo {


// ...
getCruisingAltitude() {
restituisci [Link]() - [Link]();
}
22

class AirForceOne estende aereo {


// ...
getCruisingAltitude() {
restituisci [Link]();
}
}

classe Cessna estende Aeroplano {


// ...
getCruisingAltitude() {
restituisci [Link]() - [Link]();
}
}

Evita il controllo dei tipi (parte 1)


JavaScript non ha tipi, il che significa che le sue funzioni possono
ricevere qualsiasi tipo di argomento. A volte questa libertà
può morderti, e diventa tentatore effettuare controlli sui tipi nei tuoi
funzioni. Ci sono molti modi per evitare di doverlo fare. A
La prima cosa da considerare sono API coerenti.

Ruim:

funzione viaggiaInTexas(veicolo) {
se (veicolo instanceof Bicicletta) {
[Link]([Link]àCorrente, nuovo
Luogo('texas'));
} else if (vehicle instanceof Auto) {
[Link]([Link]àCorrente, nuovo
Posizione('texas');
}
}

Bene:

function travelToTexas(vehicle) {
[Link]([Link], new Location('texas'));
}

Evita il controllo dei tipi (parte 2)


23

Se stai lavorando con valori primitivi di base come


string e interi, e voi non potete usare il polimorfismo, ma ancora
senti la necessità di verificare il tipo, dovresti considerare di usare
TypeScript è un'eccellente alternativa al JavaScript normale, già
che fornisce una tipizzazione statica sulla sintassi standard del
JavaScript. Il problema con la verifica manuale in JavaScript è che
per fare bene richiede tanta verbosità extra che il falso
"tipaggio sicuro" che riesci a ottenere non compensa per la perdita di
leggibilità. Mantieni il tuo JavaScript pulito, scrivi buoni test, e
hai buone revisioni del codice. Oppure, in un altro modo, fai tutto questo ma
com TypeScript (che, come ho detto, è una ottima alternativa!).

Ruim:

funzione combina(val1, val2) {


se (typeof val1 === 'numero' && typeof val2 === 'numero' ||
typeof val1 === 'string' && typeof val2 === 'string') {
restituire val1 + val2;
}

throw new Error('Must be of type String or Number');


}

Buono

funzione combina(val1, val2) {


return val1 + val2;
}

Non ottimizzare troppo


I browser moderni fanno molte ottimizzazioni sotto la
pannelli in tempo di esecuzione. Molte volte, se sei
ottimizzando, stai solo perdendo il tuo tempo. Ci sono buoni
risorse per verificare dove manca ottimizzazione. Concentrati su questi per
mentre, finché non verranno riparati, se possibile.

Ampli
24

// Nei browser obsoleti, ogni iterazione di `[Link]` non


cacheata sarebbe costosa
// a causa della ricomputazione di `[Link]`. Nei browser
moderni, cioè ottimizzati.
per (let i = 0, len = [Link]; i < len; i++) {
// ...
}

Bom:

per (let i = 0; i < [Link]; i++) {


// ...
}

Rimuovi codice morto


Il codice morto è altrettanto cattivo quanto il codice duplicato. Non esiste
nessun motivo per lasciarlo nel tuo codice. Se non viene utilizzato
chiamato, liberati da lui. Sarà ancora al sicuro nella tua cronologia di
versionamento se ancora ne hai bisogno.

Ruim:

function oldRequestModule(url) {
// ...
}

function newRequestModule(url) {
// ...
}

const req = newRequestModule;


inventoryTracker('mela', req, '[Link]');

Buono:

function newRequestModule(url) {
// ...
25

const req = newRequestModule;


inventoryTracker('mele', req, '[Link]');

4. Oggetti e Strutture di Dati

Usa getter e setter


Usare getter e setter per accedere ai dati negli oggetti è molto meglio
che semplicemente cercare una proprietà in un oggetto. “Per
cosa?
motivos:

Quando vuoi fare di più oltre a prendere la proprietà


da un oggetto, non dovete cercare e cambiare tutti i
accessori del tuo codice;

È più facile fare validazione quando stai dando unset;

Incapsula la rappresentazione interna;

Più facile aggiungere log e gestione degli errori quando si dà


ottieni e imposta;

Puoi utilizzare il caricamento pigro sulle proprietà del tuo oggetto,


diciamo, per esempio, prendendolo da un server.

Ruim:

funzione creaContoBancario() {
// ...

restituire {
balance: 0,
// ...
};
}

const account = creaContoBancario();


[Link] = 100;

Bom:
26

funzione creaContoBancario() {
// este é privado
lasciare saldo = 0;

// un "getter", reso pubblico attraverso l'oggetto restituito


sotto
funzione getBalance() {
restituisci saldo;
}

// un "setter", reso pubblico attraverso l'oggetto restituito


sotto
funzione impostaSaldo(importo) {
// ... convalidare prima di aggiornare il saldo
balance = amount;
}

restituire {
// ...
ottieniSaldo
impostaSaldo
};
}

const account = creaContoBancario();


[Link](100);

Fai in modo che gli oggetti abbiano membri privati


Questo può essere raggiunto attraverso le closure (per ES5 e oltre).

Ampio:

const Employee = function(name) {


[Link] = nome;
};

[Link] = function getName() {


restituisci [Link];

};

const impiegato = new Impiegato('John Doe');


[Link](`Nome dell'impiegato: ${[Link]()}`);
Employee name: John Doe
elimina [Link];
[Link](`Nome dell'impiegato: ${[Link]()}`); //
Employee name: undefined
27

Buono:

function creaDipendente(nome) {
ritorna {
getName() {
restituisci nome;
},
};
}

const employee = creaDipendente('John Doe');


[Link](`Employee name: ${[Link]()}`); //
Employee name: John Doe
elimina [Link];
[Link](`Nome dipendente: ${[Link]()}`); //
Employee name: John Doe

5. Classi

Preferisci classi ES2015/ES6 invece di funzioni


semplice dell'ES5
È molto difficile ottenere eredità di classe, costruttori, e
le definizioni dei metodi siano leggibili per le classi ES5 classiche. Se
hai bisogno di eredità (e sii consapevole che potresti non averne bisogno),
quindi preferisci classi ES2015/ES6. Nel frattempo, preferisci funzioni
piccole invece di classi finché non hai bisogno di oggetti più grandi
e più complessi.

Ruim:

const Animal = function(age) {


se (!(questa è un'istanza di Animale)) {
throw new Error('Instantiate Animal with `new`');
}

[Link] = age;
};

[Link] = function move() {};

const Mammifero = function(eta, colorePelo) {


se (!(this instanceof Mammal)) {
28

lancia nuovo Errore('Istanziato Mammifero con `new`');


}

[Link](questo, età);
[Link] = furColor;
};

[Link] = [Link]([Link]);
[Link] = Mammifero;
[Link] = function nascitaVivente() {};

const Human = function(age, furColor, languageSpoken) {


se (!(questo è un esempio di Umano)) {
throw new Error('Instantiate Human with `new`');
}

[Link](questo, età, colorePelo);


[Link] = languageSpoken;
};

[Link] = [Link]([Link]);
[Link] = Human;
[Link] = function speak() {};

Buono

classe Animale {
constructor(age) {
[Link] = age;
}

muovi() { /* ... */ }
}

classe Mammifero estende Animale {


constructor(age, furColor) {
super(età);
[Link] = furColor;
}

liveBirth() { /* ... */ }
}

classe Umano estende Mammifero {


costruttore(età, colorePelo, linguaParlata) {
super(eta, colorePelliccia);
[Link] = languageSpoken;
}

parla() { /* ... */ }
29

Utilizzare il chaining di metodi


Questo modello è molto utile in JavaScript e lo vedrai in molti
biblioteche come jQuery e Lodash. Permette al tuo codice di essere
espressivo e meno verboso. Per questo motivo, dico, usa
incatenamento di metodi e dai un'occhiata a come il tuo codice
sarà più pulito. Nelle tue funzioni di classi, restituisci semplicementequesto
no finale di ogni funzione, e potrai concatenare altri metodi di
classe nele.

Ruim:

classe Auto {
costruttore(marca, modello, colore) {
[Link] = make;
[Link] = model;
[Link] = colore;
}

setMake(make) {
[Link] = make;
}

setModel(model) {
[Link] = model;
}

setColor(color) {
[Link] = colore;
}

salva() {
[Link]([Link], [Link], [Link]);
}
}

const auto = new Auto('Ford','F-150','rosso');


[Link]('pink');
[Link]();

Bom:
30

classe Auto {
costruttore(marca, modello, colore) {
[Link] = make;
[Link] = model;
[Link] = colore;
}

setMake(make) {
[Link] = marca;
// NOTA: Restituisci questo per concatenare
restituisci questo;

setModel(model) {
[Link] = modello;
// NOTA: Restituisci this per concatenare
restituire questo;

setColor(color) {
[Link] = colore;
// NOTA: Retorne this para encadear
restituisci questo;

salva() {
[Link]([Link], [Link], [Link]);
// NOTA: Restituisci questo per concatenare
restituisci questo;

}
}

const car = new Car('Ford','F-150','red')


.setColor('pink')
.salva();

Preferisci composizione invece di ereditarietà


Come detto famosamente nel Modello di progettazione dalla Gangue dei
Quattro, dovresti preferire la composizione all'ereditarietà dove tu
puder. Esistono molte buone ragioni per usare l'ereditarietà e molte buone
ragioni per usare la composizione. Il punto principale per questa massima
se la tua mente va istintivamente all'eredità, prova a pensare
se la composizione potrebbe modellare meglio il tuo problema. In alcuni
casi può.

Dovresti stare pensando allora, "quando dovrei usare l'eredità?"


Questo dipende specificamente dal tuo problema, ma questa è una lista
decente di quando l'ereditarietà ha più senso della composizione:

La tua eredità rappresenta una relazione di "questo-è" e non una


31

relação de “isto-tem” (Human→Animal vs. User->UserDetails)

Puoi riutilizzare il codice delle classi base (Gli esseri umani possono
si muovono come tutti gli animali).

Vuoi apportare modifiche globali alle classi derivate


cambiando solo la classe base. (Cambiare il costo calorico per
tutti gli animali quando si muovono).

Ruim:

classe Dipendente {
costruttore(nome, email) {
[Link] = name;
[Link] = email;
}

// ...
}

// Ruim perché i dipendenti (Dipendenti) "hanno" dati di


impostos. EmployeeTaxData não é um tipo de Employee
classe DatiTasseDipendente estende Dipendente {
costruttore(ssn, stipendio) {
super();
[Link] = ssn;
[Link] = stipendio;
}

// ...
}

Buono:

classe DatiFiscaliDipendente {
costruttore(ssn, stipendio) {
[Link] = ssn;
[Link] = stipendio;
}

// ...
}

classe Dipendente {
costruttore(nome, email) {
[Link] = name;
32

[Link] = email;
}

setTaxData(ssn, stipendio) {
[Link] = new EmployeeTaxData(ssn, stipendio);
}
// ...
}

6. SOLIDO

Principio della Responsabilità Unica (SRP)


Come detto in Codice Pulito, "Non dovrebbe mai esserci più di uno
motivo per cui una classe deve cambiare”. È tentatore impacchettare una
classe in eccesso con molte funzionalità, come quando tu
puoi portare solo una valigia nel tuo volo. Il problema è che
la sua classe non sarà concettualmente coesa e le darà diversi
motivi per cambiarla. Minimizzare il numero di volte che hai bisogno
Cambiare una classe è importante, perché, se molte funzionalità
si trovano in una classe e cambiando una porzione di essa, potrebbe essere difficile
capire come questo influenzerà altri moduli che dipendono da essa nel
il tuo codice.

Ampio:

classe ImpostazioniUtente {
costruttore(utente) {
[Link] = user;
}

cambiaImpostazioni(impostazioni) {
se ([Link]()) {
// ...
}
}

verificareCredenziali() {
// ...
}
}

Buono:
33

classe UserAuth {
costruttore(utente) {
[Link] = utente;
}

verificaCredenziali() {
// ...
}
}

classe ImpostazioniUtente {
costruttore(utente) {
[Link] = user;
[Link] = new UserAuth(user);
}

changeSettings(settings) {
se ([Link]()) {
// ...
}
}
}

Principio Aperto/Chiuso (OCP)


Come è stato detto da Bertrand Meyer, "entità di software (classi,
moduli, funzioni, ecc.) devono rimanere aperti per estensioni, ma
chiuse per modifiche.” Ma cosa significa questo? Questo principio
Fondamentalmente dice che devi permettere agli utenti di aggiungere
nuove funzionalità senza modificare il codice esistente.

Ruim:

class AjaxAdapter extends Adapter {


costruttore() {
super();
[Link] = 'ajaxAdapter';
}
}

class NodeAdapter estende Adapter {


costruttore() {
super();
[Link] = 'nodeAdapter';
}
}

classe HttpRequester {
34

costruttore(adattatore) {
[Link] = adattatore;
}

fetch(url) {
if ([Link] === 'ajaxAdapter') {
return makeAjaxCall(url).then((response) => {
// trasforma la risposta e restituisci
});
} else if ([Link] === 'httpNodeAdapter') {
ritorna makeHttpCall(url).then((risposta) => {
// trasforma la risposta e restituisci
});
}
}
}

funzione eseguireChiamataAjax(url) {
// effettua una richiesta e restituisce la promessa

funzione faiChiamataHttp(url) {
// fa una richiesta e restituisce la promessa
}

Bom:

classe AjaxAdapter estende Adapter {}


costruttore() {
super();
[Link] = 'ajaxAdapter';
}

richiesta(url) {
// fa una richiesta e restituisce la promessa
}
}

classe NodeAdapter estende Adapter {


costruttore() {
super();
[Link] = 'nodeAdapter';
}

richiesta(url) {
// fa una richiesta e restituisce la promessa
}
}

classe HttpRequester {
costruttore(adattatore) {
[Link] = adapter;
35

fetch(url) {
return [Link](url).then((response) => {
// trasforma la risposta e restituisci
});
}
}

Princípio de Substituição de Liskov (LSP)


È un termine spaventoso per un concetto estremamente semplice.
È formalmente definito come "Se S è un sottotipo di T, allora gli oggetti"
di tipo T possono essere sostituiti da oggetti di tipo S (cioè,
Gli oggetti di tipo S possono sostituire oggetti di tipo T senza alterare
nessuna delle proprietà desiderabili di un programma (correttezza,
prestazione in compiti, ecc.)." Questa è una definizione ancora più
spaventosa.

La migliore spiegazione per questo concetto è se hai una classe padre


è una classe figlia, quindi la classe base e la classe figlia possono essere utilizzate

indistintamente senza avere risultati incorretti. Questo può ancora essere


confuso, allora diamo un'occhiata all'esempio classico del
Quadrato-Rettangolo. Matematicamente, un
un quadrato è un rettangolo, ma se lo modelli usando una relazione
«questo è» attraverso l'eredità, avrai rapidamente problemi.

Ruim:

classe Rettangolo {
costruttore() {
[Link] = 0;
[Link] = 0;
}

setColor(color) {
// ...
}

renderizza(area) {
// ...
}

setWidth(larghezza) {
[Link] = larghezza;
}
36

setHeight(altezza) {
[Link] = altezza;
}

getArea() {
restituire [Link] * [Link];

}
}

classe Quadrato estende Rettangolo {


setWidth(larghezza) {
[Link] = larghezza;
[Link] = larghezza;
}

setHeight(altezza) {
[Link] = height;
[Link] = altezza;
}
}

function renderLargeRectangles(rectangles) {
[Link]((rettangolo) => {
[Link](4);
[Link](5);
const area = [Link](); // RUIM: Retorna 25
per il Quadrato. Dovrebbe essere 20.
[Link](area);
});
}

const rectangles = [new Rectangle(), new Rectangle(), new


Quadrato()];
disegnaRettangoliGrandi(rettangoli);

Bom:

class Forma {
setColore(colore) {
// ...
}

render(area) {
// ...
}
}

class Rectangle extends Shape {


costruttore(larghezza, altezza) {
super();
[Link] = larghezza;
[Link] = altezza;
37

getArea() {
restituire [Link] * [Link];

}
}

classe Quadrato estende Forma {


costruttore(lunghezza) {
super();
[Link] = lunghezza;
}

getArea() {
restituisce [Link] * [Link];
}
}

function renderLargeShapes(shapes) {
[Link]((forma) => {
const area = [Link]();
[Link](area);
});
}

const shapes = [new Rectangle(4, 5), new Rectangle(4, 5), new


Quadrato(5)]
renderizzaGrandiForme(shapes);

Principio della Segregazione dell'Interfaccia (ISP)


JavaScript non ha interfacce quindi questo principio non si applica
estrattamente come gli altri. Tuttavia, è importante e rilevante fino a
anche con la mancanza di un sistema di tipi in JavaScript.

L'ISP dice che "i clienti non dovrebbero essere costretti a dipendere da

interfacce che non usano.” Le interfacce sono contratti impliciti in


JavaScript a causa della sua tipizzazione anatra (duck typing).

Un buon esempio da osservare che dimostra questo principio in


JavaScript ha classi che richiedono oggetti di configurazione
grandi. Non chiedere ai clienti di definire grandi quantità di
opzioni benéfiche, perché nella maggior parte dei casi non avranno bisogno di
tutte le impostazioni. Rendrele opzionali aiuta a prevenire una
interferenza grassa

Ruim:
38

classe DOMTraverser {
costruttore(settings) {
[Link] = impostazioni;
[Link]();
}

setup() {
[Link] = [Link];
[Link]();
}

traverse() {
// ...
}
}

const $ = new DOMTraverser({


rootNode: [Link]('body'),
animationModule() {} // Nella maggior parte dei casi, non
dobbiamo animarci mentre attraversiamo.
// ...
});

Bom:

classe DOMTraverser {
costruttore(settings) {
[Link] = settings;
[Link] = [Link];
[Link]();
}

setup() {
[Link] = [Link];
[Link]();
}

setupOptions() {
if ([Link]) {
// ...
}
}

traverse() {
// ...
}
}

const $ = new DOMTraverser({


rootNode: [Link]('body'),
options: {
39

moduleAnimazione() {}
}
});

Principio di Inversione delle Dipendenze (DIP)


Questo principio ci dice due cose essenziali:

Módulos de alto nível não devem depender de módulos de baixo


livello. Entrambi devono dipendere da astrazioni.

Le astrazioni non devono dipendere dai dettagli. I dettagli devono


dipendere da astrazioni.

Questo può essere difficile da capire all'inizio, ma se hai già lavorato


con AngularJS, hai già visto un'implementazione di questo principio nella
forma di iniezione delle dipendenze (DI). Anche se non sono
concetti identici, il DIP non consente ai moduli ad alto livello di sapere i
dettagli dei tuoi moduli di basso livello, così come configurarli.
Questo può essere raggiunto attraverso il DI. Un grande beneficio è che
riduce il accoppiamento tra i moduli. L'accoppiamento è uno standard di
sviluppo molto cattivo perché rende il tuo codice più difficile da
essere rifattorizzato.

Come detto in precedenza, JavaScript non ha interfacce, quindi le


Le astrazioni che sono necessarie sono contratti impliciti. Che vuole
dire che, i metodi e le classi che un oggetto/classe espone per
altri oggetti/classe. Nell'esempio seguente, il contratto implicito è che
qualunque modulo di Richiesta perTrackerInventarioteráum metodo
requestItems :

Ruim:

classe InventoryRequester {
costruttore() {
this.REQ_METHODS = ['HTTP'];
}

requestItem(item) {
// ...
}
}

classe InventoryTracker {
40

costruttore(items) {
[Link] = items;

// Ruim: Abbiamo creato una dipendenza da un'implementazione


di richiesta specifica.
// Dovremmo avere solo requestItems a seconda di
un metodo di richiesta: `request`
[Link] = new InventoryRequester();
}

requestItems() {
[Link]((item) => {
[Link](item);
});
}
}

const inventarioRintracciatore = new RintracciatoreInventario(['mele',


banane
[Link]();

Bom:

classe InventoryTracker {
constructor(items, requester) {
[Link] = elementi;
[Link] = richiedente;
}

requestItems() {
[Link]((item) => {
[Link](item);
});
}
}

class InventoryRequesterV1 {
costruttore() {
this.REQ_METHODS = ['HTTP'];
}

richiediArticolo(articolo) {

// ...
}
}

classe RichiedenteInventarioV2 {
costruttore() {
this.REQ_METHODS = ['WS'];
}

requestItem(item) {
41

// ...
}
}

// Construindo nossas dependências externamente e injetando-


possiamo facilmente
// sostituire il nostro modulo di richiesta con uno nuovo e più elegante
che usa WebSockets
const inventoryTracker = new InventoryTracker(['mele',
banane
[Link]();

[Link]
I test sono più importanti delle consegne. Se non hai test
hai una quantità inadeguata, quindi ogni volta che consegnerai il tuo
codice vocênão avrà certezza se vocênão hai rotto qualcosa.
Decidere cosa costituisce una quantità adeguata è responsabilità
del tuo team, ma avere il 100% di copertura (tutte le frasi e
branches)éa maneira que se alcança uma alta con ança e uma paz
di spirito in sviluppo. Questo significa che oltre ad avere un
ottimo framework di test, devi anche usare un buon
strumento di copertura.

Non esiste scusa per non scrivere test. Esistono diversi


frameworks de testes em JSótimos, então encontre um que seu time
pre ra. Quando trovi uno che funziona per la tua squadra, allora
ha come obiettivo scrivere sempre test per ogni novità
funzionalità/modulo che vuoi introdurre. Se il tuo metodo preferito
per lo Sviluppo Guidato dai Test (TDD), questo è ottimo, ma il
punto principale è solo assicurarsi che tu stia raggiungendo i tuoi
metas di copertura prima di lanciare qualsiasi funzionalità, o
rifattorizzare una già esistente.

Un concetto per test


Ampio:

importa assert da 'assert';

descrivi('RendiGrandiosoDiNuovoMomentJSGreatAgain', () => {

it('gestisce i confini delle date', () => {


let date;
42

date = new MakeMomentJSGreatAgain('1/1/2015');


[Link](30);
[Link]('1/31/2015', data);

date = new MakeMomentJSGreatAgain('2/1/2016');


[Link](28);
[Link]('02/29/2016', data);

date = new MakeMomentJSGreatAgain('2/1/2015');


[Link](28);
[Link]('03/01/2015', data);
});
});

Buono:

importa assert da 'assert';

descrivi('Rendi di nuovo grande MomentJSGreat', () => {


gestisce i mesi di 30 giorni
const date = new MakeMomentJSGreatAgain('1/1/2015');
[Link](30);
[Link]('1/31/2015', data);
});

it('gestisce l'anno bisestile', () => {


const data = new MakeMomentJSGreatAgain('2/1/2016');
[Link](28);
[Link]('29/02/2016', data);
});

it('gestisce l'anno non bisestile', () => {


const data = new MakeMomentJSGreatAgain('2/1/2015');
[Link](28);
[Link]('03/01/2015', date);
});
});

8. Concorrência

Usa le Promesse, non i callback


I callback non sono puliti e causano un'eccessiva quantità di
aninhamenti. A partire da ES2015/ES6, le Promesse sono un tipo nativo
globale. Usalo!
43

Ampio

importa { get } da 'request';


import { writeFile } from 'fs';

get('[Link]
(requestErr, response) => {
if (requestErr) {
[Link](requestErr);
} altro {
writeFile('[Link]', [Link], (writeErr) => {
se (writeErr) {
[Link](writeErr);
} altro {
[Link]('File written');
}
});
}
});

Bom:

importa { get } da 'richiesta';


importa { scriviFile } da 'fs';

get('[Link]
.then((risposta) => {
restituisci writeFile('[Link]', risposta);
})
.allora(() => {
[Link]('File scritto');
})
.catch((err) => {
[Link](err);
});

Async/Await è ancora più pulito delle Promises


Le promesse sono un'alternativa molto più pulita rispetto ai callback, ma il

ES2017/ES8 portaasincronoeattendereche offrono ancora una soluzione


ma più pulita. Tutto ciò di cui hai bisogno è una funzione che ha come

pre xo la parola chiaveasincrono, e poi puoi scrivere la tua logica


imperativamente senza usarepoiper concatenare le tue funzioni. Usa
questo se puoi approfittare delle funzionalità del
ES2017/ES8 oggi!
44

Ruim:

importa { get } da 'request-promise';


import { writeFile } from 'fs-promise';

ottieni('[Link]
.allora((risposta) => {
ritorna scriviFile('[Link]', risposta);
})
.allora(() => {
[Link]('File scritto');
})
.catch((err) => {
[Link](err);
});

Buono.

import { get } from 'request-promise';


import { writeFile } from 'fs-promise';

async function getCleanCodeArticle() {


prova {
const response = await get('[Link]
/wiki/Robert_Cecil_Martin
await writeFile('[Link]', risposta);
[Link]('File scritto');
} catch(err) {
[Link](err);
}
}

[Link]
lanciare erroreè una cosa buona! Loro significano che il programma
ha identificato con successo quando qualcosa è andato storto e sta permettendo
che tu sappia fermando l'esecuzione della funzione nel processo attuale,
chiudendo il processo (in Node) e notificandoti nel console con la
costa di processi.

Non ignorare gli errori catturati


Non fare nulla con un errore catturato non ti dà la capacità di
risolverlo o reagire all'errore segnalato. Mostrare un log nel
45

console([Link]) non è molto meglio perché molte volte lui


può essere perso tra un sacco di altre cose stampate nel
console. Se sviluppi qualsiasi pezzo di codice in un
try/catchquesto significa che credi che possa verificarsi un errore

Allora dovresti avere un piano, o creare un percorso di codice per


quando ciò si verifica.

Ruim:

prova {
functionThatMightThrow();
} catturare (errore) {
[Link](error);
}

Buono:

prova {
funcioneChePotrebbeLanciare();
} catturare (errore) {
// Un'opzione (più appariscente di [Link]):
[Link](error);
// Un'altra opzione:
notificaUtenteDiErrore(error);
// Un'altra opzione:
reportErrorToService(error);
// OU tutte e tre!
}

Non ignorare le promesse rifiutate


Per la stessa ragione per cui non dovresti ignorare errori catturati di
try/catch

Ruim:

ottieniDati()
.then((dati) => {
funzioneChePotrebbeLanciare(dati);
})
.catch((errore) => {
46

[Link](error);
});

Buono:

ottieniDati()
.then((dati) => {
functionThatMightThrow(data);
})
.catch((errore) => {
// Un'opzione (più rumorosa di [Link]):
[Link](error);
// Un'altra opzione:
notifyUserOfError(error);
// Un'altra opzione:
reportErrorToService(error);
// O fai tutti e tre!
});

10. Formattazione
Formattazione è soggettiva. Come molte regole qui, non ce n'è nessuna.
regola è chiara e veloce che devi seguire. Il punto principale è NON
DISCUTA sobre formatação. Existem muitas ferramentas para
automatizzare questo. Usane una! È uno spreco di tempo e denaro
per gli ingegneri discutere sulla formattazione.

Per cose che non possono utilizzare la formattazione automatica


(indentazione, tabulazioni vs. spazi, virgolette singole vs. doppie, ecc.) guarda qui
per qualche orientamento.

Utilizza la capitalizzazione coerente


JavaScript non è un linguaggio tipizzato, quindi la capitalizzazione dice
molto sulle tue variabili, funzioni, ecc. Queste regole sono soggettive,
quindi la tua squadra può scegliere ciò che vuole. Il punto è, non
Importa ciò che scegliete tutti, basta che siate coerenti.

Ruim:

const DAYS_IN_WEEK = 7;
47

const giorniNelMese = 30;

const songs = ['Back In Black', 'Stairway to Heaven', 'Hey


Giuda
const Artists = ['ACDC', 'Led Zeppelin', 'The Beatles'];

funzione cancellaDatabase() {}
function ripristina_database() {}

classe animale {}
classe Alpaca {}

Bom:

const GIORNI_NEL_SETTIMANA = 7;
const GIORNI_IN_MESE = 30;

const SONGS = ['Back In Black', 'Stairway to Heaven', 'Hey


Giuda
const ARTISTS = ['ACDC', 'Led Zeppelin', 'The Beatles'];

funzione cancellaDatabase() {}
funzione ripristinaDatabase() {}

classe Animale {}
classe Alpaca {}

Le funzioni e le chiamate di funzione devono essere vicine


Se una funzione chiama un'altra, mantieni queste funzioni in verticale
prossime nel file sorgente. In uno scenario ideale, mantenere la chiamata
logo sopra la funzione. Tendiamo a leggere il codice dall'alto verso il basso,
come in un giornale. A causa di ciò, fai il tuo codice in questo modo.

Ruim:

class PerformanceReview {
costruttore(dipendente) {
[Link] = employee;
}

lookupPeers() {
restituisci [Link]([Link], 'peers');
48

lookupManager() {
return [Link]([Link], 'manager');
}

getPeerReviews() {
const peers = [Link]();
// ...
}

perfReview() {
[Link]();
[Link]();
[Link]();
}

ottieniRecensioneManager() {

const manager = [Link]();


}

getSelfReview() {
// ...
}
}

const review = new PerformanceReview(employee);


[Link]();

Bom:

classe RevisionePerformance {
costruttore(dipendente) {
[Link] = dipendente;
}

perfReview() {
[Link]();
[Link]();
[Link]();
}

ottieniRecensioniPeer() {
const peers = [Link]();
// ...
}

lookupPeers() {
restituisci [Link]([Link], 'peers');
}
49

ottieniRecensioneManager() {

const manager = [Link]();


}

lookupManager() {
ritorna [Link]([Link], 'manager');
}

getSelfReview() {
// ...
}
}

const review = new PerformanceReview(employee);


[Link]();

11. Commenti

Apenas comente cose che abbiano complessità di


logica di affari.
I commenti sono un'apologia, non un requisito. Un buon codice
documenta-se,a maior parte, por si só.

Ruim

funzione hashIt(dati) {
// Un hash
let hash = 0;

Lunghezza della stringa


const lunghezza = [Link];

// Esegui il ciclo su ogni carattere dell'informazione

per (let i = 0; i < lunghezza; i++) {


// Ottieni il codice del carattere.
const char = [Link](i);
// Crea una hash
hash = ((hash << 5) - hash) + char;
// Converte in un intero a 32 bit
hash &= hash;
}
}

Fatto bene:
50

funzione hashIt(dati) {
lascia hash = 0;
const lunghezza = [Link];

per (let i = 0; i < lunghezza; i++) {


const char = [Link](i);
hash = ((hash << 5) - hash) + char;

// Converte in un intero a 32 bit


hash &= hash;
}
}

Non lasciare codice commentato nella tua base di codice


Il controllo di versione esiste per una ragione. Lasciare vecchi codici nel
il tuo storico.

Ruim:

faCose();
// fareAltreCose();
// faiAlcuneAltreCose();
// faiTanteCose();

Buono:

fareCose();

Non commentare il registro delle modifiche


Ricorda, utilizza il controllo delle versioni! Non è necessario lasciare
codici inutilizzati, codici commentati e specialmente registri di
modifiche. Utilizzareregistro gitper prendere la cronologia!

Ampio:

/**
51

2016-12-20: Rimos le monadi, non le capivo (RM)


2016-10-01: Miglioramento utilizzando monadi speciali (JP)
* 2016-02-03: Rimozione del controllo dei tipi (LI)
* 2015-03-14: Aggiunta verifica dei tipi (JR)
*/
funzione combina(a, b) {
ritorna a + b;
}

Buono:

funzione combina(a, b) {
ritorna a + b;
}

Evitare i segnaposto
Di solito fanno rumore. Lascia che le funzioni e i nomi di
variabili insieme con la dovuta indentazione e formattazione diano la
estrutura visual para o seu código.

Spazio

/////////////////////////////////////////////////////////////
///////////////////
// Instanziazione del Modello di Ambito
/////////////////////////////////////////////////////////////
///////////////////
$[Link] = {
menu: 'foo',
nav: 'bar'
};

/////////////////////////////////////////////////////////////
///////////////////
// Configurazione dell'Action
/////////////////////////////////////////////////////////////
///////////////////
const actions = function() {
// ...
};

Bom:
52

$[Link] = {
menu: 'foo',
nav: 'bar'
};

const azioni = function() {


// ...
};

12. Crediti
clean-code-javascript, tradotto originalmente da Felipe
Augusto
53

Potrebbero piacerti anche