<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Blog di Mattia Natali]]></title><description><![CDATA[Il mio blog personale]]></description><link>https://www.mattianatali.it</link><generator>GatsbyJS</generator><lastBuildDate>Sat, 14 Nov 2026 21:00:44 GMT</lastBuildDate><item><title><![CDATA[Sei cose che avrei voluto sapere prima di diventare Engineering Manager]]></title><description><![CDATA[Ho sempre lavorato come individual contributor in un team. Vedo uno schema ricorrente: inizio come Engineer in un’azienda, ma prima o poi…]]></description><link>https://www.mattianatali.it/it/sei-cose-che-avrei-voluto-sapere-prima-di-diventare-engineering-manager/</link><guid isPermaLink="false">https://www.mattianatali.it/it/sei-cose-che-avrei-voluto-sapere-prima-di-diventare-engineering-manager/</guid><pubDate>Mon, 08 Apr 2024 08:50:08 GMT</pubDate><content:encoded>&lt;p&gt;Ho sempre lavorato come individual contributor in un team. Vedo uno schema ricorrente: inizio come Engineer in un’azienda, ma prima o poi finisco per guidare il team, prendere decisioni difficili che nessuno vuole prendere, assumermi la responsabilità del bene e del male, e le persone fuori dal team mi vedono come una persona di riferimento.&lt;/p&gt;
&lt;p&gt;Comincio a pensare: forse posso contribuire di più se gestisco persone e non solo codice. Invece di ricominciare da zero se cambio lavoro, perché non iniziare direttamente come Engineering Manager?&lt;/p&gt;
&lt;p&gt;Quindi eccomi qui: sono stato promosso Engineering Manager. Congratulazioni!&lt;/p&gt;
&lt;p&gt;Sono Engineering Manager da un po’ di tempo ormai, e voglio condividere qualcosa che avrei voluto sapere prima.&lt;/p&gt;
&lt;h2&gt;Avere ottime competenze tecniche e fiuto per gli affari non basta più&lt;/h2&gt;
&lt;p&gt;Penso che la mia più grande abilità sia imparare in fretta: se sei bravo in questo, puoi risolvere qualsiasi problema tecnico. Gli ingegneri sono molto fortunati da questo punto di vista: c’è abbondanza di documentazione su Internet. Puoi letteralmente imparare tutto senza spendere un centesimo, devi solo voler imparare: non devi supplicare nessuno per ottenere informazioni. Se lavori in buone aziende, anche i processi interni e la conoscenza sono aperti.&lt;/p&gt;
&lt;p&gt;Quindi puoi crescere senza dipendere troppo dalle persone. Almeno fino a Senior Software Engineer, poi devi affinare la tua capacità di influenzare per diventare Staff Software Engineer.&lt;/p&gt;
&lt;p&gt;Ma se sei sul percorso Manager, il tuo team è la tua risorsa più preziosa per crescere. Quindi dovresti “espandere la tua influenza” il prima possibile.&lt;/p&gt;
&lt;p&gt;L’ho imparato a mie spese durante la performance review. Ho passato un anno intero a mantenere il mio team coinvolto e a rispettare le scadenze nonostante fossimo sotto organico. Questo significa che ho contribuito anche come Individual Contributor.&lt;/p&gt;
&lt;p&gt;Ero felice della mia performance: sono un Engineering Manager che può essere un Individual Contributor quando l’azienda ne ha bisogno. Sto superando le aspettative, giusto?&lt;/p&gt;
&lt;p&gt;Ma il mio duro lavoro come individual contributor è valso quasi nulla durante la performance review. E sicuramente non mi ha aiutato nel mio percorso di carriera.&lt;/p&gt;
&lt;p&gt;Il giorno dopo ero piuttosto arrabbiato, ma ho imparato a non preoccuparmi troppo di qualcosa che non posso cambiare (le regole del gioco dell’azienda), è sempre meglio concentrarsi sulle cose che posso cambiare (i miei comportamenti).&lt;/p&gt;
&lt;p&gt;Quindi non essere come me: se sei un Manager, hai bisogno di un team, e possibilmente di più di uno, e più persone ti conoscono, meglio è.&lt;/p&gt;
&lt;h2&gt;Devi rinunciare alla cosa più gioiosa del lavoro&lt;/h2&gt;
&lt;p&gt;Se prima sei stato Software Engineer per diversi anni e sei sopravvissuto, probabilmente significa che ami programmare. Programmare è difficile e anche stressante, soprattutto quando hai scadenze strette.&lt;/p&gt;
&lt;p&gt;Tuttavia, la dopamina che ricevi dopo aver finito un compito, risolto un problema complesso o visto il tuo lavoro usato dai clienti non ha prezzo! Lo adoro, e adoro anche costruire cose. Più esperienza accumuli come Software Engineer, meno ti blocchi, quindi senti anche di poter ottenere &lt;strong&gt;qualsiasi cosa&lt;/strong&gt;. Questo aumenta molto l’autostima dell’Engineer.&lt;/p&gt;
&lt;p&gt;Tale gioia e felicità sono più difficili da trovare se sei un Manager.&lt;/p&gt;
&lt;p&gt;Ogni attività nel backlog dovrebbe essere svolta dai tuoi riporti. E i tuoi riporti sono esseri umani; gli esseri umani sono pigri per natura. Se sei fortunato, trovi ingegneri che combattono la pigrizia automatizzando le cose e facendo comunque le cose difficili perché gli piace. Ma di solito hai ingegneri che hanno ogni sorta di intoppi: passano tempo su qualcosa non richiesto nel task, hanno problemi personali, non sono convinti del task stesso, non seguono ciò che il team ha concordato, ecc.&lt;/p&gt;
&lt;p&gt;Quindi devi ottenere risultati attraverso le persone: hai sempre questo livello di indirezione che rende le cose più complicate. E questo è stressante; non avrai lo stesso livello di dopamina che ottieni come individual contributor, di sicuro.&lt;/p&gt;
&lt;p&gt;Ora sto cercando di riprogrammare il mio cervello per trovare gioia in cose a cui prima prestavo poca attenzione:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sono felice quando ho una riunione con alcuni punti d’azione concordati.&lt;/li&gt;
&lt;li&gt;Sono felice quando vedo lo sprint funzionare come previsto e i miei riporti trovare soluzioni autonomamente.&lt;/li&gt;
&lt;li&gt;Sono felice quando faccio gli 1:1 e sono contenti di come sta lavorando il team, nonostante l’ambiente intorno a noi non sia così buono.&lt;/li&gt;
&lt;li&gt;Sono felice quando vedo un neolaureato/riporto crescere e prendermi come mentore, riconoscendo il mio impegno.&lt;/li&gt;
&lt;li&gt;Sono felice quando vedo team/clienti diversi avere lo stesso contesto e lavorare insieme per costruire qualcosa di molto grande.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Come puoi vedere, ci sono molte opportunità di felicità qui. Ma devi sempre coinvolgere le persone, e a volte il risultato non è tangibile. Quindi devi praticare alcune tecniche di “mindfulness” per apprezzarlo.&lt;/p&gt;
&lt;p&gt;A volte ho davvero bisogno di parlare con me stesso: “Ehi! Hai un sacco di cose. So che sei arrabbiato perché hai passato 1 ora a spiegare una cosa banale a qualcun altro. Ma ora l’altro ne sa di più, e sarà più veloce la prossima volta. Goditi l’interesse composto nei prossimi giorni.”
Questo è ciò che faccio per godermi il mio percorso manageriale. Più ci sto dentro, meno ho bisogno di parlare con me stesso per sentire la gioia. Come ho detto, questo è necessario per riprogrammare il cervello e goderti il tuo nuovo lavoro.&lt;/p&gt;
&lt;p&gt;Sono sicuro che ci sono persone che lo sentono naturalmente. Ma se tu non lo fai, prova le tecniche di “mindfulness”.&lt;/p&gt;
&lt;h2&gt;Per avere successo hai bisogno delle persone&lt;/h2&gt;
&lt;p&gt;È molto allettante fare il task da soli, è certamente più facile: parlare con qualcuno, spiegare cosa fare, convincerlo che è la persona giusta per farlo, impegnarlo a farlo in modo tempestivo richiede molto tempo…
Quindi… Perché dovrei prendere quella strada invece di farlo da solo?
Perché non è scalabile, non puoi fare tutto da solo. Prima lo capisci, meno dolore provi.
L’ho imparato a mie spese: mi stavo lamentando con il mio product owner del fatto che non riuscivo a fare tutto da solo, le cose cominciavano a sfuggirmi di mano, mi ha interrotto bruscamente e ha detto: “hai un intero team a tua disposizione, fallo lavorare!“.&lt;/p&gt;
&lt;p&gt;Quello è stato il mio momento di svolta! Ero troppo concentrato su me stesso e non stavo sfruttando il mio team come avrei dovuto. Da quel giorno ho deciso di dedicare più sforzo agli altri che a me stesso. È stato facile? No, perché la tentazione di tornare alla vecchia cattiva abitudine era alta… Ma sapevo che non poteva funzionare nel vecchio modo.&lt;/p&gt;
&lt;p&gt;Alla fine sono riuscito a gestire il mio team efficacemente al massimo del suo potenziale. Poi abbiamo avuto un problema di sotto organico, ma almeno nessuno si è lamentato che stessi sottoutilizzando le mie risorse 😅.&lt;/p&gt;
&lt;h2&gt;Non esiste la tecnica migliore per gestire le persone&lt;/h2&gt;
&lt;p&gt;Gestire persone che creano software è completamente diverso dal creare da soli: scrivere software richiede esperienza, e questa esperienza che accumuli è ubiqua. Se scrivi buon codice TypeScript, probabilmente sarai in grado di scrivere buon codice anche in altri linguaggi. Le best practice e le tecniche di debugging sono ancora le stesse e rimarranno le stesse negli anni.&lt;/p&gt;
&lt;p&gt;Ma le persone sono una bestia completamente diversa; ogni persona è unica. Ciò che funziona con uno dei tuoi riporti può completamente allontanarne un altro. Fare mentoring a un junior è diverso dal fare mentoring a un senior.&lt;/p&gt;
&lt;p&gt;Se lavori in un ambiente internazionale, scoprirai presto che le tue capacità manageriali dovrebbero adattarsi a culture diverse.&lt;/p&gt;
&lt;p&gt;Per esempio, alle persone nordiche non piace lavorare se uno dei membri del team non è pienamente convinto. Alle persone dell’area mediterranea piace essere in un ambiente amichevole e sono più propense ad agire sulla base dell’amicizia piuttosto che dell’autorità del manager. Amano le chiacchiere. D’altra parte, alle persone tedesche non piacciono le chiacchiere. Gli europei sono più propensi a esprimere quando qualcosa non va, mentre gli americani tendono a dire che tutto va bene anche quando non è così. Le persone indiane spesso dicono di aver capito quello che hai detto, anche se non è vero.&lt;/p&gt;
&lt;p&gt;C’è un sacco di informazioni là fuori per imparare queste dinamiche multiculturali. Ti danno un buon punto di partenza, ma poi affronti la realtà dove capisci rapidamente che non funzionerà perché ogni persona è diversa e può differire completamente da ciò che hai imparato.&lt;/p&gt;
&lt;p&gt;Quindi qual è la soluzione? Resta semplicemente in silenzio.&lt;/p&gt;
&lt;p&gt;Ascolta i tuoi riporti negli 1:1. Puoi imparare come vedono il loro lavoro, come pensano. Guardali lavorare, osserva quando e come si arrabbiano, quando sono felici. Capisci cosa gli interessa e cosa no.
Poi puoi iniziare a parlare, assegnare loro compiti e coinvolgerli nel progetto in base a ciò che hai imparato.&lt;/p&gt;
&lt;p&gt;Questo è il modo migliore per ottenere risultati con loro. Cercherò di scrivere altri post su questo argomento perché so che c’è molto altro da dire qui.&lt;/p&gt;
&lt;h2&gt;Devi essere empatico per essere un buon manager&lt;/h2&gt;
&lt;p&gt;Essere empatico significa “mostrare la capacità di comprendere e condividere i sentimenti di un altro”, e credo che questo sia obbligatorio per essere un buon manager.&lt;/p&gt;
&lt;p&gt;Se alcuni dei miei ex colleghi stanno leggendo quello che ho appena scritto, probabilmente stanno ridendo di me: “Dai, sei la persona meno empatica che conosco!“. Sono sicuro che è quello che stanno pensando.
E hanno ragione! Ma non voglio negarlo, sono pienamente consapevole che i miei peggiori errori manageriali hanno tutti avuto la stessa radice: la mancanza di empatia.&lt;/p&gt;
&lt;p&gt;Scriverò degli errori che ho fatto così non dovrai farli tu per imparare.&lt;/p&gt;
&lt;p&gt;Cosa puoi fare se sei un blocco di ghiaccio senza emozioni come me? Puoi comunque imparare a essere empatico. Magari non proverai le stesse emozioni proprio quando il tuo interlocutore parla. Ma puoi chiederti: “Quali emozioni ha provato il tuo riporto quando ti ha parlato? Perché la persona si sente così? Se faccio X, può sentirsi meglio?“. Se non sei una persona empatica, è difficile esprimere empatia e ricavare direttamente dalla conversazione punti d’azione empatici, ma non devi per forza farlo sul momento! Puoi semplicemente digerire offline quello che hai sentito e poi tornare più tardi.&lt;/p&gt;
&lt;h2&gt;È tua responsabilità avere conversazioni difficili come manager&lt;/h2&gt;
&lt;p&gt;È tuo dovere avere conversazioni difficili che nessuno vuole avere.
Queste conversazioni possono riguardare la gestione di problemi di performance, il fornire feedback costruttivi o la risoluzione di conflitti all’interno del team.&lt;/p&gt;
&lt;p&gt;Sebbene queste conversazioni possano essere scomode, sono cruciali per la crescita e lo sviluppo sia degli individui che del team nel suo insieme. Affrontando questi problemi direttamente e onestamente, puoi creare un ambiente di lavoro più produttivo e armonioso, favorendo la crescita personale e professionale di tutti i coinvolti.&lt;/p&gt;
&lt;p&gt;Sfortunatamente, non puoi delegarle a qualcun altro. Quindi, se non ti senti a tuo agio nell’avere conversazioni difficili, devi lavorare per migliorare le tue capacità in questo ambito.&lt;/p&gt;
&lt;h2&gt;Conclusione&lt;/h2&gt;
&lt;p&gt;Spero che questo post ti abbia dato qualche spunto sulle sfide e le ricompense del passaggio da individual contributor a manager. Sebbene la transizione possa essere impegnativa, può anche essere incredibilmente gratificante. Concentrandoti sulla costruzione di relazioni solide con il tuo team, abbracciando nuovi modi di lavorare e sviluppando le tue capacità di leadership, puoi diventare un manager efficace e di successo.&lt;/p&gt;
&lt;p&gt;Se stai considerando di fare il salto, ti incoraggio a prenderti il tempo per riflettere sui tuoi punti di forza e di debolezza, e a considerare come puoi sfruttare le tue capacità ed esperienza per eccellere nel tuo nuovo ruolo.&lt;/p&gt;
&lt;p&gt;Ricorda, va bene commettere errori lungo il percorso, purché tu sia disposto a imparare da essi e a crescere come leader.&lt;/p&gt;
&lt;p&gt;Ci vediamo nel prossimo post!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come memorizzare i segreti nei repository pubblici]]></title><description><![CDATA[Prima o poi proviamo tutti questo dolore: stai lavorando duramente sul tuo repository git. Per un motivo qualsiasi cambi PC ma vuoi comunque…]]></description><link>https://www.mattianatali.it/it/come-memorizzare-i-segreti-nei-repository-pubblici/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-memorizzare-i-segreti-nei-repository-pubblici/</guid><pubDate>Sun, 27 Nov 2022 08:04:12 GMT</pubDate><content:encoded>&lt;p&gt;Prima o poi proviamo tutti questo dolore: stai lavorando duramente sul tuo repository git. Per un motivo qualsiasi cambi PC ma vuoi comunque continuare a lavorare al tuo progetto.
Quindi scarichi il repository usando &lt;code class=&quot;language-text&quot;&gt;git clone&lt;/code&gt;. Sei pronto a partire, ma poi ti blocchi perché non ricordi i segreti che avevi messo nel file &lt;code class=&quot;language-text&quot;&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Fortunatamente ora esiste una soluzione. Si chiama &lt;a href=&quot;https://www.agwa.name/projects/git-crypt/&quot;&gt;git-crypt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Git-crypt cifra i tuoi segreti prima di fare il push delle modifiche sul branch remoto, e li decifra quando scarichi da esso. Quindi, dopo averlo configurato, tutto è completamente trasparente. Ti dimenticherai di avere dei segreti nel repository!&lt;/p&gt;
&lt;h2&gt;Bootstrap&lt;/h2&gt;
&lt;p&gt;Per iniziare devi installarlo. Su Mac puoi eseguire il seguente comando nel terminale dopo aver installato il gestore di pacchetti &lt;a href=&quot;https://brew.sh/&quot;&gt;brew&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; git-crypt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Poi devi andare nel tuo repository pubblico dove vuoi mettere i segreti. E inizializzare &lt;code class=&quot;language-text&quot;&gt;git-crypt&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_REPO_PATH&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
git-crypt init&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Aggiungere i segreti&lt;/h2&gt;
&lt;p&gt;Ora devi aggiungere il file &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt; nella cartella principale del repository. In questo file dichiari i file e le cartelle che vuoi mantenere segreti.
Questo è un esempio di file &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Rendi segreto il file .env&lt;/span&gt;
.env &lt;span class=&quot;token assign-left variable&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;git-crypt &lt;span class=&quot;token assign-left variable&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;git-crypt

&lt;span class=&quot;token comment&quot;&gt;# Rendi segreti tutti i file che terminano con .key&lt;/span&gt;
*.key &lt;span class=&quot;token assign-left variable&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;git-crypt &lt;span class=&quot;token assign-left variable&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;git-crypt

&lt;span class=&quot;token comment&quot;&gt;# Rendi segreti tutti i file contenuti nella cartella secretdir&lt;/span&gt;
secretdir/** &lt;span class=&quot;token assign-left variable&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;git-crypt &lt;span class=&quot;token assign-left variable&quot;&gt;diff&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;git-crypt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Dopo&lt;/strong&gt; aver creato il file &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt;, puoi mettere i segreti nel posto che hai appena dichiarato. Se metti i file prima del &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt;, i tuoi segreti non verranno cifrati!
Prima di fare commit di qualsiasi cosa, puoi avere la conferma che i file verranno cifrati usando il comando &lt;code class=&quot;language-text&quot;&gt;git-crypt status&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Mostra se i file sono cifrati o meno&lt;/span&gt;
git-crypt status

&lt;span class=&quot;token comment&quot;&gt;# Mostra solo i file cifrati&lt;/span&gt;
git-crypt status &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Mostra solo i file non cifrati&lt;/span&gt;
git-crypt status &lt;span class=&quot;token parameter variable&quot;&gt;-u&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Se un file era già presente, non verrà cifrato. Devi eseguire il comando &lt;code class=&quot;language-text&quot;&gt;git-crypt status -f&lt;/code&gt;. Mi ripeto: se stai usando questo comando, significa che il file era già nel tuo repository in chiaro.
Quindi devi ruotare i segreti contenuti in quei file. Altrimenti, è molto facile per un attaccante vedere i segreti semplicemente guardando i commit precedenti.&lt;/p&gt;
&lt;p&gt;Ora puoi fare commit e push. Vedrai solo alcuni file binari cifrati nel tuo repository pubblico! Ma sarai in grado di vederli localmente.&lt;/p&gt;
&lt;h2&gt;Spostare la chiave simmetrica su un altro dispositivo&lt;/h2&gt;
&lt;p&gt;Fin qui tutto bene… Ma se cloni il repository altrove, scaricherai i file cifrati. Quindi come possiamo decifrare di nuovo i file?
Per rispondere a questa domanda dobbiamo svelare un po’ di magia. &lt;code class=&quot;language-text&quot;&gt;git-crypt&lt;/code&gt; decifra i file usando una chiave simmetrica.&lt;/p&gt;
&lt;p&gt;Durante l’inizializzazione con &lt;code class=&quot;language-text&quot;&gt;git-crypt init&lt;/code&gt;, ha creato la chiave simmetrica e l’ha messa in &lt;code class=&quot;language-text&quot;&gt;&amp;lt;YOUR_REPO_PATH&gt;/.git-crypt/keys/default&lt;/code&gt;.
Puoi esportarla facilmente con questo comando&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;git-crypt export-key /path/to/keyfile&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;con questa chiave puoi decifrare anche sugli altri tuoi dispositivi. Quindi tienila al sicuro.
Per decifrare un repository protetto con &lt;code class=&quot;language-text&quot;&gt;git-crypt&lt;/code&gt; puoi usare il comando&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;git-crypt unlock /path/to/keyfile&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Usare le chiavi GPG&lt;/h2&gt;
&lt;p&gt;So cosa stai pensando: “Dai… ho più di 30 repository. Non posso memorizzare e spostare le chiavi per ogni repo! Dovrebbe esserci un modo più semplice per gestirle.”. Esiste, davvero!&lt;/p&gt;
&lt;p&gt;Puoi usare la tua chiave GPG per sbloccare il tuo repository. Se non ne hai una, puoi seguire la &lt;a href=&quot;https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key&quot;&gt;guida di Github per creare la chiave GPG&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Tutto ciò che devi fare è permettere alla tua chiave GPG di decifrare il repository&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Da questo momento puoi sbloccare usando &amp;lt;YOUR_GPG_KEY&gt;&lt;/span&gt;
git-crypt add-gpg-user &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_GPG_KEY_ID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Per trovare la tua chiave GPG, puoi usare il seguente comando. Presumo che tu abbia già installato &lt;a href=&quot;https://gnupg.org/index.html&quot;&gt;GnuPG&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;gpg --list-secret-keys --keyid-format&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;long&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Poi, se cloni il tuo repository altrove, puoi sbloccarlo con&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;git-crypt unlock&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;git-crypt sarà abbastanza intelligente da cercare la chiave GPG sulla tua macchina. Se la trova, decifrerà tutto!&lt;/p&gt;
&lt;h3&gt;Come funziona la modalità GPG&lt;/h3&gt;
&lt;p&gt;… Ma come funziona? Presumo che non ti piaccia la magia.&lt;/p&gt;
&lt;p&gt;Quando scrivi&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;git-crypt add-gpg-user &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;YOUR_GPG_KEY_ID&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;git-crypt&lt;/code&gt; cifrerà la chiave simmetrica usando la tua chiave GPG pubblica, e farà il commit nel tuo repository nella cartella &lt;code class=&quot;language-text&quot;&gt;.git-crypt/keys/default/0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Poi, quando scrivi&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;git-crypt unlock&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;git-crypt&lt;/code&gt; troverà la tua chiave GPG sul tuo Mac, decifrerà la chiave simmetrica che ha salvato in &lt;code class=&quot;language-text&quot;&gt;.git-crypt/keys/default/0&lt;/code&gt; usando la tua chiave GPG privata. Infine, decifrerà i segreti usando la chiave simmetrica appena decifrata.&lt;/p&gt;
&lt;p&gt;Spero di esserti stato d’aiuto nel trovare un buon modo per gestire i segreti nei tuoi repository. Lo uso intensamente sia nei miei progetti hobbistici che al lavoro. Sono così soddisfatto che volevo condividerlo con voi.&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come costruire un sensore per la qualità dell'aria utilizzando un Raspberry Pi]]></title><description><![CDATA[Abito a Milano e mi chiedevo quanto l’aria fosse inquinata. Così ho iniziato a imparare come costruire un sensore per la qualità dell’aria e…]]></description><link>https://www.mattianatali.it/it/sensore-qualita-aria-raspberry-pi/</link><guid isPermaLink="false">https://www.mattianatali.it/it/sensore-qualita-aria-raspberry-pi/</guid><pubDate>Sun, 17 Jan 2021 16:40:20 GMT</pubDate><content:encoded>&lt;p&gt;Abito a Milano e mi chiedevo quanto l’aria fosse inquinata. Così ho iniziato a imparare come costruire un sensore per la qualità dell’aria e come integrarlo nel mio Home Assistant. Poi me ne sono pentito perché ho capito che la qualità dell’aria a Milano è terribile! Non è una notizia dell’ultima ora, ma è diverso avere il tuo sensore che analizza l’aria che stai respirando invece di sentire il telegiornale che dice: “Stop del traffico a Milano per abbassare le emissioni perché è sopra i limiti”. Poi ho spostato il sensore a Serina, un paesino sperduto tra le montagne, dove la qualità dell’aria è decisamente migliore!&lt;/p&gt;
&lt;p&gt;Ora voglio condividere ciò che ho imparato: come creare lo stesso sensore per la qualità dell’aria che ho costruito e come leggere questi dati in Home Assistant proprio in questo modo&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1006px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/434621f3a2d0d32f344dc6f671eb02c4/aabec/home-assistant-air-wifi.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 90.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAABYlAAAWJQFJUiTwAAACBUlEQVR42oVU2W6DMBDMRySEAMYcgYRgjhxS2///sO3MFiOEQvowslkvs7OHvYuiSBKTSpIkUpal1HUtl8tFmqaRLMskjmM920KapgprrfruTqeTFM0oNitkHAb5/v6RAStJ/yPkWVEU6k8oIRUam0GlUYUEiRjRwPZJnVdIfxKTa1I4SJrlcr1e5X6/S9/3GpFOnxSSgGRd1+k/c8q2OItBJKo7n8+zUtaTCrbSJRn9PWbC/NpJanNE+Yt0u92kbVuNvJU2f2bAcRzVl/8xuBKmqtCCwIlzTh240rmqKk1ti1QF5flK4aXTGrJurCEjMx2ufhzeEVI9weCPx0P3u+B4lPAYSBiGM46wBUGg4H59trYdDgfZ7/e6qkKmRBWpH1SookKmok3haMBmJzvxrrbk0jl8PZ/SoBEl9g7riLSZutYQA24BNugJPz/EDLYuxUzIEWHEeFEbX3TaDFa7aMRWTWdCppJsOJGwxJljR0n+4dbMhKxJ9K6LdAIKoOXNWBCaFblZEuYgpArLxswpMV1c/iiWChk4zFnIecSZmXyW0Ku4TPmFwj/xZD34dGH+HAGSL3z3uOMtzgY0wgEv2O9FKV1VSw+/gS8OcOLj4AkL3mHADytBe4mbYvmMQYFF81L8SFvN7nPEJr8Me31tOJjRlAqlc+8xp+JtnNnF3Hq7n2Vy/QIQLeqzul8bcgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - Qualità dell&amp;#39;aria e segnale WiFi&quot;
        title=&quot;&quot;
        src=&quot;/static/434621f3a2d0d32f344dc6f671eb02c4/aabec/home-assistant-air-wifi.png&quot;
        srcset=&quot;/static/434621f3a2d0d32f344dc6f671eb02c4/c6e3d/home-assistant-air-wifi.png 500w,
/static/434621f3a2d0d32f344dc6f671eb02c4/da8b6/home-assistant-air-wifi.png 1000w,
/static/434621f3a2d0d32f344dc6f671eb02c4/aabec/home-assistant-air-wifi.png 1006w&quot;
        sizes=&quot;(max-width: 1006px) 100vw, 1006px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;L’hardware necessario&lt;/h2&gt;
&lt;p&gt;Per raggiungere questo obiettivo abbiamo bisogno di:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 Raspberry Pi con relativo alimentatore e SD Card: uno sarà il sensore per la qualità dell’aria (&lt;em&gt;Rpi Sensor&lt;/em&gt;), l’altro sarà il nostro ricevitore con Home Assistant (&lt;em&gt;Rpi Hub&lt;/em&gt;). È inoltre necessario un dongle USB WiFi se il Raspberry Pi di qualità dell’aria non lo ha integrato.&lt;/li&gt;
&lt;li&gt;Il sensore per la qualità dell’aria SDS011: questo hardware viene comunemente fornito con il dongle USB, quindi è facile da collegare al Raspberry Pi.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Il software che utilizziamo&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mosquitto.org&quot;&gt;Mosquitto&lt;/a&gt;: broker di messaggi open source che implementa il protocollo MQTT. Il &lt;a href=&quot;https://en.wikipedia.org/wiki/MQTT&quot;&gt;protocollo MQTT&lt;/a&gt; è ampiamente utilizzato nei sistemi IoT perché funziona molto bene in condizioni estreme come un segnale WiFi debole e larghezza di banda WiFi molto limitata.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.home-assistant.io&quot;&gt;Home Assistant&lt;/a&gt;: sistema domotico open source.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Al momento sto utilizzando un Mac, quindi tutti i comandi che vedi funzioneranno su un terminale Mac o Linux. Se utilizzi Windows hai due opzioni:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/windows/wsl/install-win10&quot;&gt;Installa WSL&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Utilizza una macchina virtuale con Linux installato utilizzando &lt;a href=&quot;https://www.virtualbox.org&quot;&gt;VirtualBox&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Cosa impariamo&lt;/h2&gt;
&lt;p&gt;Qualcuno può dire: “Ehi! Sei un bugiardo! Non stai costruendo un sensore per la qualità dell’aria, l’hai appena comprato!“. Forse ha ragione, ma penso che il sensore sia solo la punta dell’iceberg. Abbiamo molto lavoro da fare per estrarre i dati dal sensore e renderli utili.&lt;/p&gt;
&lt;p&gt;L’architettura complessiva che vogliamo costruire è mostrata nella figura successiva&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1508px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8ba32478928ee8a8355c79289bcc52df/93af6/rasberrypi-air-architecture.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 81.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAIAAACZeshMAAAACXBIWXMAAAsTAAALEwEAmpwYAAABhklEQVR42o2TO1PCQBDH+RhWfgx6u3SOM3a0fg+ttFS70Dk26ex8ZBwYCjI60gRCYDIwEJKA0Ege5IXJxQ2rIY5J8Iqbvb397W7+eylFOYsQsvOqlBfh+76maaqqwj6dTufzufazPM/LhTGxqii2bQdBEIYhJOp0OpZlgd80TciIYaUEICREDHdFUYAEA2CoxjAM5IIjOCeTyS84o7KqrtdrMFqtFkVR5XK53W7DEZyQ9xvG0MVSawr3tmumYaxsGEa1WqVpWtd1rLxtO9xEPN/enOzv9QUe+0QYDRQPe8bbNBxH9B8alweVWq0ee//AhqGzLJsBY5O6aTZfuLRgadixneFwnAvL4zHHcTCGTPhVeHzrPiXwVrACtWPBCPGj6Pzw6PS48rH5pCBdOQ+GYaLa8vvi7uzq+oKpL+PLzyD4V2XXdcHwXFcQu0KvZztOfPS80Wi0A16tVrIsz2YzeNiSJA0HA7DwtePYsuFkQdswYdh5nhdFEaSCsomKRX/V5rWTqHB9AdUCjItoiqBIAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Architettura&quot;
        title=&quot;&quot;
        src=&quot;/static/8ba32478928ee8a8355c79289bcc52df/93af6/rasberrypi-air-architecture.png&quot;
        srcset=&quot;/static/8ba32478928ee8a8355c79289bcc52df/c6e3d/rasberrypi-air-architecture.png 500w,
/static/8ba32478928ee8a8355c79289bcc52df/da8b6/rasberrypi-air-architecture.png 1000w,
/static/8ba32478928ee8a8355c79289bcc52df/93af6/rasberrypi-air-architecture.png 1508w&quot;
        sizes=&quot;(max-width: 1508px) 100vw, 1508px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Quindi, attraverso questo tutorial, impareremo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Come creare un programma che estrae i dati dal sensore. Lo scriveremo in &lt;a href=&quot;https://golang.org&quot;&gt;Go&lt;/a&gt;. Per semplificare lo sviluppo impareremo come cross-compilare il binario per l’architettura ARM utilizzando il nostro PC / Mac che ha un’architettura diversa dal Raspberry Pi.&lt;/li&gt;
&lt;li&gt;Come collegare automaticamente il Raspberry Pi con il sensore al WiFi con il segnale più forte, come riconnettersi automaticamente in caso di interruzione.&lt;/li&gt;
&lt;li&gt;Come avviare automaticamente il programma Go in caso di problemi.&lt;/li&gt;
&lt;li&gt;Come passare i dati utilizzando il protocollo MQTT e come digerire quelli all’interno di &lt;a href=&quot;https://www.home-assistant.io&quot;&gt;Home Assistant&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ora che abbiamo in mente il quadro generale, iniziamo!&lt;/p&gt;
&lt;h2&gt;Prepariamo il Raspberry Pi con il sensore per la qualità dell’aria&lt;/h2&gt;
&lt;p&gt;Cominciamo con il Raspberry Pi con il sensore per la qualità dell’aria.
&lt;strong&gt;La prima cosa di cui abbiamo bisogno è &lt;a href=&quot;https://www.raspberrypi.org/documentation/installation/&quot;&gt;installare il sistema operativo Raspberry Pi Lite&lt;/a&gt;&lt;/strong&gt;. Abbiamo solo bisogno della lite perché usiamo solo il terminale e &lt;a href=&quot;https://www.raspberrypi.org/documentation/remote-access/ssh/README.md&quot;&gt;ci collegheremo usando SSH&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ora dobbiamo collegare la scheda SD al Raspberry, collegare la porta ethernet per collegarla alla nostra rete domestica per il primo setup e collegare il sensore SDS011 tramite USB. Il Raspberry Pi dovrebbe rilevarlo automaticamente.&lt;/p&gt;
&lt;p&gt;Diamo un’occhiata: connettiamoci a questo Raspberry Pi usando tramite SSH usando &lt;code class=&quot;language-text&quot;&gt;ssh pi@&amp;lt;RPI_SENSOR_IP&gt;&lt;/code&gt;, con password &lt;code class=&quot;language-text&quot;&gt;raspberry&lt;/code&gt;. Cambia “&amp;#x3C;RPI_SENSOR_IP&gt;” con l’indirizzo IP del sensore Raspberry Pi. Di solito trovo il suo indirizzo IP tramite il pannello di controllo del mio router, o semplicemente digito sul terminale &lt;code class=&quot;language-text&quot;&gt;ping raspberrypi.local&lt;/code&gt;. Dovresti trovare qualcosa di simile&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;PING raspberrypi.local &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;192.168&lt;/span&gt;.1.123&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;: &lt;span class=&quot;token number&quot;&gt;56&lt;/span&gt; data bytes
&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt; bytes from &lt;span class=&quot;token number&quot;&gt;192.168&lt;/span&gt;.1.123: &lt;span class=&quot;token assign-left variable&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;13.452&lt;/span&gt; ms
&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt; bytes from &lt;span class=&quot;token number&quot;&gt;192.168&lt;/span&gt;.1.123: &lt;span class=&quot;token assign-left variable&quot;&gt;icmp_seq&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;ttl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;17.451&lt;/span&gt; ms
--- raspberrypi.local &lt;span class=&quot;token function&quot;&gt;ping&lt;/span&gt; statistics ---
&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; packets transmitted, &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; packets received, &lt;span class=&quot;token number&quot;&gt;0.0&lt;/span&gt;% packet loss
round-trip min/avg/max/stddev &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13.452&lt;/span&gt;/15.451/17.451/2.000 ms&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;L’IP che vedi lì, è l’IP che stai cercando.&lt;/p&gt;
&lt;p&gt;Ora che siamo connessi tramite SSH, digitiamo &lt;code class=&quot;language-text&quot;&gt;lsusb&lt;/code&gt; per verificare che il Raspberry Pi veda il sensore&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pi@edge-rpi:~ $ lsusb
Bus 001 Device 005: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 001 Device 004: ID &lt;span class=&quot;token number&quot;&gt;2001&lt;/span&gt;:330d D-Link Corp.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp. SMC9512/9514 USB Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation &lt;span class=&quot;token number&quot;&gt;2.0&lt;/span&gt; root hub&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dovresti vedere alcuni nomi cinesi come “QinHeng Electronics HL-340”. Questo è il nostro sensore. Se digitiamo &lt;code class=&quot;language-text&quot;&gt;ls /dev/ttyUSB*&lt;/code&gt; dovremmo vedere &lt;code class=&quot;language-text&quot;&gt;/dev/ttyUSB0&lt;/code&gt; come risposta: questo è il nostro canale per comunicare con il sensore.&lt;/p&gt;
&lt;h3&gt;Compilare il programma Go per recuperare i dati&lt;/h3&gt;
&lt;p&gt;Ora dovremmo creare un programma che prenda i dati del sensore &lt;code class=&quot;language-text&quot;&gt;/dev/ttyUSB0&lt;/code&gt; creati e li pubblichi su un topic MQTT.&lt;/p&gt;
&lt;p&gt;Se non conosci MQTT, non preoccuparti: &lt;a href=&quot;https://en.wikipedia.org/wiki/MQTT&quot;&gt;Wikipedia spiega brevemente di cosa si tratta&lt;/a&gt;. Questa è la mia spiegazione: è un protocollo leggero che si basa sui &lt;em&gt;topics&lt;/em&gt;. Qualcuno pubblica qualcosa su un topic, come i dati del sensore per la qualità dell’aria. &lt;strong&gt;Qualcun altro può iscriversi a quel topic, in questo modo viene avvisato ogni volta che ci sono nuovi dati su quell’argomento&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ho creato questa applicazione per te in Go. &lt;a href=&quot;https://github.com/matitalatina/sds011-mqtt&quot;&gt;Puoi trovarlo su GitHub&lt;/a&gt;.
Dovremmo cambiare la configurazione che si trova in &lt;code class=&quot;language-text&quot;&gt;cmd/sensor/main.go&lt;/code&gt;, il file dovrebbe essere così&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;go&quot;&gt;&lt;pre class=&quot;language-go&quot;&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; main

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mattianatali.it/sds011-mqtt/internal/sensor&quot;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  c &lt;span class=&quot;token operator&quot;&gt;:=&lt;/span&gt; sensor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Config&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Topic&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;home/serina/edge-rpi/air-quality&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SensorPortPath&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/dev/ttyUSB0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    CycleMinutes&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    MqttBroker&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tcp://192.168.1.117:1883&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  sensor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Cambia &lt;code class=&quot;language-text&quot;&gt;Topic&lt;/code&gt; con una stringa a tua scelta. La mia convenzione è &lt;code class=&quot;language-text&quot;&gt;home/&amp;lt;HOME_IDENTIFIER&gt;/&amp;lt;DEVICE_IDENTIFIED&gt;/&amp;lt;DATA&gt;&lt;/code&gt;. Il topic è solo una stringa che fa riferimento a dove vogliamo pubblicare i dati e quindi dove vogliamo fare subscribe per recuperarli.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;SensorPortPath&lt;/code&gt;: dovrebbe essere lo stesso, è dove recuperiamo i dati del sensore.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;CycleMinutes&lt;/code&gt;: cambialo se 1 campione/minuto è troppo per te. Non puoi mettere meno di 1 minuto.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MqttBroker&lt;/code&gt;: Dovresti inserire l’indirizzo IP del Raspberry Pi dove abbiamo messo Mosquitto, il broker di messaggi che gestisce i nostri argomenti MQTT. Ti consiglio di utilizzare lo stesso Raspberry Pi dove installi anche Home Assistant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se sei curioso, puoi vedere l’implementazione in &lt;code class=&quot;language-text&quot;&gt;internal/sensor/main.go&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ora è il momento di compilarlo per il nostro Raspberry Pi!&lt;/strong&gt; Mi aspetto che tu abbia scaricato questo codice sorgente sul tuo Mac / PC e che tu abbia &lt;a href=&quot;https://golang.org/doc/installare&quot;&gt;Go installato&lt;/a&gt;. Quindi, dobbiamo sapere che tipo di architettura ha il tuo Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Lancia questo comando sul Raspberry Pi: &lt;code class=&quot;language-text&quot;&gt;cat /proc/cpuinfo&lt;/code&gt;
Dovresti vedere qualcosa di simile&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; /proc/cpuinfo

processor &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
model name &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; ARMv6-compatible processor &lt;span class=&quot;token function&quot;&gt;rev&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;v6l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
BogoMIPS &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;697.95&lt;/span&gt;
Features &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; half thumb fastmult vfp edsp &lt;span class=&quot;token function&quot;&gt;java&lt;/span&gt; tls
CPU implementer &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 0x41
CPU architecture: &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;
CPU variant &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 0x0
CPU part &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 0xb76
CPU revision &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;

Hardware &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; BCM2835
Revision &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 0002
Serial &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; 00000000cdea9a84
Model &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; Raspberry Pi Model B Rev &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il mio Raspberry ha “ARMv6”, quindi devo compilare per quel tipo. Se hai un Raspberry Pi 2 dovresti vedere “ARMv7”.
Ho creato un &lt;a href=&quot;https://github.com/matitalatina/sds011-mqtt/blob/main/Makefile&quot;&gt;Makefile&lt;/a&gt; per semplificare la cross-compilazione. Il makefile è molto comune su Linux, viene utilizzato per semplificare le attività comuni. Se non lo sai, ti suggerisco di leggere &lt;a href=&quot;https://learnxinyminutes.com/docs/make/&quot;&gt;Learn make in Y minutes&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Se hai &lt;code class=&quot;language-text&quot;&gt;ARMv6&lt;/code&gt;, digita semplicemente &lt;code class=&quot;language-text&quot;&gt;make build-arm6&lt;/code&gt; nella cartella in cui hai scaricato il mio &lt;a href=&quot;https://github.com/matitalatina/sds011-mqtt&quot;&gt;progetto GitHub&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Se hai &lt;code class=&quot;language-text&quot;&gt;ARMv7&lt;/code&gt;, digita &lt;code class=&quot;language-text&quot;&gt;make build-arm&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ora dovremmo avere un file binario situato in &lt;code class=&quot;language-text&quot;&gt;dist/pm-sensor&lt;/code&gt;. Dovremmo trasferire al nostro sensore sul Raspberry Pi. Useremo il comando &lt;a href=&quot;https://linuxize.com/post/how-to-use-scp-command-to-securely-transfer-files/&quot;&gt;scp&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;scp&lt;/span&gt; dist/pm-sensor pi@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RPI_SENSOR_IP&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;:&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Come al solito, cambia &lt;code class=&quot;language-text&quot;&gt;&amp;lt;RPI_SENSOR_IP&gt;&lt;/code&gt; con l’IP reale, ma lascia i due punti alla fine. Ciò significa che posizioneremo il &lt;code class=&quot;language-text&quot;&gt;pm-sensor&lt;/code&gt; nella cartella home del nostro utente &lt;code class=&quot;language-text&quot;&gt;pi&lt;/code&gt; all’interno del Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Ora possiamo entrare tramite SSH nel Raspberry Pi, dovremmo vedere il nostro nuovo file binario chiamato &lt;code class=&quot;language-text&quot;&gt;pm-sensor&lt;/code&gt;. Se proviamo a farlo partire, fallisce&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Aggiungi il permesso di esecuzione allo script&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x ./pm-sensor
&lt;span class=&quot;token comment&quot;&gt;# Fallo partire&lt;/span&gt;
./pm-sensor
&lt;span class=&quot;token comment&quot;&gt;# Questo è l&apos;output del programma&lt;/span&gt;
panic: Network Error &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; dial tcp &lt;span class=&quot;token number&quot;&gt;192.168&lt;/span&gt;.1.118:1883: connect: connection refused

goroutine &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;running&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;:
mattianatali.it/sds011-mqtt/internal/sensor.Start&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;0x12d3bcd, 0x20, 0x12cc844, 0xc, 0x1, 0x12d0ec0, 0x18&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 /Users/mattia/Repositories/sds011-mqtt/internal/sensor/main.go:28 +0x7e5
main.main&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 /Users/mattia/Repositories/sds011-mqtt/cmd/sensor/main.go:12 +0xac&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;si lamenta perché non riesce a connettersi al broker MQTT per pubblicare i dati del sensore. Ha ragione, non abbiamo preparato l’altro Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Ora lasciamo per un attimo il sensore, e lavoreremo sul Raspberry Pi che si trova all’interno della nostra casa, lo chiamiamo &lt;em&gt;Hub&lt;/em&gt; per semplicità.&lt;/p&gt;
&lt;h2&gt;Aggiungiamo mosquitto al Raspberry Pi hub&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Ora è il momento di configurare la parte “ricevitore” dell’architettura.&lt;/strong&gt; Quindi abbiamo bisogno dell’altro Raspberry Pi con installato un sistema operativo Raspberry pulito.&lt;/p&gt;
&lt;p&gt;Quindi &lt;a href=&quot;https://mosquitto.org/blog/2013/01/mosquitto-debian-repository/&quot;&gt;installiamo Mosquitto&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; apt-key &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt; mosquitto-repo.gpg.key
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; /etc/apt/sources.list.d/
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; http://repo.mosquitto.org/debian/mosquitto-buster.list
&lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; update
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; mosquitto&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;La nuova versione di Mosquitto &lt;a href=&quot;https://mosquitto.org/blog/2020/12/version-2-0-0-released/&quot;&gt;ha aggiunto l’autenticazione di default per ottime ragioni&lt;/a&gt;. Ho iniziato questo progetto quando Mosquitto non aveva l’autenticazione abilitato di default, quindi il mio script non lo supporta ancora. Per abilitare il supporto per gli utenti anonimi dovremmo aggiungere queste due righe nel file &lt;code class=&quot;language-text&quot;&gt;/etc/mosquitto/mosquitto.conf&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;listener 1883
allow_anonymous true&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il primo abilita i messaggi in arrivo da diversi host alla porta &lt;code class=&quot;language-text&quot;&gt;1883&lt;/code&gt;. Ciò è necessario perché il nostro sensore non è su questo Rpi Hub. Il secondo abilita gli utenti anonimi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ci assicuriamo che Mosquitto funzioni&lt;/strong&gt;, prenda il nuovo file di configurazione e &lt;strong&gt;si avvia all’avvio di Raspberry&lt;/strong&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Restart mosquitto to get the new config file&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl restart mosquitto

&lt;span class=&quot;token comment&quot;&gt;# Make sure mosquitto is enabled on startup&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; mosquitto&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Ora abbiamo il Broker MQTT attivo e funzionante!&lt;/strong&gt; Significa che il nostro sensore può inviare i dati a questo broker. Testiamo se il nostro sensore può inviare dati a questo broker.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Connetti al Raspberry Pi sensor e digita la password&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; pi@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RPI_SENSOR_IP&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Fai partire il programma per inviare i dati sulla qualità dell&apos;aria&lt;/span&gt;
./pm-sensor
&lt;span class=&quot;token comment&quot;&gt;# Questo è l&apos;output atteso (1 linea ogni minuto)&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T05:58:15Z,8.4,21
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T05:59:15Z,10.5,60.9
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T06:00:15Z,8.5,48.9
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T06:01:15Z,12.3,99.5
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T06:02:15Z,20.1,214.3
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T06:03:14Z,17.6,183.2
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T06:04:14Z,16.5,173.7
&lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T06:05:14Z,10.4,52.2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Questo è davvero un buon segno! Significa che possiamo recuperare i dati dal nostro sensore e possiamo inviarli al nostro broker MQTT che è installato sul nostro Hub Raspberry Pi!&lt;/p&gt;
&lt;p&gt;Per fare una contro prova, &lt;strong&gt;lasciamo il programma attivo&lt;/strong&gt; e facciamo subscribe sul topic a cui stiamo inviando i dati&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Ci colleghiamo a Raspberry Pi Hub&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; pi@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RPI_HUB_IP&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Facciamo subscribe al topic&lt;/span&gt;
mosquitto_sub &lt;span class=&quot;token parameter variable&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;home/serina/edge-rpi/air-quality&apos;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Dovremmo vedere un output come questo&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PM25&quot;&lt;/span&gt;:14.8,&lt;span class=&quot;token string&quot;&gt;&quot;PM10&quot;&lt;/span&gt;:18.6,&lt;span class=&quot;token string&quot;&gt;&quot;Timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2021-01-06T13:42:08.33019206Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PM25&quot;&lt;/span&gt;:14.5,&lt;span class=&quot;token string&quot;&gt;&quot;PM10&quot;&lt;/span&gt;:16.2,&lt;span class=&quot;token string&quot;&gt;&quot;Timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2021-01-06T13:43:08.192798603Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PM25&quot;&lt;/span&gt;:8.7,&lt;span class=&quot;token string&quot;&gt;&quot;PM10&quot;&lt;/span&gt;:9.7,&lt;span class=&quot;token string&quot;&gt;&quot;Timestamp&quot;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2021-01-06T13:44:08.057092356Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dovresti cambiare &lt;code class=&quot;language-text&quot;&gt;&amp;lt;RPI_HUB_IP&gt;&lt;/code&gt; con l’IP del tuo Hub e sostituire &lt;code class=&quot;language-text&quot;&gt;home/serina/edge-rpi/air-quality&lt;/code&gt; con l’argomento che hai inserito nella configurazione Go all’interno della proprietà &lt;code class=&quot;language-text&quot;&gt;Topic&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ora sappiamo cosa pubblica sull’argomento il nostro programma Go: invia un file JSON con tre proprietà:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“PM25”: contiene il PM 2.5 espresso in &lt;code class=&quot;language-text&quot;&gt;µg/m^3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;“PM10”: contiene il PM 10 espresso in &lt;code class=&quot;language-text&quot;&gt;µg/m^3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Timestamp&lt;/code&gt;: contiene l’ora in &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601&lt;/a&gt; in cui ha recuperato i dati.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Riepilogo&lt;/h3&gt;
&lt;p&gt;Congratulazioni! &lt;strong&gt;Ora abbiamo un sensore che recupera i dati sulla qualità dell’aria e li invia a un broker MQTT, ogni applicazione che desidera questi dati dovrebbe iscriversi al topic scelto&lt;/strong&gt; e il gioco è fatto! Abbiamo finito?&lt;/p&gt;
&lt;p&gt;Beh… Non esattamente.&lt;/p&gt;
&lt;p&gt;Vogliamo mettere il sensore all’esterno, quindi dovremmo usare il WiFi e staccare la porta Ethernet. Non vogliamo collegarci al sensore per avviare il programma. Se mettiamo il sensore lontano dal nostro router, il sensore dovrebbe essere in grado di ricollegarsi automaticamente ogni volta, dovrebbe fare lo stesso se riavviamo il router. Abbiamo tutti questi problemi da risolvere!&lt;/p&gt;
&lt;p&gt;Quindi potenziamo il nostro sensore per renderlo wireless e abbastanza intelligente da mantenere la connessione automaticamente.&lt;/p&gt;
&lt;h2&gt;Potenziamo il sensore!&lt;/h2&gt;
&lt;h3&gt;Avviare automaticamente il programma&lt;/h3&gt;
&lt;p&gt;Il programma non si avvia automaticamente. Dobbiamo connetterci tramite SSH e avviarlo con il comando &lt;code class=&quot;language-text&quot;&gt;./pm-sensor&lt;/code&gt;. Questo è molto frustrante.&lt;/p&gt;
&lt;p&gt;Per raggiungere questo obiettivo, &lt;strong&gt;utilizziamo &lt;a href=&quot;https://en.wikipedia.org/wiki/Systemd&quot;&gt;systemd&lt;/a&gt;&lt;/strong&gt;. Systemd è il gestore di sistema e servizi per Raspberry Pi. Hai notato che abbiamo già utilizzato systemd in questo tutorial? Quando abbiamo avviato mosquitto abbiamo scritto&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl restart mosquitto
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; mosquitto&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;usando il comando &lt;code class=&quot;language-text&quot;&gt;systemctl&lt;/code&gt; possiamo avviare / arrestare / riavviare i servizi su una macchina Linux. E possiamo anche avviare automaticamente un servizio all’avvio se scriviamo &lt;code class=&quot;language-text&quot;&gt;sudo systemctl enable &amp;lt;SERVICE&gt;&lt;/code&gt;. Quindi dobbiamo creare un servizio per il nostro programma di sensori pm.&lt;/p&gt;
&lt;p&gt;Fortunatamente è molto semplice: i servizi personalizzati sono archiviati nella cartella &lt;code class=&quot;language-text&quot;&gt;/etc/systemd/system&lt;/code&gt;. Quindi possiamo aggiungere il nuovo servizio, se aggiungiamo il file chiamato &lt;code class=&quot;language-text&quot;&gt;pm-sensor.service&lt;/code&gt; in quella cartella. Il contenuto di quel file è il seguente&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[Unit]
Description=PM Air Quality Sensor
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pi
Group=pi
ExecStart=/home/pi/pm-sensor
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Come puoi vedere, la dichiarazione del servizio è composta da tre sezioni: &lt;code class=&quot;language-text&quot;&gt;[Unit]&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;[Service]&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;[Install]&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nella sezione “[Unit]” mettiamo una piccola descrizione del nostro servizio e dichiariamo che vogliamo che la rete sia attiva e funzionante prima di avviarla.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;[Service]&lt;/code&gt; dichiara il tipo di servizio, il nome e il gruppo dell’utente che dovrebbe avviare lo script, dove si trova il programma e definiamo come dovrebbe comportarsi systemd in caso di panico del servizio. Vogliamo che il programma si riavvii sempre.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;[Install]&lt;/code&gt; definisce che questo servizio non necessita dell’interfaccia utente grafica.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Systemd è un argomento molto vasto e merita un libro completo su di esso. So che questa spiegazione è molto sommaria, ma è sufficiente per i nostri scopi. Ma so che sei molto curioso! Quindi, se vuoi scavare più a fondo, puoi digitare &lt;code class=&quot;language-text&quot;&gt;man systemd.unit&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;man systemd.service&lt;/code&gt; sulla tua macchina Linux. In Linux, se vuoi sapere qualcosa di più basta digitare &lt;code class=&quot;language-text&quot;&gt;man &amp;lt;PROGRAM_YOU_WANT_TO_LEARN_MORE&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ora che abbiamo creato il servizio, dobbiamo ricaricare la configurazione di systemd, avviare il programma e abilitarlo durante l’avvio.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl daemon-reload
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl start pm-sensor
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl &lt;span class=&quot;token builtin class-name&quot;&gt;enable&lt;/span&gt; pm-sensor&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Possiamo verificare se tutto è avviato correttamente con il seguente comando&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl status pm-sensor
&lt;span class=&quot;token comment&quot;&gt;# Questo è l&apos;output che abbiamo ottenuto&lt;/span&gt;
● pm-sensor.service - PM Air Quality Sensor
 Loaded: loaded &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;/etc/systemd/system/pm-sensor.service&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; enabled&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; vendor preset: enabled&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 Active: active &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;running&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; since Wed &lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06 &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;:01:26 GMT&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 1h 43min ago
 Main PID: &lt;span class=&quot;token number&quot;&gt;1182&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pm-sensor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 Tasks: &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;limit: &lt;span class=&quot;token number&quot;&gt;272&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 CGroup: /system.slice/pm-sensor.service
 └─1182 /home/pi/pm-sensor

Jan 06 &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;:36:01 edge-rpi pm-sensor&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1182&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;: &lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T16:36:01Z,21.2,33.9
Jan 06 &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;:37:00 edge-rpi pm-sensor&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1182&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;: &lt;span class=&quot;token number&quot;&gt;2021&lt;/span&gt;-01-06T16:37:00Z,61.1,303.4&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Se tutto è corretto, dovremmo vedere anche i log del nostro programma.&lt;/p&gt;
&lt;p&gt;Non è più necessario avviare manualmente il programma! Ma siamo ancora connessi tramite Ethernet, non possiamo mettere il nostro sensore fuori casa. Risolviamo il problema!&lt;/p&gt;
&lt;h3&gt;Aggiungere la connessione WiFi&lt;/h3&gt;
&lt;p&gt;Il modo migliore per aggiungere il WiFi al Raspberry Sensor è &lt;a href=&quot;https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md&quot;&gt;leggendo la documentazione ufficiale&lt;/a&gt;, è inutile fare copia-incolla. Ti suggerisco di aggiungere tutti i tuoi WiFi SSID che hai a casa. In questo modo, imposti il ​​sensore solo una volta. Se desideri spostarlo in un altro luogo, proverà a connettersi al punto di accesso WiFi più vicino.&lt;/p&gt;
&lt;p&gt;Tieni presente che ora &lt;strong&gt;l’indirizzo IP del sensore potrebbe essere cambiato&lt;/strong&gt;. Quindi ricordati di trovare il nuovo indirizzo.&lt;/p&gt;
&lt;h3&gt;Mantenere il WiFi persistente&lt;/h3&gt;
&lt;p&gt;Ora possiamo mettere il nostro sensore all’esterno! Si connette automaticamente al nostro WiFi e avvia il nostro programma che recupera il sensore. Dovremmo essere orgogliosi del nostro lavoro fatto fino ad ora… Ma ci rendiamo presto conto che c’è un problema. Ce ne rendiamo conto quando riavviamo il nostro router o mettiamo il nostro sensore troppo lontano da esso: &lt;strong&gt;il Raspberry Pi non prova a ricollegare il WiFi se perde la connessione&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Sistemiamo. Ho trovato un piccolo script sul web e l’ho adattato per i nostri scopi. Creiamo il file &lt;code class=&quot;language-text&quot;&gt;check-wifi.sh&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Connettiti al Raspberry Pi sensor&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ssh&lt;/span&gt; pi@&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RPI_SENSOR_IP&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Crea il nuovo file&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; check-wifi.sh

&lt;span class=&quot;token comment&quot;&gt;# Aggiungi il permesso di esecuzione su di esso&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x check-wifi.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;mettiamo questo contenuto al suo interno&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;##################################################################&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Impostazioni&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Quale interfaccia vuoi controllare&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;wlan&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;wlan0&apos;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Quale indirizzo vuoi eseguire il ping per vedere se l&apos;interfaccia di rete è attiva?&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;pingip&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;192.168.1.1&apos;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;##################################################################&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Performing Network check for &lt;span class=&quot;token variable&quot;&gt;$wlan&lt;/span&gt;&quot;&lt;/span&gt;
/bin/ping &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-I&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$wlan&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$pingip&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /dev/null &lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;2&lt;/span&gt;&gt;&lt;/span&gt; /dev/null
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$?&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-ge&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;then&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Network connection down! Attempting reconnection.&quot;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$wlan&lt;/span&gt; down
  &lt;span class=&quot;token function&quot;&gt;sleep&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ip&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$wlan&lt;/span&gt; up
&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Network is Okay&quot;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lo script dovrebbe essere autoesplicativo. Abbiamo due variabili in alto: &lt;code class=&quot;language-text&quot;&gt;wlan&lt;/code&gt; che non dovresti cambiare e &lt;code class=&quot;language-text&quot;&gt;pingip&lt;/code&gt; dove metti l’indirizzo IP del tuo router.&lt;/p&gt;
&lt;p&gt;Lo script tenta di eseguire il ping del router: se raggiunge il router, va tutto bene. Se non può farlo: disabilita il WiFi, quindi si riattiva. Dovrebbe attivare la riconnessione.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Abbiamo bisogno di qualcuno che chiami questo script ogni minuto… &lt;a href=&quot;https://en.wikipedia.org/wiki/Cron&quot;&gt;cron&lt;/a&gt; ci viene in soccorso!&lt;/strong&gt; Questo applicativo è uno standard per fare queste cose su Linux.&lt;/p&gt;
&lt;p&gt;Per aggiungere un lavoro pianificato che attivi il nostro script ogni minuto, dobbiamo scrivere &lt;code class=&quot;language-text&quot;&gt;crontab -e&lt;/code&gt; nel terminale. Si aprirà un editor di testo.
In quella pagina scrivi questa cosa&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;* * * * * /home/pi/check-wifi.sh&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Questa strana sintassi può spaventare ma è molto semplice. La prima parte, &lt;code class=&quot;language-text&quot;&gt;* * * * *&lt;/code&gt; indica quando lo script deve essere attivato. L’ultima parte si riferisce allo script che vogliamo lanciare.
L’orario programmato è sempre rappresentato da cinque valori. L’ordine di questi cambia il significato di quegli asterischi. Da sinistra a destra si riferiscono a:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minuto (0-59)&lt;/li&gt;
&lt;li&gt;Ora (0-23)&lt;/li&gt;
&lt;li&gt;Giorno del mese (1 - 31)&lt;/li&gt;
&lt;li&gt;Mese (1-12)&lt;/li&gt;
&lt;li&gt;Giorno della settimana (0 - 6): da domenica a sabato&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ma mettiamo &lt;code class=&quot;language-text&quot;&gt;*&lt;/code&gt;… Non numeri. Abbiamo aggiunto degli asterischi perché hano un significato speciale. &lt;code class=&quot;language-text&quot;&gt;*&lt;/code&gt; significa “qualsiasi”. Così abbiamo scritto: “Per favore Linux, esegui lo script &lt;code class=&quot;language-text&quot;&gt;/home/pi/check-wifi.sh&lt;/code&gt; ogni minuto di ogni ora di ogni giorno del mese di ogni giorno della settimana”. Linux è abbastanza intelligente da capire che dovrebbe attivare lo script ogni minuto d’ora in poi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ora abbiamo un sensore per la qualità dell’aria molto robusto!&lt;/strong&gt; Possiamo metterlo fuori casa e, qualunque cosa accada, dovrebbe mantenere sempre la connessione finché raggiunge il segnale WiFi del nostro router.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Usare &lt;code class=&quot;language-text&quot;&gt;mosquitto_sub&lt;/code&gt; è l’unico modo per vedere i dati dal sensore&lt;/strong&gt;. Questo va bene solo per scopi di debug, dovremmo avere un modo migliore per vedere quei dati. &lt;strong&gt;&lt;a href=&quot;https://www.home-assistant.io&quot;&gt;Home Assistant&lt;/a&gt; risolverà questo problema&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Aggiungi il sensore a Home Assistant&lt;/h2&gt;
&lt;h3&gt;Installa e impara Home Assistant&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.home-assistant.io&quot;&gt;Home Assistant&lt;/a&gt; è un ottimo software. Se sei un appassionato di tecnologia che ama automatizzare la casa, penso che tu l’abbia già installato.&lt;/p&gt;
&lt;p&gt;Se ancora non lo sai: puoi collegare dispositivi intelligenti e creare regole per automatizzare i tuoi dispositivi domotici. Puoi anche collegare i sensori per vedere facilmente i dati. In altre parole, se decidi di installarlo, Home Assistant può diventare il centro di controllo della tua casa.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Il nostro obiettivo qui è vedere i dati del sensore nell’Home Assistant.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Come primo passo, &lt;a href=&quot;https://www.home-assistant.io/docs/installation/&quot;&gt;dobbiamo installarlo&lt;/a&gt; sul Raspberry Pi hub.
Quindi, ti suggerisco di leggere il &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/&quot;&gt;manuale di configurazione&lt;/a&gt;. Home Assistant utilizza pesantemente i &lt;a href=&quot;https://learnxinyminutes.com/docs/yaml/&quot;&gt;file YAML&lt;/a&gt; per installare sensori personalizzati come il nostro.&lt;/p&gt;
&lt;p&gt;Forse stai pensando che Home Assistant sia eccessivo per vedere solo i dati del sensore. Ma penso che questo sia solo il punto di partenza: sono sicuro che alla fine avrai più di 20 dispositivi con un totale di 200 sensori collegati e dozzine di automazioni che orchestrano tutto!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3bd50a28adb9b11f32b98deccce3db5e/256cb/home-assistant-serina.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 57.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACCklEQVR42nWSS27bMBCGdQNbsiRLfIgSRT2s2vEmiAtEXbaLBjlA0Rv0/vu//1B2EQToYjAczszHeTBp5jPs6QLjTqj0CBUWVGGGGmj7iXqJ5512SG2H1GyyNy11G++y+70ZvyAxTQNTaxRvA7LfIyqnobWB0hrWtfB9T1tvYgzaroO1Fl3boROf2WJrpXjXIrG5Qvk+QP25YlzPKNURqq4ZaOFaj3ma0DQOhokRRKBjYu8cFtpeHqE0hDr6ElsblDeH6XLC7ek5Jiq1ARtWIUCBSIUC7L2HIuwn7V9VhTdW9srzV+pFgBJoSoUiL5BmKSoGCVRaeACsbeI5xtKn6et5bh7V0edoj9KyBFSsSACeycfjcYPxXlpTfNXwXtqReVVMlLjlfMZpWaDvD9UCDtMGPJoK8zJjXdfYXs0qawbeuLAfPK+UmY9IRTMfN5xpGCeE0LNiC6Pp8wH++oIkz3McDgdkWYb9fh/PudhliWcC3wn+zpl94/mV+oVQ0wX044mVqfvMFcZhwPXCb/MApWn6T8QuioJLaWFCQEmYpnjCreEcG245jHF20rLyQ/xCC0cQgR9hH4GeEGlTqjCcUydzYjVagMMYWw58sA9D1PM8E8j2/gfspCpCOtm2bJTaUHL64mjyAw75prM0i8tJCs7qc8sikiAbl29U36Xih68psatPObvdLsb+BS7JQLUCTpyMAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - My home&quot;
        title=&quot;&quot;
        src=&quot;/static/3bd50a28adb9b11f32b98deccce3db5e/9fabd/home-assistant-serina.png&quot;
        srcset=&quot;/static/3bd50a28adb9b11f32b98deccce3db5e/c6e3d/home-assistant-serina.png 500w,
/static/3bd50a28adb9b11f32b98deccce3db5e/da8b6/home-assistant-serina.png 1000w,
/static/3bd50a28adb9b11f32b98deccce3db5e/9fabd/home-assistant-serina.png 2000w,
/static/3bd50a28adb9b11f32b98deccce3db5e/256cb/home-assistant-serina.png 2558w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Quindi non è eccessivo, è solo il nostro punto di partenza, credimi 😊.&lt;/p&gt;
&lt;p&gt;Ora che abbiamo installato Home Assistant e imparato a conoscere &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/&quot;&gt;dove è installata la sua configurazione&lt;/a&gt;, &lt;strong&gt;è ora di aggiungere il nostro sensore&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Aggiungere l’integrazione MQTT&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Dobbiamo aggiungere l’integrazione MQTT a Home Assistant.&lt;/strong&gt; Andiamo sul portale Home Assistant, dovrebbe essere esposto sulla porta &lt;code class=&quot;language-text&quot;&gt;8123&lt;/code&gt;. Quindi apri il browser e digita l’URL &lt;code class=&quot;language-text&quot;&gt;http://&amp;lt;RPI_HUB_IP&gt;:8123&lt;/code&gt; dove &lt;code class=&quot;language-text&quot;&gt;&amp;lt;RPI_HUB_IP&gt;&lt;/code&gt; è l’IP del nostro Raspberry Pi Hub. Fai clic sull’icona a forma di ingranaggio (Configurazione) e fare clic su “Aggiungi integrazione”. Possiamo vedere un enorme elenco di integrazioni, siamo interessati a MQTT. Quindi cercalo e poi chiederà due campi obbligatori:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Broker: è necessario aggiungere l’IP dell’hub Raspberry Pi. È dove abbiamo installato Mosquitto, il nostro broker MQTT.&lt;/li&gt;
&lt;li&gt;Porta: è &lt;code class=&quot;language-text&quot;&gt;1883&lt;/code&gt;. Lo avevamo messo nella configurazione mosquitto.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fai clic su Invia e ora abbiamo collegato Home Assistant al nostro broker MQTT Mosquitto.&lt;/p&gt;
&lt;p&gt;Dovremmo vedere la nuovissima integrazione in Configurazione -&gt; Integrazioni. Facciamo clic su configura&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/905f02a3817e651ce0126eb3c8eb5b16/51519/home-assistant-mqtt-configure.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAACvklEQVR42k1TS24TQRCdCyT+zq+7Z7rnP+Px2LGjOIkhiRIIKEgEAiIIwYYNQkLssmHLAbgEd+B6j6p2HFiUWl3fV1WvHCkljDHQWsNog0hFUEqRRBB5A5FV/+z/vVsfRfFRpEgixHEMpygK65QmKeLUIIgFuAgLB0mW+/9W96AXApFJIaMYQoTW7qQpKZSA2/dx9GaKq7sjjAcekjSBtZETVxYUzEGB7yMMAgjSB+4Ij24+YnXxHE1V2kJOWZbWsSxKnJ2vsFo38P3AGiftBHvzOY1BWR9FSLq9BZppR//NqLjDbbv8OlmWWRQmL5BXLUJpbCtKKhT1BJOOEtJsRUgJKcgUNXReEUKFJEnQtu3DPG1CDh6HAkNShJqQ6AgB6UZxhn5SoxfnGKtNy4HJ4BJ6Scn5z6hymns47kF4A7sgx3XHWB+e4fLkFXK3Qq4mKKjAeSrxolR4W0k8KxQ8mluhY5w2GTyyM5DA96DyDunJJ6jjDwgkbdn1XKz3T3H99BbLaoVp1uFYhrikJF8XKb4tU7xvNQJCVdCiHs9bFDR3RhdSwnJ9g8PbH1hevKPlUsvcv+uNaSY+qo6WoHzUwocfG8z2D9CRRGmGMAyQGI1ytkQ7X0JzQi6Sp9hfdLTlfNMyz4K3J3SCmlq61gFc2mAUaxTtDPVsQVxLNpxj+vCspbIzlJKEeGjKBirJrc5hpzDSEGRQJAkhDplzVCDkZVgy06Jobruhtgl460pJm5j/gtBLsTkIJ6g6SwlN6GISRsutsI5PSiexLaCJ/N9fLmnDPkajETzPs++g38Ogt4vB7g69O0TsZmKhbjm1vQquVtUF6rqyJNaU/PPVAWbTlnQN8jzfJBwOMWRqmZKol8J58vrWBjMp2Und36gtQqdX1bW9W+ZmoAyaCZGdhG0jQtcXGrt3vzH8+Qe9L7/wF15VhgxQchoQAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - MQTT configure&quot;
        title=&quot;&quot;
        src=&quot;/static/905f02a3817e651ce0126eb3c8eb5b16/9fabd/home-assistant-mqtt-configure.png&quot;
        srcset=&quot;/static/905f02a3817e651ce0126eb3c8eb5b16/c6e3d/home-assistant-mqtt-configure.png 500w,
/static/905f02a3817e651ce0126eb3c8eb5b16/da8b6/home-assistant-mqtt-configure.png 1000w,
/static/905f02a3817e651ce0126eb3c8eb5b16/9fabd/home-assistant-mqtt-configure.png 2000w,
/static/905f02a3817e651ce0126eb3c8eb5b16/51519/home-assistant-mqtt-configure.png 2492w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;e poi possiamo fare subscribe del nostro topic MQTT, solo per verificare se Home Assistant può vedere i nostri dati.&lt;/p&gt;
&lt;p&gt;Nella sezione “Subscribe topic”, inserisci il nostro topic MQTT, fai clic su “Start listening” e attendi almeno 1 minuto. L’attesa dipende dalla configurazione impostata sul nostro programma Go. Se non modifichi il mio valore, dovrebbe pubblicare un valore al minuto.&lt;/p&gt;
&lt;p&gt;Se vedi i dati come la figura sotto, hai collegato con successo Home Assistant al nostro Broker MQTT!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/38e4e345ce21697946cd27fc488c2c86/0d413/home-assistant-mqtt-test.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAABXklEQVR42o2TzVKDQBCE8wjBQGTZ/x8WOFjFxSo9efEBPPn+b9LObEUrygZz6IJUlo/unuEwDAOUUuDrtfq+JwkIITb/7emQUkLTND86Ho/oug7LPBd57wucwX/Vtm05f/38IYSwAfJBFTP0OENbByVlSXEtrTXO5/MWOI5jFeh8gHUe2pjipr/X4a3IM8VlZXrhQI4CyZDkfw65yBowxghHcY21CNbg1Ur6bWEvcs7VgZL62QDbrjibpgwfEyat8Gxo8trAkDN2Z6iKu4DNpcNHbUtPHWnVAlkNEHRWXsSxOcldDhk4zQtyzoi0BW9DCy36zWCqQ6l1yAd5/ywpO4sX6k/y+lDUf9dGUy+3gJ6K5/JlSNApw9A9d7cL7KcnPFSAvDLLsoDXKsVQorP4Q9gFxjz/HgrpdDphpP7WdcVE02ZIoDVieHFMvd8Evn981r+U73hlRWy5ZzFob8pfrNVnsiTpkxEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - MQTT test&quot;
        title=&quot;&quot;
        src=&quot;/static/38e4e345ce21697946cd27fc488c2c86/9fabd/home-assistant-mqtt-test.png&quot;
        srcset=&quot;/static/38e4e345ce21697946cd27fc488c2c86/c6e3d/home-assistant-mqtt-test.png 500w,
/static/38e4e345ce21697946cd27fc488c2c86/da8b6/home-assistant-mqtt-test.png 1000w,
/static/38e4e345ce21697946cd27fc488c2c86/9fabd/home-assistant-mqtt-test.png 2000w,
/static/38e4e345ce21697946cd27fc488c2c86/0d413/home-assistant-mqtt-test.png 2486w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Aggiungere i sensori di qualità dell’aria tramite la piattaforma MQTT&lt;/h3&gt;
&lt;p&gt;Sappiamo che i valori sono pubblicati su un argomento MQTT (il mio è &lt;code class=&quot;language-text&quot;&gt;home/serina/edge-rpi/air-quality&lt;/code&gt;). Dovremmo creare due sensori che fanno subscribe sul topic ed estraggono i dati. Questi sensori lo saranno&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Qualità dell’aria PM 10.&lt;/li&gt;
&lt;li&gt;Qualità dell’aria PM 2.5.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Per raggiungere questo obiettivo, modifichiamo il file &lt;code class=&quot;language-text&quot;&gt;configuration.yaml&lt;/code&gt; di Home Assistant. Dobbiamo aggiungere questi due sensori all’interno della sezione &lt;code class=&quot;language-text&quot;&gt;sensor:&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;sensor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mqtt
    &lt;span class=&quot;token key atrule&quot;&gt;state_topic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;home/serina/edge-rpi/air-quality&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;unit_of_measurement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;μg/m³&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mdi:weather-fog&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;value_template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{{value_json.PM10 | float}}&apos;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Air Quality PM 10&apos;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;unique_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rpi-edge:air-quality-pm-10&apos;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; mqtt
    &lt;span class=&quot;token key atrule&quot;&gt;state_topic&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;home/serina/edge-rpi/air-quality&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;unit_of_measurement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;μg/m³&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;icon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;mdi:weather-fog&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;value_template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;{{value_json.PM25 | float}}&apos;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Air Quality PM 2.5&apos;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;unique_id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rpi-edge:air-quality-pm-2.5&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Fortunatamente, il file YAML è molto leggibile. Stiamo utilizzando la &lt;a href=&quot;https://www.home-assistant.io/integrations/sensor.mqtt/&quot;&gt;piattaforma sensor MQTT&lt;/a&gt;. Riavvia Home Assistant.&lt;/p&gt;
&lt;p&gt;Dovresti cambiare &lt;code class=&quot;language-text&quot;&gt;state_topic&lt;/code&gt; con il tuo. Puoi anche cambiare &lt;code class=&quot;language-text&quot;&gt;unique_id&lt;/code&gt; con qualsiasi valore, basta che sia univoco.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;value_template&lt;/code&gt; è il campo dove estraiamo il valore da JSON nell’argomento con la parola chiave &lt;code class=&quot;language-text&quot;&gt;value_json&lt;/code&gt; e poi prendiamo i valori interessanti &lt;code class=&quot;language-text&quot;&gt;PM10&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;PM25&lt;/code&gt;. Infine, diciamo che siamo interessati a un valore di tipo &lt;code class=&quot;language-text&quot;&gt;float&lt;/code&gt;, ossia con la virgola. Tutta questa roba è circondata da &lt;code class=&quot;language-text&quot;&gt;{{}}&lt;/code&gt;: quando vedi questa sintassi significa che stiamo sfruttando il &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/templating/&quot;&gt;motore di templating&lt;/a&gt; che sfrutta &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/templating/&quot;&gt;Jinja2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Se vuoi cambiare l’icona del sensore, di solito &lt;a href=&quot;https://materialdesignicons.com&quot;&gt;uso questo sito&lt;/a&gt;. Ad esempio, cerco
per una parola chiave, &lt;code class=&quot;language-text&quot;&gt;fog&lt;/code&gt;, e infine passo il mouse sull’icona scelta. Dovresti anteporre al nome che appare con &lt;code class=&quot;language-text&quot;&gt;mdi:&lt;/code&gt;. Nel nostro esempio è &lt;code class=&quot;language-text&quot;&gt;mdi:weather-fog&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c8e085750117893e626a62a54d04c294/051b6/material-icon-fog.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 70.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAACr0lEQVR42n1TSWsUQRgd8O/4Czwo/oScvHlTIhERCWgISMAIEq8BEReMK0a9i3gYYlCCEicLjpNMZunpvauq1+qe/flVj5lMDPjB61q66tX7tsKZpxznVzjOrgicey7wo8YQ+Qyux8AYg+d5YATvHzgE2zbRatbR0prQNA2WZaFgej4s7sM2PNRrOjTdgGGMoNPcMnSYdMEyDTiOA9d1icjBIBH4XAmxUIyxVg0gQx9C+CiEvkAYCHi2DZsumeaIrNlsEiE9QKNJpI1GA8ViEV/W1rD+bQOrOx42Gxw1EqI7DL4QRChQUB/h++CWkbuWJAm63S7a7fYYnU4nH5WCLEvR69A8pTO038tiRIGfk40IOQcPQ2T1fejVPQRhBGWDwQD9fn8M9YgyTdNR2jOhswS9ISC7A8g0heIZEwoiDIwWnN0SyXehmxRsgkGwVSgIKp7K5uYXcer0Rcyu/ATrAFX6RDIjMn7kMvcDpIIhqf7O5UtbR2xqkDQnERgOh7liZVu7ZSy/+IjNOv/rSZ/CkYHzCUJGiwHF5fvqK3xdXgQezWFw/zKwvY7RrT7+Zyq+xwgV4jjG/K2buDI9TXUoENGBkJIVxwkiiqv6H0URQgqPII9C2lNrpVwl7RghJ7RTiZDrcAN+QsGhywqH88kwnFDokyLOAlgtQeDQGy6MppePjX2Lip5DSpmrjOOR2jAIIROZQ63HhIzR4TTCRrGMu9feYmn2Pe7deIc7M2+wMP0aV6ce4PHSp7zNSqUStna2US6XYdG608uQddL8MTFZ2Eqh53JoBzZadQdazUHzwEKjahKOFGZUHkNVd3GKyq6GX6UGDioGdRjDiMefTEqEjNKfUidIiqdMKRkRuSWT/EHVJX7goO5XUDdt3L70EjNTD3H9whN8eLaOREbU6y7+AJNCBgf8JdIkAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Material Design Icons&quot;
        title=&quot;&quot;
        src=&quot;/static/c8e085750117893e626a62a54d04c294/9fabd/material-icon-fog.png&quot;
        srcset=&quot;/static/c8e085750117893e626a62a54d04c294/c6e3d/material-icon-fog.png 500w,
/static/c8e085750117893e626a62a54d04c294/da8b6/material-icon-fog.png 1000w,
/static/c8e085750117893e626a62a54d04c294/9fabd/material-icon-fog.png 2000w,
/static/c8e085750117893e626a62a54d04c294/051b6/material-icon-fog.png 2510w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Aggiungere i sensori all’interfaccia utente di Home Assistant&lt;/h2&gt;
&lt;p&gt;Ora dovremmo avere due nuove entità che mostrano la qualità dell’aria. Per vederli, dovremmo andare su configurazione -&gt; entità e cercare “Qualità dell’aria”&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2720db67002dc217bd380ad03cbcd918/f0b95/home-assistant-entity-page.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 62.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABWklEQVR42p2STU/DMAyG+yOAtU2cNE3atN0nEmgTiAvijpi4c+PK/z+92NnGhpgQ9PAoies8jpNmeZ7DGAOtNSZKQfFYKJ1iMcY0OueYCrkLqOuAxhqoynEuQRt7hAhZ13Vo2xaL5RKbIcLz5ql3vLH+hmd0E/HQerx4hUVdYZivEK7XMItbqNkNKt6bhRAQvAfx4jkQtpy8dbtTy7e2adLcWgtrCJ6Lr6PHW3WJhtcVFyI+mSD5mVTfteRgeD5rAuZGQ3H7IkkFGZFKTPKJ540uYfaiU7K+749t+RqhjVAsOgjlOgS7j0meyAu+a32GdEIxy+JQ5TThXOw3MqlKPDFMKS+8R/1R8ENotELOz3/BrKjEQAodU2s1SppRO+DOlrinHE80SeOGCkSWl2OEeX+NR1tgyq9WpbYJV0w5tuWhiyww3Lb+ktBIWRK+vn+kX0HzndGZ/+q/fAIaQEckT9jqAgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - Entity page&quot;
        title=&quot;&quot;
        src=&quot;/static/2720db67002dc217bd380ad03cbcd918/9fabd/home-assistant-entity-page.png&quot;
        srcset=&quot;/static/2720db67002dc217bd380ad03cbcd918/c6e3d/home-assistant-entity-page.png 500w,
/static/2720db67002dc217bd380ad03cbcd918/da8b6/home-assistant-entity-page.png 1000w,
/static/2720db67002dc217bd380ad03cbcd918/9fabd/home-assistant-entity-page.png 2000w,
/static/2720db67002dc217bd380ad03cbcd918/f0b95/home-assistant-entity-page.png 2120w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;come puoi vedere, è abbastanza scomodo. È meglio inserire queste entità nella pagina panoramica / dashboard.&lt;/p&gt;
&lt;p&gt;Nell’Home Assistant, fai clic su Panoramica sulla barra di sinistra, i tre punti sulla destra, Modifica dashboard e infine “Aggiungi scheda” in basso. Dovrebbe apparire una modale, fare clic sulla scelta “Entità”.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8845bfd7a5eec64980978ef412368887/1d10b/home-assistant-add-card.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 61.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAACNElEQVR42m1Sy5LTMBDUnaI2D8cPSdbDb8dJzAJLiixbxYXDHoEP4MCRb+Gbmx4nywUOU2ONrJ7unlHbvIAZT/DDBM9s+wOKeoDp9tDNCNNec173iNOMna/x2lY4O4t3jKNz+OwNvjBWroEa317wPjpk2iFNMyTJDkXBJsag0AYuRNR1Dc2z1hpVVaEkSF46PAWDT1211KZhgPce6r5r8SNs8TyskOY5HH/c7ZIrqLUIVYO+6+AIIk28dwh8eI4lnl2GvS9hY8XGgQQ0lI01pkrj97dXOB73eHx8QlmWyLIM1pZXwL5H27awAti0+BgtvhLsqC0qqhiFOe8MSahpPyJlcchyfHAalp3sTZ509KEiWLMwFNbCpKd3J53hnv5Plm+p5IERGappGjKxKIzGbrPBakXpabrUBLRkFm/EN8mGtbxgnd6W4icbLP6K53kGJb5IbLdb1ASf53mRK6DCquajyKEE5pqyNRtIs2maMJ9OODCLIuM8ilBDiV8CmHMgh8MB5/P5rzzNu4nRyoDILDB3VGIMQflYph9i5F2B0I2wxwcoKSZJsjDcUPJ6vb5+M8vUZ8q8EPQNpV3YSKLksCL3VdZlsYaNDpzFQK+VFAVAvBOwl5CzSJf7hlK9eEhgyyzT91W3MFz2lWxj20HmoYZxXBj+D1BsiGQmA3Fk0vBxEL+EYTsu69RxR5t+wJ5eyll9//kLGR+u7u7+Zci6vy10vA2jko2gxJRrJg2vkXEjiuX/P10vRjVgOEWbAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - Add card&quot;
        title=&quot;&quot;
        src=&quot;/static/8845bfd7a5eec64980978ef412368887/9fabd/home-assistant-add-card.png&quot;
        srcset=&quot;/static/8845bfd7a5eec64980978ef412368887/c6e3d/home-assistant-add-card.png 500w,
/static/8845bfd7a5eec64980978ef412368887/da8b6/home-assistant-add-card.png 1000w,
/static/8845bfd7a5eec64980978ef412368887/9fabd/home-assistant-add-card.png 2000w,
/static/8845bfd7a5eec64980978ef412368887/1d10b/home-assistant-add-card.png 2128w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Scrivi il titolo che desideri; nella sezione “entità”, cerca le entità che abbiamo visto in precedenza. Dovresti vedere un’anteprima della nuova carta in basso. Quando sei soddisfatto, fai clic su “Salva” ed il gioco è fatto!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e3d680543a03ec91d35eba55a910b315/7495a/home-assistant-add-entity-card.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 67%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAACFElEQVR42n2TS4/TMBSFs4Q208RJnDjvd5pM2g6aEQ8JNiAkEGLBX+H/Lw7nui2qBjSLT3Ht63MfPnWSdsDTl+84vfuI9XTC+uaJPGK4P6Cb7/+hv1m3+wXTesTDh094+/UHHj9/g2OaHnnbo6hqjMOArmsx9D2qskSWpsizzCJrITUJMRaTJPasahpkTYecOEms4e12KBh8OKxoeFgUBaqqQlXXDK5RULztOhyPR5tQzoWS+xIXhCGU8qE8D07KDDpQaMsC3XLEfhrRtqzSVtuRnklqZEWJcZowz7MVyfPcJh/HEWkUoQtCpMTRWkNxkeQVxocnttvZCz3bFmERlYtpliOXyiiUyQguo5C9PI7RUCdmpU4QBPCVQmZSrMtsBWwwL16R1qRFWV/bvSXmPANWGbBTJ2R1KqRgnWNdVyzLYiu8vXAV/B9yFrNCKUxF8VkwiNhyabDMixUUpOWajyJtCy8JJhSMIg1dthSUF6KoSQz2+4nsMXH4IiKze1nwPA5NwZgWKrL0PMPNZmM3umFEST9Ky1LdLXLxOcXFWkmaITJ0Cx/Gkf63FPQprIsaOjvPRDA0sbkY2H6vhpYvfWuKCqaskNiY2MZZ22y3W7iua4Ut/C34vg/NkYgdIhLyJTVRdIXHM8/b/UX53NvR2Av/uyIigs/xVXCxQwCZtSQXJJGNubuD+/oVtqaC++s33Pc/8QcwpldG4tyBTwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - Add entity card&quot;
        title=&quot;&quot;
        src=&quot;/static/e3d680543a03ec91d35eba55a910b315/9fabd/home-assistant-add-entity-card.png&quot;
        srcset=&quot;/static/e3d680543a03ec91d35eba55a910b315/c6e3d/home-assistant-add-entity-card.png 500w,
/static/e3d680543a03ec91d35eba55a910b315/da8b6/home-assistant-add-entity-card.png 1000w,
/static/e3d680543a03ec91d35eba55a910b315/9fabd/home-assistant-add-entity-card.png 2000w,
/static/e3d680543a03ec91d35eba55a910b315/7495a/home-assistant-add-entity-card.png 2666w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Ora dovremmo avere questa bella card ogni volta che apriamo Home Assistant! Se clicchiamo su questo, dovremmo vedere anche un grafico che riguarda l’ultimo giorno.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 938px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0b43934526e7c15368ace45f77d22a18/a0abd/home-assistant-card-final.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 38.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA8UlEQVR42pWSyW6AMAxE+Qn2NexhhxNCiCv//0VTxm0uVUXbw5MdMZmMbCzf9+E4Dmzbluq6LsIw/DdRFMl967ou7PuO8zxx3zeO40AQBIjjWKDwL1DLMFbTNOi0xrIsGIYB+umZmtD4zYTJqKGWvRjGqUKYZM8LEcqyRFVVaNsWfd+jrutXM+qpZSj2YqgqjfQhzxW6rsM4jmLG/jfDPM9FN02TaD8TJimiOEGaJiIwFEWBLMteDZVSAnWsYljoCaodURY55nnGtm0yz3VdZZ5mOd+hof6aPe8wqed5sMwCeOALXL2BZ/P9J4yelfDX+wBCMtpg8FgNbAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - Finalized card&quot;
        title=&quot;&quot;
        src=&quot;/static/0b43934526e7c15368ace45f77d22a18/a0abd/home-assistant-card-final.png&quot;
        srcset=&quot;/static/0b43934526e7c15368ace45f77d22a18/c6e3d/home-assistant-card-final.png 500w,
/static/0b43934526e7c15368ace45f77d22a18/a0abd/home-assistant-card-final.png 938w&quot;
        sizes=&quot;(max-width: 938px) 100vw, 938px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Conclusioni&lt;/h2&gt;
&lt;p&gt;Finalmente arriviamo alla fine di questo viaggio. Spero che tu abbia imparato qualcosa di nuovo e apprezzi la bellezza di creare un sensore per la qualità dell’aria da solo.&lt;/p&gt;
&lt;p&gt;Vorrei raccontarvi di più a riguardo: ad esempio, non ho spiegato come vedere questi dati su &lt;a href=&quot;http://grafana.com&quot;&gt;Grafana&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1554px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/94f8dad4315c5a8c2fe586b3a2620617/0d8e8/grafana-air-quality.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 40%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAABh0lEQVR42k1S2W7bMBDUJwSyDlK8xEMUJdeOJQdwFLTvQfoc9P+/ZLqU68IPg11qubOzQxV1y8E6hUPV4lCz/yjpbEPE9OOChon9/Fx/4KWsIY2F8QEvhxqFUD2sH1Ezibrt9uYc8+Wq6SgX/2Ku3eMz9sFzwHidwbVCwYVGHyZwFaiRoWkzIUeII2KadzhSWucau9dyfAyuGw7nImKcobQjhbpHSido6VBSU1YqyILLsu7wIeC2fUBqg7LOdVJMRA9k0iFNmE4nGOdR5A95wnk4g3ONKb5CSYu+j4QBVg9I8Qgheng3odcRSnloHcBoeNN1WL+u2L43pG2+EwptIZVFRQq0ceCksBMGQvZoSZGyeeUOkgawTtNdB0V5xQwaIbD8XnD7viF9TCiyqX5IuKxviNORfOT7GhV5lfPs1Xi+0itGHNd3SDtgPK3QpDotG1opsXxe8fPPL8RbIkJ6at17DHGCsWE3+RkNkRvrSbGG86SQS7rv0NEWhvrKQwMmFfyY6M9o8RcGBNkK6fFBuwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Home Assistant - Qualità dell&amp;#39;aria e segnale WiFi&quot;
        title=&quot;&quot;
        src=&quot;/static/94f8dad4315c5a8c2fe586b3a2620617/0d8e8/grafana-air-quality.png&quot;
        srcset=&quot;/static/94f8dad4315c5a8c2fe586b3a2620617/c6e3d/grafana-air-quality.png 500w,
/static/94f8dad4315c5a8c2fe586b3a2620617/da8b6/grafana-air-quality.png 1000w,
/static/94f8dad4315c5a8c2fe586b3a2620617/0d8e8/grafana-air-quality.png 1554w&quot;
        sizes=&quot;(max-width: 1554px) 100vw, 1554px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;o come vedere l’SSID WiFi e la sua potenza del segnale direttamente su Home Assistant.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1006px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/434621f3a2d0d32f344dc6f671eb02c4/aabec/home-assistant-air-wifi.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 90.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAABYlAAAWJQFJUiTwAAACBUlEQVR42oVU2W6DMBDMRySEAMYcgYRgjhxS2///sO3MFiOEQvowslkvs7OHvYuiSBKTSpIkUpal1HUtl8tFmqaRLMskjmM920KapgprrfruTqeTFM0oNitkHAb5/v6RAStJ/yPkWVEU6k8oIRUam0GlUYUEiRjRwPZJnVdIfxKTa1I4SJrlcr1e5X6/S9/3GpFOnxSSgGRd1+k/c8q2OItBJKo7n8+zUtaTCrbSJRn9PWbC/NpJanNE+Yt0u92kbVuNvJU2f2bAcRzVl/8xuBKmqtCCwIlzTh240rmqKk1ti1QF5flK4aXTGrJurCEjMx2ufhzeEVI9weCPx0P3u+B4lPAYSBiGM46wBUGg4H59trYdDgfZ7/e6qkKmRBWpH1SookKmok3haMBmJzvxrrbk0jl8PZ/SoBEl9g7riLSZutYQA24BNugJPz/EDLYuxUzIEWHEeFEbX3TaDFa7aMRWTWdCppJsOJGwxJljR0n+4dbMhKxJ9K6LdAIKoOXNWBCaFblZEuYgpArLxswpMV1c/iiWChk4zFnIecSZmXyW0Ku4TPmFwj/xZD34dGH+HAGSL3z3uOMtzgY0wgEv2O9FKV1VSw+/gS8OcOLj4AkL3mHADytBe4mbYvmMQYFF81L8SFvN7nPEJr8Me31tOJjRlAqlc+8xp+JtnNnF3Hq7n2Vy/QIQLeqzul8bcgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Grafana&quot;
        title=&quot;&quot;
        src=&quot;/static/434621f3a2d0d32f344dc6f671eb02c4/aabec/home-assistant-air-wifi.png&quot;
        srcset=&quot;/static/434621f3a2d0d32f344dc6f671eb02c4/c6e3d/home-assistant-air-wifi.png 500w,
/static/434621f3a2d0d32f344dc6f671eb02c4/da8b6/home-assistant-air-wifi.png 1000w,
/static/434621f3a2d0d32f344dc6f671eb02c4/aabec/home-assistant-air-wifi.png 1006w&quot;
        sizes=&quot;(max-width: 1006px) 100vw, 1006px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Ne parlerò in altri post del blog perché questo è già molto lungo.&lt;/p&gt;
&lt;p&gt;Se vuoi essere aggiornato lascia la tua email qui sotto e ti avviserò. O semplicemente visita il mio blog di tanto in tanto.&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Autenticazione JWT con Angular]]></title><description><![CDATA[Al lavoro ho dovuto creare un nuovo portale web che dovesse comunicare con il nostro backend.
La nostra scelta per il framework frontend è…]]></description><link>https://www.mattianatali.it/it/autenticazione-jwt-con-angular/</link><guid isPermaLink="false">https://www.mattianatali.it/it/autenticazione-jwt-con-angular/</guid><pubDate>Sun, 15 Dec 2019 16:40:20 GMT</pubDate><content:encoded>&lt;p&gt;Al lavoro ho dovuto creare un nuovo portale web che dovesse comunicare con il nostro backend.
&lt;strong&gt;La nostra scelta per il framework frontend è Angular e il nostro backend usa il JWT (JSON Web Token) come sistema di autenticazione.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Quindi il mio obiettivo era integrare quel sistema di autenticazione in Angular per comunicare con il backend.
Dato che si trattava di un progetto Angular iniziato da zero, ho avuto la possibilità di pensare a come implementarlo.&lt;/p&gt;
&lt;h2&gt;Obiettivi&lt;/h2&gt;
&lt;p&gt;I miei criteri di accettazione erano i seguenti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Per ottenere il token, il frontend dovrebbe chiamare l’endpoint &lt;code class=&quot;language-text&quot;&gt;POST auth/login&lt;/code&gt; con &lt;code class=&quot;language-text&quot;&gt;email&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;password&lt;/code&gt;. Il backend risponderà con &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Il frontend dovrebbe persistere entrambi i token, così l’utente resterà autenticato anche se chiude il browser.&lt;/li&gt;
&lt;li&gt;Dovrebbe inviare l’accessToken per ogni chiamata API autenticata. Invia il token nell’header &lt;code class=&quot;language-text&quot;&gt;X-AUTH-TOKEN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Se il backend risponde &lt;code class=&quot;language-text&quot;&gt;401 - Unauthorized&lt;/code&gt;, significa che il token è scaduto. Quindi il frontend dovrebbe chiamare l’endpoint &lt;code class=&quot;language-text&quot;&gt;POST auth/refresh&lt;/code&gt; passando &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt;. Se il &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; è valido, il backend risponde con nuovi &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; nel body della risposta.
&lt;ul&gt;
&lt;li&gt;Dopo aver recuperato il nuovo &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt;, dovrebbe ritentare la chiamata fallita con il token aggiornato.&lt;/li&gt;
&lt;li&gt;Se il backend risponde di nuovo con &lt;code class=&quot;language-text&quot;&gt;401 - Unauthorized&lt;/code&gt; durante il refresh, significa che il &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; non è più valido. Dobbiamo fare il logout dell’utente.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Dovremmo gestire tutte queste cose in modo trasparente, lo sviluppatore non dovrebbe preoccuparsene troppo quando implementa qualche classe per comunicare con il backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Questo flusso dovrebbe essere abbastanza standard per un sistema di autenticazione JWT. Ora pensiamo a come strutturarlo!&lt;/p&gt;
&lt;h2&gt;Prerequisiti&lt;/h2&gt;
&lt;p&gt;Mi aspetto da te un po’ di conoscenza di questi argomenti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt; e gli &lt;a href=&quot;https://angular.io/guide/http#intercepting-requests-and-responses&quot;&gt;interceptor di Angular&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rxjs-dev.firebaseapp.com/&quot;&gt;RxJS&lt;/a&gt;, che è integrato nell’&lt;a href=&quot;https://angular.io/guide/http&quot;&gt;HTTP Client&lt;/a&gt; di Angular.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Architettura&lt;/h2&gt;
&lt;p&gt;Ho costruito questa integrazione JWT usando il &lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;Test Driven Development (TDD)&lt;/a&gt;. Così sono finito con classi facilmente testabili che hanno una sola responsabilità. Questa è la bellezza del TDD: per semplificare i test &lt;strong&gt;devi&lt;/strong&gt; scrivere buon codice!&lt;/p&gt;
&lt;p&gt;Ho costruito le seguenti classi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt;: effettua le chiamate API al backend. Nel nostro esempio implementeremo &lt;code class=&quot;language-text&quot;&gt;auth/login&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;auth/refresh&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;: persiste i token e mantiene lo stato degli utenti. Possiamo sapere se gli utenti sono autenticati o meno.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuthService&lt;/code&gt;: gestisce la logica di business del nostro sistema di autenticazione, sfrutta sia &lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt; che &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt;: inietta il token in ogni chiamata API autenticata, e gestisce anche la logica di retry quando l’&lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; è scaduto.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Possiamo raggiungere i nostri criteri di accettazione con queste classi, ora implementiamole!&lt;/p&gt;
&lt;h2&gt;Implementazione&lt;/h2&gt;
&lt;h3&gt;Interfacce&lt;/h3&gt;
&lt;p&gt;Costruire una single page application è complesso. Gestisce molti oggetti diversi ed è molto difficile tenerne traccia senza un sistema di tipi. TypeScript aggiunge i tipi a JavaScript e io lo sfrutto il più possibile.
Quindi creo sempre una cartella &lt;code class=&quot;language-text&quot;&gt;/model&lt;/code&gt; che tiene traccia di tutti gli oggetti che creo o ricevo dal backend.
In questo tutorial affronteremo queste interfacce:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ILogin&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    email&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    password&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ILoginResponse&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    accessToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    refreshToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IRefreshRequest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  refreshToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;AuthClient&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt; è molto semplice da implementare. Effettua solo le chiamate API al nostro backend&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Injectable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ILogin &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./model/Login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ILoginResponse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./model/LoginResponse&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; IRefreshRequest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./model/RefreshRequest&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Observable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; HttpClient &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/common/http&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; environment &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;src/environments/environment&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./constants&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Injectable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  providedIn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;root&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AuthClient&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; http&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ILogin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ILoginResponse&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;http
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ILoginResponse&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;environment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;portalBaseUrl&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/auth/login&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;true&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;refreshToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IRefreshRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;http
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ILoginResponse&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;environment&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;portalBaseUrl&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/refresh&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;true&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Puoi vedere che &lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt; è abbastanza semplice. L’unica cosa strana è l’header &lt;code class=&quot;language-text&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/code&gt; che ha un significato speciale. È il mio modo per comunicare con &lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt;, sto dicendo: “Ehi! Questa è una chiamata API pubblica, non devi iniettare il token”. Ne parlo più in dettaglio dopo.&lt;/p&gt;
&lt;h3&gt;AuthStore&lt;/h3&gt;
&lt;p&gt;Memorizza e persiste le credenziali dell’utente. &lt;strong&gt;La mia implementazione è fortemente ispirata al pattern Business Logic Component (BLoC) + RxJS&lt;/strong&gt;. È un pattern nuovo che sta emergendo nel &lt;a href=&quot;https://medium.com/flutter-community/why-use-rxdart-and-how-we-can-use-with-bloc-pattern-in-flutter-a64ca2c7c52d&quot;&gt;mondo Dart + Flutter&lt;/a&gt;. Mi piace e ho portato il concetto in Angular.
Non voglio parlare troppo del pattern BLoC dato che ci sono &lt;a href=&quot;https://www.google.com/search?q=BLoC+Pattern&amp;#x26;oq=BLoC+Pattern&quot;&gt;molti articoli a riguardo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In breve: sfrutto RxJS per creare uno store reattivo delle credenziali, chiunque sia interessato a dei dati di autenticazione dovrebbe sottoscriversi ad esso. Se qualcuno vuole cambiare i dati di autenticazione, può chiamare i metodi di autenticazione. Molto semplice.&lt;/p&gt;
&lt;h4&gt;Store generico&lt;/h4&gt;
&lt;p&gt;La prima cosa da fare è creare lo store generico che gestisce lo stato di tipo &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt;. Questo è agnostico rispetto allo stato, quindi è una classe astratta. Questo store si chiama semplicemente &lt;code class=&quot;language-text&quot;&gt;Store&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Observable&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BehaviorSubject &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Store&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    state$&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; stateSubject$&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; BehaviorSubject&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stateSubject$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BehaviorSubject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state$ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stateSubject$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asObservable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stateSubject$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stateSubject$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Come puoi vedere:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Accetta lo stato iniziale nel costruttore.&lt;/li&gt;
&lt;li&gt;Puoi cambiare lo stato chiamando il metodo &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Puoi sottoscriverti ai cambiamenti di stato sottoscrivendoti all’observable &lt;code class=&quot;language-text&quot;&gt;state$&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Puoi ottenere lo stato corrente una volta sola tramite il getter &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Il motore del mio store è il &lt;code class=&quot;language-text&quot;&gt;stateSubject$&lt;/code&gt; BehaviorSubject privato&lt;/strong&gt;. Se è la &lt;a href=&quot;https://www.learnrxjs.io/subjects/behaviorsubject.html&quot;&gt;prima volta che vedi un BehaviorSubject&lt;/a&gt;, pensa a uno stream che ha anche un “sink”, dove puoi aggiungere un nuovo elemento nello stream chiamando il metodo &lt;code class=&quot;language-text&quot;&gt;next&lt;/code&gt;. BehaviorSubject ha anche lo stato iniziale che dovresti fornire nel costruttore.&lt;/p&gt;
&lt;p&gt;Un’altra cosa interessante è che puoi mantenere il “sink” privato ed esporre solo il suo observable. Sto esponendo solo la variabile &lt;code class=&quot;language-text&quot;&gt;state$&lt;/code&gt; che è l’&lt;code class=&quot;language-text&quot;&gt;Observable&lt;/code&gt; creato da &lt;code class=&quot;language-text&quot;&gt;stateSubject$&lt;/code&gt;.
In questo modo, nessuno può aggiungere un elemento in questo observable se non chiamando il metodo &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt;. In altre parole, puoi solo vedere i cambiamenti sottoscrivendoti all’observable &lt;code class=&quot;language-text&quot;&gt;state$&lt;/code&gt;, e puoi cambiare i dati dello store tramite il metodo &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt;. L’implementazione dello store è gestita da &lt;code class=&quot;language-text&quot;&gt;stateSubject$&lt;/code&gt; che non è esposto esternamente.&lt;/p&gt;
&lt;h4&gt;Implementazione concreta&lt;/h4&gt;
&lt;p&gt;Ora possiamo creare il nostro &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;, la prima implementazione concreta dello &lt;code class=&quot;language-text&quot;&gt;Store&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; IAuthState &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./auth-store.service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; map &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs/operators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Injectable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Store &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;../shared/store&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Observable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ILoginResponse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./model/LoginResponse&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IAuthState&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  accessToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  refreshToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ACCESS_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;auth.accessToken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;REFRESH_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;auth.refreshToken&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Injectable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  providedIn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;root&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AuthStoreService&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Store&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;IAuthState&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; initialState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IAuthState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      accessToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ACCESS_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      refreshToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;REFRESH_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initialState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextState&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IAuthState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ACCESS_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nextState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ACCESS_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;refreshToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;REFRESH_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nextState&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;refreshToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      localStorage&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;REFRESH_TOKEN_LOCAL_STORAGE_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nextState&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isLoggedIn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isLoggedIn$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state$&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;accessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;setAccessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;accessToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; accessToken &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;refreshToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;refreshToken&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loginResponse&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ILoginResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;loginResponse&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newTokens&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ILoginResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;newTokens &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;logout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      accessToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      refreshToken&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ci sono molti metodi di supporto per semplificare l’uso della classe. Questi sono i punti chiave di questa classe:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;È una sottoclasse di &lt;code class=&quot;language-text&quot;&gt;Store&lt;/code&gt;, ha l’interfaccia &lt;code class=&quot;language-text&quot;&gt;IAuthState&lt;/code&gt; come stato. &lt;code class=&quot;language-text&quot;&gt;IAuthState&lt;/code&gt; è molto semplice, contiene solo &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ogni volta che qualcuno chiama &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt;, persiste i dati nel local storage. In questo modo, se l’utente chiude o ricarica la pagina, le credenziali non vanno perse. Se &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt; viene chiamato con credenziali falsy (ad esempio &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; o &lt;code class=&quot;language-text&quot;&gt;false&lt;/code&gt;), le rimuove dal local storage.&lt;/li&gt;
&lt;li&gt;Nel costruttore fornisce lo stato iniziale alla superclasse &lt;code class=&quot;language-text&quot;&gt;State&lt;/code&gt;. Prova a ottenere le credenziali dal local storage.&lt;/li&gt;
&lt;li&gt;Molti metodi getter: sia reattivi (terminano con &lt;code class=&quot;language-text&quot;&gt;$&lt;/code&gt;), sia standard (variabili classiche).&lt;/li&gt;
&lt;li&gt;Alcuni metodi di supporto per cambiare lo stato dello store (&lt;code class=&quot;language-text&quot;&gt;setAccessToken&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;login&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;refresh&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Attenzione&lt;/strong&gt;: memorizzare &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; nel local storage può esporre la tua applicazione a problemi di sicurezza. Qualsiasi JavaScript in esecuzione nella tua web app può leggerli.
Quindi &lt;strong&gt;se la tua web app è vulnerabile al &lt;a href=&quot;https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)&quot;&gt;cross-site scripting (XSS)&lt;/a&gt;, allora qualcuno può rubarli&lt;/strong&gt;. I framework web, come Angular, sono consapevoli di questo problema: adottano standard di sicurezza elevati per evitare vulnerabilità XSS. Ti consiglio di dedicare un po’ di tempo a leggere del &lt;a href=&quot;https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)&quot;&gt;cross-site scripting (XSS)&lt;/a&gt;.
Se hai paura di questo, semplicemente non salvare i token nel local storage, sarai al sicuro… Ma se il tuo utente chiude la pagina, dovrà fare di nuovo il login.&lt;/p&gt;
&lt;p&gt;Ora il nostro AuthStore è pronto! Passiamo alla classe che collega tutto insieme: l’&lt;code class=&quot;language-text&quot;&gt;AuthService&lt;/code&gt;!&lt;/p&gt;
&lt;h3&gt;AuthService&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;AuthService&lt;/code&gt; è la classe che contiene la logica di business per far funzionare l’autenticazione. Vediamo il codice:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Injectable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Observable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; switchMap&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tap &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs/operators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AuthClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; IRefreshRequest &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./auth-client.service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AuthStoreService &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./auth-store.service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ILogin &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./model/Login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ILoginResponse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./model/LoginResponse&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Router &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/router&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Injectable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  providedIn&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;root&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AuthService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; authClient&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; authStore&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthStoreService&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; router&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Router&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ILogin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ILoginResponse&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loginResponse &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loginResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;refreshTokenRequest&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IRefreshRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ILoginResponse&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authClient&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;refreshToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;refreshTokenRequest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;refreshResponse &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;refreshResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;logout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;logout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;router&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;navigateByUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/auth/login&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Questa classe usa sia &lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt;, per effettuare le chiamate API, sia &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;, per persistere le credenziali.
Ci sono tre metodi che possiamo chiamare:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;login&lt;/code&gt;: lo chiamiamo quando vogliamo che l’utente faccia il login. Chiama l’API di login e poi persiste le credenziali in AuthStore.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;refresh&lt;/code&gt;: usato per aggiornare il token. Effettua le chiamate API e poi le persiste.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;logout&lt;/code&gt;: svuota l’&lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt; e poi porta l’utente alla pagina di login.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Questa è una versione semplificata della mia implementazione. Durante il login ho anche effettuato una chiamata API a un endpoint per ottenere i dati dell’utente (chiamato anche &lt;code class=&quot;language-text&quot;&gt;auth/me&lt;/code&gt;). Non l’ho aggiunto perché la sua implementazione dipende dalla tua architettura ed è fuori dallo scopo del post. Il punto chiave è questo: &lt;strong&gt;dovresti aggiungere tutta la tua logica di business dell’autenticazione qui&lt;/strong&gt;, delegando la persistenza ad &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt; e le chiamate API ad &lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;AuthInterceptor&lt;/h3&gt;
&lt;p&gt;Siamo nell’ultima parte di questo post: possiamo autenticare l’utente e persistere le credenziali nell’&lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;. Possiamo aggiornare il token quando scade. Possiamo fare il logout dell’utente.&lt;/p&gt;
&lt;p&gt;Ora ci concentriamo su questi obiettivi:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Non passare il token quando chiamiamo un’API pubblica.&lt;/li&gt;
&lt;li&gt;Passare il token JWT durante le chiamate API autenticate.&lt;/li&gt;
&lt;li&gt;Aggiornare il token quando l’&lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; scade. Sappiamo che il token scade solo quando effettuiamo qualche chiamata API: quindi quando una chiamata API fallisce, perché il token è scaduto, dobbiamo chiamare l’API di refresh per ottenere il nuovo token, poi dobbiamo rifare la prima chiamata con il token aggiornato.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tutte queste cose sono gestite dall’&lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt;. È una sottoclasse dell’&lt;a href=&quot;https://angular.io/guide/http#http-interceptors&quot;&gt;HTTP Interceptor di Angular&lt;/a&gt;. In breve, &lt;strong&gt;un HTTP Interceptor è uno strato che possiamo aggiungere tra la chiamata API che effettuiamo e la vera HTTP Request fatta dal browser&lt;/strong&gt;. In questo modo possiamo iniettare trasparentemente tutti questi comportamenti di autenticazione senza modificare le nostre classi Client.&lt;/p&gt;
&lt;h4&gt;Capire l’HTTP Interceptor&lt;/h4&gt;
&lt;p&gt;Prima di tutto, dobbiamo capire come implementare un HTTP Interceptor: &lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt; dovrebbe implementare l’interfaccia &lt;code class=&quot;language-text&quot;&gt;HttpInterceptor&lt;/code&gt;. Quindi dobbiamo implementare il metodo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;intercept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequest&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpHandler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HttpEvent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il primo parametro è la richiesta HTTP che Angular sta per effettuare. Alla fine della nostra logica, dobbiamo chiamare &lt;code class=&quot;language-text&quot;&gt;next.handle(request)&lt;/code&gt; per continuare la richiesta HTTP attraverso il flusso normale.
In altre parole, assumiamo di creare un HTTP interceptor che non fa assolutamente nulla. Il codice minimo che dobbiamo scrivere è questo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Injectable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NoOpInterceptor&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HttpInterceptor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;intercept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequest&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpHandler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HttpEvent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; next&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Implementazione di AuthInterceptor&lt;/h4&gt;
&lt;p&gt;Ora facciamo la stessa cosa per il nostro &lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt;, ma questa volta dobbiamo aggiungere tutta la logica di autenticazione di cui abbiamo parlato prima.&lt;/p&gt;
&lt;p&gt;Diamo un’occhiata alla sua implementazione:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AuthStoreService &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./auth-store.service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; HttpInterceptor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HttpRequest&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HttpHandler&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HttpEvent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HttpErrorResponse &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/common/http&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Observable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Injectable &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/core&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; tap&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mergeMap&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; catchError &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rxjs/operators&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AuthService &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./auth.service&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./constants&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Injectable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AuthInterceptor&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HttpInterceptor&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; authStore&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthStoreService&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; authService&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthService&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;intercept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequest&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpHandler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;HttpEvent&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;/* Se la richiesta in arrivo ha lo speciale INTERCEPTOR_NO_AUTH_HEADER,
           significa che non dobbiamo aggiungere il token JWT
        */&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;/* Quindi invia semplicemente al prossimo handler la stessa richiesta
               rimuovendo lo speciale header INTERCEPTOR_NO_AUTH_HEADER
            */&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; next&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;headers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// Se l&apos;utente ha fatto il login&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isLoggedIn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; next
                &lt;span class=&quot;token comment&quot;&gt;// Allora aggiungi il token e continua la chiamata API.&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addTokenToRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;token comment&quot;&gt;// Ma se la chiamata è fallita, prova a recuperarla usando il metodo retryWhenExpiredToken&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;catchError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;retryWhenExpiredToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;token function-variable function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpErrorResponse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;token comment&quot;&gt;/*
                              Se la chiamata, dopo il nostro metodo di refresh, sta ancora fallendo con
                              lo status code 401 UNAUTHORIZED
                            */&lt;/span&gt;
                            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                                &lt;span class=&quot;token comment&quot;&gt;// Allora fai il logout dell&apos;utente, non possiamo fare altro.&lt;/span&gt;
                                &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;logout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;/*
          Se l&apos;utente non ha fatto il login, non fare nulla.
          Non abbiamo nessun token JWT da allegare alla richiesta
        */&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; next&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Questo metodo viene chiamato solo durante una risposta di errore&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;retryWhenExpiredToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequest&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; next&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpHandler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Observable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; refreshToken &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;refreshToken&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;/* Se lo status code è 401 UNAUTHORIZED e non abbiamo il refresh token,
               oppure lo status code è diverso da 401 UNAUTHORIZED
            */&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;401&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;refreshToken &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;status &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;401&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// Non possiamo fare nulla, rilancia semplicemente l&apos;errore e continua.&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// Altrimenti, chiama il backend per aggiornare il nostro token&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authService
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;refresh&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; refreshToken &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;token comment&quot;&gt;// Poi richiama la richiesta fallita con il token appena aggiornato&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;mergeMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; next&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addTokenToRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// Clona semplicemente la richiesta, aggiungendo il token JWT alla richiesta&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;addTokenToRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequest&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HttpRequest&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; request
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                setHeaders&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token string-property property&quot;&gt;&apos;X-JWT-TOKEN&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;accessToken&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Prenditi il tuo tempo per leggerlo… Vediamo che il metodo &lt;code class=&quot;language-text&quot;&gt;intercept&lt;/code&gt; è più complesso. &lt;strong&gt;Ho aggiunto tantissimi commenti nel codice&lt;/strong&gt;, così è più facile capire cosa succede.&lt;/p&gt;
&lt;p&gt;Vediamo se abbiamo raggiunto tutti i nostri obiettivi prefissati:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Non passare il token quando chiamiamo un’API pubblica:&lt;/em&gt; fatto tramite lo speciale header &lt;code class=&quot;language-text&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Passare il token JWT durante le chiamate API:&lt;/em&gt; fatto grazie al metodo &lt;code class=&quot;language-text&quot;&gt;addTokenToRequest&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Aggiornare il token quando l’&lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; scade:&lt;/em&gt; ottenuto tramite il metodo &lt;code class=&quot;language-text&quot;&gt;retryWhenExpiredToken&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Il codice non è così lungo, ha più o meno 50 righe. Ma penso che sia abbastanza pieno di concetti complicati di RxJS come &lt;a href=&quot;https://www.learnrxjs.io/operators/transformation/mergemap.html&quot;&gt;mergeMap&lt;/a&gt;, &lt;a href=&quot;https://www.learnrxjs.io/operators/utility/do.html&quot;&gt;tap&lt;/a&gt;, &lt;a href=&quot;https://www.learnrxjs.io/operators/error_handling/catch.html&quot;&gt;catchError&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures&quot;&gt;Ho usato una closure&lt;/a&gt; per far funzionare &lt;code class=&quot;language-text&quot;&gt;retryWhenExpiredToken&lt;/code&gt;. Ho creato una funzione che restituisce una funzione. La prima chiamata ottiene la richiesta originale e l’handler &lt;code class=&quot;language-text&quot;&gt;next&lt;/code&gt; e restituisce la funzione che passiamo al metodo &lt;code class=&quot;language-text&quot;&gt;catchError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scrivere questo codice senza bug in un colpo solo è molto difficile&lt;/strong&gt;, anche se non è lungo. Due cose mi hanno aiutato a raggiungerlo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Uso massiccio del sistema di tipi di TypeScript&lt;/strong&gt;: TypeScript aggiunge i tipi a JS, grazie al cielo! Aggiungere i tipi a tutto è il modo migliore per evitare bug fastidiosi. Il transpiler può avvisarti il prima possibile se stai restituendo qualcosa di sbagliato. Se metti &lt;code class=&quot;language-text&quot;&gt;any&lt;/code&gt; ovunque, o non aggiungi i tipi per i parametri attesi, sei da solo! Il transpiler non può aiutarti, prima o poi farai un errore. L’unico &lt;code class=&quot;language-text&quot;&gt;any&lt;/code&gt; che vedi in questo codice è perché la firma di &lt;code class=&quot;language-text&quot;&gt;intercept&lt;/code&gt; viene da Angular e non posso farci nulla.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Usa il Test Driven Development (TDD)&lt;/strong&gt; per la parte cruciale del tuo sistema, o usa il TDD il più possibile. Testare manualmente questo sistema di autenticazione richiede molto più tempo che scrivere qualche unit test. E non c’è niente di peggio di qualcuno che ti chiama dicendo che gli utenti non riescono ad accedere. L’ho fatto usando il TDD e il risultato sono queste piccole classi facili da testare grazie alla &lt;a href=&quot;https://angular.io/guide/testing&quot;&gt;suite di testing di Angular&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lo sviluppatore perfetto, che non fa bug, non esiste. &lt;strong&gt;Alcuni sviluppatori sono migliori di altri non perché sono perfetti, ma perché prendono più contromisure per evitare bug&lt;/strong&gt;, quindi scrivono codice meno buggato. TypeScript e il TDD sono le contromisure più efficaci che conosco per lo sviluppo frontend. Quindi usali.&lt;/p&gt;
&lt;p&gt;Se sei interessato al TDD, ho scritto due articoli sull’argomento. Li trovi qui:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero/&quot;&gt;Come programmare in Test-Driven Development (TDD) partendo da zero&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/it/come-sviluppare-rest-api-in-tdd-con-spring-boot/&quot;&gt;Come sviluppare delle API in TDD con Spring Boot&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Aggiungere AuthInterceptor all’app Angular&lt;/h4&gt;
&lt;p&gt;Dobbiamo ricordarci di aggiungere l’AuthInterceptor alla nostra applicazione.
È molto facile: dobbiamo dichiararlo nel modulo Angular root dell’app&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HTTP_INTERCEPTORS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;@angular/common/http&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; AuthInterceptor &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;./auth/auth-interceptor&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token decorator&quot;&gt;&lt;span class=&quot;token at operator&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NgModule&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  declarations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  imports&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    AuthModule&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  bootstrap&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;AppComponent&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  providers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; provide&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;HTTP_INTERCEPTORS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; useClass&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AuthInterceptor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; multi&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AppModule&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;E questo è tutto! Ora la nostra app gestisce l’autenticazione JWT del nostro backend!&lt;/p&gt;
&lt;h3&gt;Conclusione&lt;/h3&gt;
&lt;p&gt;Spero che tu ti sia goduto questo viaggio sull’autenticazione JWT + Angular. Questa è la mia implementazione, e ha soddisfatto tutti i miei obiettivi. Spero che questo lavoro ti ispiri a raggiungere i tuoi!&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Benvenuti nel nuovo blog!]]></title><description><![CDATA[Eccoci qui, con un nuovo blog scintillante! Ho deciso di creare un altro blog personale. Ma questo è diverso dal mio precedente. È in…]]></description><link>https://www.mattianatali.it/it/benvenuto-2019/</link><guid isPermaLink="false">https://www.mattianatali.it/it/benvenuto-2019/</guid><pubDate>Sun, 25 Aug 2019 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Eccoci qui, con un nuovo blog scintillante!&lt;/p&gt;
&lt;p&gt;Ho deciso di creare un altro blog personale. Ma questo è diverso dal &lt;a href=&quot;https://www.mattianatali.it&quot;&gt;mio precedente&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;È in inglese.&lt;/h2&gt;
&lt;p&gt;Scrivevo in italiano dato che sono italiano! Ma mi sono reso conto che per i post tecnici la lingua preferita è l’inglese.&lt;/p&gt;
&lt;p&gt;Non è un cambio facile per me, perché amo l’Italia e volevo diffondere un po’ di conoscenza nella mia lingua madre. Ma scrivendo post in italiano raggiungo una nicchia di una nicchia… Non so quanto sia utile.&lt;/p&gt;
&lt;p&gt;Un’altra grande ragione è che tutti i riferimenti che collego nei miei post erano in inglese! Quindi anche un lettore italiano dovrebbe conoscere l’inglese per capire bene il contenuto.&lt;/p&gt;
&lt;h2&gt;Riguarda il mio lavoro&lt;/h2&gt;
&lt;p&gt;Il mio blog precedente era più personale, è nato senza un’idea fissa su cosa ci avrei scritto. Infatti era più un esercizio su come distribuire un blog &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost&lt;/a&gt; e come costruire un sito &lt;a href=&quot;https://www.gatsbyjs.org/&quot;&gt;Gatsby&lt;/a&gt;. I contenuti al suo interno sono più misti: dalla fotografia, ai giochi, ai post tecnici.&lt;/p&gt;
&lt;p&gt;In questo blog voglio condividere con voi i miei pensieri sul mio lavoro quotidiano, su come ho affrontato qualche compito impegnativo, o semplicemente su cosa faccio al lavoro.&lt;/p&gt;
&lt;p&gt;Voglio condividere contenuti utili per altri sviluppatori.&lt;/p&gt;
&lt;p&gt;Spero di avere il tempo di condividere queste cose e spero che vi piacciano!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Impariamo ad automatizzare con Ansible · DevOps]]></title><description><![CDATA[Introduzione Siete al lavoro e avete il compito di configurare 20 macchine virtuali tutte allo stesso modo? Siete a casa e avete il vostro…]]></description><link>https://www.mattianatali.it/it/come-automatizzare-con-ansible-tutorial/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-automatizzare-con-ansible-tutorial/</guid><pubDate>Sun, 25 Aug 2019 07:03:47 GMT</pubDate><content:encoded>&lt;h2&gt;Introduzione&lt;/h2&gt;
&lt;p&gt;Siete al lavoro e avete il compito di configurare 20 macchine virtuali tutte allo stesso modo? Siete a casa e avete il vostro Raspberry Pi che purtroppo ha corrotto l’SD card e quindi dovete riconfigurarlo per l’ennesima volta? Allora &lt;strong&gt;Ansible potrebbe risolvere molti dei vostri problemi&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Se siete come me sono certo che non vi piace passare la giornata ad eseguire task ripetitivi che danno praticamente zero valore aggiunto a voi stessi: &lt;strong&gt;eseguire task ripetitivi non è un compito da far svolgere a noi umani&lt;/strong&gt;, possiamo benissimo delegarlo alle macchine per poterci dedicare a cose che veramente contano.&lt;/p&gt;
&lt;p&gt;Come facciamo ad automatizzare questi task? Una risposta sicuramente efficace è &lt;a href=&quot;https://www.ansible.com/&quot;&gt;Ansible&lt;/a&gt;, lo strumento di configurazione che preferisco.&lt;/p&gt;
&lt;h2&gt;Obiettivo&lt;/h2&gt;
&lt;p&gt;Se avete avuto di leggere la &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/quickstart.html&quot;&gt;documentazione ufficiale di Ansible&lt;/a&gt;, sono certo che avrete notato che è tanto noiosa quanto è potente il tool stesso. È facile che vi addormentiate a leggerla ancor prima di capire le reali potenzialità di Ansible.&lt;/p&gt;
&lt;p&gt;Ecco che allora ho deciso di scrivere questa mini guida sperando che sia un po’ più efficace. Spero di raggiungere questo obiettivo tramite un esempio concreto che è mi è capitato e che utilizzo tutt’ora: &lt;strong&gt;andremo a configurare un &lt;a href=&quot;https://it.wikipedia.org/wiki/Virtual_Private_Network&quot;&gt;VPN Server&lt;/a&gt; su un &lt;a href=&quot;https://www.raspberrypi.org/&quot;&gt;Raspberry Pi&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Grazie a questo playbook di Ansible, possiamo creare un VPN Server su un Raspberry Pi lanciando un unico comando &lt;code class=&quot;language-text&quot;&gt;ansible-playbook -vv -i hosts vpn.yml&lt;/code&gt;. &lt;strong&gt;Le funzioni che esegue sotto le quinte sono molte&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scarica il certificato tramite &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;https://letsencrypt.org/&lt;/a&gt; del dominio che sta puntando a casa nostra, per esempio &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Imposta il rinnovo automatico del certificato stesso.&lt;/li&gt;
&lt;li&gt;Apre le porte corrette sul Raspberry Pi per far funzionare la VPN.&lt;/li&gt;
&lt;li&gt;Installa tutte le librerie ed applicazioni necessarie per installare il VPN Server.&lt;/li&gt;
&lt;li&gt;Configura correttamente le impostazioni che decidiamo noi per la VPN, per esempio l’utente per accedervi.&lt;/li&gt;
&lt;li&gt;Imposta l’aggiornamento automatico dei certificati in base al rinnovo del certificato di Let’s Encrypt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Immaginate ora se non avessimo avuto Ansible che facesse tutte queste cose con un comando. Sicuramente dopo 2 giorni che ho eseguito manualmente questi comandi mi sarei già dimenticato tutto, senza contare il numero di tentativi che avrei dovuto fare anche la seconda volta per riconfigurare tutto da zero.
Proprio per questo, una volta che ho capito come potevo fare, ho creato lo script Ansible. &lt;strong&gt;Ora ho in una &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/&quot;&gt;repository pubblica&lt;/a&gt; il playbook versionato e pronto all’uso&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In questa guida non ci soffermeremo troppo sui dettagli della VPN: &lt;strong&gt;a noi interessano di più i ragionamenti che ci sono stati per arrivare a questo risultato e quali funzionalità di Ansible abbiamo utilizzato&lt;/strong&gt;. La creazione della VPN è solo un esempio concreto che copre molte funzionalità di Ansible.&lt;/p&gt;
&lt;h2&gt;Requisiti&lt;/h2&gt;
&lt;p&gt;I requisiti per seguire questa guida sono i seguenti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abbiamo un minimo di conoscenze di linux. I comandi &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;apt-get install&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;chmod&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;ssh&lt;/code&gt; dovrebbero esserci familiari.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html&quot;&gt;Abbiamo installato sul vostro portatile Ansible&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.raspberrypi.org/documentation/remote-access/ssh/&quot;&gt;Il nostro Raspberry Pi deve avere SSH abilitato&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Glossario&lt;/h2&gt;
&lt;p&gt;Il primo scoglio che si incontra con Ansible è imparare e ricordarsi i vari termini che utilizza. Qui un piccolo riassunto che ci aiuterà nel corso della guida:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Moduli&lt;/em&gt;: i moduli sono dei piccoli programmi che Ansible ci offre per portare a termine i task. Per esempio: vogliamo installare un pacchetto tipo vim? Possiamo usare il modulo &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/apt_module.html&quot;&gt;apt&lt;/a&gt;, vogliamo aggiungere un cronjob? C’è il modulo &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/cron_module.html&quot;&gt;cron&lt;/a&gt;. &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/modules_by_category.html&quot;&gt;Ce ne sono davvero un’infinità&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Task&lt;/em&gt;: per esempio un task è “installa il programma nginx”. Possiamo vederli come l’unità più piccola che abbiamo in Ansible, sostanzialmente è il richiamo di un modulo con i vari parametri. Un esempio di task è il seguente&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install nginx
    &lt;span class=&quot;token key atrule&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
      &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; nginx&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Ruolo&lt;/em&gt;: Ansible spiega il ruolo usando una metafora calcistica. Un esempio di ruolo può essere “attaccante”, “difensore”, “centrocampista”. Calando nel nostro esempio abbiamo due ruoli: “installatore del certificato”, “installatore della VPN”. Insomma è un insieme di tasks che hanno una funzione ben precisa, un ruolo appunto.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Playbook&lt;/em&gt;: è l’unità più grande che abbiamo in Ansible. Un playbook organizza i vari ruoli per portare a termine il nostro compito. Per esempio nel nostro caso è l’insieme dei due ruoli precedentemente spiegati. &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/&quot;&gt;La mia repository sulla creazione della VPN&lt;/a&gt; è appunto un playbook. Nel nostro caso avremo un playbook che svolgerà il nostro compito, ossia installare la VPN con i vari certificati.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Inventory&lt;/em&gt;: È un file che contiene al suo interno dei gruppi che a loro volta contengono delle macchine. Queste macchine sono quelle che verranno influenzate dalla nostro playbook. Ansible è molto potente, con un solo comando potete installare la VPN su 100 macchine. Noi avremo un gruppo chiamato &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; che al suo interno avrà definito la nostra macchina target di nome &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt; (il Raspberry Pi).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ora abbiamo una terminologia comune, non è necessario capire tutto ora, sicuramente è ancora tutto molto fumoso. Ma più avanti, dopo aver visto un esempio concreto, sarà tutto più chiaro.&lt;/p&gt;
&lt;h2&gt;Eseguiamo il task manualmente&lt;/h2&gt;
&lt;p&gt;Prima di automatizzare dobbiamo aver chiaro cosa dobbiamo fare, la prima volta magari non abbiamo proprio le idee chiare, facciamo molti tentativi e alcuni finiranno in un nulla di fatto. &lt;strong&gt;Quindi la prima cosa da fare è provare manualmente&lt;/strong&gt; senza scomodare Ansible così da essere più veloci nella fase di “costruzione” dei vari task per raggiungere l’obiettivo. Nel nostro caso ci facciamo prima un po’ di cultura sulla VPN, leggiamo come funziona &lt;a href=&quot;https://www.strongswan.org/&quot;&gt;strongswan&lt;/a&gt;, che librerie ha bisogno per funzionare, come configurarlo ecc. Poi ci facciamo una cultura su &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let’s Encrypt&lt;/a&gt; per rilasciare un certificato valido per il nostro dominio &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt; che punta a casa nostra, in modo tale da avere il punto di accesso alla nostra VPN.&lt;/p&gt;
&lt;p&gt;Tutta questa fase ve la risparmio, la cosa che dobbiamo tenere a mente è questa: &lt;strong&gt;durante la fase manuale teniamo a mente ogni passaggio che svolgiamo per portare a termine il nostro compito&lt;/strong&gt;, ogni singolo file di configurazione che abbiamo modificato, qualsiasi cosa dobbiamo tenerne traccia perché fra poco la automatizzeremo.&lt;/p&gt;
&lt;h2&gt;Definiamo i ruoli&lt;/h2&gt;
&lt;p&gt;Una volta raggiunto l’obiettivo manualmente, è tempo di organizzare le idee. Alla fine della nostra analisi il nostro playbook di Ansible deve eseguire i seguenti task:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scarica il certificato tramite &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;https://letsencrypt.org/&lt;/a&gt; del dominio che sta puntando a casa nostra, per esempio &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Imposta il rinnovo automatico del certificato stesso.&lt;/li&gt;
&lt;li&gt;Apre le porte corrette sul Raspberry Pi per far funzionare la VPN.&lt;/li&gt;
&lt;li&gt;Installa tutte le librerie ed applicazioni necessarie per installare il VPN Server.&lt;/li&gt;
&lt;li&gt;Configura correttamente le impostazioni che decidiamo noi per la VPN, per esempio l’utente per accedervi.&lt;/li&gt;
&lt;li&gt;Imposta l’aggiornamento automatico dei certificati in base al rinnovo del certificato di Let’s Encrypt.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Di tutti questi task &lt;strong&gt;possiamo trovare due ruoli ben distinti&lt;/strong&gt; che possono essere separati.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;La generazione e il mantenimento dei certificati&lt;/strong&gt; per &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt; usando Let’s Encrypt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Installazione della VPN&lt;/strong&gt; che utilizza i certificati precedentemente creati.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Che vantaggi porta separare i task trovati in questi due ruoli?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Più i ruoli sono autocontenuti e specifici, più sono semplici da mantenere.&lt;/li&gt;
&lt;li&gt;Più sono autocontenuti più è facile riutilizzarli per altri playbook.&lt;/li&gt;
&lt;li&gt;Se il ruolo definito è abbastanza standard, è facile che qualcuno lo abbia già implementato!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Infatti &lt;strong&gt;Ansible ha un sito per cercare questi ruoli: si chiama &lt;a href=&quot;https://galaxy.ansible.com/&quot;&gt;Ansible Galaxy&lt;/a&gt;&lt;/strong&gt;. La generazione dei certificati tramite Let’s Encrypt è una cosa abbastanza standard, ed infatti siamo fortunati! Abbiamo un ruolo che fa già quello che ci interessa, &lt;a href=&quot;https://galaxy.ansible.com/geerlingguy/certbot&quot;&gt;lo possiamo trovare qui&lt;/a&gt;, il modo migliore per imparare ad usarlo è comunque guardare &lt;a href=&quot;https://github.com/geerlingguy/ansible-role-certbot&quot;&gt;il suo repository su GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Per installare il ruolo, per poterlo utilizzare fra poco, scriviamo in console:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ansible-galaxy &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; geerlingguy.certbot&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cercando sempre su quel sito non ho trovato un ruolo che crei la VPN, quindi per quello dobbiamo arrangiarci.&lt;/p&gt;
&lt;h2&gt;Definiamo il Playbook&lt;/h2&gt;
&lt;p&gt;Abbiamo detto che i moduli e i task sono la parte atomica di Ansible, questi sono raggruppati in ruoli che svolgono una determinata funzione (nel nostro caso sono due), &lt;strong&gt;l’entità che orchestra questi ruoli è il playbook&lt;/strong&gt;.
Se volessimo raffigurarlo in un grafico:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;playbook
  ruoli
    tasks&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Per creare la configurazione della nostra VPN adottiamo un approccio &lt;a href=&quot;https://it.wikipedia.org/wiki/Progettazione_top-down_e_bottom-up&quot;&gt;top-down&lt;/a&gt;&lt;/strong&gt;. In altre parole iniziamo a lavorare sulla parte più “esterna” e generale al problema, per poi entrare sempre più nel dettaglio fino ai vari task. La parte che contiene tutte le altre è il &lt;strong&gt;playbook&lt;/strong&gt;.
Il nostro playbook deve far partire in sequenza:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il ruolo che genera i certificati. Già implementato grazie alla libreria che abbiamo trovato su &lt;a href=&quot;https://galaxy.ansible.com/&quot;&gt;Ansible Galaxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Il ruolo che installa la VPN. Dobbiamo implementarlo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ansible lavora molto sulle convenzioni, iniziamo fin da subito ad utilizzare le &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html&quot;&gt;best practices&lt;/a&gt; fornite da Ansible.&lt;/p&gt;
&lt;p&gt;Possiamo prendere come riferimento la mia repository con il playbook finalizzato. La struttura per creare il nostro playbook è il seguente:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;group_vars/
  vpns.yml           &lt;span class=&quot;token comment&quot;&gt;# Qui vanno tutte le variabili a livello di gruppo (il nostro gruppo si chiama vpns)&lt;/span&gt;
   
host_vars/
   rpi.yml           &lt;span class=&quot;token comment&quot;&gt;# Qui assegnamo le variabili per le singole macchine (l&apos;unica nostra macchina si chiama rpi)&lt;/span&gt;

vpn.yml              &lt;span class=&quot;token comment&quot;&gt;# Questo è il nostro playbook&lt;/span&gt;
hosts                &lt;span class=&quot;token comment&quot;&gt;# È il nostro inventory, definiamo i gruppi (vpns) e le macchine (rpi) su cui vogliamo eseguire il playbook.&lt;/span&gt;

roles/               &lt;span class=&quot;token comment&quot;&gt;# Questa cartella contiene tutti i ruoli che andremo a definire&lt;/span&gt;
    vpn&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;install/     &lt;span class=&quot;token comment&quot;&gt;# Questa cartella contiene il nostro ruolo per installare la VPN.&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;            &lt;span class=&quot;token comment&quot;&gt;# La struttura delle sottocartelle la vedremo più avanti.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Iniziamo a scrivere il nostro playbook nel file &lt;code class=&quot;language-text&quot;&gt;vpn.yml&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy IKEv2 Road Warrior VPN
  &lt;span class=&quot;token key atrule&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; vpns

  &lt;span class=&quot;token key atrule&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; geerlingguy.certbot
      &lt;span class=&quot;token key atrule&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yes
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; vpn&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;install
      &lt;span class=&quot;token key atrule&quot;&gt;become&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yes&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il formato con cui viene scritto il file è &lt;a href=&quot;https://it.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt;, è un formato molto leggibile ed è ormai uno standard de facto negli applicativi che strizzano l’occhio ai DevOps. &lt;a href=&quot;https://learnxinyminutes.com/docs/yaml/&quot;&gt;Se non lo avete mai visto vi consiglio di leggere questa guida, che spiega velocemente il formato&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Il nostro Playbook dovrà fare solo una cosa: creare un VPN Server. Nel gerco di Ansible, un playbook è formato da più &lt;strong&gt;plays&lt;/strong&gt;. Noi abbiamo un solo &lt;em&gt;play&lt;/em&gt; nel nostro playbook.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Come si fa a capire come e quando creare un play?&lt;/strong&gt; Solitamente se abbiamo &lt;em&gt;più ruoli&lt;/em&gt; che influenzano &lt;em&gt;un unico gruppo&lt;/em&gt; di macchine, allora questo è un buon candidato per essere un play. Se invece avessimo avuto &lt;em&gt;dei ruoli&lt;/em&gt; che avevano come target il &lt;em&gt;Raspberry&lt;/em&gt; ed &lt;em&gt;altri ruoli&lt;/em&gt; che dovevano configurare &lt;em&gt;dei routers&lt;/em&gt;, allora il nostro playbook sarebbe composto da due plays. Perché un play andava a lavorare sui Raspberry Pi, l’altro sui routers.&lt;/p&gt;
&lt;p&gt;Spieghiamo i vari comandi che ci sono dentro ad un play:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;name&lt;/code&gt;: possiamo inserire una breve descrizione di cosa farà il nostro play.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;hosts&lt;/code&gt;: definiamo quale gruppo verrà utilizzato come target del nostro play. Nel nostro caso è il gruppo &lt;code class=&quot;language-text&quot;&gt;vpn&lt;/code&gt;, che al suo interno avrà il nostro Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;roles&lt;/code&gt;: definiamo i ruoli in ordine cronologico che verranno avviati sui nostri hosts.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;role: geerlingguy.certbot&lt;/code&gt;: il primo ruolo che verrà avviato sarà quello che abbiamo trovato in &lt;a href=&quot;https://galaxy.ansible.com/&quot;&gt;Ansible Galaxy&lt;/a&gt;, esso installerà e manterrà aggiornati i certificati per la VPN.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;become: yes&lt;/code&gt;: significa che verrà avviato lo script abilitando il &lt;em&gt;priviledge escalation&lt;/em&gt;. In pratica avvieremo il ruolo come root. Sia il ruolo per scaricare i certificati, sia l’installazione della VPN ha bisogno di essere avviato come root. Quindi in entrambi metteremo &lt;code class=&quot;language-text&quot;&gt;become: yes&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;role: vpn-install&lt;/code&gt;: avviamo l’installazione della VPN dopo il ruolo dei certificati. Questo ruolo dobbiamo ancora capire come definirlo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il playbook lo abbiamo ultimato. In pratica il nostro playbook sta dicendo questa cosa: “Installa i certificati e poi installa la VPN sulle macchine che fanno parte del gruppo &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt;“.&lt;/p&gt;
&lt;h2&gt;Definiamo l’inventario&lt;/h2&gt;
&lt;p&gt;Abbiamo detto che il playbook lavorerà sul gruppo di macchine denominato &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt;. Ma dove è definito questo gruppo? Qui entra in gioco &lt;strong&gt;l’inventario&lt;/strong&gt;. L’oggetto inventario è dove definiamo i gruppi di macchine e le macchine che compongono questo gruppo.
Il file che contiene questo inventario è il file &lt;code class=&quot;language-text&quot;&gt;hosts&lt;/code&gt;. Il nome è arbitrario, qualsiasi nome gli diamo poi dovrà essere richiamato quando invocheremo il comando per far partire il playbook.&lt;/p&gt;
&lt;p&gt;Il nostro file hosts avrà questo contenuto.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ini&quot;&gt;&lt;pre class=&quot;language-ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;vpns&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
rpi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Semplicemente con queste due righe stiamo dicendo che il gruppo &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; contiene la macchina &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt; che è il nome che stiamo dando al nostro Raspberry Pi. È facile intuire che se avessimo avuto più Raspberry Pi, potevamo configurarli contemporaneamente definendoli in questo file nel gruppo &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La sintassi dell’inventario è semplice ed è questa&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ini&quot;&gt;&lt;pre class=&quot;language-ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;gruppo1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
macchina1
macchina2

&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;gruppo2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
macchina3
macchina4

...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Definiamo le variabili di gruppo e di host&lt;/h2&gt;
&lt;p&gt;Abbiamo definito il playbook che lavora sul gruppo &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt;, abbiamo dichiarato il gruppo &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; dicendo che al suo interno ha il nostro Raspberry Pi con il nome &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt; tramite l’inventario. Ma &lt;strong&gt;Ansible come fa a sapere come connettersi al nostro Raspberry Pi?&lt;/strong&gt; Come gli forniamo l’IP, utente, password per connettersi con SSH? Come gli diciamo su quale dominio vogliamo ottenere i certificati? Per ora sa solo che c’è una macchina chiamata &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Tutte queste cose sono delle &lt;strong&gt;variabili&lt;/strong&gt;, variano in base alla macchina o al gruppo di macchine su cui vogliamo agire. Ansible ha due cartelle adibite a questo scopo, una cartella chiamata &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; conterrà le variabili che sono comuni a tutte le macchine che appartengono ad un gruppo, la cartella &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt; conterrà tutte le variabili che sono proprie ad una singola macchina.&lt;/p&gt;
&lt;p&gt;Nel nostro progetto possiamo inserire queste due cartelle, queste cartelle avranno dei file YAML che avranno il nome del nostro gruppo in &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; e il nome &lt;code class=&quot;language-text&quot;&gt;rpi.yml&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Quindi la struttura delle nostre cartelle, per quanto riguarda le variabili è il seguente:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;group_vars/
  vpns.yml           &lt;span class=&quot;token comment&quot;&gt;# Contiene tutte le variabili comuni a tutte le macchine che appartengono al gruppo vpns&lt;/span&gt;
   
host_vars/
   rpi.yml           &lt;span class=&quot;token comment&quot;&gt;# Contiene tutte le variabili che appartengono alla macchina rpi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All’interno del file &lt;code class=&quot;language-text&quot;&gt;rpi.yml&lt;/code&gt; definito nella cartella &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt;, Ansible potrà trovare tutte le informazioni di cui necessita per portare a termine il playbook. Il file &lt;code class=&quot;language-text&quot;&gt;rpi.yml&lt;/code&gt; contiene le seguenti variabili:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;ansible_host&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; YOUR&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;SSH&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;HOST
&lt;span class=&quot;token key atrule&quot;&gt;ansible_user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pi
&lt;span class=&quot;token key atrule&quot;&gt;ansible_password&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; YOUR&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;SSH&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;PASSWORD
&lt;span class=&quot;token key atrule&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; casamia.mattianatali.it
&lt;span class=&quot;token comment&quot;&gt;# You can add more than one Road Warrior Client.&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;vpn_users&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CLIENT&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;WARRIOR&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;USERNAME
    &lt;span class=&quot;token key atrule&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; CLIENT&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;WARRIOR&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;PASSWORD
&lt;span class=&quot;token comment&quot;&gt;# Change it if you want to restrict the local hosts the Road Warrior Client should see.&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;vpn_local_ts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0.0.0.0/0&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# ansible-role-certbot variables&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# More info here https://github.com/geerlingguy/ansible-role-certbot&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;certbot_auto_renew&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;certbot_create_if_missing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;certbot_create_method&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; standalone
&lt;span class=&quot;token key atrule&quot;&gt;certbot_auto_renew_user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; root
&lt;span class=&quot;token key atrule&quot;&gt;certbot_auto_renew_hour&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;certbot_auto_renew_minute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;certbot_auto_renew_options&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;--quiet --no-self-upgrade&quot;&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;certbot_create_standalone_stop_services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token key atrule&quot;&gt;certbot_certs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; YOUR&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;EMAIL&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;HERE
    &lt;span class=&quot;token key atrule&quot;&gt;domains&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{{domain}}&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Tramite le variabili &lt;code class=&quot;language-text&quot;&gt;ansible_host&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;ansible_user&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;ansible_password&lt;/code&gt; possiamo fornire ad Ansible tutte le informazioni per connettersi ad SSH, per eseguire il nostro playbook.
Possiamo evitare di inserire nome utente e password usando le configurazioni di SSH. &lt;a href=&quot;come-essere-produttivi-con-il-terminale/&quot;&gt;In questa guida, nella sezione SSH, spiego come fare&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I campi successivi sono quelli che utilizzeremo quando andremo a creare il ruolo per installare la VPN. Il campo &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; conterrà il nome del nostro dominio che punta a casa nostra, nel nostro caso è &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt;. In &lt;code class=&quot;language-text&quot;&gt;vpn_users&lt;/code&gt; definiamo l’username e password dei clienti che possono connettersi alla nostra VPN. &lt;code class=&quot;language-text&quot;&gt;vpn_local_ts&lt;/code&gt; è una variabile che ci permette di limitare l’accesso ai clienti che si connettono alla VPN, per esempio a casa mia ho limitato alla mia sottorete &lt;code class=&quot;language-text&quot;&gt;192.168.1.0/24&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Tutte le variabili che iniziano con &lt;code class=&quot;language-text&quot;&gt;certbot_&lt;/code&gt; fanno parte del ruolo che abbiamo scaricato con Ansible Galaxy, ci permettono di configurare qualsiasi cosa riguardo l’aggiornamento dei certificati per il dominio &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt;. Trovare le variabili che compongono il ruolo che abbiamo scaricato è semplice, &lt;a href=&quot;https://github.com/geerlingguy/ansible-role-certbot&quot;&gt;basta leggere la documentazione del ruolo che abbiamo utilizzato&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Possiamo notare che l’ultima riga del nostro file ha una variabile particolare &lt;code class=&quot;language-text&quot;&gt;{{domain}}&lt;/code&gt;. &lt;strong&gt;Le doppie graffe ci permettono di richiamare un’altra variabile già definita&lt;/strong&gt;. In questo modo possiamo definire solo la variabile &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; nella quarta riga, che automaticamente la variabile &lt;code class=&quot;language-text&quot;&gt;{{domain}}&lt;/code&gt; avrà lo stesso valore. Così facendo abbiamo &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_source_of_truth&quot;&gt;“una singola sorgente di verità”&lt;/a&gt; ed evitiamo errori grossolani tipo aggiornare solo una variabile e non l’altra.&lt;/p&gt;
&lt;p&gt;Per inserire i valori nelle doppie graffe, Ansible utilizza un template engine molto famoso in Python: &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html&quot;&gt;Jinja2&lt;/a&gt;. Jinja2 è molto potente, per ora ci basta sapere che quando scriviamo &lt;code class=&quot;language-text&quot;&gt;{{valore}}&lt;/code&gt; significa che stiamo inserendo il contenuto della variabile che troviamo nelle parentesi.&lt;/p&gt;
&lt;h2&gt;Implementiamo il ruolo per installare la VPN&lt;/h2&gt;
&lt;p&gt;Abbiamo definito il playbook, l’inventario, le variabili e il ruolo per installare i certificati che abbiamo trovato su Ansible Galaxy; ora &lt;strong&gt;ci manca da implementare il ruolo che installa il VPN server sul Raspberry Pi&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I ruoli vengono definiti nella cartella &lt;code class=&quot;language-text&quot;&gt;roles/&lt;/code&gt;, creiamo una cartella al suo interno che prenderà il nome del ruolo (&lt;code class=&quot;language-text&quot;&gt;vpn-install&lt;/code&gt;), lo stesso nome che abbiamo definito nel playbook in &lt;code class=&quot;language-text&quot;&gt;vpn.yml&lt;/code&gt;.
La struttura delle nostre cartelle sarà definita così:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
roles/    
    vpn&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;install/
        files/        &lt;span class=&quot;token comment&quot;&gt;# Contiene i file da copiare sul Raspberry Pi&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
        tasks/        &lt;span class=&quot;token comment&quot;&gt;# Contiene le istruzioni da eseguire&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
        templates/    &lt;span class=&quot;token comment&quot;&gt;# Contiene i template sorgenti per poi caricare sul Raspberry Pi&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;      &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Anche in questo caso &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#directory-layout&quot;&gt;stiamo usando le convenzioni di Ansible&lt;/a&gt;, non ci stiamo inventando nulla:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;files&lt;/em&gt;: contiene tutti i file che dobbiamo caricare sul Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;tasks&lt;/em&gt;: contiene i task da eseguire sul Raspberry Pi per installare la VPN.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;templates&lt;/em&gt;: è simile alla cartella files, ma in questo caso non avremo i file da copiare, bensì un template che dobbiamo renderizzare prima di poterlo copiare sul Raspberry Pi. Aspettiamo ancora un attimo e poi il suo utilizzo sarà chiaro.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Definiamo i task&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Ora ci focalizziamo sulla cartella &lt;em&gt;tasks&lt;/em&gt;&lt;/strong&gt;, come abbiamo detto qui avremo tutti i comandi da eseguire sul Raspberry Pi per installare la VPN.
Il primo file che Ansible cerca nella cartella tasks è il &lt;code class=&quot;language-text&quot;&gt;main.yml&lt;/code&gt;. In questo file scriviamo tutti i task.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Come sappiamo quali task eseguire?&lt;/strong&gt; Qui dobbiamo recuperare i comandi che abbiamo eseguito manualmente all’inizio dell’articolo. Una volta recuperati li dobbiamo tradurre in task, utilizzando i &lt;strong&gt;moduli&lt;/strong&gt; che ci fornisce Ansible.&lt;/p&gt;
&lt;p&gt;Questi sono i “comandi” che dobbiamo tradurre in task Ansible, prendeteli per buoni, non voglio annoiarvi troppo sulla questione VPN:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Installa i seguenti pacchetti usando &lt;code class=&quot;language-text&quot;&gt;apt-get&lt;/code&gt;: &lt;code class=&quot;language-text&quot;&gt;strongswan&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;strongswan-swanctl&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;libstrongswan-standard-plugins&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;libstrongswan-extra-plugins&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;libcharon-extra-plugins&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Attivare &lt;a href=&quot;http://www.ducea.com/2006/08/01/how-to-enable-ip-forwarding-in-linux/&quot;&gt;l’Ip-Forwarding&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Aggiungere il file con la configurazione VPN in &lt;code class=&quot;language-text&quot;&gt;/etc/swanctl/swanctl.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Aggiungere il file con i vari plugin di Strongswan in &lt;code class=&quot;language-text&quot;&gt;/etc/strongswan.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Creare le cartelle &lt;code class=&quot;language-text&quot;&gt;x509&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;x509ca&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;private&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;/etc/swanctl/&lt;/code&gt;, qui aggiungeremo i vari certificati creati dal ruolo precedente che abbiamo trovato su Ansible Galaxy.&lt;/li&gt;
&lt;li&gt;Copiare i certificati creati dal ruolo che li crea dalla cartella &lt;code class=&quot;language-text&quot;&gt;/etc/letsencrypt/live/casamia.mattianatali.it/&lt;/code&gt; nelle cartelle corrette create nel punto precedente.&lt;/li&gt;
&lt;li&gt;Aggiungere uno script che ripete il punto precedente ogni volta che i certificati vengono aggiornati. I certificati di &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let’s Encrypt&lt;/a&gt; durano solo 3 mesi.&lt;/li&gt;
&lt;li&gt;Aggiungere un &lt;a href=&quot;https://it.wikipedia.org/wiki/Crontab&quot;&gt;cronjob&lt;/a&gt; che esegue il punto precedente subito dopo la generazione dei certificati.&lt;/li&gt;
&lt;li&gt;Abilitare &lt;a href=&quot;https://it.wikipedia.org/wiki/Network_address_translation#IP_masquerading_o_PAT_(Port_Address_Translation)&quot;&gt;l’IP Masquerading&lt;/a&gt;, cambiando le regole del firewall del Raspberry Pi.&lt;/li&gt;
&lt;li&gt;Riavviare il Raspberry Pi.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Queste sono tutte le operazioni che dobbiamo automatizzare per avere la nostra VPN funzionante sul Raspberry Pi. &lt;strong&gt;Le operazioni sono tante, alcune complesse, noiose da fare manualmente, la possibilità di errore è alta, i comandi sono praticamente impossibili da ricordare a memoria per una futura configurazione&lt;/strong&gt;. Forse ora capite perché ho subito pensato ad Ansible quando mi sono cimentato in questa impresa!&lt;/p&gt;
&lt;p&gt;Con Ansible possiamo fare tutto questo con poche righe di codice e con una chiarezza disarmante. Il risultato finale del nostro file &lt;code class=&quot;language-text&quot;&gt;main.yml&lt;/code&gt;, che include tutti i nostri comandi è il seguente. Ho aggiunto dei commenti nel file così da avere la giusta corrispondenza coi punti scritti appena sopra:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Installa i seguenti pacchetti usando `apt-get`: `strongswan`, `strongswan-swanctl`, `libstrongswan-standard-plugins`, `libstrongswan-extra-plugins`, `libcharon-extra-plugins`.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install strongswan dependencies
  &lt;span class=&quot;token key atrule&quot;&gt;apt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; strongswan
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; strongswan&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;swanctl
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; libstrongswan&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;standard&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;plugins
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; libstrongswan&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;extra&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;plugins
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; libcharon&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;extra&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;plugins

&lt;span class=&quot;token comment&quot;&gt;# Attivare l&apos;Ip-Forwarding.&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add Client Traffic Forwarding
  &lt;span class=&quot;token key atrule&quot;&gt;sysctl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{{ item }}&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;with_items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; net.ipv4.ip_forward
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; net.ipv6.conf.all.forwarding

&lt;span class=&quot;token comment&quot;&gt;# Aggiungere il file con la configurazione VPN in /etc/swanctl/swanctl.conf&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add VPN configuration
  &lt;span class=&quot;token key atrule&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; templates/swanctl.conf.j2
    &lt;span class=&quot;token key atrule&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/swanctl/swanctl.conf

&lt;span class=&quot;token comment&quot;&gt;# Aggiungere il file con i vari plugin di Strongswan in /etc/strongswan.conf&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add strongswan.conf with correct plugins
  &lt;span class=&quot;token key atrule&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; files/strongswan.conf
    &lt;span class=&quot;token key atrule&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/strongswan.conf

&lt;span class=&quot;token comment&quot;&gt;# Creare le cartelle x509, x509ca, private in /etc/swanctl/&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Create folders to store certificates
  &lt;span class=&quot;token key atrule&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/swanctl/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; directory
    &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0755&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;with_items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; x509
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; x509ca
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; private

&lt;span class=&quot;token comment&quot;&gt;# Copiare i certificati creati dal ruolo che li crea dalla cartella /etc/letsencrypt/live/casamia.mattianatali.it/ nelle cartelle corrette create nel punto precedente&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Notare l&apos;uso della variabile domain per inserire casamia.mattianatali.it&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Copy certificates from let&apos;s encrypt to strongswan
  &lt;span class=&quot;token key atrule&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt;      &lt;span class=&quot;token comment&quot;&gt;# In YAML il &quot;|&quot; significa &quot;prendi tutto quello che scrivo dopo come una variabile e preserva i ritorni a capo&quot;&lt;/span&gt;
    cp /etc/letsencrypt/live/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; domain &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/chain.pem /etc/swanctl/x509ca/
    cp /etc/letsencrypt/live/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; domain &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/privkey.pem /etc/swanctl/private/
    cp /etc/letsencrypt/live/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; domain &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;/fullchain.pem /etc/swanctl/x509/

&lt;span class=&quot;token comment&quot;&gt;# Aggiungere uno script che ripete il punto precedente ogni volta che i certificati vengono aggiornati&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add script to copy new certificate
  &lt;span class=&quot;token key atrule&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; templates/renew&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;certs.sh.j2
    &lt;span class=&quot;token key atrule&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /root/renew&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;certs.sh
    &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; u=rwx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;g=r&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;o=r

&lt;span class=&quot;token comment&quot;&gt;# Aggiungere un cronjob che esegue il punto precedente subito dopo la generazione dei certificati&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add cronjob to copy new certs
  &lt;span class=&quot;token key atrule&quot;&gt;cron&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Copy certs to strongswan
    &lt;span class=&quot;token key atrule&quot;&gt;hour&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{{ certbot_auto_renew_hour }}&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;minute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{{ certbot_auto_renew_minute + 15 }}&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/root/renew-certs.sh&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Abilitare l&apos;IP Masquerading]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add iptable rule permanently
  &lt;span class=&quot;token key atrule&quot;&gt;lineinfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/rc.local
    &lt;span class=&quot;token key atrule&quot;&gt;line&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; iptables &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;t nat &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;A POSTROUTING &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;o eth0 &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;j MASQUERADE
    &lt;span class=&quot;token key atrule&quot;&gt;insertbefore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ^exit 0

&lt;span class=&quot;token comment&quot;&gt;# Riavviare il Raspberry Pi&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Finished&lt;span class=&quot;token tag&quot;&gt;!&lt;/span&gt; Rebooting the system&lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
  reboot&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Possiamo subito notare che &lt;strong&gt;i tasks hanno tutti la seguente struttura&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; DESCRIZIONE DEL TASK
  &lt;span class=&quot;token key atrule&quot;&gt;NOME_MODULO&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;OPZIONE_1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; VALORE_OPZIONE_1
    &lt;span class=&quot;token key atrule&quot;&gt;OPZIONE_2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; VALORE_OPZIONE_2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/modules_by_category.html&quot;&gt;I moduli forniti da Ansible sono tantissimi&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I moduli che ho utilizzato in questo ruolo sono i seguenti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/apt_module.html&quot;&gt;&lt;em&gt;apt&lt;/em&gt;&lt;/a&gt;: per installare i pacchetti usando il comando &lt;code class=&quot;language-text&quot;&gt;apt-get&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/sysctl_module.html&quot;&gt;&lt;em&gt;sysctl&lt;/em&gt;&lt;/a&gt;: per modificare il file &lt;code class=&quot;language-text&quot;&gt;sysctl.conf&lt;/code&gt; e quindi modificare gli attributi del kernel di sistema. Nel nostro caso è servito per abilitare l’IP Forwarding.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/template_module.html&quot;&gt;&lt;em&gt;template&lt;/em&gt;&lt;/a&gt;: per processare un file usando il template engine Jinja2, e copiare il risultato sul Raspberry Pi. &lt;strong&gt;Abbiamo bisogno di Jinja2 per inserire un file che sia dinamico in base alle variabili dell’host e del gruppo su cui stiamo lavorando&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/copy_module.html&quot;&gt;&lt;em&gt;copy&lt;/em&gt;&lt;/a&gt;: per copiare un file da una cartella locale sul nostro Raspberry Pi, in questo caso non abbiamo bisogno di Jinja2 per inserire delle variabili.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/file_module.html&quot;&gt;&lt;em&gt;file&lt;/em&gt;&lt;/a&gt;: per lavorare con i file e le cartelle sul Raspberry Pi, per esempio modificare dei permessi, creare o eliminare cartelle ecc.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/shell_module.html&quot;&gt;&lt;em&gt;shell&lt;/em&gt;&lt;/a&gt;: per eseguire dei comandi classici tramite la cli sulla macchina di destinazione.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/cron_module.html&quot;&gt;&lt;em&gt;cron&lt;/em&gt;&lt;/a&gt;: per modificare il file &lt;a href=&quot;https://it.wikipedia.org/wiki/Crontab&quot;&gt;crontab&lt;/a&gt; sulla macchina.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/lineinfile_module.html&quot;&gt;&lt;em&gt;lineinfile&lt;/em&gt;&lt;/a&gt;: per verificare che esista una linea specifica in un determinato file.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;(https://docs.ansible.com/ansible/latest/modules/reboot_module.html)&quot;&gt;&lt;em&gt;reboot&lt;/em&gt;&lt;/a&gt;: per riavviare il Raspberry Pi a fine di tutto.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le opzioni dei vari moduli sono abbastanza esplicativi, in ogni caso se qualcuno non è chiaro potete leggere la documentazione dei singoli moduli. I nomi dei moduli, nella lista precedente, puntano tutti alla guida di riferimento.&lt;/p&gt;
&lt;p&gt;Ci sono alcuni però che meritano una descrizione più approfondita: per esempio il task&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Creare le cartelle x509, x509ca, private in /etc/swanctl/&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Create folders to store certificates
  &lt;span class=&quot;token key atrule&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/swanctl/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; item &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; directory
    &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0755&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;with_items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; x509
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; x509ca
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; private&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;sono tre tasks in uno, &lt;strong&gt;grazie a &lt;code class=&quot;language-text&quot;&gt;with_items&lt;/code&gt; si può definire una lista di variabili e poi, tramite &lt;code class=&quot;language-text&quot;&gt;{{ item }}&lt;/code&gt;, è possibile eseguire il modulo per ogni elemento in lista&lt;/strong&gt;. Quindi nel caso precedente è come se avessimo scritto:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Creare le cartelle x509, x509ca, private in /etc/swanctl/&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Create folder x509
  &lt;span class=&quot;token key atrule&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/swanctl/x509
    &lt;span class=&quot;token key atrule&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; directory
    &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0755&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Create folder x509ca
  &lt;span class=&quot;token key atrule&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/swanctl/x509ca
    &lt;span class=&quot;token key atrule&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; directory
    &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0755&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Create folder private
  &lt;span class=&quot;token key atrule&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/swanctl/private
    &lt;span class=&quot;token key atrule&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; directory
    &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0755&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Vedendo il tag &lt;code class=&quot;language-text&quot;&gt;{{ item }}&lt;/code&gt; possiamo intuire che il nostro file &lt;code class=&quot;language-text&quot;&gt;main.yml&lt;/code&gt; viene processato con &lt;a href=&quot;https://jinja.palletsprojects.com/en/2.10.x/&quot;&gt;Jinja2&lt;/a&gt; prima di essere eseguito. Infatti &lt;strong&gt;nel nostro file per definire i tasks possiamo fare riferimento a tutte le variabili degli hosts e dei gruppi precedentemente dichiarati&lt;/strong&gt;. Per esempio il task:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add cronjob to copy new certs
  &lt;span class=&quot;token key atrule&quot;&gt;cron&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Copy certs to strongswan
    &lt;span class=&quot;token key atrule&quot;&gt;hour&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{{ certbot_auto_renew_hour }}&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;minute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;{{ certbot_auto_renew_minute + 15 }}&quot;&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/root/renew-certs.sh&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Utilizza le variabili &lt;code class=&quot;language-text&quot;&gt;certbot_auto_renew_hour&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;certbot_auto_renew_minute&lt;/code&gt;. Jinja2 è molto potente e ci permette anche di fare operazioni con le variabili. Con questo task stiamo essenzialmente dicendo “esegui il comando &lt;code class=&quot;language-text&quot;&gt;/root/renew-certs.sh&lt;/code&gt; 15 minuti dopo il task che genera i certificati”. Questo è possibile grazie all’operazione &lt;code class=&quot;language-text&quot;&gt;{{ certbot_auto_renew_minute + 15 }}&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Il modulo template&lt;/h4&gt;
&lt;p&gt;Merita una spiegazione aggiuntiva il modulo template dato che è molto potente. Abbiamo detto che il modulo template permette di inserire un file processato con Jinja2 nella macchina di destinazione.
Per esempio noi lo abbiamo usato per il task:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add script to copy new certificate
  &lt;span class=&quot;token key atrule&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; templates/renew&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;certs.sh.j2
    &lt;span class=&quot;token key atrule&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /root/renew&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;certs.sh
    &lt;span class=&quot;token key atrule&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; u=rwx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;g=r&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;o=r&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In questo caso prendiamo il file &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/blob/master/roles/vpn-install/templates/renew-certs.sh.j2&quot;&gt;templates/renew-certs.sh.j2&lt;/a&gt;, Jinja2 sostituisce le variabili che trova usando quelle che abbiamo definito nelle cartelle &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt; e poi lo inserisce nella cartella &lt;code class=&quot;language-text&quot;&gt;/root/renew-certs.sh&lt;/code&gt; sul Raspberry Pi &lt;a href=&quot;https://it.wikipedia.org/wiki/Permessi_(Unix)&quot;&gt;settando i permessi a &lt;code class=&quot;language-text&quot;&gt;744&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Vediamo velocemente il contenuto del template:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jinja2&quot;&gt;&lt;pre class=&quot;language-jinja2&quot;&gt;&lt;code class=&quot;language-jinja2&quot;&gt;#!/bin/sh -
cp /etc/letsencrypt/live/&lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;domain&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;/chain.pem /etc/swanctl/x509ca/
cp /etc/letsencrypt/live/&lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;domain&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;/privkey.pem /etc/swanctl/private/
cp /etc/letsencrypt/live/&lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;domain&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;/fullchain.pem /etc/swanctl/x509/
/usr/sbin/swanctl --load-all&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;nel nostro caso &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; verrà sostituito da &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt; prima di essere copiato sul Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Un template ancora più complesso possiamo trovarlo con il task&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yml&quot;&gt;&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Aggiungere il file con la configurazione VPN in /etc/swanctl/swanctl.conf&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add VPN configuration
  &lt;span class=&quot;token key atrule&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; templates/swanctl.conf.j2
    &lt;span class=&quot;token key atrule&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; /etc/swanctl/swanctl.conf&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In questo caso &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/blob/master/roles/vpn-install/templates/swanctl.conf.j2&quot;&gt;templates/swanctl.conf.j2&lt;/a&gt; contiene:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;jinja2&quot;&gt;&lt;pre class=&quot;language-jinja2&quot;&gt;&lt;code class=&quot;language-jinja2&quot;&gt;connections {
    ikev2-eap {
        version = 2
        proposals = aes192gcm16-aes128gcm16-prfsha256-ecp256-ecp521,aes192-sha256-modp3072,default
        rekey_time = 0s
        pools = primary-pool-ipv4
        fragmentation = yes
        dpd_delay = 30s
        send_cert = always
        # dpd_timeout doesn&apos;t do anything for IKEv2. The general IKEv2 packet timeouts are used.
        local-1 {
            auth = pubkey
            certs = fullchain.pem
            id = &lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;domain&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
        }
        remote-1 {
            auth = eap-mschapv2
            # go ask the client for its eap identity.
            eap_id = %any
        }
        children {
            ikev2-eap {
                local_ts = &lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;vpn_local_ts&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;,
                rekey_time = 0s
                dpd_action = clear
                esp_proposals = aes192gcm16-aes128gcm16-prfsha256-ecp256-modp3072,aes192-sha256-ecp256-modp3072,default
            }
        }
    }
}

pools {
    primary-pool-ipv4 {
        addrs = 172.16.252.0/24
        dns = 8.8.8.8, 8.8.4.4
        split_exclude = 172.16.0.0/12
    }
}

secrets {
  &lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;token tag keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;vpn_users&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;%}&lt;/span&gt;&lt;/span&gt;
   eap-&lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt; {
      id = &lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;
      secret = &quot;&lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;}}&lt;/span&gt;&lt;/span&gt;&quot;
   }
  &lt;span class=&quot;token jinja2 language-jinja2&quot;&gt;&lt;span class=&quot;token delimiter punctuation&quot;&gt;{%&lt;/span&gt; &lt;span class=&quot;token tag keyword&quot;&gt;endfor&lt;/span&gt; &lt;span class=&quot;token delimiter punctuation&quot;&gt;%}&lt;/span&gt;&lt;/span&gt;
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Qui verranno sostituite le variabili &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;vpn_local_ts&lt;/code&gt;. Grazie al costrutto &lt;code class=&quot;language-text&quot;&gt;{% for user in vpn_users %}&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;{% endfor %}&lt;/code&gt; inseriamo gli username e password degli utenti presenti nella variabile &lt;code class=&quot;language-text&quot;&gt;vpn_users&lt;/code&gt; che abbiamo definito in nel file &lt;code class=&quot;language-text&quot;&gt;host_vars/rpi.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Immaginiamo ora di non avere un template engine e di dover far manualmente questa operazione… Non è per niente banale!
&lt;strong&gt;Grazie ad Ansible possiamo separare nettamente le variabili dal contenuto statico dei file, in questo modo possiamo rendere molto semplice la configurazione personalizzata su più macchine.&lt;/strong&gt;
Infatti il contenuto del ruolo rimarrebbe sempre uguale, quello che cambia è l’inventario, dove definiamo la nuova macchina da configurare e le sue variabili da utilizzare in &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Esecuzione del playbook&lt;/h2&gt;
&lt;p&gt;Abbiamo finalmente completato il nostro Playbook per creare un VPN sul nostro Raspberry Pi! &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/&quot;&gt;Il risultato finale lo potete trovare sulla mia repository&lt;/a&gt;. Ci manca solamente da eseguire il nostro playbook attraverso il comando&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ansible-playbook &lt;span class=&quot;token parameter variable&quot;&gt;-vv&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; hosts vpn.yml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Grazie a questo comando, avviamo il playbook definito in &lt;code class=&quot;language-text&quot;&gt;vpn.yml&lt;/code&gt; in modo verboso (&lt;code class=&quot;language-text&quot;&gt;-vv&lt;/code&gt;) passando l’inventario definito nel file hosts (&lt;code class=&quot;language-text&quot;&gt;-i hosts&lt;/code&gt;).
Vedremo che Ansible cercherà di connettersi tramite SSH al nostro Raspberry Pi ed eseguirà punto per punto i nostri task, usando tutte le variabili che abbiamo definito in &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt;.
In meno di 2 minuti avrà finito di fare il tutto e noi possiamo connetterci alla VPN mettendo come indirizzo del server e il suo id il dominio che abbiamo definito (nel mio caso &lt;code class=&quot;language-text&quot;&gt;casamia.mattianatali.it&lt;/code&gt;) e come username e password quelli inseriti nella variabile &lt;code class=&quot;language-text&quot;&gt;vpn_users&lt;/code&gt; nel file &lt;code class=&quot;language-text&quot;&gt;host_vars/rpi.yml&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1560px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3d702e71eb56b6a4bdb7cc6725edca22/298f8/vpn-mac-config.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 86.60000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAABYlAAAWJQFJUiTwAAADHUlEQVR42p2U2W7bSBBFnQCZbwjgkaxsGCBeJIraKLG5L+KilYkZWZEtb0H+JA82Eswn5GUA5QcDKATuVLUtx4nnaQhcdJNUn75dt6itLbryvv3icBrY49lMny8vxJIUJiPhhAmNicjyXGRZLucb5fOlWF58FIvTU/3o+IM9zvMXW5srdqyv2STFKMt/vH33HoezBZwghuWGMJ0A8XAqxfe216exj+xwjqPjM+SzxY/3ywuE8eDrHXBfaX3ThIumJopW14SmWwSMEA8mmNOi0fQQCQHTUYZ08AbRPEXT7aHR0qG2e0WHfr+vNL7dA6orzXHQ7Iji9UEdey0DHcOD4fgwyZUbxvCjFEE8QJgMYfohdMuT6pluYZHrWqO9+gXYFjraXaOoNzvYU3to066mG8hFXj9FPx2R4ykScskAww5owwDC9gsuj3IfWDtQV5ZmoEu7EZReauj0TLlAN112ga7hQBO2FN8TSIo2LGw/+tVhraasDAKRq6JLC6pqB20C8nH5iEE8lEeOBmMKZ0LjRJbB9ikgL/wPIDk0u+zQKZodHbtVVQLZIcOyfE6pznB8don5yRkWp+dIx5nchETA+DegQg6FAeH4xW61jr/2Du6AgmrIUOpLWUeuKzs3vVB2Arl8CDwgoCCgLvzi9W4drj8iGCVpe7JOXDM/GmB5/gEn55c4YafUThwGp/zQoaqs3CE5TOxiX68iPhrD6t+0BrmWwbDLs8uP8tgMdwnGTjnlBzVUurVV/tlA9rdTeJ+qyK8G8PIQvR732k3KG236j1PnhqbUH/ZhTVVX/bELI/KKWreBOJvACkNYUQAvTCjRGzm3rhjI8+H0LSdf+NEQSusesN7o/NNPJvRZZd8dL1774XBtuMHaSv01NfXaJxFYzimoNbmiebLOjxbryZt337kECjF+OiS7uuVTH5oFNy6NdBwaNQutngH+vjfi5zxG6RgEQxANCv6TUFrancPHT7e3sz/LlS/bpZ2r7VL5+k7l8nWpXLkulSp0vxlv3vHzSuXl9c7O86vKs1dfmMEsBj66nTwh/fE/9eSW8ehf2UbeSnS1eo8AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Configurazione della VPN sul mio Mac&quot;
        title=&quot;&quot;
        src=&quot;/static/3d702e71eb56b6a4bdb7cc6725edca22/298f8/vpn-mac-config.png&quot;
        srcset=&quot;/static/3d702e71eb56b6a4bdb7cc6725edca22/c6e3d/vpn-mac-config.png 500w,
/static/3d702e71eb56b6a4bdb7cc6725edca22/da8b6/vpn-mac-config.png 1000w,
/static/3d702e71eb56b6a4bdb7cc6725edca22/298f8/vpn-mac-config.png 1560w&quot;
        sizes=&quot;(max-width: 1560px) 100vw, 1560px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Alla fine ci manca di fare il port forwarding delle porte della VPN dal router al Raspberry Pi, questa parte non l’ho automatizzata con Ansible perché i router sono tutti diversi tra di loro, &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/blob/master/README.md&quot;&gt;se volete avere la VPN completa vi consiglio di leggere il README del mio repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusioni&lt;/h2&gt;
&lt;p&gt;Spero che questa guida vi abbia fornito delle linee guida su come automatizzare task anche complessi usando Ansible. Ho sorvolato di proposito parecchi punti che erano strettamente legati alla creazione della VPN, questo perché &lt;strong&gt;lo scopo della guida è di mostrarvi le potenzialità di Ansible con un esempio che non fosse il semplice “Hello World”&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Quello che &lt;strong&gt;deve essere chiaro è il modus operandi con cui siamo arrivati alla soluzione&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Proviamo la configurazione manualmente, registrando i passaggi.&lt;/li&gt;
&lt;li&gt;Definiamo eventuali ruoli del nostro procedimento. Cerchiamo su Ansible Galaxy se qualche ruolo è già stato fatto.&lt;/li&gt;
&lt;li&gt;Creiamo il playbook per dichiarare il procedimento completo.&lt;/li&gt;
&lt;li&gt;Per definire le macchine target, definiamo l’inventario e inseriamo tutte le variabili in &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;I task da eseguire li definiamo nel ruolo. I moduli ci aiuteranno nella definizione di questi task.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ansible si basa molto sulle convenzioni e best practices&lt;/strong&gt;. Questo è un vantaggio enorme perché se avete capito questo esempio, praticamente potete capire qualsiasi playbook di Ansible perché la struttura è sempre la stessa! &lt;a href=&quot;https://github.com/ansible/ansible-examples&quot;&gt;Provate a sfogliare i vari esempi che fornisce Ansible&lt;/a&gt;, ritroverete gli stessi concetti e cartelle in tutti.&lt;/p&gt;
&lt;p&gt;Una volta assimilato questi concetti, non importa se dobbiamo impostare una VPN, un’istanza ridondata di MongoDB, configurare l’NTP su 100 macchine, possiamo fare configurare tutto quello che vogliamo con Ansible in modo efficiente e chiaro.&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come sviluppare delle API in TDD con Spring Boot]]></title><description><![CDATA[In questo articolo abbiamo visto cosa significa sviluppare in Test Driven Development (TDD) e i pregi che ne derivano. L’esempio utilizzato…]]></description><link>https://www.mattianatali.it/it/come-sviluppare-rest-api-in-tdd-con-spring-boot/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-sviluppare-rest-api-in-tdd-con-spring-boot/</guid><pubDate>Tue, 30 Jul 2019 09:03:47 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;/it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero&quot;&gt;In questo articolo&lt;/a&gt; abbiamo visto cosa significa sviluppare in Test Driven Development (TDD) e i pregi che ne derivano. L’esempio utilizzato potrebbe sembrare un giochino fine a se stesso, ma il mio focus lì era di spiegare il TDD per chi proprio non ne aveva mai sentito parlare.&lt;/p&gt;
&lt;p&gt;In questa guida invece vediamo insieme un caso d’uso che ci sarà molto più familiare: lo sviluppo delle API RESTful. Per far ciò ho deciso di utilizzare il framework Spring Boot, il linguaggio scelto è Java.
Spring boot è molto utilizzato in ambito enterprise per creare un’architettura a microservizi. Anche &lt;a href=&quot;https://hub.packtpub.com/netflix-adopts-spring-boot-as-its-core-java-framework/&quot;&gt;Netflix lo utilizza&lt;/a&gt;. Inoltre Java è un linguaggio di programmazione ormai noto a tutti e quindi penso sia una buona scelta per vedere insieme un esempio pratico.&lt;/p&gt;
&lt;p&gt;Come sempre iniziamo completamente da zero, per non lasciare nulla al caso. Oltre al TDD, vedremo insieme anche come strutturare in modo corretto il progetto e altre librerie molto comode che uso ogni giorno per aumentare la nostra produttività, come per esempio la libreria &lt;a href=&quot;https://projectlombok.org/&quot;&gt;Lombok&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Requisiti&lt;/h2&gt;
&lt;p&gt;Il lettore che mi sto immaginando è uno &lt;strong&gt;sviluppatore che ha già sentito parlare di Spring Boot, non si spaventa se parliamo di API RESTful, ha voglia di utilizzare il TDD come driver principale di sviluppo ma che non riesce ad applicarlo in modo efficace&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Questo articolo &lt;strong&gt;è una continuazione della mia &lt;a href=&quot;/it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero&quot;&gt;prima puntata sul TDD&lt;/a&gt;&lt;/strong&gt;, quindi vi consiglio caldamente di leggere prima &lt;a href=&quot;/it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero&quot;&gt;“Come sviluppare in TDD partendo da zero”&lt;/a&gt;. Così avrete un’infarinatura iniziale sul TDD e siamo allineati su alcuni concetti che qui darò per scontato.&lt;/p&gt;
&lt;p&gt;La mia guida si basa su un sistema operativo UNIX-like (Mac OS X), ma può essere facilmente seguito anche da chi utilizza Windows.&lt;/p&gt;
&lt;p&gt;Sul nostro PC deve essere installato &lt;a href=&quot;https://www.oracle.com/technetwork/java/javase/downloads/jdk12-downloads-5295953.html&quot;&gt;Java Development Kit 12&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Obiettivo&lt;/h2&gt;
&lt;p&gt;Immaginiamo che dobbiamo creare due endpoint:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;GET - /api/v1/vehicles/{id}&lt;/code&gt;: per il recupero di un veicolo tramite id.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;POST - /api/v1/vehicles&lt;/code&gt;: per l’aggiunta di un veicolo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il veicolo è composto da queste proprietà&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;brand&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Ferrari&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;model&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;488 GTB&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;year&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il &lt;code class=&quot;language-text&quot;&gt;brand&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; sono obbligatori, l’anno di produzione del veicolo non può essere antecedente al &lt;code class=&quot;language-text&quot;&gt;1950&lt;/code&gt; per ragioni di business.&lt;/p&gt;
&lt;p&gt;Per ora non siamo interessati ad altri endpoint.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/matitalatina/tdd-spring-boot-api&quot;&gt;Potete trovare l’implementazione di questo piccolo progetto in questa mia repository pubblica&lt;/a&gt;, in questo modo se vi state perdendo potete ritrovare il filo del discorso direttamente leggendo il codice.&lt;/p&gt;
&lt;h2&gt;Creiamo il progetto&lt;/h2&gt;
&lt;p&gt;Ora che abbiamo le idee chiare su cosa dobbiamo fare, &lt;strong&gt;andiamo a generare il progetto&lt;/strong&gt;.
Il modo migliore per farlo è andando sul sito &lt;a href=&quot;https://start.spring.io/&quot;&gt;Spring Initializr&lt;/a&gt;. Da qui possiamo decidere quali librerie integrare, versione di Java ecc.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6ae2b6ad13e17749f5bf48be927cbb58/85fe6/spring-initializr.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 67.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAACKklEQVR42pWSW2sTQRSA9ycUK0bTJtKHokJBUFT8F01+hLgSWxBfJFCEEFiCEEKegkai1ks3ySYiZFV8Tv6BPihIQQiaK9nL7MzuzvHMmMa0kVIXPs7O7Ztz9qyydnb12qUL6x+u3Lxhbly+aq5f3DAj0Zi5dGrZXFo+g5yexkVWzkXNWHytFYnFW9HoysdIZPW6sv0glSy/egxPK894ZbfC9WoNakYTjEYTY0NSrRuHqBkGvN7TofpGh7rR4HuIjuNUajup1N4/35ywAViWxSx3zCjzfAD4H5jA8zwolUqbit58kXBdAtSj3LYcPhig3JnAz34XLNsCx3GAMQZBGEIQBAv4vs9RyMW+YrGYUPR3KCQO4A18PB7xfq8PmCWOCULFvDxIKQXmM5RT4Fw4Zo8UEkL+CglxASd4t9vlvV4PDzMce+J2icyE+fKiP0I4mdC2bbmAUTI7MTXIeFj2b6ErhR4XZYvSxKIo9UBylBMJhWw4HPLRaDT7Vgf7j5EdI8QMRcmui9l6LjjYKOw8hEE4k4Uhl9kT3BNi1+eForJyuZxQ6ihkjACjHhf4mJlohOgyQSj15g/Pfpe5bPkUaLfbCaX6djdpER/6Y5v/+DXiEyuA/fFnaH0rw6fvL6H19QnsD7+A5zKwHVv+l0J4tGTx0ul0ksrW1q14VnukZrI5dSejqdkcvud21HuZO+r9zF2Mt9WM9lDNaTlV0zRJPp9XC4XCAul0+vxv9sBgvfHSzm0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Spring Initializr&quot;
        title=&quot;&quot;
        src=&quot;/static/6ae2b6ad13e17749f5bf48be927cbb58/9fabd/spring-initializr.png&quot;
        srcset=&quot;/static/6ae2b6ad13e17749f5bf48be927cbb58/c6e3d/spring-initializr.png 500w,
/static/6ae2b6ad13e17749f5bf48be927cbb58/da8b6/spring-initializr.png 1000w,
/static/6ae2b6ad13e17749f5bf48be927cbb58/9fabd/spring-initializr.png 2000w,
/static/6ae2b6ad13e17749f5bf48be927cbb58/85fe6/spring-initializr.png 2854w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;La configurazione che ho scelto è la seguente:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Project&lt;/em&gt;: Gradle Project. Probabilmente avrete già sentito parlare di Maven come gestore delle dipendenze e build tool per Java. Se invece sviluppate su Android, con Gradle vi sentirete a casa, dato che è quello usato di default.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Language&lt;/em&gt;: Java.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Spring Boot&lt;/em&gt;: 2.1.6.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Project Metadata&lt;/em&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Group&lt;/em&gt;: it.mattianatali.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Artifact&lt;/em&gt;: tdd-spring-boot-api.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Name&lt;/em&gt;: tdd-spring-boot-api.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Description&lt;/em&gt;: Sample project to explain how to develop APIs in TDD with Spring Boot.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Package Name&lt;/em&gt;: it.mattianatali.tdd-spring-boot-api.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Packaging&lt;/em&gt;: Jar.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Java&lt;/em&gt;: 12.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Dependencies&lt;/em&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Spring Web Starter&lt;/em&gt;: fornisce le varie annotazioni per creare delle API RESTful in modo semplice e veloce.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lombok&lt;/em&gt;: è una libreria Java che ci permette di ridurre la verbosità del nostro codice Java.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Spring Data JPA&lt;/em&gt;: fornisce tutto l’occorrente per la persistenza dei dati.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;H2 Database&lt;/em&gt;: fornisce un DB in memory. In produzione sarebbe opportuno usare un DB PostgreSQL o MySQL, ma per non perderci troppo nella configurazione del DB, ho preferito usare H2.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Premiamo “Generate the project”. Ci ritroviamo un bel file zip. Scompattiamo in una cartella a nostro piacimento.
Apriamo il progetto, io utilizzo IntelliJ.&lt;/p&gt;
&lt;h3&gt;Abilitiamo lombok e l’annotation processor in IntelliJ&lt;/h3&gt;
&lt;p&gt;Se è la prima volta che usate &lt;a href=&quot;https://projectlombok.org/&quot;&gt;Lombok&lt;/a&gt;, &lt;strong&gt;avete bisogno del Plugin “Lombok”&lt;/strong&gt;. Aprite “Preferences”, andate su “Plugins”, cercate “Lombok” sul marketplace e installatelo.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/951bbb394a8877de62cd24ec68779f2c/655f0/lombok-plugin.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 69.19999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAClElEQVR42qVSy27TQBSN1D1ILPgANpEIbRK/xjP22OPYebZp2qRpClHpi0rs+QMW8BH8AagSK9QNqtQqhIhfqudwx00LlSo2WDq6njt3ztxz7pR+fPr85Ou3L8ffLy6OLgiXl5dHs/m8iLc4Pz8vMKf8bDa7iwa3NVdXVwdnZ2dPS2na5gfHJzh6c6oPT06xN32Nl9N9DHd2MdgeYnNrRHFEcYjReEL5McaTvWJ/e7Rj8nq5r7Msi0vPqirojN4i6h5ee+k0Z8lO7gcy90WY1203r1kORS+3HEbwcptg8sW/69G+e31bV65UklKZT8Tg+CM2Dj9oNXkPNXwHHkRod7qIVQLH8wtkrTZa7S5kTDnGEUYKvfU+AhnruuOBCDURqlKt5oit4a6RoI28rNUD3YhQxsUhLkJTDBaEEFEE5oti32E+uJTwfKFtl/0hrNS46A320B9NddjoQzY2YLs+HeRYcxjieg37tedYJQLb92ERmSG0PIY6Z1TLtGX/3aEjhWpuIs76moAw6YL8I3kdiDACeYWWY+GVipC2OqajIme675AFkWpox+P3CQ1RlG7oKL0htM0Bpag4KSS/sFz0BMNQctDAig5dUiCTBCKQ2nj8T0LLeOITlvIMar6xgWRay5zrwfLNwNh9Dx8iNJIbadPcfjMA6iBpZGjR5F3y0kgOpEKLLJCx0r4IHiTMiVATobZcT0uldJw0tJlitW5rHspiHYSRpks0EWuyxKxzupBqrLxcJkLbD4NGewDV7OtiOOk6+SPgygAup0hvrkAQ3GC59oSAH9Mz4kJ7QsLhMSrValKybXvVD+UvOry4AzPgSzy05gsmwoXKmgsuxE8WtxdOOp6vrTn1En0rhEeEx/8Jw7HyG4tRuVHGmjSoAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;IntelliJ - Installiamo Lombok plugin&quot;
        title=&quot;&quot;
        src=&quot;/static/951bbb394a8877de62cd24ec68779f2c/9fabd/lombok-plugin.png&quot;
        srcset=&quot;/static/951bbb394a8877de62cd24ec68779f2c/c6e3d/lombok-plugin.png 500w,
/static/951bbb394a8877de62cd24ec68779f2c/da8b6/lombok-plugin.png 1000w,
/static/951bbb394a8877de62cd24ec68779f2c/9fabd/lombok-plugin.png 2000w,
/static/951bbb394a8877de62cd24ec68779f2c/655f0/lombok-plugin.png 2352w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Una volta aperto il progetto in IntelliJ, &lt;strong&gt;dobbiamo abilitare l’annotation processor&lt;/strong&gt;. Per fare questo aprite “Preferences”, cercate “annotation” e spuntate l’opzione “Enable annotation processing”.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2dcc7eeb6d19c8d97284eda33dee8518/006ce/intellij-enable-annotation-processing.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 72.39999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC90lEQVR42oWSv28TSRTH09ABxVkugnPBEoogBUKHY+/uzM6v3ZmN7dhrso5xLoHTdVehE1AhIaVFosLiD4AIUH5YEKH7Y664lkgUSATduWDFPN5sIgdobqWP3szuzvd933szszUYnH3+avz45Zu/nu7tjZ/s7o9H4/Hr0euDg9HBCc+2t0fb2y+K9/sHbzGOR7u7u6N9/Ned2dnZe7ozfvtoa2vr/Mzc3E+VG5t3/kvX/4C0v25XslugVzKkB2I5BbPShbXBGjKAteEQNlZ7kDRbIPQyxGYZlE6swrXQ7aPFxcWLKLhQ4VHrU3Olb5lqf2ZxN28QmXtM5qGKc4+EeUDDPGQs/8Un+Ubtaj5cupbXGl5+reHnSw3/85IXQK3e+FCtVo8Fpe5O0mwTpEmt0ClQoQEPQN0PEAJByMGnvIhLGJMwhF9JA5qUQD0UlnKJ39lRteocLixUWNSetNOboJLUct2dCrrMDRTkUgFXERAmij2LNAilIEPRLKhbwjh4hB5NHQrdmaT9Y4cq6QGVphCsoSCWCzpJIEaYE0a0SUAZAwTXCedWYbKQC+zhiaAyKZa8AQn2MW6uQsCiqUOfEAiFcxi7AYCMDUQ4jALc8zixTMZATwXnKrq1OsmGv4EwXRtGHXSofxAU7gBGWbj8HmldpJyfOtStbNJf/x3avXW73BlOe+hKJiEFkxgs2+A10cAFB/YNXAorFCbi7BuHSWvSSTMsqWUj08JsCgX9wmFA6bTMpNUu1jJyaIhw7e6hwDUT8kRwwa+Qzp//dm8/BN2/+4XfuG/9qG+v12sWHVqPBDbkEicpLfbSomABihRg8i+uxzjpj1NB1r0z6Ww+ALN216rVexBEGV4Pdw8pEJyyVG66rn/SOSngJxPH91hy7Pp77HB+fn42ZOE/NKTvMb4LaHCIgzj0AnoMobj/Hi8ghzKKD2PTRMw7qnvvPTP4u1KpzM3gc6ZcLl86WypdOVcqXS45Llw4pfQ/uH9mZ6+Uyz9fclpfAZH1vrygWSFKAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;IntelliJ - Abilitiamo l&amp;#39;annotation processing&quot;
        title=&quot;&quot;
        src=&quot;/static/2dcc7eeb6d19c8d97284eda33dee8518/9fabd/intellij-enable-annotation-processing.png&quot;
        srcset=&quot;/static/2dcc7eeb6d19c8d97284eda33dee8518/c6e3d/intellij-enable-annotation-processing.png 500w,
/static/2dcc7eeb6d19c8d97284eda33dee8518/da8b6/intellij-enable-annotation-processing.png 1000w,
/static/2dcc7eeb6d19c8d97284eda33dee8518/9fabd/intellij-enable-annotation-processing.png 2000w,
/static/2dcc7eeb6d19c8d97284eda33dee8518/006ce/intellij-enable-annotation-processing.png 2248w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Carichiamo JUnit 5&lt;/h3&gt;
&lt;p&gt;Purtroppo la dipendenza per i test &lt;code class=&quot;language-text&quot;&gt;org.springframework.boot:spring-boot-starter-test&lt;/code&gt;, che possiamo trovare nel file &lt;code class=&quot;language-text&quot;&gt;build.gradle&lt;/code&gt;, utilizza ancora JUnit 4. Siccome più avanti utilizzeremo delle funzionalità avanzate, abbiamo bisogno di &lt;strong&gt;JUnit 5&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Per raggiungere l’obiettivo, aggiungiamo nel file &lt;code class=&quot;language-text&quot;&gt;build.gradle&lt;/code&gt; le dipendenze per JUnit 5.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;groovy&quot;&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;dependencies &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
  testImplementation &lt;span class=&quot;token string&quot;&gt;&apos;org.junit.jupiter:junit-jupiter-api&apos;&lt;/span&gt;
  testRuntimeOnly &lt;span class=&quot;token string&quot;&gt;&apos;org.junit.jupiter:junit-jupiter-engine&apos;&lt;/span&gt;
  testImplementation &lt;span class=&quot;token string&quot;&gt;&apos;org.junit.jupiter:junit-jupiter-params&apos;&lt;/span&gt;
  testImplementation &lt;span class=&quot;token string&quot;&gt;&apos;org.mockito:mockito-junit-jupiter&apos;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Infine ci serve “avvisare” Gradle di utilizzare JUnit 5 durante il comando di test &lt;code class=&quot;language-text&quot;&gt;./gradlew test&lt;/code&gt; e di mostrare i log completi. Così ci è più semplice debuggare in caso di problemi.
Sempre nel file &lt;code class=&quot;language-text&quot;&gt;build.gradle&lt;/code&gt; aggiungiamo in fondo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;groovy&quot;&gt;&lt;pre class=&quot;language-groovy&quot;&gt;&lt;code class=&quot;language-groovy&quot;&gt;test &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token function&quot;&gt;useJUnitPlatform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 testLogging &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  exceptionFormat &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;full&apos;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nel nostro progetto, c’è già un file di test scritto in JUnit 4. Il file si trova in &lt;code class=&quot;language-text&quot;&gt;src/test/java/it/mattianatali/tddspringbootapi/TddSpringBootApiApplicationTests.java&lt;/code&gt;. Questo test prova semplicemente a caricare il contesto di Spring. Può sembrare un test banale, ma a mano a mano che il progetto cresce, basta poco per dimenticarsi qualche annotazione e che quindi Spring non si carichi correttamente.&lt;/p&gt;
&lt;p&gt;Il nostro primo passo è di &lt;strong&gt;migrarlo a JUnit 5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Dovrebbe essere scritto così:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;runner&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;RunWith&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringBootTest&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit4&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringRunner&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@RunWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringRunner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@SpringBootTest&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TddSpringBootApiApplicationTests&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contextLoads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Noi lo modifichiamo così:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extension&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ExtendWith&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringBootTest&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@SpringBootTest&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TddSpringBootApiApplicationTests&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;contextLoads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Avete notato delle differenze? Per migrare un test da JUnit 4 a JUnit 5 bisogna stare attenti a queste cose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modificare l’annotazione &lt;code class=&quot;language-text&quot;&gt;@RunWith(SpringRunner.class)&lt;/code&gt; con &lt;code class=&quot;language-text&quot;&gt;@ExtendWith(SpringExtension.class)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Essere certi di avere &lt;strong&gt;sempre&lt;/strong&gt; la scritta &lt;code class=&quot;language-text&quot;&gt;junit.jupiter&lt;/code&gt; nell’&lt;code class=&quot;language-text&quot;&gt;import&lt;/code&gt; di tutte le classi di JUnit. Infatti Se leggete &lt;code class=&quot;language-text&quot;&gt;jupiter&lt;/code&gt; significa che state usando JUnit 5. Possiamo notare che l’annotazione &lt;code class=&quot;language-text&quot;&gt;@Test&lt;/code&gt; ha cambiato package… Ricordatevi dovete usare &lt;code class=&quot;language-text&quot;&gt;junit.jupiter&lt;/code&gt;!&lt;/li&gt;
&lt;li&gt;Le classi di test e i metodi non devono essere necessariamente &lt;code class=&quot;language-text&quot;&gt;public&lt;/code&gt;. Se usate IntelliJ si lamenterà di questo fatto.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ora proviamo a vedere se la nostra suite di test è configurata correttamente. Per far ciò creiamo un test temporaneo che sicuramente fallisce.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Assertions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;fail&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TddSpringBootApiApplicationTests&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

  &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;shouldFail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;fail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;You shall not pass!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I puntini di sospensione &lt;code class=&quot;language-text&quot;&gt;...&lt;/code&gt; nel codice significa che c’è altro nel file che però non ho scritto per evitare distrazioni.&lt;/p&gt;
&lt;p&gt;Proviamo a far girare i test: utiliziamo IntelliJ oppure Gradle con il comando &lt;code class=&quot;language-text&quot;&gt;./gradlew test&lt;/code&gt;.
Ci aspettiamo che un test passi e l’altro fallisca.&lt;/p&gt;
&lt;p&gt;L’output del test è il seguente&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; Task :test FAILED

it.mattianatali.tddspringbootapi.TddSpringBootApiApplicationTests &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; shouldFail&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; FAILED
    org.opentest4j.AssertionFailedError: You shall not pass&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;
        at org.junit.jupiter.api.AssertionUtils.fail&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AssertionUtils.java:38&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        at org.junit.jupiter.api.Assertions.fail&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Assertions.java:84&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        at it.mattianatali.tddspringbootapi.TddSpringBootApiApplicationTests.shouldFail&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TddSpringBootApiApplicationTests.java:20&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;-07-20 &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;:56:43.465  INFO &lt;span class=&quot;token number&quot;&gt;13515&lt;/span&gt; --- &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;       Thread-4&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; o.s.s.concurrent.ThreadPoolTaskExecutor  &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; Shutting down ExecutorService &lt;span class=&quot;token string&quot;&gt;&apos;applicationTaskExecutor&apos;&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;-07-20 &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;:56:43.466  INFO &lt;span class=&quot;token number&quot;&gt;13515&lt;/span&gt; --- &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;       Thread-4&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; j.LocalContainerEntityManagerFactoryBean &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; Closing JPA EntityManagerFactory &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; persistence unit &lt;span class=&quot;token string&quot;&gt;&apos;default&apos;&lt;/span&gt;
&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;-07-20 &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;:56:43.466  INFO &lt;span class=&quot;token number&quot;&gt;13515&lt;/span&gt; --- &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;       Thread-4&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; .SchemaDropperImpl&lt;span class=&quot;token variable&quot;&gt;$DelayedDropActionImpl&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down&lt;span class=&quot;token string&quot;&gt;&apos;
2019-07-20 12:56:43.468  INFO 13515 --- [       Thread-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2019-07-20 12:56:43.472  INFO 13515 --- [       Thread-4] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

2 tests completed, 1 failed

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task &apos;&lt;/span&gt;:test&apos;.
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; There were failing tests. See the report at: file:///Users/mattia/Repositories/tdd-spring-boot-api/build/reports/tests/test/index.html

* Try:
Run with &lt;span class=&quot;token parameter variable&quot;&gt;--stacktrace&lt;/span&gt; option to get the stack trace. Run with &lt;span class=&quot;token parameter variable&quot;&gt;--info&lt;/span&gt; or &lt;span class=&quot;token parameter variable&quot;&gt;--debug&lt;/span&gt; option to get &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt; log output. Run with &lt;span class=&quot;token parameter variable&quot;&gt;--scan&lt;/span&gt; to get full insights.

* Get &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;help&lt;/span&gt; at https://help.gradle.org

BUILD FAILED &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; 5s
&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; actionable tasks: &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; executed, &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; up-to-date&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;È proprio quello che ci aspettavamo! Ora &lt;strong&gt;togliamo il test che fallisce&lt;/strong&gt; e possiamo essere certi che JUnit 5 è configurato alla perfezione!&lt;/p&gt;
&lt;h2&gt;Come strutturare il backend&lt;/h2&gt;
&lt;p&gt;Prima di iniziare a scrivere il codice dobbiamo essere allineati su come andremo ad architettare il nostro software.
Solitamente, il minimo indispensabile per creare un backend che espone delle API RESTful è implementare tre tipi di classi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Controller&lt;/strong&gt;: il suo unico scopo è di validare i valori in input, dichiarare gli endpoint che vogliamo esporre, di invocare un service e di fornire la risposta data dalla classe service.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service&lt;/strong&gt;: al suo interno abbiamo la vera logica di business che dipende dal progetto, fa il lavoro sporco e se deve persistere qualche dato, invoca i repository.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repository&lt;/strong&gt;: esiste per persistere i dati da qualche parte, solitamente in un DB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ovviamente si può fare tutto in una classe, ma &lt;strong&gt;se vogliamo strutturare del buon codice testabile e riusabile, questo è il minimo&lt;/strong&gt;. Dobbiamo sempre ricordarci che più una classe ha uno scopo ben preciso, più è semplice da implementare ma soprattutto è facile da riutilizzare in altri punti.&lt;/p&gt;
&lt;h2&gt;Implementiamo la chiamata GET&lt;/h2&gt;
&lt;p&gt;Iniziamo! La chiamata &lt;code class=&quot;language-text&quot;&gt;GET - /api/v1/vehicles/{id}&lt;/code&gt; abbiamo detto che deve fornire il dettaglio del veicolo. Per sviluppare immagino di essere la richiesta HTTP. La prima classe che viene intaccata dalla chiamata è il controller, come abbiamo detto la sua funzione è quella di validare i valori di input e di esporre l’endpoint che andiamo a chiamare.
Andiamo a creare il controller. Creiamo il file &lt;code class=&quot;language-text&quot;&gt;src/main/java/it/mattianatali/tddspringbootapi/vehicle/VehicleController.java&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Per ora ci basta questo, stiamo sviluppando in TDD quindi &lt;strong&gt;la nostra implementazione deve essere guidata dai test&lt;/strong&gt;. Con IntelliJ possiamo premere &lt;code class=&quot;language-text&quot;&gt;cmd&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;shift&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt;, selezionare “Create New Test…” e confermare. In questo modo ci troviamo il file di test creato ad hoc per il nostro controller.&lt;/p&gt;
&lt;p&gt;Pensiamo ora cosa deve fare il nostro controller per raggiungere l’obiettivo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dichiarare che esiste l’endpoint &lt;code class=&quot;language-text&quot;&gt;GET - /api/v1/vehicles/{id}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ricevere l’id del veicolo dal path della chiamata.&lt;/li&gt;
&lt;li&gt;Chiamare il servizio &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;, che non esiste ancora, con l’id preso dal punto precedente.&lt;/li&gt;
&lt;li&gt;Se &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; restituisce un veicolo, allora risponde con un &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt; come &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt; e il veicolo nel body, altrimenti risponde con un bel &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Versione Semplificata&lt;/h3&gt;
&lt;p&gt;Siccome siamo alle prime armi con il TDD, è veramente difficile fare un test così completo al primo tentativo.
Cerchiamo allora di procedere per piccoli passi. &lt;strong&gt;Testiamo una versione semplificata&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Il nostro primo test verificherà solo questo, poi pian piano aggiungiamo i punti rimanenti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verificare che esiste l’endpoint &lt;code class=&quot;language-text&quot;&gt;GET - /api/v1/vehicles/{id}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Restituisce come statusCode &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il nostro test è il seguente:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extension&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ExtendWith&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beans&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Autowired&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;autoconfigure&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;WebMvcTest&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcRequestBuilders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;get&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;status&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@WebMvcTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleControllerTest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MockMvc&lt;/span&gt; mvc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDetail_shouldReturn200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        mvc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isOk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora spieghiamo punto per punto le cose nuove che non abbiamo mai visto:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ExtendWith(SpringExtension.class)&lt;/code&gt; serve per collegare il contesto di JUnit con il framework di Spring Boot. In questo modo possiamo usare le annotazioni che comunemente usiamo con Spring Boot più altre annotazioni che esistono apposta per semplificare la vita durante il testing, come la successiva.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@WebMvcTest(VehicleController.class)&lt;/code&gt; è il nostro modo per dire a JUnit 5 + Spring Boot: “Voglio testare solo la parte adibita al controller &lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt;, quindi evita di caricare tutto il contesto di Spring Boot”. In altre parole il nostro test si avvierà più velocemente perché il nostro test sa bene che non deve caricare per esempio &lt;a href=&quot;https://hibernate.org/&quot;&gt;Hibernate&lt;/a&gt;, caricare i drivers del DB, configurazioni, servizi, repositories o altre cose, perché non ne abbiamo bisogno. Stiamo testando solo quel controller. Se invece vogliamo testare qualcosa caricando tutto il contesto di Spring Boot possiamo usare l’annotazione &lt;code class=&quot;language-text&quot;&gt;@SpringBootTest&lt;/code&gt;. Ma è sempre meglio evitare per non rallentare il caricamente ed esecuzione dei test.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Autowired private MockMvc mvc&lt;/code&gt; significa “Spring Boot: forniscimi un modo per comunicare con il controller che ho definito nell’annotazione precedente (&lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt;), che mi permetta di fare delle chiamate HTTP”. &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt; significa che è Spring Boot a fornircelo, non dobbiamo preoccuparci come lo istanzia per noi. &lt;code class=&quot;language-text&quot;&gt;MockMvc mvc&lt;/code&gt; è l’istanza fornita da Spring Boot che useremo per fare le chiamate HTTP.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Io solitamente adotto questa convenzione per i nomi dei test: &lt;code class=&quot;language-text&quot;&gt;nomeMetodo_cosaStiamoTestando&lt;/code&gt;. Non preoccupatevi di scrivere un nome troppo lungo, non andrete mai a riscrivere il nome del metodo. Qui &lt;strong&gt;è importante essere chiarissimi su cosa stiamo testando e cosa ci aspettiamo&lt;/strong&gt;. Ogni volta che programmate mettetevi nei panni di un altro sviluppatore che non sa nulla di quello che state facendo, &lt;strong&gt;cercate di semplificare la vita al prossimo&lt;/strong&gt;: in questo caso più siamo chiari, più i nostri colleghi saranno felici del nostro lavoro.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;mvc.perform(get(&quot;api/v1/vehicles/&quot; + vehicleId))&lt;/code&gt; è il nostro modo per fare una chiamata &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; all’endpoint che stiamo testando.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;.andExpect(status().isOk())&lt;/code&gt; è la nostra asserzione sullo &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt; della nostra chiamata HTTP, ci aspettiamo un bel &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Facciamo girare il test, ci aspettiamo che fallisca e che invece dello &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt; ci restituisca un &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt;, perché l’endpoint non è stato ancora dichiarato. Con IntelliJ è molto facile testare un singolo test, basta premere sulla freccia verde vicino al nome del metodo.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0f50a73250e5c794576a4dca7d05654a/fb012/intellij-test-execution.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAABYlAAAWJQFJUiTwAAACtklEQVR42lWT+W7bOBCH/Rp9gEV8SJZiRpd1krpZOXYOt7Hbt1ggaFCkiHN0sS9R/9OXbAXit0MVaLN/fJghQXycEUejw6e/nceXw/fnf/799vTy9Xh4ejoeDi/H+8MDcTh++fJwvCPuHygn7j7fHz/dfR7Qud57fH75dnh8/n57e+uO2q7b7z5+wNX2Wm2urnC5vSbeoTtfY70+x2r7HpvdDt1mBZ4LCJFD6EikXCCjNUVV1hVqWe9GXhDdXG4aVGX6M8viXois5znvXXba88Dps6LtEyH6KIn6IPR6x7V6w5j04/H4NycnJz9M00QQRTcj5jj7Sq5Qtp3iRUU3FvDSHI7nIvMtJJlAnKQIljH8ZQg/COB6HizbxnQ6xWw201HpdZSmu5Hj+HstkptLJbsVsqrBdbRE7dnwkzmWYYiFbWE6GQ+C6XQGwzBgkGj2BzW3LDDXJaEf7suLDqubKyW3l9iuG1xIgdo/w5pNEEYBnLMFGDulquawLHuQaOEg/oWytJCx3dBy0nbgqwsl3lKFtQQT1dBWYZ6gPTXhLBawqSXTNKC/1SvRK6ENm1GFjDn78/UaXfdWhVGMKMkQxSnsMxezU6pM36xlcwuGOac4H/L/Yc6Vrc/qln1quaDKhDxXAW8Q8BKi+EPCaSxoNJKMIwgjeP7yN64fDFCu4jSDG0S7UcL5npc1RN0qUUl6KY6yKtE2LZq2hZQSdV2jLEtwzgd0XhTFQJZRR1FIwlSPzW5EL7zneYlllCjdLkWUdFDKFi0Jm6YZhA2h13VVIU0SxHGMhKKGsYVyXI/E6a8KRUnzl5eKQExzl5OwJlFB+zoXeY6M/gpOM5ro1jwfWqAfztG55yn93QMtpEl/4zhOt0wSaTMmDdsemBiG/GsyeYUxoPcnhj2gzzPPI5YyCKJuzNib/wDZyaF3si6vMgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;IntelliJ - Far girare i test&quot;
        title=&quot;&quot;
        src=&quot;/static/0f50a73250e5c794576a4dca7d05654a/9fabd/intellij-test-execution.png&quot;
        srcset=&quot;/static/0f50a73250e5c794576a4dca7d05654a/c6e3d/intellij-test-execution.png 500w,
/static/0f50a73250e5c794576a4dca7d05654a/da8b6/intellij-test-execution.png 1000w,
/static/0f50a73250e5c794576a4dca7d05654a/9fabd/intellij-test-execution.png 2000w,
/static/0f50a73250e5c794576a4dca7d05654a/9d489/intellij-test-execution.png 3000w,
/static/0f50a73250e5c794576a4dca7d05654a/fb012/intellij-test-execution.png 3170w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Questo è il risultato del nostro test:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;-07-20 &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;:33:15.748  WARN &lt;span class=&quot;token number&quot;&gt;14736&lt;/span&gt; --- &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;    Test worker&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; o.s.web.servlet.PageNotFound             &lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; No mapping &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; GET api/v1/vehicles/1

&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Status expected:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;0&lt;/span&gt;&gt;&lt;/span&gt; but was:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;4&lt;/span&gt;&gt;&lt;/span&gt;
Expected :200
Actual   :404
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Click to see difference&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;

java.lang.AssertionError: Status expected:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;0&lt;/span&gt;&gt;&lt;/span&gt; but was:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;4&lt;/span&gt;&gt;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Esattamente come ci aspettavamo.&lt;/p&gt;
&lt;p&gt;Ora andiamo ad implementare il minimo indispensabile per far passare il test. Scriviamo in &lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GetMapping&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;PathVariable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;RestController&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles/{id}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getVehicleDetails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@RestController&lt;/code&gt; è l’annotazione di Spring Boot che serve per dichiarare che stiamo creando un Controller.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@GetMapping(&quot;/api/v1/vehicles/{id}&quot;)&lt;/code&gt; dichiariamo l’esistenza del nostro endpoint con il metodo &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; e che ha una variabile nel path chiamata &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@PathVariable Long id&lt;/code&gt; serve per estrapolare l’id dal path.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Come possiamo notare non restituiamo nulla dall’endpoint… Infatti non abbiamo messo nessuna asserzione nel test, quindi non è necessario mettere altro. Per ora vogliamo solo testare che risponda con &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt;. Che è il valore di default se non inseriamo niente.&lt;/p&gt;
&lt;p&gt;Facciamo girare il test, aspettiamo qualche secondo, e stavolta è verde! Possiamo facilmente intuire che il nostro test non è sufficiente, ora miglioriamolo in modo tale da testare almeno “l’happy path” completo.&lt;/p&gt;
&lt;h3&gt;Versione Completa&lt;/h3&gt;
&lt;p&gt;Modifichiamo il test rendendolo completo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extension&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ExtendWith&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beans&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Autowired&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;autoconfigure&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;WebMvcTest&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockBean&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hamcrest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Matchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;is&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Mockito&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;when&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcRequestBuilders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;get&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;jsonPath&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;status&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@WebMvcTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleControllerTest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MockMvc&lt;/span&gt; mvc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@MockBean&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDetail_shouldReturnVehicleIfFound&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; returnedVehicle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ferrari&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;488 GTB&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;returnedVehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        mvc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isOk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;returnedVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;intValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.brand&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;returnedVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBrand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;returnedVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.year&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;returnedVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In questo momento c’è il nostro compilatore che si sta disperando perché non trova &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; e nemmeno la classe &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;… Infatti non li abbiamo ancora creati!&lt;/p&gt;
&lt;p&gt;Anche in questo caso vediamo cosa c’è di nuovo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@MockBean private VehicleService vehicleService&lt;/code&gt; stiamo dicendo a Spring Boot: “Se qualche classe ti chiede il servizio &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;, tu non passare la vera implementazione, ma fornisci un’istanza finta, dove io posso decidere cosa ritornare nell’invocazione dei metodi”. Infatti più avanti con il metodo &lt;code class=&quot;language-text&quot;&gt;when&lt;/code&gt; possiamo decidere cosa ritornare come valore, senza andare a richiamare la vera implementazione. Il discorso di cosa vuol dire “Mockare” le classi è già stato trattato nel mio articolo precedente, se non vi è chiaro è meglio che &lt;a href=&quot;/it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero&quot;&gt;leggiate la puntata precedente&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;var returnedVehicle = Vehicle.builder()....build()&lt;/code&gt; stiamo semplicemente creando un modello di veicolo che verrà restituito in output dal &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; e di conseguenza dal controller. In questo caso useremo il builder che ci fornisce Lombok, non preoccupatevi per ora, quando creeremo la classe sarà più chiaro.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;when(vehicleService.get(vehicleId)).thenReturn(Optional.of(returnedVehicle));&lt;/code&gt; stiamo dicendo “se qualcuno invoca &lt;code class=&quot;language-text&quot;&gt;vehicleService.get&lt;/code&gt; con l’id &lt;code class=&quot;language-text&quot;&gt;vehicleId&lt;/code&gt;, allora ritorna un opzionale con il nostro veicolo appena creato”.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;.andExpect(jsonPath(&quot;$.id&quot;, is(returnedVehicle.getId())))&lt;/code&gt; significa che ci aspettiamo nel body di risposta un JSON che contiene un campo &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt;, con dentro l’id del nostro veicolo creato. Le altre righe sono molto simili, cambia solo il campo che andiamo a controllare.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Non possiamo far girare i test perché il codice non compila nemmeno. Andiamo allora a creare le classi mancanti. Con IntellJ è molto semplice creare classi o metodi che non esistono ancora, basta spostare il cursore sulla classe inesistente, premere &lt;code class=&quot;language-text&quot;&gt;alt&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;Invio&lt;/code&gt;, cliccare su ”&lt;em&gt;Create class …&lt;/em&gt;”, come target directory scegliere &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; e non &lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt;, e confermate.&lt;/p&gt;
&lt;p&gt;Facciamo questo procedimento con &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;. Poi implementiamola.
Il file dovrebbe trovarsi in &lt;code class=&quot;language-text&quot;&gt;/src/main/java/it/mattianatali/tddspringbootapi/vehicle/Vehicle.java&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;lombok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Builder&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;lombok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Data&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Data&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toBuilder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; brand&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt; year&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Qui possiamo vedere Lombok in azione! Grazie all’annotazione &lt;code class=&quot;language-text&quot;&gt;@Data&lt;/code&gt; non dobbiamo scrivere né getter, né setter, né fare l’override di equals o hash, fa tutto lui! Con &lt;code class=&quot;language-text&quot;&gt;@Builder(toBuilder = true)&lt;/code&gt; invece ci viene gratis un comodo builder che abbiamo già usato nel test. &lt;code class=&quot;language-text&quot;&gt;toBuilder = true&lt;/code&gt; ci fornisce un comodo metodo sull’istanza che ci permette di avere un builder dall’istanza stessa, molto comodo per creare per esempio un clone modificando magari qualche suo campo.
&lt;code class=&quot;language-text&quot;&gt;@NoArgsConstructor&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;@AllArgsConstructor&lt;/code&gt; sono ancora due annotazioni di Lombok che ci forniscono sia il costruttore con tutti i parametri, sia il costruttore vuoto. Sono molto utili per la serializzazione delle istanze in JSON. Se infatti non mettiamo queste due annotazioni, &lt;a href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Jackson&lt;/a&gt;, che è la libreria che utilizza Spring Boot per creare i JSON di risposta, si lamenterà perché non riesce a serializzare l’oggetto.
Meno codice da scrivere significa meno codice da gestire e testare!&lt;/p&gt;
&lt;p&gt;Ora dobbiamo creare il &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;. In questo caso &lt;strong&gt;scriviamo il minimo indispensabile per poter compilare&lt;/strong&gt;, ci dobbiamo ricordare che &lt;strong&gt;nel test usiamo la versione mockata, quindi la vera implementazione ora non ci interessa&lt;/strong&gt;. Ci preoccuperemo quando andremo a sviluppare in TDD su di essa. Anche qui possiamo farci aiutare da IntelliJ.&lt;/p&gt;
&lt;p&gt;Una volta creata la classe, possiamo dire ad IntelliJ di creare il metodo &lt;code class=&quot;language-text&quot;&gt;VehicleService.get&lt;/code&gt; che abbiamo invocato nella riga di test &lt;code class=&quot;language-text&quot;&gt;when(vehicleService.get(vehicleId))&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;alt&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;invio&lt;/code&gt; è il nostro migliore amico in questo caso.&lt;/p&gt;
&lt;p&gt;Il file &lt;code class=&quot;language-text&quot;&gt;src/main/java/it/mattianatali/tddspringbootapi/vehicle/VehicleService.java&lt;/code&gt; conterrà quindi&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stereotype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Service&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt; vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Service&lt;/code&gt; serve a dire che la classe è un servizio e che può essere creata da Spring Boot tramite la &lt;em&gt;Dependency Injection (DI)&lt;/em&gt; e che può essere iniettata nelle altre classi quando usano l’annotazione &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il metodo è ovviamente sbagliato, ma ripeto, ora ci interessa solo che compili in modo tale da far girare i test.&lt;/p&gt;
&lt;p&gt;Qui c’è una cosa molto interessante da notare: &lt;strong&gt;abbiamo definito prima la &lt;em&gt;firma&lt;/em&gt; del metodo prima di pensare alla sua attuale implementazione&lt;/strong&gt;. In questo molto &lt;strong&gt;definiamo le classi dal punto di vista dell’&lt;em&gt;utilizzatore&lt;/em&gt; e non del &lt;em&gt;creatore&lt;/em&gt;&lt;/strong&gt;. Solitamente questo è un bene perché si creano delle firme dei metodi facilmente utilizzabili. Se invertiamo il procedimento finiamo di semplificare l’implementazione ma rendiamo difficile l’utilizzo delle classi create perché appunto non pensiamo a come un possibile utilizzatore possa sfruttare queste classi.&lt;/p&gt;
&lt;p&gt;Facendo girare il test abbiamo il seguente errore&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lang&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;AssertionError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;No&lt;/span&gt; value at &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt; path &lt;span class=&quot;token string&quot;&gt;&quot;$.id&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Caused&lt;/span&gt; by&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lang&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; json can not be &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt; or empty
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora si sta lamentando che il nostro endpoint non restituisce nessun JSON e che quindi non può testare le varie proprietà.
Perfetto, andiamo ad implementare per far passare il test.&lt;/p&gt;
&lt;p&gt;Modifichiamo il nostro &lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beans&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Autowired&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GetMapping&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;PathVariable&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;RestController&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicleService &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles/{id}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getVehicleDetails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Possiamo vedere per la prima volta come si può sfruttare la &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;Dependency Injection&lt;/a&gt; di Spring Boot&lt;/strong&gt;. Possiamo chiedere a Spring Boot di fornirci delle istanze di classi che ci servono per svolgere il nostro compito (in questo caso il recupero del veicolo), senza che noi dobbiamo preoccuparci effettivamente di &lt;em&gt;come&lt;/em&gt; queste istanze siano create. In altre parole, tramite l’annotazione &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt; stiamo dicendo a Spring Boot di fornirci nel costruttore tutte le istanze che abbiamo bisogno, delegando al framework il come crearle.&lt;/p&gt;
&lt;p&gt;In questo modo possiamo creare delle classi disaccoppiate tra di loro e soprattutto nei test possiamo &lt;em&gt;iniettare&lt;/em&gt; delle istanze finte (mockate). Iniettando nei test delle classi mockate possiamo pilotare il flusso di esecuzione senza distogliere lo sguardo dalla classe sotto test. Perché infatti l’unica vera implementazione testata è il controller, il resto è tutta finzione (la finzione è data dall’annotazione &lt;code class=&quot;language-text&quot;&gt;@MockBean&lt;/code&gt; e dal metodo &lt;code class=&quot;language-text&quot;&gt;when().thenReturn()&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Dobbiamo infatti immaginare che durante il test, il controller riceve la nostra istanza mockata nel costruttore, quindi non va a toccare la vera implementazione di &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; (che per ora non esiste ancora… ritorna sempre &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt;!).&lt;/p&gt;
&lt;p&gt;Magari vi state chiedendo perché c’è un doppio &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;vehicleService.get(id).get()&lt;/code&gt;. Il primo è l’invocazione del nostro metodo di &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;, il secondo serve per estrapolare il valore contenuto in &lt;code class=&quot;language-text&quot;&gt;Optional&amp;lt;Vehicle&gt;&lt;/code&gt;. &lt;strong&gt;È fortemente sconsigliato chiamare &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; su un opzionale&lt;/strong&gt; perché non stiamo gestendo il caso in cui l’opzionale sia vuoto, in altre parole quando il veicolo non esiste. Ma per ora il nostro obiettivo è di far passare il test, poi &lt;strong&gt;quando faremo il test che testa il caso in cui il veicolo non esiste, lo sistemeremo&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Facendo girare il test vediamo che effettivamente funziona! Ritorniamo il JSON con tutti i campi.&lt;/p&gt;
&lt;h3&gt;Testiamo il caso di assenza veicolo&lt;/h3&gt;
&lt;p&gt;Abbiamo testato quando il veicolo viene ritornato dal &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;, ma cosa succede quando il veicolo con un determinato id non esiste? Noi ci aspettiamo che l’endpoint ritorni &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Andiamo a creare il test che verifica questo caso, nel &lt;code class=&quot;language-text&quot;&gt;VehicleControllerTest&lt;/code&gt; scriviamo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDetail_shouldReturn404IfVehicleNotFound&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    mvc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isNotFound&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Facendo girare il test esplode in questo modo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
org.springframework.web.util.NestedServletException: Request processing failed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; nested exception is java.util.NoSuchElementException: No value present

	&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Caused by: java.util.NoSuchElementException: No value present
  &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
	&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;. &lt;span class=&quot;token number&quot;&gt;57&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In pratica è il nostro famoso &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; sull’opzionale che abbiamo messo nel controller. Stiamo cercando di recuperare un dato che non esiste e quindi va in eccezione.&lt;/p&gt;
&lt;p&gt;Andiamo a modificare il controller in modo tale che ci restituisca uno status code &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt; quando il servizio non ci restituisce alcun veicolo.
Per rispondere &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt; abbiamo bisogno di un’eccezione che ci generi quello status code.
Quindi creiamo l’eccezione in  &lt;code class=&quot;language-text&quot;&gt;src/main/java/it/mattianatali/tddspringbootapi/vehicle/errors/VehicleNotFoundException.java&lt;/code&gt; e scriviamo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;errors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;http&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;HttpStatus&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ResponseStatus&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ResponseStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;HttpStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NOT_FOUND&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleNotFoundException&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RuntimeException&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Grazie a &lt;code class=&quot;language-text&quot;&gt;@ResponseStatus(HttpStatus.NOT_FOUND)&lt;/code&gt; siamo sicuri che lo status code della chiamata sarà &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ora modifichiamo il metodo &lt;code class=&quot;language-text&quot;&gt;VehicleController.getVehicleDetails&lt;/code&gt; utilizzando questa nuova eccezione&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles/{id}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getVehicleDetails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; vehicleService
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;orElseThrow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleNotFoundException&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In pratica abbiamo sostituito il metodo &lt;code class=&quot;language-text&quot;&gt;.get&lt;/code&gt; con &lt;code class=&quot;language-text&quot;&gt;.orElseThrow(VehicleNotFoundException::new)&lt;/code&gt;. Questo è il modo per generare un’eccezione in caso di mancato valore nell’opzionale.&lt;/p&gt;
&lt;p&gt;Facciamo girare il test ed ora funziona tutto!&lt;/p&gt;
&lt;h3&gt;Ricapitoliamo&lt;/h3&gt;
&lt;p&gt;Fermiamoci un secondo per fare mente locale. Il lavoro per ultimare l’endpoint GET non è ancora concluso. Però ora è importante focalizzare cosa abbiamo imparato e fatto fino ad ora:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abbiamo creato un nuovo progetto Spring Boot utilizzando &lt;a href=&quot;https://start.spring.io/&quot;&gt;Spring Initializr&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Abbiamo migrato la suite di test a &lt;a href=&quot;https://junit.org/junit5/&quot;&gt;JUnit 5&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Abbiamo imparato ad utilizzare alcune funzionalità di &lt;a href=&quot;https://projectlombok.org/&quot;&gt;Lombok&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Abbiamo sviluppato in TDD il controller per la chiamata &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Abbiamo imparato a sfruttare la &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;Dependency Injection&lt;/a&gt; e l’annotazione &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt; di Spring Boot per testare in isolamento il controller, ancor prima di aver implementato il servizio &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Abbiamo imparato a fare delle finte chiamate HTTP utilizzando &lt;code class=&quot;language-text&quot;&gt;@WebMvcTest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prendiamoci una pausa, tutti i concetti appena esposti hanno bisogno di un attimo per essere assimilati. Poi continuiamo a sviluppare i due componenti rimanenti: il servizio &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; e il repository &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Implementiamo il servizio VehicleService&lt;/h3&gt;
&lt;p&gt;Ora che ci siamo rigenerati un attimo, svolgiamo un lavoro abbastanza semplice: l’implementazione di &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;. In questa classe ci dovrebbe andare tutta la logica di business, ma la logica che ha la chiamata GET è davvero banale: recuperare il veicolo dato il suo id. Non preoccupatevi, nei progetti veri la logica di business diventa sempre complessa a piacere. Noi siamo solo fortunati perché siamo all’inizio.
In altre parole, nel nostro caso dobbiamo testare che venga invocato il &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; per recuperare il veicolo, il valore di ritorno deve essere esattamente lo stesso che otteniamo dal &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; non esiste ancora e quindi dobbiamo pensare al metodo che fa al caso nostro. Non reinventiamo niente e quindi immaginiamo di utilizzare il metodo &lt;code class=&quot;language-text&quot;&gt;VehicleRepository.findById(Long id)&lt;/code&gt; che ci fornice gratis &lt;a href=&quot;https://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html&quot;&gt;JpaRepository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Scriviamo i test nel nuovo file &lt;code class=&quot;language-text&quot;&gt;src/test/java/it/mattianatali/tddspringbootapi/vehicle/VehicleServiceTest.java&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extension&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ExtendWith&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;InjectMocks&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Mock&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockitoExtension&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Assertions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;assertEquals&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Assertions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;assertTrue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Mockito&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;when&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockitoExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleServiceTest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Mock&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@InjectMocks&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_shouldReturnVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; returnedVehicle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ferrari&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;488 GTB&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;returnedVehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                returnedVehicle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_shouldReturnOptionalEmptyIfNotFound&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;assertTrue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notiamo però delle diversità nelle annotazioni utilizzate, ci stiamo riferendo a&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ExtendWith(MockitoExtension.class)&lt;/code&gt; invece di &lt;code class=&quot;language-text&quot;&gt;@ExtendWith(SpringExtension.class)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Mock&lt;/code&gt; invece di &lt;code class=&quot;language-text&quot;&gt;@MockBean&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@InjectMocks&lt;/code&gt; è nuovo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Perché abbiamo queste differenze rispetto al nostro test sul controller? Perché se ci pensiamo bene &lt;strong&gt;non abbiamo bisogno di caricare nessun componente di Spring Boot&lt;/strong&gt; (nel controller avevamo bisogno di &lt;code class=&quot;language-text&quot;&gt;MockMvc&lt;/code&gt; di Spring Boot per simulare delle chiamate HTTP), quindi possiamo utilizzare solo la libreria &lt;a href=&quot;https://site.mockito.org/&quot;&gt;Mockito&lt;/a&gt; per testare il nostro servizio. Questo &lt;strong&gt;significa avere dei test più veloci&lt;/strong&gt; ad avviarsi perché non dobbiamo caricare il contesto di Spring Boot. Le annotazioni per usare Mockito sono appunto&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ExtendWith(MockitoExtension.class)&lt;/code&gt; per avviare il contesto di Mockito e le sue annotazioni durante il test.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Mock&lt;/code&gt; per creare un’istanza mockata che possiamo decidere le risposte da dare, attraverso il metodo &lt;code class=&quot;language-text&quot;&gt;when(...).thenReturn(...)&lt;/code&gt; durante i test.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@InjectMocks&lt;/code&gt; per iniettare le istanze mockate nel nostro servizio sotto test (nel nostro caso &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il resto non dovrebbe sorprendervi più di tanto, normalissimi test organizzati in &lt;em&gt;setup&lt;/em&gt;, &lt;em&gt;call&lt;/em&gt;, &lt;em&gt;assertions&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Siccome il compilatore si sta lamentando che &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; non esiste, andiamo a crearlo senza implementare il metodo. In modo tale da poter eseguire il test del &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;.
In &lt;code class=&quot;language-text&quot;&gt;src/main/java/it/mattianatali/tddspringbootapi/vehicle/VehicleRepository.java&lt;/code&gt; scriviamo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stereotype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Repository&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Repository&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt; vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora compila! Facciamo girare i test del nostro servizio ed ovviamente falliscono.
Andiamo ad implementare il servizio che sarà molto semplice, non fa nient’altro che fare da “proxy” al nostro futuro &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beans&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Autowired&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stereotype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Service&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicleRepository &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt; vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Anche qui niente di eccezionale. Prendiamo &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; tramite DI nel costruttore e lo utilizziamo per fornire il veicolo nella chiamata &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt;.
Facciamo girare i test e sono verdi!&lt;/p&gt;
&lt;h3&gt;Implementiamo il VehicleRepository&lt;/h3&gt;
&lt;p&gt;Siamo quasi giunti al termine, ci manca solo il &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; per ultimare la chiamata &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt;.
Qui abbiamo bisogno di testare il metodo &lt;code class=&quot;language-text&quot;&gt;findById&lt;/code&gt; per recuperare il veicolo, per fare un test completo dobbiamo anche poter salvare un veicolo prima di recuperarlo.&lt;/p&gt;
&lt;p&gt;Scriviamo il test in &lt;code class=&quot;language-text&quot;&gt;src/test/java/it/mattianatali/tddspringbootapi/vehicle/VehicleRepositoryTest.java&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extension&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ExtendWith&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beans&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Autowired&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;autoconfigure&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;orm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jpa&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;DataJpaTest&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Assertions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;assertEquals&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@DataJpaTest&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleRepositoryTest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findById_shouldGetVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleToSave &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ferrari&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;488 GTB&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; expectedVehicle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expectedVehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expectedVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Con questo test salviamo un veicolo, poi lo recuperiamo con l’id che ci viene restituito nella &lt;code class=&quot;language-text&quot;&gt;save&lt;/code&gt; e poi verifichiamo che il &lt;code class=&quot;language-text&quot;&gt;findById&lt;/code&gt; ci restituisca il veicolo.
Ma vediamo le annotazioni che abbiamo utilizzato: sono praticamente le stesse che abbiamo utilizzato per il controller, ma stavolta invece di &lt;code class=&quot;language-text&quot;&gt;@WebMvcTest&lt;/code&gt; abbiamo utilizzato &lt;code class=&quot;language-text&quot;&gt;@DataJpaTest&lt;/code&gt; che serve per testare la persistenza dei dati. Abbiamo bisogno di usare il contesto di Spring Boot perché JPA lo richiede, di conseguenza non possiamo usare solamente Mockito come abbiamo fatto con &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Anche in questo caso non compila, perché non abbiamo il metodo &lt;code class=&quot;language-text&quot;&gt;save&lt;/code&gt; dichiarato in &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt;. Andiamo a sistemare in modo intelligente la questione. Trasformiamo &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; in questo modo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;repository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CrudRepository&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stereotype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Repository&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Repository&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CrudRepository&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Abbiamo trasformato il &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; in un’interfaccia che estende &lt;code class=&quot;language-text&quot;&gt;CrudRepository&lt;/code&gt;, in questo caso &lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-spring-data-jpa-repositories&quot;&gt;utilizziamo un po’ di magia offerta da JPA&lt;/a&gt;. &lt;code class=&quot;language-text&quot;&gt;CrudRepository&lt;/code&gt; ci offre gratis i metodi &lt;code class=&quot;language-text&quot;&gt;save&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;findById&lt;/code&gt; che stiamo utilizzando.&lt;/p&gt;
&lt;p&gt;Ora compila! Proviamo ad avviare il test del Repository, ma purtroppo fallisce in questo modo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;java.lang.IllegalStateException: Failed to load ApplicationContext
	&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
	at com.intellij.rt.execution.junit.JUnitStarter.main&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;JUnitStarter.java:70&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name &lt;span class=&quot;token string&quot;&gt;&apos;vehicleRepository&apos;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;:&lt;/span&gt; Invocation of init method failed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; nested exception is java.lang.IllegalArgumentException: Not a managed type: class it.mattianatali.tddspringbootapi.vehicle.Vehicle
	&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
Caused by: java.lang.IllegalArgumentException: Not a managed type: class it.mattianatali.tddspringbootapi.vehicle.Vehicle
	&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Quello che Spring Boot sta cercando di dirci è che sul modello &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; mancano le annotazioni per poterlo utilizzare insieme al &lt;code class=&quot;language-text&quot;&gt;CrudRepository&lt;/code&gt;, infatti se ci pensiamo bene nessuno ha detto qual’è il campo id del nostro veicolo e come generarlo. Il povero JPA sa solo che esiste il modello &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; e nient’altro.&lt;/p&gt;
&lt;p&gt;Andiamo a risolvere il problema modificando il nostro file &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;lombok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Builder&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;lombok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Data&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Entity&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GeneratedValue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GenerationType&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Data&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@NoArgsConstructor&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@AllArgsConstructor&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@Builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;toBuilder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@Entity&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Id&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@GeneratedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;strategy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GenerationType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;IDENTITY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; brand&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt; year&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Abbiamo aggiunto tre annotazioni:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Entity&lt;/code&gt; serve a JPA per capire che la classe &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; può essere utilizzata come modello per la persistenza del dato sul DB.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Id&lt;/code&gt; stiamo indicando come id della nostra tabella sul DB il campo &lt;code class=&quot;language-text&quot;&gt;Long id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@GeneratedValue(strategy = GenerationType.IDENTITY)&lt;/code&gt; stiamo dicendo a JPA di delegare al DB la generazione dell’id qualora non fosse indicato.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Facciamo partire il test e stavolta funziona!&lt;/p&gt;
&lt;h3&gt;Test in caso di mancato veicolo&lt;/h3&gt;
&lt;p&gt;Aggiungiamo un semplice test per verificare che venga restituito un &lt;code class=&quot;language-text&quot;&gt;Optional.empty()&lt;/code&gt; qualora non esistesse il veicolo.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findById_shouldReturnEmptyIfVehicleNotFound&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;assertEquals&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;999999L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Possiamo andare tranquilli che durante il test non esiste un valore con quell’id perché l’annotazione &lt;code class=&quot;language-text&quot;&gt;@DataJpaTest&lt;/code&gt; ci garantisce che, ogni volta che eseguiamo il test, il DB è pulito.
Eseguendolo vediamo che il test passa come ci aspettavamo, non dobbiamo implementare nient’altro.&lt;/p&gt;
&lt;p&gt;Dobbiamo ricordarci che il setup del DB solitamente è molto più impegnativo: ci sono migrazioni, creazioni di tabelle in modo esplicito, chiamate ad un DB remoto ecc. Noi ce la stiamo cavando facilmente con il DB H2 che abbiamo inserito durante la creazione del progetto. Purtroppo non tratteremo insieme queste tematiche per non perdere il focus dal TDD.&lt;/p&gt;
&lt;h3&gt;Test sui repository&lt;/h3&gt;
&lt;p&gt;Nel nostro caso, a causa di questa semplificazione, stiamo testando su un DB in memory creato ad hoc per i test, tutto questo grazie con l’annotazione &lt;code class=&quot;language-text&quot;&gt;@DataJpaTest&lt;/code&gt;. Purtroppo, cosi facendo, i test sui repository perdono la maggior parte dell’efficacia. Ma ora proviamo ad immaginare di usare questo modus operandi su un progetto vero.&lt;/p&gt;
&lt;p&gt;Noi in Pirelli testiamo i repository su un DB molto simile a quello reale. In questo caso i vantaggi di testare i repo sono tanti, anche se l’implementazione viene fatta “magicamente” da Spring. Per esempio testando un banale &lt;code class=&quot;language-text&quot;&gt;.save()&lt;/code&gt; autogenerato:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Possiamo testare che tutte le proprietà proprietà del modello siano mappate a DB.&lt;/li&gt;
&lt;li&gt;Possiamo verificare che le migrazioni rispecchino veramente il codice.&lt;/li&gt;
&lt;li&gt;Possiamo verificare che non ci siano dei typo negli enum che si mappano nel DB, o che tutti gli enum siano presenti anche lato DB.&lt;/li&gt;
&lt;li&gt;Possiamo verificare che il driver JDBC sia in grado di mappare tutte le proprietà presenti sul modello (e.g. driver vecchi potrebbero non mappare correttamente le classi &lt;code class=&quot;language-text&quot;&gt;Date&lt;/code&gt; di Java 8).&lt;/li&gt;
&lt;li&gt;Possiamo verificare che le relazioni vengano salvate come ci aspettiamo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Poi il repository può crescere e possiamo creare nuovi metodi autogenerati da Spring ma anche qui:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Possiamo testare che le relazioni siano recuperate in modo corretto.&lt;/li&gt;
&lt;li&gt;Possiamo verifiare che non ci siano errori logici nel metodo autogenerato (basta un attimo a confondere un id con un altro o dimenticarti un Not nel metodo).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Infine non dobbiamo trarci in inganno pensando che l’implementazione è semplice (il metodo &lt;code class=&quot;language-text&quot;&gt;.save()&lt;/code&gt; è autogenerato!) e quindi è inutile il test: i test guidano il nostro sviluppo in TDD. Quindi prima testiamo che la funzionalità non esista, poi la implementiamo, infine &lt;strong&gt;il test verifica che esista e rimanga tale per &lt;em&gt;tutti&lt;/em&gt; i prossimi sviluppi&lt;/strong&gt;: il metodo &lt;code class=&quot;language-text&quot;&gt;.save()&lt;/code&gt; può complicarsi, magari non sarà più autogenerato perchè sono state aggiunte logiche ad hoc. Il nostro test sarà sempre lì a darci questa garanzia. Se non lo facciamo all’inizio, ci perdiamo questa opportunità e potremmo avere dei dispiaceri più avanti.&lt;/p&gt;
&lt;h3&gt;Chiamata GET completata!&lt;/h3&gt;
&lt;p&gt;Finalmente ora abbiamo la chiamata GET completamente sviluppata in TDD! Abbiamo 3 componenti ben isolati, facili da testare, con una coverage del 100%.
Sembra che sia stato lungo e difficile, ma solamente perché abbiamo spiegato ogni singola riga di codice e anche perché abbiamo spiegato ogni singolo passo che abbiamo svolto.
La buona notizia è che tramite questo processo possiamo creare qualsiasi endpoint che ci venga in mente: possiamo complicare la logica di business quanto vogliamo, ma il procedimento in TDD rimarrà sempre il medesimo.&lt;/p&gt;
&lt;p&gt;Ora andiamo ad implementare la chiamata POST, ma spiegheremo con lo stesso livello di dettaglio solo il controller dove posso condividere con voi alcuni trucchetti che non ho ancora trattato. Lo sviluppo dei metodi nel service e del repository sarà molto simile a quello che abbiamo fatto per la chiamata GET, quindi sarebbe poco utile ripetere le stesse cose.&lt;/p&gt;
&lt;h2&gt;Implementiamo il controller per la chiamata POST&lt;/h2&gt;
&lt;p&gt;Passiamo ora allo sviluppo della chiamata POST per creare dei nuovi veicoli. Come sempre iniziamo con i test. La prima cosa che verifichiamo è che il nostro veicolo passato nel body venga digerito correttamente da Spring Boot e che venga passato al metodo &lt;code class=&quot;language-text&quot;&gt;VehicleService.save(vehicle)&lt;/code&gt; per salvarlo.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@WebMvcTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleControllerTest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MockMvc&lt;/span&gt; mvc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ObjectMapper&lt;/span&gt; objectMapper&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@MockBean&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create_shouldSaveTheVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleId &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vehicleToSave &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;aValidVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                        vehicleToSave
                                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        mvc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MediaType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeValueAsBytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isCreated&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.id&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.brand&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getBrand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.model&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getModel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;jsonPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$.year&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getYear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;aValidVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ferrari&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;488 GTB&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2019&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Come possiamo leggere, stiamo emulando una chiamata POST, settiamo correttamente il &lt;code class=&quot;language-text&quot;&gt;contentType&lt;/code&gt; della chiamata tramite &lt;code class=&quot;language-text&quot;&gt;.contentType(MediaType.APPLICATION_JSON)&lt;/code&gt; e inseriamo nel body il nostro veicolo da salvare tramite &lt;code class=&quot;language-text&quot;&gt;.content(objectMapper.writeValueAsBytes(vehicleToSave))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Con&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            vehicleToSave
                    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicleId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;emuliamo il fatto che il nostro servizio ci restituisca lo stesso oggetto passato in input ma con l’id popolato. Per questo caso abbiamo usato il metodo &lt;code class=&quot;language-text&quot;&gt;toBuilder&lt;/code&gt; che ci viene gentilmente offerto dall’annotazione &lt;code class=&quot;language-text&quot;&gt;@Builder(toBuilder = true)&lt;/code&gt; che avevamo aggiunto sulla classe &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Infine testiamo che la chiamata HTTP risponda con lo statusCode &lt;code class=&quot;language-text&quot;&gt;201 - Created&lt;/code&gt; e che nel body abbiamo tutti i campi popolati.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;objectMapper&lt;/code&gt; è il serializzatore di default di Spring Boot &lt;a href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Jackson&lt;/a&gt;. Chiediamo una sua istanza a Spring Boot tramite &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Il compilatore si sta lamentando che non esiste il metodo save sul &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;, andiamo ad aggiungerlo senza implementare la logica corretta.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleRepository&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicleRepository &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vehicleRepository&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; vehicleToSave&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Avviamo il test e fallisce per questo motivo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.
java.lang.AssertionError: Status expected:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;1&lt;/span&gt;&gt;&lt;/span&gt; but was:&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&lt;span class=&quot;token file-descriptor important&quot;&gt;4&lt;/span&gt;&gt;&lt;/span&gt;
Expected :201
Actual   :404
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Click to see difference&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Giustamente l’endpoint non esiste ancora, quindi andiamo ad aggiungerlo sul &lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;errors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleNotFoundException&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beans&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Autowired&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;http&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;HttpStatus&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleService&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicleService &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token annotation punctuation&quot;&gt;@PostMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@ResponseStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;HttpStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CREATED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saveVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@RequestBody&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; vehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@PostMapping&lt;/code&gt; è l’annotazione che ci permette di definire un’endpoint POST.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ResponseStatus(HttpStatus.CREATED)&lt;/code&gt; possiamo definire lo status code di risposta, di default è &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt;, noi invece vogliamo &lt;code class=&quot;language-text&quot;&gt;201 - Created&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@RequestBody&lt;/code&gt; è l’annotazione che ci permette di prendere il valore passato nel body e di deserializzarlo a &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In questo caso ci basta invocare il metodo &lt;code class=&quot;language-text&quot;&gt;vehicleService.save&lt;/code&gt; e di ritornare il suo valore.&lt;/p&gt;
&lt;p&gt;Facendo girare i test è tutto ok!&lt;/p&gt;
&lt;p&gt;Abbiamo quasi finito, ma dobbiamo ancora implementare la regola che ci è stata data quando salviamo un veicolo. La ripropongo qui:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il &lt;code class=&quot;language-text&quot;&gt;brand&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; sono obbligatori, l’anno di produzione del veicolo non può essere antecedente al &lt;code class=&quot;language-text&quot;&gt;1950&lt;/code&gt; per ragioni di business.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Andiamo a creare il test che verifica queste condizioni.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fasterxml&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jackson&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;databind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ObjectMapper&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;api&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;extension&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ExtendWith&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ParameterizedTest&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;params&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;provider&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MethodSource&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;beans&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Autowired&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;autoconfigure&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;WebMvcTest&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;boot&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockBean&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;http&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MediaType&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;junit&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jupiter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvc&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;util&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;stream&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Stream&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hamcrest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Matchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;is&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mockito&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Mockito&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;when&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcRequestBuilders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;get&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcRequestBuilders&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;post&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;jsonPath&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token import static&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;springframework&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;test&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;web&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;servlet&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MockMvcResultMatchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token static&quot;&gt;status&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@ExtendWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SpringExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@WebMvcTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;VehicleController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VehicleControllerTest&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@ParameterizedTest&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@MethodSource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;getInvalidVehicles&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;create_shouldReturnBadRequestIfBodyIsInvalid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; invalidVehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        mvc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MediaType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;objectMapper&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeValueAsBytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;invalidVehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isBadRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getInvalidVehicles&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; validVehicle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;aValidVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                validVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                validVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;brand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                validVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                validVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                validVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                validVehicle&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;year&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1949&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Qui possiamo vedere una bellissima funzionalità di JUnit 5: i &lt;strong&gt;test parametrici&lt;/strong&gt;!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Attraverso l’annotazione &lt;code class=&quot;language-text&quot;&gt;@ParametrizedTest&lt;/code&gt; definiamo un test che in input vuole un parametro.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@MethodSource(&quot;getInvalidVehicles&quot;)&lt;/code&gt; definiamo il metodo che ci fornirà i veicoli che sono invalidi e che dobbiamo testare.&lt;/li&gt;
&lt;li&gt;Il medodo &lt;code class=&quot;language-text&quot;&gt;getInvalidVehicles()&lt;/code&gt; ci ritorna uno stream di veicoli invalidi, per creare questo stream partiamo da un veicolo valido che abbiamo già testato nell’altro test (&lt;code class=&quot;language-text&quot;&gt;aValidVehicle()&lt;/code&gt;), poi da questo creiamo un veicolo invalido modificando i parametri. In questo modo creiamo 6 test che testa rispettivamente tutte le regole che il business ci ha imposto ossia:
&lt;ul&gt;
&lt;li&gt;Il parametro &lt;code class=&quot;language-text&quot;&gt;brand&lt;/code&gt; non può essere nullo o stringa vuota.&lt;/li&gt;
&lt;li&gt;Il parametro &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; non può essere nullo o stringa vuota.&lt;/li&gt;
&lt;li&gt;Il parametro &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; non può essere nullo.&lt;/li&gt;
&lt;li&gt;Il parametro &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; non può essere inferiore al &lt;code class=&quot;language-text&quot;&gt;1950&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Facciamo partire il test ed effettivamente vediamo che abbiamo 6 test che falliscono.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;java&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lang&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;AssertionError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Status&lt;/span&gt; expected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;400&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; but was&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;201&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Expected&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Actual&lt;/span&gt;   &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;201&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Per implementare la validazione dei veicoli possiamo sfruttare la validazione di Spring Boot.
Quindi andiamo ad inserire le regole di validazione sul modello &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;it&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mattianatali&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tddspringbootapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Entity&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GeneratedValue&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;GenerationType&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;persistence&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Id&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;validation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constraints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Min&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;validation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constraints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NotEmpty&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token import&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;javax&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;validation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;constraints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;NotNull&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Id&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@GeneratedValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;strategy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;GenerationType&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;IDENTITY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Long&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@NotNull&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@NotEmpty&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; brand&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@NotNull&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@NotEmpty&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@NotNull&lt;/span&gt;
    &lt;span class=&quot;token annotation punctuation&quot;&gt;@Min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1950&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Integer&lt;/span&gt; year&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@NotNull&lt;/code&gt; diciamo che il campo non può essere &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@NotEmpty&lt;/code&gt; diciamo che il campo non può essere stringa vuota.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Min(1950)&lt;/code&gt; significa che il campo deve essere almeno &lt;code class=&quot;language-text&quot;&gt;1950&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Infine, per abilitare la validazione, dobbiamo modificare il controller mettendo l’annotazione &lt;code class=&quot;language-text&quot;&gt;@Valid&lt;/code&gt; nel &lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;java&quot;&gt;&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@PostMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/vehicles&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token annotation punctuation&quot;&gt;@ResponseStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;HttpStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CREATED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;saveVehicle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@RequestBody&lt;/span&gt; &lt;span class=&quot;token annotation punctuation&quot;&gt;@Valid&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vehicle&lt;/span&gt; vehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; vehicleService&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vehicle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Facciamo girare i test e ora sono tutti verdi! In questo modo abbiamo fatto in un colpo ben 6 test senza duplicare il codice.&lt;/p&gt;
&lt;p&gt;Ora che abbiamo implementato il controller, manca il metodo &lt;code class=&quot;language-text&quot;&gt;vehicleService.save&lt;/code&gt; da implementare, questo lo lascio come compito a casa dato che non darebbe nessun valore aggiunto a questo articolo: dobbiamo praticamente fare la stessa cosa che abbiamo fatto con la chiamata GET. E il metodo del &lt;code class=&quot;language-text&quot;&gt;VehicleRepository.save&lt;/code&gt;, lo abbiamo già testato quando abbiamo implementato la chiamata GET.
In ogni caso &lt;a href=&quot;https://github.com/matitalatina/tdd-spring-boot-api&quot;&gt;nel mio repository&lt;/a&gt; potete trovare il progetto completo.&lt;/p&gt;
&lt;h1&gt;Conclusioni&lt;/h1&gt;
&lt;p&gt;È stata una lunga chiacchierata, &lt;strong&gt;spero proprio che&lt;/strong&gt; dopo questa lettura abbiate imparato un po’ di funzionalità offerte da JUnit 5, Spring Boot, Lombok, ma soprattutto &lt;strong&gt;sia entrato in voi la filosofia del TDD&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;La cosa che deve essere chiara è questa: &lt;strong&gt;prima ci preoccupiamo di cosa vogliamo raggiungere, poi ci preoccupiamo di come raggiungerlo&lt;/strong&gt;. Il &lt;em&gt;cosa&lt;/em&gt; vogliamo raggiungere si traduce in test, il &lt;em&gt;come&lt;/em&gt; si traduce nell’implementazione.&lt;/p&gt;
&lt;p&gt;In questo modo abbiamo un codice ben testato, ben organizzato in classi isolate (se una classe è facile da testare, significa che è ben isolata dal resto dei componenti) e soprattutto facile da mantenere (i refactor sono semplici perché ogni singola funzionalità è testata, le regressioni sono pressochè azzerate).&lt;/p&gt;
&lt;p&gt;All’inizio può essere difficile, ma poi una volta internalizzato esce naturale e si ha un valore aggiunto che non si può capire fino a che si ha in produzione un progetto sviluppato in TDD. Provare per credere!&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come creare una pipeline di Continuous Integration e Continuous Deployment (CI/CD) · DevOps]]></title><description><![CDATA[Introduzione Una cosa che ho imparato in Pirelli è l’implementazione delle pipeline per avere la Continuous Integration (CI) e Continuous…]]></description><link>https://www.mattianatali.it/it/creare-pipeline-ci-cd/</link><guid isPermaLink="false">https://www.mattianatali.it/it/creare-pipeline-ci-cd/</guid><pubDate>Sat, 16 Mar 2019 07:03:47 GMT</pubDate><content:encoded>&lt;h1&gt;Introduzione&lt;/h1&gt;
&lt;p&gt;Una cosa che ho imparato in Pirelli è l’implementazione delle pipeline per avere la Continuous Integration (CI) e Continuous Deployment (CD), d’ora in poi lo chiamerò semplicemente &lt;a href=&quot;https://en.wikipedia.org/wiki/CI/CD&quot;&gt;CI/CD&lt;/a&gt;. Nascono sempre numerosi progetti con architettura a microservizi: il tempo al lavoro è sempre poco e i lavori ripetitivi mi annoiano facilmente… Cosa c’è di più ripetitivo di una messa in produzione di tutti questi microservizi? Queste pipeline automatiche quindi diventano essenziali per non passare la giornata a fare solo questo noioso mestiere.&lt;/p&gt;
&lt;p&gt;Non voglio annoiarvi troppo parlando sui vari vantaggi che CI/CD comporta, se siete giunti su questo post significa che lo sapete già, quindi inizio subito con un esempio pratico.&lt;/p&gt;
&lt;h2&gt;Creazione della pipeline per GasLow Backend&lt;/h2&gt;
&lt;p&gt;Come esempio utilizzerò il backend di un mio progetto che ho creato nel mio tempo libero: &lt;a href=&quot;https://github.com/matitalatina/gaslow&quot;&gt;GasLow&lt;/a&gt;. Sostanzialmente è un backend che è in grado di recuperare gli open data che riguardano i prezzi dei carburanti in Italia e di fornire queste informazioni in base alla propria posizione. L’app Android, basata su &lt;a href=&quot;https://flutter.dev/&quot;&gt;Flutter&lt;/a&gt;, che utilizza questo backend è &lt;a href=&quot;https://play.google.com/store/apps/details?id=it.mattianatali.gaslowapp&amp;#x26;hl=it&quot;&gt;disponibile gratuitamente sul Play Store&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;La cosa importante per noi sono queste:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il backend è scritto in Node.js + TypeScript, il database è MongoDB.&lt;/li&gt;
&lt;li&gt;Il file di configurazione con i dati per connettersi al DB si trova nel file &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt;, nella root del progetto. Ovviamente il file non è pubblicato su Git per evitare che il mondo intero sappia le credenziali del DB. Potete vedere un esempio di dati contenuti in questo file leggendo &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Il server di “produzione” si trova su &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; su una macchina gratuita. In questa guida saremo in grado di automatizzare il deploy su Heroku.&lt;/li&gt;
&lt;li&gt;Sto implementando anche la versione AWS serverless, dove viene deployata usando CloudFormation. Purtroppo questa parte è un po’ troppo da spiegare in questa guida introduttiva sulla CI/CD. Magari farò una guida dedicata su questo argomento in futuro.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Prerequisiti&lt;/h1&gt;
&lt;p&gt;Per capire a pieno questa guida abbiamo bisogno di queste conoscenze:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un minimo di conoscenza di &lt;a href=&quot;https://it.wikipedia.org/wiki/Git_(software)&quot;&gt;Git&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Com’è strutturato un progetto in &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; e i comandi base del suo package manager &lt;a href=&quot;https://it.wikipedia.org/wiki/Npm_(software)&quot;&gt;npm&lt;/a&gt;. Questa parte in realtà non è obbligatoria per capire la pipeline come concetto, serve solamente per capire la pipeline di questo esempio specifico.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Scegliamo il servizio di CI/CD&lt;/h1&gt;
&lt;p&gt;Il primo passo importante per automatizzare il tutto è scegliere il servizio che vogliamo utilizzare. La scelta è veramente ampia. Quelli che conosco ed ho utilizzato sono questi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt;: molto potente e flessibile. È hostato da loro e quindi non abbiamo bisogno di una nostra macchina per farlo girare. Offre un piano gratuito di 1000 minuti/mese sia per i vostri progetti pubblici che privati, non è male per un uso hobbista. Per ora è la mia prima scelta per i miei progetti privati ed era quello che usavo in Pirelli fino ad un mese fa.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://about.gitlab.com/&quot;&gt;GitLab&lt;/a&gt;: anche questo è potente quanto CircleCI. Si può utilizzare la versione hostata da loro come installarlo sulla vostra macchina. È un po’ diverso dagli altri perché offre un pacchetto completo per il vostro progetto (ha Git integrato quindi lo potete usare anche come repository). Per ora è la nostra prima scelta in Pirelli e stiamo infatti facendo una bella migrazione da CircleCI.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt;: forse è un pelino più indietro rispetto ai primi due. Per esempio non è possibile fare ancora un deploy di tipo manuale, &lt;a href=&quot;https://stackoverflow.com/questions/50831785/travis-manually-confirm-next-stage&quot;&gt;a meno di non inventarsi hack come questo&lt;/a&gt;. Per manuale intendo avere un bottone che ci permetta di eseguire un deploy solo dopo una conferma. Questa funzione per me è molto utile per avere pieno controllo di quando vogliamo fare il deploy in produzione. A parte questo piccolo neo ha un grossissimo vantaggio: è gratis per tutti i progetti pubblici! Proprio per questo motivo lo uso per i miei progetti pubblici (come GasLow). &lt;strong&gt;La nostra guida si baserà su Travis CI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt;: è una pietra miliare e il più antico di tutti. Io l’ho usato solo poche volte e sinceramente non mi ha mai entusiasmato più di tanto, soprattutto per quanto riguarda la UX. Ma questa è una mia opinione personale e quindi parecchio soggettiva.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Obiettivo della guida&lt;/h1&gt;
&lt;p&gt;In questa guida vorrei vivere con voi la &lt;strong&gt;creazione di una pipeline avendo un progetto già avviato e che è già in produzione&lt;/strong&gt;. Perché farlo con un progetto già avviato? Perché è un caso d’uso tipico che si incontra al lavoro e probabilmente è la vostra situazione attuale, infine perché di “hello world” per la creazione della pipeline c’è già pieno il web. Ma solitamente sono esempi focalizzati sull’apprendimento del servizio che offre le pipeline, e non tanto per apprendere i concetti e le difficoltà che si incontrano nella vita reale.&lt;/p&gt;
&lt;p&gt;Mettiamo in chiaro cosa vogliamo raggiungere: immaginiamo di essere al lavoro e come task della settimana ci è stato proposto di creare la pipeline CI/CD per il progetto GasLow.
Alla fine della guida avremo una pipeline composta da due fasi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Esecuzione dei test: passo fondamentale per ottenere la &lt;strong&gt;Continuous Integration (CI)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Deploy in produzione sulla macchina di Heroku: passo per ottenere il &lt;strong&gt;Continuous Deployment (CD)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Questo è il minimo indispensabile per ottenere una pipeline completa di CI/CD e per non allungare troppo la guida ci limiteremo a questi due passi.
Una volta preso dimestichezza con l’argomento si può complicare la pipeline a piacere. Per esempio una tipica pipeline che utilizzo al lavoro è composta dai seguenti passi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build e unit tests dell’applicazione.&lt;/li&gt;
&lt;li&gt;Creazione dell’immagine Docker attraverso il Dockerfile, push dell’immagine sul repository AWS ECR.&lt;/li&gt;
&lt;li&gt;Migrazione del database e deploy dell’immagine Docker in ambiente di DEV.&lt;/li&gt;
&lt;li&gt;Integration tests sull’ambiente di DEV.&lt;/li&gt;
&lt;li&gt;Migrazione del database e deploy con conferma manuale in ambiente di QLT utilizzato dal nostro QA Team.&lt;/li&gt;
&lt;li&gt;Migrazione del database e deploy con conferma manuale in ambiente di Produzione.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Registrazione a Travis CI&lt;/h1&gt;
&lt;p&gt;Questo passo è semplicissimo, vi basta andare sulla loro &lt;a href=&quot;https://cdn.travis-ci.org/images/landing-page/laptop-f308ed79defa4f49c5f01af29a60084d.png&quot;&gt;home page&lt;/a&gt; e premere sul bottone “SignUp”, inserite le vostre credenziali di GitHub, e a questo punto avete di fatto collegato Travis CI al vostro GitHub. Una volta fatto questo entrerete nella pagina principale di Travis CI.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.travis-ci.org/images/landing-page/laptop-f308ed79defa4f49c5f01af29a60084d.png&quot; alt=&quot;Pagina principale di Travis CI&quot;&gt;&lt;/p&gt;
&lt;p&gt;sulla sinistra vi compariranno i vostri progetti GitHub che utilizzano Travis CI come servizio di CI/CD. All’inizio sarà vuoto ovviamente. Per ora non ci serve sapere altro.&lt;/p&gt;
&lt;h1&gt;Fork del progetto&lt;/h1&gt;
&lt;p&gt;Se volete provare con mano anche voi, potete fare il fork del mio progetto e buttare via il file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; perché lo ricreeremo insieme per formare la pipeline che abbiamo in mente.
Il commit di riferimento ha come hash &lt;code class=&quot;language-text&quot;&gt;d09f1068a14ddcdb857f1ced90b532680b050917&lt;/code&gt;, quindi per essere perfettamente allineati a questa guida dovremo fare il checkout di questo specifico commit, non escludo che il progetto possa avere profonde modifiche nel corso del tempo.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; checkout d09f1068a14ddcdb857f1ced90b532680b050917&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Una volta forkato e rimosso il file possiamo andare sui settaggi di Travis CI (menu utente in alto a destra -&gt; Settings). In questa pagina dovrebbero comparire tutti i nostri repo, compreso questo appena forkato. Se non vedete nulla cliccate sul bottone &lt;code class=&quot;language-text&quot;&gt;Sync Account&lt;/code&gt;, per sincronizzare Travis CI. Poi possiamo vedere il repo gaslow come in figura, abilitiamo il toggle.
Ora abbiamo la repo forkata, Travis CI pronto e connesso ad esso. Ora inizia la parte divertente: mettiamo in piedi il primo step della nostra pipeline.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0cfe33d207b68d3ff31e2dd1c4506444/9e121/travis-activate-repo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 59.199999999999996%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAABUklEQVR42qVS207EIBDl8/0XP0JfjDEboy8+6G40bndba3cLBQplgNZDm66X7Zsnk8kAM5wzAyzLsvfttizLPM8RF0UBn+/3yec5llVVHX4ASyHE3e3NZr1mROSsdV1nrTXGTN57341wzqUE57oZSMBW9VlKKVnTCFSEvo+zAZv1M+c1jpVSnHNcNyyBXa1WD7vdTmlL1BIZIhRLwZumQTGoUAnyP2XIScWXb9uL+8frbH/aAkyIxhMqTzvLzG31IYVAczHGKRW+0RrWam3aFh4AfzsC8RRADqPXF6uk/U3iY/QhUojOBwTjHIbR9+AIsAAXmbI2NdeASUMn5oy0Uh0KeTgYXrZ1bYUmNZlyEsq+ZdP4DDQjiR96Lo+NFr53FDsXbDebIQ1GTVCWwM7HAG2pMd0uTgt/4OlYgxIPzhbHCAk4w93nR5iAckkg2mbDP/AFQ2i4LXQzdxEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;travis-activate-repo&quot;
        title=&quot;&quot;
        src=&quot;/static/0cfe33d207b68d3ff31e2dd1c4506444/9fabd/travis-activate-repo.png&quot;
        srcset=&quot;/static/0cfe33d207b68d3ff31e2dd1c4506444/c6e3d/travis-activate-repo.png 500w,
/static/0cfe33d207b68d3ff31e2dd1c4506444/da8b6/travis-activate-repo.png 1000w,
/static/0cfe33d207b68d3ff31e2dd1c4506444/9fabd/travis-activate-repo.png 2000w,
/static/0cfe33d207b68d3ff31e2dd1c4506444/9e121/travis-activate-repo.png 2062w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;Implementazione della pipeline di Continuous Integration (fase di testing)&lt;/h1&gt;
&lt;h2&gt;Testing in locale&lt;/h2&gt;
&lt;p&gt;Prima di andare a creare la pipeline poniamoci questa domanda: come si eseguono i test in locale? &lt;strong&gt;Il modo migliore per creare una pipeline automatica è di pensare tutti i vari step che dobbiamo fare in locale per raggiungere lo stesso obiettivo&lt;/strong&gt;. Qui do per scontato che abbiamo un minimo di esperienza in Node.js e come funziona il package manager &lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Uno che mastica Node.js da mattina a sera ha già pensato a come si fa: c’è il comando &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;… Ma siamo sicuri che basta solo questo? In questo caso stiamo dando per scontato un po’ di cose che per Travis CI non lo saranno affatto.&lt;/p&gt;
&lt;p&gt;Per eseguire i test con &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; stiamo dando per scontato i seguenti punti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sulla propria macchina c’è installato Node.js v8.&lt;/li&gt;
&lt;li&gt;Sulla propria macchina abbiamo MongoDB installato e attivo sulla porta standard &lt;code class=&quot;language-text&quot;&gt;:27017&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Abbiamo installato tutte le dipendenze (tramite il comando &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt;) e che quindi abbiamo la cartella &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; correttamente popolata.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quindi i passaggi corretti per eseguire i test su una macchina pulita sono i seguenti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/it/download/&quot;&gt;Installa Node.js v8&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/installation/&quot;&gt;Installa MongoDB&lt;/a&gt; e attivalo sulla porta di default &lt;code class=&quot;language-text&quot;&gt;:27017&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; per installare le dipendenze presenti nel file &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; e quindi popolare la cartella &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; per eseguire i test.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Testing usando Travis CI&lt;/h2&gt;
&lt;p&gt;Ora che abbiamo capito i passaggi in locale, proviamo a tradurli in passaggi che possono essere digeriti da Travis CI.&lt;/p&gt;
&lt;p&gt;Per far eseguire automaticamente i test a Travis CI abbiamo bisogno di un mezzo per comunicare. &lt;strong&gt;Il modo di comunicare con questo servizio è il file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt;&lt;/strong&gt;, proprio il file che vi ho fatto cancellare durante il fork del progetto. L’estensione del file magari vi può essere sconosciuta. &lt;code class=&quot;language-text&quot;&gt;yml&lt;/code&gt; viene usato per il formato &lt;em&gt;YAML&lt;/em&gt; che sta per (&lt;em&gt;YAML Ain’t Markup Language&lt;/em&gt;). È diventato lo standard de-facto nel mondo DevOps perché da un lato è “espressivamente” molto potente, dall’altro è molto semplice da leggere per un umano.
Questo formato, per quanto possa essere semplice da leggere, ha molte regole che ci vuole un po’ di tempo per padroneggiarle e conoscerle tutte. Comunque non dobbiamo preoccuparci più di tanto: noi useremo solo il minimo indispensabile e dei concetti molto di base. Io di solito utilizzo &lt;a href=&quot;https://learnxinyminutes.com/docs/yaml/&quot;&gt;Learn yaml in Y minutes&lt;/a&gt; come cheatsheet per lo yaml: questo sito è molto conciso ed allo stesso tempo ricco di informazioni; dateci un’occhiata anche per altri linguaggi, non ve ne pentirete.&lt;/p&gt;
&lt;p&gt;Iniziamo con il creare il file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; nella root di progetto. Al suo interno inseriamo questo contenuto:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; node_js

&lt;span class=&quot;token key atrule&quot;&gt;node_js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;8&apos;&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; mongodb

&lt;span class=&quot;token key atrule&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm install
&lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In questo modo, Travis CI è in grado di far girare i nostri test. Proviamo a committare il file, effettivamente vediamo che Travis CI ha iniziato a lavorare e che ha eseguito i test.&lt;/p&gt;
&lt;p&gt;Ora proviamo a vedere le similitudini con i passaggi che avevamo bisogno in locale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Abbiamo detto a Travis CI di installare Node.js v8? Sì attraverso la direttiva&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; node_js

&lt;span class=&quot;token key atrule&quot;&gt;node_js&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;8&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Abbiamo detto a Travis CI di installare MongoDB e di aprire la porta standard di Mongo? Sì attravers la direttiva&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; mongodb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Abbiamo installato le dipendenze del progetto prima di eseguire i test? Sì attraverso l’esecuzione dello script &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; durante la fase di installazione del nostro job, attraverso la direttiva&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Abbiamo fatto girare i test? Sì attraverso l’esecuzione dello script &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; durante la fase principale del job, tramite la direttiva&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; npm test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Quindi possiamo dire di aver eseguito gli stessi passaggi che facevamo in locale usando un linguaggio che Travis CI capisce. Non voglio dilungarmi troppo sul linguaggio che utilizza Travis CI perché è molto specifico al servizio che stiamo utilizzando: CircleCI, GitLab avrebbero usato un linguaggio leggermente diverso. Quello che deve passare qui è questo: &lt;strong&gt;Travis CI è come se fosse un foglio di carta bianco&lt;/strong&gt;, siamo noi che dobbiamo istruirlo come eseguire i nostri test. Il modo migliore di istruirlo è di &lt;strong&gt;pensare prima ai passaggi che facciamo in locale, poi li rifacciamo nel linguaggio della piattaforma che noi utilizziamo&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Per chi volesse saperne di più sul linguaggio specifico di Travis CI, lascio qui dei link che approfondiscono gli argomenti appena trattati:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/languages/&quot;&gt;Per conoscere i linguaggi supportati&lt;/a&gt;, nello specifico &lt;a href=&quot;https://docs.travis-ci.com/user/languages/javascript-with-nodejs/&quot;&gt;JavaScript&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/database-setup/&quot;&gt;Per sapere come aggiungere dei nuovi servizi&lt;/a&gt; come MongoDB.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/job-lifecycle/&quot;&gt;Per conoscere le varie fasi di un job&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/637cc8d05ad051a045baf3c246e52f29/fe98d/travis-test-ok.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 57.400000000000006%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeUlEQVR42o2QTW+CQBCG95+o9VBNo1TURHuwJqYXYzxxrIlnT/7bnlqtKCrKguyyn4AdqTEcTNMnhIQ388wMgzzPwxgHQYBzwCchhGZEAGUkBwSuu18uvlCstZQyjuMkQ3COfXw8Hk9hCH05E9/O8jP4ON8DEaWEjs/pFZ71kuLycM4hiRNorPMOhEIIrTVyQpdwqrSCVGi5JnsRSyIjqhgU3YQIWilxTq8yYwxGINt3CCURjyBlmq9OToB9z8cwOy/T6PL/t+R3TbQCGQ6iOHQFeYHtKKRSqfQfoPVpS3nEJU+TFNb2eABd8jP/IJtMCfgJ2Gnq+77tbNfO1s3YbDa73c7Nccw4HA5QiezAIYzCzXR20vl83uu9DIdv/f5r/x6DwcCyrNFoNJvN0CpwQkrAh8kgTybvlUq5223U60+lUqlYhNfDjXK5XCgU2u12o9EYj8cX+XLJbG2Qp9NptfrY6UBB0zSNZtMwzed6jlqt1mq1DMOwLOsHB6AYSqxkhl0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;travis-test-ok&quot;
        title=&quot;&quot;
        src=&quot;/static/637cc8d05ad051a045baf3c246e52f29/9fabd/travis-test-ok.png&quot;
        srcset=&quot;/static/637cc8d05ad051a045baf3c246e52f29/c6e3d/travis-test-ok.png 500w,
/static/637cc8d05ad051a045baf3c246e52f29/da8b6/travis-test-ok.png 1000w,
/static/637cc8d05ad051a045baf3c246e52f29/9fabd/travis-test-ok.png 2000w,
/static/637cc8d05ad051a045baf3c246e52f29/fe98d/travis-test-ok.png 2720w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Deployment usando Travis CI&lt;/h2&gt;
&lt;p&gt;Ora che abbiamo eseguito i test vogliamo deployare il nostro codice su Heroku. &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;, per chi non lo conoscesse, permette di deployare il proprio codice sulla loro piattaforma &lt;a href=&quot;https://it.wikipedia.org/wiki/Platform_as_a_service&quot;&gt;PaaS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prima di creare la pipeline, abbiamo bisogno di creare un’applicazione su Heroku,&lt;/strong&gt; fortunatamente danno la possibilità di ospitare il nostro progetto gratuitamente.&lt;/p&gt;
&lt;p&gt;Ci registriamo e creiamo una nuova app.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1804px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b8f3c53ce68d9e1fd29f44a255809a94/d956b/heroku-new-app.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 37.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAo0lEQVR42qWQyw4CMQhF+///aZyok2mBtkBpKzUuXLhw4s0JgfAKBIxcSfsYvQ+zLmIOf6DaW1t41mtW2RgkBpnDdomPG6VYIVUATokTvInI0R2UBS0gO3oAXze87yXUorWqqGnr3/HUi6ZG2WdlxBJ3LFkCYjaz+ZtK5f1IRAWpiGoA9+nXfj+bWUS0LttCyezxGGOelH/Ob16z5nn5vjD/0BP74db9LSq2VwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Creazione nuova app su Heroku&quot;
        title=&quot;&quot;
        src=&quot;/static/b8f3c53ce68d9e1fd29f44a255809a94/d956b/heroku-new-app.png&quot;
        srcset=&quot;/static/b8f3c53ce68d9e1fd29f44a255809a94/c6e3d/heroku-new-app.png 500w,
/static/b8f3c53ce68d9e1fd29f44a255809a94/da8b6/heroku-new-app.png 1000w,
/static/b8f3c53ce68d9e1fd29f44a255809a94/d956b/heroku-new-app.png 1804w&quot;
        sizes=&quot;(max-width: 1804px) 100vw, 1804px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Ora torniamo sul file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; e aggiungiamo alla fine:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;before_deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &amp;lt;STEP_MISTERIOSO&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; npm run build
&lt;span class=&quot;token key atrule&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; heroku
  &lt;span class=&quot;token key atrule&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&amp;lt;API_KEY&gt;&apos;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &amp;lt;HEROKU_APP&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; master
  &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; NODE_ENV=production
  &lt;span class=&quot;token key atrule&quot;&gt;skip_cleanup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Una piccola spiegazione di quello che abbiamo aggiunto:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;before_deploy&lt;/code&gt; è la keyword per definire cosa bisogna fare appena prima della fase di &lt;em&gt;deploy&lt;/em&gt;. La fase di deploy è il passo all’interno di un job che è adibito a deployare il nostro codice su Heroku. Il &lt;em&gt;job&lt;/em&gt;, per Travis CI, si compone essenzialmente di tre fasi: &lt;em&gt;install&lt;/em&gt;, &lt;em&gt;script&lt;/em&gt; e &lt;em&gt;deploy&lt;/em&gt;. Se volete approfondire, potete leggere direttamente dalla &lt;a href=&quot;https://docs.travis-ci.com/user/job-lifecycle/&quot;&gt;documentazione di Travis CI le varie fasi che compongono un job&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;STEP_MISTERIOSO&gt;&lt;/code&gt; è un passo essenziale per il deploy che non vi ho ancora detto, ne parlo più avanti.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npm run build&lt;/code&gt; è lo script che dobbiamo eseguire prima del deploy. Questo script è legato strettamente al nostro progetto. Se siete curiosi potete andare nel file &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; e vedere che lo script build esegue il comando &lt;code class=&quot;language-text&quot;&gt;parcel build src/server.ts --target node&lt;/code&gt;. Esso non fa altro che chiamare &lt;a href=&quot;https://parceljs.org/&quot;&gt;Parcel.js&lt;/a&gt; &lt;a href=&quot;https://en.wikipedia.org/wiki/Source-to-source_compiler&quot;&gt;transpilare&lt;/a&gt; il codice TypeScript in JavaScript, fare il bundling, minificarlo e inserirlo nella cartella &lt;code class=&quot;language-text&quot;&gt;/dist&lt;/code&gt;. Alla fine di questo progetto abbiamo quindi il file &lt;code class=&quot;language-text&quot;&gt;/dist/server.js&lt;/code&gt; pronto per essere eseguito in produzione.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;deploy&lt;/code&gt; è la keyword per definire cosa bisogna fare durante la fase di deploy.&lt;/li&gt;
&lt;li&gt;Con &lt;code class=&quot;language-text&quot;&gt;provider&lt;/code&gt; definiamo che stiamo usando Heroku come piattaforma.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;api_key&lt;/code&gt; serve per definire le credenziali per poter effettivamente deployare con Heroku. Il prossimo passo sarà di sostituire &lt;code class=&quot;language-text&quot;&gt;&apos;&amp;lt;API_KEY&gt;&apos;&lt;/code&gt; con le vere chiavi (criptate).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;app: &amp;lt;HEROKU_APP&gt;&lt;/code&gt; indichiamo a Travis CI su quale app di Heroku vogliamo fare il deploy. Dobbiamo sostituire &lt;code class=&quot;language-text&quot;&gt;&amp;lt;HEROKU_APP&gt;&lt;/code&gt; con il nome dell’applicazione Heroku che abbiamo creato nel passo precedente.&lt;/li&gt;
&lt;li&gt;Con &lt;code class=&quot;language-text&quot;&gt;on: branch: master&lt;/code&gt; possiamo fare il deploy solo quando pushiamo sul branch &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt;. Senza questa direttiva ogni singolo push su un qualsiasi branch git farebbe scatenare il deploy automatico.&lt;/li&gt;
&lt;li&gt;Con &lt;code class=&quot;language-text&quot;&gt;env:&lt;/code&gt; possiamo definire le variabili d’ambiente che il nostro progetto avrà a disposizione su Heroku. Nel nostro caso abbiamo aggiunto la variabile &lt;code class=&quot;language-text&quot;&gt;NODE_ENV=production&lt;/code&gt; che è uno standard nel mondo Node.js per definire che siamo su un ambiente di produzione.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;skip_cleanup: true&lt;/code&gt; ci permette di evitare la cancellazione dei file generati nel passo precedente. Durante la fase di test abbiamo eseguito il comando &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; che popola la cartella &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; che è essenziale per il corretto funzionamento del sistema. In questo modo possiamo evitare di rifarlo e quindi risparmiamo del tempo nella fase di deploy. Dobbiamo immaginare che la fase di &lt;em&gt;deploy&lt;/em&gt; è separata dalla fase di &lt;em&gt;script&lt;/em&gt;, quindi avremmo solo il codice sorgente senza questa direttiva.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se vogliamo conoscere tutti i vari parametri che possiamo utilizzare per fare un deploy su Heroku &lt;a href=&quot;https://docs.travis-ci.com/user/deployment/heroku/&quot;&gt;possiamo leggere la documentazione ufficiale&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ricapitolando ci sono ancora due cose da fare:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Capire cosa dobbiamo fare nello &lt;code class=&quot;language-text&quot;&gt;STEP_MISTERIOSO&lt;/code&gt;: ha a che fare con la configurazione del nostro progetto in produzione. Vi do un indizio: andate a leggere il file &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/src/util/secrets.ts&quot;&gt;src/util/secrets.ts&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Recuperare l’&lt;code class=&quot;language-text&quot;&gt;API_KEY&lt;/code&gt; di Heroku criptata per far sì che Travis CI possa autenticarsi ed eseguire il deploy.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Capire lo step misterioso&lt;/h3&gt;
&lt;p&gt;C’è una parte che ho tenuto nascosto fin dall’inizio e che ora è giunto il momento di parlarne. Abbiamo detto che il progetto si basa su MongoDB, ma dove prende le credenziali per collegarsi? Abbiamo eseguito dei test precedentemente, eppure pare che si sia connesso senza problemi. Anche Travis CI, durante i test, si è connesso.
Il recupero delle informazioni sulla connessione possiamo leggerlo nel file &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/src/util/secrets.ts&quot;&gt;src/util/secrets.ts&lt;/a&gt; che riporto qui per semplicità:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; logger &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./logger&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; dotenv &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dotenv&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; fs &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;fs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Using .env file to supply config environment variables&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dotenv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.env&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Using .env.example file to supply config environment variables&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dotenv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.env.example&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// you can delete this after you create your own .env file!&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ENVIRONMENT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; prod &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ENVIRONMENT&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;production&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Anything else is treated as &apos;dev&apos;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;SESSION_SECRET&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SESSION_SECRET&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;MONGODB_URI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; prod &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;MONGODB_URI&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;MONGODB_URI_LOCAL&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SESSION_SECRET&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No client secret. Set SESSION_SECRET environment variable.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MONGODB_URI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    logger&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;No mongo connection string. Set MONGODB_URI environment variable.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In pratica il codice si comporta in questo modo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Recupera il file &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt;, se non c’è fai il fallback sul file &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Recupera il valore &lt;code class=&quot;language-text&quot;&gt;SESSION_SECRET&lt;/code&gt; da questo file.&lt;/li&gt;
&lt;li&gt;Recupera il valore &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI&lt;/code&gt; se sei in produzione, altrimenti &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI_LOCAL&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finalmente possiamo capire come facevano i test a collegarsi a MongoDB senza che noi facessimo nulla: in pratica faceva il fallback sul file &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt; che è versionato su Git, andava a leggete il valore &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI_LOCAL=mongodb://localhost:27017&lt;/code&gt; e quindi si collegava al nostro MongoDB locale, mentre Travis CI si collegava al servizio MongoDB che abbiamo instanziato nella pipeline.&lt;/p&gt;
&lt;p&gt;Il nostro compito è quello di &lt;strong&gt;trovare un modo per caricare il file &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; in produzione&lt;/strong&gt; in modo sicuro, versionato, ma allo stesso tempo che non abbia scritto in chiaro tutte le credenziali per accedere al nostro MongoDB.&lt;/p&gt;
&lt;h3&gt;Caricare in modo sicuro il file .env&lt;/h3&gt;
&lt;p&gt;Una soluzione al problema precedente ci è data &lt;a href=&quot;https://docs.travis-ci.com/user/encrypting-files/&quot;&gt;direttamente da Travis CI&lt;/a&gt;. Per questo step abbiamo bisogno di &lt;a href=&quot;https://github.com/travis-ci/travis.rb#readme&quot;&gt;Travis CI Command Line Client&lt;/a&gt; che su Mac possiamo installare in questo modo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; gem &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; travis
travis login&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Grazie ad esso possiamo criptare i file in modo sicuro e salvare nella repo il file criptato senza aver paura che qualcuno possa rubarci le credenziali.&lt;/p&gt;
&lt;p&gt;Il primo passo è quello di creare il file di configurazione &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; pronto per la produzione, &lt;strong&gt;dobbiamo stare attenti a non caricarlo per nessun motivo su Git&lt;/strong&gt;, non è criptato e se lo versioniamo chiunque è in grado di accedere al nostro DB! Se state lavorando sul mio progetto ci ho già pensato io. Se andiamo infatti nel file &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/.gitignore&quot;&gt;.gitignore&lt;/a&gt; notiamo che il file .env è nella blacklist dei file da non tenere in considerazione con Git.&lt;/p&gt;
&lt;p&gt;Allora creiamo il file &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; con gli stessi dati che trovate nel file &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;# Get this from https://mlab.com/home after you&apos;ve logged in and created a database
MONGODB_URI=mongodb://&amp;lt;mlab_user&gt;:&amp;lt;mlab_password&gt;@&amp;lt;mlab_connection_url&gt;

# This is standard running mongodb locally
MONGODB_URI_LOCAL=mongodb://localhost:27017

SESSION_SECRET=&amp;lt;session_secret&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dobbiamo modificare due parti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI&lt;/code&gt;, sostituiamo &lt;code class=&quot;language-text&quot;&gt;&amp;lt;mlab_user&gt;&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;&amp;lt;mlab_password&gt;&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;&amp;lt;mlab_connection_url&gt;&lt;/code&gt; con le nostre credenziali del DB che vogliamo usare in produzione. Io utilizzo il servizio &lt;a href=&quot;https://mlab.com/&quot;&gt;mLab&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Sostituiamo &lt;code class=&quot;language-text&quot;&gt;&amp;lt;session_secret&gt;&lt;/code&gt; con una stringa alfanumerica casuale.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ora cancelliamo il file &lt;code class=&quot;language-text&quot;&gt;.env.enc&lt;/code&gt;, dove ci sono le mie chiavi criptate, perché ora andremo a creare il nostro file criptato. Con i valori che abbiamo appena inserito nel file &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt;. Per questo passo usiamo le linea di comando di Travis CI.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;travis encrypt-file .env&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il terminale vi dirà di inserire nel file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; una stringa del genere&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;openssl aes-256-cbc &lt;span class=&quot;token parameter variable&quot;&gt;-K&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$encrypted_0a6446eb3ae3_key&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-iv&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$encrypted_0a6446eb3ae3_iv&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-in&lt;/span&gt; .env.enc &lt;span class=&quot;token parameter variable&quot;&gt;-out&lt;/span&gt; .env &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;questo è esattamente quello che dobbiamo scrivere nello step misterioso!
Andiamo allora ad aggiornare il file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt;, la fase &lt;code class=&quot;language-text&quot;&gt;before_deploy&lt;/code&gt; sarà così&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;before_deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; openssl aes&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;256&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;cbc &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;K $encrypted_0a6446eb3ae3_key &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;iv $encrypted_0a6446eb3ae3_iv &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;in .env.enc &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;out .env &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;d
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; npm run build&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il comando che abbiamo appena aggiunto non fa altro che decodificare il file criptato prima di fare il deploy.&lt;/p&gt;
&lt;h3&gt;Ottenere l’API key criptata di Heroku&lt;/h3&gt;
&lt;p&gt;Siamo quasi alla fine, ora ci manca solo di &lt;strong&gt;inserire nella nostra pipeline l’API key criptata per permettere a Travis CI di poter fare il deploy tramite Heroku&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Per questo passo abbiamo bisogno di &lt;a href=&quot;https://devcenter.heroku.com/articles/heroku-cli&quot;&gt;Heroku CLI&lt;/a&gt; installato sul nostro PC. Se avete Mac vi basta scrivere nel terminale (se avete installato &lt;a href=&quot;https://brew.sh/&quot;&gt;brew&lt;/a&gt;)&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew tap heroku/brew &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; heroku&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ci autentichiamo con Heroku usando il comando&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;heroku login&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ed infine scriviamo questo comando per ottenere l’API Key&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;travis encrypt &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;$(&lt;/span&gt;heroku auth:token&lt;span class=&quot;token variable&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il comando ci ritornerà l’API Key, dobbiamo inserirla al posto di &lt;code class=&quot;language-text&quot;&gt;&apos;&amp;lt;API_KEY&gt;&apos;&lt;/code&gt; nel file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt;.
Fatto questo avremo quindi concluso il lavoro e possiamo goderci la nostra pipeline di Continuous Integration e Continuous Deployment!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ef86c9cfd54bdbfdbd911fe51e2d9375/96219/heroku-deploy-ok.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAABe0lEQVR42qWTb0+DMBDG71qaQllAOrYZFzQx/okbMHDT7/8lbAvMbyH41sKcvtG44Itfrr3knj69a2FXrLu8SLs0Lbt8U7yX5WNXFOV7luU2l3Xb7a57enoecnmed6u1ZZW161XabjZFm2Wb9u7uvr25ue15AxGEJgxCHUVyiIv5okqSpI7j2Ehpc2Fooigyy+WyYowpzrlCJC8A8DNhEBvhB8bhVCNFzTxm145GREUIUcdohbQtUH9CqavPosuaz3gNIRjwLfSEwt8ghOvZonylCW1wCQ1hRAPpTwI9QOB7T04RpFzLabqnCWtAQgUeGnBtcY9n3XIb2bA+xL9dogrCq9qbRBU6qAG/Gjz22vAixHkVxw97T7rV4Kp3x0GPEkQEJXxpPG9mUNjrsqF36qR+/erQv6jn89VeTL2Dw6PLcVMmyvcXlcPF8A6HqdJPlyMdKjm9bqYXlw1xiP7HMI49RDWZTOy3k+bfYj2cu9ph7mGq/S8RFme84AcUIgEdFUI/7gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Test del deploy su Heroku&quot;
        title=&quot;&quot;
        src=&quot;/static/ef86c9cfd54bdbfdbd911fe51e2d9375/9fabd/heroku-deploy-ok.png&quot;
        srcset=&quot;/static/ef86c9cfd54bdbfdbd911fe51e2d9375/c6e3d/heroku-deploy-ok.png 500w,
/static/ef86c9cfd54bdbfdbd911fe51e2d9375/da8b6/heroku-deploy-ok.png 1000w,
/static/ef86c9cfd54bdbfdbd911fe51e2d9375/9fabd/heroku-deploy-ok.png 2000w,
/static/ef86c9cfd54bdbfdbd911fe51e2d9375/96219/heroku-deploy-ok.png 2050w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;Consigli sulla creazione delle pipeline&lt;/h1&gt;
&lt;p&gt;Ora che abbiamo visto un caso d’uso reale voglio condividere con voi qualche consiglio. Spero che vi faranno evitare un po’ di mal di testa che invece mi sono beccato:&lt;/p&gt;
&lt;h2&gt;Prima la creiamo più è semplice&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;L’implementazione della CI/CD prima la si crea, più si risparmia tempo, ma soprattutto più è semplice!&lt;/strong&gt; Idealmente è meglio farla durante la creazione del progetto. Le motivazioni sono tante:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Durante la creazione del progetto stiamo già lavorando sulla questione configurazione e dipendenze del progetto&lt;/strong&gt;. Quindi tutto quello che stiamo facendo localmente per impostare il nostro ambiente locale, ci basta fare il corrispettivo nella pipeline. Inoltre se sappiamo che stiamo implementando una pipeline fin dall’inizio, &lt;strong&gt;evitiamo di creare dei test o delle configurazioni che sono troppo legate alla nostra macchina locale&lt;/strong&gt;, evitiamo di scrivere configurazioni strane che ci complicano la pipeline proprio perché ci è difficile replicarlo in Travis CI (come per esempio il recupero di file che si trovano in cartelle al di fuori del nostro progetto Git).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non dobbiamo fare Reverse Engineering sul progetto per capire come configurarlo&lt;/strong&gt;: nessuno ci avvertirà di trovare “lo step misterioso” nella vita reale e nessuno ci dirà di guardare il file &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/src/util/secrets.ts&quot;&gt;src/util/secrets.ts&lt;/a&gt; per avere qualche indizio. In questa guida l’ho fatto per evitare di perdere troppo tempo. Senza questo aiuto avremmo dovuto sbattere la testa numerose volte e fare un minimo di Reverse Engineering del progetto per capire effettivamente come funzionava il recupero delle credenziali. Tutto questo poteva essere evitato se chi ha ideato questo recupero delle credenziali, avesse mantenuto aggiornata la pipeline. E chi è nuovo sul progetto, gli basta vedere il file &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; per capire esattamente il procedimento per ottenere una versione locale funzionante.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Si evita l’errore umano nei deploy&lt;/strong&gt;: averlo automatizzato è un vantaggio perché non si hanno errori grossolani nel deploy. Immaginate che voi dobbiate eseguire numerosi deploy al giorno… Dopo un po’ abbasserete la guardia e la concentrazione, l’errore per disattenzione è dietro l’angolo e fare errori nel deploy può costare molto caro!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Si risparmia tempo&lt;/strong&gt;: banalmente prima creiamo una pipeline più ore uomo risparmiamo. Nessuno in azienda è responsabile del deploy, chiunque può farlo. Sono stato in aziende dove il deploy era manuale, e ho visto una persona che era occupata tempo pieno solo per i deploy nei momenti più frenetici. Secondo me è inaccettabile. Gli strumenti per automatizzare ci sono e sono alla portata di tutti. Usiamoli!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Pensiamo ad impostare la pipeline in locale&lt;/h2&gt;
&lt;p&gt;Provare direttamente su Travis CI può portare via molto tempo. Per esempio se abbiamo problemi nel deploy, dobbiamo pushare le nuove modifiche, attendere tutti i passi precedenti e poi magari ritrovarsi un bell’errore dopo 15 minuti. In questo caso tentiamo di fixare il problema caricando le nuove modifiche e il ciclo ricomincia… Tutto questo porta via ore.
&lt;strong&gt;Il modo migliore per evitare tutto questo è provare localmente i passaggi&lt;/strong&gt;. Un po’ come abbiamo fatto in questa guida durante la creazione della pipeline di Continuous Integration.
Per raggiungere questo obiettivo dobbiamo creare degli step che siano agnostici rispetto al servizio di CI/CD che utilizziamo. Solitamente io creo una cartella con tutti gli script utili per il deploy. In questo modo posso invocare questi script anche in locale e testare più velocemente la corretta esecuzione.
Inoltre se teniamo in mente questo punto sarà più facile anche raggiungere il prossimo.&lt;/p&gt;
&lt;h2&gt;Non focalizziamoci troppo sul singolo servizio di CI/CD&lt;/h2&gt;
&lt;p&gt;In questa guida abbiamo usato Travis CI, nel lavoro precedentemente usavamo Jenkins. Nel lavoro attuale usavamo CircleCI, ora invece usiamo GitLab CI. Insomma vi capiterà di usare di tutto che però tutti risolvono lo stesso problema: automatizzare l’integrazione ed il deploy.
&lt;strong&gt;Cerchiamo quindi di focalizzarci sui concetti di base e non tanto su come farlo su uno specifico servizio&lt;/strong&gt;. Quest’ultima parte è semplice se abbiamo chiaro cosa dobbiamo raggiungere: basta leggere la guida del servizio specifico. Questo modo di lavorare ci dà parecchia flessibilità sia al lavoro che nei nostri progetti hobbisti.
Infine &lt;strong&gt;questa flessibilità ci rende liberi di usare un servizio in base ai vantaggi che esso porta&lt;/strong&gt;: in questa guida abbiamo usato appunto Travis CI perché è gratuito per i progetti open source, ma non è di certo il migliore sulla piazza. Questo non sarebbe possibile se usassimo solo ed esclusivamente un servizio.&lt;/p&gt;
&lt;h2&gt;Leggiamo delle pipeline già fatte&lt;/h2&gt;
&lt;p&gt;Dobbiamo ricordarci che non siamo gli unici sulla faccia della terra che stanno pensando di creare una pipeline. &lt;strong&gt;Non sottovalutiamo quindi la possibilità di vedere le pipeline dei progetti open source!&lt;/strong&gt; Ci sono numerosi progetti su GitHub che mostrano degli esempi pratici di pipeline che molto probabilmente risolvono tutto o in parte i nostri problemi. Così facendo possiamo vedere anche dei modi diversi di ragionare che è sempre utile per migliorare il proprio bagaglio culturale. Ricordo infine che Travis CI è gratis per i progetti open source, è il motivo principale per cui ho deciso di scrivere questa guida. Quindi GitHub è pieno di pipeline fatte con Travis CI!&lt;/p&gt;
&lt;h2&gt;Non cerchiamo la perfezione&lt;/h2&gt;
&lt;p&gt;Ricordiamoci che il nostro lavoro non è di passare giorni a fare pipeline. &lt;strong&gt;È sempre possibile ottimizzarla per velocizzarla, ma come tutte le ottimizzazioni richiedono tempo&lt;/strong&gt;. Il mio consiglio è di raggiungere il minimo indispensabile per raggiungere l’obiettivo, anche se magari non è la soluzione più elegante possibile. Poi ricordiamoci che col tempo impariamo nuovi concetti, come per esempio il caching e la possibilità di eseguire più job in parallelo, conosciamo meglio il sistema e quindi sarà più semplice per noi ottimizzarla impiegandoci meno tempo. Quindi teniamo sempre a mente che la pipeline è uno strumento che velocizza e automatizza il nostro lavoro… Ma se impiega 5 minuti o 10 minuti cambia davvero poco lato nostro, quindi non spendiamo ore o giorni per queste ottimizzazioni, soprattutto nei primi stadi dove le sfide sono già tante.&lt;/p&gt;
&lt;h1&gt;Conclusioni&lt;/h1&gt;
&lt;p&gt;Spero che con questa guida abbiate toccato con mano cosa significhi implementare una pipeline di Continuous Integration e Continuous Delivery su un progetto già esistente. Le difficoltà, come abbiamo visto, sono maggiori se il progetto è già avviato. Quindi, la prossima volta che inizierete a costruire una vostra idea, ricordatevi di pensare subito alla pipeline CI/CD; non ve ne pentirete. In questo modo potrete delegare questi task ad una macchina e voi potrete concentrarvi esclusivamente a ciò che porta realmente valore al vostro progetto: lo sviluppo del codice.&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come programmare in Test-Driven Development (TDD) partendo da zero]]></title><description><![CDATA[TDD di qui, TDD di là, tutti ne parlano. Molti ne elogiano i pregi, altri dicono che è una perdita di tempo… Ma alla fine come si procede a…]]></description><link>https://www.mattianatali.it/it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero/</guid><pubDate>Fri, 28 Dec 2018 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;TDD di qui, TDD di là, tutti ne parlano. Molti ne elogiano i pregi, altri dicono che è una perdita di tempo… Ma alla fine come si procede a sviluppare in TDD?&lt;/p&gt;
&lt;p&gt;In questa guida potrai vedere un esempio reale sviluppato in &lt;a href=&quot;https://it.wikipedia.org/wiki/Test_driven_development&quot;&gt;Test-Driven Development&lt;/a&gt;. Questa tecnica di programmazione la sto adottando da oltre un anno per i backend che sviluppo in Java, Python e TypeScript. I benefici nel codice che ho scritto sono visibili e molti. Spero di riuscire a convincerti che questa tecnica:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migliora la qualità del codice.&lt;/li&gt;
&lt;li&gt;Diminuisce il tempo speso in debugging e la ricerca di eventuali regressioni del software.&lt;/li&gt;
&lt;li&gt;Diminuisce il numero di bug che riescono a raggiungere la produzione.&lt;/li&gt;
&lt;li&gt;Semplifica lo sviluppo di applicativi complessi.&lt;/li&gt;
&lt;li&gt;È più semplice di quanto sembri.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Come posso convincerti di tutte queste cose? Spero di farcela attraverso un &lt;strong&gt;esempio pratico partendo completamente da zero&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Obiettivo&lt;/h2&gt;
&lt;p&gt;In questa guida svilupperemo una classe che prende in input un’URL e una parola da cercare nella pagina che abbiamo inserito.
In questa ricerca ci risponderà dicendo quante volte ha trovato la parola.&lt;/p&gt;
&lt;p&gt;Faremo questo semplice applicativo in &lt;a href=&quot;https://nodejs.org/it/&quot;&gt;Node.Js&lt;/a&gt; + &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;, interamente in TDD.
Durante questo sviluppo spiegherò tutti i passaggi e espliciterò tutti i vantaggi che sta introducendo il TDD.&lt;/p&gt;
&lt;h2&gt;Prerequisiti&lt;/h2&gt;
&lt;p&gt;Per seguire la guida dovresti avere:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installato Node.js.&lt;/li&gt;
&lt;li&gt;Un minimo di esperienza con Node.js. TypeScript, se non lo hai mai usato, è JavaScript con i tipi, per ora è tutto quello che devi sapere.&lt;/li&gt;
&lt;li&gt;Per la seconda parte c’è bisogno di sapere il concetto di programmazione asincrona in JavaScript: andremo ad utilizzare le &lt;a href=&quot;https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt; e le keyword &lt;a href=&quot;https://javascript.info/async-await&quot;&gt;async e await&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Un sistema UNIX (Linux o Mac). Oppure aver abilitato il &lt;a href=&quot;http://wsl-guide.org/en/latest/&quot;&gt;WSL su Windows&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se per caso ti stai perdendo, &lt;a href=&quot;https://github.com/matitalatina/word-counter&quot;&gt;in questa repo su GitHub&lt;/a&gt; puoi trovare il prodotto finito. Ma ti consiglio di non “sbirciare” la soluzione perché introdurremo molti concetti nel corso dell’articolo. Vedere il progetto finito senza sapere &lt;em&gt;come&lt;/em&gt; ci siamo arrivati non apporta alcun beneficio nell’apprendimento.&lt;/p&gt;
&lt;h2&gt;Creazione del progetto&lt;/h2&gt;
&lt;p&gt;Il primo passo è ovviamente creare il progetto. Per questo apriamo il &lt;em&gt;terminale&lt;/em&gt; in una cartella su cui lavoreremo. La mia cartella si chiamerà &lt;code class=&quot;language-text&quot;&gt;word-counter&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; word-counter
&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; word-counter&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Creiamo il file &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; dove inseriremo le varie dipendenze Node.js e gli scripts.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; init&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Inseriamo i vari dati che ci chiede. Per ora possiamo anche solo premere &lt;code class=&quot;language-text&quot;&gt;Enter&lt;/code&gt; e mantenere i valori di default.&lt;/p&gt;
&lt;h2&gt;Aggiunta delle dipendenze&lt;/h2&gt;
&lt;p&gt;Ora possiamo inserire il minimo indispensabile per poter iniziare a sviluppare in TDD. Le dipendenze che ci servono sono:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;: per sviluppare con questo linguaggio.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://palantir.github.io/tslint/&quot;&gt;TSLint&lt;/a&gt;: il &lt;a href=&quot;https://en.wikipedia.org/wiki/Lint_(software)&quot;&gt;linter&lt;/a&gt; di TypeScript che ci aiuterà nello sviluppo per scrivere codice pulito. Questo è opzionale, ma io solitamente lo aggiungo sempre per avere un ottimo aiuto durante lo sviluppo. Inoltre è integrato molto bene con &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;, che è il mio Text Editor preferito per quanto riguarda il mondo Node.js.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt;: la nostra piattaforma di testing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Per installare tutto questo scriviamo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev typescript tslint jest ts-jest @types/jest&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Possiamo verificare che in &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; sono state aggiunte queste cinque dipendenze in &lt;code class=&quot;language-text&quot;&gt;devDependencies&lt;/code&gt;, ossia sono dipendenze che servono per lo sviluppo e non al programma vero e proprio. Inoltre possiamo notare che queste dipendenze sono state scaricare nella cartella &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Il comando dovrebbe essere chiaro, l’unica parte che forse ha bisogno di spiegazione sono le librerie per Jest. Infatti abbiamo installato tre dipendenze per far girar il tutto.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;jest&lt;/code&gt; è la nostra piattaforma di testing.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ts-jest&lt;/code&gt; è il transpilatore che transforma TypeScript in JavaScript prima di far girare i test. Senza di esso dovremmo ogni volta &lt;a href=&quot;https://it.quora.com/Qual-%C3%A8-la-differenza-tra-la-transpilazione-e-la-compilazione-nella-programmazione-per-computer&quot;&gt;transpilare&lt;/a&gt; manualmente il codice, cosa che vogliamo assolutamente evitare per non perdere tempo.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@types/jest&lt;/code&gt; serve a TypeScript per sapere i tipi che sono dentro la libreria di Jest. Immagina che molte volte le librerie sono scritte in JavaScript, quindi TypeScript non avrebbe idea di cosa le funzioni accettano in input o restituiscono in output. Fortunatamente ci sono degli sviluppatori che creano delle librerie che mappano le funzioni JavaScript in TypeScript. Solitamente per installare questi mapping si installa la dipendenza &lt;code class=&quot;language-text&quot;&gt;@types/&amp;lt;LIBRERIA_DA_MAPPARE&gt;&lt;/code&gt;. Se volete sapere di più per quanto riguarda queste dichiarazione dei tipi in TypeScript potete leggervi direttamente dal sito di &lt;a href=&quot;http://definitelytyped.org/&quot;&gt;DefinitelyTyped&lt;/a&gt;, ma per questa guida non è necessario approfondire oltre.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Inizializzazione&lt;/h3&gt;
&lt;p&gt;Ora che abbiamo scaricato le librerie, dobbiamo configurarle per farle funzionare al meglio.
Iniziamo con &lt;strong&gt;TypeScript&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx typescript &lt;span class=&quot;token parameter variable&quot;&gt;--init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il comando significa:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npx&lt;/code&gt;: avvia un programma che puoi trovare nella cartella &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;typescript --init&lt;/code&gt;: il comando di inizializzazione di TypeScript.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dovrebbe aver creato il file &lt;code class=&quot;language-text&quot;&gt;tsconfig.json&lt;/code&gt; con i vari parametri di configurazione. Entriamo in questo file e dovremmo vedere commentato la parte &lt;code class=&quot;language-text&quot;&gt;// &quot;lib&quot;: [],&lt;/code&gt;, decommentiamola e scriviamo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;lib&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
  &lt;span class=&quot;token string&quot;&gt;&quot;es2015&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Così facendo possiamo usare &lt;a href=&quot;https://javascript.info/async-await&quot;&gt;le keyword async e await&lt;/a&gt; quando avremo a che fare con le &lt;a href=&quot;https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promise&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ora passiamo a &lt;strong&gt;TSLint&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx tslint &lt;span class=&quot;token parameter variable&quot;&gt;--init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Possiamo effettivamente vedere che è stato creato un file nella root con il nome &lt;code class=&quot;language-text&quot;&gt;tslin.json&lt;/code&gt;. Per ora va benissimo così, non lo tocchiamo.&lt;/p&gt;
&lt;p&gt;Ora inizializziamo &lt;strong&gt;Jest&lt;/strong&gt;, la nostra piattaforma di test, più o meno come abbiamo fatto con TSLint&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx jest &lt;span class=&quot;token parameter variable&quot;&gt;--init&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dovrebbe riconoscere in automatico che c’è TypeScript, creare il file &lt;code class=&quot;language-text&quot;&gt;jest.config.js&lt;/code&gt; con all’interno la configurazione di default di Jest, ed infine ha inserito in &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; lo script &lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt;. In questo modo quando scriviamo in console &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;, Jest si avvia ed esegue tutti i test.&lt;/p&gt;
&lt;p&gt;Qui dobbiamo fare una piccola modifica al file &lt;code class=&quot;language-text&quot;&gt;jest.config.js&lt;/code&gt;: dobbiamo rinominare il campo da &lt;code class=&quot;language-text&quot;&gt;globals.ts-jest.tsConfigFile&lt;/code&gt; a &lt;code class=&quot;language-text&quot;&gt;globals.ts-jest.tsConfig&lt;/code&gt; per evitare un messaggio di warning durante i test.
Quindi dovremo rinominare quella parte di configurazione in questo modo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;globals&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token string-property property&quot;&gt;&quot;ts-jest&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token string-property property&quot;&gt;&quot;tsConfig&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tsconfig.json&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Per essere sicuri di aver fatto tutto proviamo a scrivere finalmente un test: lo inseriremo nella cartella &lt;code class=&quot;language-text&quot;&gt;src/__tests__&lt;/code&gt; e lo chiamiamo &lt;code class=&quot;language-text&quot;&gt;hello-test.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Quindi scriviamo nel file &lt;code class=&quot;language-text&quot;&gt;src/__tests__/hello-test.ts&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should work&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il test appena scritto non fa altro che verificare che &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt; sia effettivamente &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt;. A che serve? Nella vita reale a niente, ma nel nostro caso specifico serve a noi per capire che Jest sia configurato correttamente.&lt;/p&gt;
&lt;p&gt;Avviamo i test con &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; e dovresti avere un risultato simile al mio.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt;

&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; word-counter@1.0.0 &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; /Users/mattia/Repositories/word-counter
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; jest

 PASS  src/__tests__/hello-test.ts
  ✓ should work &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;5ms&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

Test Suites: &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; total
Tests:       &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; total
Snapshots:   &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; total
Time:        &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.553s
Ran all &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; suites.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Perfetto! Il nostro primo test in TypeScript ha funzionato.&lt;/p&gt;
&lt;h2&gt;Analisi del progetto&lt;/h2&gt;
&lt;p&gt;Ora si inizia a fare sul serio: riprendiamo il nostro obiettivo e cominciamo a pensare come creare l’architettura.&lt;/p&gt;
&lt;p&gt;Per raggiungere l’obiettivo abbiamo bisogno di tre parti:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Raccolta dei valori di input (URL e parola da cercare).&lt;/li&gt;
&lt;li&gt;Scaricamento della pagina web.&lt;/li&gt;
&lt;li&gt;Conteggio della parola nella pagina web appena scaricata.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Test-Driven Development: si inizia!&lt;/h2&gt;
&lt;p&gt;Da dove iniziamo? Ovviamente con un test! Alla fine siamo qui per questo no? Imparare il Test-Driven Development.
Come si fa ad iniziare con un test? &lt;strong&gt;Bisogna pensare a come creare un’architettura che possa essere facilmente testabile, dove ogni test controlla solo un unico aspetto del progetto&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Utilizzeremo un &lt;a href=&quot;https://it.wikipedia.org/wiki/Progettazione_top-down_e_bottom-up&quot;&gt;approccio bottom-up&lt;/a&gt; per creare il progetto, ossia inizieremo dalla parte più semplice, autocontenuta che non ha bisogno di nessuna dipendenza per funzionare. In questo caso è il punto 3.&lt;/p&gt;
&lt;h2&gt;Classe WordCounter&lt;/h2&gt;
&lt;p&gt;WordCounter è la nostra classe che serve per il “Conteggio della parola nella pagina web appena scaricata”. Possiamo tradurlo anche in questo modo: “Data una stringa in input &lt;em&gt;text&lt;/em&gt; e una parola da cercare &lt;em&gt;wordToFind&lt;/em&gt;, restituisce il numero di volte che &lt;em&gt;wordToFind&lt;/em&gt; è contenuta in &lt;em&gt;text&lt;/em&gt;“.&lt;/p&gt;
&lt;p&gt;Iniziamo allora dal test: senza avere in mano questa classe WordCounter, che non esiste ancora, mi immagino di utilizzarla in questo modo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;testo scaricato&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wordToFind &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;testo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wordCounter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WordCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Output 1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Vediamo di tradurre questo ipotetico utilizzo in un test.
Nel nuovo file &lt;code class=&quot;language-text&quot;&gt;src/__tests__/word-counter.ts&lt;/code&gt; scriviamo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; WordCounter &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../word-counter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;WordCounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wordCounter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WordCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should count the word inside text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;testo scaricato&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;testo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Qui ci serve sapere un minimo come funziona Jest. In poche parole, useremo la convenzione di inglobare i test che sono riferiti ad una classe usando la funzione &lt;a href=&quot;https://jestjs.io/docs/en/api#describename-fn&quot;&gt;describe&lt;/a&gt;, e poi ogni test della classe userà la funzione &lt;a href=&quot;https://jestjs.io/docs/en/api#testname-fn-timeout&quot;&gt;it&lt;/a&gt; che è il nostro test vero e proprio. La funziona &lt;code class=&quot;language-text&quot;&gt;it&lt;/code&gt; si compone di una stringa che spiega brevemente cosa andiamo a testare e una funzione che ha al suo interno la logica del test.  Per maggiori approfondimenti ti consiglio la loro &lt;a href=&quot;https://jestjs.io/docs/en/getting-started&quot;&gt;documentazione ufficiale&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ora che abbiamo scritto il nostro primo test, possiamo notare un vantaggio nello scrivere in TDD: &lt;strong&gt;ci preoccupiamo solamente dell’interfaccia e non dell’implementazione&lt;/strong&gt;. Alla fine, l’utilizzatore finale delle nostre classi, interessa solo &lt;em&gt;come&lt;/em&gt; invocare una determinata funzione, e non &lt;em&gt;come è stata fatta&lt;/em&gt;. Capita spesso in programmazione di buttarsi a capofitto nell’implementazione per poi avere un’interfaccia convoluta e poco chiara, proprio perché nella programmazione tradizionale lo sforzo cognitivo va tutto nell’implementazione e l’interfaccia è una cosa secondaria. Qui invece si ribalta il tutto.&lt;/p&gt;
&lt;p&gt;Una regola molto importante nel TDD è di &lt;strong&gt;procedere a piccoli passi&lt;/strong&gt;. Non dobbiamo scrivere mille test per poi passare all’implementazione. Si scrive un solo test, che fallisce, e poi il nostro obiettivo è di far funzionare il test implementando il codice necessario. Perché tutto questo? Essenzialmente per due motivi:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Sappiamo perfettamente qual è il nostro obiettivo, far passare l’unico test che fallisce&lt;/strong&gt;. In questo modo il progetto può essere complesso a piacere, ma mettendoci solo un piccolo obiettivo il tutto diventa semplice, &lt;em&gt;divide et impera&lt;/em&gt; funziona sempre!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scriviamo il minimo indispensabile per far passare il test&lt;/strong&gt;. Quanti di noi si sono messi a scrivere montagne di codice perché “Non si sa mai”, o perché la nostra mente ha pensato a mille casistiche che nessuno ha mai chiesto? Nel TDD non succede, ogni singola riga di codice è stata scritta per far passare un test. Se scriviamo altro stiamo sbagliando.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ora che ci siamo detti che dobbiamo procedere a piccoli passi, andiamo effettivamente a scrivere il codice che renderà verde il nostro test. Prima di tutto verifichiamo che fallisca.&lt;/p&gt;
&lt;p&gt;In console scriviamo &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Come output abbiamo una cosa del genere.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; word-counter@1.0.0 &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; /Users/mattia/Repositories/word-counter
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; jest

 PASS  src/__tests__/hello-test.ts
 FAIL  src/__tests__/word-counter.ts
  ● Test suite failed to run

    TypeScript diagnostics &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;customize using &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;jest-config&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;.globals.ts-jest.diagnostics&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt; option&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;:
    src/__tests__/word-counter.ts:1:25 - error TS2307: Cannot &lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; module &lt;span class=&quot;token string&quot;&gt;&apos;../word-counter&apos;&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt;

    &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;import&lt;/span&gt; WordCounter from &lt;span class=&quot;token string&quot;&gt;&quot;../word-counter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                              ~~~~~~~~~~~~~~~~~

Test Suites: &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; failed, &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; total
Tests:       &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; total
Snapshots:   &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; total
Time:        &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.557s
Ran all &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; suites.
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; ERR&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; Test failed.  See above &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt; details.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il transpilatore di TypeScript si lamenta giustamente che la classe word-counter non esiste.&lt;/p&gt;
&lt;p&gt;Ora scriviamo il minimo indispensabile per far passare il test. Andiamo a creare la classe e il metodo in &lt;code class=&quot;language-text&quot;&gt;src/word-counter.ts&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WordCounter&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Facciamo girare il test con &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;. E questo è il risultato:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; word-counter@1.0.0 &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; /Users/mattia/Repositories/word-counter
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; jest

 PASS  src/__tests__/hello-test.ts
 PASS  src/__tests__/word-counter.ts

Test Suites: &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; total
Tests:       &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; total
Snapshots:   &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; total
Time:        &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.669s
Ran all &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; suites.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ce l’abbiamo fatta! Ma immagino che ti sei accorto che ho barato. Il metodo che ho scritto restituisce sempre 1, indipendentemente dal testo passato. Ma questo non è sbagliato nel TDD perché &lt;strong&gt;il nostro obiettivo è far passare i test il prima possibile con il minimo indispensabile&lt;/strong&gt;. Se sono riuscito a barare significa che il test non è abbastanza approfondito per verificare il corretto funzionamento del programma.
Ora risolviamo scrivendo un test che ci obbliga a considerare l’input &lt;em&gt;text&lt;/em&gt;. Nel file &lt;code class=&quot;language-text&quot;&gt;src/__tests__/word-counter.ts&lt;/code&gt; aggiungiamo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should count the word inside text (multiple)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pippo pippo ciao pippo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pippo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ciao ciao&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ciao&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ciao&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nonesistequestaparola&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Facendo girare i test effettivamente questo test fallisce&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; word-counter@1.0.0 &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; /Users/mattia/Repositories/word-counter
&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; jest

 FAIL  src/__tests__/word-counter.ts
  ● WordCounter › should count the word inside text &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;multiple&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    expect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;received&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.toBe&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expected&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; // Object.is equality

    Expected: &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;
    Received: &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;

      &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;   it&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should count the word inside text (multiple)&quot;&lt;/span&gt;, &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;     expect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter.count&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;pippo pippo ciao pippo&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;pippo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;))&lt;/span&gt;.toBe&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
         &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;                                                                  ^
      &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;     expect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter.count&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ciao ciao&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;ciao&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;))&lt;/span&gt;.toBe&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;     expect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter.count&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ciao&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;nonesistequestaparola&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;))&lt;/span&gt;.toBe&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

      at Object.&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;anonymous&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src/__tests__/word-counter.ts:13:66&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

 PASS  src/__tests__/hello-test.ts

Test Suites: &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; failed, &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; total
Tests:       &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; failed, &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; passed, &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; total
Snapshots:   &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; total
Time:        &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;.612s
Ran all &lt;span class=&quot;token builtin class-name&quot;&gt;test&lt;/span&gt; suites.
&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; ERR&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; Test failed.  See above &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt; details.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora cambiamo l’implementazione di &lt;code class=&quot;language-text&quot;&gt;WordCounter.count&lt;/code&gt; in &lt;code class=&quot;language-text&quot;&gt;src/word-counter.ts&lt;/code&gt; in modo tale da far passare il test&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; text
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; word &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; wordToFind&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I test sono entrambi OK! …Ma c’è una cosa che non abbiamo testato, cosa succede se il testo da cercare è tutto minuscolo ma il testo è maiuscolo? &lt;strong&gt;Non lo sappiamo e non ci preoccupiamo nemmeno di scoprilo, ci basta scrivere un test per essere sicuri&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Aggiungiamo il test&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should count the word case insensitive&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Ciao ciao CIAO&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ciao&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Facendo girare i test fallisce… Allora risolviamo!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wordToFindLower &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wordToFind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; word &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; wordToFindLower&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Tutto ok, di nuovo. Ma non abbiamo considerato il testo dove la parola finisce con una virgola o un qualsiasi segno di interpunzione. Nuovo test&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should count word that have signs nearby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ciao, ciao! &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ciao&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nuova implementazione per gestire questo test che fallisce&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wordToFindLower &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wordToFind&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toLowerCase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;[^a-zA-Z\d]&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;word&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; word &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; wordToFindLower&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Tutto verde! Insomma ora è abbastanza chiaro come creare una classe in TDD. Abbiamo visto che &lt;strong&gt;è un continuo ping pong di test che falliscono e implementazione che risolve il fail&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Ma questo ping pong, oltre ai benefici che avevamo scritto in precedenza, ne porta anche altri:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Itera lo sviluppo di app complesse attraverso semplici passaggi, in modo incrementale&lt;/strong&gt;: è palese che abbiamo iniziato con un’implementazione molto semplice, e poi, tramite piccoli passi, siamo arrivati ad avere un metodo che gestisce numerose casistiche che magari non avevamo neppure pensato inizialmente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I test scritti in precedenza rimangono, l’implementazione cambia continuamente&lt;/strong&gt;: forse tramite questo esempio non si nota molto, ma ogni volta che abbiamo aggiunto un nuovo test, e abbiamo cambiato l’implementazione, eravamo certi che &lt;strong&gt;anche i test precedentemente scritti continuano a funzionare&lt;/strong&gt;. Questa certezza è fondamentale quando dobbiamo fare pesanti refactor dei metodi, senza il TDD questa certezza, il più delle volte, non esiste. Quindi si tende a non modificare il codice già esistente, si aggiunge il codice “attorno” per evitare di toccare una cosa “che funziona già” e quindi di evitare delle &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_regression&quot;&gt;regressioni nel software&lt;/a&gt;. Questo comportamento funziona ma per un breve periodo, il codice perde facilmente di leggibilità, diventa confuso e oscuro, ed ecco a voi il famoso &lt;a href=&quot;https://it.wikipedia.org/wiki/Debito_tecnico&quot;&gt;debito tecnico&lt;/a&gt;! Sono certo che vi è già capitato un codice del genere sottomano e non è divertente.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tutte le funzionalità che ci servono sono testate&lt;/strong&gt;: questo è gratis con il TDD. Scriviamo prima il test e poi l’implementazione, per forza di cose è vero.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ormai ci sentiamo soddisfatti con la nostra classe &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt;. In realtà ci sarebbe un’altra altra casistica da testare. Per esempio&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cosa succede se passiamo &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; ai due parametri?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dobbiamo inserire il test anche per questo caso? La risposta è &lt;em&gt;dipende&lt;/em&gt;. Se sappiamo che il nostro codice non deve gestire i &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; possiamo anche farne a meno. Molti potrebbero ribattere che così il codice non è robusto, ma in realtà il nostro obiettivo non è gestire tutti i casi del mondo, dobbiamo creare una classe che sia ok per il nostro progetto. Quindi &lt;strong&gt;bisogna cercare di rimanere focalizzati sull’obiettivo iniziale&lt;/strong&gt;, in questo modo non complichiamo il codice con casi che non accadono mai e non perdiamo tempo a scrivere codice e test inutili.&lt;/p&gt;
&lt;p&gt;Ora che siamo soddisfatti del nostro &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; passiamo alla classe successiva.&lt;/p&gt;
&lt;h2&gt;Classe TextFetcher&lt;/h2&gt;
&lt;p&gt;Questa classe risolve il punto 2 del nostro obiettivo. Ossia scarica una pagina web e recupera il testo da esso.
Ormai sappiamo come funziona e, carichi come una molla, usiamo lo stesso procedimento usato con &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pensiamo all’interfaccia di TextFetcher: io mi immagino di utilizzarlo così &lt;code class=&quot;language-text&quot;&gt;new TextFetcher().getContent(url)&lt;/code&gt; e ci resituisce una &lt;code class=&quot;language-text&quot;&gt;Promise&amp;lt;string&gt;&lt;/code&gt;, insomma ci restituisce una stringa in modo asincrono (non possiamo averlo sincrono perché la chiamata HTTP per recuperare il contenuto da un URL è lenta). Qui entra in gioco un prerequisito che avevo scritto in precedenza: la programmazione asincrona in JavaScript/TypeScript. Se volete capire fino in fondo gli esempi che andrò a scrivere vi consiglio le letture che ho inserito nella sezione prerequisiti.&lt;/li&gt;
&lt;li&gt;Scriviamo il test per testare la futura implementazione.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TextFetcher &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../text-fetcher&quot;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;TextFetcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; textFetcher &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextFetcher&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should get the content as text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; textFetcher&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://raw.githubusercontent.com/matitalatina/word-counter/master/README.md&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toContain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;WordCounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Se apriamo l’URL che ho inserito nel test possiamo vedere che è il &lt;code class=&quot;language-text&quot;&gt;README.md&lt;/code&gt; della repository che sto utilizzando per creare questa app.&lt;/p&gt;
&lt;p&gt;Al suo interno c’è la parola WordCounter. Il nostro test verifica che effettivamente l’istanza &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; scarica il README e ci restituisce il suo contenuto. Nel test cerco solo la parola &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; e non esattamente il contenuto perché il README potrebbe cambiare, ma almeno il nome del progetto spero che rimanga sempre!&lt;/p&gt;
&lt;p&gt;Ora proviamo a far passare il test (senza barare per non appesantire troppo il discorso). Per fare la chiamata HTTP che scarica il file, utilizzo una libreria famosissima in Node.js che è &lt;a href=&quot;https://github.com/axios/axios&quot;&gt;Axios&lt;/a&gt;. Per questo motivo la installiamo tra le nostre dipendenze&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--save&lt;/span&gt; axios&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Scriviamo una possibile implementazione in &lt;code class=&quot;language-text&quot;&gt;src/text-fetcher.ts&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; axios &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;axios&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextFetcher&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; axios&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Abbiamo sostanzialmente creato ed esportato la classe &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt;, creato il metodo asincrono &lt;code class=&quot;language-text&quot;&gt;async getContent&lt;/code&gt;, nell’implementazione usiamo &lt;code class=&quot;language-text&quot;&gt;axios&lt;/code&gt; per scaricare il contenuto dell’&lt;code class=&quot;language-text&quot;&gt;url&lt;/code&gt;, aspettiamo in modo asincrono che scarichi il contenuto usando la keyword &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt;, infine prendiamo il contenuto della risposta usando la proprietà &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Facciamo girare i test con &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; ed ecco che tutto funziona!&lt;/p&gt;
&lt;p&gt;Però non so se senti anche tu un piccolo odore di “bruciato”… Se hai notato ho messo nel test un’URL che va a prendere una risorsa esterna al nostro programma, che potrebbe cambiare, potrebbe non essere accessibile perché abbiamo il PC offline. Tutto questo influenzerebbe il nostro test facendolo fallire anche se in realtà il codice è giusto.&lt;/p&gt;
&lt;p&gt;Ricorda che &lt;strong&gt;gli unit tests devono essere veloci e non devono dipendere da fattori esterni&lt;/strong&gt;. La chiamata HTTP può essere lenta per via della connessione se non addirittura fallire per possibili cambiamenti o disconnessioni.&lt;/p&gt;
&lt;p&gt;Come possiamo risolvere questo problema? Andremo a &lt;a href=&quot;https://it.wikipedia.org/wiki/Mock_object&quot;&gt;mockare&lt;/a&gt; la chiamata HTTP.&lt;/p&gt;
&lt;p&gt;Per fare questo abbiamo bisogno di un’altra libreria esterna: &lt;a href=&quot;https://github.com/ctimmerm/axios-mock-adapter&quot;&gt;axios-mock-adapter&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev axios-mock-adapter&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Andiamo a modificare il test in &lt;code class=&quot;language-text&quot;&gt;src/__tests__/text-fetcher.ts&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; axios &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;axios&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; MockAdapter &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;axios-mock-adapter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TextFetcher &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../text-fetcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;TextFetcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; textFetcher &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextFetcher&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mock &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MockAdapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;axios&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should get the content as text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Questo è il contenuto della pagina web&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    mock&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;onGet&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/fake-url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; textFetcher&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/fake-url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Attraverso &lt;code class=&quot;language-text&quot;&gt;MockAdapter&lt;/code&gt; andiamo ad agganciarci alla libreria &lt;code class=&quot;language-text&quot;&gt;axios&lt;/code&gt;, in modo tale da creare delle chiamate HTTP false. Con &lt;code class=&quot;language-text&quot;&gt;mock.onGet(&quot;/fake-url&quot;).reply(200, content);&lt;/code&gt; andiamo a creare una finta risposta HTTP tramite l’indirizzo &lt;code class=&quot;language-text&quot;&gt;/fake-url&lt;/code&gt; con il valore della variabile &lt;code class=&quot;language-text&quot;&gt;content&lt;/code&gt; come contenuto. Infine andiamo a testare che la risposta sia effettivamente &lt;code class=&quot;language-text&quot;&gt;content&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Facendo girare i test funziona tutto e stavolta possiamo testare anche offline.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mockare le chiamate HTTP esterne ai vari URL oppure ai microservizi esterni è fondamentale per avere una buona suite di test unitari&lt;/strong&gt;. Non possiamo chiamare delle risorse reali durante i test unitari anche perché probabilmente queste risorse esistono sono nell’ambiente di produzione e noi non vogliamo sporcare il contenuto di produzione con dei test.&lt;/p&gt;
&lt;h2&gt;Classe CounterApp&lt;/h2&gt;
&lt;p&gt;Questa è l’ultima classe che andremo a costruire. Il suo obiettivo è quello di:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Invocare il &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; per recuperare il testo dall’URL.&lt;/li&gt;
&lt;li&gt;Invocare il &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; per contare quante volte la parola da cercare è contenuta nel testo scaricato.&lt;/li&gt;
&lt;li&gt;Restituire il numero ritornato da &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Negli unit tests di una classe non vogliamo testare l’implementazione anche delle sue dipendenze&lt;/strong&gt;. Nel nostro caso non vogliamo testare di nuovo &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt;. Queste classi le abbiamo testate già bene. Per questo motivo andremo a mockare queste dipendenze un po’ come abbiamo fatto per le chiamate HTTP.&lt;/p&gt;
&lt;p&gt;Mockando le dipendenze esterne da una classe porta i seguenti vantaggi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Evitiamo che un errore nella dipendenza faccia fallire anche i test della classe che stiamo testando&lt;/strong&gt;. Idealmente un errore nel codice dovrebbe far fallire un solo test, e non anche tutte le parti che dipendono da esso.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Abbiamo quindi bisogno di una libreria che si chiama &lt;a href=&quot;https://github.com/NagRock/ts-mockito&quot;&gt;ts-mockito&lt;/a&gt; che si ispira alla famosa libreria di Mock su Java chiamata &lt;a href=&quot;https://site.mockito.org/&quot;&gt;Mockito&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rende semplice creare dei casi speciali&lt;/strong&gt;: immaginate che dobbiamo testare correttamente la gestione di un eccezione, la generazione di questa eccezione richiede una situazione molto particolare. Se mockiamo possiamo iniettare un mock che generi questa eccezione senza dover ricreare questa situazione speciale.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mettiamo in pratica ciò che ci siamo detti. Primo passo è installare &lt;code class=&quot;language-text&quot;&gt;ts-mockito&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev ts-mockito&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Andiamo a scrivere il test nel nuovo file &lt;code class=&quot;language-text&quot;&gt;src/__tests__/counter-app.ts&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; instance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mock&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; when &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ts-mockito&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; CounterApp &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../counter-app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TextFetcher &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../text-fetcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; WordCounter &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;../word-counter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CounterApp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// Initialization&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockWordCounter&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WordCounter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WordCounter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mockTextFetcher&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TextFetcher &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TextFetcher&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; counterApp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CounterApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockTextFetcher&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockWordCounter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;should get parameters and return the count&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; providedUrl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;url&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; providedWordToFind &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;word&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fakeContent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Testo recuperato&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; expectedCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockTextFetcher&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;providedUrl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fakeContent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;when&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mockWordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fakeContent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; providedWordToFind&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenReturn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expectedCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; counterApp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;countWordFromUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;providedUrl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; providedWordToFind&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expectedCount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nell’inizializzazione andiamo a creare i mock delle nostre due classi &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt;, con la riga &lt;code class=&quot;language-text&quot;&gt;new CounterApp(instance(mockTextFetcher), instance(mockWordCounter))&lt;/code&gt; andiamo ad inserire le istanze dei nostri mock nel costruttore della classe &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt;. Questa tecnica di “iniettare” le dipendenze utilizzate direttamente nel suo costruttore si sposa bene con i frameworks che utilizzano la &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;dependency injection&lt;/a&gt;. Se quest’ultima frase che ho scritto è puro arabo, non preoccuparti. Il messaggio che deve passare è questo: &lt;strong&gt;è buona prassi richiedere nel &lt;a href=&quot;https://it.wikipedia.org/wiki/Costruttore_(informatica)&quot;&gt;costruttore&lt;/a&gt; le dipendenze esterne che la classe ha bisogno per funzionare correttamente&lt;/strong&gt;. Questo è vero per due motivi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Indica chiaramente al programmatore che utilizza la vostra classe, quali dipendenze ha bisogno per svolgere la propria funzione.&lt;/li&gt;
&lt;li&gt;Rende facile i test della classe in questione, perché nel costruttori possiamo iniettare delle istanze mockate, come nel nostro caso.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La parte all’interno del test &lt;code class=&quot;language-text&quot;&gt;it(&quot;should get parameters and return the count&quot;, ...)&lt;/code&gt; dovrebbe essere abbastanza autoesplicativa: creo le variabili che mi aspetto di utilizzare e poi utilizzo &lt;a href=&quot;https://github.com/NagRock/ts-mockito&quot;&gt;ts-mockito&lt;/a&gt; per fare le dovute asserzioni. Per esempio con &lt;code class=&quot;language-text&quot;&gt;when(mockTextFetcher.getContent(providedUrl)).thenReturn(Promise.resolve(fakeContent));&lt;/code&gt; significa: “quando la classe chiama &lt;code class=&quot;language-text&quot;&gt;textFetcher&lt;/code&gt; utilizzando il metodo &lt;code class=&quot;language-text&quot;&gt;getContent&lt;/code&gt; con il parametro &lt;code class=&quot;language-text&quot;&gt;providedUrl&lt;/code&gt;, ritorna una &lt;code class=&quot;language-text&quot;&gt;Promise&lt;/code&gt; risolta con il valore &lt;code class=&quot;language-text&quot;&gt;fakeContent&lt;/code&gt;”. La funzionalità &lt;code class=&quot;language-text&quot;&gt;when(...).thenReturn(...)&lt;/code&gt; serve a noi per bypassare la vera implementazione delle classi mockate e ritornare un valore che decidiamo noi.&lt;/p&gt;
&lt;p&gt;Così facendo stiamo testando:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Che la classe &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt; chiami i metodi delle classi &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; con i parametri corretti, tramite i vari &lt;code class=&quot;language-text&quot;&gt;when(...).thenReturn(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Che la classe &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt; ritorni il numero corretto tramite &lt;code class=&quot;language-text&quot;&gt;expect(...).toBe(...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Facciamo girare i test con &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;. Chiaramente fallisce, ora andiamo ad implementare la classe nel nuovo file &lt;code class=&quot;language-text&quot;&gt;src/counter-app.ts&lt;/code&gt;;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TextFetcher &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./text-fetcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; WordCounter &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./word-counter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CounterApp&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; textFetcher&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; TextFetcher&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; wordCounter&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WordCounter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;countWordFromUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textFetcher&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wordCounter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Abbiamo creato un costruttore che inserisce nelle variabili private &lt;code class=&quot;language-text&quot;&gt;textFetcher&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;wordCounter&lt;/code&gt; le istanze di &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; (il costruttore è vuoto, sembra che non faccia niente, ma il lavoro sporco lo sta facendo la &lt;a href=&quot;https://www.stevefenton.co.uk/2013/04/stop-manually-assigning-typescript-constructor-parameters/&quot;&gt;keyword private&lt;/a&gt;). Poi abbiamo implementato il metodo asincrono &lt;code class=&quot;language-text&quot;&gt;countWordFromUrl&lt;/code&gt; che non fa altro che scaricare il contenuto dall’URL e poi conteggia il numero delle volte che compare la parola che stiamo cercando e lo ritorna.&lt;/p&gt;
&lt;p&gt;Proviamo con &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; ed effettivamente è tutto ok!&lt;/p&gt;
&lt;h2&gt;Prova reale&lt;/h2&gt;
&lt;p&gt;Ora che finalmente abbiamo raggiunto il nostro obiettivo, programmando completamente in TDD, proviamo a fare una prova reale.&lt;/p&gt;
&lt;p&gt;Creiamo il file &lt;code class=&quot;language-text&quot;&gt;src/index.ts&lt;/code&gt; dove inserirò un piccolo script per provare il tutto.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;typescript&quot;&gt;&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; CounterApp &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./counter-app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; TextFetcher &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./text-fetcher&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; WordCounter &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./word-counter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;testApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;https://raw.githubusercontent.com/matitalatina/word-counter/master/README.md&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; wordToFind &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;WordCounter&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CounterApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TextFetcher&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WordCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;countWordFromUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wordToFind&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;The word &quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;wordToFind&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;, in &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, appears &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;count&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; times&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;testApp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ho creato una piccola funzione &lt;code class=&quot;language-text&quot;&gt;testApp&lt;/code&gt; dove crea la mia classe &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt; con le dovute dipendenze, e provo a contare quante volte compare la parola &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; dalla pagina &lt;a href=&quot;https://raw.githubusercontent.com/matitalatina/word-counter/master/README.md&quot;&gt;README.md&lt;/a&gt; della mia repository per questo progetto.
Per avviare il programma, ho bisogno di transpilare TypeScript in JavaScript, perché come sappiamo Node.js non sa leggere direttamente TypeScript. Per risolvere utilizzerò la libreria &lt;a href=&quot;https://github.com/TypeStrong/ts-node&quot;&gt;ts-node&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;npm install --save-dev ts-node&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Ora che è installato, avviamo il nostro script in questo modo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx ts-node src/index.ts&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il risultato è questo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;The word &lt;span class=&quot;token string&quot;&gt;&quot;WordCounter&quot;&lt;/span&gt;, &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; https://raw.githubusercontent.com/matitalatina/word-counter/master/README.md, appears &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;times&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Funziona!!!&lt;/p&gt;
&lt;h2&gt;Mantenimento del progetto&lt;/h2&gt;
&lt;p&gt;Abbiamo finito il nostro piccolo progettino in TDD. Ma un vero progetto che si rispetti non è mai “finito”, bisogna mantenerlo e migliorarlo ogni giorno. Un altro vantaggio che ho apprezzato dopo qualche mese di sviluppo in TDD è il tempo drasticamente calato in termini di debugging o di bug in produzione. Quindi &lt;strong&gt;il tempo speso a scrivere test è di gran lunga ricompensato dal tempo risparmiato dal debugging del prodotto&lt;/strong&gt;. Provare per credere!
Però non pensare che i bug non esistano più utilizzando il TDD. Sono molto di meno ma ogni tanto capitano. Quando capitano dobbiamo sempre ricordarci di &lt;strong&gt;scrivere il test che manifesta il bug prima di fixare il bug&lt;/strong&gt;. In questo modo continuiamo ad usare il TDD, ma soprattutto abbiamo la garanzia che il bug non si manifesterà più anche se noi andiamo a modificare pesantemente il codice in futuro.&lt;/p&gt;
&lt;h2&gt;Quando utilizzare il TDD&lt;/h2&gt;
&lt;p&gt;Ora che abbiamo visto cosa è il TDD, una domanda può sorgere spontanea: &lt;strong&gt;quando si dovrebbe utilizzare il TDD?&lt;/strong&gt; Qui meglio fare una distinzione: &lt;strong&gt;se devo scegliere tra il TDD e i test unitari classici, per esperienza personale sceglierei sempre il TDD&lt;/strong&gt;. L’approccio classico non mi ha mai portato nessun giovamento rispetto al TDD. L’unico “vantaggio” che ho visto è che l’approccio classico permette di non testare tutto, ma sinceramente non lo reputo un vantaggio proprio perché crea dei buchi pericolosi che vanificano gran parte dei vantaggi che abbiamo trovato in questa guida.&lt;/p&gt;
&lt;p&gt;Se invece la scelta è tra il TDD e solamente l’implementazione senza test unitari il discorso cambia.
Sicuramente queste sono le casistiche dove si dovrebbe utilizzare il TDD (o almeno test unitari).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sistemi di backend: quando si hanno dei clienti (mobile app, microservizi etc.) che si appoggiano al nostro sistema è fondamentale che il backend funzioni perfettamente.&lt;/li&gt;
&lt;li&gt;Parti “mission critical”: se abbiamo delle componenti che devono funzionare e sono cruciali per erogare il nostro servizio, non possiamo permetterci di avere dei bug o andare sulla fiducia.&lt;/li&gt;
&lt;li&gt;Componenti che sono difficili da testare “live”: se ci impiego 5 minuti solo per testare una singola volta una casistica speciale, meglio spenderli per creare un test che poi almeno ce l’ho sempre e mi basta un &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; per ricontrollare.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Quando invece non serve il TDD e si può andare solamente con l’implementazione?&lt;/strong&gt; Sembra un’eresia ma io ho trovato alcuni casi in cui solo l’implementazione basta e avanza:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quando la nostra implementazione è facilmente testabile “live”: mai sentito parlare di live-reloading? Con le web-app o anche nello sviluppo di app ibride con &lt;a href=&quot;https://flutter.io/&quot;&gt;Flutter&lt;/a&gt;, &lt;a href=&quot;https://ionicframework.com/&quot;&gt;Ionic&lt;/a&gt; o &lt;a href=&quot;https://facebook.github.io/react-native/&quot;&gt;React Native&lt;/a&gt;, è possibile implementare e visionare subito l’output. Questo è uno strumento potentissimo che velocizza enormemente lo sviluppo, ma soprattutto il tempo tra l’implementazione e il risultato finale è pari a zero. Che serve scrivere i test se mi basta salvare il codice e subito vedo il risultato finale e posso provarlo?&lt;/li&gt;
&lt;li&gt;Quando ci possiamo permettere qualche libertà, le specifiche sono ancora fumose ed il nostro cliente è a stretto contatto con lo sviluppo: mi è capitato di sviluppare letteralmente con il cliente che poteva darmi i feedback quasi in tempo reale. Se l’ambiente è molto informale/colloquiale è possibile creare un intero progetto senza scrivere una riga di test ed il cliente è contento comunque anche se magari di tanto in tanto ti chiama per segnalare un bug. L’importante è che possiate risolverlo velocemente così che il cliente possa apprezzare la vostra rapidità nel fix.&lt;/li&gt;
&lt;li&gt;Quando il progetto è un esperimento: certe volte capita di creare un progetto solo per capire se una determinata cosa possa funzionare. Oppure si implementa una piccola variazione per fare A/B testing, o ancora si sviluppa una cosa temporanea per ovviare ad un problema altrettanto temporaneo. In questi casi non apprezzeremo mai i vantaggi del TDD, perché il tempo speso nei test non verrà compensato dal tempo risparmiato dal debugging o fix di bug.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Il messaggio che deve passare è questo: valutate il vostro caso e agite di conseguenza. &lt;strong&gt;Il TDD è la soluzione a molti problemi, ma non a tutti&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusioni&lt;/h2&gt;
&lt;p&gt;Prima di tutto mi scuso se leggendo questa guida magari non è passato molto il concetto del “è più semplice di quanto si creda”.
Ma non dimenticare che qui hai visto numerosi concetti che, se è la prima volta che li vedi, ci vuole un po’ di tempo per digerirli. Se magari ti sei perso i concetti che hai imparato in questo articolo ti faccio un piccolo sommario:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Inizializzazione di un progetto in Node.js, utilizzo del packet manager &lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Inserimento di TypeScript con Linter integrato.&lt;/li&gt;
&lt;li&gt;Utilizzo di Jest per il testing.&lt;/li&gt;
&lt;li&gt;Programmazione asincrona con con le keyword &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; introdotte in ECMAScript 2017.&lt;/li&gt;
&lt;li&gt;Utilizzo di librerie di Mocking, quando e perché usarle.&lt;/li&gt;
&lt;li&gt;Test Driven Development.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All’inizio il TDD sembra un freno, come tutte le cose nuove, ma una volta preso dimestichezza, tutto diventa più veloce e anche più divertente! Fa sempre piacere arrivare a fine giornata e vedere il proprio progetto che cresce insieme ai test che aumentano e sono tutti verdi… &lt;em&gt;tranne uno&lt;/em&gt;! Ebbene sì: &lt;strong&gt;a fine giornata, se il progetto non è concluso, scriviamo un test che fallisce prima di andare via&lt;/strong&gt;. Questo è un consiglio che è molto efficace per riprendere i lavori. In questo modo ci ricordiamo perfettamente cosa stavamo facendo quando ritorneremo a lavorare. Il test fallito ci dirà esattamente cosa abbiamo lasciato indietro.&lt;/p&gt;
&lt;p&gt;Spero che questo articolo ti abbia fatto venire voglia di provare questa affascinante tecnica che, a primo impatto, può sembrare quasi assurda, ma una volta adottata, aumenta enormemente la qualità del codice e di conseguenza anche la qualità del prodotto finale.&lt;/p&gt;
&lt;p&gt;Se volete vedere il TDD in azione con Spring Boot potete leggere il mio articolo che parla di &lt;a href=&quot;/it/come-sviluppare-rest-api-in-tdd-con-spring-boot&quot;&gt;come sviluppare delle API RESTful in TDD con Spring Boot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[11 lezioni che ho imparato lavorando nelle startup]]></title><description><![CDATA[Sono quasi 4 anni che ormai lavoro in startup. Sono convinto che la startup sia un’ottima scelta per uno studente fresco fresco di laurea…]]></description><link>https://www.mattianatali.it/it/11-lezioni-che-ho-imparato-lavorando-nelle-startup/</link><guid isPermaLink="false">https://www.mattianatali.it/it/11-lezioni-che-ho-imparato-lavorando-nelle-startup/</guid><pubDate>Sat, 21 Apr 2018 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Sono quasi 4 anni che ormai lavoro in startup. Sono convinto che la startup sia un’ottima scelta per uno studente fresco fresco di laurea, perchè sono ambienti molto dinamici: data la loro natura instabile si è “costretti” ad adattarsi, si impara ogni giorno qualcosa di nuovo e quindi è un’ottima opportunità per crescere personalmente insieme all’azienda.&lt;/p&gt;
&lt;p&gt;Siccome ora sto cambiando ambiente lavorativo è giunta l’ora di tirare le somme. In questo post racconterò ciò che ho imparato a lavorare nelle startup, nel mio caso &lt;a href=&quot;http://wavein.ch/&quot;&gt;wavein.ch&lt;/a&gt; e &lt;a href=&quot;https://cloudacademy.com&quot;&gt;Cloud Academy&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Il tuo capo vuole soluzioni, non problemi&lt;/h2&gt;
&lt;p&gt;Nelle startup, i propri superiori sono spesso le stesse persone che hanno scritto il codice prima di te, quindi la tentazione di chiedere aiuto a loro è molto alta. Ma ricorda che ora il loro ruolo è cambiato, quindi hanno mille altre faccende per la testa. Infatti contano su di te per portare a termine il compito che ti è stato affidato. &lt;strong&gt;Invece di chiedere aiuto, bisogna chiedere a loro che decisione prendere&lt;/strong&gt;. Il flusso corretto è che loro ti chiedano di fare X, tu analizzi il problema e porti le soluzioni con pro e contro di ognuna, infine il superiore deciderà la soluzione da intraprendere assumendosi la responsabilità. In questo modo tutti sono felici: tu sai perfettamente cosa fare, il superiore ha perso poco tempo e ha ricevuto solo le informazioni che gli interessavano.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1278px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/39379d8f97747d8393feb3b511969100/c0d6e/waveinch.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.400000000000006%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUHBAb/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgT/2gAMAwEAAhADEAAAAdVBmKzM9SLiz//EABkQAAMBAQEAAAAAAAAAAAAAAAEDBAUCAP/aAAgBAQABBQKHaTx5xVep6wGbs64tPKvoclnfRP8A/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERAv/aAAgBAwEBPwHLqpT/xAAXEQADAQAAAAAAAAAAAAAAAAAAAhIR/9oACAECAQE/AWWWwg//xAAcEAACAwADAQAAAAAAAAAAAAABAgADEQQSITH/2gAIAQEABj8C5HobqNGH2JcjMAyA4DDLXoQVMVG9Zj2kjtPs/8QAGRAAAwEBAQAAAAAAAAAAAAAAAAEhEUGR/9oACAEBAAE/IUavHJ5HXeQjGwxW+ii303iDI6XMyM1LZw//2gAMAwEAAgADAAAAEEzP/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/ECzJ/8QAGREAAwADAAAAAAAAAAAAAAAAAAEhEXHB/9oACAECAQE/EEUTuzBn/8QAGhABAAMBAQEAAAAAAAAAAAAAAREhMQBBUf/aAAgBAQABPxA8kBUt0RqAk/c4qnyG3tSOinDp4GPbO9AKNcGxRhXw4InLIGw+H1WPJY3hKT09/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Lo studio di wavein.ch&quot;
        title=&quot;&quot;
        src=&quot;/static/39379d8f97747d8393feb3b511969100/c0d6e/waveinch.jpg&quot;
        srcset=&quot;/static/39379d8f97747d8393feb3b511969100/d1f95/waveinch.jpg 500w,
/static/39379d8f97747d8393feb3b511969100/dbdff/waveinch.jpg 1000w,
/static/39379d8f97747d8393feb3b511969100/c0d6e/waveinch.jpg 1278w&quot;
        sizes=&quot;(max-width: 1278px) 100vw, 1278px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Tieni traccia di ciò che stai facendo&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;La trasparenza nelle startup è fondamentale&lt;/strong&gt;: tu ovviamente sai benissimo su cosa stai lavorando, quale bug ti sta facendo impazzire… Ma tutto questo non è così scontato per il resto del mondo. Io usavo &lt;a href=&quot;https://www.jetbrains.com/youtrack/&quot;&gt;YouTrack&lt;/a&gt; e &lt;a href=&quot;https://it.atlassian.com/software/jira&quot;&gt;Jira&lt;/a&gt; come &lt;a href=&quot;https://en.wikipedia.org/wiki/Issue_tracking_system&quot;&gt;issue tracking system&lt;/a&gt;, non c’è niente di peggio che avere giornate di fuoco al lavoro ed avere la board vuota. Questo può essere un problema per te che non sei in grado di mostrare agli altri su cosa stai lavorando, ma sopratutto è un problema per il Product Manager che non potrà mai schedulare correttamente i lavori, non avrà nessuna visibilità sui possibili ritardi e infine non può prioritizzare correttamente i lavori. Stesso discorso vale per i task che sono bloccati: &lt;strong&gt;metti sempre nero su bianco su cosa stai lavorando&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/aebc1b1ecd2d4db342018e471862e580/c2cc8/Postazione.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.199999999999996%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAALABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYDBAUH/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgP/2gAMAwEAAhADEAAAAebyK2/NIZRKj//EAB0QAAICAQUAAAAAAAAAAAAAAAMFAQIEAAYUIyT/2gAIAQEAAQUCXLOQd8rY7YNUop0jn2MZ7gssrGp//8QAGBEBAQADAAAAAAAAAAAAAAAAAQACElH/2gAIAQMBAT8BQbXHl//EABgRAAMBAQAAAAAAAAAAAAAAAAABAhJR/9oACAECAQE/AVTNX0//xAAlEAACAQIFAwUAAAAAAAAAAAABAgMAERITISIxBAUUQUJRcbH/2gAIAQEABj8CiggUp15bK1Jw3P3UY7l48gnVssXuPymMrOWv7NaHB2HkXqDapGPgqD6VgindE+Aa/8QAHBABAAMAAwEBAAAAAAAAAAAAAQARITFBUaHw/9oACAEBAAE/IQtRMEyK4/qYN3Cbaq3hu/YkkMYAdb7N5EFy7HszHGUzVeJKFc3nJ//aAAwDAQACAAMAAAAQfO//xAAYEQADAQEAAAAAAAAAAAAAAAAAARFR8P/aAAgBAwEBPxCZFFhyR//EABkRAQACAwAAAAAAAAAAAAAAAAEAQREhkf/aAAgBAgEBPxAGRVW13Gpdn//EABoQAQEAAwEBAAAAAAAAAAAAAAERACFBMWH/2gAIAQEAAT8QGHhAkGogjQ2xENWePiDGFDRmYb0dhEkPQ7PmJC4GIp0h3FL9wEvxS4QKBo96D6DgRSAoF9Zn/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Postazione&quot;
        title=&quot;&quot;
        src=&quot;/static/aebc1b1ecd2d4db342018e471862e580/109c0/Postazione.jpg&quot;
        srcset=&quot;/static/aebc1b1ecd2d4db342018e471862e580/d1f95/Postazione.jpg 500w,
/static/aebc1b1ecd2d4db342018e471862e580/dbdff/Postazione.jpg 1000w,
/static/aebc1b1ecd2d4db342018e471862e580/109c0/Postazione.jpg 2000w,
/static/aebc1b1ecd2d4db342018e471862e580/9a593/Postazione.jpg 3000w,
/static/aebc1b1ecd2d4db342018e471862e580/008f5/Postazione.jpg 4000w,
/static/aebc1b1ecd2d4db342018e471862e580/c2cc8/Postazione.jpg 4032w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Ognuno di noi è diverso&lt;/h2&gt;
&lt;p&gt;Noi abbiamo un carattere, la propria personalità: per questo motivo ci comportiamo spesso con tutti in egual modo. Ma ci dimenticano che anche gli altri sono tutti diversi: c’è chi è più espansivo, chi si offende facilmente, chi è timido, chi si inalbera per il nulla ecc. &lt;strong&gt;Non possiamo comportarci allo stesso modo con tutti indiscriminatamente&lt;/strong&gt;. E peggio ancora &lt;strong&gt;non possiamo pretendere che gli altri debbano adattarsi al nostro carattere&lt;/strong&gt;, non funzionerà mai!&lt;/p&gt;
&lt;p&gt;Secondo me è nostro compito tirar fuori il meglio da ognuno facendo leva sulle qualità di ognuno:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;La persona ama aiutare il prossimo&lt;/em&gt;: fatti aiutare! Sicuramente può insegnarti sempre qualcosa.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Si offende facilmente&lt;/em&gt;: cerca di non fare battute inutili, mantieni un profilo più professionale / distaccato.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;La persona si infiamma facilmente e odia “non aver ragione”&lt;/em&gt;: se hai già in mente la soluzione ad un problema e vuoi solo una conferma, non spiegargli subito il macro problema. Altrimenti ti darà la sua soluzione e non vorrà più discuterne. Invece cerca di spezzettarlo in piccoli problemi dove le soluzioni sono ovvie e sono quelle che hai adottato tu. Infine tutte queste soluzioni porteranno alla tua soluzione definitiva per logica conseguenza.&lt;/p&gt;
&lt;p&gt;Se questa persona comincia a scaldarsi, non cominciare a mimare il suo tono… Altrimenti è solo un crescere di toni che finirà solo male. Non aver paura di interrompere la discussione senza una soluzione se vedi che non sta portando a niente.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Ama fare battutacce e piace “insultare amichevolmente” gli altri&lt;/em&gt;: stai al gioco! Non prenderti troppo sul serio. Molto spesso se ti prendono in giro apertamente è solo perchè vogliono farsi una risata insieme a te. Se non si è abituati è veramente difficile da digerire inizialmente, ma poi non ci si fa più caso e anzi ci si diverte. Alla fine si capisce quando qualcuno lo fa solo per divertirsi oppure perchè prova rancone nei tuoi confronti.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Una persona non gli vai a genio&lt;/em&gt;: la cosa peggiore che si possa fare è fare terra bruciata intorno a lui. Devi passare la quotidianità con lui e quindi non serve a nessuno. Invece cerca di evitare il comportamento che gli dà fastidio se qualcuno te lo dice. Altrimenti cerca di comportarti sempre bene con lui: aiutalo e non stargli troppo attaccato, così piano piano capirà che non dovrebbe avere nulla contro di te. Se non funziona… Beh pace, cerca sempre di non dargli dei buoni motivi per odiarti, è l’unica cosa che si può fare in questi casi.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;È timida&lt;/em&gt;: non verrà mai a chiederti aiuto o consiglio. Ogni tanto fatti sentire, così che poi si sblocchi anche lui. In questo modo entrambi potete lavorare.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;È uno scaricabarile&lt;/em&gt;: “Scusa, potresti farmi questo? So che tu ci hai lavorato poco tempo fa.”, “Io non so niente di sta roba, puoi farmelo tu che so che ne sai?“. Un conto è aiutare, un’altro è fare il lavoro di altri al posto loro. Anche tu hai i tuoi obiettivi, cerca di rimanere focalizzato sui tuoi.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Insomma questi sono solo dei piccoli esempi e comportarsi in modo diverso con persone diverse non significa essere falsi. È secondo me l’unico modo per poter vivere in modo pacifico con numerose persone nella quotidianità lavorativa.&lt;/p&gt;
&lt;h2&gt;È lecito dire di No&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Il lavoro è come l’acqua: fluisce dove viene fatto&lt;/em&gt;. Quindi bisogna stare attenti a dire troppi sì, altrimenti finisce che tutto il lavoro si riversa su di te e poi hai due problemi molto seri: rischi il burnout perchè non hai un attimo di respiro ed in più ti accusano di essere il collo di bottiglia! È importante aiutare gli altri, fare del lavoro extra, ma lo è di più finire i propri task assegnati. Per l’azienda è importante rispettare il proprio piano, se fallisci nel rispettare le tempistiche originarie, tutto ciò avrà ripercussioni sul planning e questo avrà una ripercussione negativa su tutta l’azienda. Più si è in pochi e più le conseguenze sono visibili. Quindi &lt;strong&gt;non bisogna avere paura a dire ‘No’&lt;/strong&gt; a chi ci chiede di fare altro lavoro in più. Prima fai il tuo poi, se avanza tempo, accetta del lavoro extra.
Altri ‘No’ che sono portanti sono quelli dal punto di vista tecnico. Non è raro che vengano calati dall’alto dei task che da un punto di vista tecnico o di usabilità non stanno né in cielo né in terra. In questi casi &lt;strong&gt;è nostro dovere dire ‘No’ e dare le proprie motivazioni&lt;/strong&gt;: è lo sviluppatore che può capire le conseguenze di requirement esotici (debito tecnico, logiche fumose già dall’inizio, eccessiva complessità della UX ecc).&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a966367c22abbdaf97c05791f6199f15/109c0/CAWork2.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMHBQb/xAAVAQEBAAAAAAAAAAAAAAAAAAACA//aAAwDAQACEAMQAAABW+P5M13BNg1//8QAGxAAAwACAwAAAAAAAAAAAAAAAgMEBQYABxP/2gAIAQEAAQUCX2Jday7cKiVXuI1vTfj5OPzXsCIFuD//xAAZEQADAAMAAAAAAAAAAAAAAAAAAQIEITH/2gAIAQMBAT8BcbFj0+H/xAAZEQACAwEAAAAAAAAAAAAAAAAAIQECERP/2gAIAQIBAT8B1I71g//EAB0QAAICAwEBAQAAAAAAAAAAAAECERIAAzEEIRP/2gAIAQEABj8CUa6opeH2VtHyMX0SmxFadmqvQMZx4PNXij9ODGQn3gLxAU+5BsHHKiBhbYxtOf/EABsQAQACAwEBAAAAAAAAAAAAAAEAESExQVFx/9oACAEBAAE/IX3zEBYWKPuNNcjmD8GayV1qdEiNDmalgOBWx22vQ5ABl9Es2YPvkOPasJ//2gAMAwEAAgADAAAAEHz/AP/EABgRAQEBAQEAAAAAAAAAAAAAAAERADFx/9oACAEDAQE/EAYeYYYnu//EABkRAAMAAwAAAAAAAAAAAAAAAAABESFBcf/aAAgBAgEBPxDFNhsR28P/xAAbEAEAAwADAQAAAAAAAAAAAAABESExAEFRYf/aAAgBAQABPxBplVXIEpQnqArw7YtPZWzkuTWhOGxBmj1LV64BMfVJSLQkQ6zYkpucqZgncgkBTt8ecYC9guzB95//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Io e il team di CloudAcademy che lavoriamo seriamente&quot;
        title=&quot;&quot;
        src=&quot;/static/a966367c22abbdaf97c05791f6199f15/109c0/CAWork2.jpg&quot;
        srcset=&quot;/static/a966367c22abbdaf97c05791f6199f15/d1f95/CAWork2.jpg 500w,
/static/a966367c22abbdaf97c05791f6199f15/dbdff/CAWork2.jpg 1000w,
/static/a966367c22abbdaf97c05791f6199f15/109c0/CAWork2.jpg 2000w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Un fallimento è realmente tale se non si impara nulla&lt;/h2&gt;
&lt;p&gt;Ora dico una cosa che non fa piacere a nessuno. Tutti falliscono in qualcosa: io ho fatto sbagli e ne farò ancora, è impossibile fare tutto perfetto nella propria carriera lavorativa. Diffida da chi ti dice “Io non ho mai fatto errori / Non ho mai fallito / Sinceramente non mi ricordo di miei errori commessi nel passato”. Ti sta solo prendendo in giro oppure sta mentendo a se stesso, perchè noi, soprattutto italiani, odiamo fallire e soprattutto odiamo ammetterlo.&lt;/p&gt;
&lt;p&gt;Ma &lt;strong&gt;sbagliare è parte integrante dell’apprendimento&lt;/strong&gt;. L’esperienza non è altro che un insieme di errori che ti sei portato a casa e che sei pronto a non ripetere. È per questo che chi dice di non aver mai sbagliato sta mentendo, significa che o non ha mai fatto niente oppure non ha mai avuto un compito veramente sfidante.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prima si riconosce un errore, prima è possibile porvi rimedio&lt;/strong&gt;. Prima si pone rimedio e meno danni si fanno. Se una strada sta portando ad un niente di fatto, oppure sta diventando più difficile del previsto, fermati… Fai un bel respiro, analizza la situazione e vedi se ne vale la pena continuare. Altrimenti è giunto il momento di chiedere un parere ad un collega e poi annunciare il problema al proprio superiore (possibilmente con qualche soluzione in mano). Poi si fanno le dovute correzioni.&lt;/p&gt;
&lt;p&gt;Vedrai che così facendo nessuno può dirti niente, apprezzeranno la tua capacità di prevedere un possibile danno ancora maggiore, si prende nota di cosa è andato storto così da non ripetere lo stesso errore in futuro e si continua felici di aver evitato un possibile disastro.&lt;/p&gt;
&lt;p&gt;L’alternativa a tutto questo? Dire a tutti che è tutto ok, andare avanti sulla propria strada, cercare di tirar fuori il meno peggio, prendere tempo per cercare di tenere in piedi una cosa che è morta, prendere ancora tempo, disperarsi, gettare la spugna e dire che stai lavorando su una cavolata, che non può funzionare, incolpando la donna delle pulizie pur di non assumersi la propria responsabilità… Nessuno lo apprezzerà, anzi capiranno che non possono fare affidamento su di te, quindi evita.&lt;/p&gt;
&lt;p&gt;Fallire non è bello, ma succede. Quindi se deve succedere fallo il prima possibile.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e2246affc18286618dc50eb2f3acdd74/4771e/SF_Mattia.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.199999999999996%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAUHBP/EABUBAQEAAAAAAAAAAAAAAAAAAAME/9oADAMBAAIQAxAAAAHO+hzWma4kSCH/xAAcEAACAgIDAAAAAAAAAAAAAAADBAIFAAESFBX/2gAIAQEAAQUCVuq1wyvUaH56+RJJKxrGCbHMkuX/xAAaEQACAgMAAAAAAAAAAAAAAAAAAgEUAxFR/9oACAEDAQE/AauFo0UE6f/EABsRAAIBBQAAAAAAAAAAAAAAAAABAwIEEhVS/9oACAECAQE/AXdTxrNm1q5P/8QAJBAAAQMCBAcAAAAAAAAAAAAAAQACAxESBCExoRMiMjNBcZH/2gAIAQEABj8CayNs0ldLGjPdMeJBHcK2v1Htd5n1Ybg8mQ3UjLzaPC6iv//EABsQAAICAwEAAAAAAAAAAAAAAAERAGEhMVGx/9oACAEBAAE/IXoGmR6VLm3PBFXaOR3VhgPMuA+DuoRZDFcZj70n/9oADAMBAAIAAwAAABCYD//EABgRAQADAQAAAAAAAAAAAAAAAAEAESGB/9oACAEDAQE/EAQiNu8jdH//xAAaEQEAAQUAAAAAAAAAAAAAAAABABEhceHx/9oACAECAQE/EHLCULZh3an/xAAbEAEAAwEBAQEAAAAAAAAAAAABABEhMVFhkf/aAAgBAQABPxBz9mtGsIBFtUUGr5GBRSmmqCwpvWJrIFj1P2GJSoAW2YTUlc8iSjL8ssPmGcgSDPBk/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Classica foto con il Golden Gate Bridge a San Francisco&quot;
        title=&quot;&quot;
        src=&quot;/static/e2246affc18286618dc50eb2f3acdd74/109c0/SF_Mattia.jpg&quot;
        srcset=&quot;/static/e2246affc18286618dc50eb2f3acdd74/d1f95/SF_Mattia.jpg 500w,
/static/e2246affc18286618dc50eb2f3acdd74/dbdff/SF_Mattia.jpg 1000w,
/static/e2246affc18286618dc50eb2f3acdd74/109c0/SF_Mattia.jpg 2000w,
/static/e2246affc18286618dc50eb2f3acdd74/4771e/SF_Mattia.jpg 2592w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Chiedere aiuto è un’arma, non una debolezza&lt;/h2&gt;
&lt;p&gt;Purtroppo per molti chiedere aiuto è quasi una sconfitta personale, altri non lo fanno per non rubare troppo tempo alla persona che si rende disponibile ad aiutare. Ma &lt;strong&gt;chiedere una mano&lt;/strong&gt; a chi ne sa di più su un determinato prodotto, parte di codice, tecnologia è fondamentale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Si raggiunge prima l’obiettivo&lt;/strong&gt;. Chiedere una domanda e ottenere una risposta richiede pochi minuti. Cercare di capire una parte di codice scritta da altri, cercare una risposta online per un caso molto specifico ci si impiega ore.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Si capisce realmente il funzionamento della piattaforma&lt;/strong&gt;. Purtroppo nelle startup la documentazione lascia un po’ a desiderare, quindi molto spesso si finisce a leggere direttamente il codice. Alcune parti possono essere oscure da capire semplicemente perchè non è esplicitata la reale motivazione. Non è raro trovare orribili hack in mezzo al codice per risolvere dei casi specifici che solo una persona conosce… E non è detto che quella persona sia ancora in azienda! Se c’è ti consiglio una cosa, vai a chiedere.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Si evita di scrivere strafalcioni&lt;/strong&gt;: ho visto persone che pur di non chiedere o capire il funzionamento di una parte di prodotto, “bypassava” completamente quella parte scrivendone un’altra molto simile. Questo è il male, perchè si creando due parti di codice che coesistono, non si capisce bene il perchè e ovviamente rende il codice non manutenibile. Oppure altri che risolvevano un problema solo in superficie perchè “hey, non tocco il codice scritto da altri!“… Anche questo è il male assoluto: in questo modo si può distruggere l’architettura in poche settimane. Piuttosto si chiede a chi ha scritto il codice e poi si risolve.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Si impara più velocemente!&lt;/strong&gt; Anche da un punto di vista personale è molto meglio chiedere aiuto: si impara molto più velocemente e sentire come ragionano altri sviluppatori è il miglior modo per migliorare se stessi…&lt;/li&gt;
&lt;li&gt;Anche tu hai bisogno di aiuto… Cosa? Stai pensando che tu sei il migliore e che non hai niente da imparare soprattutto dai tuoi colleghi? Beh, tutti quelli che la pensano così sono quelli che crescono di meno e rimangono indietro, perchè pensano che non hanno più nulla da imparare e rimangono fermi con la loro conoscenza. Letteralmente chiunque può insegnarci qualcosa, anche la persona più junior in azienda, perchè semplicemente ogni persona ha un proprio, unico, background personale.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 747px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6d7f2969e49e6c2423de5ba6406835d8/d61d8/IoEZacco2.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAYFBAf/xAAZAQACAwEAAAAAAAAAAAAAAAAABgECAwT/2gAMAwEAAhADEAAAAambxYKDsbjQ96kxSZIcdtf/xAAdEAACAgMAAwAAAAAAAAAAAAACBAMFAQYUABUW/9oACAEBAAEFAn7RWtBuP6RaDslj2erZ4oWGAfD1Ji0tGwDVIlkca6n5/8QAHhEAAgAGAwAAAAAAAAAAAAAAAAIBAwQREhVBUWH/2gAIAQMBAT8BenusZT8mvTwUwXo//8QAHxEAAgECBwAAAAAAAAAAAAAAAAEDAgQSFSExUWGR/9oACAECAQE/AYbhJqWh7GYyd+DbT0MdXJ//xAAlEAACAAUEAAcAAAAAAAAAAAABAgADERIhBDEyQRMUIiNxkaH/2gAIAQEABj8CB1M9EuH3CDRtLZB6r642zApLl2rgeKi1/YTVamZL9luLDlWFkeYIkXcUwCMRc80IxJxaT38wRMUONqGBSQqmu46hsNue4//EAB0QAAICAwADAAAAAAAAAAAAAAERACExQXFRYYH/2gAIAQEAAT8h201ItcoD5C5VNMOCRrSgchnOfZXDAmSFQgKIBHazFNValNqA0fFqWQpIjiyXChuZw2FDBgDLxHqYqHc//9oADAMBAAIAAwAAABDs34P/xAAeEQACAQMFAAAAAAAAAAAAAAAAATERIZFBUWFx8P/aAAgBAwEBPxBqB22v7QVCMhE5OPhH/8QAHBEAAwABBQAAAAAAAAAAAAAAAAERkSExUWHx/9oACAECAQE/ENRpWV7yOm5IFQ7+Wf/EAB4QAQEAAgMAAwEAAAAAAAAAAAERACExQVFhgZHR/9oACAEBAAE/EIblj6MIyv8AWP7BqDoUoLOfQwODQGDi36M+8mDY0YtEonpCVkuOceIxE6Rq/BGrpFOIsp24E6e33BT8oCoKR6YfmaGDgnZasdY8wSRIFM46sz//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Io e Zacco che lavoriamo felici&quot;
        title=&quot;&quot;
        src=&quot;/static/6d7f2969e49e6c2423de5ba6406835d8/d61d8/IoEZacco2.jpg&quot;
        srcset=&quot;/static/6d7f2969e49e6c2423de5ba6406835d8/d1f95/IoEZacco2.jpg 500w,
/static/6d7f2969e49e6c2423de5ba6406835d8/d61d8/IoEZacco2.jpg 747w&quot;
        sizes=&quot;(max-width: 747px) 100vw, 747px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Il codice perfetto non interessa a nessuno&lt;/h2&gt;
&lt;p&gt;Ecco qui una lezione che può fare male a chi esce fresco fresco dall’università. Nel mondo accademico la cosa più importante è scrivere il codice perfetto, avere il codice più astratto possibile per avere un codice che si adatta facilmente a qualsiasi caso d’uso. Nessuno guarda il tuo codice fino all’esame finale e quindi si può lavorare in tutta tranquillità. C’è solo un piccolo particolare… Nel mondo universitario si ha un sacco di tempo a disposizione, nelle startup no. La feature che ti è stata richiesta è bloccante per altri sviluppatori, gli stakeholder vogliono la tua parte pronta e deployata ieri. Quindi &lt;strong&gt;non viene valutata la bontà del tuo codice, ma la tua execution&lt;/strong&gt;. La velocità con cui porti a termine il tuo compito.&lt;/p&gt;
&lt;p&gt;Quindi come si fa a far coesistere il buon codice con velocità di esecuzione? Tramite &lt;strong&gt;iterazioni&lt;/strong&gt;: scrivi il minimo indispensabile per raggiungere l’obiettivo, non complicare le cose con costrutti strani. Scrivere il minimo indispensabile è ben diverso dallo scrivere un brutto codice: continua a seguire le best practice, mantieni il codice più pulito possibile, continua a valutare che più scorciatoie prendi più bisogna sacrificare la manutenibilità. Ma non fasciarti la testa prima del problema, perchè magari quel problema non arriverà mai… E se mai arrivasse, si itera, ma almeno la tua feature originale è già arrivata sul mercato e può essere validata dal cliente.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8be827184d75035a8fd96b639fb4525c/7f20e/startup_weekend2.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 56.400000000000006%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAYHAwj/xAAVAQEBAAAAAAAAAAAAAAAAAAAEAv/aAAwDAQACEAMQAAABnz/znUzXkK4ZP//EABkQAAMBAQEAAAAAAAAAAAAAAAIDBAUABv/aAAgBAQABBQKPY0/TnoBUK3ZzGlM456NGhhyFS0O//8QAGhEAAgIDAAAAAAAAAAAAAAAAAQIAEhExQf/aAAgBAwEBPwEmi3PIjM6hs7n/xAAZEQEAAgMAAAAAAAAAAAAAAAABABICIUH/2gAIAQIBAT8BdtTsQxaz/8QAIRAAAgEEAQUBAAAAAAAAAAAAAQIDAAQRIRMSI0FRYZH/2gAIAQEABj8CHLciUW3cCyEa+4okSrLEByEtssT61QPRGdflM8bFGG8io7kueaRMsw80MORqv//EABsQAAICAwEAAAAAAAAAAAAAAAERACExQWGx/9oACAEBAAE/Ib2FaXJGREjJZozmwryOKVdo8ELMNyZKUZdhtFgsChEEdoDP/9oADAMBAAIAAwAAABAIL//EABkRAQEAAwEAAAAAAAAAAAAAABEBACExkf/aAAgBAwEBPxBnZFTiGaGhL7n/xAAYEQEAAwEAAAAAAAAAAAAAAAABABEhMf/aAAgBAgEBPxAV4OLjsHGp/8QAGhABAQEBAQEBAAAAAAAAAAAAAREhADFBkf/aAAgBAQABPxAXQ7hYCWFiwQCMt7ExV59jBIsQwfF5ksxDdLMoRBLwlxP1g/l+edA1ykpp5BAwAtZVUZfhpC73/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;startup_weekend2&quot;
        title=&quot;&quot;
        src=&quot;/static/8be827184d75035a8fd96b639fb4525c/109c0/startup_weekend2.jpg&quot;
        srcset=&quot;/static/8be827184d75035a8fd96b639fb4525c/d1f95/startup_weekend2.jpg 500w,
/static/8be827184d75035a8fd96b639fb4525c/dbdff/startup_weekend2.jpg 1000w,
/static/8be827184d75035a8fd96b639fb4525c/109c0/startup_weekend2.jpg 2000w,
/static/8be827184d75035a8fd96b639fb4525c/9a593/startup_weekend2.jpg 3000w,
/static/8be827184d75035a8fd96b639fb4525c/7f20e/startup_weekend2.jpg 3552w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Raggiungi i tuoi obiettivi, punto&lt;/h2&gt;
&lt;p&gt;Altra lezione che ho imparato a mie spese e che l’ho ricevuto come un calcio rotante sulle gengive. Appena entrato a Cloud Academy era tutto un mondo nuovo, avevo voglia di fare ed ero veramente carico. Uno dei primi compiti che mi era stato assegnato era l’automatizzazione della generazione dei file statici lato frontend. Mentre lo stavo facendo ho avuto la brillante idea di fare anche una miglioria extra che purtroppo ora non mi ricordo. Ero andato dal mio superiore per mostrargli i miei progressi: dopo aver detto a che punto ero arrivato, gli spiego anche la mia miglioria e cosa potevamo fare in più grazie ad essa. Mentre spiegavo mi ha interrotto bruscamente con un “Ma a me che ca@@o me ne frega?“… Imbarazzo totale, 5 secondi di silenzio… Tutto quello che sono riuscito a dire è stato un “Ah…“.&lt;/p&gt;
&lt;p&gt;Io ero abituato a &lt;a href=&quot;http://wavein.ch/&quot;&gt;wavein.ch&lt;/a&gt; ad avere molto più margine di manovra, ma semplicemente perchè eravamo più piccoli e io ero quasi capo di me stesso. Quindi tutto quello che facevo bene o male andava nella direzione che reputavo giusta. Ma in una startup si hanno dei task “ben definiti”. Se si hanno dei task assegnati bisogna fare quelli e fare il minimo per raggiungere quell’obiettivo. Tutto il resto non è visto di buon occhio, viene visto come tempo perso. Ricorda che &lt;strong&gt;il tempo è la risorsa più scarsa in una startup&lt;/strong&gt;. Quindi occhio con le funzionalità non richieste, anche se per te possono essere un grande miglioramento, per altri potrebbe non interessare “un ca@@o di niente”.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/db724ec2f922c79e4a823db6a6417b26/b46c2/Google.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAYCBAf/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQT/2gAMAwEAAhADEAAAAcAaWmeYLhRI/wD/xAAaEAACAwEBAAAAAAAAAAAAAAACBAEDBQAT/9oACAEBAAEFApg7CyMCx6uUfQF2rl50Nh1/iM6+/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARAv/aAAgBAwEBPwHkE2wv/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAECAxIxUf/aAAgBAgEBPwFWp6M5dP/EACAQAAIBBAIDAQAAAAAAAAAAAAECEQADEiETYSIxMrH/2gAIAQEABj8CgKfHqaYFN3DCKPcikxW0sDE8yZEwT3T3LbKLj/TFZJ3P7S897IqZEKBWMjXQr//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExUUH/2gAIAQEAAT8hbWOG6GNTamUybxzsFDqKCxXwUBTnE1AlTA71wMr4rCALvRGAAaW3t8n/2gAMAwEAAgADAAAAEMQ//8QAGBEAAgMAAAAAAAAAAAAAAAAAAGEBESH/2gAIAQMBAT8Q3ioY8//EABcRAQADAAAAAAAAAAAAAAAAAAEAESH/2gAIAQIBAT8QHtbFXBU//8QAGRABAQEBAQEAAAAAAAAAAAAAAREhAEEx/9oACAEBAAE/EGPko3IIge2V5nTnzjFB8oIfToLVQhGwwAAVft4/QLSrUqsTw5wMcAESBaZvHWphTUtUur3/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Google&quot;
        title=&quot;&quot;
        src=&quot;/static/db724ec2f922c79e4a823db6a6417b26/b46c2/Google.jpg&quot;
        srcset=&quot;/static/db724ec2f922c79e4a823db6a6417b26/d1f95/Google.jpg 500w,
/static/db724ec2f922c79e4a823db6a6417b26/dbdff/Google.jpg 1000w,
/static/db724ec2f922c79e4a823db6a6417b26/b46c2/Google.jpg 1600w&quot;
        sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;La startup non è una famiglia&lt;/h2&gt;
&lt;p&gt;La startup non è una famiglia. Bisogna tenerlo bene in mente. Ci piace la &lt;strong&gt;meritocrazia&lt;/strong&gt;, la vogliamo ovunque, ma dobbiamo anche essere in grado di accettare il rovescio della medaglia.&lt;/p&gt;
&lt;p&gt;Ora spiego cosa è per me un rapporto lavorativo, nella versione più meritocratica e cinica possibile: io vengo stipendiato per offrire un determinato servizio all’azienda. Tramite il mio servizio, l’azienda acquista del valore. Se il valore generato dal mio servizio è più alto rispetto al mio stipendio, l’azienda ha tutti gli interessi a mantenermi. Più questo delta è alto più l’azienda “mi vuole bene”, se questo delta è troppo marcato io posso chiedere un aumento e l’azienda dovrebbe riconoscermelo. Se non me lo da, ho tutto il diritto di guardarmi in giro per vedere se qualcun’altro riconosce il mio valore.
Se invece il delta è negativo significa che all’azienda non gli conviene più darmi lo stipendio e quindi ha tutto il diritto di lasciarmi a casa. C’è infine un’ultima opzione: l’azienda non ha più fondi, quindi comincia a licenziare le persone che hanno un delta meno marcato, ossia sono quelli che generano meno valore all’azienda.&lt;/p&gt;
&lt;p&gt;Usando questa versione pulita pulita, meritocratica, cinica quanto vuoi, non si può rimanere “scottati” da un possibile licenziamento. Son cose puramente logiche e razionali.&lt;/p&gt;
&lt;p&gt;Però noi non siamo delle macchine e quindi ci sono un sacco di altre variabili in gioco che possono colpire a fondo la sensibilità delle persone: va bene tutta sta storia del delta, ma è meglio licenziare una persona giovane senza figli a carico oppure licenziare una persona con famiglia e 3 figli anche se mi genera meno valore all’azienda? Meglio continuare a lavorare per l’azienda in cui lavoro anche se mi pagano poco, dove mi sono fatto un sacco di amici e mi ci trovo bene oppure cambio lavoro e vado dove mi pagano di più?&lt;/p&gt;
&lt;p&gt;Ho conosciuto persone che hanno vissuto malissimo il licenziamento perchè si sentivano “traditi” dall’azienda. Ma secondo me c’è poco da arrabbiarsi: a nessuno piace licenziare persone, la scelta su chi poi bisogna licenziare penso sia una cosa che angoscerebbe chiunque.&lt;/p&gt;
&lt;p&gt;Io ho vissuto sulla mia pelle cosa vuol dire essere licenziati dall’oggi al domani. Ciononostante sono rimasto in ottimi rapporti con chi mi ha licenziato perchè, essendo in una startup, sapevo benissimo che i soldi non crescono sugli alberi: ho capito le reali motivazioni e quindi sono riuscito efficacemente a dividere il &lt;strong&gt;rapporto lavorativo dall’amicizia&lt;/strong&gt;. &lt;strong&gt;Sono due cose che insieme coesistono, ma non sono certo la stessa cosa&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Con questo non sto dicendo che non si possono fare amici al lavoro. Anzi al lavoro si conoscono persone stupende e nascono delle amicizie che vanno avanti anni anche fuori dal lavoro. Sto solo dicendo che &lt;strong&gt;io non ho un posto di lavoro perché sono amico di qualcuno, ma perché sto generando valore all’azienda&lt;/strong&gt; ed essa è in grado di riconoscermi questo valore generato. Se si tiene in mente questo aspetto secondo me è più facile accettare un licenziamento.&lt;/p&gt;
&lt;h2&gt;Non esasperare l’ambiente lavorativo&lt;/h2&gt;
&lt;p&gt;“Possibile Natali che tu non ti arrabbi mai?“. In realtà mi arrabbio anche io, ma semplicemente cerco di non mostrarlo. Passiamo una buona parte della giornata al lavoro e quindi è importante che manteniamo l’ambiente il più calmo possibile, anche se l’incazzatura è sempre dietro l’angolo. In questi anni ho imparato fondamentalmente queste due cose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Arrabbiarsi è inutile&lt;/strong&gt;. Purtroppo capita di vedere persone che pretendono di aver ragione solamente urlando o mostrandosi visibilmente irritati. La cosa importante è mantenere comunque la calma, attendere qualche secondo prima di rispondere e, se proprio la situazione non si calma, è meglio concludere la conversazione e rinviarla quando i toni sono più calmi… Anche perchè il problema non si risolve in queste situazioni.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Con la forza non si ottiene niente&lt;/strong&gt;: nessuno ti farà un favore/task sotto costrizione, bisogna motivare le persone, non obbligarle. Ho avuto la fortuna di vedere tre tipologie di leadership: chi ti costringe, chi ti “minaccia” e chi invece ti motiva a farle. I risultati migliori ovviamente di ottengono con l’ultima. Esasperare l’ambiente lavorativo per ottenere qualcosa non è mai una soluzione, magari può funzionare nel breve termine, ma nel lungo periodo può solo far nascere un problema ben più grave: far schizzare il &lt;a href=&quot;https://it.wikipedia.org/wiki/Ricambio_del_personale&quot;&gt;turnover&lt;/a&gt; alle stelle. Il problema è che costringere o minacciare una persona è semplice, motivare non lo è affatto. Ed è per questo che è importante scegliere bene i vari leader in azienda… Non tutti sono in grado di farlo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/aefe50c62d90971bccaf3c30d9bfea23/ping-pong2.gif&quot; alt=&quot;Ping Pong&quot;&gt;&lt;/p&gt;
&lt;h2&gt;La formazione personale è fondamentale&lt;/h2&gt;
&lt;p&gt;Pensavi che una volta finito gli studi potessi dire addio allo studio? Beh, nell’informatica è solo l’inizio! &lt;strong&gt;L’IT è una continua evoluzione, se si rimane fermi anche solo due anni si è tagliati automaticamente fuori&lt;/strong&gt;. Per molti questa è una condanna, ma per me è la parte più interessante del lavoro. Non si smette mai di imparare e si può vedere in modo tangibile una continua evoluzione nel proprio lavoro e in noi stessi… Il lavoro ripetitivo alla fine annoia!
Per formarsi c’è solo l’imbarazzo della scelta: dalle piattaforme e-learning, piccoli progetti, ai meetup organizzati da gente appassionata che veramente ci mette l’anima in ciò che fa.&lt;/p&gt;
&lt;h2&gt;Conclusioni&lt;/h2&gt;
&lt;p&gt;Spero che questo post possa essere d’aiuto a chi ha paura di iniziare una carriera lavorativa, specialmente in una startup. È sicuramente una buona palestra per apprendere velocemente, ma sono certo che può un po’ spaventare a chi non ci ha mai lavorato.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/da235cf588c0a724732788ed44947686/b46c2/spritz.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgADBf/EABYBAQEBAAAAAAAAAAAAAAAAAAQCA//aAAwDAQACEAMQAAAB6QVkCGt1a1Y//8QAGhAAAgMBAQAAAAAAAAAAAAAAAgQBAwUABv/aAAgBAQABBQJhikeq9Cu85FYRB5kZQV4i7DxwRF//xAAYEQADAQEAAAAAAAAAAAAAAAAAAQIRIf/aAAgBAwEBPwFRbWwtR0//xAAYEQACAwAAAAAAAAAAAAAAAAAAAREiMv/aAAgBAgEBPwGq0yEf/8QAIhAAAgEDAwUBAAAAAAAAAAAAAQIRAAMSITEyBCJBQlFx/9oACAEBAAY/Ame0tzAeNzQ6cO1gzHesa/K9n/KTm6CSXtNjFC9ck5uWDnd/hrnjGkRX/8QAHhAAAgMAAQUAAAAAAAAAAAAAAREAITFRQWFxgaH/2gAIAQEAAT8hEGYGF86Ww4RKLRyzy/sBNLZ6LSijc2Jks0S+ajm00GTex74hIIh//9oADAMBAAIAAwAAABBQP//EABkRAAIDAQAAAAAAAAAAAAAAAAAhETFBwf/aAAgBAwEBPxB+opt8rSR//8QAFhEBAQEAAAAAAAAAAAAAAAAAAREQ/9oACAECAQE/EFaScf/EABwQAQEAAwEAAwAAAAAAAAAAAAERACFBMVFhcf/aAAgBAQABPxBpt2l4UAl/EK4gROqMiejxzYN3QklAFaElU2I4kuxOPKWhVQwvccB00q0nQ+kb8xqgPoj95ruf/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Aperitivo d&amp;#39;addio a Cloud Academy&quot;
        title=&quot;&quot;
        src=&quot;/static/da235cf588c0a724732788ed44947686/b46c2/spritz.jpg&quot;
        srcset=&quot;/static/da235cf588c0a724732788ed44947686/d1f95/spritz.jpg 500w,
/static/da235cf588c0a724732788ed44947686/dbdff/spritz.jpg 1000w,
/static/da235cf588c0a724732788ed44947686/b46c2/spritz.jpg 1600w&quot;
        sizes=&quot;(max-width: 1600px) 100vw, 1600px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Se siete giovani non vi posso consigliare altro che lavorare in questi ambienti: ci si diverte, si conoscono persone veramente stupende che condividono la tua stessa passione e non ci si annoia mai!&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come risolvere le regressioni del software usando git bisect]]></title><description><![CDATA[Avete aggiunto una funzionalità al software ed è andata in produzione. Dopo qualche settimana il Product Owner vi comunica che non funziona…]]></description><link>https://www.mattianatali.it/it/come-risolvere-le-regressioni-del-software-usando-git-bisect/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-risolvere-le-regressioni-del-software-usando-git-bisect/</guid><pubDate>Mon, 15 Jan 2018 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Avete aggiunto una funzionalità al software ed è andata in produzione. Dopo qualche settimana il Product Owner vi comunica che non funziona più. Don’t panic. Usando solamente &lt;a href=&quot;https://it.wikipedia.org/wiki/Git_(software)&quot;&gt;Git&lt;/a&gt; si può risolvere tutto in pochi minuti!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A tutti può capitare una &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_regression&quot;&gt;regressione del software&lt;/a&gt;&lt;/strong&gt; e non è mai piacevole. Ho visto molti sviluppatori che, in un caso come questo, cominciano a tentare di riprodurre il bug in locale e a rileggere furiosamente il codice nella speranza di risolvere il bug. Se nel codice ci lavorano molte mani, &lt;strong&gt;la ricerca del bug può essere tutt’altro che semplice&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Usando quest’approccio naive &lt;strong&gt;non stiamo sfruttando tutte le nostre informazioni in possesso&lt;/strong&gt;: noi &lt;em&gt;siamo certi&lt;/em&gt; che la funzionalità &lt;em&gt;prima&lt;/em&gt; funzionava correttamente. Quindi è successo qualcosa nel mentre che ha sicuramente rotto la nostra parte di codice. Quindi perchè cercare questa modifica manualmente quando Git può fare il lavoro sporco per noi in pochissimi passaggi? &lt;strong&gt;Git può dirci puntualmente &lt;em&gt;cosa&lt;/em&gt; è successo, &lt;em&gt;quando&lt;/em&gt;, &lt;em&gt;chi&lt;/em&gt; è stato e &lt;em&gt;perchè&lt;/em&gt;&lt;/strong&gt; (se lo sviluppatore che ha introdotto il bug ha scritto un testo decente nel commit).&lt;/p&gt;
&lt;h2&gt;git bisect&lt;/h2&gt;
&lt;p&gt;Ebbene sì, Git offre proprio questa funzionalità. Non tutti la sfruttano ma in casi come questi è potentissima. È il comando &lt;strong&gt;&lt;a href=&quot;https://git-scm.com/docs/git-bisect&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git bisect&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Per farla breve, si definiscono due commit: il primo è un commit “buggato”, ossia che presenta il problema, il secondo è un commit sano, dove il problema non esisteva ancora. Git poi mostra un commit che sta nel mezzo e sta a noi a dire a Git se funziona o no. Git a questo punto mostra un altro commit che sta sempre nel mezzo tra il commit buggato e quello sano. Si va avanti così finchè Git ci mostra il commit che ha introdotto il bug.&lt;/p&gt;
&lt;p&gt;Sembra un procedimento lunghissimo ma non lo è: infatti, ad ogni nostra verifica, dimezziamo il numero di commit tra quello buono e quello buggato. Per esempio se abbiamo 1000 commit che separano i nostri due commit di riferimento, noi troviamo quello che ha introdotto il problema in log_2(1000) ~ 10 passi!&lt;/p&gt;
&lt;h2&gt;Esempio pratico&lt;/h2&gt;
&lt;p&gt;Come esempio ho usato un &lt;a href=&quot;http://8ball.mattianatali.it&quot;&gt;mio piccolo progetto&lt;/a&gt; che avevo creato per imparare un po’ di concetti su &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;. Supponiamo che vogliamo sapere chi ha aggiunto l’effetto particellare alla pagina.
Durante il procedimento di &lt;code class=&quot;language-text&quot;&gt;git bisect&lt;/code&gt; etichettiamo come &lt;code class=&quot;language-text&quot;&gt;bad&lt;/code&gt; tutte le volte che il progetto ha la cartella &lt;code class=&quot;language-text&quot;&gt;src/components/atoms/ParticlesBackground&lt;/code&gt;. Mentre tutti i commit che non la possiedono saranno &lt;code class=&quot;language-text&quot;&gt;good&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7d7e73440cd4bd99d1d8b6a6816632af/3f9ef/git-bisect-app-preview.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAACfElEQVR42qWRW08TQRTH94F2aSttQEvLXrvbrfRCoe2CtyAWISbGFAiklhDCJfoggaAxfgsfjJGRaIypEAqin8MXH230W5hIYkLZsMcz022hkPDiJr+cnf855z9nZjhTNwOjI9lX+cnRzcnSw40HM8ukUFom08USmZ2bJU/mCmS+OEGmpmfIzPwimSrNkom5x6RQXCC3794nhXtjG/mxsc3hfP6laZpXuFumGV1eWjhcefEc3rx9bW+++wDkfRk+7uxDeXsP9nYrsP9lHz6Vy7BT2YXtymfYqnyFcnkLnq2tw9rqqr3ydB0Wlx4djI+PJ7igP2ik5czflDJ4nBL7j/rkjJUQMlZczFnxnpyVlHJWnzpoJYUBq0/MWClcJ8Ws1S9l2TopZo76ZdNOS9nfSpeS5Pyc3+hxqTXRpYHg0mzBHQHRrSERhuBC2lSmCY11Kzb2AXocdLnDaMgHDdmr1xSvAbI3aiOg+GJA16oTW6AaUs9FKTbr9egnhpJHr8meKIpoiFHgcTpeY5EitesgtmuMhkbzjR7FY2CNdtbQqBvibteUERiSh1m8qeUhcXkArqsjcCNyh+ksSsNso6ahRzsInzZUGoa4q94RB90fh6g/AUYgBfGuAUgFcxALJJmuo05rTk510YRYRHduoF3qhXT3EKRDQ6B6YziJk/PoFxlqNefSbaeoCdXZ/Z3c2VmcI7c+ymH9paLHzpR16Av6DLtFO8+xM+GfpiE+fY0eB7GdeIqroPl62dHp//l8zI6gjsb1CTu5TiXEK99DvPwzzCs/kOppJG+kqvmNqtph4L9ePZunPdj7K+SWvwX4bp3Drw0JIj1I+D+gHm3/AIIZVsO7kMkTAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;git-bisect-app-preview&quot;
        title=&quot;&quot;
        src=&quot;/static/7d7e73440cd4bd99d1d8b6a6816632af/9fabd/git-bisect-app-preview.png&quot;
        srcset=&quot;/static/7d7e73440cd4bd99d1d8b6a6816632af/c6e3d/git-bisect-app-preview.png 500w,
/static/7d7e73440cd4bd99d1d8b6a6816632af/da8b6/git-bisect-app-preview.png 1000w,
/static/7d7e73440cd4bd99d1d8b6a6816632af/9fabd/git-bisect-app-preview.png 2000w,
/static/7d7e73440cd4bd99d1d8b6a6816632af/3f9ef/git-bisect-app-preview.png 2310w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Iniziamo! Per prima cosa cloniamo il progetto ed entriamoci dentro con il terminale.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git clone https://github.com/matitalatina/8ball
cd 8ball&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora iniziamo la ricerca&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git bisect start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Avviando il programma notiamo che il branch &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; ha la cartella &lt;code class=&quot;language-text&quot;&gt;src/components/atoms/ParticlesBackground&lt;/code&gt;. Quindi etichettiamo il commit come &lt;code class=&quot;language-text&quot;&gt;bad&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git bisect bad&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Poi torniamo indietro nella storia di Git abbastanza da non trovare più la cartella in questione. Nel nostro caso tornare indietro di 10 commit è sufficiente.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git checkout HEAD~10&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ok! Ora la cartella è sparita! Quindi possiamo etichettarlo come &lt;code class=&quot;language-text&quot;&gt;good&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git bisect good&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora Git cambierà commit e si porterà esattamente in un punto a metà tra i commit etichettati come &lt;code class=&quot;language-text&quot;&gt;good&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;bad&lt;/code&gt;. Ve lo notifica con la seguente dicitura.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Bisecting: 5 revisions left to test after this (roughly 3 steps)
[5e2a30980acb38d3d3958359c56fd0a8d0325136] Improve particles system&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Andate avanti a scrivere &lt;code class=&quot;language-text&quot;&gt;git bisect good&lt;/code&gt; o &lt;code class=&quot;language-text&quot;&gt;git bisect bad&lt;/code&gt; finchè avrete analizzato circa 4 passi.&lt;/p&gt;
&lt;p&gt;Nel nostro caso specifico sarà:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git bisect bad
git bisect good
git bisect bad
git bisect good&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Alla fine, quando Git ha individuato il commit che stavamo cercando, ve lo comunica in questo modo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;b7b5d042a8cba637c56cc52401dcd61ec785d9b4 is the first bad commit
commit b7b5d042a8cba637c56cc52401dcd61ec785d9b4
Author: Mattia Natali &amp;lt;***@***.***&gt;
Date:   Mon Nov 6 22:24:32 2017 +0100

    Add particles

:100644 100644 d93738e6743c2460699030cfe8df000e1bc7ecd7 570e0890ece45c8d4ef6640a3ea7a386fd63f7da M	package-lock.json
:100644 100644 994aebed4cf0ebfb0dd56e2bebf2a6e411e44e1c 0dc0290897d7082dadda14595739b80b07766603 M	package.json
:040000 040000 9f912726175c5d9794d00deffdb422136555846f a934e7f36f14c1ec38058bfbfbf403d3fb8043b3 M	src&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/873eb03183270181634c4bf64865a34d/736f8/git-bisect-terminal.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 88.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAAsTAAALEwEAmpwYAAADHklEQVR42pWTXU/aYBTHCyhCVxD7BqW0pUBpC8KWfQfvvSG7WHaDH8ChMjche7ndy5fYt9j94p2JMSFebA5xQtunFeIScdmF3WmdmzITtckv53mann//5zznwYyPn+6Zu58f7xl7S47h1B2EAKfe3evWt7a26zvbO/XdTqfe6ezCuuPvDw4O6qPRcf0Y8L4djUZLw+HwyebmZhR7tLhY3Git/Hj+su0226/P1lptt9UGIK6vb7iNRsN9urzsLjdW3ZXGiru6Aqyuuatr62671XKba82zjRcb7rNmc7ywsCBjBBHWKI74FksyaIZmjVAiYcxSlJFKJY14PDbAMKx/A4eAAXSBPEZQhEaxxH6CY51EOmPRkmTPkqRFUZRFMwzCcdwMhoLm9PS0GQqFzGAwOIkBIKB3LkgQmijK+3JWdoqKYsmShPg0jzKZDBJEAUnZLMrKMqxFNDMzY0LSJJ47BPwTZFimy7Ksk0qlLDaZRCzEdDqNMoLgC6d53uLSHCII3LpRMIxh6tzcXJehGYciSZNhGIumaSsajVpRHLcikYgZDodNcGd5Zd/KYVqg91mRd1gpi0hwJOZyKAulilBmLBb7279rxK4XVHSxlysVh6JeRoKu22qlYlcARVFsr3dQsn84txYsaEJPUOQjvqgiLp9Hsqra5VLZE/R7GI/HrWAgcBeHQk/WC0cZEBRUFeU1zS6XzwU5jvMFL0oO/C88cSgw2GpF6uXKypBXNSSVSrYyP2+XIOZB0Dttnj93CT/3mejnVUGOojRdk3rVinwEQKlZ++EDxfHWhTxvkxRp4SAyNTV1ZaAvnEI0gEsOw2E1Go10E4lZG+bM9BJh78cJF7frITxqoaB8qVbvm8VC8TCfL/R1vTSAkiHqfRifPvQT9uWBt4f3A5iAQS6X6+MR/LsgCIckSQ7A9VfQynkOS7zMHPEF6RcjZce0IJzq1epPnufHLMOMGQ+W9WMqmRrDjRrDQY3hro9hPk+gpycQT0FsCCiewyTwCvgAvAXe3YH3f3K83DcA6wkGXMwN1Gq1UK2GhWoY4K9vBnIvE/D4DTmfmHFHtvTzAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;git-bisect-terminal&quot;
        title=&quot;&quot;
        src=&quot;/static/873eb03183270181634c4bf64865a34d/9fabd/git-bisect-terminal.png&quot;
        srcset=&quot;/static/873eb03183270181634c4bf64865a34d/c6e3d/git-bisect-terminal.png 500w,
/static/873eb03183270181634c4bf64865a34d/da8b6/git-bisect-terminal.png 1000w,
/static/873eb03183270181634c4bf64865a34d/9fabd/git-bisect-terminal.png 2000w,
/static/873eb03183270181634c4bf64865a34d/736f8/git-bisect-terminal.png 2008w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Già il messaggio del commit ci fa intuire che Git ha fatto centro (“Add particles”)! Ma noi non ci fidiamo e allora vediamo effettivamente cosa è stato fatto in questo commit: prendiamo l’id del commit (&lt;code class=&quot;language-text&quot;&gt;b7b5d042a8cba637c56cc52401dcd61ec785d9b4&lt;/code&gt;) e scriviamo:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;git show b7b5d042a8cba637c56cc52401dcd61ec785d9b4&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;scorrendo il commit notiamo la parte&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;diff --git a/src/components/atoms/ParticlesBackground/index.js b/src/components/atoms/ParticlesBackground/index.js
new file mode 100644
index 0000000..748f50d
--- /dev/null
+++ b/src/components/atoms/ParticlesBackground/index.js
@@ -0,0 +1,129 @@
+import Particles from &apos;react-particles-js&apos;
+import styled from &apos;styled-components&apos;
+import React from &apos;react&apos;
+
+const Wrapper = styled.div`
+  pointer-events: none;
+  position: fixed;
+  top: 0;
+  bottom: 0;
+  left: 0;
+  right: 0;
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;che è proprio la parte che stavamo cercando! Quindi in definitiva ora sappiamo che Mattia Natali ha aggiunto questa parte il Lunedì 6 Novembre 2017 alle 22:24.&lt;/p&gt;
&lt;h2&gt;Conclusioni&lt;/h2&gt;
&lt;p&gt;Immaginate ora di farlo per un bug che vi sta facendo impazzire, è molto potente perchè vi indica esattamente chi è stato e cosa è stato cambiato. In questo modo potete chiedere chiarimenti all’autore del commit e sapere esattamente la modifica che ha creato il bug.&lt;/p&gt;
&lt;p&gt;Magari &lt;code class=&quot;language-text&quot;&gt;git bisect&lt;/code&gt; non vi servirà tutti i giorni, ma è giusto tenerlo a mente perchè è sicuro che &lt;strong&gt;prima o poi vi tornerà utile&lt;/strong&gt; e vi farà risparmiare un sacco di tempo.&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come essere produttivi con il terminale]]></title><description><![CDATA[Se state leggendo questo blog post immagino che siate più o meno nella mia stessa situazione. Siete uno sviluppatore e avete a disposizione…]]></description><link>https://www.mattianatali.it/it/come-essere-produttivi-con-il-terminale/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-essere-produttivi-con-il-terminale/</guid><pubDate>Fri, 06 Oct 2017 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Se state leggendo questo blog post immagino che siate più o meno nella mia stessa situazione. Siete uno sviluppatore e avete a disposizione 8 ore al giorno per lavorare: in questo lasso di tempo dovete revisionare il codice di altri, fare meeting, gestire le vostre milioni di issue e magari anche quelle di altri, aiutare chi vi chiede aiuto, pensare a come raggiungere i propri obiettivi e infine programmare quello che avete pensato.&lt;/p&gt;
&lt;p&gt;Fare tutte queste cose e rientrare nelle 8 ore giornaliere prefissate è difficile senza deludere le aspettative di nessuno. Quindi da bravi ingegneri/sviluppatori state cercando di ottimizzare qualsiasi cosa.&lt;/p&gt;
&lt;p&gt;In questo blog post vi spiegherò come ho cercato di ottimizzare il mio tempo passato davanti al terminale. Mi concentrerò soprattutto sul sistema operativo Mac, che è quello su cui lavoro attualmente.&lt;/p&gt;
&lt;p&gt;In questa guida non voglio spiegare come si utilizza il terminale. Quello per me è un prerequisito. Il mio fine è di condividere con voi tanti piccoli trucchetti che vi faranno risparmiare tempo nella vostra quotidianità lavorativa in modo tale da concentrarvi maggiormente sull’attività che effettivamente porta valore: la programmazione.&lt;/p&gt;
&lt;h1&gt;Le basi&lt;/h1&gt;
&lt;h2&gt;Velocizziamo il cursore&lt;/h2&gt;
&lt;p&gt;Iniziamo con una piccola ottimizzazione tanto semplice quanto efficace, ancora prima di aprire il terminale. Molte volte nel terminale o nel proprio IDE occorre spostare il cursore. Tenendo premuto le frecce direzionali il cursore si sposta finchè non rilasciamo il tasto. Bene, fin qui nulla di nuovo. La cosa esasperante è la lentezza con cui questo cursore si sposta! Molte persone che vedo, per fare veloce, cominciano a premere compulsivamente le frecce oppure semplicemente attendono secondi preziosi finchè il cursore si sposta nella posizione desiderata.&lt;/p&gt;
&lt;p&gt;Una semplice ottimizzazione che tutti dovrebbero fare è di &lt;strong&gt;diminuire il tempo in cui inizia la ripetizione del tasto e l’intervallo di tempo tra una ripetizione e l’altra&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Per farlo è molto semplice. Andiamo nel Mac in Settings -&gt; Keyboard -&gt; Tab Keyboard. Impostate &lt;em&gt;Key Repeat&lt;/em&gt; a &lt;em&gt;Fast&lt;/em&gt; e &lt;em&gt;Delay Until Repeat&lt;/em&gt; a &lt;em&gt;Short&lt;/em&gt;. Ora provate e la differenza sarà enorme. So che all’inizio sembra troppo veloce il cursore, ma poi ci si abitua e non si torna più indietro!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1560px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d99a1b807299a4cd3bbfd55e32796346/298f8/terminal-keyboard.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 88.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAAsTAAALEwEAmpwYAAACnklEQVR42r2Uy2rbQBSGQy9vkoUhAe9iyCskz9lFoYvsEm9aevFVjq27ZWlG0kiWZdlKsEubxJX194xTh9LWaaDQgY8jjeZ8mnM0aG+Phtt4u29ffjpmjB1xh9cGJq8pA6dmmsTArClNpaYoCt2bNWeDQ8/NzRrDEUe2Gx8bhtjf245h48NZPuaI4vEqTZIyT8JyEngl9xjBS9uyS8u0Sp/5P+ZYabmiHPJx6Y/nq/nyG/omO9v6ntmOc3F7t0KWTgovnuFV7wveqF8RT+eYTFMIEWE2myEQApN0inSaIRonmM5yJMmkuLm5hW0PL6RrIzQMvb5YLBCGYRG4HnodC+/fdeAoXcSmBp8xRIEP1lcw7LRgtRpwlQ5inyGgHJlrGEb9J6FRXyyXiLhXJMYAvjfEyNIwtG0IzjAxVIz1Aah/MA0Dhq7DoWdyLuSskLm/CZfLBUY8KDxNhdH4CK4NEOgqRrQTZpkIHRuh2kPiDAkbvtpHaJubqv64w88k1N2o6GsmtP4lBr0e+j0FhqbJ/iCIU6hOBJckzHURhQFEFO0ueStsK5doNptot9vodDqbqKkDKH0NTdWjNljwGEccx4gisXuHsmRGJXe7CrpSREhxq9UiKNK1TmXa1DvZRzqTUkLR2vFR5FcOgkKIkGIo3/yAEHInAgHN+76PwA/o+h7O+W5hsBEKPEZEfZNs73eW/FThr8ic/yI8v7q6kv1Z0YL136Ay11T2ejQarT2PrZb3B/v8Qeh5Xh008jwvrq+v8Rjz+RxpmmKaZZhSzLKskLnS8SCks/aafl13juNk9Nb8MejY5Kqm5Zqu56qq5pZlZpwHd01ybIUvDg4OqsRppVI5eQrVavXk8PBwQ6UiqZxKh3Rtf2HPiZf/iHTsfQeZUgCK/XbOXgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Impostazioni della tastiera, velocizziamo il cursore!&quot;
        title=&quot;&quot;
        src=&quot;/static/d99a1b807299a4cd3bbfd55e32796346/298f8/terminal-keyboard.png&quot;
        srcset=&quot;/static/d99a1b807299a4cd3bbfd55e32796346/c6e3d/terminal-keyboard.png 500w,
/static/d99a1b807299a4cd3bbfd55e32796346/da8b6/terminal-keyboard.png 1000w,
/static/d99a1b807299a4cd3bbfd55e32796346/298f8/terminal-keyboard.png 1560w&quot;
        sizes=&quot;(max-width: 1560px) 100vw, 1560px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Shortcuts&lt;/h2&gt;
&lt;p&gt;Questo consiglio vale in generale in ogni programma. &lt;strong&gt;Se utilizzate spesso la stessa funzione, cercate di imparare la sua scorciatoria da tastiera&lt;/strong&gt;. È sicuramente più veloce non staccare le dita dalla tastiera. Capita che la scorciatoia non possa esistere per la vostra funzione, fortunatamente il più delle volte nelle impostazioni si può creare. Vi consiglio di spendere un po’ del vostro tempo nella creazione di queste shortcuts: risparmierete tempo prezioso nel lungo periodo.&lt;/p&gt;
&lt;h2&gt;iTerm&lt;/h2&gt;
&lt;p&gt;Il terminale del Mac è buono, ma se volete ancora di più potete utilizzare &lt;a href=&quot;https://www.iterm2.com&quot;&gt;iTerm&lt;/a&gt;. Sostanzialmente è come il terminale nativo ma ha le seguenti funzionalità aggiuntive che aumenteranno la vostra produttività:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Ricerca migliorata&lt;/strong&gt;: premete &lt;code class=&quot;language-text&quot;&gt;cmd + F&lt;/code&gt; e aprite la modalità ricerca. Scrivete la parola chiave da cercare e subito vi evidenzierà la vostra parola nel terminale. Usando &lt;code class=&quot;language-text&quot;&gt;cmd + G&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;cmd + shift + G&lt;/code&gt; potete cercare la parola successiva o precedente.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Split panels&lt;/strong&gt;: è possibile suddividere sia verticalmente (&lt;code class=&quot;language-text&quot;&gt;cmd + D&lt;/code&gt;) che orizzontalmente (&lt;code class=&quot;language-text&quot;&gt;cmd + shift + D&lt;/code&gt;) la vista in modo da avere più terminali in un’unica pagina. Molto utile se avete più programmi avviati e avete bisogno di monitorarli contemporaneamente.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Profili personalizzabili&lt;/strong&gt;: con un profilo è possibile customizzare completamente il terminale come colori, shortcuts. Se passate tanto tempo collegati a macchine remote è facile confondersi tra le varie tab aperte. Un ottimo modo per evitare di fare pasticci è di utilizzare profili diversi per macchine con finalità diverse. Il nostro buon DevOp utilizza quotidianamente questa tecnica: per la macchina di produzione ha un bellissimo sfondo rosso vivo, così capisce chiaramente di stare attento e di non starci per troppo tempo. Per l’environment di stage è blu, il resto sfondo nero.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Se siete curiosi per iTerm vi consiglio di leggere le &lt;a href=&quot;https://www.iterm2.com/features.html&quot;&gt;altre feature degne di nota&lt;/a&gt;, ma soprattutto di provarlo!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Ordinaria amministrazione&lt;/h2&gt;
&lt;p&gt;Ecco qui una lista di trucchetti che utilizzo quotidianamente nel terminale. Ho scritto tutti quelli che mi vengono in mente, alcuni saranno ovvi per chi vive tutto il giorno davanti al terminale, altri spero di no ?.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;tab&lt;/code&gt;: Bastano poche lettere di ciò che volete scrivere, poi premete &lt;code class=&quot;language-text&quot;&gt;tab&lt;/code&gt; per l’autocompletamento. Questo è molto utile per esempio nella navigazione tra tab.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;sudo !!&lt;/code&gt;: quante volte avete scritto &lt;code class=&quot;language-text&quot;&gt;apt-get install&lt;/code&gt; senza dare i permessi di root? Molti, dopo aver letto il messaggio di errore premono &lt;code class=&quot;language-text&quot;&gt;freccia su&lt;/code&gt; e poi spostano in cursore all’inizio del comando e finalmente inseriscono la parola &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt; per diventare root… Quando tempo perso! Basta scrivere &lt;code class=&quot;language-text&quot;&gt;sudo !!&lt;/code&gt; e boom! Fatto. In sostanza &lt;code class=&quot;language-text&quot;&gt;!!&lt;/code&gt; viene sostituito con il comando precedente ed è proprio quello che volevamo.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt;: ritorna nella propria home. Perchè scrivere &lt;code class=&quot;language-text&quot;&gt;cd ~&lt;/code&gt; o peggio ancora &lt;code class=&quot;language-text&quot;&gt;cd ../../../../../&lt;/code&gt; per tornare alla home se basta &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;cd -&lt;/code&gt;: ritorna nella directory precedente. Molto simile è il comando &lt;code class=&quot;language-text&quot;&gt;git checkout -&lt;/code&gt;: fa il checkout del branch su cui lavoravamo in precedenza.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;lsof -i :&amp;lt;PORT&gt;&lt;/code&gt;: solo per Mac. Questo comando serve per identificare il programma che sta usando la porta &lt;code class=&quot;language-text&quot;&gt;&amp;lt;PORT&gt;&lt;/code&gt;. Molto utile quando un programma si blocca in background e voi avete bisogno disperatamente della porta libera. Una volta eseguito il programma vi basta prendere nota del PID del programma e poi &lt;code class=&quot;language-text&quot;&gt;kill &amp;lt;PID&gt;&lt;/code&gt;. Ora la porta è libera!&lt;/li&gt;
&lt;li&gt;Concatenare i comandi: perchè stare a fissare un comando che finisca per poi eseguire il prossimo? Usando &lt;code class=&quot;language-text&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;;&lt;/code&gt; è possibile concatenare più comandi. &lt;code class=&quot;language-text&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; esegue il secondo comando solo se il primo si è concluso correttamente, mentre &lt;code class=&quot;language-text&quot;&gt;;&lt;/code&gt; lo esegue a prescindere.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ctrl + c&lt;/code&gt;: serve per chiudere le applicazioni ma anche per cancellare velocemente quello che stiamo scrivendo.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ctrl + a&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;ctrl + e&lt;/code&gt;: porta rispettivamente all’inizio e alla fine il cursore nel comando che stiamo scrivendo.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ctrl+l&lt;/code&gt;: pulisce il terminale, molto più veloce rispetto a scrivere &lt;code class=&quot;language-text&quot;&gt;clear&lt;/code&gt;!&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;!$&lt;/code&gt;: riprende l’ultimo argomento del comando precedente. Molto utile in casi come questi
&lt;code class=&quot;language-text&quot;&gt;mkdir -p creo/una/nuova/cartella/ &amp;amp;&amp;amp; cd !$&lt;/code&gt;
Come avrete intuito sto creando una cartella, ed una volta creata ci entro senza dover scrivere tutto il path di nuovo.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;man &amp;lt;APPLICAZIONE&gt;&lt;/code&gt;: quante volte vi è capitato di non ricordarvi le opzioni di un comando e siete andati online a cercare la documentazione? Non serve andare online! Basta scrivere &lt;code class=&quot;language-text&quot;&gt;man&lt;/code&gt; seguito dall’applicazione e avrete tutta la documentazione a portata di mano senza googlare.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1840px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/fc94308f14fca2c26eca67849f0166bf/2b103/man-ifconfig.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 67.60000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAACdklEQVR42qVSS08TURSmL0qn82o7M8x0UmgJpTQlgiHdWAgr9nTDz9AFP4CNJhBjldKntLrQ3+LWjUuisbF07nRMk9IpRk2u51wEA8HUxJt8ueeee+53z3fOmRp9eL/28fO73f5wsOMOh8XBYHADnU6neHr6ie3M5wyKrusWhwiIB+ycn5/vwt3aFK5nTx6/bb2q0xfH1Z/l8hGtVCq0Ua/TeqNJK9UGrVaO6eHT57RUKtFqrUFr9SZtNpssrl6r0aNy+cfLk9f08PDgDSMUZbklSfLI5/N14dgLBAI9juMsQRCsUIgDhCz0I9DH8/z1+Te+AEaAE0ZomGZbicXcYDB4NjMzgw9IiOMIEBG0eZ4jXq8XSf4GTMS9JhRFsZ1OL10YhtFTFZXoukY0TSOxmEJUVSGmadqqptrRaJQocK8oCruPRCLEMHQi8PzZDUI0ljKZi3w+TzKZjL1+f72/vJztJ1NJW9d19jgej9uYLZTF8vv9lj/gt3x+nwXlsSD77m3CVmphYXxvddVKp9P9bDZr51ZW+rlcrj8/P2+LgkhQmsfj+TfJSLi4mB5vbG6SQqHgPChsOFtbW87c3JyNGU2o3501bKWSqXEikeipqmprs7O2pqkEasbqhrJQJu6I6enp23YX4MLnl4TQ2ZZpJsbJZLKHHcVOX3UbxofAh2y/7Dh/eeZhrHiBwBghuuAfw6d/JEuS5EI2Z2xkYO5wDpFkgtS7JYfD4TaMwDcgtQEOEDuwf5VE0YEPHEmWHYhhdhggwxmydDjwiaKEsZj1d1DVZoRQu22oxR6YDyHtR5MAsbd9+G4Parh9Jdm7v7/PgPZ/wIP4BQ+yPO/coPBhAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Esempio di &amp;quot;man ifconfig&amp;quot;&quot;
        title=&quot;&quot;
        src=&quot;/static/fc94308f14fca2c26eca67849f0166bf/2b103/man-ifconfig.png&quot;
        srcset=&quot;/static/fc94308f14fca2c26eca67849f0166bf/c6e3d/man-ifconfig.png 500w,
/static/fc94308f14fca2c26eca67849f0166bf/da8b6/man-ifconfig.png 1000w,
/static/fc94308f14fca2c26eca67849f0166bf/2b103/man-ifconfig.png 1840w&quot;
        sizes=&quot;(max-width: 1840px) 100vw, 1840px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;cmd + t&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;cmd + w&lt;/code&gt;: rispettivamente apre e chiude una nuova tab del terminale. Se ci fate caso questi comandi sono “universali”, ossia funzionano anche con le tab del browser, del finder, del vostro text editor preferito ecc.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;open .&lt;/code&gt;: apre nel Finder la cartella in cui ci troviamo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Navigazione tra i comandi ed auditing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;last&lt;/code&gt;: mostra chi è connesso con il terminale alla macchina o chi si è connesso in precedenza.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;w&lt;/code&gt;: molto simile a &lt;code class=&quot;language-text&quot;&gt;last&lt;/code&gt;. Mostra le persone correntemente connesse alla macchina.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;freccia su&lt;/code&gt;: inserisce il comando eseguito precedentemente. Molto utile per revisionare il comando o per modificarlo in caso di typo. Se si continua a premere &lt;code class=&quot;language-text&quot;&gt;freccia su&lt;/code&gt; si torna indietro nella history.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;history&lt;/code&gt;: mostra tutti i comandi eseguiti. Insieme al comando &lt;code class=&quot;language-text&quot;&gt;grep&lt;/code&gt; è molto facile ricercare un comando. Per esempio avevate avviato un’app utilizzando &lt;code class=&quot;language-text&quot;&gt;runserver&lt;/code&gt; ma non vi ricordate tutte le opzioni a memoria? Vi basterà scrivere un pezzo del comando, nel nostro caso scriviamo &lt;code class=&quot;language-text&quot;&gt;history | grep runserver&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ctrl + r &amp;lt;TEXT_SEARCH&gt;&lt;/code&gt;: si chiama &lt;em&gt;reverse-i-search&lt;/em&gt; e significa “cerca nel passato un comando simile a questo”. Insomma è come il comando precedente solo che è ancora più veloce. Per esempio possiamo premere &lt;code class=&quot;language-text&quot;&gt;ctrl + r&lt;/code&gt; e poi scrivere &lt;code class=&quot;language-text&quot;&gt;runserver&lt;/code&gt; per avere nel terminale il comando che stavamo cercando. Se il comando che stavate cercando non è l’ultimo ma uno precedente, continuate a premere &lt;code class=&quot;language-text&quot;&gt;ctrl + r&lt;/code&gt; finchè non ritrovate il comando desiderato!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Spingiamoci oltre!&lt;/h2&gt;
&lt;h3&gt;Fuck!&lt;/h3&gt;
&lt;p&gt;Capita a tutti di sbagliare a scrivere qualche comando: quando scriviamo un typo e vediamo che il terminale ci risponde picche la prima cosa che pensiamo è “fuck”. Con &lt;a href=&quot;https://github.com/nvbn/thefuck&quot;&gt;thefuck&lt;/a&gt; possiamo esternare la nostra rabbia in modo produttivo!
Questa app è tanto semplice quanto geniale. Se sbagliamo a scrivere un comando, ci basta scrivere &lt;code class=&quot;language-text&quot;&gt;fuck&lt;/code&gt; nel terminale, in questo modo questa app ci ripropone il comando precedente scritto correttamente. Vedetelo come un &lt;strong&gt;correttore automatico del terminale&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/nvbn/thefuck/master/example.gif&quot; alt=&quot;Funzionamento di thefuck&quot;&gt;&lt;/p&gt;
&lt;p&gt;L’installazione e molto semplice: avendo installato &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; ci basta scrivere&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;brew install thefuck
eval $(thefuck --alias)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Bene! Ora se sbagliate a scrivere qualche comando arrabbiatevi e scrivete &lt;code class=&quot;language-text&quot;&gt;fuck&lt;/code&gt; che sarete più produttivi!&lt;/p&gt;
&lt;h3&gt;Zsh&lt;/h3&gt;
&lt;p&gt;Spesso ci ritroviamo bash come shell installata di default. Se volete avere quella marcia in più vi consiglio di usare Zsh insieme al plugin Oh My Zsh! Questa combo vi permetterà di essere più produttivi per i seguenti motivi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Autocompletamento delle cartelle migliorato&lt;/strong&gt;: una migliore navigazione tra le scelte proposte.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autocompletamento per i programmi più utilizzati&lt;/strong&gt;: Git, Docker, npm, Django sono i plugin di Oh My Zsh che utilizzo, ma &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins&quot;&gt;ce ne sono molti altri&lt;/a&gt;!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/wiki/themes&quot;&gt;Temi completamente configurabili&lt;/a&gt;&lt;/strong&gt;: ci sono moltissimi temi pronti all’uso, sicuramente ne troverete uno che soddisferà i vostri gusti personali. Il mio preferito è &lt;code class=&quot;language-text&quot;&gt;eastwood&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maggiore integrazione con Git&lt;/strong&gt;: appena entriamo in una cartella che contiene un progetto versionato con Git, possiamo notare che viene mostrato il branch su cui siamo e anche un piccolo alert quando non abbiamo committato e pushato tutto il nostro codice. Grazie a questi piccoli aiuti risparmieremo molti &lt;code class=&quot;language-text&quot;&gt;git status&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ricerca di comandi precedenti migliorata&lt;/strong&gt;: scrivete solo l’inizio di un comando, poi premendo &lt;code class=&quot;language-text&quot;&gt;freccia su&lt;/code&gt; vi mostra il comando precedentemente utilizzato che inizia proprio nello stesso modo.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Installazione&lt;/h4&gt;
&lt;p&gt;Se volete installare Zsh con Oh My Zsh! questi sono i passi da seguire:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;brew install zsh zsh-completions
sh -c &quot;$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora riavviate la shell, per utilizzare Zsh vi basta scrivere &lt;code class=&quot;language-text&quot;&gt;zsh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Se volete che Zsh diventi la vostra shell di default allora scrivete&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;chsh -s $(which zsh)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Cambio del tema&lt;/h4&gt;
&lt;p&gt;I file di configurazione di Zsh si trovano nel file &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt;. Con il vostro editor preferito andate a modificare la variabile &lt;code class=&quot;language-text&quot;&gt;ZSH_THEME&lt;/code&gt;. Se non sapete quale tema scegliere, potete utilizzare la modalità &lt;code class=&quot;language-text&quot;&gt;random&lt;/code&gt;: così ogni volta che aprite una shell avrete un tema diverso. Quando ne individuate uno che vi piace, prendete il nome del tema che vi appare all’avvio e andate a scriverlo nella variabile sopra citata.&lt;/p&gt;
&lt;p&gt;Io, come ho già detto in precedenza, sto utilizzando &lt;code class=&quot;language-text&quot;&gt;eastwood&lt;/code&gt;. Ha dei colori molto rilassanti e non distrae troppo l’attenzione rispetto ad altri temi.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1994px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c85e45d8a3abf3a3a84349fa31500020/ee6e3/terminal-zsh-eastwood.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 67.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAACeklEQVR42p3QXUvbUBgH8Jy8tGlt0qaJL2mTFGsTq83wU9TRSkHn6mBfphfbx3C58W6fYK3Mu8GkaakMJsoolvUlSYerOMcwgntOmFPEDbbAjzw5nPPPn0O8rtZCx/bbl+1De6f7qfuq2+1aR0dHVqfdtprNptXpdAK2bVttWMPzwcFBsOfk5MQaDofb/X5/p9frvajVaiyhKEpyo1o5fvr82XVla+uytL7ul55sXlU2N6+q1aq/vrHhl8plf21tza9UKv7q6uplsVgM4BnWf5RL5evi4+KhLMsSAY8oSIn9GWVuHJfEPi8IAy6ZHPBJYRCLxfokSX5GCAXwDPvv6wEXvAPTQWDWyLQyxsJZdrngzefzY21xcSylUx7HcS7Lsm4oFHJJEjkQ6lAUdd8QnMLP9n8H6rrRKiwXJouG4S4vLY2z2XnP0HVP1TRPEAQ3HA7jBs4fDMEpuA3UNM0umOZkdnbWAR7DMA4O4riYi1v9JezhwFxOb+mGMcH1obpzE8JGwm4kSrkUzOS/BGYymZZpmmeqqjrpdNoTRdGlKRpaJlw+ybh0iHApJuA8YEiFiFOSuROYVhS78MicqJrqyKmUp6iqx/O8E41G4P5oF5HQkHoYQtAQQUN0J1DRtGY+n/8KdzlKpVK4pcPz3EiUxFGMj4wQTYygwYi64+abRMQAMr6A97eBafnjklnwV1ZWvum53Hdd1y9UVbtYmM9ecNGpc9hzTiF0juB9gyRQsA7OwCX4AGZwYFxO0BYdY/fi8Xh9OhHflURxVxDFhjItNSSWbbAkWY8zdINBqE6TqI7fUzRdh7PYG7AHtoGAA8lfgwzm/hM+m8RZPwGvDRZEMfFHBgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Tema Zsh Eastwood&quot;
        title=&quot;&quot;
        src=&quot;/static/c85e45d8a3abf3a3a84349fa31500020/ee6e3/terminal-zsh-eastwood.png&quot;
        srcset=&quot;/static/c85e45d8a3abf3a3a84349fa31500020/c6e3d/terminal-zsh-eastwood.png 500w,
/static/c85e45d8a3abf3a3a84349fa31500020/da8b6/terminal-zsh-eastwood.png 1000w,
/static/c85e45d8a3abf3a3a84349fa31500020/ee6e3/terminal-zsh-eastwood.png 1994w&quot;
        sizes=&quot;(max-width: 1994px) 100vw, 1994px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;Modifica dei plugin&lt;/h4&gt;
&lt;p&gt;Sempre nel file &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt; possiamo trovare la variabile &lt;code class=&quot;language-text&quot;&gt;plugins&lt;/code&gt;. I plugins potete vederli come dei miglioramenti nell’autocompletamento per delle applicazioni che utilizzate spesso nel terminale.&lt;/p&gt;
&lt;p&gt;Io attualmente uso questa configurazione.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;plugins=(django npm docker)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Vi ricordo di separare i plugin con lo spazio e non con la virgola. Ovviamente &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins&quot;&gt;Zsh offre molti altri plugins&lt;/a&gt;, sceglietene il minimo indispensabile perchè potrebbero rallentare l’avvio del terminale.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1798px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3d1120501d14bfa6878c51e4daf6d768/da9c1/terminal-zsh-docker-plugin.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 54%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAABr0lEQVR42qWPXUvCUBjHN20KmkynjZIN54ISb+pLdCNFjV4u6qIvUPRJ1HKbtJTqrq/RB6jQLgIjGBhp56QuJl6Vs+fIAomwogM/znNenh//h7q6GjBPN5dL94/X67Zlr1mtllI3TeXh7k6p1WqKCTVhtCbU63XFsiyl1+ut2ba90e12lwzDYKjNzd3p01LBPL84G2jGybtmHDuHuu7kNc05UlWnUCg4xWLR0eCczWb7hFwu18/n831d1/vlUumtXC4PVFU1M5nMNAVL3NrZqC6vrrQphmnyoohigoBmkknMxWIoGo0ijuOQz+drwt/veAJaQIW4hsJEQqpGIpGO1+ttyLKM5+fnMD81heBuCMuyn9Jnj8fzDD2jNIC2KxSGQkEQqhGO60xMMI2EJOGknMQSJJSgjsfjWBRFHIO0oVAI+f3+n4WQqsrzfIeBkVOpFE6n03hhYfFFnpUxy4ZRIDCJvkjGC4PBYAVkbTJyOBxGBJKGAPfumPTvhe6h7T42x6T5tfAWeAUQTdMvsA8ZrceA3N7bT2EI2AYOgD1g/4/sub07rouiAQ/g/SfEQX8AI/D1Nbzwa04AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Zsh Docker Plugin&quot;
        title=&quot;&quot;
        src=&quot;/static/3d1120501d14bfa6878c51e4daf6d768/da9c1/terminal-zsh-docker-plugin.png&quot;
        srcset=&quot;/static/3d1120501d14bfa6878c51e4daf6d768/c6e3d/terminal-zsh-docker-plugin.png 500w,
/static/3d1120501d14bfa6878c51e4daf6d768/da8b6/terminal-zsh-docker-plugin.png 1000w,
/static/3d1120501d14bfa6878c51e4daf6d768/da9c1/terminal-zsh-docker-plugin.png 1798w&quot;
        sizes=&quot;(max-width: 1798px) 100vw, 1798px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Alias, alias ovunque!&lt;/h3&gt;
&lt;p&gt;Nel terminale si possono aggiungere degli alias per velocizzare l’esecuzione di uno o più comandi. Se vi accorgete di &lt;strong&gt;scrivere sempre lo stesso comando&lt;/strong&gt; (o addirittura una serie di comandi) allora significa che è giunta l’ora di dover &lt;strong&gt;aggiungere un alias&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Per aggiungere un alias è semplice: bisogna aggiungerli nel file &lt;code class=&quot;language-text&quot;&gt;~/.bash_profile&lt;/code&gt; se usate bash oppure &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt; se usate Zsh.
La sintassi per aggiungerne uno è la seguente:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;alias &amp;lt;ALIAS&gt;=&quot;&amp;lt;COMMAND&gt;&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ecco qui alcuni miei alias come esempio:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;alias gbd=&quot;git branch | grep -v &apos;*&apos; | xargs git branch -D&quot;&lt;/code&gt;: eseguendo &lt;code class=&quot;language-text&quot;&gt;gbd&lt;/code&gt; (Git Branch Delete) verranno cancellati tutti i branch locali di Git del progetto contenuto nella cartella. Avviatelo solo se siete sicuri di quello che fate!&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;alias pycc=&apos;find . -name &quot;*.pyc&quot; -exec rm -f {} \;&apos;&lt;/code&gt;: eseguendo &lt;code class=&quot;language-text&quot;&gt;pycc&lt;/code&gt; (pyc clean) cancellerete ricorsivamente tutti i file compilati python presenti nella cartella. Molto utile se si fa refactoring in Python e abbiamo il timore che i file compilati non rispettino più il codice sorgente.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;alias yda=&apos;youtube-dl -x --audio-format m4a --audio-quality 160k&apos;&lt;/code&gt;: eseguendo &lt;code class=&quot;language-text&quot;&gt;yda &amp;lt;YOUTUBE_URL&gt;&lt;/code&gt; (YouTube Download Audio) scaricherete il file audio di un video di YouTube. Questo comando funziona solo se avete seguito la mia guida su &lt;a href=&quot;/it/come-scaricare-i-video-da-youtube-con-il-terminale/&quot;&gt;come scaricare un video da YouTube&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;alias ddev=&apos;docker-compose -f &amp;lt;ABSOLUTE_PATH_DOCKER_YAML_FILE&gt;&apos;&lt;/code&gt;: eseguendo &lt;code class=&quot;language-text&quot;&gt;ddev &amp;lt;DOCKER_COMPOSE_COMMAND&gt;&lt;/code&gt; (Docker dev) potete impartire qualsiasi al vostro Docker Compose senza preoccuparvi della cartella in cui vi trovate. Senza questo comando ero sempre costretto ad andare nella cartella del mio progetto Docker Compose &lt;code class=&quot;language-text&quot;&gt;cd &amp;lt;PATH_TO_DOCKER_COMPOSE_PROJECT&gt;&lt;/code&gt; e poi scrivere &lt;code class=&quot;language-text&quot;&gt;docker-compose -f &amp;lt;DOCKER_YAML_FILE&gt; &amp;lt;DOCKER_COMPOSE_COMMAND&gt;&lt;/code&gt;… Tutto tempo buttato!&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;alias c&amp;lt;PROJECT_NAME&gt;=&apos;cd &amp;lt;PROJECT_NAME_ABSOLUTE_PATH&gt;&apos;&lt;/code&gt;: se avete un progetto su cui ci lavorate quotidianamente vi consiglio di creare un alias per raggiungerlo velocemente. Io come convenzione utilizzo la lettera &lt;code class=&quot;language-text&quot;&gt;c&lt;/code&gt; iniziale che ricorda il comando &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt; e poi il nome del progetto.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Git&lt;/h4&gt;
&lt;p&gt;Anche &lt;strong&gt;Git supporta un suo meccanismo di alias interno&lt;/strong&gt;. Aprite o create il file &lt;code class=&quot;language-text&quot;&gt;~/.gitconfig&lt;/code&gt;. Al suo interno aggiungiamo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[alias]
    st = status -sbu
    lg = log --color --graph --pretty=format:&apos;%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&amp;lt;%an&gt;%Creset&apos; --abbrev-commit&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Come si può intuire abbiamo aggiunto la sezione alias e abbiamo aggiunto due nuovi alias git.
Una volta riavvito il terminale possiamo usare:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;git st&lt;/code&gt;: una versione modificata di &lt;code class=&quot;language-text&quot;&gt;git status&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;git lg&lt;/code&gt;: mostra l’albero dei commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ovviamente questi sono due miei comandi ma nessuno vi vieta di crearne dei vostri!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1994px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e18407d372adf5c005a88f7034128c19/ee6e3/terminal-gitst.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 67.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC8klEQVR42n2Ry27bRhSGyRnOhXeRlCiRoimpkgIDzlu4BWI4kiIbTpCn8aZ9i0Sb7PoCbVF02wvsADEMFCkUGW5DmTND1HYrddFIQDpsLs4iCIEPPHOI/xvOGeXrg0P8/On3Xz2bPnvy4sXvj2ez6WQ6nU7OZmeTs7PzyUzWp6enk5OTk8lM9s7Pz9/0Z7PJfD6fXFxcPMqy7Insf3l4eEgVJ0n88e7ub/eHg9d747uv9se764O9nfXe3p31aLS9Ho521vv7w/VwuLMa3v18dW/4xWo02F4NdrdX43t3VvcPxv8+ePDw9WAweh5FUVWRT0AR/NmjtHBc+tI0YGab2pwSMCdEyTBWM0OuyzcESqZBNcOEZpqGXkIIM4TQHwAAIT0/Smql0I9t8nSz4v61uXVb9Pv9otfrFp1uWnzW7Rbd/mbRbrdFs1kXft0UYTMUzVa3cKquoBbitusz0/GuIYK/vBd6BB+nUL3eSBK2tXW76PV7RdppiqQdi06vXzTTjgjrkQhqrvCqHq+GsTAqhtCowqnlMN3yruVf3ggNSo5DoFw1fI9ttFoiTVsijAJu+kBU6p4IN3pFJQg5xoSVaJrGgKYyKNEwzSVXiqreCCExjpCqXlKk5bphyBD+H53q3DAsicEppUzCdUMva65hwDWicqJbOdHNK/VDIcXkyIbg0rbtXMIdx+W6RTiiKsc6kceypIBwADQmg0xmPuRCcil5K3Qcv4rRcQ3DK3lcFsexaEQRD+Oq8Gqm8Oq+JBCuXxW63AgiwAAEDCLMVAA+InxzKUcNDVx20jTv37rFu90eT9KYBbHF60mDJe1NHiUtRnWUExPkum3lhlNhiOAcQDiHEP0pPT+9EwaIGr96QHkV2PYibjaXYRguPd9dOj5dBmF1WYvTf5yKtzQNc2Ga1kLOcAGxukAULKlp/y1ZyVGcSldYCl1Vo49l4wdZfyP59hN89xHKTJl9JPFKIXhbRPI2GzcoDUXybi2/f4qoHF3p+g9Achr1bwRSngAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Comando &amp;quot;git st&amp;quot;&quot;
        title=&quot;&quot;
        src=&quot;/static/e18407d372adf5c005a88f7034128c19/ee6e3/terminal-gitst.png&quot;
        srcset=&quot;/static/e18407d372adf5c005a88f7034128c19/c6e3d/terminal-gitst.png 500w,
/static/e18407d372adf5c005a88f7034128c19/da8b6/terminal-gitst.png 1000w,
/static/e18407d372adf5c005a88f7034128c19/ee6e3/terminal-gitst.png 1994w&quot;
        sizes=&quot;(max-width: 1994px) 100vw, 1994px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;SSH&lt;/h4&gt;
&lt;p&gt;Anche l’accesso ad una macchina remota può essere velocizzato. Immagino che le macchine a cui vi connettete da remoto siano sempre le stesse, ed ogni volta scrivere nel temrinale &lt;code class=&quot;language-text&quot;&gt;ssh &amp;lt;USERNAME&gt;@&amp;lt;REMOTE_ADDRESS&gt; -i &amp;lt;PRIVATE_KEY_PATH&gt;&lt;/code&gt; è lungo, tedioso e difficile da ricordare. È tutta un’altra storia se noi potessimo connetterci semplicemente scrivendo &lt;code class=&quot;language-text&quot;&gt;ssh &amp;lt;ALIAS&gt;&lt;/code&gt; dove &lt;code class=&quot;language-text&quot;&gt;&amp;lt;ALIAS&gt;&lt;/code&gt; è il nome che noi abbiamo dato alla macchina remota. Tutto questo è possibile grazie al file di configurazione &lt;code class=&quot;language-text&quot;&gt;~/.ssh/config&lt;/code&gt;. Se il file non è presente, potete crearlo scrivendo &lt;code class=&quot;language-text&quot;&gt;touch ~/.ssh/config&lt;/code&gt;. Tramite questo file &lt;strong&gt;possiamo salvare delle connessioni remote e richiamarle tramite un’alias&lt;/strong&gt;, senza necessariamente riscrivere tutti i parametri ogni volta.&lt;/p&gt;
&lt;p&gt;Il file &lt;code class=&quot;language-text&quot;&gt;~/.ssh/config&lt;/code&gt; ha la seguente sintassi:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Host &amp;lt;ALIAS&gt;
    HostName &amp;lt;REMOTE_ADDRESS&gt;
    Port &amp;lt;PORT&gt;
    User &amp;lt;USERNAME&gt;
    IdentityFile &amp;lt;PRIVATE_KEY_FILE&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Sostituite le variabili scritte tra le parentesi angolate con i vostri parametri: in questo modo invece di scrivere&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ssh &amp;lt;USERNAME&gt;@&amp;lt;REMOTE_ADDRESS&gt;:&amp;lt;PORT&gt; -i &amp;lt;PRIVATE_KEY_FILE&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ora vi basta scrivere&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ssh &amp;lt;ALIAS&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;molto ma molto più veloce ed immediato.
Nel file di configurazione sono obbligatori i campi &lt;code class=&quot;language-text&quot;&gt;HostName&lt;/code&gt; ed &lt;code class=&quot;language-text&quot;&gt;User&lt;/code&gt;, il resto sono opzionali. Si possono aggiungere più Host qualora abbiate diverse macchine a cui accedete da remoto.&lt;/p&gt;
&lt;p&gt;I parametri SSH disponibili non sono solamente questi, se avete bisogno di funzionalità avanzate come il tunnelling vi consiglio di leggere la &lt;a href=&quot;https://www.ssh.com/ssh/config/&quot;&gt;guida ufficiale su SSH Config File&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1462px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0154da21b46e1efa713867028c145e9c/8d0e6/ssh-config.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.39999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsTAAALEwEAmpwYAAACOklEQVR42qWSXW/SUByHoSAt0BfaBjpoQ0EdZEtM/BrDDL+M3owtXu1jGO+5MkuI3QCjyUa8MOgUWlrKnIt0vHwETervkMKIIdHEkzw5p+ec/9PfOW0ohDY9P39wNXz/dOC5ezNvVpl5XsUL6Pf7lW63W3FddwGZm81m6+zN5/PqZDK5H1q2169eHn+4eOOfnJ78bLff+cbZW7/TufDb7bbfaDT8VqvlG8bpYmwYht9sNheQefCr0+n49Xr9eCXMPSwd7Tx6PN0t79ilctkVJfkqm82O8vm8UywWCSOWZUeSJDmiKA7Q2zzPD5LJJMHE2k0ikThcCRMsW+N4fszxXF8QhEE4HL6ORCIjFFkcx1kUFRli23eGYZx4PG5CYkWjURNzffAVfAMHK2EsxtSQ5rZU2rZRYOVyOUvP63ahUHR0XXewZsuybEJCBERk4qVLeiQARVG1lRAbD1DgpVIpE8kscpx0Om0TZKAoW+hlm6bvWUvhGj1wDe6E5CElCGMkMwuFgpPJZGxNyzmKQnrNUTIKpIpNruOfhEh2qGraLTkqSaWqGlCRiLbWj7dBtlkYpaI1hmZ+MDTdI8eCyEzgLnH8ZVE/KOwF478klFJHakGdqjqSaZqLD+EirYt7HQq8YDNMbIRtY+ABF5DkgwAivQF3vw0jM89ZnXPjW/GuIIuXkihdYrqLhCDaxRf8jOcvAZ/I2hofA+mzpY8C2+AJ2A+orrG/geofkNpS4EJ7gcFuKEZ+yf8gQly/ARL5CO9Ca6BAAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Esempio di connessione remota usando SSH config&quot;
        title=&quot;&quot;
        src=&quot;/static/0154da21b46e1efa713867028c145e9c/8d0e6/ssh-config.png&quot;
        srcset=&quot;/static/0154da21b46e1efa713867028c145e9c/c6e3d/ssh-config.png 500w,
/static/0154da21b46e1efa713867028c145e9c/da8b6/ssh-config.png 1000w,
/static/0154da21b46e1efa713867028c145e9c/8d0e6/ssh-config.png 1462w&quot;
        sizes=&quot;(max-width: 1462px) 100vw, 1462px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Curiosità&lt;/h3&gt;
&lt;p&gt;Questi comandi non sono legati alla produttività, ma sono pur sempre degni di nota.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;say &apos;&amp;lt;TEXT&gt;&apos;&lt;/code&gt;: lo sapevate che il Mac può parlare e lo si può far parlare tramite il terminale? Combinando questo comando con &lt;code class=&quot;language-text&quot;&gt;ssh&lt;/code&gt; possiamo far parlare un Mac anche da remoto. Quindi nessuno ci vieta di mandare un messaggio d’amore alla propria ragazza attraverso il comando &lt;code class=&quot;language-text&quot;&gt;ssh girlfriend@&amp;lt;IP_ADDRESS&gt; say &apos;I love you!&apos;&lt;/code&gt;, provate a farlo e osservate la sua reazione! (Spoiler: non apprezzerà ve lo posso assicurare ?).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;yes&lt;/code&gt;: se avete un gelone temporaneo e avete bisogno di una fonte di calore, allora vi consiglio di avviare &lt;code class=&quot;language-text&quot;&gt;yes&lt;/code&gt; da terminale. Questo comando non fa altro che mandare la CPU al 100%!&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Conclusioni&lt;/h1&gt;
&lt;p&gt;Spero che tutti questi miei trucchetti vi aiutino nel vostro quotidiano a raggiungere i vostri obiettivi lavoritivi nel minor tempo possibile. Sicuramente ci saranno altri milioni tips and tricks che non ne sono a conoscenza: se ne imparo degli altri cercherò di aggiungerli qui in modo da condividerli con voi.&lt;/p&gt;
&lt;p&gt;A presto, buon lavoro e alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come scaricare i video da YouTube con il terminale]]></title><description><![CDATA[Avete appena trovato un video bellissimo su YouTube e volete a tutti i costi scaricarlo, oppure volete scaricare solo la parte audio del…]]></description><link>https://www.mattianatali.it/it/come-scaricare-i-video-da-youtube-con-il-terminale/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-scaricare-i-video-da-youtube-con-il-terminale/</guid><pubDate>Sun, 17 Sep 2017 15:10:47 GMT</pubDate><content:encoded>&lt;p&gt;Avete appena trovato un video bellissimo su YouTube e volete a tutti i costi scaricarlo, oppure volete scaricare solo la parte audio del video per inserirlo nella vostra playlist musicale? Il terminale non vi spaventa? Bene, allora questa guida fa per voi!&lt;/p&gt;
&lt;p&gt;Ci sono un sacco di siti online che fanno queste cose: pieni di pubblicità, a volte non funzionano neanche e solitamente danno pochissima possibilità di personalizzazione su cosa scaricare. Io mi sono stancato di appoggiarmi a questi programmi esterni e ho deciso di fare tutto “in casa”.&lt;/p&gt;
&lt;p&gt;Questa guida si basa sul sistema operativo Mac OS. Ma con piccoli accorgimenti è possibile seguirla anche per Windows e Linux dato che i programmi che utilizzerò sono multi piattaforma.&lt;/p&gt;
&lt;h1&gt;Preparazione&lt;/h1&gt;
&lt;p&gt;Sostanzialmente per raggiungere lo scopo servono 3 programmi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://brew.sh/index_it.html&quot;&gt;Homebrew&lt;/a&gt;&lt;/strong&gt;: il miglior gestore di applicazioni per il Mac. Con questo software sarà una passeggiata installare gli altri due.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.ffmpeg.org/&quot;&gt;Ffmpeg&lt;/a&gt;&lt;/strong&gt;: quando si parla di conversione audio/video lui è il punto di riferimento. Gratis, open source, cross platform, potente… Cosa chiedere di più?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/rg3/youtube-dl&quot;&gt;Youtube-dl&lt;/a&gt;&lt;/strong&gt;: il programma che fa il lavoro sporco di scaricare il video da YouTube.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installazione&lt;/h2&gt;
&lt;p&gt;Ora che sappiamo cosa ci serve procediamo con le installazioni di questi software!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Apriamo il terminale del Mac.&lt;/li&gt;
&lt;li&gt;Installiamo Homebrew
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;/usr/bin/ruby -e &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Installiamo Ffmpeg
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;brew install ffmpeg --with-fdk-aac --with-tools --with-freetype --with-libass --with-libvorbis --with-libvpx --with-x265&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Installiamo Youtube-dl
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;brew install youtube-dl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Bene! Ora abbiamo tutto l’occorrente per scaricare tutti i video di YouTube che vogliamo!&lt;/p&gt;
&lt;h1&gt;Si inizia!&lt;/h1&gt;
&lt;p&gt;Come esempio utilizzerò il video di Gigi D’Agostino che ha appena caricato online. Vi consiglio di vederlo ed ascoltarlo: la sobrietà delle sue pellicole non ha eguali :D!&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1rem; width: 100%;&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/UyyxYha4j6o&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h2&gt;Modalità automatica&lt;/h2&gt;
&lt;p&gt;Partiamo dalla cosa più semplice: scaricare il video senza perdere troppo tempo!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Andiamo su YouTube, apriamo il video e copiamo l’URL. Nel nostro caso è &lt;a href=&quot;https://www.youtube.com/watch?v=UyyxYha4j6o&quot;&gt;https://www.youtube.com/watch?v=UyyxYha4j6o&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Apriamo il terminale e scriviamo &lt;code class=&quot;language-text&quot;&gt;youtube-dl &lt;/code&gt; e incolliamo l’url del punto precedente. Quindi
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;youtube-dl https://www.youtube.com/watch\?v\=UyyxYha4j6o&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
noterete che copiando vengono aggiunti dei &lt;code class=&quot;language-text&quot;&gt;\&lt;/code&gt; prima di &lt;code class=&quot;language-text&quot;&gt;?&lt;/code&gt; e &lt;code class=&quot;language-text&quot;&gt;=&lt;/code&gt;. Non preoccupatevi, sono dei caratteri di escaping che sono necessari e che il terminale aggiunge automaticamente.&lt;/li&gt;
&lt;li&gt;Attendiamo ed è fatta! Nella cartella in cui ci troviamo avremo il video!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Scegliere il formato video&lt;/h2&gt;
&lt;p&gt;Ok Ok, forse il formato scaricato non vi aggrada o ne volete uno con minor qualità… Per far questo scrivete:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Aggiungiamo l’opzione &lt;code class=&quot;language-text&quot;&gt;-F&lt;/code&gt; che ci mostra tutti i formati disponibili
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;youtube-dl -F https://www.youtube.com/watch\?v\=UyyxYha4j6o&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Avremo una bella lista di formati disponibili. Scegliamo quello che più ci aggrada e prendiamo nota del &lt;code class=&quot;language-text&quot;&gt;format code&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Per scaricare la versione scelta ci basterà aggiungere &lt;code class=&quot;language-text&quot;&gt;-f &amp;lt;format_code&gt;&lt;/code&gt; dove &lt;code class=&quot;language-text&quot;&gt;&amp;lt;format_code&gt;&lt;/code&gt; è il codice scelto nel punto precedente. Quindi, per esempio, se volessimo scaricare la versione
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;299          mp4        1920x1080  DASH video 5820k , avc1.64002a, 50fps, video only, 274.09MiB&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
ci basterà scrivere.
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;youtube-dl -f 299 https://www.youtube.com/watch\?v\=UyyxYha4j6o&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Estrarre la traccia audio&lt;/h2&gt;
&lt;p&gt;Per avere solo la traccia audio ci basta scegliere il format code che ha nella colonna &lt;code class=&quot;language-text&quot;&gt;resolution&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;audio only&lt;/code&gt;. Nel nostro video se mostriamo la lista dei formati disponibili possiamo notare che ci sono queste tracce audio&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;format code  extension  resolution note
139          m4a        audio only DASH audio   48k , m4a_dash container, mp4a.40.5@ 48k (22050Hz), 2.26MiB
249          webm       audio only DASH audio   62k , opus @ 50k, 2.39MiB
250          webm       audio only DASH audio   79k , opus @ 70k, 3.16MiB
140          m4a        audio only DASH audio  128k , m4a_dash container, mp4a.40.2@128k (44100Hz), 6.03MiB
171          webm       audio only DASH audio  152k , vorbis@128k, 6.18MiB
251          webm       audio only DASH audio  153k , opus @160k, 6.24MiB&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Molto probabilmente il formato audio non è quello che vogliamo. Quindi abbiamo bisogno una conversione audio. Youtube-dl utilizza ffmpeg per effettuare la conversione.
Per esempio se volessivo avere un file audio con formato &lt;code class=&quot;language-text&quot;&gt;.m4a&lt;/code&gt; con un bitrate di &lt;code class=&quot;language-text&quot;&gt;160k&lt;/code&gt; ci basterà scrivere&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;youtube-dl -x --audio-format m4a --audio-quality 160k https://www.youtube.com/watch\?v\=UyyxYha4j6o&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dove le opzioni significano&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;-x&lt;/strong&gt;: estrai la traccia audio dal video.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;—audio-format m4a&lt;/strong&gt;: il formato da scaricare, o da convertire se non presente nella lista, è m4a. I formati disponibili sono &lt;code class=&quot;language-text&quot;&gt;&quot;best&quot;, &quot;aac&quot;, &quot;flac&quot;, &quot;mp3&quot;, &quot;m4a&quot;, &quot;opus&quot;, &quot;vorbis&quot;, &quot;wav&quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;—audio-quality 160k&lt;/strong&gt;: bitrate della traccia audio desiderato.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Scaricare più video o una playlist&lt;/h2&gt;
&lt;p&gt;Ora che sappiamo come scaricare un video nel formato perfetto per noi, perchè non applicare le stesse impostazioni per più video in un colpo? È semplicissimo! Basta aggiungere più url nel nostro terminale separati da uno spazio. Per esempio possiamo scrivere&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;youtube-dl -x --audio-format m4a --audio-quality 160k https://www.youtube.com/watch\?v\=UyyxYha4j6o https://www.youtube.com/watch\?v\=6L5a3Qt7cvg&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;per avere entrambi i video trasformati in traccia audio.&lt;/p&gt;
&lt;p&gt;Se invece volessimo scaricare una playlist invece di un singolo video ci basta inserire l’URL della playlist!&lt;/p&gt;
&lt;h2&gt;Semplifichiamoci la vita con gli alias&lt;/h2&gt;
&lt;p&gt;Quando voglio scaricare le canzoni da YouTube, di solito uso sempre le stesse impostazioni. E scrivere ogni volta &lt;code class=&quot;language-text&quot;&gt;youtube-dl -x --audio-format m4a --audio-quality &amp;lt;URL&gt;&lt;/code&gt; è una rottura oltre che difficile da ricordare. Sarebbe molto meglio se si potesse scrivere solamente &lt;code class=&quot;language-text&quot;&gt;yda &amp;lt;URL&gt;&lt;/code&gt; (&lt;code class=&quot;language-text&quot;&gt;yda&lt;/code&gt; sta per Youtube Download Audio). La buona notizia è che si può fare!&lt;/p&gt;
&lt;p&gt;Apriamo il terminale e inseriamo&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;echo &quot;alias yda=&apos;youtube-dl -x --audio-format m4a --audio-quality 160k&apos;&quot; | tee -a ~/.bash_profile &amp;amp;&amp;amp; source !$&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Cosa fa questo comando?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;echo &quot;alias yda=&apos;youtube-dl -x --audio-format m4a --audio-quality 160k&apos;&quot; | tee -a ~/.bash_profile&lt;/code&gt;: scrivi il nuovo alias in fondo al file &lt;code class=&quot;language-text&quot;&gt;~/.bash_profile&lt;/code&gt;. In questo modo, ogni volta che apririamo un nuovo terminale avremo questo alias pronto all’uso.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;amp;&amp;amp; source !$&lt;/code&gt;: dopo aver scritto il nuovo alias ricarica il file &lt;code class=&quot;language-text&quot;&gt;~/.bash_profile&lt;/code&gt; nel terminale, in modo da avere il nuovo alias disponibile anche nel terminale corrente.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ora, se vogliamo scaricare una qualsiasi canzone da YouTube sarà semplicissimo.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cerchiamo il video su YouTube, copiate l’url.&lt;/li&gt;
&lt;li&gt;Apriamo il terminale e scriviamo &lt;code class=&quot;language-text&quot;&gt;yda &amp;lt;URL&gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Fine!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Voglio saperne di più!&lt;/h2&gt;
&lt;p&gt;Youtube-dl non ha solo queste impostazioni, queste sono solamente quelle che utilizzo io. Se volete saperne di più vi basta scrivere &lt;code class=&quot;language-text&quot;&gt;youtube-dl --help&lt;/code&gt;. In questo modo avrete tutte, ma proprio tutte, le impostazioni di questo programma e vi assicuro che sono tantissime!&lt;/p&gt;
&lt;h1&gt;Conclusioni&lt;/h1&gt;
&lt;p&gt;Spero che questa guida vi abbia dato uno strumento in più per poter scaricare i video di YouTube a voi più cari, senza aver bisogno di siti online pieni di pubblicità che funzionano una volta sì e dieci no.
Inoltre spero che ora abbiate intuito le potenzialità del terminale, applicazione usata giornalmente dagli sviluppatori, ma snobbata ingiustamente da molti!&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come giocare ai videogiochi di due o tre ere fa]]></title><description><![CDATA[In questi giorni di vacanza mi è venuto un momento nostalgia dei vecchi, vecchissimi videogiochi degli anni ‘90 che giocavo sul mio primo PC…]]></description><link>https://www.mattianatali.it/it/come-giocare-ai-videogiochi-di-due-o-tre-ere-fa/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-giocare-ai-videogiochi-di-due-o-tre-ere-fa/</guid><pubDate>Mon, 02 Jan 2017 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;In questi giorni di vacanza mi è venuto un momento nostalgia dei vecchi, vecchissimi videogiochi degli anni ‘90 che giocavo sul mio primo PC, un vetusto Compaq Presario con 133MHz di CPU.&lt;/p&gt;
&lt;p&gt;Sembra impossibile ma è ancora possibile giocare a questi videogiochi senza aver troppi problemi di compatibilità grazie a &lt;a href=&quot;http://www.dosbox.com/&quot;&gt;DOSBox&lt;/a&gt;. Questo programma non è altro che un emulatore del sistema operativo DOS: negli anni ‘90 moltissimi giochi supportavano questo sistema operativo e quindi possiamo sfruttare a nostro vantaggio questa cosa.&lt;/p&gt;
&lt;p&gt;In questa guida spiegherò come poter giocare a qualche videogioco che ha segnato la mia infanzia.&lt;/p&gt;
&lt;h2&gt;Installiamo DOSBox&lt;/h2&gt;
&lt;p&gt;Per prima cosa bisogna installare &lt;a href=&quot;http://www.dosbox.com/&quot;&gt;DOSBox&lt;/a&gt;, io vi consiglio di utilizzare come sistema operativo Windows… Su Mac ho qualche problema di performance… Sembra assurdo ma è così :D. L’installazione non è niente di che: basta andare nella sezione download del sito e scaricare il pacchetto ed installarlo come un comune software. Una volta ultimato questo passo siamo pronti a tuffarci nel passato!&lt;/p&gt;
&lt;h2&gt;Grand Prix Circuit&lt;/h2&gt;
&lt;p&gt;Cominciamo ad avviare un gioco semplice semplice. &lt;a href=&quot;https://en.wikipedia.org/wiki/Grand_Prix_Circuit_(video_game)&quot;&gt;Grand Prix Circuit&lt;/a&gt;!&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.27198124267292%; position: relative; height: 0; overflow: hidden; margin-bottom: 1rem; width: 100%;&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/EJ2XmzYg-n4?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h3&gt;Download&lt;/h3&gt;
&lt;p&gt;Per prima cosa dobbiamo &lt;a href=&quot;http://www.bestoldgames.net/eng/old-games/grand-prix-circuit.php&quot;&gt;scaricare il gioco&lt;/a&gt;. Scarichiamo il pacchetto ed estraiamo i file dall’archivio &lt;code class=&quot;language-text&quot;&gt;.zip&lt;/code&gt; in una cartella, per esempio in &lt;code class=&quot;language-text&quot;&gt;C:\giochi\gp\&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Mounting del volume&lt;/h3&gt;
&lt;p&gt;Ora avviamo DOSBox. Ci compare un prompt dei comandi che non è altro che la classica shell di DOS.
La prima cosa è montare il volume dove risiede il nostro gioco. In parole più semplici dobbiamo dare a DOSBox un volume &lt;code class=&quot;language-text&quot;&gt;C:\&lt;/code&gt;, una parte di memoria, che abbia accesso al gioco. DOSBox, senza questa operazione, non può leggere nessun dato del nostro hard disk proprio perchè i volumi (&lt;code class=&quot;language-text&quot;&gt;C:\&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;D:\&lt;/code&gt; ecc) che utilizza Windows sono completamenti differenti rispetto a quelli che usa DOSBox.
Per fare questa operazione basta scrivere in DOSBox&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;mount c c:\giochi\&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora che abbiamo montato la nostra cartella &lt;code class=&quot;language-text&quot;&gt;giochi&lt;/code&gt; come volume &lt;code class=&quot;language-text&quot;&gt;C&lt;/code&gt;, possiamo accederci tramite DOS.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;c:&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Potete vedere che ora DOSBox mostra &lt;code class=&quot;language-text&quot;&gt;C:\&gt;&lt;/code&gt; invece di &lt;code class=&quot;language-text&quot;&gt;Z:\&gt;&lt;/code&gt; proprio perchè è all’interno del nostro volume appena creato. Sostanzialmente ora in DOSBox siamo nella cartella &lt;code class=&quot;language-text&quot;&gt;C:\giochi\&lt;/code&gt; del nostro PC.&lt;/p&gt;
&lt;h3&gt;Avvio del gioco&lt;/h3&gt;
&lt;p&gt;Ora utilizziamo un’altro comando DOS:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;dir&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;questo comando mostra tutti i file e le cartelle contenute nel path in cui ci troviamo. Dovrebbe comparire la nostra cartella &lt;code class=&quot;language-text&quot;&gt;gp&lt;/code&gt;. Per accederci utilizziamo il comando&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;cd gp&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora siamo nella cartella dove è presente Grand Prix Circuit appena scaricato. Per avviare il gioco con ci resta che eseguire il comando&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;GP.EXE&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Complimenti! Ora potete divertirvi a giocare ad un super gioco che ha fatto la storia!&lt;/p&gt;
&lt;h3&gt;Riassunto&lt;/h3&gt;
&lt;p&gt;Bene, fin qui abbiamo imparato a fare le seguenti cose:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download del gioco e avvio di DOSBox.&lt;/li&gt;
&lt;li&gt;Mounting della directory &lt;code class=&quot;language-text&quot;&gt;giochi&lt;/code&gt; per offrire a DOSBox una parte di memoria del nostro PC.&lt;/li&gt;
&lt;li&gt;Navigazione tra le cartelle in DOS tramite i comandi &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;dir&lt;/code&gt;. Questa guida non vuole insegnare ad utilizzare questo sistema operativo e quindi sono stato abbastanza sbrigativo. Se volete saperne di più potete &lt;a href=&quot;http://www.myw0.com/2010/1635/list-of-dos-commands-cheat-sheet-for-dos/&quot;&gt;documentarvi tramite questo link&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Avvio del gioco.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Questi passi vanno bene per buona parte dei vecchi videogiochi, ma ce ne sono altri che richiedono l’installazione oppure l’inserimento del CD-ROM per poter giocare. Il prossimo gioco rientra proprio in questa casistica.&lt;/p&gt;
&lt;h2&gt;Ignition&lt;/h2&gt;
&lt;p&gt;Questo gioco mi piace davvero parecchio! Mi ricorda le ore passate insieme a mio cugino parecchi anni fa!&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.27198124267292%; position: relative; height: 0; overflow: hidden; margin-bottom: 1rem; width: 100%;&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/f2lajsZt4Hg?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;La modalità di avvio è simile alla precedente, solo che in questo caso dobbiamo installare il gioco come se avessimo un CD-ROM.&lt;/p&gt;
&lt;h3&gt;Download&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bestoldgames.net/eng/old-games/ignition.php&quot;&gt;Scarichiamo il gioco&lt;/a&gt; ed estraiamo l’archivio in &lt;code class=&quot;language-text&quot;&gt;C:\giochi\ign\&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Mounting dei volumi&lt;/h3&gt;
&lt;p&gt;Montiamo il volume &lt;code class=&quot;language-text&quot;&gt;C:&lt;/code&gt; con lo stesso comando usato in precedenza&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;mount c: c:\giochi\&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ora inseriamo il CD-ROM di Ignition! In che modo? Più o meno come si monta un classico volume.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;mount d: c:\giochi\ign\ -t cdrom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In questo caso stiamo dicendo a DOSBox di mostrare la nostra cartella &lt;code class=&quot;language-text&quot;&gt;c:\giochi\ign\&lt;/code&gt;, dove c’è dentro il gioco scaricato, come se fosse un CD-ROM.&lt;/p&gt;
&lt;h3&gt;Installazione&lt;/h3&gt;
&lt;p&gt;Ora entriamo nel CD e avviamo l’installazione&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;d:
DOS_INST.EXE&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A questo punto partirà l’installazione. Scegliete italiano e premete sempre avanti.&lt;/p&gt;
&lt;h3&gt;Avvio del gioco&lt;/h3&gt;
&lt;p&gt;Ora siamo pronti per giocare. Scrivete questi tre comandi e buon divertimento!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;c:
cd IGNITION
IGN_DOS.BAT&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Come scaricare le canzoni da Soundcloud in pochi semplici click]]></title><description><![CDATA[Soundcloud, per chi non lo conoscesse, è un ottimo sito web che permette ai musicisti di collaborare, promuovere e distribuire la loro…]]></description><link>https://www.mattianatali.it/it/come-scaricare-le-canzoni-da-soundcloud-in-pochi-semplici-click/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-scaricare-le-canzoni-da-soundcloud-in-pochi-semplici-click/</guid><pubDate>Sun, 13 Nov 2016 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://soundcloud.com/&quot;&gt;Soundcloud&lt;/a&gt;, per chi non lo conoscesse, è un ottimo sito web che permette ai musicisti di collaborare, promuovere e distribuire la loro musica.&lt;/p&gt;
&lt;p&gt;Purtroppo non permette lo scaricamento delle canzoni, ma utilizzando gli &lt;a href=&quot;https://support.google.com/dfp_premium/answer/4497389?hl=it&quot;&gt;strumenti per sviluppatori&lt;/a&gt; di Google Chrome è molto semplice bypassare questa restrizione.&lt;/p&gt;
&lt;h2&gt;Istruzioni&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Accedete a &lt;a href=&quot;https://soundcloud.com/&quot;&gt;Soundcloud&lt;/a&gt;&lt;/strong&gt; usando Google Chrome, e andate sulla pagina della canzone che volete scaricare.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Aprite gli &lt;a href=&quot;https://support.google.com/dfp_premium/answer/4497389?hl=it&quot;&gt;strumenti per sviluppatori&lt;/a&gt;&lt;/strong&gt; premendo &lt;code class=&quot;language-text&quot;&gt;F12&lt;/code&gt; su Windows oppure &lt;code class=&quot;language-text&quot;&gt;cmd&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;opt&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;I&lt;/code&gt; su Mac. Cliccate sul tab Network. In questa sezione, cliccate sulla sesta icona a partire da sinistra. In questo modo vi si aprirà la linea del tempo dei vari scaricamenti che effettua il browser.&lt;/li&gt;
&lt;li&gt;Ora siete pronti per intercettare il file &lt;code class=&quot;language-text&quot;&gt;.mp3&lt;/code&gt; da scaricare! &lt;strong&gt;Avviate la canzone&lt;/strong&gt; dal browser. Appena avviata la canzone vedrete degli scaricamenti avviarsi sulla timeline, una linea sicuramente attirerà la vostra attenzione perchè sarà molto più lunga delle altre. Questa linea rappresenta proprio la canzone in formato &lt;code class=&quot;language-text&quot;&gt;.mp3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Selezionate la canzone dalla timeline&lt;/strong&gt;. Per farlo basta trascinare il mouse su un pezzettino della linea, vi consiglio di prendere una parte in cui questa linea è isolata così da non sbagliare la selezione.&lt;/li&gt;
&lt;li&gt;Una volta selezionato lo scaricamento nella timeline, in basso vi comparirà la voce della vostra traccia. Premete con il tasto destro del mouse e cliccate su &lt;strong&gt;“Apri il link in una nuova tab”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Ecco fatto! Ora avete la vostra traccia in &lt;code class=&quot;language-text&quot;&gt;.mp3&lt;/code&gt;! Cliccate su &lt;code class=&quot;language-text&quot;&gt;File&lt;/code&gt;-&gt;&lt;code class=&quot;language-text&quot;&gt;Salva con nome...&lt;/code&gt; e &lt;strong&gt;godetevi la canzone&lt;/strong&gt; dove volete e quando volete!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Video tutorial&lt;/h2&gt;
&lt;p&gt;6 passi vi sembrano troppi? Vi assicuro che dopo averci preso la mano potete scaricare quello che volete in meno di 2 secondi. Ecco qui i 6 passaggi racchiusi in un piccolo video.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/6f50bca971d1f2f6612fa015b3efb6d1/soundcloud-download.gif&quot; alt=&quot;Video tutorial&quot;&gt;&lt;/p&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come migliorare le foto con Nik Collection]]></title><description><![CDATA[Il digitale ha rivoluzionato parecchi settori, incluso quello della fotografia. Io mi sono affacciato a questo mondo proprio nel momento di…]]></description><link>https://www.mattianatali.it/it/come-migliorare-le-foto-con-nik-collection/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-migliorare-le-foto-con-nik-collection/</guid><pubDate>Thu, 11 Aug 2016 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Il digitale ha rivoluzionato parecchi settori, incluso quello della fotografia. Io mi sono affacciato a questo mondo proprio nel momento di transizione… e devo dire che il vecchio rullino non mi manca proprio.&lt;/p&gt;
&lt;p&gt;Un grande vantaggio della fotografia digitale è sicuramente l’affascinante mondo della &lt;strong&gt;post produzione&lt;/strong&gt;. I puristi della fotografia lo detestano, i veterani del vecchio rullino pensano che sia un abominio.
Per me invece è diventata una fase importante quasi quanto lo scatto: con la post produzione si può completamente modificare una foto mediocre e renderla in uno scatto unico, aggiungere dinamicità, dare carattere ad una foto insipida.&lt;/p&gt;
&lt;p&gt;Questa piccola guida vi insegnerà proprio questo (o si spera): la fotografia che utilizzerò l’ho scattata in Francia e si tratta della famosissima Notre Dame de Paris.&lt;/p&gt;
&lt;h2&gt;Prima di iniziare&lt;/h2&gt;
&lt;p&gt;Per seguire questa guida servono software professionali: io ho utilizzato &lt;strong&gt;&lt;a href=&quot;http://www.adobe.com/products/photoshop.html&quot;&gt;Adobe Photoshop&lt;/a&gt;&lt;/strong&gt;. Potete utilizzare anche &lt;a href=&quot;https://support.apple.com/aperture&quot;&gt;Aperture&lt;/a&gt; oppure &lt;a href=&quot;http://www.adobe.com/products/photoshop-lightroom.html&quot;&gt;Lightroom&lt;/a&gt;. Questi software costano e non poco: la prima cosa da fare è acquistarli o sperare che la vostra azienda abbia una licenza per voi, oppure che qualche vostro amico sia particolarmente gentile e vi passi uno slot della loro licenza (Photoshop può essere utilizzato fino a 3 PC con una singola licenza).&lt;/p&gt;
&lt;p&gt;Questa guida non vuole insegnarvi ad utilizzare questi software, diciamo che è un prerequisito averne almeno una conoscenza base.&lt;/p&gt;
&lt;p&gt;Il software principe di questa guida è invece questa collezione di plugin che si appoggiano ad essi: &lt;strong&gt;&lt;a href=&quot;https://www.google.com/nikcollection/&quot;&gt;Nik Collection&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Fino all’anno scorso questa suite costava circa $500, e secondo me li valeva tutti. Ora invece Google ha deciso di renderla &lt;strong&gt;gratuita&lt;/strong&gt;!&lt;/p&gt;
&lt;h2&gt;Scelta della fotografia&lt;/h2&gt;
&lt;p&gt;Prima cosa da fare è scegliere quale scatto si intende migliorare / modificare. Una cosa deve essere chiara: &lt;strong&gt;la post produzione può fare miracoli ma c’è un limite a tutto&lt;/strong&gt;. Se la foto iniziale fa pena, è facile che anche sotto un pesante ritocco farà pena uguale. La post produzione valorizza il contenuto, ma se il valore iniziale è zero difficile che esca qualcosa di sensazionale. Quindi cercate sempre di scattare il miglior scatto possibile per avere una buona base di partenza.
La mia fotografia è questa: l’ho scattata con il mio LG G3, non una reflex, semplicemente uno smartphone vecchio di 3 anni. Durante il mio soggiorno a Parigi non avevo di meglio, ma comunque ha un ottimo potenziale.
&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameOrigLow-1470935433506.jpg&quot; alt=&quot;Notre Dame de Paris&quot;&gt;&lt;/p&gt;
&lt;p&gt;Scelta la fotografia bisogna decidere che fare: magari se non sapete cosa può fare Nik Collection questo passo vi sarà un po’ difficile.
Il mio obiettivo in questa foto è di valorizzare la cattedrale, far risaltare i dettagli e di dare un tono drammatico, tipico delle cattedrali, a tutta la scena.&lt;/p&gt;
&lt;h2&gt;Conosciamo Nik Collection&lt;/h2&gt;
&lt;p&gt;Ora che abbiamo deciso il nostro punto di partenza e il nostro obiettivo è giunta l’ora di conoscere gli strumenti a nostra disposizione.&lt;/p&gt;
&lt;p&gt;Se non lo avete ancora fatto scaricate &lt;a href=&quot;https://www.google.com/nikcollection/&quot;&gt;Nik Collection&lt;/a&gt; e installatelo. Sul vostro PC deve essere già presente Photoshop.&lt;/p&gt;
&lt;p&gt;Una volta installato, se avviate Photoshop, potete vedere un piccolo nuovo riquadrino dove potete scegliere i vari plugin che compongono questa suite:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dfine:&lt;/strong&gt; è il primo plugin da avviare. Il suo compito è di rimuovere il rumore dalle fotografie.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analog Efex Pro:&lt;/strong&gt; simula l’effetto delle vecchie pellicole e delle antiche macchine fotografiche che hanno fatto la storia con i loro particolari effetti. Avete presente i filtri Instagram? Ecco avete colto cosa può fare questo plugin.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Color Efex Pro:&lt;/strong&gt; se volete correggere qualche tinta, creare effetti che hanno a che fare con i colori, questo plugin è perfetto.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Silver Efex Pro:&lt;/strong&gt; utilissimo se volete creare un’immagine monocromatica.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Viveza:&lt;/strong&gt; ottimo se volete modificare solo dei particolari della foto, dare risalto a dei soggetti.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HDR Efex Pro:&lt;/strong&gt; per creare un’&lt;a href=&quot;https://it.wikipedia.org/wiki/High_dynamic_range_imaging&quot;&gt;immagine HDR&lt;/a&gt;. Senza entrare troppo in tecnicismi, per creare una reale immagine HDR c’è bisogno di più scatti dello stesso soggetto usando esposizioni diverse. Ma questo plugin riesce ad ottenere lo stesso risultato anche da una singola immagine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sharpener Pro:&lt;/strong&gt; il suo compito è quello di far risaltare i dettagli e di rendere meno sfuocata l’immagine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Se per caso non vi compare il riquadro di Nik Collection, potete trovare tutti questi software nel menu in alto alla voce &lt;em&gt;Filtri&lt;/em&gt; &gt; &lt;em&gt;Nik Collection&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Rimuoviamo il rumore&lt;/h2&gt;
&lt;p&gt;Ora è il momento di iniziare! Il primo passo che eseguo sempre è quello di rimuovere il rumore dalla fotografia. Se lo scatto è stato eseguito da una fotocamera non particolarmente performante, come il mio smartphone, questo passaggio è praticamente obbligatorio. Il rumore, anche se impercettibile, viene amplificato durante i passaggi di modifica. Quindi pulire l’immagine da questi disturbi è molto importante.&lt;/p&gt;
&lt;p&gt;Questo passaggio è molto semplice. Caricate l’immagine in Photoshop, avviate &lt;strong&gt;Dfine&lt;/strong&gt;. Come lo aprire potete notare che fa qualche magia e rimuovere il rumore automaticamente. Potrebbe sembrare che non sia cambiato nulla, in realtà per apprezzare il lavoro di Dfine è utile ingrandire l’immagine al 100%. Per far ciò fate doppio click sull’immagine, infine, in alto a sinistra, dove c’è scritto &lt;em&gt;Views&lt;/em&gt;, avete tre modalità di visualizzazione:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single image view:&lt;/strong&gt; la vista di default. Vedete solo l’output finale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Split view:&lt;/strong&gt; potete vedere contemporaneamente l’immagine prima e dopo l’applicazione del filtro. Potete spostare anche la linea rossa per avere un rapido confronto tra le due versioni.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Side by side preview:&lt;/strong&gt; sostanzialmente avrete le due immagini, prima e dopo l’applicazione del filtro affiancate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Una volta che avete potuto apprezzare i cambiamenti premete &lt;em&gt;OK&lt;/em&gt;. Così da poter passare al passo successivo.&lt;/p&gt;
&lt;h2&gt;HDR Efex Pro, tocca a te!&lt;/h2&gt;
&lt;p&gt;Ora è giunto il momento di aggiungere un tocco di HDR all’immagine. HDR sta per &lt;a href=&quot;https://it.wikipedia.org/wiki/High_dynamic_range_imaging&quot;&gt;High Dynamic Range&lt;/a&gt; ed è una tecnica fotografica che permette di mostrare più dettagli rispetto ad una fotografia normale. Avete presente quelle situazioni in cui scattate una fotografia ad un’ambiente che presenta sia punti particolarmente illuminati che bui? Capita che la parte molto illuminata viene solo una bella chiazza bianca e la parte scura una chiazza nera. L’HDR riesce a superare queste problematiche.
Questa è solo per darvi una idea di cosa sia l’HDR, ci sarebbe da scrivere una guida solo su questo… Ma è meglio tornare alla nostra immagine!&lt;/p&gt;
&lt;p&gt;Sempre dal riquadro di Nik Collection, nella sezione &lt;em&gt;HDR Efex Pro&lt;/em&gt; scegliete &lt;em&gt;Tone Mapping (Single Image)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Sulla parte sinistra potete trovare il &lt;strong&gt;Preset Library&lt;/strong&gt;, in esso ci sono già degli ottimi &lt;strong&gt;punti di partenza&lt;/strong&gt;. Io ho scelto &lt;em&gt;Deep 1&lt;/em&gt; che si trova nella libreria &lt;em&gt;Realistic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Una volta scelto il punto di partenza potete focalizzarvi sulla parte che si trova a destra della finestra. Qui potete trovare una marea di configurazioni per modificare ogni singolo aspetto del filtro. Le macro aree sono queste:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tone Compression:&lt;/strong&gt; ci sono tutte le impostazioni che riguardano solamente l’effetto HDR. Sicuramente è qui che trovate le impostazioni che cambiano radicalmente l’aspetto della vostra immagine.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tonality:&lt;/strong&gt; qui potete trovare le impostazioni classiche dell’immagine come esposizione, ombre, luci, contrasto ecc. Un’opzione che a me piace particolarmente è &lt;em&gt;structure&lt;/em&gt;. Aumentandola potete notare come l’immagine diventi particolarmente definita. Occhio a non esagerare perchè oltre ad esaltare i dettagli esalta anche il rumore. Ecco perchè vi avevo caldamente consigliato di rimuoverlo con Dfine… Ora i nodi vengono al pettine!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Finishing:&lt;/strong&gt; è la post produzione dell’effetto di post produzione! Nel senso sono gli ultimi ritocchi che potete fare prima di abbandonare questo plugin. Io da questa area ho aggiunto un piccolo effetto di vignettatura. Vicino alla scritta &lt;em&gt;Vignette&lt;/em&gt; c’è un piccolo menu di scelta. Io ho scelto &lt;em&gt;Lens 2&lt;/em&gt;. L’effetto vignettatura non fa altro che scurire i bordi dell’immagine (o schiarire). È un ottimo modo per guidare l’attenzione dell’osservatore. In questo caso il mio intento è di esaltare la cattedrale.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Anche in questo caso non sono andato troppo in dettaglio. Il mio consiglio è di giocare e provare da soli tutte le varie funzionalità. Solo così si può padroneggiare questa suite… Usandola!&lt;/p&gt;
&lt;p&gt;Ecco qui il risultato finale dopo questo passaggio.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameHdr-1470935603909.jpg&quot; alt=&quot;HDR Efex Pro&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Correggiamo i colori&lt;/h2&gt;
&lt;p&gt;Ora l’immagine ha un tono molto più drammatico rispetto all’originale, si addice molto ad una cattedrale. I dettagli della struttura sono stati messi in risalto, possiamo essere soddisfatti del nostro lavoro! C’è solo un piccolo problema… La cattedrale è diventata un canarino! È troppo satura e quindi abbiamo bisogno di rimuovere un po’ di saturazione alla cattedrale.&lt;/p&gt;
&lt;p&gt;Per far questo avviamo &lt;strong&gt;Color Efex Pro&lt;/strong&gt;. La finestra che si apre ormai dovrebbe essere familiare: cambiano solo i filtri di partenza sulla sinistra e le impostazioni sulla destra.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameColor-1470935567508.jpg&quot; alt=&quot;Color Efex Pro&quot;&gt;&lt;/p&gt;
&lt;p&gt;Il filtro che andremo ad utilizzare per desaturare l’immagine si chiama &lt;em&gt;&lt;a href=&quot;https://it.wikipedia.org/wiki/Bleach_bypass&quot;&gt;Bleach Bypass&lt;/a&gt;&lt;/em&gt;. Selezioniamolo dai filtri disponibili e notiamo subito i cambiamenti sull’immagine.&lt;/p&gt;
&lt;p&gt;Fino ad ora abbiamo applicato i filtri &lt;em&gt;sull’immagine intera&lt;/em&gt;, in questo caso noi vogliamo applicarlo solo &lt;em&gt;sulla cattedrale&lt;/em&gt; senza intaccare il resto.&lt;/p&gt;
&lt;h3&gt;Dite ciao ai control points!&lt;/h3&gt;
&lt;p&gt;Per risolvere questo problema è necessario imparare un’importantissima feature che fino adesso vi ho tenuto nascosto. I &lt;strong&gt;control points&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Questi &lt;em&gt;“punti di controllo”&lt;/em&gt; &lt;strong&gt;vi permettono di applicare il filtro solo su aree specifiche&lt;/strong&gt;. Proviamo subito ad utilizzarne uno. Sulla parte destra cercate la funzione &lt;em&gt;Control Points&lt;/em&gt;, qui potete notare due pulsanti: il primo raffigura un cerchio con accanto il ”+” e l’altro un ”-“. La differenza tra i due è che il primo aggiunge un punto con opacità 100%, il secondo con 0%. In altre parole il primo applica il filtro nel punto selezionato, il secondo lo rimuove.&lt;/p&gt;
&lt;p&gt;A noi serve applicare il filtro nel punto in cui selezioniamo. Quindi abbiamo bisogno di premere sul bottone con il ”+“. Una volta premuto spostiamo il cursore sulla cattedrale, noterete che il simbolo del cursore è diventato una sorta di mirino, clicchiamo sulla cattedrale. Nik Collection è abbastanza intelligente da capire che volete applicare il filtro solo sul punto selezionato, quindi rimuove il filtro dal resto dell’immagine e lo lascia solo sul control point.&lt;/p&gt;
&lt;p&gt;Una volta posizionato il control point si può notare che c’è un cerchiolino sull’immagine con due sliders. Il primo determina il &lt;em&gt;raggio d’azione&lt;/em&gt; del control point, il secondo la sua opacità. Ovviamente più il raggio d’azione è grande più il nostro filtro influenzerà una porzione più grande dell’immagine e più aumentiamo l’opacità più si nota la differenza (nel nostro caso è già al 100%).&lt;/p&gt;
&lt;p&gt;Siccome il control point ha un raggio d’azione circolare, vi consiglio di aggiungere tanti punti di piccole dimensioni piuttosto che averne uno grande per avere un maggiore controllo su di esso.&lt;/p&gt;
&lt;p&gt;Ma come facciamo a capire il vero raggio d’azione di un control point? Effettivamente &lt;strong&gt;Nik collection applica il filtro in modo intelligente&lt;/strong&gt;: nonostante il raggio d’azione sia circolare, non si nota il punto in cui smette di applicare queste correzioni. Perchè appunto il punto di forza di Nik sono i suoi algoritmi di creazione delle maschere di applicazione. Probabilmente questa frase può essere arabo per chi non non è ferrato con Photoshop, ma sarà chiaro a breve.
Per capire cosa ho scritto torniamo su Color Efex Pro; nella sezione &lt;em&gt;Control Points&lt;/em&gt; possiamo notare la lista dei nostri punti aggiunti. Ogni voce di questa lista è composta da 4 punti:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checkbox per abilitare il control point.&lt;/li&gt;
&lt;li&gt;Il suo nome.&lt;/li&gt;
&lt;li&gt;La percentuale di immagine influenzata.&lt;/li&gt;
&lt;li&gt;Checkbox per visualizzare il punto di applicazione (la sua maschera).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mettiamo la spunta a quest’ultima checkbox di un qualsiasi control point inserito. L’immagine diventa monocroma e da qui possiamo vedere effettivamente il &lt;strong&gt;vero punto di applicazione&lt;/strong&gt; del filtro del control point selezionato. Il nero indica che non è stato applicato il filtro, il bianco dove è stato applicato, le varie gradazioni intermedie indicano una diversa opacità dell’applicazione.&lt;/p&gt;
&lt;p&gt;Aggiungete tutti i punti di controllo necessari per “rendere bianca” la cattedrale, in questo modo applicherete il filtro solo sulla cattedrale. Ecco qui la mia cattedrale bianca, indice che sto applicando il filtro bleach bypass solo su di essa.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameColorMask-1470935624170.jpg&quot; alt=&quot;Punti di applicazione del filtro&quot;&gt;&lt;/p&gt;
&lt;p&gt;I control points secondo me sono il vero punto di forza di Nik Collection. Per creare la stessa maschera utilizzando solo Photoshop, invece di impiegarci 5 minuti, ci avremmo impiegato ore!&lt;/p&gt;
&lt;p&gt;Una volta che ci siamo accertati che il filtro viene applicato solo alla cattedrale, possiamo rimuovere le spunte alla checkbox della maschere dei punti di controllo e tornare a visualizzare l’immagine normale.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameMod-1470935662758.jpg&quot; alt=&quot;Risultato finale&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finalmente ci siamo!&lt;/p&gt;
&lt;h2&gt;Conclusioni&lt;/h2&gt;
&lt;p&gt;Ecco qui il risultato finale affiancato alla nostra immagine originale:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameComparison-1470935678418.jpg&quot; alt=&quot;Comparazione&quot;&gt;&lt;/p&gt;
&lt;p&gt;Spero che questa guida vi abbia dato una vaga idea delle potenzialità di questa suite di plugin. Ovviamente questa è solo la punta della punta dell’iceberg: il mio intento non è di spiegare la suite e tutti i suoi comandi, ma di applicarlo in un vero caso d’uso.&lt;/p&gt;
&lt;p&gt;Se avete voglia di saperne di più vi consiglio caldamente questo video tutorial introduttivo… È in inglese e dura un’ora… Ma ne vale veramente la pena!&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 75%; position: relative; height: 0; overflow: hidden; margin-bottom: 1rem; width: 100%;&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/gikVjBnpTRQ?rel=0&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Come rimuovere i virus dal computer]]></title><description><![CDATA[“Ciao! Tutto bene? Senti penso di avere un virus nel PC, puoi darci un’occhiata?” Le varianti di questa frase sono infinite, ma più o meno…]]></description><link>https://www.mattianatali.it/it/come-rimuovere-i-virus-dal-computer/</link><guid isPermaLink="false">https://www.mattianatali.it/it/come-rimuovere-i-virus-dal-computer/</guid><pubDate>Sun, 07 Aug 2016 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;“Ciao! Tutto bene? Senti penso di avere un virus nel PC, puoi darci un’occhiata?”&lt;/p&gt;
&lt;p&gt;Le varianti di questa frase sono infinite, ma più o meno quasi la totalità delle persone che mi chiamano per avere una mano per questo problema esordiscono così.&lt;/p&gt;
&lt;p&gt;Oggi vi spiego cosa si può fare per risolvere questo problema da soli, senza spendere un centesimo e senza neppure aver bisogno di chissà quali competenze.&lt;/p&gt;
&lt;h2&gt;Ci sono virus e virus&lt;/h2&gt;
&lt;p&gt;Prima di iniziare è meglio sapere un minimo le varie tipologie di virus che potreste imbattervi. Secondo me è utile per capire i messaggi di errore che il vostro antivirus vi propone se trova qualcosa di insolito.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Malware:&lt;/strong&gt; è qualsiasi cosa che può recare danno al vostro pc. Quindi è la macrocategoria che contiene tutte le voci sottostranti… Infatti avrei dovuto scrivere “Ci sono malware e malware”, ma vabbè ci siamo capiti!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virus:&lt;/strong&gt; malware che è in grado di autoreplicarsi e di infettare altri utenti tramite le chiavette usb o supporti removibili.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Worm:&lt;/strong&gt; simile al virus ma infetta gli altri PC attraverso la rete.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trojan:&lt;/strong&gt; si mostra come un software utile, in realtà apre letteralmente una porta ad un attaccante per poter rubare i vostri dati sensibili oppure prendere il possesso del vostro PC. È appunto un cavallo di Troia!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spyware:&lt;/strong&gt; spiano ciò che fate sul PC e vendono queste informazioni sul mercato nero.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adware:&lt;/strong&gt; vi insozzano il PC di pubblicità indesiderata.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keylogger:&lt;/strong&gt; registrano i tasti che premete nella speranza che digitiate qualche credenziale o meglio ancora il codice della carta di credito.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backdoor:&lt;/strong&gt; se l’attaccante riesce ad installare questa roba può utilizzare il vostro PC per fare parecchie cose in rete: per esempio inviare email o connettere il vostro PC ad un sito per sovraccaricarlo e provocare un disservizio.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rootkit:&lt;/strong&gt; sono molto diffici da scovare, se ne avete uno è come se l’attaccante avesse il vostro pc in casa loro. Semplicemente possono fare quello che vogliono a distanza.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scareware:&lt;/strong&gt; sono malware che vi spaventano, vi dicono che il vostro PC ha milioni di problemi e di pagare loro per sistemare tutto. Peccato che invece il vero problema è il programma stesso che finge di aiutarvi. Il più delle volte le persone si beccano questo tipo di malware.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cryptolocker:&lt;/strong&gt; nell’ultimo periodo è stato molto in voga. In pratica, una volta avviato, comincia a criptare tutti i vostri documenti e quando ha finito vi chiede un riscatto. Se rivolete i vostri documenti dovete pagare!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;La prevenzione prima di tutto!&lt;/h2&gt;
&lt;p&gt;Premessa: io non uso &lt;strong&gt;antivirus&lt;/strong&gt;, secondo me è possibile vivere anche senza. L’importante è stare attenti e sapere ciò che si avvia… Sempre! Se invece non vi sentite sicuri allora è meglio installare qualche antivirus che possa colmare le vostre disattenzioni &lt;em&gt;in tempo reale&lt;/em&gt;. Infine se avete già un malware nel vostro PC allora &lt;strong&gt;installatelo&lt;/strong&gt; immediatamente. Io di solito installo &lt;a href=&quot;http://www.bitdefender.com/solutions/free.html&quot;&gt;Bitdefender&lt;/a&gt; sui PC che sistemo. Ci sono davvero pochissime opzioni e fa il suo lavoro.
Una volta installato eseguite una &lt;strong&gt;scansione completa del PC&lt;/strong&gt; e sperate che riesca a risolvere il vostro problema.&lt;/p&gt;
&lt;h2&gt;Disinstallazione del malware&lt;/h2&gt;
&lt;p&gt;L’antivirus fa bene due cose: mantenere i &lt;em&gt;virus&lt;/em&gt; alla larga prima che possano fare danni e rimuoverli se per caso sono già all’interno del vostro PC. Il problema è che sono molto bravi solo su una categoria, i &lt;em&gt;virus&lt;/em&gt; appunto. Ma come avete letto poco tempo fa esistono una miriade di malware che non rientrano in questa categoria.
Qualora il vostro malware fosse ancora lì a darvi fastidio avete bisogno di altro… Forse anche di poco altro… Alcune volte basta veramente solo &lt;strong&gt;disinstallare l’app&lt;/strong&gt; che vi da fastidio senza aver bisogno di chissà quali software.&lt;/p&gt;
&lt;p&gt;Eseguire questo passo è molto semplice:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Leggete il nome dell’app che si apre e che vi da fastidio.&lt;/li&gt;
&lt;li&gt;Andate in &lt;em&gt;Pannello di Controllo&lt;/em&gt; &gt; &lt;em&gt;Programmi e Funzionalità&lt;/em&gt; &gt; cercate il nome dell’app e disinstallatela.&lt;/li&gt;
&lt;li&gt;Se per caso vi dice che l’app è in uso, chiudetela. Se non riuscite a chiuderla aprite il &lt;em&gt;task manager&lt;/em&gt; premendo &lt;code class=&quot;language-text&quot;&gt;ctrl&lt;/code&gt;+&lt;code class=&quot;language-text&quot;&gt;shift&lt;/code&gt;+&lt;code class=&quot;language-text&quot;&gt;esc&lt;/code&gt;. Andate nella tab processi e terminate l’app in questione.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Questi passi possono variare sensibilmente in base alla versione di Windows che possedete.&lt;/p&gt;
&lt;h2&gt;Antibiotici ad ampio spettro&lt;/h2&gt;
&lt;p&gt;Immagino che se state leggendo qui significa che il vostro bel malware vi vuole molte bene ed è ancora lì nel vostro PC a rendervi la giornata un inferno. Bene! Ora è tempo di utilizzare due software: &lt;strong&gt;&lt;a href=&quot;https://it.malwarebytes.com/&quot;&gt;Malwarebytes&lt;/a&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;a href=&quot;http://www.bleepingcomputer.com/download/adwcleaner/&quot;&gt;AdwCleaner&lt;/a&gt;&lt;/strong&gt;.
Questi due software io li chiamo &lt;em&gt;antibiotici ad ampio spettro&lt;/em&gt; proprio perchè fanno questo lavoro: cercano di togliere qualsiasi malware e quindi riescono a togliere più schifezze rispetto ad un antivirus normale.&lt;/p&gt;
&lt;p&gt;Io vi consiglio di iniziare con Malwarebytes. &lt;a href=&quot;http://download.cnet.com/malwarebytes-anti-malware/windows.html?hlndr=1&amp;#x26;part=dl-x&amp;#x26;lang=it&quot;&gt;Scaricatelo&lt;/a&gt;, installatelo (non c’è bisogno della versione premium), aggiornate il suo database e infine fate partire una scansione completa. Tutti questi passi dovrebbero essere semplici e quindi non mi dilungo troppo.
&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/mbam-1470564058773.png&quot; alt=&quot;Malwarebytes&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finita la scansione, probabilmente avrà trovato qualcosa, seguite i passi e rimuovete ciò che ha trovato. Infine vi chiederà di riavviare il PC. Fatelo.&lt;/p&gt;
&lt;p&gt;Ora è il momento del secondo software: &lt;strong&gt;AdwCleaner&lt;/strong&gt;.
Anche qui i passi sono semplici. &lt;a href=&quot;http://www.bleepingcomputer.com/download/adwcleaner/&quot;&gt;Scaricatelo&lt;/a&gt;, installatelo e infine avviatelo.
&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/adwcleaner_001-1470564066850.jpg&quot; alt=&quot;AdwCleaner&quot;&gt;
La schermata è molto semplice: premete per prima cosa su &lt;em&gt;Scan&lt;/em&gt; per avviare la scansione. Poi, una volta concluso, premete su &lt;em&gt;Clean&lt;/em&gt; per avviare la pulizia. Infine vi chiederà di riavviare il PC. Anche in questo caso fate come vi dice.&lt;/p&gt;
&lt;h2&gt;Un po’ di esperienza non guasta mai&lt;/h2&gt;
&lt;p&gt;A questo punto spero che i vostri problemi siano finiti. Se invece il vostro malware è ancora lì allora è il caso di &lt;strong&gt;chiamare un tecnico&lt;/strong&gt; perchè i tool semplici da utilizzare sono finiti e c’è bisogno di una mano esperta. Tutto quello che potete fare è salvare il salvabile e alzare la cornetta per chiedere assistenza.&lt;/p&gt;
&lt;h2&gt;Extrema ratio&lt;/h2&gt;
&lt;p&gt;In realtà c’è ancora una &lt;em&gt;piccola&lt;/em&gt; cosa che potete fare da soli, anche se è abbastanza pericolosa: potete &lt;strong&gt;tentare il ripristino completo&lt;/strong&gt; del vostro PC.
Nel corso degli anni il ripristino del PC è diventato un processo molto semplice e secondo me è un passo che è diventato alla portata di tutti.&lt;/p&gt;
&lt;p&gt;La cosa che dovete fare prima di tutto è &lt;strong&gt;salvare i vostri dati&lt;/strong&gt;, e per salvare intendo su un Hard Disk esterno, unità rimovibile come una chiavetta USB. Insomma salvateli fuori dal PC per essere sicuri di non fare danni.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/qindows_10_ripristino-1470564126930.png&quot; alt=&quot;Reimposta il PC - Windows 10&quot;&gt;&lt;/p&gt;
&lt;p&gt;Se avete Windows 10 i passi sono semplici: andate in &lt;em&gt;Impostazioni&lt;/em&gt; &gt; &lt;em&gt;Aggiornamento e sicurezza&lt;/em&gt; &gt; &lt;em&gt;Reimposta il PC&lt;/em&gt; &gt; &lt;em&gt;Per iniziare&lt;/em&gt; e puoi scegliere tra queste opzioni:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mantieni i miei file&lt;/strong&gt;: magari provate per prima cosa questa opzione. In questo modo i vostri dati sono al sicuro, ma Windows 10 verrà ripristinato e verranno cancellate le vostre applicazioni.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ripristina le impostazioni del produttore&lt;/strong&gt;: questa opzione è la più efficace perchè rende il vostro PC come nuovo.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rimuovi tutto&lt;/strong&gt;: scegliete questa opzione nel caso non trovaste la voce precedente.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusioni&lt;/h2&gt;
&lt;p&gt;Spero che questa guida vi abbia aiutato a risolvere il vostro problemino da soli… Alla fine c’è anche una bella soddisfazione a risolvere i problemi senza l’aiuto di nessuno, no :)?
Alla prossima!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Benvenuti!]]></title><description><![CDATA[Eccomi qui, sull’Eurocity diretto per la Svizzera, ovviamente fermo a causa dei lavori alla stazione di Monza. Proprio per questo motivo ho…]]></description><link>https://www.mattianatali.it/it/benvenuti/</link><guid isPermaLink="false">https://www.mattianatali.it/it/benvenuti/</guid><pubDate>Wed, 03 Aug 2016 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Eccomi qui, sull’Eurocity diretto per la Svizzera, ovviamente fermo a causa dei &lt;a href=&quot;http://www.trenord.it/it/media-news/avvisi/linea-chiasso-como-monza-milano.aspx&quot;&gt;lavori alla stazione di Monza&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Proprio per questo motivo ho deciso di impiegare il mio tempo che passo sui treni a scrivere questo mio piccolo blog (e anche a crearlo).&lt;/p&gt;
&lt;p&gt;Non ho ancora ben deciso cosa e quanto scriverò. Probabilmente molti articoli saranno delle guide per risolvere i milioni di problemi che ogni tanto risolvo a chi mi “ingaggia” come tecnico informatico. Oppure altro, davvero non lo so ancora. Per ora mi sono divertito a creare questo piccolo blog. Ora mancano solo i contenuti! :)&lt;/p&gt;</content:encoded></item></channel></rss>