Skip to content

Latest commit

 

History

History
979 lines (563 loc) · 49.2 KB

README-it.md

File metadata and controls

979 lines (563 loc) · 49.2 KB

中文版 | 日本語版 | 한국어 | English | Русский | Português

Linee guida di un progetto · PRs Welcome

Se sviluppare un nuovo progetto è per voi come rotolarsi in un campo erboso, il mantenimento è un potenziale oscuro incubo per qualcun altro. Ecco un elenco delle linee guida che abbiamo trovato, scritto e raccolto che (pensiamo), possano realmente ben funzionare con la maggior parte dei progetti qui a elsewhen. Se volete condividere una pratica ottimale, o pensate che qualcuna di queste linee guida debba essere rimossa, fatecelo sapere.


1. Git

Git

Alcune regole di Git

Ecco un insieme di regole da tenere a mente:

  • Eseguire il lavoro in un branch di funzionalità.

    Perchè:

    In questo modo tutto il lavoro viene fatto in isolamento su branch dedicato piuttosto che nel principale. Questo consente di sottomettere delle richieste pull multiple senza creare confusione. E' possibile iterare senza inquinare il branch master con codice potenzialmente instabile e/o non completato. maggiori informazioni...

  • Creare branch da develop

    Perchè:

    In questo modo ci si può assicurare che il codice in master possa essere quasi sempre compilato senza problemi, e che possa essere principalmente usato direttamente per i rilasci (potrebbe essere una esagerazione per alcuni progetti).

  • Mai eseguire push nei branch develop o master. Eseguire una richiesta pull

    Perchè:

    Notifica i membri della squadra che una funzionalità è stata completata. Consente anche una facile revisione tra i propri pari del codice e una discussione della funzionalità proposta sui forum dedicati.

  • Aggiornare il branch develop locale ed eseguire un rebase interattivo prima di proporre la propria funzionalità ed eseguire una richiesta pull.

    Perchè:

    L'azione di rebase integrerà nei branch richiesti (master o develop) i commit fatti localmente all'inizio della storicizzazione senza creare un merge commit (assumendo che non ci siano conflitti). Il risultato è una buona e pulita storicizzazione. maggiori informazioni ...

  • Risolvere conflitti potenziali durante l'azione di rebase e prima di eseguire una richiesta pull.

  • Eliminare i branch di funzionalità locali e remoti dopo l'integrazione.

    Perchè:

    Il non farlo sporcherà il proprio elenco di branch con branch morti. Assicura che si possa integrare il branch in (master o develop) una volta sola. I branch di funzionalità dovrebbero esistere solo se il lavoro è ancora in corso.

  • Prima di eseguire una richiesta pull, assicurarsi che il proprio branch di funzionalità venga compilato con successo e superi tutti i test (compresi quelli di stile di codice).

    Perchè:

    Si sta per aggiungere il proprio codice a un branch stabile. Se i test nel proprio branch di funzionalità falliscono, ci sarà un alta probabilità che la compilazione nel branch di destinazione fallirà anch'essa. Inoltre, occorre applicare un controllo di stile di codice prima di eseguire una richiesta pull. Aggiunge leggibilità e riduce le possibilità che correzioni di formattazione vengano mescolate con le vere modifiche.

  • Usare questo file .gitignore.

    Perchè:

    Ha già un elenco di file di sistema che non dovrebbero essere inviati assieme al proprio codice in un repository remoto. Inoltre esclude cartelle e file di impostazione per la maggior parte degli editor utilizzati, così come molte delle più comuni cartelle di dipendenze.

  • Proteggere i propri branch di develop e master.

    Perchè:

    Protegge i propri branch pronti per la produzione dal ricevere modifiche inattese e irreversibili, maggiori informazioni... Github, Bitbucket e GitLab

1.2 Flusso di lavoro di Git

Per la maggior parte delle ragioni sopra esposte usiamo il flusso di lavoro Feature-branch-workflow con Rebase Interattivo e alcuni elementi di Gitflow (denominazioni e avere un branch di sviluppo). I passi principali sono i seguenti:

  • Per un nuovo progetto, inizializzare un repository git nella directory di progetto. Per le funzionalità/modifiche successive questo passo dovrebbe essere ignorato.

    cd <directory di progetto>
    git init
  • Eseguire il checkout di un nuovo branch di funzionalità/risoluzione bug.

    git checkout -b <nome branch>
  • Eseguire le modifiche.

    git add <file1> <file2> ...
    git commit

    Perchè:

    git add <file1> <file2> ... - si dovrebbero aggiungere solo file che costituiscono una piccola e coerente modifica.

    git commit lancerà un editor che consente di separare il soggetto dal corpo.

    Si legga di più in merito nella sezione 1.3.

    Suggerimento:

    Si può invece usare git add -p, che potrebbe dare la possibilità di rivedere tutte le modifiche introdotte una ad una e decidere se includerle nel commit oppure no.

  • Sincronizzare con il repository remoto per ottenere modifiche che altrimenti si sarebbero perso.

    git checkout develop
    git pull

    Perchè:

    Fornisce la possibilità di gestire i conflitti sulla propria macchina mentre si esegue la successiva azione di rebase invece che creare una richiesta pull che contiene conflitti.

  • Aggiornare il proprio branch di funzionalità con le ultime modifiche da develop tramite rebase interattivo.

    git checkout <nome branch>
    git rebase -i --autosquash develop

    Perchè:

    Si può usare --autosquash per comprimere tutti i propri commit in un commit singolo. Nessuno vuole molti commit per una singola funzionalità nel branch di sviluppo. maggiori informazioni...

  • Se non si hanno conflitti saltare questo passo. Se si hanno conflitti, risolverli e continuate l'azione di rebase.

    git add <file1> <file2> ...
    git rebase --continue
  • Eseguire l'azione di push del proprio branch. L'azione di rebase modificherà la storicizzazione, quindi si dovrà usare -f per forzare le modifiche nel branch remoto. Se qualcun altro sta lavorando sul proprio branch, usare l'opzione meno distruttiva --force-with-lease.

    git push -f

    Perchè:

    Quando si esegue una azione di rebase, si sta modificando la storicizzazione del proprio branch di funzionalità. Come risultato, Git respingerà i normali git push. Dovrà invece essere usata l'opzione -f o --force flag. maggiori informazioni...

  • Eseguire una richiesta pull.

  • La richiesta pull verrà accettata, incorporata e chiusa da un revisore.

  • Rimuovere il proprio branch locale di funzionalità se completato.

    git branch -d <branchname>

    rimuovere tutti i rami che non sono più nel repository remoto

    git fetch -p && for branch in `git branch -vv --no-color | grep ': gone]' | awk '{print $1}'`; do git branch -D $branch; done

1.3 Scrivere messaggi di commit efficaci

Avere buone linee guida per la creazione di commit e osservarle rende molto più facile lavorare con Git e collaborare con altri. Ecco alcune regole di massima (sorgente):

  • Separare l'oggetto dal corpo con una riga vuota tra i due.

    Perchè:

    Git è in grado di considerare la prima riga del proprio messaggio di commit come sommario. In effetti se si esegue git shortlog invece che git log, si vedrà un lungo elenco di messaggi di commit, che contengono l'identificativo del commit e il solo sommario.

  • Limitare la riga dell'oggetto a 50 caratteri e la lunghezza della riga nel corpo a massimo 72 caratteri.

    Perchè:

    I commit dovrebbero essere più dettagliati e specifici possibile, non è il posto per essere prolissi. maggiori informazioni...

  • Maiuscole nella riga di oggetto.

  • Non terminare la riga dell'oggetto con un punto.

  • Usare il modo imperativo nella riga dell'oggetto.

    Perchè:

    Invece che scrivere messaggi che dicono cosa ha fatto chi ha eseguito il commit, è meglio considerare questi messaggi come istruzioni per quello che si andrà a fare dopo che il commit è stato applicato nel repository. maggiori informazioni...

  • Usare il corpo per spiegare cosa e perchè invece di come.

2. Documentazione

Documentazione

  • Usare questo modello per README.md. Si è liberi di aggiungere sezioni non trattate.
  • Per progetti con più di un repository, fornire collegamenti agli stessi nei rispettivi file README.md.
  • Mantenere aggiornato README.md mano a mano che il progetto evolve.
  • Commentare il proprio codice. Cercate di rendere il più chiaro possibile il proprio intendimento con ogni sezione principale.
  • Se esiste una discussione aperta su github o stackoverflow riguardo al codice o all'approccio che si sta usando, includere il collegamento nel proprio commento.
  • Non usare commenti come scusa per cattivo codice, mantenere il proprio codice pulito.
  • Non usare codice pulito come scusa per non commentarlo del tutto.
  • Mantenere i commenti rilevanti mano a mano che il proprio codice evolve.

3. Ambienti

Environments

  • Definire ambienti development (sviluppo), test (collaudo) e production (produzione) separati se serve.

    Perchè:

    Dati diversi, token, API, porte ecc... potrebbero essere necessari in ambienti diversi. Si potrebbe volere un ambiente di sviluppo (development) isolato che chiami delle "false" API che forniscono dati predeterminati, rendendo i test sia manuali che automatici molto più facili. Oppure si portrebbe voler abilitare Google Analytics solo in ambiente di produzione (production) e così via. maggiori informazioni...

  • Caricare le proprie configurazioni di sviluppo specifiche da variabili di ambiente e non aggiungerle mai alla base di codice come costanti, guardare questo esempio.

    Perchè:

    Si hanno token, password e altre preziose informazioni lì dentro. La propria configurazione dovrebbe essere correttamente separata dalle logiche interne dell'app come se la base di codice potesse essere resa pubblica in qualsiasi momento.

    Come:

    Usare file .env per conservare le proprie variabili e aggiungerli a .gitignore per escluderli. Eseguire un commit di un .env.esempio che serva come guida per gli sviluppatori. Per la produzione, si dovrebbero comunque impostare le proprie variabili nel modo standard. maggiori informazioni

  • E' raccomandato che si validino le variabili di ambiente prima che la propria app venga lanciata. Guardare questo esempio che usa joi per validare i valori passati.

    Perchè:

    Potrebbe risparmiare ad altri ore passate a risolvere problemi.

3.1 Ambienti di sviluppo consistenti:

  • Impostare la propria versione di node in engines in package.json.

    Perchè:

    Consente agli altri di sapere su quale versione di node il progetto lavora. maggiori informazioni...

  • Inoltre usare nvm e creare un file .nvmrc in radice del proprio progetto. Non dimenticare di citarlo nella documentazione.

    Perchè:

    Chiunque usi nvm può semplicemente usare nvm use per passare alla versione di node adatta. maggiori informazioni...

  • E' una buona idea impostare uno script di preinstallazione che verifichi le versioni di node e npm.

    Perchè:

    Alcune dipendenze potrebbero fallire quando installate da versioni più nuove di npm.

  • Usare immagini Docker se possibile.

    Perchè:

    Può fornire un ambiente consistente lungo tutto il flusso di lavoro. Senza tanto bisogno di armeggiare con dipendenze o configurazioni. maggiori informazioni...

  • Usare moduli locali invece di quelli installati globalmente.

    Perchè:

    Consente di condividere il proprio equipaggiamento con il collega invece di aspettarsi che li abbia installati globalmente sul proprio sistema.

3.2 Consistenza nella dipendenze:****

  • Assicurarsi che i membri della propria squadra abbiano le stesse esatte dipendenze.

    Perchè:

    Perchè si vuole che il codice si comporti come atteso e in modo identico in qualsiasi macchina di sviluppo maggiori informazioni...

    Come:

    Usare package-lock.json su npm@5 o superiori

    Non ho npm@5:

    Come alternativa si potrebbe usare Yarn e assicurarsi di citarlo nel README.md. I propri file di lock e package.json dovrebbero avere le stesse versioni dopo ogni aggiornamento di dipendenze. maggiori informazioni...

    Non mi piace il nome Yarn:

    Peccato. Per versioni più vecchie di npm, usare —save --save-exact quando si installa una nuova dipendenza e creare npm-shrinkwrap.json prima della pubblicazione. maggiori informazioni...

4. Dipendenze

Github

  • Tenere traccia dei propri pacchetti attualmente disponibili: es. npm ls --depth=0. maggiori informazioni...

  • Verificare se qualcuno dei propri pacchetti è diventato irrilevante o inutilizzato: depcheck. maggiori informazioni...

    Perchè:

    Si potrebbe includere una libreria inutilizzata nel proprio codice aumentando la dimensione del pacchetto di produzione. Cercare le dipendenze inutilizzate e sbarazzarsene.

  • Prima di usare una dipendenza, verificare le statistiche degli scaricamenti per verificare se sia ampiamente utilizzata dalla comunità: npm-stat. maggiori informazioni...

    Perchè:

    Più utilizzi in genere significa più collaboratori, il che in genere significa migliore manutenzione, e la conseguenza è che i bug vengono scoperti e corretti più velocemente.

  • Prima di usare una dipendenza, verificare se ha una frequenza di rilascio di versione buona, matura e con un ampio numero di manutentori: npm view async. maggiori informazioni...

    Perchè:

    Avere un gran numero di sottomissioni di codice da parte dei collaboratori non è così efficace se non ci sono manutentori che incorporano le correzioni e patch con sufficiente velocità.

  • Se è necessaria una dipendenza poco conosciuta, discuterne con la squadra prima di usarla.

  • Assicurarsi sempre che la propria app funzioni con le ultime versioni delle proprie dipendenze senza errori: npm outdated. maggiori informazioni...

    Perchè:

    Gli aggiornamenti delle dipendenze talvolta contengono modifiche che rompono l'app. Verificate sempre le loro note di rilascio quando vengono messi a disposizione gli aggiornamenti. Aggiornare le proprie dipendenze una ad una, il che facilita la risoluzione dei problemi se qualcosa dovesse andare storto. Usare uno strumento tipo npm-check-updates.

  • Verificare se il pacchetto abbia delle vulnerabilità di sicurezza note con Snyk as esempio.

5. Eseguire Test

Testing

  • Se necessario dotarsi di un ambiente in modalità test.

    Perchè:

    Sebbene qualche volta il test end-to-end in ambiente di produzione possa sembrare sufficiente, ci sono alcune eccezioni: un esempio è che si potrebbe non voler abilitare informazioni analitiche (in modalità produzione) e inquinare il cruscotto di qualcuno con dati di test. Un altro esempio è che la propria API potrebbero avere dei parametri di limite in produzione e bloccare le chiamate di test dopo un certo numero di richieste.

  • Posizionare i propri file di test vicino ai moduli testati usando la convenzione nominale *.test.js o *.spec.js, tipo nomeModulo.spec.js.

    Perchè:

    Non si vorrà rovistare all'interno di una struttura di directory per trovare una unità di test. maggiori informazioni...

  • Inserire i propri file di test addizionali in una cartella di test separata per evitare confusione.

    Perchè:

    Alcuni file di test non sono particolarmente legati a specifici file di implementazione. Si dovranno inserire in una cartella che sia facile da trovare per gli altri sviluppatori: __test__. Questo nome: __test__ è anche uno standard ora e viene scelto dalla maggior parte delle infrastrutture di test di Javascript.

  • Scrivere codice che si possa testare, evitare effetti collaterali, eliminare effetti collaterali, scrivere funzioni pure

    Perchè:

    Si vuole testare una logica di business come unità separate. Si deve "minimizzare l'impatto della casualità e dei processi non deterministici sulla affidabilità del proprio codice". maggiori informazioni...

    Una funzione pura è una funzione che ritorna sempre lo stesso risultato dato lo stesso input. Al contrario una funzione impura è quella che potrebbe avere effetti collaterali o dipende da condizioni esterne per produrre un valore. Il che la rende meno prevedibile. maggiori informazioni...

  • Usare un verificatore di tipo statico

    Perchè:

    Talvolta si potrebbe aver bisogno di un verificatore di tipo statico. Porta un certo grado di affidabilità al proprio codice. maggiori informazioni...

  • Eseguire i test localmente prima di eseguire una richiesta pull nel branch di sviluppo (develop).

    Perchè:

    Non si vuole essere quello che ha causato una fallita compilazione in un branch pronto per la produzione. Eseguire i propri test prima della propria azione di rebase e prima di inviare il proprio branch di funzionalità in un repository remoto.

  • Documentare i propri test includendo istruzioni nelle sezioni rilevanti del proprio file README.md.

    Perchè:

    E' una nota utile che si lascia a disposizione degli altri sviluppatori o esperti DevOps o chiunque sia abbastanza fortunato da lavorare al codice.

6. Struttura e Assegnazione dei Nomi

Structure and Naming

  • Organizzare i propri file attorno a funzionalità / pagine / componenti, non ruoli. Inoltre inserire i propri file di test vicino alla loro implementazione.

    Cattivo

    .
    ├── controllers
    |   ├── product.js
    |   └── user.js
    ├── models
    |   ├── product.js
    |   └── user.js
    

    Buono

    .****
    ├── product
    |   ├── index.js
    |   ├── product.js
    |   └── product.test.js
    ├── user
    |   ├── index.js
    |   ├── user.js
    |   └── user.test.js
    

    Perchè:

    Invece di un lungo elenco di file, si creeranno piccoli moduli che incapsulano una responsabilità compresi i test relativi e così via. E' molto più facile scorrerli e le cose si possono trovare a colpo d'occhio.

  • Inserire i propri file di test aggiuntivi in cartelle di test separate per evitare confusione.

    Perchè:

    Costituisce un risparmio di tempo per gli altri sviluppatori o esperti DevOps nella propria squadra.

  • Usare una cartella ./config e non creare file di configurazione diversi per i diversi ambienti.

    Perchè:

    Quando si divide un file di configurazione per diversi scopi (database, API eccetera) metterli in una cartella con un nome molto riconoscibile tipo config. Ricordarsi di non generare diversi file di configurazione per diversi ambienti. Non sarebbe possibile scalarli in modo pulito, mano a mano che sono creati più sviluppi per l'app e saranno necessari nuovi nomi di ambiente per ogni distribuzione. I valori da usare nei file di configurazione dovrebbero essere forniti da variabili di ambiente. maggiori informazioni...

  • Inserire i propri script in una cartella ./scripts . Compresi gli script bash e node.

    Perchè:

    E' molto probabile che si finisca per avere più di uno script, per la produzione, lo sviluppo, alimentazione di database, sincronizzazione di database eccetera.

  • Piazzare il risultato delle compilazioni in una cartella ./build. Aggiungere build/ a .gitignore.

    Perchè:

    Denominarla a piacimento, anche dist va bene, ma assicurarsi di mantenere consistenza con la propria squadra. Quello che finisce lì per la maggior parte è generato (assemblato, compilato, soggetto a transpiling), o ivi spostato. Anche i componenti della propria squadra dovrebbero essere in grado di generarlo, quindi non ha senso portare questi dati nel repository remoto. A meno che non lo si voglia specificatamente.

7. Stile di codice

Code style

7.1 Alcune linee guida sullo stile di codice

  • Usare una sintassi di secondo stadio (stage-2) o superiore (modern) di Javascript per i propri nuovi progetti. Per quelli vecchi restare consistenti con la sintassi esistente a meno che si intenda modernizzare il progetto.

    Perchè:

    E' una scelta personale. Qui usiamo programmi per il transpiling per trarre vantaggio dalla nuova sintassi, è probabile che stage-2 diventi alla fine parte delle specifiche con poche minori revisioni.

  • Includere verifiche di stile di codice nel proprio processo di compilazione.

    Perchè:

    Rompere la compilazione è un modo per imporre uno stile di codice. Evita di prenderlo sotto gamba. Farlo sia per il codice della parte client che per quella server. maggiori informazioni...

  • Usare ESLint - Pluggable JavaScript linter per imporre lo stile di codice.

    Perchè:

    Semplicemente noi preferiamo eslint, ma gli altri non sono obbligati. Supporta più regole e la possibilità di configurarle nonchè di aggiungerne di personalizzate.

  • Usiamo Airbnb JavaScript Style Guide per JavaScript, maggiori informazioni. Usare lo stile di codice javascript richiesto dal proprio progetto o dalla propria squadra.

  • Usiamo Flow type style check rules for ESLint quando usiamo FlowType.

    Perchè:

    Flow introduce poca sintassi, la quale deve seguire certe regole di stile di codice e possono essere verificate.

  • Usare .eslintignore per escludere file o cartelle dalle verifiche di stile di codice.

    Perchè:

    Non si deve inquinare il proprio codice con commenti eslint-disable ogni volta che si deve escludere un paio di file dalla verifica di stile.

  • Rimuovere tutti i propri commenti di disabilitazione di eslint prima di eseguire una richiesta pull.

    Perchè:

    E' normale disabilitare verifiche di stile mentre si lavora a un blocco di codice per focalizzarsi più sulla logica. Ricordarsi solo di rimuovere quei commenti eslint-disable e seguire le regole.

  • A seconda della dimensione dell'attività usare commenti //TODO: oppure aprire un ticket.

    Perchè:

    In questo modo si può ricordare agli altri e a se stessi di una piccola attività (tipo rifattorizzare una funzione o aggiornare un commento). Per attività più complesse usare //TODO(#3456) che viene imposto da una regola di lint e il numero è quello di un ticket aperto.

  • Commentare sempre il codice e mantenere i commenti in linea con le modifiche fino ad ora apportate. Eliminare i blocchi di codice commentati.

    Perchè:

    Il proprio codice dovrebbe essere il più leggibile possibile, ci si dovrebbe sbarazzare di ogni distrazione. Se si rifattorizza una funzione non commentare la vecchia ma eliminarla.

  • Evitare commenti, log e attribuzione di nominativi irrilevanti o divertenti.

    Perchè:

    Anche se il proprio processo di compilazione potrebbe (dovrebbe) sbarazzarsi di questi, talvolta il proprio codice sorgente potrebbe essere affidato ad altra ditta/cliente e potrebbero non trovarli così divertenti.

  • Rendere i propri nomi ricercabili con distinzioni significative ed evitare abbreviazioni di nomi. Per le funzioni usare nomi lunghi e descrittivi. Un nome di funzione dovrebbe essere un verbo o una frase verbale, e deve comunicare le proprie intenzioni.

    Perchè:

    Rende la lettura del codice sorgente più naturale.

  • Organizzare le proprie funzioni in un file a seconda della regole di discesa. Funzioni di alto livello dovrebbero essere in testa e quelle di basso livello più in basso.

    Perchè:

    Rende la lettura del codice sorgente più naturale.

7.2 Imporre standard di stile di codice

  • Usare un file .editorconfig che aiuta gli sviluppatori a definire e mantenere stili di codice consistente tra i diversi editor e IDE usati nel progetto.

    Perchè:

    Il progetto EditorConfig consiste in un file che descrive un formato per definire stili di codice e una collezione di plugin che consentono agli editor di leggere il file di formato e di aderire agli stili definiti. I file EditorConfig sono facilmente leggibili e funzionano bene con sistemi di controllo di versione.

  • Fare in modo di essere notificati dal proprio editor circa gli errori di stile di codice. Usare eslint-plugin-prettier e eslint-config-prettier con la propria configurazione esistente di ESLint. maggiori informazioni...

  • Considerare l'uso di Git hooks.

    Perchè:

    Accrescono notevolmente la produttività di uno sviluppatore. Fare modifiche, eseguire commit e portarle sugli ambienti di staging o produzione senza paura di rompere la compilazione. maggiori informazioni...

  • Usare Prettier con un hook prima del commit.

    Perchè:

    Sebbene prettier per se stesso possa essere molto potente, non è molto produttivo se eseguito semplicemente come una attività npm a se stante ogni volta per formattare il codice. Ecco dove lint-staged (e husky) entrano in gioco. Maggiori informazioni su come configurare lint-staged qui e husky qui.

8. Logging

Logging

  • Evitare log su console lato client in produzione.

    Perchè:

    Anche se il processo di compilazione possa (dovrebbe) sbarazzarsene, assicurarsi che il proprio verificatore di stile di codice avvisi rispetto a log su console lasciati nel codice.

  • Produrre dei log di produzione leggibili. Idealmente utilizzare librerie di logging in produzione (tipo winston o node-bunyan).

    Perchè:

    Rende l'identificazione dei problemi molto meno sgradevole con colorazioni, marcature temporali, registrazioni a un file oltre a quelle su console, anche la registrazione su file che ruota giornalmente. maggiori informazioni...

9. API

API

9.1 Progettazione API

Perchè:

Si cerca di imporre lo sviluppo di interfacce RESTful ben costruite, che possono essere consumate dai membri della squadra e i client in modo semplice e consistente.

Perchè:

La mancanza di consistenza e semplicità può accrescere enormemente i costi di integrazione e mantenimento. Ecco perchè la progettazione API è inclusa in questo documento.

  • Noi seguiamo per la maggior parte una progettazione orientata alle risorse. Ci sono tre fattori principali: risorse, collezioni e URL.

    • Una risorsa ha dati, viene annidata e ci sono metodi che operano su di essa.
    • Un gruppo di risorse è chiamata collezione.
    • Un URL identifica la posizione online di risorse o collezioni.

    Perchè:

    Questa è una progettazione ben nota agli sviluppatori (i principali consumatori della propria API). A parte la leggibilità e la facilità d'uso, consente di scrivere librerie generiche e connettori senza neppure sapere come sia fatta l'API stessa.

  • Usare il kebab-case per gli URL.

  • Usare il camelCase per parametri in query string o campi che rappresentano una risorsa.

  • Usare il kebab-case al plurale per nomi di risorse negli URL.

  • Usare sempre la forma plurale dei nomi per denominare un url che punta a una collezione: /utenti.

    Perchè:

    Fondamentalmente risulta meglio leggibile e rende gli URL consistenti. maggiori informazioni...

  • Nel codice sorgente convertire le forme plurali in variabili e le proprietà con un suffisso List.

    Perchè:

    La forma plurale va bene negli URL ma nel codice sorgente è troppo debole e incline a errori.

  • Usare sempre un concetto al singolare che parte da una collezione e finisce con un identificatore:

    /studenti/245743
    /aeroporti/kjfk
    
  • Evitare URL tipo questo:

    GET /blogs/:blogId/posts/:postId/sommario
    

    Perchè:

    Non punta a una risorsa ma a una proprietà. Si possono passare le proprietà come parametro per ridurre la propria risposta.

  • Escludere i verbi dai propri URL di risorse.

    Perchè:

    Se si usa un verbo per ogni operazione su una risorsa presto si avrà una enorme lista di URL e un modello non consistente che lo rende difficile da imparare per gli sviluppatori. Inoltre usiamo i verbi per altri scopi.

  • Usare verbi per non-risorse. In questo caso, la propria API non ritorna alcuna risorsa; viceversa si esegue una operazione e si ritorna il risultato. Queste non sono operazioni CRUD (creazione, lettura, aggiornamento e cancellazione):

    /traduci?testo=Ciao
    

    Perchè:

    Per le operazioni CRUD usiamo i metodi HTTP su URL su risorse o collezioni. I verbi di cui si sta parlando sono in realtà Controllers. In genere non ne sviluppano molti di questi. maggiori informazioni...

  • Il corpo della richiesta o il tipo di risposta è JSON pertanto seguire la forma camelCase per i nomi di proprietà per mantenere una consistenza.

    Perchè:

    Queste sono linee guida per un progetto Javascript, dove il linguaggio di programmazione per generare ed elaborare JSON si assume sia JavaScript.

  • Anche se una risorsa rappresenta un concetto al singolare, simile a una istanza di un oggetto o un record di database, non si dovrebbe usare il nome_tabella per un nome di risorsa e il nome_colonna per una proprietà.

    Perchè:

    L'intendimento è di esporre risorse, non i dettagli dello schema del proprio database.

  • Ancora una volta, usare solo nomi nei propri URL quando si denominano le proprie risorse non si cerchi di spiegarne la loro funzionalità.

    Perchè:

    Usare nomi solamente nei propri URL di risorsa, evitare URL che finiscono con /aggiungiNuovoUtente o /aggiornaUtente. Evitare inoltre di inviare operazioni su risorse come parametro.

  • Esprimere le funzionalità CRUD usando i metodi HTTP:

    Come:

    GET: Per ottenere la rappresentazione di una risorsa.

    POST: Per creare nuove risorse e sotto risorse.

    PUT: Per aggiornare risorse esistenti.

    PATCH: Per aggiornare risorse esistenti. Aggiorna solo i campi che sono stati forniti lasciando gli altri invariati.

    DELETE: Per eliminare risorse esistenti.

  • Per risorse annidate, usare la relazione tra loro nell'URL. Ad esempio usare id per collegare un dipendente a una ditta.

    Perchè:

    Questo è il modo naturale per rendere le risorse esplorabili.

    Come:

    GET /scuole/2/studenti , dovrebbe ottenere la lista di tutti gli studenti dalla scuola 2.

    GET /scuole/2/studenti/31, dovrebbe ottenere i dettagli dello studente 31, che appartiene alla scuola 2.

    DELETE /scuole/2/studenti/31 , dovrebbe eliminare lo studente 31, che appartiene alla scuola 2.

    PUT /scuole/2/studenti/31 , dovrebbe aggiornare le info sullo studente 31, usare PUT solo su URL che rappresentano risorse, non collezioni.

    POST /scuole , dovrebbe creare una nuova scuola e ritornare i dettagli della nuova scuola creata. Usare POST su URL che rappresentano una collezione.

  • Usare un semplice numero ordinale per una versione con un prefisso v (v1, v2). Spostare tutto alla sinistra nell'URL in modo che abbia l'ordine di identificazione maggiore:

    http://api.domain.com/v1/scuole/3/studenti
    

    Perchè:

    Quando le proprie API sono disponibili per terze parti, l'aggiornamento di API con alcune modifiche incompatibili con le versioni precedenti faranno sì che i prodotti o servizi che si basano su di esse non funzioneranno più. L'utilizzo di un controllo di versione nel proprio URL previene questa eventualità. maggiori informazioni...

  • I messaggi di risposta devono essere auto descrittivi. Un buon messaggio di errore in risposta potrebbe essere tipo questo:

    {
      "code": 1234,
      "message": "E' successo qualcosa di brutto",
      "description": "Maggiori dettagli"
    }

    oppure per errori di validazione:

    {
      "code": 2314,
      "message": "Validazione fallita",
      "errors": [
        {
          "code": 1233,
          "field": "email",
          "message": "Email non valida"
        },
        {
          "code": 1234,
          "field": "password",
          "message": "Nessuna password fornita"
        }
      ]
    }

    Perchè:

    Gli sviluppatori fanno affidamento su messaggi di errore ben concepiti quando stanno cercando di risolvere il problema dopo che l'applicazione che hanno costruito usando la vostra API viene utilizzata dai loro utenti.

  • _Nota: Mantenere i messaggi di eccezione di sicurezza più generici possibile. Ad esempio invece di 'password errata' utilizzare 'utente o password errati' in modo che l'utente non possa dedurre che il nome utente sia corretto e la sola password sia sbagliata.

  • Usare questi codici di stato per inviare i propri codici di risposta per descrivere che tutto ha funzionato, che l'app client ha fatto qualcosa di errato oppure l'API ha fatto qualcosa di errato.

    Quali sono:

    200 OK la risposta rappresenta un successo per le richieste GET, PUT o POST.

    201 Created quando viene creata una nuova istanza. Quando si crea una nuova istanza usando un metodo POST ritornare il codice di stato 201.

    204 No Content la risposta rappresenta un successo ma non c'è contenuto da inviare con la risposta. Usarlo quando una operazione di DELETE ha successo.

    304 Not Modified la risposta è per minimizzare la info da trasferire quando il ricevente ne ha già una rappresentazione in cache.

    400 Bad Request quando la richiesta non viene elaborata, come se il server non potesse capire cosa gli è stato chiesto.

    401 Unauthorized quando la richiesta è priva di credenziali valide e dovrebbe essere riproposta con le credenziali richieste.

    403 Forbidden il server ha compreso la richiesta ma si rifiuta di autorizzarla.

    404 Not Found la risorsa richiesta non esiste.

    500 Internal *Server* Error la richiesta è valida, ma il server non può esaudirla a causa di condizioni inaspettate.

    Perchè:

    La maggior parte dei fornitori di API usa un piccolo sottoinsieme di codici di stato HTTP. Ad esempio l'api di Google GData usa solo 10 codici di stato, Netflix ne usa 9 e Digg solo 8. Naturalmente queste risposte contengono un corpo con info aggiuntive. Ci sono oltre 70 codici di stato HTTP. In ogni caso la maggior parte degli sviluppatori non li ha tutti memorizzati. Quindi quando si scelgono codici di stato che non sono molto comuni si obbligheranno gli sviluppatori ad abbandonare lo sviluppo della propria applicazione per consultare wikipedia per scoprire cosa gli si sta cercando di dire. maggiori informazioni...

  • Fornire il numero totale di risorse nella risposta.

  • Accettare parametri di limit (limite) e offset (scostamento).

  • Il volume di dati che la risorsa espone dovrebbe essere tenuto in considerazione. Il consumatore dell'API non sempre necessita della piena rappresentazione di una risorsa. Usare un parametro di specifica di campi che riceve un elenco separato da virgola di campi che devono essere inclusi nella risposta:

GET /studente?campi=id,nome,eta,classe
  • Paginazioni, filtri, e ordinamento non devono essere supportati dall'inizio per tutte le risorse. Documentare quali risorse offrono filtro e ordinamento.

9.2 Sicurezza delle API

Ci sono alcune migliori pratiche consigliate

  • Non usare l'autenticazione basica a meno di avere una connessione sicura (HTTPS). I token di autenticazione non devono essere trasmessi nell'URL: GET /users/123?*token*=asdf....

    Perchè:

    I token o identificativo utente e password sono passati attraverso la rete in chiaro (codificato in base64, che è una codifica reversibile), lo schema di autenticazione basica non è sicuro. maggiori informazioni...

  • I token devono essere trasmessi usando l'intestazione di autorizzazione per ogni richiesta: Authorization: Bearer xxxxxx, Extra yyyyy.

  • I codici di autorizzazione dovrebbero avere vita breve.

  • Rifiutare qualsiasi richiesta non-TLS non rispondendo a qualunque richiesta HTTP per evitare scambio di dati non sicuro. Rispondere a queste richieste HTTP con 403 Forbidden.

  • Considerare l'adozione di limiti di utilizzo

    Perchè:

    Per proteggere le proprie API da minacce di bot che chiamano l'API migliaia di volte all'ora. Si consideri l'implementazione di limiti di utilizzo ai primi stadi dello sviluppo.

  • L'appropriata impostazione delle intestazioni HTTP può aiutare a isolare e mettere in sicurezza la propria applicazione web. maggiori informazioni...

  • La propria API dovrebbe convertire i dati ricevuti nella loro forma canonica o rifiutarli. Ritornare un 400 Bad Request con dettagli circa gli errori per dati non corretti o mancanti.

  • Tutti i dati scambiati con API REST devono essere validati dall'API.

  • Serializzare il proprio JSON.

    Perchè:

    Una preoccupazione chiave con i codificatori JSON è la prevenzione dell'esecuzione di codice Javascript arbitrario all'interno del browser oppure, se si sta usando node.js, sul server. E' vitale utilizzare un appropriato serializzatore JSON per codificare correttamente i dati forniti dall'utente per prevenire l'esecuzione di input fornito dall'utente nel browser.

  • Validare il Content-type e per lo più utilizzare l'intestazione Content-Type application/*json.

    Perchè:

    Ad esempio accettando il tipo mime application/x-www-form-urlencoded si consente a un attaccante di creare un form e scatenare una semplice richiesta POST. Il server non dovrebbe mai dare per scontato il Content-Type. La mancanza di una intestazione Content-Type oppure una non attesa dovrebbe risultare in un rifiuto del contenuto da parte del server con una risposta 4XX.

  • Verificare il "Progetto per la Lista delle Verifiche per la Sicurezza delle API". maggiori informazioni...

9.3 Documentazione delle API

  • Riempire la sezione API Reference in README.md template per l'API.
  • Descrivere i metodi di autenticazione dell'API con un esempio di codice.
  • Spiegare la struttura dell'URL (solo il percorso, non la radice dell'URL) includendo il tipo di richiesta (metodo).

Per ogni endpoint spiegare:

  • I parametri per l'URL, se esistono, specificarli in base al nome citato nella sezione URL:

    Richiesto: id=[intero]
    Opzionale: photo_id=[alfanumerico]
    
  • Se il tipo di richiesta è POST, fornire esempi funzionanti. Le regole per i parametri di URL si applicano anche qui. Separare le sezioni tra Richiesto e Opzionale.

  • Risposte di successo. Quale dovrebbe essere il codice di stato e ci sono anche dei dati da ritornare? Questo è utile quando a qualcuno occorre sapere cosa dovrebbero aspettarsi i propri callback:

    Code: 200
    Content: { id : 12 }
    
  • Risposte di errore, la maggior parte degli endpoint hanno molti modi per fallire. Da accesso non autorizzato a parametri errati ecc. Tutto ciò dovrebbe essere documentato qui. Può sembrare ripetitivo, ma aiuta ad evitare che vengano fatte delle assunzioni. Ad esempio

    {
      "code": 401,
      "message": "Autenticazione fallita",
      "description": "Nome utente o password errati"
    }
  • Usare strumenti di progettazione di API. Ce ne sono molti open source con buona documentazione tipo API Blueprint e Swagger.

Accessibilità

10.1 Mettere a punto metodi di accessibilità

Prendere le seguenti misure all'inizio del proprio progetto per assicurare che un livello di accessibilità sia intenzionalmente sostenuto:

Perchè:

Il contenuto Web è accessibile in modalità predefinita.Questo concetto viene compromesso quando si costruiscono funzionalità complesse. E' molto più facile ridurre questo impatto tenendo in considerazione l'accessibilità dall'inizio invece che reimplementare queste funzionalità successivamente.

  • Disporsi per eseguire revisioni regolari usando lighthouse accessibility o l'estensione di DevTools axe. Condividere un punteggio minimo in base alle proprie specifiche di progetto. Il punteggio per entrambi gli strumenti è basato su usare l'impatto di valutazione utente di axe.

    Nota: alcune importanti verifiche devono essere fatte manualmente, es. ordine logico delle tabulazioni. Gli strumenti qui sopra elencano questi test manuali/guidati assieme ai risultati automatizzati. Con axe si devono salvare i propri risultati automatizzati per vedere questi.

  • Installare un linter a11y:

    Perchè:

    Un linter verificherà automaticamente che un livello base di accessibilità sia raggiunto dal proprio progetto ed è relativamente facile da impostare.

  • Impostare e usare test a11y usando axe-core o simili.

  • Se si sta usando storybook, fare questo.

    Perchè:

    Includere verifiche a11y nei propri test aiuterà a catturare qualsiasi modifica che abbia impatto sull'accessibilità del propri progetti e il proprio punteggio di revisione.

  • Considerare l'uso di un sistema di progettazione accessibile tipo React Spectrum o Material Design.

    Perchè:

    Questi componenti sono altamente accessibili fuori dalla scatola.

10.2 Alcune regole di accessibilità di base da aggiungere al proprio progetto:

  • Assicurarsi che i nomi dei link siano accessibili. Usare aria-label per descrivere i collegamenti.

    Perchè:

    Elementi di collegamento inaccessibili pongono barriere all'accessibilità.

  • Assicurarsi che le liste siano strutturate correttamente e gli elementi della lista siano usati in modo semantico.

    Perchè:

    Le liste devono avere elementi sia genitori che figli affinchè siano valide. I lettori di schermo informano gli utenti quando trovano una lista e quanti elementi ci sono in una lista.

  • Assicurarsi che l'ordine delle intestazioni sia semanticamente corretto.

    Perchè:

    Le intestazioni veicolano la struttura della pagina. Quando applicate correttamente rendono la pagina più facile da navigare.

  • Assicurarsi che gli elementi di testo abbiano contrasto sufficiente rispetto allo sfondo della pagina.

    Perchè:

    Alcune persone con impedimenti alla vista soffrono di un basso contrasto, il che vuol dire che non riescono a distinguere aree molto chiare o molto scure. Tutto tende ad apparire quasi della stessa luninosità, il che rende difficile distinguere strutture, cornici, margini e dettagli. Un testo troppo vicino in luminosità allo sfondo può essere difficile da leggere.

  • Fornire testo alternativo per le immagini.

    Perchè:

    I lettori di schermo non hanno modo di tradurre un'immagine in parole che vengono lette all'utente, anche se l'immagine è composta solo da testo. Di conseguenza, è necessario che le immagini abbiano un testo alternativo (l'attributo alt) descrittivo in modo che gli utenti del lettore di schermo comprendano chiaramente i contenuti e lo scopo dell'immagine.

Altre regole di accessibilità possono essere trovate qui.

11. Gestione Licenza

Licensing

Assicurarsi di usare risorse per la quali si possiede il diritto di utilizzo. Se si utilizzano librerie, ricordarsi di cercare se licenza MIT, Apache o BSD ma se vengono modificate, verificare anche i dettagli della licenza. Le immagini o i video sottoposti a copyright potrebbero causare problemi legali.


Sorgenti: RisingStack Engineering, Mozilla Developer Network, Heroku Dev Center, Airbnb/javascript, Atlassian Git tutorials, Apigee, Wishtack

Icone di icons8