<?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[Mattia Natali's Blog]]></title><description><![CDATA[My technical personal blog]]></description><link>https://www.mattianatali.it</link><generator>GatsbyJS</generator><lastBuildDate>Sat, 14 Nov 2026 21:00:44 GMT</lastBuildDate><item><title><![CDATA[Six things I wish I knew before becoming an Engineering Manager]]></title><description><![CDATA[I have always worked as an individual contributor in a team. I see a continuous pattern: I start as an Engineer in a company, but sooner or…]]></description><link>https://www.mattianatali.it/en/things-i-wish-i-knew-before-becoming-engineering-manager/</link><guid isPermaLink="false">https://www.mattianatali.it/en/things-i-wish-i-knew-before-becoming-engineering-manager/</guid><pubDate>Mon, 08 Apr 2024 08:50:08 GMT</pubDate><content:encoded>&lt;p&gt;I have always worked as an individual contributor in a team. I see a continuous pattern: I start as an Engineer in a company, but sooner or later I end up leading the team, taking tough decisions that nobody wants to take, assuming accountability for the good and bad, and people outside the team see me as a go-to-person.&lt;/p&gt;
&lt;p&gt;I start thinking: maybe I can contribute more if I manage people and not just code. Instead of just starting from scratch if I change jobs, why don’t I start directly as an Engineering Manager?&lt;/p&gt;
&lt;p&gt;So here I am: I’ve been promoted as an Engineering Manager. Congratulations!&lt;/p&gt;
&lt;p&gt;I have been an Engineering Manager for a while now, and I want to share something I wish I had known earlier.&lt;/p&gt;
&lt;h2&gt;Having extremely good technical skills and business acumen is not enough anymore&lt;/h2&gt;
&lt;p&gt;I think my biggest skill is to learn quickly: if you are good at it, you can solve any technical problems. Engineers are very lucky for this: there’s an abundance of documentation on the Internet. You can literally learn everything without spending any penny, you just want to learn: you don’t need to beg anyone to get information. If you are working in good companies, also the internal processes and knowledge are open.&lt;/p&gt;
&lt;p&gt;So you can grow without relying too much on people. At least until Senior Software Engineer, then you have to sharpen your influential skill to become a Staff Software Engineer.&lt;/p&gt;
&lt;p&gt;But if you are on the Manager path, your team is your most valuable asset for growth. Then you should “expand your influence” as soon as possible.&lt;/p&gt;
&lt;p&gt;I learned it the hard way during the performance check-in. I spent a whole year keeping my team engaged and keeping up with deliverables even though we were understaffed. This means I also contributed as an Individual Contributor.&lt;/p&gt;
&lt;p&gt;I was happy about my performance: I am an Engineering Manager that can be an Individual Contributor when the company needs it. I’m exceeding expectations, right?&lt;/p&gt;
&lt;p&gt;But my hard work as an individual contributor was almost worthless during the performance check-in. And it definitely did not help me in my career path.&lt;/p&gt;
&lt;p&gt;I was quite upset the next day, but I learned not to bother too much about something that I can’t change (the company game rules), it’s always better to focus on things I can change (my behaviors).&lt;/p&gt;
&lt;p&gt;So don’t be like me: if you are a Manager, you need a team, and possibly more than one, and the more people who know you, the better it is.&lt;/p&gt;
&lt;h2&gt;You have to give up the most joyful thing in the job&lt;/h2&gt;
&lt;p&gt;If you were previously a Software Engineer for several years and you have survived, it likely means you love coding. Coding is hard and also stressful, especially when you have tight deadlines.&lt;/p&gt;
&lt;p&gt;However, the dopamine you receive after finishing a task, solving a complex problem, or seeing your work used by customers is priceless! I love it, and I also love building stuff. The more experience you gain as a Software Engineer, the less you get stuck, so you also feel you can achieve &lt;strong&gt;anything&lt;/strong&gt;. This boosts the self-esteem of the Engineer a lot.&lt;/p&gt;
&lt;p&gt;Such joy and happiness are harder to find if you are a Manager.&lt;/p&gt;
&lt;p&gt;Every task in the backlog should be done by your reports. And your reports are humans; humans are lazy by nature. If you are lucky, you find engineers who combat laziness by automating stuff and still doing the hard stuff because they enjoy it. But you usually have engineers who have any sort of hiccups: they spend time on something not required in the task, they have personal issues, they are not convinced about the task itself, they do not follow what the team agreed, etc.&lt;/p&gt;
&lt;p&gt;So you need to deliver through people: you always have this level of indirection that makes things more complicated. And this is stressful; you won’t have the same dopamine level as you get as an individual contributor, for sure.&lt;/p&gt;
&lt;p&gt;Now I’m trying to rewire my brain to find joy in something I paid little attention to before:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I’m happy when I have a meeting with some agreed action points.&lt;/li&gt;
&lt;li&gt;I’m happy when I see the sprint working as expected and my reports finding solutions autonomously.&lt;/li&gt;
&lt;li&gt;I’m happy when I have 1:1s and they are happy with how the team is working, despite the environment around us not being that good.&lt;/li&gt;
&lt;li&gt;I’m happy when I see a graduate/reporter growing and taking me as a mentor, recognizing my effort.&lt;/li&gt;
&lt;li&gt;I’m happy when I see different teams/clients having the same context and working together to build something very big.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, there are a lot of opportunities for happiness here. But you always need to engage people, and sometimes the outcome is not tangible. So you need to practice some “mindful” techniques to appreciate.&lt;/p&gt;
&lt;p&gt;Sometimes I really need to speak to myself: “Hey! You have tons of things. I know you’re upset you spent 1 hour explaining a trivial thing to someone else. But now the other guy knows more, and he will be quicker next time. Enjoy the compound interest in the upcoming days.”
This is what I’m doing to enjoy my managerial path. The more I’m on it, the less I need to speak to myself to feel the joy. As I said, this is needed to rewire your brain to enjoy your new job.&lt;/p&gt;
&lt;p&gt;I’m sure there are people who naturally feel it. But if you don’t, just give “mindful” techniques a try.&lt;/p&gt;
&lt;h2&gt;To succeed, you need people&lt;/h2&gt;
&lt;p&gt;It’s very tempting to do the task by yourself, it’s certainly easier doing that: talking to someone, explain what to do, convince him it’s the right guy to do it, commit him doing that in a timely fashion takes a lot of time…
So… Why do I need to take that path instead of doing by myself?
Because it’s not scalable, you can’t do everything by yourself. The quicker you understand it, the lesser pain you get.
I learned the hard way: I was complaining with my product owner about I can’t take everything by myself, things started to slip out of my hands, he interrupted me abruptly and he said: “you have a whole team at your disposal, make them work!“.&lt;/p&gt;
&lt;p&gt;That was my a-ha moment! I was too focused on myself and I wasn’t exploiting my team as I should. From that day, I decided to spend more effort on others than myself. Was it easy? No, because the temptation of returning to the old bad habit was high… But I knew it couldn’t work in the old way.&lt;/p&gt;
&lt;p&gt;In the end, I was able to manage my team effectively at its full potential. Then, we had an understaffing problem, but at least no one complained about me underutilizing my resources 😅.&lt;/p&gt;
&lt;h2&gt;There is no best technique to manage people&lt;/h2&gt;
&lt;p&gt;Managing people to craft software is completely different from crafting by yourself: writing software requires expertise, and this experience you gain is ubiquitous. If you write good TypeScript code, you will likely be able to write good code even in other languages. Best practices and debugging techniques are still the same and will remain the same over the years.&lt;/p&gt;
&lt;p&gt;But people are a completely different beast; every person is unique. What works with one of your reports can completely put off another one. Mentoring a junior is different from mentoring a senior.&lt;/p&gt;
&lt;p&gt;If you are working in an international environment, you’ll quickly discover that your managerial skills should adapt to different cultures.&lt;/p&gt;
&lt;p&gt;For example, Nordic people don’t like to work if one of the team members is not fully convinced. People from Mediterranean areas like to be in a friendly environment and are more prone to take action based on friendship rather than the manager’s authority. They enjoy chit-chat. On the other hand, people from Germany hate chit-chat. Europeans are more prone to express when something is wrong, while Americans tend to say that everything is good even when it’s not. Indian people often say they understand what you said, even if they don’t.&lt;/p&gt;
&lt;p&gt;There is a ton of information out there to learn about these multicultural dynamics. It gives you a good starting point, but then you face the reality where you quickly understand that it won’t work because every person is different and can differ completely from what you learned.&lt;/p&gt;
&lt;p&gt;So what’s the solution? Just stay silent.&lt;/p&gt;
&lt;p&gt;Listen to your reports in 1:1s. You can learn how they see their jobs, how they think. Watch them work, observe when and how they get angry, when they are happy. Understand what they care about and what they don’t.
Then you can start to talk, assign them tasks, and involve them in the project based on what you have learned.&lt;/p&gt;
&lt;p&gt;This is the best way to get things done with them. I’ll try to write other blog posts on this topic because I know there’s much more to say here.&lt;/p&gt;
&lt;h2&gt;You need to be empathetic to be a good manager&lt;/h2&gt;
&lt;p&gt;Being empathetic means “showing an ability to understand and share the feelings of another”, and I believe this is mandatory to be a good manager.&lt;/p&gt;
&lt;p&gt;If some of my ex-colleagues are reading what I’ve just written, they are probably laughing at me: “C’mon, you are the least empathetic person I know!“. I’m sure this is what they are thinking.
And they are right! But I don’t want to deny it, I’m fully aware that my worst managerial mistakes have all had the same root: lack of empathy.&lt;/p&gt;
&lt;p&gt;I will write about the mistakes I made so you don’t have to make them in order to learn.&lt;/p&gt;
&lt;p&gt;What can you do if you are an emotionless ice block like myself? You can still learn to be empathetic. Maybe you won’t feel the same emotions just when your interlocutor talks. But you can ask yourself, “What feelings did your report experience when they talked to you? Why is the person feeling that way? If I do X, can they feel better?“. If you are not an empathetic person, it is difficult to express empathy and derive empathetic action points directly from the conversation, but you don’t have to make them on the spot! You can just digest offline what you heard and then come back later.&lt;/p&gt;
&lt;h2&gt;It’s your responsibility to have difficult conversations as a manager&lt;/h2&gt;
&lt;p&gt;It is your duty to have difficult conversations that nobody wants to have.
These conversations may involve addressing performance issues, providing constructive feedback, or resolving conflicts within the team.&lt;/p&gt;
&lt;p&gt;While these conversations can be uncomfortable, they are crucial for the growth and development of both individuals and the team as a whole. By addressing these issues directly and honestly, you can create a more productive and harmonious work environment, fostering personal and professional growth for everyone involved.&lt;/p&gt;
&lt;p&gt;Unfortunately, you can’t delegate those to someone else. So, if you are not comfortable with having difficult conversations, you need to work on improving your skills in this area.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope this post has given you some insights into the challenges and rewards of transitioning from an individual contributor to a manager. While the transition can be challenging, it can also be incredibly rewarding. By focusing on building strong relationships with your team, embracing new ways of working, and developing your leadership skills, you can become an effective and successful manager.&lt;/p&gt;
&lt;p&gt;If you are considering making the switch, I encourage you to take the time to reflect on your strengths and weaknesses, and consider how you can leverage your skills and experience to excel in your new role.&lt;/p&gt;
&lt;p&gt;Remember, it’s okay to make mistakes along the way, as long as you are willing to learn from them and grow as a leader.&lt;/p&gt;
&lt;p&gt;See you in the next post!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to store secrets in public repositories]]></title><description><![CDATA[We all feel this pain sooner or later: you are working hard on your git repository. For whatever reason, you change the PC but you still…]]></description><link>https://www.mattianatali.it/en/store-secrets-in-public-repositories/</link><guid isPermaLink="false">https://www.mattianatali.it/en/store-secrets-in-public-repositories/</guid><pubDate>Sun, 27 Nov 2022 08:04:12 GMT</pubDate><content:encoded>&lt;p&gt;We all feel this pain sooner or later: you are working hard on your git repository. For whatever reason, you change the PC but you still want to work on your project.
So you download the repo using &lt;code class=&quot;language-text&quot;&gt;git clone&lt;/code&gt;. You’re ready to go, but then you’re stuck because you don’t remember the secrets that you put in your &lt;code class=&quot;language-text&quot;&gt;.gitignore&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Luckily now there’s a solution for that. And it’s called &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 will encrypt your secrets before pushing your changes on your remote branch, and it decrypts them when you download from it. So after you set it up, everything is completely transparent. You will forget to have secrets in your repo!&lt;/p&gt;
&lt;h2&gt;Bootstrap&lt;/h2&gt;
&lt;p&gt;To start with it, you need to install it. On Mac you can run the following command in the terminal after you installed the package manager &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;Then, you need to go to your public repository where you want to put secrets. And initialize &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;Add secrets&lt;/h2&gt;
&lt;p&gt;Now you need to add the &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt; file in the repository’s root folder. In this file, you declare the files and folders you want to keep secret.
This is an example of &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt; file&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;# Make the file .env secret&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;# Make all files that ends with .key secret&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;# Make all the files contained in secretdir folder secret&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;After&lt;/strong&gt; you created the &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt; file, you can put the secrets in the place you have just declared. If you put the files before the &lt;code class=&quot;language-text&quot;&gt;.gitattribute&lt;/code&gt;, your secrets won’t be encrypted!
Before committing anything, you can have a confirmation that files will be encrypted using &lt;code class=&quot;language-text&quot;&gt;git-crypt status&lt;/code&gt; command&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;# Show whether files are encrypted or not&lt;/span&gt;
git-crypt status

&lt;span class=&quot;token comment&quot;&gt;# Show encrypted files only&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;# Show unencrypted files only&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;If a file was previously there, it won’t be encrypted. You need to run the command &lt;code class=&quot;language-text&quot;&gt;git-crypt status -f&lt;/code&gt;. I repeat myself: if you’re using this command, it means the file was already in your repo in cleartext.
So you need to rotate the secrets that are in that files. Otherwise, it’s very easy for an attacker to see the secrets just by looking at previous commits.&lt;/p&gt;
&lt;p&gt;Now you can commit and push. You’ll see only some encrypted binary files in your public repository! You’re able to see them locally.&lt;/p&gt;
&lt;h2&gt;Moving the symmetric key to another device&lt;/h2&gt;
&lt;p&gt;So good so far… But if you clone the repository elsewhere, you will download the encrypted files. So how can we decrypt the files again?
To answer this question we need to reveal some magic. &lt;code class=&quot;language-text&quot;&gt;git-crypt&lt;/code&gt; decrypt files using a symmetric key.&lt;/p&gt;
&lt;p&gt;During the initialization with &lt;code class=&quot;language-text&quot;&gt;git-crypt init&lt;/code&gt;, it created the symmetric key and he put it in &lt;code class=&quot;language-text&quot;&gt;&amp;lt;YOUR_REPO_PATH&gt;/.git-crypt/keys/default&lt;/code&gt;.
You can easily export it with this command&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;with this key you are able to decrypt also on your other devices. So keep it secure.
To decrypt a repository protected with &lt;code class=&quot;language-text&quot;&gt;git-crypt&lt;/code&gt; you can use the command&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;Using GPG keys&lt;/h2&gt;
&lt;p&gt;I know what you’re thinking: “Come on… I have 30+ repositories. I can’t store and move the keys for every repo! There should be an easier way to handle them.”. There is, indeed!&lt;/p&gt;
&lt;p&gt;You can use your GPG key to unlock your repository. If you don’t have one, you can follow the &lt;a href=&quot;https://docs.github.com/en/authentication/managing-commit-signature-verification/generating-a-new-gpg-key&quot;&gt;Github guide to create the GPG key&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All you need to do is to allow your GPG key to decrypt the 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;# From now on, you&apos;re able to unlock using &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;To find your GPG key, you can use the following command. I’m assuming you have already installed &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;Then, if you clone your repo elsewhere, you can unlock it with&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 will be smart enough to look into your machine for the GPG key. If it finds it, it will decrypt everything!&lt;/p&gt;
&lt;h3&gt;How the GPG mode works&lt;/h3&gt;
&lt;p&gt;… But how does it work? I assume you don’t like magic.&lt;/p&gt;
&lt;p&gt;When you write&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; will encrypt the symmetric key using your public GPG key, and it will commit into your repo in &lt;code class=&quot;language-text&quot;&gt;.git-crypt/keys/default/0&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Then, when you write&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; will find your GPG key in your Mac, it will decrypt the symmetric key that it saved in &lt;code class=&quot;language-text&quot;&gt;.git-crypt/keys/default/0&lt;/code&gt; using your private GPG key. Finally, it will decrypt the secrets using the symmetric key just decrypted.&lt;/p&gt;
&lt;p&gt;I hope I helped you to find a good way to manage the secrets in your repositories. I’m extensively using it both in my hobby projects and at work. I’m so happy with it that I wanted to share it with you.&lt;/p&gt;
&lt;p&gt;See you!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to build an Air Quality Sensor using a Raspberry Pi]]></title><description><![CDATA[I live in Milan and I was wondering how much the air is polluted. So I started learning how to build an air quality sensor and how to…]]></description><link>https://www.mattianatali.it/en/air-quality-sensor-raspberry-pi/</link><guid isPermaLink="false">https://www.mattianatali.it/en/air-quality-sensor-raspberry-pi/</guid><pubDate>Sun, 17 Jan 2021 16:40:20 GMT</pubDate><content:encoded>&lt;p&gt;I live in Milan and I was wondering how much the air is polluted. So I started learning how to build an air quality sensor and how to integrate it in my Home Assistant. Then I regretted it because I understood the Milan air quality is very awful! It’s not breaking news, but it’s different having your air quality sensor that analyzes the air you’re breathing instead of hearing the news on TV that says: “Milan had stopped the traffic to lower the emissions because it’s above the limits”. Then I moved the sensor to Serina, a little town lost in the mountains, where the air quality is much better!&lt;/p&gt;
&lt;p&gt;Now I want to share my learning: how to create the same air quality sensor I built, and how to read this data into Home Assistant just like this&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 - Air Quality and WiFi signal&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;The hardware we need&lt;/h2&gt;
&lt;p&gt;To reach this goal we need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 Raspberry Pis and related power adapter and SD Cards: one will be the air quality sensor (&lt;em&gt;Rpi Sensor&lt;/em&gt;), the other one will be our receiver with Home assistant (&lt;em&gt;Rpi Hub&lt;/em&gt;). You also need a WiFi USB dongle if the air quality Raspberry Pi doesn’t have built-in.&lt;/li&gt;
&lt;li&gt;The air quality sensor SDS011: this hardware is commonly shipped with the USB dongle, so it’s easy to attach to the Raspberry Pi.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The software we use&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mosquitto.org&quot;&gt;Mosquitto&lt;/a&gt;: open source message broker that implements MQTT protocol. &lt;a href=&quot;https://en.wikipedia.org/wiki/MQTT&quot;&gt;MQTT protocol&lt;/a&gt; is widely used in IoT system because it performs very well under extreme conditions like weak WiFi signal, and very limited WiFi bandwidth.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.home-assistant.io&quot;&gt;Home Assistant&lt;/a&gt;: open-source home automation system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m currently using a Mac, so all the commands you see will work on Mac or Linux terminal. If you are using Windows you have two options:&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;Install WSL&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Use a virtual machine with Linux installed using &lt;a href=&quot;https://www.virtualbox.org&quot;&gt;VirtualBox&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What we learn&lt;/h2&gt;
&lt;p&gt;Someone can say: “Hey! You are a liar! You’re not building an air quality sensor, you’ve just bought that!“. Maybe he is right, but I think the sensor is just the tip of the iceberg. We have a lot of work to extract the data from the sensor and make them useful.&lt;/p&gt;
&lt;p&gt;The overall architecture we want to build is shown in the next figure&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;Architecture&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;So through this tutorial, we will learn:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to create a program that extracts data from the sensor. We will write it in &lt;a href=&quot;https://golang.org&quot;&gt;Go&lt;/a&gt;. To simplify the development we will learn how to cross-compile the binary for ARM architecture using our PC/Mac that has a different architecture than the Raspberry Pi.&lt;/li&gt;
&lt;li&gt;How to automatically connect the Raspberry Pi with the sensor to the WiFi with the strongest signal, how to automatically reconnect if we have some outage.&lt;/li&gt;
&lt;li&gt;How to start automatically the Go program if there are some issues.&lt;/li&gt;
&lt;li&gt;How to pass data using MQTT protocol and how to digest those inside &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;Now that we have the overall picture in our minds, let’s get started!&lt;/p&gt;
&lt;h2&gt;Build the Raspberry Pi with the air quality sensor&lt;/h2&gt;
&lt;p&gt;Let’s start with the Raspberry Pi with the air quality sensor.
&lt;strong&gt;The first thing we need is &lt;a href=&quot;https://www.raspberrypi.org/documentation/installation/&quot;&gt;install the Raspberry Pi OS Lite&lt;/a&gt;&lt;/strong&gt;. We just need the lite because we just use the terminal and &lt;a href=&quot;https://www.raspberrypi.org/documentation/remote-access/ssh/README.md&quot;&gt;we will connect using SSH&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now we are ready to attach the SD card to the Raspberry, attach the ethernet port to connect it to our home network for the first setup, attach the SDS011 sensor using the USB. The Raspberry Pi should automatically detect it.&lt;/p&gt;
&lt;p&gt;Let’s check it out: connect to this Raspberry Pi using via SSH using &lt;code class=&quot;language-text&quot;&gt;ssh pi@&amp;lt;RPI_SENSOR_IP&gt;&lt;/code&gt;, with password &lt;code class=&quot;language-text&quot;&gt;raspberry&lt;/code&gt;. Change &lt;code class=&quot;language-text&quot;&gt;&amp;lt;RPI_SENSOR_IP&gt;&lt;/code&gt; with the Raspberry Pi sensor IP address. I usually find its IP address through my router control panel, or just type on the terminal &lt;code class=&quot;language-text&quot;&gt;ping raspberrypi.local&lt;/code&gt;. You should find something like this&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;The IP you see there, it’s the IP you’re looking for.&lt;/p&gt;
&lt;p&gt;Now that we are connected via SSH, we type &lt;code class=&quot;language-text&quot;&gt;lsusb&lt;/code&gt; to check the Raspberry Pi sees the sensor&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;You should see some Chinese names like “QinHeng Electronics HL-340”. This is our sensor. If we type &lt;code class=&quot;language-text&quot;&gt;ls /dev/ttyUSB*&lt;/code&gt; we should see &lt;code class=&quot;language-text&quot;&gt;/dev/ttyUSB0&lt;/code&gt; as response: this is our channel to communicate with the sensor.&lt;/p&gt;
&lt;h3&gt;Compile the Go program to fetch data&lt;/h3&gt;
&lt;p&gt;Now we should create a program that fetches data from &lt;code class=&quot;language-text&quot;&gt;/dev/ttyUSB0&lt;/code&gt; created by the sensor and publishes those on an MQTT topic.&lt;/p&gt;
&lt;p&gt;If you don’t know MQTT, don’t worry: &lt;a href=&quot;https://en.wikipedia.org/wiki/MQTT&quot;&gt;Wikipedia explains briefly what it is&lt;/a&gt;. This is my explanation: it’s a lightweight protocol that relies on topics. Someone publish something on a topic, like the air quality sensor data. &lt;strong&gt;Someone else can subscribe to that topic, in that way he’s notified whenever there’s new data on that topic&lt;/strong&gt;. Maybe you are more comfortable with the HTTP protocol, but I think that MQTT is best suited for this kind of application.&lt;/p&gt;
&lt;p&gt;I made this application for you in Go. &lt;a href=&quot;https://github.com/matitalatina/sds011-mqtt&quot;&gt;You can find it on GitHub&lt;/a&gt;.
We should change the configuration that is in &lt;code class=&quot;language-text&quot;&gt;cmd/sensor/main.go&lt;/code&gt;, the file should be like this&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;Change the &lt;code class=&quot;language-text&quot;&gt;Topic&lt;/code&gt; with a string of your choice. I had his convention &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;. The topic is just a string that refers to where we want to publish the data and then where we want to subscribe to fetch them.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;SensorPortPath&lt;/code&gt;: should be the same, it’s where we fetch the sensor data.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;CycleMinutes&lt;/code&gt;: Change it if 1 sample/minute is too much for you. You can’t put less than 1 minute.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MqttBroker&lt;/code&gt;: You should put the IP address of the Raspberry Pi where we put Mosquitto, the message broker that handles our MQTT topics. I suggest you use the same Raspberry Pi where you install also Home Assistant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are curious, you can see the implementation 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;Now it’s time to cross-compile it for our Raspberry Pi!&lt;/strong&gt; I’m expecting that you have downloaded this source code on your Mac/PC and you have &lt;a href=&quot;https://golang.org/doc/install&quot;&gt;Go installed&lt;/a&gt;. Then, we need to know what type of architecture your Raspberry Pi has.&lt;/p&gt;
&lt;p&gt;Launch this command on the Raspberry Pi: &lt;code class=&quot;language-text&quot;&gt;cat /proc/cpuinfo&lt;/code&gt;
You should see something like this&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;My raspberry has &lt;code class=&quot;language-text&quot;&gt;ARMv6&lt;/code&gt;, so I need to compile for that type. If you have a Raspberry Pi 2 you should see &lt;code class=&quot;language-text&quot;&gt;ARMv7&lt;/code&gt;.
I created a &lt;a href=&quot;https://github.com/matitalatina/sds011-mqtt/blob/main/Makefile&quot;&gt;Makefile&lt;/a&gt; to simplify the cross-compilation. Makefile is very common on Linux, it’s used to simplify common tasks. If you don’t know about it I suggest reading &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;If you have &lt;code class=&quot;language-text&quot;&gt;ARMv6&lt;/code&gt;, just type &lt;code class=&quot;language-text&quot;&gt;make build-arm6&lt;/code&gt; in the folder where you downloaded my &lt;a href=&quot;https://github.com/matitalatina/sds011-mqtt&quot;&gt;GitHub Project&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If you have &lt;code class=&quot;language-text&quot;&gt;ARMv7&lt;/code&gt;, type &lt;code class=&quot;language-text&quot;&gt;make build-arm&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we should have a binary file located in &lt;code class=&quot;language-text&quot;&gt;dist/pm-sensor&lt;/code&gt;. We should transfer to our Raspberry Pi sensor. We will use the command &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;As usual, change &lt;code class=&quot;language-text&quot;&gt;&amp;lt;RPI_SENSOR_IP&gt;&lt;/code&gt; with the real IP, but leave the colon at the end. This means we’re going to place the &lt;code class=&quot;language-text&quot;&gt;pm-sensor&lt;/code&gt; in the home folder of our user &lt;code class=&quot;language-text&quot;&gt;pi&lt;/code&gt; inside the Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Now we can enter via SSH in the Raspberry Pi, we should see our new binary file called &lt;code class=&quot;language-text&quot;&gt;pm-sensor&lt;/code&gt;. If we try to run, it fails&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;# Add execute permission to the 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;# Start it&lt;/span&gt;
./pm-sensor
&lt;span class=&quot;token comment&quot;&gt;# This is the program output&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;it’s complaining because it can’t connect to the MQTT broker to publish the sensor data. It is right, we don’t have prepared the other Raspberry Pi.&lt;/p&gt;
&lt;p&gt;Now we leave the sensor for a moment, and we’ll work on the Raspberry Pi that is inside our home, we call it &lt;em&gt;Hub&lt;/em&gt; for simplicity.&lt;/p&gt;
&lt;h2&gt;Add mosquitto to the Raspberry Pi Hub&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Now it’s time to set up the “receiver” part of the architecture.&lt;/strong&gt; So we need the other Raspberry Pi with a clean Raspberry OS installed.&lt;/p&gt;
&lt;p&gt;Then &lt;a href=&quot;https://mosquitto.org/blog/2013/01/mosquitto-debian-repository/&quot;&gt;we install 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;The new version of Mosquitto &lt;a href=&quot;https://mosquitto.org/blog/2020/12/version-2-0-0-released/&quot;&gt;added the authentication by default for very good reasons&lt;/a&gt;. I started this project when Mosquitto didn’t have authentication by default, so my script doesn’t support it, yet. To enable support for anonymous users we should add these two lines in the 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;The first one enables the incoming messages from different hosts to the port 1883. This is required because our sensor is not on this Rpi Hub. The second one enables anonymous users.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We make sure that Mosquitto is working&lt;/strong&gt;, it takes the new config file, and &lt;strong&gt;it’s starting on Raspberry boot&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;Now we have the MQTT Broker up and running!&lt;/strong&gt; It means that our sensor can send the data to this broker. Let’s test if our sensor can send data to this 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;# Connect to Raspberry Pi sensor and type the 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;# Start the Go program to send air quality data&lt;/span&gt;
./pm-sensor
&lt;span class=&quot;token comment&quot;&gt;# This is the expected output (1 line every one minute)&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;This is a really good sign! It means we can fetch data from our quality sensor and we can send them to our MQTT broker that it’s installed on our Raspberry Pi Hub!&lt;/p&gt;
&lt;p&gt;To double-check it, &lt;strong&gt;we leave the program active&lt;/strong&gt; and we subscribe on the topic we are sending data to&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;# We connect to 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;# We subscribe to our 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;# We should see an output like this&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;You should change &lt;code class=&quot;language-text&quot;&gt;&amp;lt;RPI_HUB_IP&gt;&lt;/code&gt; with the IP of your Hub and replace &lt;code class=&quot;language-text&quot;&gt;home/serina/edge-rpi/air-quality&lt;/code&gt; with the topic you have inserted in the Go configuration inside the property &lt;code class=&quot;language-text&quot;&gt;Topic&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now we know what our Go program publish on the topic: it sends a JSON file with three properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;PM25&lt;/code&gt;: contains the PM 2.5 expressed 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;PM10&lt;/code&gt;: contains the PM 10 expressed 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;: contains the time in &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601&lt;/a&gt; when it fetched the data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Recap&lt;/h3&gt;
&lt;p&gt;Congratulation! &lt;strong&gt;Now we have a sensor that fetches air quality data and sends them to an MQTT broker, every application that wants this data should subscribe to the chosen topic&lt;/strong&gt; and that’s it! Are we finished?&lt;/p&gt;
&lt;p&gt;Well… Not exactly.&lt;/p&gt;
&lt;p&gt;We want to put the sensor outside, so we should use the WiFi and detach the Ethernet port. We don’t want to connect to the sensor to start the program. If we put the sensor far away from our router, the sensor should be able to reconnect every time automatically, it should do the same if we restart the router. We have all these issues to fix!&lt;/p&gt;
&lt;p&gt;So let’s pimp up our sensor to make it wireless and smart enough to keep the connection on automatically.&lt;/p&gt;
&lt;h2&gt;Pimp the sensor!&lt;/h2&gt;
&lt;h3&gt;Make the program start automatically&lt;/h3&gt;
&lt;p&gt;The program doesn’t start automatically. We have to connect via SSH and start it with the command &lt;code class=&quot;language-text&quot;&gt;./pm-sensor&lt;/code&gt;. This is very frustrating.&lt;/p&gt;
&lt;p&gt;To reach this goal, &lt;strong&gt;we take leverage of &lt;a href=&quot;https://en.wikipedia.org/wiki/Systemd&quot;&gt;systemd&lt;/a&gt;&lt;/strong&gt;. Systemd is the system and service manager for the Raspberry Pi. Did you notice we have already used systemd in this tutorial? When we started mosquitto we wrote&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;using the command &lt;code class=&quot;language-text&quot;&gt;systemctl&lt;/code&gt; we can start/stop/restart the services on a Linux machine. And we can also start automatically a service on boot if we write &lt;code class=&quot;language-text&quot;&gt;sudo systemctl enable &amp;lt;SERVICE&gt;&lt;/code&gt;. So we need to create a service for our pm-sensor program.&lt;/p&gt;
&lt;p&gt;Luckily it’s very easy: the custom services are stored in the folder &lt;code class=&quot;language-text&quot;&gt;/etc/systemd/system&lt;/code&gt;. So we can add the new service, if we add the file called &lt;code class=&quot;language-text&quot;&gt;pm-sensor.service&lt;/code&gt; in that folder. The content of that file is the following&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;As you can see, the service declaration consists of three sections: &lt;code class=&quot;language-text&quot;&gt;[Unit]&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;[Service]&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;[Install]&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the &lt;code class=&quot;language-text&quot;&gt;[Unit]&lt;/code&gt; section we put a little description of our service and we declare that we want the network up and running before starting it.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;[Service]&lt;/code&gt; declare the type of the service, the name, and the group of the user that should start the script, where the program is located and we define how systemd should behave if the service panics. We want the program to always restart.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;[Install]&lt;/code&gt; defines that this service does not need the graphical user interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Systemd is a very big topic and it deserves a complete book on it. I know this explanation scratches only the surface, but it’s enough for our purposes. But I know you’re very curious! So if you want to dig deeper you can type &lt;code class=&quot;language-text&quot;&gt;man systemd.unit&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;man systemd.service&lt;/code&gt; on your Linux machine. In linux, if you want to know something more just type &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;Now that we have created the service, we need to reload the systemd configuration, start the program, and enable it during startup.&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;We can check if everything is started correctly with the following command&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;# This is the output we got&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;Everything is ok, we should also see the logs of our program.&lt;/p&gt;
&lt;p&gt;We don’t need to start manually the program anymore! But we are still connected via Ethernet, we can’t put our sensor outside our home. Let’s fix it!&lt;/p&gt;
&lt;h3&gt;Add WiFi connection&lt;/h3&gt;
&lt;p&gt;The best way to add the WiFi in the Raspberry Sensor is by &lt;a href=&quot;https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md&quot;&gt;reading the official documentation&lt;/a&gt;, it’s useless to copy-paste. I suggest adding all your WiFi SSID that you have in your home. In this way, you set up the sensor just one time. If you want to move it to another place, it tries to connect to the nearest WiFi access point.&lt;/p&gt;
&lt;p&gt;Be aware that now &lt;strong&gt;the sensor IP address could be changed&lt;/strong&gt;. So remember to get the new address.&lt;/p&gt;
&lt;h3&gt;Keep WiFi persistent&lt;/h3&gt;
&lt;p&gt;Now we can put our sensor outside! It automatically connects to our WiFi and starts our program that fetches the sensor. We should be proud of our work until now… But we realize soon that there’s a problem. We realize it when we reboot our router or we put our sensor too far from it: &lt;strong&gt;the Raspberry Pi doesn’t try to reconnect the WiFi if it loses the connection&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Let’s fix it. I found a little script on the web and I adapted it for our purposes. We create the 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;# Connect to sensor Raspberry Pi&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;# Create the new 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;# Add execution permission on it&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;we put this content inside it&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;# Settings&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Which Interface do you want to check/fix&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;# Which address do you want to ping to see if the network interface is alive?&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;The script should be self-explanatory. We have two variables at the top: &lt;code class=&quot;language-text&quot;&gt;wlan&lt;/code&gt; that you should not change and &lt;code class=&quot;language-text&quot;&gt;pingip&lt;/code&gt; where you put your router IP address.&lt;/p&gt;
&lt;p&gt;The script tries to ping the router, if it reaches the router, everything is fine. If it can’t do it, it disables the WiFi, and then it enables again. It should trigger the reconnection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We need someone that calls this script every minute… &lt;a href=&quot;https://en.wikipedia.org/wiki/Cron&quot;&gt;cron&lt;/a&gt; to the rescue!&lt;/strong&gt; This is the common way to do such things on Linux.&lt;/p&gt;
&lt;p&gt;To add a scheduled job that triggers our script every minute, we need to write &lt;code class=&quot;language-text&quot;&gt;crontab -e&lt;/code&gt; in the terminal. It will open a text editor.
On that page write this stuff&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;This strange syntax can be scary but it’s very easy. The first part, the &lt;code class=&quot;language-text&quot;&gt;* * * * *&lt;/code&gt; indicate when the script should trigger. The last part refers to the script we want to launch.
The scheduled time is always represented by five values. The order of them changes the meaning of those asterisks. From left to right they refer to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minute (0 - 59)&lt;/li&gt;
&lt;li&gt;Hour (0 - 23)&lt;/li&gt;
&lt;li&gt;Day of month (1 - 31)&lt;/li&gt;
&lt;li&gt;Month (1 - 12)&lt;/li&gt;
&lt;li&gt;Day of the week (0 - 6): Sunday to Saturday&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But we put &lt;code class=&quot;language-text&quot;&gt;*&lt;/code&gt;… Not numbers. We added asterisks because it has a special meaning. &lt;code class=&quot;language-text&quot;&gt;*&lt;/code&gt; means “any”. So we wrote: “Please Linux, run the script &lt;code class=&quot;language-text&quot;&gt;/home/pi/check-wifi.sh&lt;/code&gt; every minute of every hour of every day of the month of every day of the week”. Linux is smart enough to understand he should trigger the script every minute from now on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;We have a very robust air quality sensor now!&lt;/strong&gt; We can put it outside our home and no matter what happens, it should keep always the connection as long as it reaches our router WiFi signal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Using &lt;code class=&quot;language-text&quot;&gt;mosquitto_sub&lt;/code&gt; is the only way to see the data from the sensor&lt;/strong&gt;. This is ok only for debugging purposes, we should have a better way to see those data. &lt;strong&gt;&lt;a href=&quot;https://www.home-assistant.io&quot;&gt;Home Assistant&lt;/a&gt; will solve this problem&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Add sensor to Home Assistant&lt;/h2&gt;
&lt;h3&gt;Install and learn Home Assistant&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.home-assistant.io&quot;&gt;Home Assistant&lt;/a&gt; is a great piece of software. If you are a tech enthusiast that loves automating home, I think you have already installed it.&lt;/p&gt;
&lt;p&gt;If you don’t know yet: you can attach smart devices to it and you can create rules to automate things. You can also attach sensors to easily see the data. In other words, if you decide to install it, Home Assistant can become the control center of your home.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Seeing the sensor data in the Home Assistant is our goal here.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As the first step, &lt;a href=&quot;https://www.home-assistant.io/docs/installation/&quot;&gt;we need to install it&lt;/a&gt; on the Raspberry Pi Hub.
Then, I suggest you read the &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/&quot;&gt;configuration manual&lt;/a&gt;. Home Assistant heavily uses &lt;a href=&quot;https://learnxinyminutes.com/docs/yaml/&quot;&gt;YAML files&lt;/a&gt; to install custom sensors like ours.&lt;/p&gt;
&lt;p&gt;Maybe you’re thinking that Home Assistant is overkill for seeing just sensor data. But I think this is only the starting point: I’m sure that in the end, you will have more than 20 devices with a total of 200 sensors attached and dozens of automation that orchestrate everything!&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;So it’s not overkill, it’s only our starting point, trust me 😊.&lt;/p&gt;
&lt;p&gt;Now that we have installed Home Assistant and learned about &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/&quot;&gt;where its configuration is installed&lt;/a&gt;, &lt;strong&gt;it’s time to add our sensor&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Add MQTT integration&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;We need to add the MQTT integration to Home Assistant.&lt;/strong&gt; Go to the Home Assistant portal, it should be exposed on port &lt;code class=&quot;language-text&quot;&gt;8123&lt;/code&gt;. So open the browser and type the URL &lt;code class=&quot;language-text&quot;&gt;http://&amp;lt;RPI_HUB_IP&gt;:8123&lt;/code&gt; where &lt;code class=&quot;language-text&quot;&gt;&amp;lt;RPI_HUB_IP&gt;&lt;/code&gt; is the IP of our Raspberry Pi Hub. Click the cog icon (Configuration) and click on “Add integration”. We can see a huge list of integrations, we are interested in MQTT. So search for that and then it will ask for two mandatory fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Broker: you need to add the Raspberry Pi Hub IP. It’s where we installed Mosquitto, our MQTT broker.&lt;/li&gt;
&lt;li&gt;Port: it’s &lt;code class=&quot;language-text&quot;&gt;1883&lt;/code&gt;. We put that in the mosquitto configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Click submit and now we have linked Home Assistant to our MQTT broker Mosquitto.&lt;/p&gt;
&lt;p&gt;We should see the brand new integration in Configuration -&gt; Integration Tab. We click on configure&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;and then we can listen to our MQTT topic, just to check if Home Assistant can see our data.&lt;/p&gt;
&lt;p&gt;In the section “Listen to a topic”, write down our chosen MQTT topic, click “start listening” and wait at least 1 minute. The wait depends on the configuration you set on our Go program. If you don’t change my value, it should publish one datum per minute.&lt;/p&gt;
&lt;p&gt;If you see the data like the figure below, you have successfully attached Home Assistant to our MQTT Broker!&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;Add air quality sensors through the MQTT platform&lt;/h3&gt;
&lt;p&gt;We know that the values are published on an MQTT topic (you chose the name, mine is &lt;code class=&quot;language-text&quot;&gt;home/serina/edge-rpi/air-quality&lt;/code&gt;). We should create two sensors that subscribe to that topic and extract data. These sensors will be&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Air Quality PM 10.&lt;/li&gt;
&lt;li&gt;Air Quality PM 2.5.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To achieve this goal, we edit the Home assistant &lt;code class=&quot;language-text&quot;&gt;configuration.yaml&lt;/code&gt; file. We need to add these two sensors inside the &lt;code class=&quot;language-text&quot;&gt;sensor:&lt;/code&gt; section.&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;Luckily, the YAML file is very readable. We are using &lt;a href=&quot;https://www.home-assistant.io/integrations/sensor.mqtt/&quot;&gt;MQTT sensor platform&lt;/a&gt;. We restart the Home Assistant.&lt;/p&gt;
&lt;p&gt;You should change &lt;code class=&quot;language-text&quot;&gt;state_topic&lt;/code&gt; with yours. You can also change the &lt;code class=&quot;language-text&quot;&gt;unique_id&lt;/code&gt; with any value, it just need to be unique, of course.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;value_template&lt;/code&gt; is the field where we extract the value from JSON in the topic with the keyword &lt;code class=&quot;language-text&quot;&gt;value_json&lt;/code&gt; and then we take the interesting values &lt;code class=&quot;language-text&quot;&gt;PM10&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;PM25&lt;/code&gt;. Finally, we say that we are interested in a &lt;code class=&quot;language-text&quot;&gt;float&lt;/code&gt; value. All this stuff is surrounded by &lt;code class=&quot;language-text&quot;&gt;{{ }}&lt;/code&gt;: when you see this syntax means we are exploiting the &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/templating/&quot;&gt;template system&lt;/a&gt; that is powered by &lt;a href=&quot;https://www.home-assistant.io/docs/configuration/templating/&quot;&gt;Jinja2&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you want to change the icon of the sensor, I usually &lt;a href=&quot;https://materialdesignicons.com&quot;&gt;use this website&lt;/a&gt;. For example, I search
for a keyword, &lt;code class=&quot;language-text&quot;&gt;fog&lt;/code&gt;, and finally I hover the mouse on the chosen icon. You should prepend the name it appears with &lt;code class=&quot;language-text&quot;&gt;mdi:&lt;/code&gt;. In our example is &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;Add sensors to Home Assistant UI&lt;/h2&gt;
&lt;p&gt;Now we should have two new entities that show air quality. To see them, we should go to configuration -&gt; entities and search for “Air quality”&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;as you can see, it’s quite uncomfortable. It’s better to put those entities on the overview/dashboard page.&lt;/p&gt;
&lt;p&gt;In the Home Assistant, click on overview on the left bar, the three dots on the right, edit dashboard, and finally “Add card” on the bottom. A modal should appear, click on the “Entities” choice.&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;Write the title that you want; in the “entities” section, search for the entities we saw earlier. You should see a preview of the new card at the bottom. When you’re satisfied click “Save” and we’re done!&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;Now we should have this nice card every time we open Home Assistant! If we click on that, we should see also a graph for the last day.&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;Conclusions&lt;/h2&gt;
&lt;p&gt;We finally reach the end of this journey. I hope you’ve learned something new and appreciate the beauty of making an air quality sensor by yourself.&lt;/p&gt;
&lt;p&gt;I would like to tell you more about it: for example, I haven’t explained how to see this data on &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 - Air Quality and WiFi signal&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;or how to see the WiFi SSID and its signal strength directly on 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;I’ll talk about them in other blog posts because this is already very long.&lt;/p&gt;
&lt;p&gt;If you want to be updated, leave your email below and I’ll notify you. Or simply visit my blog from time to time.&lt;/p&gt;
&lt;p&gt;See you!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[JWT authentication with Angular]]></title><description><![CDATA[At work, I had to create a new web portal that should communicate with our backend.
Our frontend framework choice is Angular and our backend…]]></description><link>https://www.mattianatali.it/en/jwt-authentication-angular/</link><guid isPermaLink="false">https://www.mattianatali.it/en/jwt-authentication-angular/</guid><pubDate>Sun, 15 Dec 2019 16:40:20 GMT</pubDate><content:encoded>&lt;p&gt;At work, I had to create a new web portal that should communicate with our backend.
&lt;strong&gt;Our frontend framework choice is Angular and our backend uses the JWT (JSON Web Token) as the authentication system.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So my goal was to integrate that authentication system in Angular to communicate with the backend.
Since this was an Angular project started from scratch, I had the chance to think about how to implement it.&lt;/p&gt;
&lt;h2&gt;Objectives&lt;/h2&gt;
&lt;p&gt;My acceptance criteria were the following ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To get the token, the frontend should call the endpoint &lt;code class=&quot;language-text&quot;&gt;POST auth/login&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;email&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;password&lt;/code&gt;. The backend will reply with &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The frontend should persist both tokens, so the user will be still authenticated even if he closes the browser.&lt;/li&gt;
&lt;li&gt;It should send the accessToken for every authenticated API calls. It sends the token inside the header &lt;code class=&quot;language-text&quot;&gt;X-AUTH-TOKEN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If the backend replies &lt;code class=&quot;language-text&quot;&gt;401 - Unauthorized&lt;/code&gt;, it means that the token is expired. So the frontend should call the endpoint &lt;code class=&quot;language-text&quot;&gt;POST auth/refresh&lt;/code&gt; passing &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt;. If the &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; is valid, the backend replies with new &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; in the response body.
&lt;ul&gt;
&lt;li&gt;After retrieving the new &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt;, it should retry the failed call with the refreshed token.&lt;/li&gt;
&lt;li&gt;If the backend reply again with &lt;code class=&quot;language-text&quot;&gt;401 - Unauthorized&lt;/code&gt; during refresh, it means that the &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; is not valid anymore. We need to logout the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We should handle all this stuff transparently, the developer should not worry too much about that when he implements some class to communicate with the backend.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This flow should be pretty standard for a JWT Auth system. Now let’s think about how to architecture it!&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;I’m expecting from you some knowledge about these topics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.io/&quot;&gt;Angular&lt;/a&gt; and &lt;a href=&quot;https://angular.io/guide/http#intercepting-requests-and-responses&quot;&gt;Angular interceptors&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://rxjs-dev.firebaseapp.com/&quot;&gt;RxJS&lt;/a&gt; that is built-in in Angular &lt;a href=&quot;https://angular.io/guide/http&quot;&gt;HTTP Client&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Architecture&lt;/h2&gt;
&lt;p&gt;I built this JWT integration using &lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;Test Driven Development (TDD)&lt;/a&gt;. So I ended up with easily testable classes that have one single responsibility. This is the beauty of TDD: to simplify testing you &lt;strong&gt;have to&lt;/strong&gt; write good code!&lt;/p&gt;
&lt;p&gt;I built the following classes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt;: it makes the API calls to the backend. In our example, we will implement &lt;code class=&quot;language-text&quot;&gt;auth/login&lt;/code&gt; and &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;: it persists the tokens and keeps the state of the users. We can know whether the users are authenticated or not.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AuthService&lt;/code&gt;: it manages the business logic of our authentication system, it exploits both &lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt; and &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;: it injects the token in every authenticated API calls, also it handles the retry logic when the &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; is expired.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can achieve our acceptance criteria with these classes, now let’s implement them!&lt;/p&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;h3&gt;Interfaces&lt;/h3&gt;
&lt;p&gt;Building a single page application is complex. It handles a lot of different objects and it’s very difficult to keep track of them without a type system. TypeScript adds types to JavaScript and I exploit this as much as I can.
So I always create a folder &lt;code class=&quot;language-text&quot;&gt;/model&lt;/code&gt; that keeps track of all the objects that I create or receive from the backend.
In this tutorial, we will face with these interfaces:&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; is very simple to implement. It just makes the API calls to our 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;You can see &lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt; is quite simple. The only weird thing is the header &lt;code class=&quot;language-text&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/code&gt; that has a special meaning. It’s my way to communicate with &lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt;, I’m saying: “Hey! This is a public API call, you don’t need to inject the token”. I talk about it in more detail later.&lt;/p&gt;
&lt;h3&gt;AuthStore&lt;/h3&gt;
&lt;p&gt;It stores and persists the user credentials. &lt;strong&gt;My implementation is heavily inspired by the Business Logic Component (BLoC) pattern + RxJS&lt;/strong&gt;. This is a new pattern that raises in &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;Dart + Flutter world&lt;/a&gt;. I like it and I ported the concept in Angular.
I don’t want to talk too much about BLoC pattern since there are &lt;a href=&quot;https://www.google.com/search?q=BLoC+Pattern&amp;#x26;oq=BLoC+Pattern&quot;&gt;many articles about it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In a nutshell: I exploit RxJS to create a reactive credential store, anyone is interested in some auth data should subscribe to it. If someone wants to change auth data, he can call the auth methods. Very simple.&lt;/p&gt;
&lt;h4&gt;Generic Store&lt;/h4&gt;
&lt;p&gt;The first thing to do is creating the generic store that handles the state of type &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt;. This is agnostic about the state, so this is an abstract class. This store is simply called &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;As you can see:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It accepts the initial state in the constructor.&lt;/li&gt;
&lt;li&gt;You can change the state calling &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;You can subscribe to state changes by subscribing to &lt;code class=&quot;language-text&quot;&gt;state$&lt;/code&gt; observable.&lt;/li&gt;
&lt;li&gt;You can get the current state one-shot by &lt;code class=&quot;language-text&quot;&gt;state&lt;/code&gt; getter.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The engine of my store is the private &lt;code class=&quot;language-text&quot;&gt;stateSubject$&lt;/code&gt; BehaviorSubject&lt;/strong&gt;. If this is the &lt;a href=&quot;https://www.learnrxjs.io/subjects/behaviorsubject.html&quot;&gt;first time that you see a BehaviorSubject&lt;/a&gt;, think about a stream that has also a “sink”, where you can add a new element in the stream by calling &lt;code class=&quot;language-text&quot;&gt;next&lt;/code&gt; method. BehaviorSubject has also the initial state that you should provide in the constructor.&lt;/p&gt;
&lt;p&gt;Another cool thing about it, you can keep the “sink” private and only expose its observable. I’m exposing only the &lt;code class=&quot;language-text&quot;&gt;state$&lt;/code&gt; variable that is the &lt;code class=&quot;language-text&quot;&gt;Observable&lt;/code&gt; created from &lt;code class=&quot;language-text&quot;&gt;stateSubject$&lt;/code&gt;.
In this way, no one can add an element in this observable except calling &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt; method. In other words, you can only see the changes subscribing &lt;code class=&quot;language-text&quot;&gt;state$&lt;/code&gt; observable, and you can change the store data by &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt; method. The implementation of the store is managed by &lt;code class=&quot;language-text&quot;&gt;stateSubject$&lt;/code&gt; that is not exposed externally.&lt;/p&gt;
&lt;h4&gt;Concrete implementation&lt;/h4&gt;
&lt;p&gt;Now we can create our &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;, the first concrete implementation of the &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;There are a lot of helper methods to simplify the class usage. These are the key points of this class:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s a &lt;code class=&quot;language-text&quot;&gt;Store&lt;/code&gt; subclass, it has &lt;code class=&quot;language-text&quot;&gt;IAuthState&lt;/code&gt; interface as state. &lt;code class=&quot;language-text&quot;&gt;IAuthState&lt;/code&gt; is very simple, it contains only &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Every time someone calls &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt;, it persists data in the local storage. In this way, if the user closes or reloads the page, the credentials are not lost. If &lt;code class=&quot;language-text&quot;&gt;setState&lt;/code&gt; is called with falsy credentials (e.g. &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;false&lt;/code&gt;), it removes from local storage.&lt;/li&gt;
&lt;li&gt;In the constructor, it provides the initial state for the superclass &lt;code class=&quot;language-text&quot;&gt;State&lt;/code&gt;. It tries to get the credential from the local storage.&lt;/li&gt;
&lt;li&gt;A lot of getters method: both reactive (ends with &lt;code class=&quot;language-text&quot;&gt;$&lt;/code&gt;), and standard (classic variables).&lt;/li&gt;
&lt;li&gt;Some helper methods to change the state of the 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;Be aware&lt;/strong&gt;: storing &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;refreshToken&lt;/code&gt; inside the local storage can expose your application to security issues. Any JavaScript running on your web app can read it.
So &lt;strong&gt;if your web app is vulnerable to &lt;a href=&quot;https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)&quot;&gt;cross-site scripting (XSS)&lt;/a&gt;, then someone can steal them&lt;/strong&gt;. Web frameworks, like Angular, are aware of this issue: they adopt high-security standards to avoid XSS vulnerabilities. I recommend you to spend some time to read about &lt;a href=&quot;https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)&quot;&gt;cross-site scripting (XSS)&lt;/a&gt;.
If you are scared about that, just don’t save the tokens inside the local storage, you’ll be safe… But if your user closes the page, it has to login again.&lt;/p&gt;
&lt;p&gt;Now our AuthStore is ready to go! Let’s go to the class that wires everything together: the &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; is the class that contains the business logic to make authentication works. Let’s see the code:&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;This class uses both the &lt;code class=&quot;language-text&quot;&gt;AuthClient&lt;/code&gt;, to make API calls, and &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;, to persist credentials.
There are three methods that we can call:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;login&lt;/code&gt;: we call it when we want the user to login. It calls login API and then persists the credential in AuthStore.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;refresh&lt;/code&gt;: used to refresh the token. It makes API calls and then persists them.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;logout&lt;/code&gt;: it clears the &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt; and then navigates users to login page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a simplified version of my implementation. During login, I made also an API calls to an endpoint to get user data (also called &lt;code class=&quot;language-text&quot;&gt;auth/me&lt;/code&gt;). I didn’t add it because its implementation depends on your architecture and it’s out of the blog post’s scope. The key point is this: &lt;strong&gt;you should add all your authentication business logic here&lt;/strong&gt;, delegating the persistence to &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt; and the API calls to &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;We are in the last part of this blog post: we can authenticate the user and persist credentials in the &lt;code class=&quot;language-text&quot;&gt;AuthStore&lt;/code&gt;. We can refresh the token when it expires. We can logout the user.&lt;/p&gt;
&lt;p&gt;Now we focus on these goals:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Not passing the token when we call a public API.&lt;/li&gt;
&lt;li&gt;Passing the JWT token during authenticated API calls.&lt;/li&gt;
&lt;li&gt;Refreshing the token when the &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; expires. We know the token expires only when we make some API calls: so when an API call fails, because the token is expired, we need to call refresh API call to get the new token, then we need to make again the first call with the refreshed token.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All this stuff is managed by the &lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt;. It is a subclass of &lt;a href=&quot;https://angular.io/guide/http#http-interceptors&quot;&gt;Angular HTTP Interceptor&lt;/a&gt;. Briefly speaking, &lt;strong&gt;an HTTP Interceptor is a layer that we can add between the API call we make and the real HTTP Request made by the browser&lt;/strong&gt;. In this way, we can transparently inject all these auth behavior without changing our Client classes.&lt;/p&gt;
&lt;h4&gt;Understanding HTTP Interceptor&lt;/h4&gt;
&lt;p&gt;First of all, we need to understand how to implement an HTTP Interceptor: &lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt; should implement &lt;code class=&quot;language-text&quot;&gt;HttpInterceptor&lt;/code&gt; interface. So we have to implement the method&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;The first parameter is the HTTP request that Angular is going to do. At the end of our logic, we need to call &lt;code class=&quot;language-text&quot;&gt;next.handle(request)&lt;/code&gt; to continue the HTTP request through the normal flow.
In other words, let’s assume we create an HTTP interceptor that does absolutely nothing. The minimum code we have to write is this&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;AuthInterceptor implementation&lt;/h4&gt;
&lt;p&gt;Now we do the same thing for our &lt;code class=&quot;language-text&quot;&gt;AuthInterceptor&lt;/code&gt;, but this time we have to add all the authentication logic that we said before.&lt;/p&gt;
&lt;p&gt;Let’s have a look at its implementation:&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;/* If the incoming request has the special INTERCEPTOR_NO_AUTH_HEADER,
           it means that we don&apos;t have to add the JWT token
        */&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;/* So just send to the next handler the same request
               removing the special 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;// If the user is logged in&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;// Then add the token and continue the API call.&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;// But if the call has failed, try to recover it using retryWhenExpiredToken method&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;/*
                              If the call, after our refresh method, is still failing with
                              401 UNAUTHORIZED status code
                            */&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;// Then logout the user, nothing else we can do.&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;/*
          If the user is not logged in, just do nothing.
          We don&apos;t have any JWT token to attach to the request
        */&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;// This method is called only during an error response&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;/* If the status code is 401 UNAUTHORIZED and we don&apos;t have the refresh token,
               or the status code is different from 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;// We can do nothing, just re-raise the error and continue.&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;// Otherwise, call the backend to refresh our 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;// Then re-call the failed request with the brand new token&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;// It just clones the request, adding the JWT token to the request&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;Take your time to read it… We see that the &lt;code class=&quot;language-text&quot;&gt;intercept&lt;/code&gt; method is more complex. &lt;strong&gt;I added tons of comments inside the code&lt;/strong&gt;, so it’s easier to understand what’s happening.&lt;/p&gt;
&lt;p&gt;Let’s see whether we reached all our prefixed goals:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Not passing the token when we call a public API:&lt;/em&gt; done by &lt;code class=&quot;language-text&quot;&gt;INTERCEPTOR_NO_AUTH_HEADER&lt;/code&gt; special header.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Passing the JWT token during API calls:&lt;/em&gt; done thanks to &lt;code class=&quot;language-text&quot;&gt;addTokenToRequest&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Refreshing the token when the &lt;code class=&quot;language-text&quot;&gt;accessToken&lt;/code&gt; expires:&lt;/em&gt; achieved by &lt;code class=&quot;language-text&quot;&gt;retryWhenExpiredToken&lt;/code&gt; method.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The code is not so long, it has more or less 50 lines. But I think is pretty full of tricky concepts from RxJS like &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;I used closure&lt;/a&gt; to make &lt;code class=&quot;language-text&quot;&gt;retryWhenExpiredToken&lt;/code&gt; works. I created a function that returns a function. The first call gets the original request and the &lt;code class=&quot;language-text&quot;&gt;next&lt;/code&gt; handler and returns the function that we feed the method &lt;code class=&quot;language-text&quot;&gt;catchError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Writing this code without bugs in one-shot is very difficult&lt;/strong&gt;, even if it’s not long. Two things helped me reaching it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Heavy usage of TypeScript typing system&lt;/strong&gt;: TypeScript add types to JS, thank god! Adding types to everything is the best way to avoid nasty bugs. The transpiler can warn you as soon as possible if you’re returning something wrong. If you put &lt;code class=&quot;language-text&quot;&gt;any&lt;/code&gt; everywhere, or you don’t add types for your expected parameters, you’re alone! The transpiler can’t help you, soon or later you make a mistake. The only &lt;code class=&quot;language-text&quot;&gt;any&lt;/code&gt; you see in this code is because the &lt;code class=&quot;language-text&quot;&gt;intercept&lt;/code&gt; signature is coming from Angular and I can’t do anything about it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Test Driven Development (TDD)&lt;/strong&gt; for the crucial part of your system, or use TDD as much as you can. Testing manually this authentication system takes much longer than writing some unit tests. And there’s nothing worse than someone calls you saying users can’t sign in. I made this using TDD and the result is these tiny classes that are easy to test thanks to the &lt;a href=&quot;https://angular.io/guide/testing&quot;&gt;Angular testing suite&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The perfect developer, that makes no bugs, doesn’t exist. &lt;strong&gt;Some developers are better than others not because are perfect, but because they take more countermeasures to avoid bugs&lt;/strong&gt;, so they write less buggy code. TypeScript and TDD are the most effective countermeasure that I know for front-end development. So use them.&lt;/p&gt;
&lt;p&gt;If you are interested in TDD, I wrote two articles about that. Unfortunately, they are written in Italian. If you are interested in the translation just let me know: &lt;a href=&quot;https://www.linkedin.com/in/mattian/&quot;&gt;ping me on LinkedIn&lt;/a&gt; and &lt;a href=&quot;https://gmail.us4.list-manage.com/subscribe/post?u=a8dbd77c4662328d660883c64&amp;#x26;id=31345af945&quot;&gt;subscribe to my newsletter&lt;/a&gt; to be notified about these topics.
Here are the links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mattianatali.it/come-sviluppare-in-test-driven-development-tdd-partendo-da-zero/&quot;&gt;[Italian] How to code in TDD, starting from scratch&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mattianatali.it/come-sviluppare-rest-api-in-tdd-con-spring-boot/&quot;&gt;[Italian] How to develop RESTful API using Spring Boot and TDD&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Adding AuthInterceptor to Angular app&lt;/h4&gt;
&lt;p&gt;We must remember to add the AuthInterceptor to our application.
This is very easy: we need to declare it inside the root Angular module of the 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;And that’s it! Now our app handles the JWT authentication of our back-end!&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I hope you enjoyed this journey about JWT authentication + Angular. This is my implementation, and it satisfied all my goals. I hope this work inspires you to reach yours too!&lt;/p&gt;
&lt;p&gt;See you!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Let's learn to automate with Ansible · DevOps]]></title><description><![CDATA[Introduction You’re at work and you’ve been tasked with configuring 20 virtual machines all the same way? You’re at home and your Raspberry…]]></description><link>https://www.mattianatali.it/en/how-to-automate-with-ansible/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-automate-with-ansible/</guid><pubDate>Sun, 25 Aug 2019 07:03:47 GMT</pubDate><content:encoded>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;You’re at work and you’ve been tasked with configuring 20 virtual machines all the same way? You’re at home and your Raspberry Pi unfortunately corrupted the SD card and so you have to reconfigure it for the umpteenth time? Then &lt;strong&gt;Ansible could solve many of your problems&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;If you’re like me I’m sure you don’t like spending the day performing repetitive tasks that give practically zero added value to yourself: &lt;strong&gt;performing repetitive tasks isn’t a job for us humans&lt;/strong&gt;, we can easily delegate it to machines so we can dedicate ourselves to things that really matter.&lt;/p&gt;
&lt;p&gt;How do we automate these tasks? A certainly effective answer is &lt;a href=&quot;https://www.ansible.com/&quot;&gt;Ansible&lt;/a&gt;, the configuration tool I prefer.&lt;/p&gt;
&lt;h2&gt;Goal&lt;/h2&gt;
&lt;p&gt;If you’ve read the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/quickstart.html&quot;&gt;official Ansible documentation&lt;/a&gt;, I’m sure you’ve noticed that it’s as boring as the tool itself is powerful. It’s easy to fall asleep reading it even before understanding Ansible’s real potential.&lt;/p&gt;
&lt;p&gt;That’s why I decided to write this mini guide hoping it’s a bit more effective. I hope to achieve this goal through a concrete example that happened to me and that I still use: &lt;strong&gt;we’re going to configure a &lt;a href=&quot;https://en.wikipedia.org/wiki/Virtual_private_network&quot;&gt;VPN Server&lt;/a&gt; on a &lt;a href=&quot;https://www.raspberrypi.org/&quot;&gt;Raspberry Pi&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to this Ansible playbook, we can create a VPN Server on a Raspberry Pi by running a single command &lt;code class=&quot;language-text&quot;&gt;ansible-playbook -vv -i hosts vpn.yml&lt;/code&gt;. &lt;strong&gt;The functions it performs behind the scenes are many&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It downloads the certificate via &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;https://letsencrypt.org/&lt;/a&gt; for the domain pointing to our home, for example &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It sets up automatic renewal of the certificate itself.&lt;/li&gt;
&lt;li&gt;It opens the correct ports on the Raspberry Pi to make the VPN work.&lt;/li&gt;
&lt;li&gt;It installs all the libraries and applications needed to install the VPN Server.&lt;/li&gt;
&lt;li&gt;It correctly configures the settings we decide for the VPN, for example the user to access it.&lt;/li&gt;
&lt;li&gt;It sets up automatic certificate updates based on the renewal of the Let’s Encrypt certificate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now imagine if we didn’t have Ansible doing all these things with one command. Surely 2 days after running these commands manually I would have already forgotten everything, not to mention the number of attempts I would have had to make even the second time to reconfigure everything from scratch.
Precisely for this reason, once I understood how I could do it, I created the Ansible script. &lt;strong&gt;Now I have the versioned, ready-to-use playbook in a &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/&quot;&gt;public repository&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this guide we won’t dwell too much on the details of the VPN: &lt;strong&gt;we’re more interested in the reasoning that led to this result and which Ansible features we used&lt;/strong&gt;. Creating the VPN is just a concrete example that covers many Ansible features.&lt;/p&gt;
&lt;h2&gt;Requirements&lt;/h2&gt;
&lt;p&gt;The requirements to follow this guide are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have a minimum knowledge of Linux. The commands &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; should be familiar to us.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html&quot;&gt;We’ve installed Ansible on your laptop&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.raspberrypi.org/documentation/remote-access/ssh/&quot;&gt;Our Raspberry Pi must have SSH enabled&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Glossary&lt;/h2&gt;
&lt;p&gt;The first obstacle you encounter with Ansible is learning and remembering the various terms it uses. Here’s a small summary that will help us throughout the guide:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Modules&lt;/em&gt;: modules are small programs that Ansible offers us to complete tasks. For example: we want to install a package like vim? We can use the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/apt_module.html&quot;&gt;apt&lt;/a&gt; module; we want to add a cronjob? There’s the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/cron_module.html&quot;&gt;cron&lt;/a&gt; module. &lt;a href=&quot;https://docs.ansible.com/ansible/latest/modules/modules_by_category.html&quot;&gt;There really are an infinite number of them&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Task&lt;/em&gt;: for example a task is “install the nginx program”. We can see them as the smallest unit we have in Ansible; basically it’s calling a module with the various parameters. An example of a task is the following&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;Role&lt;/em&gt;: Ansible explains the role using a football metaphor. An example of a role could be “striker”, “defender”, “midfielder”. In our example we have two roles: “certificate installer”, “VPN installer”. In short it’s a set of tasks that have a very specific function, a role indeed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Playbook&lt;/em&gt;: it’s the largest unit we have in Ansible. A playbook organizes the various roles to complete our task. For example in our case it’s the set of the two roles explained above. &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/&quot;&gt;My repository about creating the VPN&lt;/a&gt; is indeed a playbook. In our case we’ll have a playbook that will carry out our task, that is, installing the VPN with the various certificates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Inventory&lt;/em&gt;: it’s a file that contains groups that in turn contain machines. These machines are the ones that will be affected by our playbook. Ansible is very powerful; with a single command you can install the VPN on 100 machines. We’ll have a group called &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; that will have our target machine named &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt; (the Raspberry Pi) defined inside it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we have a common terminology; it’s not necessary to understand everything now, surely it’s all still very foggy. But later, after seeing a concrete example, everything will be clearer.&lt;/p&gt;
&lt;h2&gt;Let’s perform the task manually&lt;/h2&gt;
&lt;p&gt;Before automating we must be clear about what we have to do; the first time maybe we don’t have clear ideas at all, we make many attempts and some will lead nowhere. &lt;strong&gt;So the first thing to do is try manually&lt;/strong&gt; without bothering Ansible so as to be faster in the “construction” phase of the various tasks to reach the goal. In our case we first educate ourselves a bit about the VPN, read how &lt;a href=&quot;https://www.strongswan.org/&quot;&gt;strongswan&lt;/a&gt; works, which libraries it needs to work, how to configure it, etc. Then we educate ourselves about &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let’s Encrypt&lt;/a&gt; to issue a valid certificate for our domain &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt; that points to our home, so as to have the access point to our VPN.&lt;/p&gt;
&lt;p&gt;I’ll spare you this whole phase; the thing we must keep in mind is this: &lt;strong&gt;during the manual phase let’s keep in mind every step we take to complete our task&lt;/strong&gt;, every single configuration file we modified, anything we must keep track of because soon we’ll automate it.&lt;/p&gt;
&lt;h2&gt;Let’s define the roles&lt;/h2&gt;
&lt;p&gt;Once the goal is reached manually, it’s time to organize our ideas. At the end of our analysis our Ansible playbook must perform the following tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It downloads the certificate via &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;https://letsencrypt.org/&lt;/a&gt; for the domain pointing to our home, for example &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;It sets up automatic renewal of the certificate itself.&lt;/li&gt;
&lt;li&gt;It opens the correct ports on the Raspberry Pi to make the VPN work.&lt;/li&gt;
&lt;li&gt;It installs all the libraries and applications needed to install the VPN Server.&lt;/li&gt;
&lt;li&gt;It correctly configures the settings we decide for the VPN, for example the user to access it.&lt;/li&gt;
&lt;li&gt;It sets up automatic certificate updates based on the renewal of the Let’s Encrypt certificate.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of all these tasks &lt;strong&gt;we can find two well-distinct roles&lt;/strong&gt; that can be separated.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The generation and maintenance of certificates&lt;/strong&gt; for &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt; using Let’s Encrypt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Installation of the VPN&lt;/strong&gt; which uses the previously created certificates.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What advantages does separating the tasks found into these two roles bring?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The more self-contained and specific the roles are, the simpler they are to maintain.&lt;/li&gt;
&lt;li&gt;The more self-contained they are, the easier they are to reuse for other playbooks.&lt;/li&gt;
&lt;li&gt;If the defined role is standard enough, it’s likely someone has already implemented it!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In fact &lt;strong&gt;Ansible has a site to search for these roles: it’s called &lt;a href=&quot;https://galaxy.ansible.com/&quot;&gt;Ansible Galaxy&lt;/a&gt;&lt;/strong&gt;. Generating certificates via Let’s Encrypt is a fairly standard thing, and indeed we’re lucky! We have a role that already does what we need; &lt;a href=&quot;https://galaxy.ansible.com/geerlingguy/certbot&quot;&gt;we can find it here&lt;/a&gt;; the best way to learn how to use it is anyway to look at &lt;a href=&quot;https://github.com/geerlingguy/ansible-role-certbot&quot;&gt;its repository on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To install the role, so we can use it shortly, let’s type in the 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;Searching again on that site I didn’t find a role that creates the VPN, so for that we have to fend for ourselves.&lt;/p&gt;
&lt;h2&gt;Let’s define the Playbook&lt;/h2&gt;
&lt;p&gt;We said that modules and tasks are the atomic part of Ansible; these are grouped into roles that perform a certain function (in our case there are two), &lt;strong&gt;the entity that orchestrates these roles is the playbook&lt;/strong&gt;.
If we wanted to depict it in a diagram:&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
  roles
    tasks&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;To create our VPN configuration we adopt a &lt;a href=&quot;https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design&quot;&gt;top-down&lt;/a&gt; approach&lt;/strong&gt;. In other words we start working on the most “external” and general part of the problem, then go deeper and deeper into detail down to the various tasks. The part that contains all the others is the &lt;strong&gt;playbook&lt;/strong&gt;.
Our playbook must start in sequence:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The role that generates the certificates. Already implemented thanks to the library we found on &lt;a href=&quot;https://galaxy.ansible.com/&quot;&gt;Ansible Galaxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The role that installs the VPN. We must implement it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ansible relies heavily on conventions; let’s start right away using the &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html&quot;&gt;best practices&lt;/a&gt; provided by Ansible.&lt;/p&gt;
&lt;p&gt;We can use my repository with the finalized playbook as a reference. The structure to create our playbook is the following:&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;# All the group-level variables go here (our group is called vpns)&lt;/span&gt;
   
host_vars/
   rpi.yml           &lt;span class=&quot;token comment&quot;&gt;# Here we assign the variables for individual machines (our only machine is called rpi)&lt;/span&gt;

vpn.yml              &lt;span class=&quot;token comment&quot;&gt;# This is our playbook&lt;/span&gt;
hosts                &lt;span class=&quot;token comment&quot;&gt;# This is our inventory, we define the groups (vpns) and the machines (rpi) on which we want to run the playbook.&lt;/span&gt;

roles/               &lt;span class=&quot;token comment&quot;&gt;# This folder contains all the roles we&apos;ll define&lt;/span&gt;
    vpn&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;install/     &lt;span class=&quot;token comment&quot;&gt;# This folder contains our role to install the VPN.&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;            &lt;span class=&quot;token comment&quot;&gt;# We&apos;ll see the subfolder structure later.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let’s start writing our playbook in the &lt;code class=&quot;language-text&quot;&gt;vpn.yml&lt;/code&gt; file&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;The format the file is written in is &lt;a href=&quot;https://en.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt;; it’s a very readable format and is now a de facto standard in applications that cater to DevOps. &lt;a href=&quot;https://learnxinyminutes.com/docs/yaml/&quot;&gt;If you’ve never seen it I recommend reading this guide, which explains the format quickly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Our Playbook will have to do only one thing: create a VPN Server. In Ansible jargon, a playbook is made up of multiple &lt;strong&gt;plays&lt;/strong&gt;. We have only one &lt;em&gt;play&lt;/em&gt; in our playbook.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do you figure out how and when to create a play?&lt;/strong&gt; Usually if we have &lt;em&gt;multiple roles&lt;/em&gt; that affect &lt;em&gt;a single group&lt;/em&gt; of machines, then this is a good candidate to be a play. If instead we had &lt;em&gt;some roles&lt;/em&gt; targeting the &lt;em&gt;Raspberry&lt;/em&gt; and &lt;em&gt;other roles&lt;/em&gt; that had to configure &lt;em&gt;routers&lt;/em&gt;, then our playbook would be made up of two plays. Because one play worked on the Raspberry Pis, the other on the routers.&lt;/p&gt;
&lt;p&gt;Let’s explain the various commands inside a play:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;name&lt;/code&gt;: we can insert a short description of what our play will do.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;hosts&lt;/code&gt;: we define which group will be used as the target of our play. In our case it’s the &lt;code class=&quot;language-text&quot;&gt;vpn&lt;/code&gt; group, which will contain our Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;roles&lt;/code&gt;: we define the roles in chronological order that will be started on our hosts.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;role: geerlingguy.certbot&lt;/code&gt;: the first role to start will be the one we found on &lt;a href=&quot;https://galaxy.ansible.com/&quot;&gt;Ansible Galaxy&lt;/a&gt;; it will install and keep the certificates for the VPN up to date.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;become: yes&lt;/code&gt;: it means the script will be started enabling &lt;em&gt;privilege escalation&lt;/em&gt;. In practice we’ll start the role as root. Both the role to download the certificates and the VPN installation need to be started as root. So in both we’ll put &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;: we start the VPN installation after the certificates role. We still have to figure out how to define this role.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’ve finished the playbook. In practice our playbook is saying this: “Install the certificates and then install the VPN on the machines that are part of the &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; group”.&lt;/p&gt;
&lt;h2&gt;Let’s define the inventory&lt;/h2&gt;
&lt;p&gt;We said the playbook will work on the group of machines called &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt;. But where is this group defined? This is where the &lt;strong&gt;inventory&lt;/strong&gt; comes in. The inventory object is where we define the groups of machines and the machines that make up this group.
The file containing this inventory is the &lt;code class=&quot;language-text&quot;&gt;hosts&lt;/code&gt; file. The name is arbitrary; whatever name we give it will then have to be referenced when we invoke the command to start the playbook.&lt;/p&gt;
&lt;p&gt;Our hosts file will have this content.&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;Simply with these two lines we’re saying that the &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; group contains the &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt; machine which is the name we’re giving to our Raspberry Pi. It’s easy to guess that if we had multiple Raspberry Pis, we could configure them at the same time by defining them in this file in the &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; group.&lt;/p&gt;
&lt;p&gt;The inventory syntax is simple and it’s this&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;group1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
machine1
machine2

&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;group2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
machine3
machine4

...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Let’s define the group and host variables&lt;/h2&gt;
&lt;p&gt;We’ve defined the playbook that works on the &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; group, we’ve declared the &lt;code class=&quot;language-text&quot;&gt;vpns&lt;/code&gt; group saying that it contains our Raspberry Pi named &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt; through the inventory. But &lt;strong&gt;how does Ansible know how to connect to our Raspberry Pi?&lt;/strong&gt; How do we give it the IP, user, password to connect with SSH? How do we tell it which domain we want to get the certificates for? For now it only knows there’s a machine called &lt;code class=&quot;language-text&quot;&gt;rpi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All these things are &lt;strong&gt;variables&lt;/strong&gt;; they vary based on the machine or group of machines we want to act on. Ansible has two folders dedicated to this purpose: a folder called &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; will contain the variables that are common to all machines belonging to a group, the &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt; folder will contain all the variables specific to a single machine.&lt;/p&gt;
&lt;p&gt;In our project we can insert these two folders; these folders will have YAML files named after our group in &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; and named &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;So the structure of our folders, as far as variables are concerned, is the following:&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;# Contains all the variables common to all machines belonging to the vpns group&lt;/span&gt;
   
host_vars/
   rpi.yml           &lt;span class=&quot;token comment&quot;&gt;# Contains all the variables belonging to the rpi machine&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Inside the &lt;code class=&quot;language-text&quot;&gt;rpi.yml&lt;/code&gt; file defined in the &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt; folder, Ansible will be able to find all the information it needs to complete the playbook. The &lt;code class=&quot;language-text&quot;&gt;rpi.yml&lt;/code&gt; file contains the following variables:&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; myhome.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;Through the &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; variables we can provide Ansible with all the information to connect to SSH, to run our playbook.
We can avoid inserting username and password by using the SSH configurations. &lt;a href=&quot;/en/how-to-be-productive-with-the-terminal/&quot;&gt;In this guide, in the SSH section, I explain how to do it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The following fields are the ones we’ll use when we create the role to install the VPN. The &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; field will contain the name of our domain that points to our home; in our case it’s &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt;. In &lt;code class=&quot;language-text&quot;&gt;vpn_users&lt;/code&gt; we define the username and password of the clients that can connect to our VPN. &lt;code class=&quot;language-text&quot;&gt;vpn_local_ts&lt;/code&gt; is a variable that allows us to limit access to clients connecting to the VPN; for example at my home I limited it to my subnet &lt;code class=&quot;language-text&quot;&gt;192.168.1.0/24&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All the variables starting with &lt;code class=&quot;language-text&quot;&gt;certbot_&lt;/code&gt; are part of the role we downloaded with Ansible Galaxy; they allow us to configure anything about certificate renewal for the &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt; domain. Finding the variables that make up the role we downloaded is simple; &lt;a href=&quot;https://github.com/geerlingguy/ansible-role-certbot&quot;&gt;just read the documentation of the role we used&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We can notice that the last line of our file has a particular variable &lt;code class=&quot;language-text&quot;&gt;{{domain}}&lt;/code&gt;. &lt;strong&gt;The double braces allow us to reference another already-defined variable&lt;/strong&gt;. This way we can define only the &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; variable in the fourth line, and automatically the &lt;code class=&quot;language-text&quot;&gt;{{domain}}&lt;/code&gt; variable will have the same value. This way we have &lt;a href=&quot;https://en.wikipedia.org/wiki/Single_source_of_truth&quot;&gt;“a single source of truth”&lt;/a&gt; and we avoid gross errors like updating only one variable and not the other.&lt;/p&gt;
&lt;p&gt;To insert values in the double braces, Ansible uses a very famous template engine in Python: &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html&quot;&gt;Jinja2&lt;/a&gt;. Jinja2 is very powerful; for now we just need to know that when we write &lt;code class=&quot;language-text&quot;&gt;{{value}}&lt;/code&gt; it means we’re inserting the content of the variable we find in the braces.&lt;/p&gt;
&lt;h2&gt;Let’s implement the role to install the VPN&lt;/h2&gt;
&lt;p&gt;We’ve defined the playbook, the inventory, the variables and the role to install the certificates we found on Ansible Galaxy; now &lt;strong&gt;we just need to implement the role that installs the VPN server on the Raspberry Pi&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Roles are defined in the &lt;code class=&quot;language-text&quot;&gt;roles/&lt;/code&gt; folder; let’s create a folder inside it that will take the name of the role (&lt;code class=&quot;language-text&quot;&gt;vpn-install&lt;/code&gt;), the same name we defined in the playbook in &lt;code class=&quot;language-text&quot;&gt;vpn.yml&lt;/code&gt;.
The structure of our folders will be defined like this:&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;# Contains the files to copy to the 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;# Contains the instructions to execute&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;...&lt;/span&gt;
        templates/    &lt;span class=&quot;token comment&quot;&gt;# Contains the source templates to then upload to the 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;In this case too &lt;a href=&quot;https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#directory-layout&quot;&gt;we’re using Ansible’s conventions&lt;/a&gt;, we’re not making anything up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;files&lt;/em&gt;: contains all the files we need to upload to the Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;tasks&lt;/em&gt;: contains the tasks to execute on the Raspberry Pi to install the VPN.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;templates&lt;/em&gt;: it’s similar to the files folder, but in this case we won’t have the files to copy, but a template that we must render before we can copy it to the Raspberry Pi. Wait a moment and then its use will be clear.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Let’s define the tasks&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Now let’s focus on the &lt;em&gt;tasks&lt;/em&gt; folder&lt;/strong&gt;; as we said here we’ll have all the commands to execute on the Raspberry Pi to install the VPN.
The first file Ansible looks for in the tasks folder is &lt;code class=&quot;language-text&quot;&gt;main.yml&lt;/code&gt;. In this file we write all the tasks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How do we know which tasks to execute?&lt;/strong&gt; Here we must retrieve the commands we executed manually at the beginning of the article. Once retrieved we must translate them into tasks, using the &lt;strong&gt;modules&lt;/strong&gt; Ansible provides us.&lt;/p&gt;
&lt;p&gt;These are the “commands” we need to translate into Ansible tasks; take them for granted, I don’t want to bore you too much with the VPN question:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the following packages using &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;Enable &lt;a href=&quot;http://www.ducea.com/2006/08/01/how-to-enable-ip-forwarding-in-linux/&quot;&gt;IP Forwarding&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Add the file with the VPN configuration in &lt;code class=&quot;language-text&quot;&gt;/etc/swanctl/swanctl.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the file with the various Strongswan plugins in &lt;code class=&quot;language-text&quot;&gt;/etc/strongswan.conf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create the &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; folders in &lt;code class=&quot;language-text&quot;&gt;/etc/swanctl/&lt;/code&gt;; here we’ll add the various certificates created by the previous role we found on Ansible Galaxy.&lt;/li&gt;
&lt;li&gt;Copy the certificates created by the role that creates them from the &lt;code class=&quot;language-text&quot;&gt;/etc/letsencrypt/live/myhome.mattianatali.it/&lt;/code&gt; folder into the correct folders created in the previous point.&lt;/li&gt;
&lt;li&gt;Add a script that repeats the previous point every time the certificates are renewed. &lt;a href=&quot;https://letsencrypt.org/&quot;&gt;Let’s Encrypt&lt;/a&gt; certificates only last 3 months.&lt;/li&gt;
&lt;li&gt;Add a &lt;a href=&quot;https://en.wikipedia.org/wiki/Cron&quot;&gt;cronjob&lt;/a&gt; that runs the previous point right after the certificates are generated.&lt;/li&gt;
&lt;li&gt;Enable &lt;a href=&quot;https://en.wikipedia.org/wiki/Network_address_translation#IP_masquerading&quot;&gt;IP Masquerading&lt;/a&gt;, changing the Raspberry Pi firewall rules.&lt;/li&gt;
&lt;li&gt;Reboot the Raspberry Pi.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These are all the operations we need to automate to have our VPN working on the Raspberry Pi. &lt;strong&gt;There are many operations, some complex, boring to do manually, the chance of error is high, the commands are practically impossible to remember by heart for a future configuration&lt;/strong&gt;. Maybe now you understand why I immediately thought of Ansible when I tackled this endeavor!&lt;/p&gt;
&lt;p&gt;With Ansible we can do all this with a few lines of code and disarming clarity. The final result of our &lt;code class=&quot;language-text&quot;&gt;main.yml&lt;/code&gt; file, which includes all our commands, is the following. I added comments in the file so as to have the right correspondence with the points written just above:&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;# Install the following packages using `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;# Enable 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;# Add the file with the VPN configuration 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;# Add the file with the various Strongswan plugins 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;# Create the x509, x509ca, private folders 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;# Copy the certificates created by the role that creates them from the /etc/letsencrypt/live/myhome.mattianatali.it/ folder into the correct folders created in the previous point&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Note the use of the domain variable to insert myhome.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 &quot;|&quot; means &quot;take everything I write after this as a variable and preserve line breaks&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;# Add a script that repeats the previous point every time the certificates are renewed&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;# Add a cronjob that runs the previous point right after the certificates are generated&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;# Enable 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;# Reboot the 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;We can immediately notice that &lt;strong&gt;the tasks all have the following structure&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; TASK DESCRIPTION
  &lt;span class=&quot;token key atrule&quot;&gt;MODULE_NAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;OPTION_1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; OPTION_1_VALUE
    &lt;span class=&quot;token key atrule&quot;&gt;OPTION_2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; OPTION_2_VALUE&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;The modules provided by Ansible are many&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The modules I used in this role are the following:&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;: to install the packages using the &lt;code class=&quot;language-text&quot;&gt;apt-get&lt;/code&gt; command.&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;: to modify the &lt;code class=&quot;language-text&quot;&gt;sysctl.conf&lt;/code&gt; file and therefore modify the system kernel attributes. In our case it was used to enable 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;: to process a file using the Jinja2 template engine, and copy the result to the Raspberry Pi. &lt;strong&gt;We need Jinja2 to insert a file that’s dynamic based on the host and group variables we’re working on&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;: to copy a file from a local folder to our Raspberry Pi; in this case we don’t need Jinja2 to insert variables.&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;: to work with files and folders on the Raspberry Pi, for example change permissions, create or delete folders, etc.&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;: to execute classic commands via the CLI on the target machine.&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;: to modify the &lt;a href=&quot;https://en.wikipedia.org/wiki/Cron&quot;&gt;crontab&lt;/a&gt; file on the machine.&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;: to verify that a specific line exists in a given 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;: to reboot the Raspberry Pi at the end of everything.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The options of the various modules are quite self-explanatory; in any case if any aren’t clear you can read the documentation of the individual modules. The module names in the previous list all point to the reference guide.&lt;/p&gt;
&lt;p&gt;There are some though that deserve a more in-depth description: for example the 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;# Create the x509, x509ca, private folders 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;are three tasks in one; &lt;strong&gt;thanks to &lt;code class=&quot;language-text&quot;&gt;with_items&lt;/code&gt; you can define a list of variables and then, through &lt;code class=&quot;language-text&quot;&gt;{{ item }}&lt;/code&gt;, it’s possible to execute the module for each element in the list&lt;/strong&gt;. So in the previous case it’s as if we had written:&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;# Create the x509, x509ca, private folders 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;Seeing the &lt;code class=&quot;language-text&quot;&gt;{{ item }}&lt;/code&gt; tag we can guess that our &lt;code class=&quot;language-text&quot;&gt;main.yml&lt;/code&gt; file is processed with &lt;a href=&quot;https://jinja.palletsprojects.com/en/2.10.x/&quot;&gt;Jinja2&lt;/a&gt; before being executed. In fact &lt;strong&gt;in our file to define the tasks we can refer to all the variables of the previously declared hosts and groups&lt;/strong&gt;. For example the 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;Uses the &lt;code class=&quot;language-text&quot;&gt;certbot_auto_renew_hour&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;certbot_auto_renew_minute&lt;/code&gt; variables. Jinja2 is very powerful and also allows us to do operations with variables. With this task we’re essentially saying “run the command &lt;code class=&quot;language-text&quot;&gt;/root/renew-certs.sh&lt;/code&gt; 15 minutes after the task that generates the certificates”. This is possible thanks to the operation &lt;code class=&quot;language-text&quot;&gt;{{ certbot_auto_renew_minute + 15 }}&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;The template module&lt;/h4&gt;
&lt;p&gt;The template module deserves an additional explanation since it’s very powerful. We said the template module allows you to insert a file processed with Jinja2 into the target machine.
For example we used it for the 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 this case we take the &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; file, Jinja2 replaces the variables it finds using the ones we defined in the &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt; folders and then inserts it into the &lt;code class=&quot;language-text&quot;&gt;/root/renew-certs.sh&lt;/code&gt; folder on the Raspberry Pi &lt;a href=&quot;https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation&quot;&gt;setting permissions to &lt;code class=&quot;language-text&quot;&gt;744&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s quickly see the content of the 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;in our case &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; will be replaced by &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt; before being copied to the Raspberry Pi.&lt;/p&gt;
&lt;p&gt;An even more complex template can be found with the 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;# Add the file with the VPN configuration 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 this case &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; contains:&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;Here the &lt;code class=&quot;language-text&quot;&gt;domain&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;vpn_local_ts&lt;/code&gt; variables will be replaced. Thanks to the &lt;code class=&quot;language-text&quot;&gt;{% for user in vpn_users %}&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;{% endfor %}&lt;/code&gt; construct we insert the usernames and passwords of the users present in the &lt;code class=&quot;language-text&quot;&gt;vpn_users&lt;/code&gt; variable we defined in the &lt;code class=&quot;language-text&quot;&gt;host_vars/rpi.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;Now let’s imagine not having a template engine and having to do this operation manually… It’s not trivial at all!
&lt;strong&gt;Thanks to Ansible we can clearly separate the variables from the static content of the files; this way we can make custom configuration on multiple machines very simple.&lt;/strong&gt;
In fact the content of the role would always remain the same; what changes is the inventory, where we define the new machine to configure and its variables to use in &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Running the playbook&lt;/h2&gt;
&lt;p&gt;We’ve finally completed our Playbook to create a VPN on our Raspberry Pi! &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/&quot;&gt;You can find the final result on my repository&lt;/a&gt;. We just need to run our playbook through the command&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;Thanks to this command, we start the playbook defined in &lt;code class=&quot;language-text&quot;&gt;vpn.yml&lt;/code&gt; verbosely (&lt;code class=&quot;language-text&quot;&gt;-vv&lt;/code&gt;) passing the inventory defined in the hosts file (&lt;code class=&quot;language-text&quot;&gt;-i hosts&lt;/code&gt;).
We’ll see that Ansible will try to connect via SSH to our Raspberry Pi and execute our tasks point by point, using all the variables we defined in &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt;.
In less than 2 minutes it will have finished doing everything and we can connect to the VPN by setting as server address and id the domain we defined (in my case &lt;code class=&quot;language-text&quot;&gt;myhome.mattianatali.it&lt;/code&gt;) and as username and password those entered in the &lt;code class=&quot;language-text&quot;&gt;vpn_users&lt;/code&gt; variable in the &lt;code class=&quot;language-text&quot;&gt;host_vars/rpi.yml&lt;/code&gt; file.&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;VPN configuration on my 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;At the end we still need to do the port forwarding of the VPN ports from the router to the Raspberry Pi; I didn’t automate this part with Ansible because routers are all different from each other. &lt;a href=&quot;https://github.com/matitalatina/vpn-raspberry-ansible/blob/master/README.md&quot;&gt;If you want the complete VPN I recommend reading the README of my repository&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I hope this guide has provided you with guidelines on how to automate even complex tasks using Ansible. I deliberately skipped quite a few points that were strictly related to creating the VPN, because &lt;strong&gt;the purpose of the guide is to show you the potential of Ansible with an example that isn’t the simple “Hello World”&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What &lt;strong&gt;must be clear is the modus operandi with which we arrived at the solution&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We try the configuration manually, recording the steps.&lt;/li&gt;
&lt;li&gt;We define any roles of our procedure. We search Ansible Galaxy to see if some role has already been made.&lt;/li&gt;
&lt;li&gt;We create the playbook to declare the complete procedure.&lt;/li&gt;
&lt;li&gt;To define the target machines, we define the inventory and insert all the variables in &lt;code class=&quot;language-text&quot;&gt;group_vars&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;host_vars&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We define the tasks to execute in the role. The modules will help us in defining these tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Ansible relies heavily on conventions and best practices&lt;/strong&gt;. This is a huge advantage because if you’ve understood this example, you can practically understand any Ansible playbook because the structure is always the same! &lt;a href=&quot;https://github.com/ansible/ansible-examples&quot;&gt;Try browsing the various examples Ansible provides&lt;/a&gt;; you’ll find the same concepts and folders in all of them.&lt;/p&gt;
&lt;p&gt;Once you’ve assimilated these concepts, it doesn’t matter if we have to set up a VPN, a redundant MongoDB instance, configure NTP on 100 machines; we can configure everything we want with Ansible efficiently and clearly.&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome]]></title><description><![CDATA[Here we are, with a new shiny blog! I decided to make another personal blog. But this is different from my previous one. It’s in English. I…]]></description><link>https://www.mattianatali.it/en/welcome/</link><guid isPermaLink="false">https://www.mattianatali.it/en/welcome/</guid><pubDate>Sun, 25 Aug 2019 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Here we are, with a new shiny blog!&lt;/p&gt;
&lt;p&gt;I decided to make another personal blog. But this is different from &lt;a href=&quot;https://www.mattianatali.it&quot;&gt;my previous one&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;It’s in English.&lt;/h2&gt;
&lt;p&gt;I used to write in Italian since I’m Italian! But I realized that the preferred language is English for technical posts.&lt;/p&gt;
&lt;p&gt;It isn’t an easy switch for me, because I love Italy and I wanted to spread some knowledge in my native tongue. But writing posts in Italian, I reach a niche of a niche… I don’t know if it’s so useful.&lt;/p&gt;
&lt;p&gt;Another big reason is that all the references that I link in my blog posts were in English! So even an Italian reader should know English to understand the content properly.&lt;/p&gt;
&lt;h2&gt;It’s about my job&lt;/h2&gt;
&lt;p&gt;My previous blog was more personal, it started with no fixed idea on what I would write in it. In fact, it was more an exercise on how to deploy a &lt;a href=&quot;https://ghost.org/&quot;&gt;Ghost blog&lt;/a&gt; and how to build a &lt;a href=&quot;https://www.gatsbyjs.org/&quot;&gt;Gatsby website&lt;/a&gt;. The content inside it is more mixed: from photography, games and tech posts.&lt;/p&gt;
&lt;p&gt;In this blog, I want to share with you my thoughts on my daily job, how I tackled some challenging task, or simply what I’m doing at work.&lt;/p&gt;
&lt;p&gt;I want to share some content that is useful for other developers.&lt;/p&gt;
&lt;p&gt;I hope that I’ll have some time to share this stuff and I hope you like them!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to develop APIs in TDD with Spring Boot]]></title><description><![CDATA[In this article we saw what it means to develop in Test Driven Development (TDD) and the benefits that come from it. The example used might…]]></description><link>https://www.mattianatali.it/en/how-to-develop-rest-apis-in-tdd-with-spring-boot/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-develop-rest-apis-in-tdd-with-spring-boot/</guid><pubDate>Tue, 30 Jul 2019 09:03:47 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;/en/how-to-develop-in-test-driven-development-tdd-from-scratch&quot;&gt;In this article&lt;/a&gt; we saw what it means to develop in Test Driven Development (TDD) and the benefits that come from it. The example used might seem like a pointless little game, but my focus there was to explain TDD to those who had never heard of it at all.&lt;/p&gt;
&lt;p&gt;In this guide instead let’s look together at a use case that will be much more familiar to us: the development of RESTful APIs. To do this I decided to use the Spring Boot framework; the chosen language is Java.
Spring Boot is widely used in the enterprise world to create a microservices architecture. &lt;a href=&quot;https://hub.packtpub.com/netflix-adopts-spring-boot-as-its-core-java-framework/&quot;&gt;Netflix uses it too&lt;/a&gt;. Moreover Java is a programming language known to everyone by now, so I think it’s a good choice to see a practical example together.&lt;/p&gt;
&lt;p&gt;As always we start completely from scratch, to leave nothing to chance. In addition to TDD, we’ll also see together how to structure the project correctly and other very handy libraries that I use every day to increase our productivity, such as the &lt;a href=&quot;https://projectlombok.org/&quot;&gt;Lombok&lt;/a&gt; library.&lt;/p&gt;
&lt;h2&gt;Requirements&lt;/h2&gt;
&lt;p&gt;The reader I’m imagining is a &lt;strong&gt;developer who has already heard of Spring Boot, isn’t scared if we talk about RESTful APIs, wants to use TDD as the main development driver but can’t apply it effectively&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This article &lt;strong&gt;is a continuation of my &lt;a href=&quot;/en/how-to-develop-in-test-driven-development-tdd-from-scratch&quot;&gt;first episode on TDD&lt;/a&gt;&lt;/strong&gt;, so I strongly recommend reading &lt;a href=&quot;/en/how-to-develop-in-test-driven-development-tdd-from-scratch&quot;&gt;“How to develop in TDD starting from scratch”&lt;/a&gt; first. This way you’ll have an initial grounding in TDD and we’ll be aligned on some concepts that I’ll take for granted here.&lt;/p&gt;
&lt;p&gt;My guide is based on a UNIX-like operating system (Mac OS X), but it can easily be followed by Windows users too.&lt;/p&gt;
&lt;p&gt;On our PC, &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; must be installed.&lt;/p&gt;
&lt;h2&gt;Goal&lt;/h2&gt;
&lt;p&gt;Let’s imagine we need to create two endpoints:&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;: to retrieve a vehicle by id.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;POST - /api/v1/vehicles&lt;/code&gt;: to add a vehicle.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The vehicle is made up of these properties&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;&lt;code class=&quot;language-text&quot;&gt;brand&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; are mandatory; the vehicle’s year of production can’t be earlier than &lt;code class=&quot;language-text&quot;&gt;1950&lt;/code&gt; for business reasons.&lt;/p&gt;
&lt;p&gt;For now we’re not interested in other endpoints.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/matitalatina/tdd-spring-boot-api&quot;&gt;You can find the implementation of this small project in this public repository of mine&lt;/a&gt;; this way, if you get lost, you can pick up the thread of the discussion by reading the code directly.&lt;/p&gt;
&lt;h2&gt;Let’s create the project&lt;/h2&gt;
&lt;p&gt;Now that we have a clear idea of what we need to do, &lt;strong&gt;let’s generate the project&lt;/strong&gt;.
The best way to do this is to go to the &lt;a href=&quot;https://start.spring.io/&quot;&gt;Spring Initializr&lt;/a&gt; website. From here we can decide which libraries to integrate, the Java version, etc.&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;The configuration I chose is the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Project&lt;/em&gt;: Gradle Project. You’ve probably already heard of Maven as a dependency manager and build tool for Java. If instead you develop on Android, with Gradle you’ll feel at home, since it’s the one used by 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;: provides the various annotations to create RESTful APIs simply and quickly.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Lombok&lt;/em&gt;: it’s a Java library that lets us reduce the verbosity of our Java code.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Spring Data JPA&lt;/em&gt;: provides everything needed for data persistence.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;H2 Database&lt;/em&gt;: provides an in-memory DB. In production it would be appropriate to use a PostgreSQL or MySQL DB, but to avoid getting too bogged down in DB configuration, I preferred to use H2.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s press “Generate the project”. We end up with a nice zip file. Let’s extract it into a folder of our choosing.
Let’s open the project; I use IntelliJ.&lt;/p&gt;
&lt;h3&gt;Let’s enable lombok and the annotation processor in IntelliJ&lt;/h3&gt;
&lt;p&gt;If it’s the first time you’re using &lt;a href=&quot;https://projectlombok.org/&quot;&gt;Lombok&lt;/a&gt;, &lt;strong&gt;you need the “Lombok” Plugin&lt;/strong&gt;. Open “Preferences”, go to “Plugins”, search for “Lombok” in the marketplace and install it.&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 - Let&amp;#39;s install the 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;Once the project is open in IntelliJ, &lt;strong&gt;we need to enable the annotation processor&lt;/strong&gt;. To do this open “Preferences”, search for “annotation” and check the “Enable annotation processing” option.&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 - Let&amp;#39;s enable 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;Let’s load JUnit 5&lt;/h3&gt;
&lt;p&gt;Unfortunately the test dependency &lt;code class=&quot;language-text&quot;&gt;org.springframework.boot:spring-boot-starter-test&lt;/code&gt;, which we can find in the &lt;code class=&quot;language-text&quot;&gt;build.gradle&lt;/code&gt; file, still uses JUnit 4. Since later on we’ll use some advanced features, we need &lt;strong&gt;JUnit 5&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To achieve the goal, let’s add the JUnit 5 dependencies to the &lt;code class=&quot;language-text&quot;&gt;build.gradle&lt;/code&gt; file.&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;Finally we need to “tell” Gradle to use JUnit 5 during the &lt;code class=&quot;language-text&quot;&gt;./gradlew test&lt;/code&gt; command and to show the full logs. This makes it easier to debug if there are problems.
Again in the &lt;code class=&quot;language-text&quot;&gt;build.gradle&lt;/code&gt; file let’s add at the bottom&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;In our project there’s already a test file written in JUnit 4. The file is located at &lt;code class=&quot;language-text&quot;&gt;src/test/java/it/mattianatali/tddspringbootapi/TddSpringBootApiApplicationTests.java&lt;/code&gt;. This test simply tries to load the Spring context. It may seem like a trivial test, but as the project grows, it takes little to forget some annotation and therefore have Spring not load correctly.&lt;/p&gt;
&lt;p&gt;Our first step is to &lt;strong&gt;migrate it to JUnit 5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It should be written like this:&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;We modify it like this:&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;Did you notice any differences? To migrate a test from JUnit 4 to JUnit 5 you need to be careful about these things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Change the &lt;code class=&quot;language-text&quot;&gt;@RunWith(SpringRunner.class)&lt;/code&gt; annotation to &lt;code class=&quot;language-text&quot;&gt;@ExtendWith(SpringExtension.class)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Be sure to &lt;strong&gt;always&lt;/strong&gt; have &lt;code class=&quot;language-text&quot;&gt;junit.jupiter&lt;/code&gt; in the &lt;code class=&quot;language-text&quot;&gt;import&lt;/code&gt; of all JUnit classes. In fact, if you read &lt;code class=&quot;language-text&quot;&gt;jupiter&lt;/code&gt; it means you’re using JUnit 5. We can notice that the &lt;code class=&quot;language-text&quot;&gt;@Test&lt;/code&gt; annotation changed package… Remember you must use &lt;code class=&quot;language-text&quot;&gt;junit.jupiter&lt;/code&gt;!&lt;/li&gt;
&lt;li&gt;Test classes and methods don’t necessarily have to be &lt;code class=&quot;language-text&quot;&gt;public&lt;/code&gt;. If you use IntelliJ it will complain about this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let’s try to see if our test suite is configured correctly. To do this let’s create a temporary test that will surely fail.&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;The ellipses &lt;code class=&quot;language-text&quot;&gt;...&lt;/code&gt; in the code mean there’s more in the file which I haven’t written to avoid distractions.&lt;/p&gt;
&lt;p&gt;Let’s try running the tests: we use IntelliJ or Gradle with the &lt;code class=&quot;language-text&quot;&gt;./gradlew test&lt;/code&gt; command.
We expect one test to pass and the other to fail.&lt;/p&gt;
&lt;p&gt;The test output is the following&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;That’s exactly what we expected! Now &lt;strong&gt;let’s remove the failing test&lt;/strong&gt; and we can be sure that JUnit 5 is configured perfectly!&lt;/p&gt;
&lt;h2&gt;How to structure the backend&lt;/h2&gt;
&lt;p&gt;Before we start writing code we need to be aligned on how we’re going to architect our software.
Usually, the bare minimum to create a backend that exposes RESTful APIs is to implement three types of classes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Controller&lt;/strong&gt;: its only purpose is to validate the input values, declare the endpoints we want to expose, invoke a service and provide the response given by the service class.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Service&lt;/strong&gt;: inside it we have the real business logic that depends on the project; it does the dirty work and, if it needs to persist some data, it invokes the repositories.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repository&lt;/strong&gt;: it exists to persist data somewhere, usually in a DB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course you can do everything in one class, but &lt;strong&gt;if we want to structure good, testable and reusable code, this is the minimum&lt;/strong&gt;. We must always remember that the more a class has a well-defined purpose, the simpler it is to implement but above all the easier it is to reuse in other places.&lt;/p&gt;
&lt;h2&gt;Let’s implement the GET call&lt;/h2&gt;
&lt;p&gt;Let’s start! The &lt;code class=&quot;language-text&quot;&gt;GET - /api/v1/vehicles/{id}&lt;/code&gt; call, we said, must provide the vehicle details. To develop it I imagine being the HTTP request. The first class affected by the call is the controller; as we said, its function is to validate the input values and expose the endpoint we’re going to call.
Let’s create the controller. Let’s create the 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;For now this is enough; we’re developing in TDD so &lt;strong&gt;our implementation must be driven by tests&lt;/strong&gt;. With IntelliJ we can press &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;, select “Create New Test…” and confirm. This way we find the test file created specifically for our controller.&lt;/p&gt;
&lt;p&gt;Let’s now think about what our controller must do to achieve the goal:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Declare that the endpoint &lt;code class=&quot;language-text&quot;&gt;GET - /api/v1/vehicles/{id}&lt;/code&gt; exists.&lt;/li&gt;
&lt;li&gt;Receive the vehicle id from the call path.&lt;/li&gt;
&lt;li&gt;Call the &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; service, which doesn’t exist yet, with the id taken from the previous point.&lt;/li&gt;
&lt;li&gt;If &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; returns a vehicle, then respond with a &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt; as &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt; and the vehicle in the body, otherwise respond with a nice &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Simplified version&lt;/h3&gt;
&lt;p&gt;Since we’re new to TDD, it’s really hard to write such a complete test on the first try.
So let’s try to proceed in small steps. &lt;strong&gt;Let’s test a simplified version&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Our first test will only verify this, then little by little we’ll add the remaining points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Verify that the endpoint &lt;code class=&quot;language-text&quot;&gt;GET - /api/v1/vehicles/{id}&lt;/code&gt; exists.&lt;/li&gt;
&lt;li&gt;It returns &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt; as statusCode.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our test is the following:&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;Now let’s explain point by point the new things we’ve never seen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ExtendWith(SpringExtension.class)&lt;/code&gt; is used to connect the JUnit context with the Spring Boot framework. This way we can use the annotations we commonly use with Spring Boot plus other annotations that exist specifically to make life easier during testing, like the next one.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@WebMvcTest(VehicleController.class)&lt;/code&gt; is our way of telling JUnit 5 + Spring Boot: “I want to test only the part dedicated to the &lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt; controller, so avoid loading the whole Spring Boot context”. In other words our test will start faster because our test knows well that it doesn’t have to load for example &lt;a href=&quot;https://hibernate.org/&quot;&gt;Hibernate&lt;/a&gt;, load DB drivers, configurations, services, repositories or other things, because we don’t need them. We’re testing only that controller. If instead we want to test something by loading the whole Spring Boot context we can use the &lt;code class=&quot;language-text&quot;&gt;@SpringBootTest&lt;/code&gt; annotation. But it’s always better to avoid it so as not to slow down test loading and execution.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Autowired private MockMvc mvc&lt;/code&gt; means “Spring Boot: provide me with a way to communicate with the controller I defined in the previous annotation (&lt;code class=&quot;language-text&quot;&gt;VehicleController&lt;/code&gt;), which lets me make HTTP calls”. &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt; means that Spring Boot provides it to us; we don’t have to worry about how it instantiates it for us. &lt;code class=&quot;language-text&quot;&gt;MockMvc mvc&lt;/code&gt; is the instance provided by Spring Boot that we’ll use to make HTTP calls.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I usually adopt this convention for test names: &lt;code class=&quot;language-text&quot;&gt;methodName_whatWeAreTesting&lt;/code&gt;. Don’t worry about writing a name that’s too long; you’ll never rewrite the method name. Here &lt;strong&gt;it’s important to be very clear about what we’re testing and what we expect&lt;/strong&gt;. Whenever you program, put yourself in the shoes of another developer who knows nothing about what you’re doing; &lt;strong&gt;try to make life easier for the next person&lt;/strong&gt;: in this case, the clearer we are, the happier our colleagues will be with our work.&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; is our way of making a &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; call to the endpoint we’re testing.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;.andExpect(status().isOk())&lt;/code&gt; is our assertion on the &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt; of our HTTP call; we expect a nice &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s run the test; we expect it to fail and to return a &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt; instead of the &lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt;, because the endpoint hasn’t been declared yet. With IntelliJ it’s very easy to test a single test; just click the green arrow next to the method name.&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 - Running the tests&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;This is the result of our 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;Exactly as we expected.&lt;/p&gt;
&lt;p&gt;Now let’s implement the bare minimum to make the test pass. Let’s write 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; is the Spring Boot annotation used to declare that we’re creating a 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; we declare the existence of our endpoint with the &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; method and that it has a variable in the path called &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; is used to extract the id from the path.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As we can notice, we don’t return anything from the endpoint… In fact we haven’t put any assertion in the test, so there’s no need to put anything else. For now we just want to test that it responds with &lt;code class=&quot;language-text&quot;&gt;statusCode&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt;. Which is the default value if we don’t insert anything.&lt;/p&gt;
&lt;p&gt;Let’s run the test, wait a few seconds, and this time it’s green! We can easily guess that our test isn’t sufficient; now let’s improve it so as to test at least the complete “happy path”.&lt;/p&gt;
&lt;h3&gt;Complete version&lt;/h3&gt;
&lt;p&gt;Let’s modify the test to make it complete:&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;Right now our compiler is in despair because it can’t find &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; nor the &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; class… In fact we haven’t created them yet!&lt;/p&gt;
&lt;p&gt;In this case too let’s see what’s new:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@MockBean private VehicleService vehicleService&lt;/code&gt; we’re telling Spring Boot: “If some class asks you for the &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; service, don’t pass the real implementation, but provide a fake instance, where I can decide what to return when invoking methods”. In fact later on with the &lt;code class=&quot;language-text&quot;&gt;when&lt;/code&gt; method we can decide what to return as a value, without calling the real implementation. The topic of what it means to “Mock” classes has already been covered in my previous article; if it’s not clear to you, it’s better that you &lt;a href=&quot;/en/how-to-develop-in-test-driven-development-tdd-from-scratch&quot;&gt;read the previous episode&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; we’re simply creating a vehicle model that will be returned as output by &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; and consequently by the controller. In this case we’ll use the builder that Lombok provides us; don’t worry for now, when we create the class it will be clearer.&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; we’re saying “if someone invokes &lt;code class=&quot;language-text&quot;&gt;vehicleService.get&lt;/code&gt; with the id &lt;code class=&quot;language-text&quot;&gt;vehicleId&lt;/code&gt;, then return an optional with our newly created vehicle”.&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; means that we expect in the response body a JSON containing an &lt;code class=&quot;language-text&quot;&gt;id&lt;/code&gt; field, with the id of our created vehicle inside. The other lines are very similar; only the field we’re checking changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We can’t run the tests because the code doesn’t even compile. So let’s create the missing classes. With IntelliJ it’s very simple to create classes or methods that don’t exist yet; just move the cursor over the non-existent class, press &lt;code class=&quot;language-text&quot;&gt;alt&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;Enter&lt;/code&gt;, click on ”&lt;em&gt;Create class …&lt;/em&gt;”, choose &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; and not &lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt; as the target directory, and confirm.&lt;/p&gt;
&lt;p&gt;Let’s do this procedure with &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;. Then let’s implement it.
The file should be located at &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;Here we can see Lombok in action! Thanks to the &lt;code class=&quot;language-text&quot;&gt;@Data&lt;/code&gt; annotation we don’t have to write getters or setters or override equals or hash; it does everything! With &lt;code class=&quot;language-text&quot;&gt;@Builder(toBuilder = true)&lt;/code&gt; instead we get for free a handy builder that we already used in the test. &lt;code class=&quot;language-text&quot;&gt;toBuilder = true&lt;/code&gt; provides us with a handy method on the instance that lets us get a builder from the instance itself, very handy for creating for example a clone by modifying maybe one of its fields.
&lt;code class=&quot;language-text&quot;&gt;@NoArgsConstructor&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;@AllArgsConstructor&lt;/code&gt; are two more Lombok annotations that provide us with both the constructor with all parameters and the empty constructor. They’re very useful for serializing instances to JSON. In fact if we don’t put these two annotations, &lt;a href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Jackson&lt;/a&gt;, which is the library Spring Boot uses to create response JSONs, will complain because it can’t serialize the object.
Less code to write means less code to manage and test!&lt;/p&gt;
&lt;p&gt;Now we need to create &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;. In this case &lt;strong&gt;let’s write the bare minimum to be able to compile&lt;/strong&gt;; we must remember that &lt;strong&gt;in the test we use the mocked version, so the real implementation doesn’t interest us now&lt;/strong&gt;. We’ll worry about it when we develop in TDD on it. Here too we can let IntelliJ help us.&lt;/p&gt;
&lt;p&gt;Once the class is created, we can tell IntelliJ to create the &lt;code class=&quot;language-text&quot;&gt;VehicleService.get&lt;/code&gt; method we invoked in the test line &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;enter&lt;/code&gt; is our best friend in this case.&lt;/p&gt;
&lt;p&gt;The file &lt;code class=&quot;language-text&quot;&gt;src/main/java/it/mattianatali/tddspringbootapi/vehicle/VehicleService.java&lt;/code&gt; will therefore contain&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; is used to say that the class is a service and that it can be created by Spring Boot through &lt;em&gt;Dependency Injection (DI)&lt;/em&gt; and that it can be injected into other classes when they use the &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt; annotation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The method is obviously wrong, but I repeat, now we only care that it compiles so as to run the tests.&lt;/p&gt;
&lt;p&gt;Here there’s a very interesting thing to notice: &lt;strong&gt;we defined the method &lt;em&gt;signature&lt;/em&gt; first before thinking about its actual implementation&lt;/strong&gt;. In this we &lt;strong&gt;define classes from the point of view of the &lt;em&gt;user&lt;/em&gt; and not of the &lt;em&gt;creator&lt;/em&gt;&lt;/strong&gt;. Usually this is a good thing because it creates method signatures that are easy to use. If we reverse the procedure we end up simplifying the implementation but making it hard to use the created classes because we don’t think about how a possible user could exploit these classes.&lt;/p&gt;
&lt;p&gt;Running the test we get the following error&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;Now it’s complaining that our endpoint doesn’t return any JSON and therefore it can’t test the various properties.
Perfect, let’s implement it to make the test pass.&lt;/p&gt;
&lt;p&gt;Let’s modify our &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;We can see for the first time how we can exploit Spring Boot’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;Dependency Injection&lt;/a&gt;&lt;/strong&gt;. We can ask Spring Boot to provide us with instances of classes we need to perform our task (in this case retrieving the vehicle), without us having to actually worry about &lt;em&gt;how&lt;/em&gt; these instances are created. In other words, through the &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt; annotation we’re telling Spring Boot to provide us in the constructor with all the instances we need, delegating to the framework how to create them.&lt;/p&gt;
&lt;p&gt;This way we can create classes that are decoupled from each other and above all in tests we can &lt;em&gt;inject&lt;/em&gt; fake (mocked) instances. By injecting mocked classes in tests we can drive the execution flow without taking our eyes off the class under test. Because in fact the only real implementation tested is the controller; the rest is all fiction (the fiction is given by the &lt;code class=&quot;language-text&quot;&gt;@MockBean&lt;/code&gt; annotation and the &lt;code class=&quot;language-text&quot;&gt;when().thenReturn()&lt;/code&gt; method).&lt;/p&gt;
&lt;p&gt;We must in fact imagine that during the test, the controller receives our mocked instance in the constructor, so it doesn’t touch the real implementation of &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; (which for now doesn’t exist yet… it always returns &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt;!).&lt;/p&gt;
&lt;p&gt;Maybe you’re wondering why there’s a double &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;. The first is the invocation of our &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; method; the second is used to extract the value contained in &lt;code class=&quot;language-text&quot;&gt;Optional&amp;lt;Vehicle&gt;&lt;/code&gt;. &lt;strong&gt;It’s strongly discouraged to call &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; on an optional&lt;/strong&gt; because we’re not handling the case where the optional is empty, in other words when the vehicle doesn’t exist. But for now our goal is to make the test pass; then &lt;strong&gt;when we write the test that tests the case where the vehicle doesn’t exist, we’ll fix it&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Running the test we see that it actually works! We return the JSON with all the fields.&lt;/p&gt;
&lt;h3&gt;Let’s test the vehicle-absent case&lt;/h3&gt;
&lt;p&gt;We’ve tested when the vehicle is returned by &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;, but what happens when the vehicle with a certain id doesn’t exist? We expect the endpoint to return &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Let’s create the test that verifies this case; in &lt;code class=&quot;language-text&quot;&gt;VehicleControllerTest&lt;/code&gt; let’s write:&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;Running the test it explodes like this&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 practice it’s our famous &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; on the optional that we put in the controller. We’re trying to retrieve data that doesn’t exist and therefore it throws an exception.&lt;/p&gt;
&lt;p&gt;Let’s modify the controller so that it returns a &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt; status code when the service doesn’t return any vehicle.
To respond &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt; we need an exception that generates that status code.
So let’s create the exception in &lt;code class=&quot;language-text&quot;&gt;src/main/java/it/mattianatali/tddspringbootapi/vehicle/errors/VehicleNotFoundException.java&lt;/code&gt; and write&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;Thanks to &lt;code class=&quot;language-text&quot;&gt;@ResponseStatus(HttpStatus.NOT_FOUND)&lt;/code&gt; we’re sure that the status code of the call will be &lt;code class=&quot;language-text&quot;&gt;404 - Not Found&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Now let’s modify the &lt;code class=&quot;language-text&quot;&gt;VehicleController.getVehicleDetails&lt;/code&gt; method using this new exception&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 practice we replaced the &lt;code class=&quot;language-text&quot;&gt;.get&lt;/code&gt; method with &lt;code class=&quot;language-text&quot;&gt;.orElseThrow(VehicleNotFoundException::new)&lt;/code&gt;. This is the way to generate an exception in case of a missing value in the optional.&lt;/p&gt;
&lt;p&gt;Let’s run the test and now everything works!&lt;/p&gt;
&lt;h3&gt;Let’s recap&lt;/h3&gt;
&lt;p&gt;Let’s stop for a second to take stock. The work to finish the GET endpoint isn’t done yet. But now it’s important to focus on what we’ve learned and done so far:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We created a new Spring Boot project using &lt;a href=&quot;https://start.spring.io/&quot;&gt;Spring Initializr&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We migrated the test suite to &lt;a href=&quot;https://junit.org/junit5/&quot;&gt;JUnit 5&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We learned to use some features of &lt;a href=&quot;https://projectlombok.org/&quot;&gt;Lombok&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;We developed the controller for the &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; call in TDD.&lt;/li&gt;
&lt;li&gt;We learned to exploit Spring Boot’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;Dependency Injection&lt;/a&gt; and &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt; annotation to test the controller in isolation, even before implementing the &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; service.&lt;/li&gt;
&lt;li&gt;We learned to make fake HTTP calls using &lt;code class=&quot;language-text&quot;&gt;@WebMvcTest&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s take a break; all the concepts just exposed need a moment to be assimilated. Then we’ll continue developing the two remaining components: the &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; service and the &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; repository.&lt;/p&gt;
&lt;h3&gt;Let’s implement the VehicleService service&lt;/h3&gt;
&lt;p&gt;Now that we’ve regenerated a bit, let’s do a fairly simple job: the implementation of &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;. All the business logic should go in this class, but the logic that the GET call has is really trivial: retrieve the vehicle given its id. Don’t worry, in real projects the business logic always becomes as complex as you like. We’re just lucky because we’re at the beginning.
In other words, in our case we must test that &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; is invoked to retrieve the vehicle, and the return value must be exactly the same as we get from &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; doesn’t exist yet, so we need to think about the method that suits our needs. Let’s not reinvent anything, so let’s imagine using the &lt;code class=&quot;language-text&quot;&gt;VehicleRepository.findById(Long id)&lt;/code&gt; method that &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; gives us for free.&lt;/p&gt;
&lt;p&gt;Let’s write the tests in the new 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;But let’s notice some differences in the annotations used; we’re referring to&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ExtendWith(MockitoExtension.class)&lt;/code&gt; instead of &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; instead of &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; is new.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why do we have these differences compared to our controller test? Because if we think about it carefully &lt;strong&gt;we don’t need to load any Spring Boot component&lt;/strong&gt; (in the controller we needed Spring Boot’s &lt;code class=&quot;language-text&quot;&gt;MockMvc&lt;/code&gt; to simulate HTTP calls), so we can use only the &lt;a href=&quot;https://site.mockito.org/&quot;&gt;Mockito&lt;/a&gt; library to test our service. This &lt;strong&gt;means having faster tests&lt;/strong&gt; to start because we don’t have to load the Spring Boot context. The annotations for using Mockito are precisely&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ExtendWith(MockitoExtension.class)&lt;/code&gt; to start the Mockito context and its annotations during the test.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Mock&lt;/code&gt; to create a mocked instance whose responses we can decide, through the &lt;code class=&quot;language-text&quot;&gt;when(...).thenReturn(...)&lt;/code&gt; method during tests.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@InjectMocks&lt;/code&gt; to inject the mocked instances into our service under test (in our case &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The rest shouldn’t surprise you too much; very normal tests organized into &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;Since the compiler is complaining that &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; doesn’t exist, let’s create it without implementing the method. This way we can run the &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt; test.
In &lt;code class=&quot;language-text&quot;&gt;src/main/java/it/mattianatali/tddspringbootapi/vehicle/VehicleRepository.java&lt;/code&gt; let’s write:&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;Now it compiles! Let’s run our service tests and of course they fail.
Let’s implement the service, which will be very simple; it does nothing but act as a “proxy” to our future &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;Here too nothing exceptional. We take &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; via DI in the constructor and use it to provide the vehicle in the &lt;code class=&quot;language-text&quot;&gt;get&lt;/code&gt; call.
Let’s run the tests and they’re green!&lt;/p&gt;
&lt;h3&gt;Let’s implement the VehicleRepository&lt;/h3&gt;
&lt;p&gt;We’re almost at the end; we only need &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; to finish the &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; call.
Here we need to test the &lt;code class=&quot;language-text&quot;&gt;findById&lt;/code&gt; method to retrieve the vehicle; to do a complete test we must also be able to save a vehicle before retrieving it.&lt;/p&gt;
&lt;p&gt;Let’s write the 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;With this test we save a vehicle, then retrieve it with the id returned to us in &lt;code class=&quot;language-text&quot;&gt;save&lt;/code&gt;, and then verify that &lt;code class=&quot;language-text&quot;&gt;findById&lt;/code&gt; returns the vehicle.
But let’s look at the annotations we used: they’re practically the same as we used for the controller, but this time instead of &lt;code class=&quot;language-text&quot;&gt;@WebMvcTest&lt;/code&gt; we used &lt;code class=&quot;language-text&quot;&gt;@DataJpaTest&lt;/code&gt;, which is used to test data persistence. We need to use the Spring Boot context because JPA requires it; consequently we can’t use only Mockito as we did with &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this case too it doesn’t compile, because we don’t have the &lt;code class=&quot;language-text&quot;&gt;save&lt;/code&gt; method declared in &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt;. Let’s fix the issue intelligently. Let’s transform &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; like this:&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;We transformed &lt;code class=&quot;language-text&quot;&gt;VehicleRepository&lt;/code&gt; into an interface that extends &lt;code class=&quot;language-text&quot;&gt;CrudRepository&lt;/code&gt;; in this case &lt;a href=&quot;https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-spring-data-jpa-repositories&quot;&gt;we use a bit of magic offered by JPA&lt;/a&gt;. &lt;code class=&quot;language-text&quot;&gt;CrudRepository&lt;/code&gt; gives us for free the &lt;code class=&quot;language-text&quot;&gt;save&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;findById&lt;/code&gt; methods we’re using.&lt;/p&gt;
&lt;p&gt;Now it compiles! Let’s try starting the Repository test, but unfortunately it fails like this:&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;What Spring Boot is trying to tell us is that the &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; model is missing the annotations needed to use it together with &lt;code class=&quot;language-text&quot;&gt;CrudRepository&lt;/code&gt;; in fact, if we think about it, nobody said which is the id field of our vehicle and how to generate it. Poor JPA only knows that the &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; model exists and nothing else.&lt;/p&gt;
&lt;p&gt;Let’s fix the problem by modifying our &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; file:&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;We added three annotations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Entity&lt;/code&gt; is used by JPA to understand that the &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; class can be used as a model for data persistence in the DB.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Id&lt;/code&gt; we’re indicating the &lt;code class=&quot;language-text&quot;&gt;Long id&lt;/code&gt; field as the id of our table in the DB.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@GeneratedValue(strategy = GenerationType.IDENTITY)&lt;/code&gt; we’re telling JPA to delegate id generation to the DB if it isn’t specified.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s start the test and this time it works!&lt;/p&gt;
&lt;h3&gt;Test in case of missing vehicle&lt;/h3&gt;
&lt;p&gt;Let’s add a simple test to verify that an &lt;code class=&quot;language-text&quot;&gt;Optional.empty()&lt;/code&gt; is returned if the vehicle doesn’t exist.&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;We can rest assured that during the test there’s no value with that id because the &lt;code class=&quot;language-text&quot;&gt;@DataJpaTest&lt;/code&gt; annotation guarantees us that every time we run the test the DB is clean.
Running it we see that the test passes as we expected; we don’t need to implement anything else.&lt;/p&gt;
&lt;p&gt;We must remember that DB setup is usually much more demanding: there are migrations, explicit table creation, calls to a remote DB, etc. We’re getting off easily with the H2 DB we inserted during project creation. Unfortunately we won’t cover these topics together so as not to lose focus on TDD.&lt;/p&gt;
&lt;h3&gt;Tests on repositories&lt;/h3&gt;
&lt;p&gt;In our case, because of this simplification, we’re testing on an in-memory DB created specifically for tests, all thanks to the &lt;code class=&quot;language-text&quot;&gt;@DataJpaTest&lt;/code&gt; annotation. Unfortunately, by doing so, tests on repositories lose most of their effectiveness. But now let’s try to imagine using this modus operandi on a real project.&lt;/p&gt;
&lt;p&gt;At Pirelli we test repositories on a DB very similar to the real one. In this case the advantages of testing repos are many, even though the implementation is done “magically” by Spring. For example by testing a trivial auto-generated &lt;code class=&quot;language-text&quot;&gt;.save()&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can test that all the model’s properties are mapped to the DB.&lt;/li&gt;
&lt;li&gt;We can verify that migrations truly reflect the code.&lt;/li&gt;
&lt;li&gt;We can verify that there are no typos in the enums that are mapped in the DB, or that all enums are present on the DB side too.&lt;/li&gt;
&lt;li&gt;We can verify that the JDBC driver is able to map all the properties present on the model (e.g. old drivers might not map Java 8 &lt;code class=&quot;language-text&quot;&gt;Date&lt;/code&gt; classes correctly).&lt;/li&gt;
&lt;li&gt;We can verify that relationships are saved as we expect.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then the repository can grow and we can create new methods auto-generated by Spring, but here too:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can test that relationships are retrieved correctly.&lt;/li&gt;
&lt;li&gt;We can verify that there are no logic errors in the auto-generated method (it takes a moment to confuse one id with another or forget a Not in the method).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally we mustn’t fool ourselves into thinking that the implementation is simple (the &lt;code class=&quot;language-text&quot;&gt;.save()&lt;/code&gt; method is auto-generated!) and therefore the test is useless: tests guide our development in TDD. So first we test that the functionality doesn’t exist, then we implement it, and finally &lt;strong&gt;the test verifies that it exists and remains so for &lt;em&gt;all&lt;/em&gt; future developments&lt;/strong&gt;: the &lt;code class=&quot;language-text&quot;&gt;.save()&lt;/code&gt; method can become complicated; maybe it will no longer be auto-generated because ad hoc logic has been added. Our test will always be there to give us this guarantee. If we don’t do it at the beginning, we miss this opportunity and we might have regrets later.&lt;/p&gt;
&lt;h3&gt;GET call completed!&lt;/h3&gt;
&lt;p&gt;Finally we have the GET call completely developed in TDD! We have 3 well-isolated components, easy to test, with 100% coverage.
It seems like it was long and difficult, but only because we explained every single line of code and also because we explained every single step we took.
The good news is that through this process we can create any endpoint we can think of: we can complicate the business logic as much as we want, but the TDD procedure will always remain the same.&lt;/p&gt;
&lt;p&gt;Now let’s implement the POST call, but we’ll explain with the same level of detail only the controller, where I can share some tricks with you that I haven’t covered yet. The development of the methods in the service and the repository will be very similar to what we did for the GET call, so it would be of little use to repeat the same things.&lt;/p&gt;
&lt;h2&gt;Let’s implement the controller for the POST call&lt;/h2&gt;
&lt;p&gt;Let’s now move on to developing the POST call to create new vehicles. As always let’s start with the tests. The first thing we verify is that our vehicle passed in the body is correctly digested by Spring Boot and that it’s passed to the &lt;code class=&quot;language-text&quot;&gt;VehicleService.save(vehicle)&lt;/code&gt; method to save it.&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;As we can read, we’re emulating a POST call, we correctly set the &lt;code class=&quot;language-text&quot;&gt;contentType&lt;/code&gt; of the call via &lt;code class=&quot;language-text&quot;&gt;.contentType(MediaType.APPLICATION_JSON)&lt;/code&gt; and we insert our vehicle to save in the body via &lt;code class=&quot;language-text&quot;&gt;.content(objectMapper.writeValueAsBytes(vehicleToSave))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With&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;we emulate the fact that our service returns the same object passed as input but with the id populated. For this case we used the &lt;code class=&quot;language-text&quot;&gt;toBuilder&lt;/code&gt; method kindly offered by the &lt;code class=&quot;language-text&quot;&gt;@Builder(toBuilder = true)&lt;/code&gt; annotation we had added to the &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;Finally we test that the HTTP call responds with the &lt;code class=&quot;language-text&quot;&gt;201 - Created&lt;/code&gt; statusCode and that in the body we have all the fields populated.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;objectMapper&lt;/code&gt; is Spring Boot’s default serializer, &lt;a href=&quot;https://github.com/FasterXML/jackson&quot;&gt;Jackson&lt;/a&gt;. We ask Spring Boot for an instance of it via &lt;code class=&quot;language-text&quot;&gt;@Autowired&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The compiler is complaining that the save method doesn’t exist on &lt;code class=&quot;language-text&quot;&gt;VehicleService&lt;/code&gt;; let’s add it without implementing the correct logic.&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;Let’s start the test and it fails for this reason&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;Rightly the endpoint doesn’t exist yet, so let’s add it to &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; is the annotation that lets us define a POST endpoint.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@ResponseStatus(HttpStatus.CREATED)&lt;/code&gt; we can define the response status code; by default it’s &lt;code class=&quot;language-text&quot;&gt;200 - Ok&lt;/code&gt;, but we want &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; is the annotation that lets us take the value passed in the body and deserialize it to &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case we just need to invoke the &lt;code class=&quot;language-text&quot;&gt;vehicleService.save&lt;/code&gt; method and return its value.&lt;/p&gt;
&lt;p&gt;Running the tests everything is OK!&lt;/p&gt;
&lt;p&gt;We’re almost done, but we still need to implement the rule we were given when saving a vehicle. Let me restate it here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;brand&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; are mandatory; the vehicle’s year of production can’t be earlier than &lt;code class=&quot;language-text&quot;&gt;1950&lt;/code&gt; for business reasons.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s create the test that verifies these conditions.&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;Here we can see a beautiful JUnit 5 feature: &lt;strong&gt;parameterized tests&lt;/strong&gt;!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Through the &lt;code class=&quot;language-text&quot;&gt;@ParametrizedTest&lt;/code&gt; annotation we define a test that wants a parameter as input.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@MethodSource(&quot;getInvalidVehicles&quot;)&lt;/code&gt; we define the method that will provide us with the vehicles that are invalid and that we need to test.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;getInvalidVehicles()&lt;/code&gt; method returns a stream of invalid vehicles; to create this stream we start from a valid vehicle that we’ve already tested in the other test (&lt;code class=&quot;language-text&quot;&gt;aValidVehicle()&lt;/code&gt;), then from this we create an invalid vehicle by modifying the parameters. This way we create 6 tests that respectively test all the rules the business has imposed on us, namely:
&lt;ul&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;brand&lt;/code&gt; parameter can’t be null or an empty string.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;model&lt;/code&gt; parameter can’t be null or an empty string.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; parameter can’t be null.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;year&lt;/code&gt; parameter can’t be less than &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;Let’s start the test and indeed we see that we have 6 failing tests.&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;To implement vehicle validation we can exploit Spring Boot’s validation.
So let’s add the validation rules to the &lt;code class=&quot;language-text&quot;&gt;Vehicle&lt;/code&gt; model.&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; we say that the field can’t be &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; we say that the field can’t be an empty string.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@Min(1950)&lt;/code&gt; means that the field must be at least &lt;code class=&quot;language-text&quot;&gt;1950&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, to enable validation, we need to modify the controller by putting the &lt;code class=&quot;language-text&quot;&gt;@Valid&lt;/code&gt; annotation 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 punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&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;Let’s run the tests and now they’re all green! This way we did 6 tests in one go without duplicating code.&lt;/p&gt;
&lt;p&gt;Now that we’ve implemented the controller, the &lt;code class=&quot;language-text&quot;&gt;vehicleService.save&lt;/code&gt; method is still missing; I’ll leave this as homework since it wouldn’t add any value to this article: we practically have to do the same thing we did with the GET call. And the &lt;code class=&quot;language-text&quot;&gt;VehicleRepository.save&lt;/code&gt; method we’ve already tested when we implemented the GET call.
In any case &lt;a href=&quot;https://github.com/matitalatina/tdd-spring-boot-api&quot;&gt;in my repository&lt;/a&gt; you can find the complete project.&lt;/p&gt;
&lt;h1&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;It’s been a long chat; &lt;strong&gt;I really hope that&lt;/strong&gt; after this reading you’ve learned a few features offered by JUnit 5, Spring Boot, Lombok, but above all &lt;strong&gt;that the philosophy of TDD has entered into you&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The thing that must be clear is this: &lt;strong&gt;first we worry about what we want to achieve, then we worry about how to achieve it&lt;/strong&gt;. The &lt;em&gt;what&lt;/em&gt; we want to achieve translates into tests, the &lt;em&gt;how&lt;/em&gt; translates into the implementation.&lt;/p&gt;
&lt;p&gt;This way we have well-tested code, well organized into isolated classes (if a class is easy to test, it means it’s well isolated from the rest of the components) and above all easy to maintain (refactors are simple because every single feature is tested, regressions are practically zero).&lt;/p&gt;
&lt;p&gt;At first it can be difficult, but then once internalized it comes naturally and you have an added value that you can’t understand until you have a project developed in TDD in production. Try it to believe it!&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to create a Continuous Integration and Continuous Deployment (CI/CD) pipeline · DevOps]]></title><description><![CDATA[Introduction One thing I learned at Pirelli is the implementation of pipelines to get Continuous Integration (CI) and Continuous Deployment…]]></description><link>https://www.mattianatali.it/en/how-to-create-a-ci-cd-pipeline/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-create-a-ci-cd-pipeline/</guid><pubDate>Sat, 16 Mar 2019 07:03:47 GMT</pubDate><content:encoded>&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;One thing I learned at Pirelli is the implementation of pipelines to get Continuous Integration (CI) and Continuous Deployment (CD), from now on I’ll simply call it &lt;a href=&quot;https://en.wikipedia.org/wiki/CI/CD&quot;&gt;CI/CD&lt;/a&gt;. Many projects with a microservices architecture are always being born: time at work is always short and repetitive work bores me easily… What’s more repetitive than putting all these microservices into production? These automatic pipelines therefore become essential so as not to spend the day doing only this boring job.&lt;/p&gt;
&lt;p&gt;I don’t want to bore you too much talking about the various advantages that CI/CD brings; if you’ve come to this post it means you already know, so I’ll start right away with a practical example.&lt;/p&gt;
&lt;h2&gt;Creating the pipeline for GasLow Backend&lt;/h2&gt;
&lt;p&gt;As an example I’ll use the backend of a project I created in my free time: &lt;a href=&quot;https://github.com/matitalatina/gaslow&quot;&gt;GasLow&lt;/a&gt;. Basically it’s a backend that’s able to retrieve open data about fuel prices in Italy and provide this information based on your location. The Android app, based on &lt;a href=&quot;https://flutter.dev/&quot;&gt;Flutter&lt;/a&gt;, that uses this backend is &lt;a href=&quot;https://play.google.com/store/apps/details?id=it.mattianatali.gaslowapp&amp;#x26;hl=en&quot;&gt;available for free on the Play Store&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The important things for us are these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The backend is written in Node.js + TypeScript, the database is MongoDB.&lt;/li&gt;
&lt;li&gt;The configuration file with the data to connect to the DB is in the &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; file, in the project root. Of course the file isn’t published on Git to avoid the whole world knowing the DB credentials. You can see an example of the data contained in this file by reading &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The “production” server is on &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; on a free machine. In this guide we’ll be able to automate the deploy to Heroku.&lt;/li&gt;
&lt;li&gt;I’m also implementing the AWS serverless version, where it’s deployed using CloudFormation. Unfortunately this part is a bit too much to explain in this introductory guide on CI/CD. Maybe I’ll make a dedicated guide on this topic in the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Prerequisites&lt;/h1&gt;
&lt;p&gt;To fully understand this guide we need these skills:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At least a basic knowledge of &lt;a href=&quot;https://en.wikipedia.org/wiki/Git_(software)&quot;&gt;Git&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;How a &lt;a href=&quot;https://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; project is structured and the basic commands of its package manager &lt;a href=&quot;https://en.wikipedia.org/wiki/Npm_(software)&quot;&gt;npm&lt;/a&gt;. This part actually isn’t mandatory to understand the pipeline as a concept, it’s only needed to understand the pipeline of this specific example.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Let’s choose the CI/CD service&lt;/h1&gt;
&lt;p&gt;The first important step to automate everything is choosing the service we want to use. The choice is really wide. The ones I know and have used are these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt;: very powerful and flexible. It’s hosted by them and so we don’t need our own machine to run it. It offers a free plan of 1000 minutes/month for both your public and private projects; not bad for hobby use. For now it’s my first choice for my private projects and it was what I used at Pirelli until a month ago.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://about.gitlab.com/&quot;&gt;GitLab&lt;/a&gt;: this is also as powerful as CircleCI. You can use the version hosted by them or install it on your machine. It’s a bit different from the others because it offers a complete package for your project (it has Git integrated so you can use it as a repository too). For now it’s our first choice at Pirelli and in fact we’re doing a nice migration from CircleCI.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis CI&lt;/a&gt;: maybe it’s a tad behind the first two. For example it’s not yet possible to do a manual deploy, &lt;a href=&quot;https://stackoverflow.com/questions/50831785/travis-manually-confirm-next-stage&quot;&gt;unless you come up with hacks like this&lt;/a&gt;. By manual I mean having a button that allows us to run a deploy only after a confirmation. This feature is very useful for me to have full control of when we want to deploy to production. Apart from this small flaw it has a huge advantage: it’s free for all public projects! Precisely for this reason I use it for my public projects (like GasLow). &lt;strong&gt;Our guide will be based on Travis CI&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jenkins.io/&quot;&gt;Jenkins&lt;/a&gt;: it’s a milestone and the oldest of all. I’ve used it only a few times and honestly it never excited me that much, especially as far as UX is concerned. But this is my personal opinion and therefore quite subjective.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Goal of the guide&lt;/h1&gt;
&lt;p&gt;In this guide I’d like to experience with you the &lt;strong&gt;creation of a pipeline with an already started project that’s already in production&lt;/strong&gt;. Why do it with an already started project? Because it’s a typical use case you encounter at work and it’s probably your current situation; finally because the web is already full of “hello world” for creating pipelines. But usually they are examples focused on learning the service that offers the pipelines, and not so much on learning the concepts and difficulties encountered in real life.&lt;/p&gt;
&lt;p&gt;Let’s make clear what we want to achieve: let’s imagine we’re at work and as the task of the week we’ve been asked to create the CI/CD pipeline for the GasLow project.
At the end of the guide we’ll have a pipeline made up of two phases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Running the tests: a fundamental step to get &lt;strong&gt;Continuous Integration (CI)&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Deploy to production on the Heroku machine: a step to get &lt;strong&gt;Continuous Deployment (CD)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the bare minimum to get a complete CI/CD pipeline and to not make the guide too long we’ll limit ourselves to these two steps.
Once you’ve become familiar with the topic you can complicate the pipeline as you like. For example a typical pipeline I use at work is made up of the following steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build and unit tests of the application.&lt;/li&gt;
&lt;li&gt;Creation of the Docker image through the Dockerfile, push of the image to the AWS ECR repository.&lt;/li&gt;
&lt;li&gt;Database migration and deploy of the Docker image in the DEV environment.&lt;/li&gt;
&lt;li&gt;Integration tests on the DEV environment.&lt;/li&gt;
&lt;li&gt;Database migration and deploy with manual confirmation in the QLT environment used by our QA Team.&lt;/li&gt;
&lt;li&gt;Database migration and deploy with manual confirmation in the Production environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Signing up to Travis CI&lt;/h1&gt;
&lt;p&gt;This step is very simple; just go to their &lt;a href=&quot;https://cdn.travis-ci.org/images/landing-page/laptop-f308ed79defa4f49c5f01af29a60084d.png&quot;&gt;home page&lt;/a&gt; and press the “SignUp” button, enter your GitHub credentials, and at this point you’ve effectively connected Travis CI to your GitHub. Once you’ve done this you’ll enter the Travis CI main page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.travis-ci.org/images/landing-page/laptop-f308ed79defa4f49c5f01af29a60084d.png&quot; alt=&quot;Travis CI main page&quot;&gt;&lt;/p&gt;
&lt;p&gt;on the left your GitHub projects that use Travis CI as a CI/CD service will appear. At the beginning it will obviously be empty. For now we don’t need to know anything else.&lt;/p&gt;
&lt;h1&gt;Forking the project&lt;/h1&gt;
&lt;p&gt;If you want to try it out yourself too, you can fork my project and throw away the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file because we’ll recreate it together to form the pipeline we have in mind.
The reference commit has the hash &lt;code class=&quot;language-text&quot;&gt;d09f1068a14ddcdb857f1ced90b532680b050917&lt;/code&gt;, so to be perfectly aligned with this guide we’ll need to check out this specific commit; I don’t rule out that the project may have deep changes over time.&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;Once forked and the file removed we can go to the Travis CI settings (user menu at the top right -&gt; Settings). On this page all our repos should appear, including this newly forked one. If you don’t see anything click on the &lt;code class=&quot;language-text&quot;&gt;Sync Account&lt;/code&gt; button to synchronize Travis CI. Then we can see the gaslow repo as in the figure; let’s enable the toggle.
Now we have the forked repo, Travis CI ready and connected to it. Now the fun part begins: let’s set up the first step of our 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;Implementing the Continuous Integration pipeline (testing phase)&lt;/h1&gt;
&lt;h2&gt;Testing locally&lt;/h2&gt;
&lt;p&gt;Before going on to create the pipeline let’s ask ourselves this question: how do you run the tests locally? &lt;strong&gt;The best way to create an automatic pipeline is to think of all the various steps we have to do locally to achieve the same goal&lt;/strong&gt;. Here I take for granted that we have a minimum of experience in Node.js and how the &lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt; package manager works.&lt;/p&gt;
&lt;p&gt;Someone who breathes Node.js from morning to night has already thought about how to do it: there’s the &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; command… But are we sure that’s enough? In this case we’re taking for granted a few things that for Travis CI won’t be at all.&lt;/p&gt;
&lt;p&gt;To run the tests with &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; we’re taking for granted the following points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js v8 is installed on your machine.&lt;/li&gt;
&lt;li&gt;On your machine we have MongoDB installed and active on the standard port &lt;code class=&quot;language-text&quot;&gt;:27017&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;We’ve installed all the dependencies (through the &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; command) and therefore we have the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder correctly populated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the correct steps to run the tests on a clean machine are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://nodejs.org/en/download/&quot;&gt;Install Node.js v8&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.mongodb.com/manual/installation/&quot;&gt;Install MongoDB&lt;/a&gt; and activate it on the default port &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; to install the dependencies present in the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file and therefore populate the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; to run the tests.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Testing using Travis CI&lt;/h2&gt;
&lt;p&gt;Now that we’ve understood the local steps, let’s try to translate them into steps that can be digested by Travis CI.&lt;/p&gt;
&lt;p&gt;To make Travis CI run the tests automatically we need a means of communicating. &lt;strong&gt;The way to communicate with this service is the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file&lt;/strong&gt;, precisely the file I had you delete during the project fork. You may be unfamiliar with the file extension. &lt;code class=&quot;language-text&quot;&gt;yml&lt;/code&gt; is used for the &lt;em&gt;YAML&lt;/em&gt; format which stands for (&lt;em&gt;YAML Ain’t Markup Language&lt;/em&gt;). It has become the de-facto standard in the DevOps world because on one hand it’s “expressively” very powerful, on the other it’s very simple for a human to read.
This format, however simple it may be to read, has many rules that take some time to master and know all of them. Anyway we don’t have to worry too much: we’ll only use the bare minimum and very basic concepts. I usually use &lt;a href=&quot;https://learnxinyminutes.com/docs/yaml/&quot;&gt;Learn yaml in Y minutes&lt;/a&gt; as a cheatsheet for yaml: this site is very concise and at the same time rich in information; give it a look for other languages too, you won’t regret it.&lt;/p&gt;
&lt;p&gt;Let’s start by creating the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file in the project root. Inside it let’s insert this content:&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;This way, Travis CI is able to run our tests. Let’s try committing the file; indeed we see that Travis CI has started working and has run the tests.&lt;/p&gt;
&lt;p&gt;Now let’s try to see the similarities with the steps we needed locally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Did we tell Travis CI to install Node.js v8? Yes, through the directive&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;Did we tell Travis CI to install MongoDB and open Mongo’s standard port? Yes, through the directive&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;Did we install the project dependencies before running the tests? Yes, through running the &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; script during the installation phase of our job, through the directive&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;Did we run the tests? Yes, through running the &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; script during the main phase of the job, through the directive&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;So we can say we’ve executed the same steps we did locally using a language that Travis CI understands. I don’t want to dwell too much on the language Travis CI uses because it’s very specific to the service we’re using: CircleCI, GitLab would have used a slightly different language. What must come across here is this: &lt;strong&gt;Travis CI is like a blank sheet of paper&lt;/strong&gt;; it’s up to us to instruct it how to run our tests. The best way to instruct it is to &lt;strong&gt;first think about the steps we do locally, then redo them in the language of the platform we use&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For those who want to know more about the specific Travis CI language, I’ll leave some links here that go deeper into the topics just covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/languages/&quot;&gt;To learn about the supported languages&lt;/a&gt;, specifically &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;To learn how to add new services&lt;/a&gt; like MongoDB.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.travis-ci.com/user/job-lifecycle/&quot;&gt;To learn about the various phases of a 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 using Travis CI&lt;/h2&gt;
&lt;p&gt;Now that we’ve run the tests we want to deploy our code to Heroku. &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;, for those who don’t know it, allows you to deploy your code on their &lt;a href=&quot;https://en.wikipedia.org/wiki/Platform_as_a_service&quot;&gt;PaaS&lt;/a&gt; platform.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before creating the pipeline, we need to create an application on Heroku,&lt;/strong&gt; fortunately they give you the possibility to host our project for free.&lt;/p&gt;
&lt;p&gt;Let’s sign up and create a new 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;Creating a new app on 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;Now let’s go back to the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file and add at the end:&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;MYSTERIOUS_STEP&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;A little explanation of what we’ve added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;before_deploy&lt;/code&gt; is the keyword to define what to do right before the &lt;em&gt;deploy&lt;/em&gt; phase. The deploy phase is the step within a job that’s dedicated to deploying our code to Heroku. The &lt;em&gt;job&lt;/em&gt;, for Travis CI, essentially consists of three phases: &lt;em&gt;install&lt;/em&gt;, &lt;em&gt;script&lt;/em&gt; and &lt;em&gt;deploy&lt;/em&gt;. If you want to go deeper, you can read the &lt;a href=&quot;https://docs.travis-ci.com/user/job-lifecycle/&quot;&gt;various phases that make up a job directly from the Travis CI documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;MYSTERIOUS_STEP&gt;&lt;/code&gt; is an essential step for the deploy that I haven’t told you yet; I’ll talk about it later.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npm run build&lt;/code&gt; is the script we need to run before the deploy. This script is strictly tied to our project. If you’re curious you can go to the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file and see that the build script runs the command &lt;code class=&quot;language-text&quot;&gt;parcel build src/server.ts --target node&lt;/code&gt;. It does nothing but call &lt;a href=&quot;https://parceljs.org/&quot;&gt;Parcel.js&lt;/a&gt; to &lt;a href=&quot;https://en.wikipedia.org/wiki/Source-to-source_compiler&quot;&gt;transpile&lt;/a&gt; the TypeScript code into JavaScript, bundle it, minify it and put it in the &lt;code class=&quot;language-text&quot;&gt;/dist&lt;/code&gt; folder. At the end of this project we therefore have the &lt;code class=&quot;language-text&quot;&gt;/dist/server.js&lt;/code&gt; file ready to be run in production.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;deploy&lt;/code&gt; is the keyword to define what to do during the deploy phase.&lt;/li&gt;
&lt;li&gt;With &lt;code class=&quot;language-text&quot;&gt;provider&lt;/code&gt; we define that we’re using Heroku as the platform.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;api_key&lt;/code&gt; is used to define the credentials to actually deploy with Heroku. The next step will be to replace &lt;code class=&quot;language-text&quot;&gt;&apos;&amp;lt;API_KEY&gt;&apos;&lt;/code&gt; with the real (encrypted) keys.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;app: &amp;lt;HEROKU_APP&gt;&lt;/code&gt; tells Travis CI which Heroku app we want to deploy to. We need to replace &lt;code class=&quot;language-text&quot;&gt;&amp;lt;HEROKU_APP&gt;&lt;/code&gt; with the name of the Heroku application we created in the previous step.&lt;/li&gt;
&lt;li&gt;With &lt;code class=&quot;language-text&quot;&gt;on: branch: master&lt;/code&gt; we can deploy only when we push to the &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; branch. Without this directive every single push to any git branch would trigger the automatic deploy.&lt;/li&gt;
&lt;li&gt;With &lt;code class=&quot;language-text&quot;&gt;env:&lt;/code&gt; we can define the environment variables that our project will have available on Heroku. In our case we added the &lt;code class=&quot;language-text&quot;&gt;NODE_ENV=production&lt;/code&gt; variable which is a standard in the Node.js world to define that we’re in a production environment.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;skip_cleanup: true&lt;/code&gt; allows us to avoid deleting the files generated in the previous step. During the test phase we ran the &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; command which populates the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder that’s essential for the correct functioning of the system. This way we can avoid redoing it and therefore save time in the deploy phase. We must imagine that the &lt;em&gt;deploy&lt;/em&gt; phase is separate from the &lt;em&gt;script&lt;/em&gt; phase, so we’d only have the source code without this directive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If we want to know all the various parameters we can use to deploy to Heroku &lt;a href=&quot;https://docs.travis-ci.com/user/deployment/heroku/&quot;&gt;we can read the official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To recap there are still two things to do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Understand what we need to do in the &lt;code class=&quot;language-text&quot;&gt;MYSTERIOUS_STEP&lt;/code&gt;: it has to do with the configuration of our project in production. Here’s a hint: go read the &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/src/util/secrets.ts&quot;&gt;src/util/secrets.ts&lt;/a&gt; file.&lt;/li&gt;
&lt;li&gt;Retrieve the encrypted Heroku &lt;code class=&quot;language-text&quot;&gt;API_KEY&lt;/code&gt; so that Travis CI can authenticate and run the deploy.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Understanding the mysterious step&lt;/h3&gt;
&lt;p&gt;There’s a part I’ve kept hidden from the start and now it’s time to talk about it. We said the project is based on MongoDB, but where does it get the credentials to connect? We ran tests earlier, yet it seems it connected without problems. Even Travis CI, during the tests, connected.
We can read the retrieval of the connection information in the &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/src/util/secrets.ts&quot;&gt;src/util/secrets.ts&lt;/a&gt; file which I’ll quote here for simplicity:&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 practice the code behaves like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It retrieves the &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; file; if it’s not there it falls back to the &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;It retrieves the &lt;code class=&quot;language-text&quot;&gt;SESSION_SECRET&lt;/code&gt; value from this file.&lt;/li&gt;
&lt;li&gt;It retrieves the &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI&lt;/code&gt; value if you’re in production, otherwise &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI_LOCAL&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally we can understand how the tests managed to connect to MongoDB without us doing anything: in practice it fell back to the &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt; file which is versioned on Git, read the value &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI_LOCAL=mongodb://localhost:27017&lt;/code&gt; and therefore connected to our local MongoDB, while Travis CI connected to the MongoDB service we instantiated in the pipeline.&lt;/p&gt;
&lt;p&gt;Our task is to &lt;strong&gt;find a way to load the &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; file in production&lt;/strong&gt; securely, versioned, but at the same time without having all the credentials to access our MongoDB written in clear text.&lt;/p&gt;
&lt;h3&gt;Loading the .env file securely&lt;/h3&gt;
&lt;p&gt;A solution to the previous problem is given to us &lt;a href=&quot;https://docs.travis-ci.com/user/encrypting-files/&quot;&gt;directly by Travis CI&lt;/a&gt;. For this step we need the &lt;a href=&quot;https://github.com/travis-ci/travis.rb#readme&quot;&gt;Travis CI Command Line Client&lt;/a&gt; which on Mac we can install like this:&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;Thanks to it we can encrypt files securely and save the encrypted file in the repo without fear that someone can steal our credentials.&lt;/p&gt;
&lt;p&gt;The first step is to create the &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; configuration file ready for production; &lt;strong&gt;we must be careful not to upload it to Git for any reason&lt;/strong&gt;, it’s not encrypted and if we version it anyone is able to access our DB! If you’re working on my project I’ve already taken care of it. In fact if we go to the &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/.gitignore&quot;&gt;.gitignore&lt;/a&gt; file we notice that the .env file is in the blacklist of files not to consider with Git.&lt;/p&gt;
&lt;p&gt;So let’s create the &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; file with the same data you find in the &lt;code class=&quot;language-text&quot;&gt;.env.example&lt;/code&gt; file&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;We need to modify two parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In &lt;code class=&quot;language-text&quot;&gt;MONGODB_URI&lt;/code&gt;, replace &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; with our DB credentials we want to use in production. I use the &lt;a href=&quot;https://mlab.com/&quot;&gt;mLab&lt;/a&gt; service.&lt;/li&gt;
&lt;li&gt;Replace &lt;code class=&quot;language-text&quot;&gt;&amp;lt;session_secret&gt;&lt;/code&gt; with a random alphanumeric string.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now let’s delete the &lt;code class=&quot;language-text&quot;&gt;.env.enc&lt;/code&gt; file, where my encrypted keys are, because now we’ll create our own encrypted file. With the values we just entered in the &lt;code class=&quot;language-text&quot;&gt;.env&lt;/code&gt; file. For this step we use the Travis CI command line.&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;The terminal will tell you to insert a string like this in the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file&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;this is exactly what we need to write in the mysterious step!
So let’s update the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file; the &lt;code class=&quot;language-text&quot;&gt;before_deploy&lt;/code&gt; phase will be like this&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;The command we just added does nothing but decode the encrypted file before deploying.&lt;/p&gt;
&lt;h3&gt;Getting the encrypted Heroku API key&lt;/h3&gt;
&lt;p&gt;We’re almost at the end; now we just need to &lt;strong&gt;insert the encrypted API key into our pipeline to allow Travis CI to deploy through Heroku&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For this step we need &lt;a href=&quot;https://devcenter.heroku.com/articles/heroku-cli&quot;&gt;Heroku CLI&lt;/a&gt; installed on our PC. If you have a Mac just type in the terminal (if you installed &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;We authenticate with Heroku using the command&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;and finally we type this command to get the 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;The command will return the API Key; we need to insert it in place of &lt;code class=&quot;language-text&quot;&gt;&apos;&amp;lt;API_KEY&gt;&apos;&lt;/code&gt; in the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file.
Once this is done we’ll have finished the work and can enjoy our Continuous Integration and Continuous Deployment 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/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;Deploy test on 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;Tips for creating pipelines&lt;/h1&gt;
&lt;p&gt;Now that we’ve seen a real use case I want to share some advice with you. I hope they’ll help you avoid a few headaches that I got instead:&lt;/p&gt;
&lt;h2&gt;The sooner we create it, the simpler it is&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The earlier you create the CI/CD implementation, the more time you save, but above all the simpler it is!&lt;/strong&gt; Ideally it’s better to do it during project creation. There are many reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;During project creation we’re already working on the project’s configuration and dependencies&lt;/strong&gt;. So everything we’re doing locally to set up our local environment, we just need to do the equivalent in the pipeline. Moreover if we know we’re implementing a pipeline from the start, &lt;strong&gt;we avoid creating tests or configurations that are too tied to our local machine&lt;/strong&gt;, we avoid writing strange configurations that complicate the pipeline precisely because it’s hard for us to replicate them in Travis CI (such as retrieving files that are in folders outside our Git project).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;We don’t have to do Reverse Engineering on the project to understand how to configure it&lt;/strong&gt;: nobody will warn us to find “the mysterious step” in real life and nobody will tell us to look at the &lt;a href=&quot;https://github.com/matitalatina/gaslow/blob/master/src/util/secrets.ts&quot;&gt;src/util/secrets.ts&lt;/a&gt; file to get a hint. In this guide I did it to avoid wasting too much time. Without this help we would have had to bang our heads several times and do a minimum of Reverse Engineering of the project to actually understand how the credential retrieval worked. All this could have been avoided if whoever designed this credential retrieval had kept the pipeline up to date. And whoever is new to the project just needs to look at the &lt;code class=&quot;language-text&quot;&gt;.travis.yml&lt;/code&gt; file to understand exactly the procedure to get a working local version.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human error in deploys is avoided&lt;/strong&gt;: having automated it is an advantage because there are no gross errors in the deploy. Imagine you have to run numerous deploys a day… After a while you’ll lower your guard and concentration, the error from carelessness is around the corner and making mistakes in deploys can cost a lot!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You save time&lt;/strong&gt;: banally, the sooner we create a pipeline the more man-hours we save. Nobody in the company is responsible for the deploy, anyone can do it. I’ve been in companies where the deploy was manual, and I saw a person who was fully occupied just with deploys during the most hectic moments. In my opinion that’s unacceptable. The tools to automate exist and are within everyone’s reach. Let’s use them!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Let’s think about setting up the pipeline locally&lt;/h2&gt;
&lt;p&gt;Trying directly on Travis CI can take a lot of time. For example if we have problems in the deploy, we have to push the new changes, wait for all the previous steps and then maybe find a nice error after 15 minutes. In this case we try to fix the problem by uploading the new changes and the cycle starts again… All this takes hours.
&lt;strong&gt;The best way to avoid all this is to try the steps locally&lt;/strong&gt;. A bit like we did in this guide during the creation of the Continuous Integration pipeline.
To achieve this goal we need to create steps that are agnostic with respect to the CI/CD service we use. Usually I create a folder with all the scripts useful for the deploy. This way I can invoke these scripts locally too and test the correct execution faster.
Moreover if we keep this point in mind it will also be easier to achieve the next one.&lt;/p&gt;
&lt;h2&gt;Let’s not focus too much on the single CI/CD service&lt;/h2&gt;
&lt;p&gt;In this guide we used Travis CI, in my previous job we used Jenkins. In my current job we used CircleCI, now instead we use GitLab CI. In short you’ll end up using all sorts of things, but they all solve the same problem: automating integration and deploy.
&lt;strong&gt;So let’s try to focus on the basic concepts and not so much on how to do it on a specific service&lt;/strong&gt;. This last part is simple if we’re clear about what we need to achieve: just read the guide of the specific service. This way of working gives us a lot of flexibility both at work and in our hobby projects.
Finally &lt;strong&gt;this flexibility makes us free to use a service based on the advantages it brings&lt;/strong&gt;: in this guide we used Travis CI precisely because it’s free for open source projects, but it’s certainly not the best on the market. This wouldn’t be possible if we used one and only one service.&lt;/p&gt;
&lt;h2&gt;Let’s read pipelines that are already made&lt;/h2&gt;
&lt;p&gt;We must remember that we’re not the only ones on the face of the earth thinking about creating a pipeline. &lt;strong&gt;So let’s not underestimate the possibility of looking at open source project pipelines!&lt;/strong&gt; There are numerous projects on GitHub that show practical examples of pipelines that very likely solve all or part of our problems. This way we can also see different ways of reasoning which is always useful for improving our cultural baggage. Finally I remind you that Travis CI is free for open source projects, which is the main reason I decided to write this guide. So GitHub is full of pipelines made with Travis CI!&lt;/p&gt;
&lt;h2&gt;Let’s not look for perfection&lt;/h2&gt;
&lt;p&gt;Let’s remember that our job isn’t to spend days making pipelines. &lt;strong&gt;It’s always possible to optimize it to speed it up, but like all optimizations they take time&lt;/strong&gt;. My advice is to reach the bare minimum to achieve the goal, even if maybe it’s not the most elegant solution possible. Then let’s remember that over time we learn new concepts, such as caching and the possibility of running multiple jobs in parallel, we know the system better and so it will be simpler for us to optimize it taking less time. So let’s always keep in mind that the pipeline is a tool that speeds up and automates our work… But whether it takes 5 minutes or 10 minutes doesn’t really change much on our side, so let’s not spend hours or days on these optimizations, especially in the early stages where the challenges are already many.&lt;/p&gt;
&lt;h1&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;I hope that with this guide you’ve experienced first-hand what it means to implement a Continuous Integration and Continuous Delivery pipeline on an already existing project. The difficulties, as we’ve seen, are greater if the project is already started. So, the next time you start building an idea of yours, remember to think about the CI/CD pipeline right away; you won’t regret it. This way you can delegate these tasks to a machine and you can focus exclusively on what really brings value to your project: code development.&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to program in Test-Driven Development (TDD) starting from scratch]]></title><description><![CDATA[TDD here, TDD there, everyone talks about it. Many praise its merits, others say it’s a waste of time… But in the end, how do you actually…]]></description><link>https://www.mattianatali.it/en/how-to-develop-in-test-driven-development-tdd-from-scratch/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-develop-in-test-driven-development-tdd-from-scratch/</guid><pubDate>Fri, 28 Dec 2018 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;TDD here, TDD there, everyone talks about it. Many praise its merits, others say it’s a waste of time… But in the end, how do you actually develop in TDD?&lt;/p&gt;
&lt;p&gt;In this guide you’ll see a real example developed in &lt;a href=&quot;https://en.wikipedia.org/wiki/Test-driven_development&quot;&gt;Test-Driven Development&lt;/a&gt;. I’ve been adopting this programming technique for over a year for the backends I develop in Java, Python and TypeScript. The benefits in the code I’ve written are visible and many. I hope I can convince you that this technique:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improves code quality.&lt;/li&gt;
&lt;li&gt;Decreases the time spent debugging and searching for possible software regressions.&lt;/li&gt;
&lt;li&gt;Decreases the number of bugs that manage to reach production.&lt;/li&gt;
&lt;li&gt;Simplifies the development of complex applications.&lt;/li&gt;
&lt;li&gt;Is simpler than it seems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How can I convince you of all these things? I hope to succeed through a &lt;strong&gt;practical example starting completely from scratch&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Goal&lt;/h2&gt;
&lt;p&gt;In this guide we’ll develop a class that takes as input a URL and a word to search for in the page we’ve entered.
This search will answer us by telling us how many times it found the word.&lt;/p&gt;
&lt;p&gt;We’ll build this simple application in &lt;a href=&quot;https://nodejs.org/en/&quot;&gt;Node.Js&lt;/a&gt; + &lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;, entirely in TDD.
During this development I’ll explain all the steps and make explicit all the advantages that TDD is introducing.&lt;/p&gt;
&lt;h2&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;To follow the guide you should have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js installed.&lt;/li&gt;
&lt;li&gt;A minimum of experience with Node.js. TypeScript, if you’ve never used it, is JavaScript with types; for now that’s all you need to know.&lt;/li&gt;
&lt;li&gt;For the second part you need to know the concept of asynchronous programming in JavaScript: we’ll use &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promises&lt;/a&gt; and the &lt;a href=&quot;https://javascript.info/async-await&quot;&gt;async and await&lt;/a&gt; keywords.&lt;/li&gt;
&lt;li&gt;A UNIX system (Linux or Mac). Or having enabled &lt;a href=&quot;http://wsl-guide.org/en/latest/&quot;&gt;WSL on Windows&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you happen to get lost, &lt;a href=&quot;https://github.com/matitalatina/word-counter&quot;&gt;in this GitHub repo&lt;/a&gt; you can find the finished product. But I advise you not to “peek” at the solution because we’ll introduce many concepts throughout the article. Seeing the finished project without knowing &lt;em&gt;how&lt;/em&gt; we got there brings no benefit to learning.&lt;/p&gt;
&lt;h2&gt;Creating the project&lt;/h2&gt;
&lt;p&gt;The first step is obviously to create the project. To do this we open the &lt;em&gt;terminal&lt;/em&gt; in a folder we’ll work in. My folder will be called &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;Let’s create the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file where we’ll insert the various Node.js dependencies and 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;Let’s enter the various data it asks for. For now we can just press &lt;code class=&quot;language-text&quot;&gt;Enter&lt;/code&gt; and keep the default values.&lt;/p&gt;
&lt;h2&gt;Adding dependencies&lt;/h2&gt;
&lt;p&gt;Now we can insert the bare minimum needed to start developing in TDD. The dependencies we need are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/&quot;&gt;TypeScript&lt;/a&gt;: to develop with this language.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://palantir.github.io/tslint/&quot;&gt;TSLint&lt;/a&gt;: the TypeScript &lt;a href=&quot;https://en.wikipedia.org/wiki/Lint_(software)&quot;&gt;linter&lt;/a&gt; that will help us during development to write clean code. This is optional, but I usually always add it to have great help during development. It’s also integrated very well with &lt;a href=&quot;https://code.visualstudio.com/&quot;&gt;Visual Studio Code&lt;/a&gt;, which is my favorite text editor for the Node.js world.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt;: our testing platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To install all this we write&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;We can verify that these five dependencies have been added in &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; under &lt;code class=&quot;language-text&quot;&gt;devDependencies&lt;/code&gt;, that is, they’re dependencies needed for development and not for the program itself. We can also notice that these dependencies have been downloaded into the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;The command should be clear; the only part that maybe needs explanation is the Jest libraries. In fact we installed three dependencies to make it all work.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;jest&lt;/code&gt; is our testing platform.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ts-jest&lt;/code&gt; is the transpiler that transforms TypeScript into JavaScript before running the tests. Without it we’d have to &lt;a href=&quot;https://en.wikipedia.org/wiki/Source-to-source_compiler&quot;&gt;transpile&lt;/a&gt; the code manually every time, something we absolutely want to avoid so as not to waste time.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;@types/jest&lt;/code&gt; is needed by TypeScript to know the types inside the Jest library. Imagine that many times libraries are written in JavaScript, so TypeScript would have no idea what the functions accept as input or return as output. Fortunately there are developers who create libraries that map JavaScript functions to TypeScript. Usually to install these mappings you install the &lt;code class=&quot;language-text&quot;&gt;@types/&amp;lt;LIBRARY_TO_MAP&gt;&lt;/code&gt; dependency. If you want to know more about these type declarations in TypeScript you can read directly from the &lt;a href=&quot;http://definitelytyped.org/&quot;&gt;DefinitelyTyped&lt;/a&gt; site, but for this guide there’s no need to go deeper.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Initialization&lt;/h3&gt;
&lt;p&gt;Now that we’ve downloaded the libraries, we need to configure them to make them work at their best.
Let’s start with &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;The command means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npx&lt;/code&gt;: starts a program that you can find in the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;typescript --init&lt;/code&gt;: the TypeScript initialization command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It should have created the &lt;code class=&quot;language-text&quot;&gt;tsconfig.json&lt;/code&gt; file with the various configuration parameters. Let’s open this file and we should see the &lt;code class=&quot;language-text&quot;&gt;// &quot;lib&quot;: [],&lt;/code&gt; part commented out; let’s uncomment it and write:&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;This way we can use &lt;a href=&quot;https://javascript.info/async-await&quot;&gt;the async and await keywords&lt;/a&gt; when we deal with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;Promises&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now let’s move on to &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;We can actually see that a file named &lt;code class=&quot;language-text&quot;&gt;tslint.json&lt;/code&gt; has been created in the root. For now it’s fine as it is, let’s not touch it.&lt;/p&gt;
&lt;p&gt;Now let’s initialize &lt;strong&gt;Jest&lt;/strong&gt;, our test platform, more or less as we did with 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;It should automatically recognize that TypeScript is present, create the &lt;code class=&quot;language-text&quot;&gt;jest.config.js&lt;/code&gt; file containing Jest’s default configuration, and finally it added the &lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt; script to &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt;. This way when we write &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; in the console, Jest starts and runs all the tests.&lt;/p&gt;
&lt;p&gt;Here we need to make a small change to the &lt;code class=&quot;language-text&quot;&gt;jest.config.js&lt;/code&gt; file: we need to rename the field from &lt;code class=&quot;language-text&quot;&gt;globals.ts-jest.tsConfigFile&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;globals.ts-jest.tsConfig&lt;/code&gt; to avoid a warning message during tests.
So we’ll need to rename that configuration part like this:&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;To be sure we’ve done everything, let’s finally try writing a test: we’ll insert it in the &lt;code class=&quot;language-text&quot;&gt;src/__tests__&lt;/code&gt; folder and call it &lt;code class=&quot;language-text&quot;&gt;hello-test.ts&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So let’s write in the &lt;code class=&quot;language-text&quot;&gt;src/__tests__/hello-test.ts&lt;/code&gt; file:&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;The test we just wrote does nothing but verify that &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt; is actually &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt;. What’s the point? In real life, none, but in our specific case it helps us understand that Jest is configured correctly.&lt;/p&gt;
&lt;p&gt;Let’s start the tests with &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; and you should get a result similar to mine.&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;Perfect! Our first test in TypeScript worked.&lt;/p&gt;
&lt;h2&gt;Project analysis&lt;/h2&gt;
&lt;p&gt;Now we get down to business: let’s go back to our goal and start thinking about how to create the architecture.&lt;/p&gt;
&lt;p&gt;To achieve the goal we need three parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Collecting the input values (URL and word to search for).&lt;/li&gt;
&lt;li&gt;Downloading the web page.&lt;/li&gt;
&lt;li&gt;Counting the word in the web page we just downloaded.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Test-Driven Development: here we go!&lt;/h2&gt;
&lt;p&gt;Where do we start? Obviously with a test! After all, that’s why we’re here, right? To learn Test-Driven Development.
How do you start with a test? &lt;strong&gt;You need to think about how to create an architecture that can be easily testable, where each test checks only a single aspect of the project&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;We’ll use a &lt;a href=&quot;https://en.wikipedia.org/wiki/Top-down_and_bottom-up_design&quot;&gt;bottom-up approach&lt;/a&gt; to create the project, that is, we’ll start from the simplest, self-contained part that doesn’t need any dependency to work. In this case it’s part 3.&lt;/p&gt;
&lt;h2&gt;WordCounter class&lt;/h2&gt;
&lt;p&gt;WordCounter is our class that handles “Counting the word in the web page we just downloaded”. We can also translate it this way: “Given an input string &lt;em&gt;text&lt;/em&gt; and a word to search for &lt;em&gt;wordToFind&lt;/em&gt;, it returns the number of times &lt;em&gt;wordToFind&lt;/em&gt; is contained in &lt;em&gt;text&lt;/em&gt;“.&lt;/p&gt;
&lt;p&gt;So let’s start from the test: without having this WordCounter class in hand, which doesn’t exist yet, I imagine using it like this:&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;downloaded text&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;text&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;Let’s try to translate this hypothetical usage into a test.
In the new file &lt;code class=&quot;language-text&quot;&gt;src/__tests__/word-counter.ts&lt;/code&gt; we write:&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;downloaded text&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;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 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;Here we need to know a minimum of how Jest works. In short, we’ll use the convention of grouping tests that refer to a class using the &lt;a href=&quot;https://jestjs.io/docs/en/api#describename-fn&quot;&gt;describe&lt;/a&gt; function, and then each test of the class will use the &lt;a href=&quot;https://jestjs.io/docs/en/api#testname-fn-timeout&quot;&gt;it&lt;/a&gt; function which is our actual test. The &lt;code class=&quot;language-text&quot;&gt;it&lt;/code&gt; function consists of a string that briefly explains what we’re testing and a function that contains the test logic. For more details I recommend their &lt;a href=&quot;https://jestjs.io/docs/en/getting-started&quot;&gt;official documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that we’ve written our first test, we can notice an advantage of writing in TDD: &lt;strong&gt;we only care about the interface and not the implementation&lt;/strong&gt;. In the end, the final user of our classes only cares about &lt;em&gt;how&lt;/em&gt; to invoke a certain function, and not &lt;em&gt;how it was made&lt;/em&gt;. It often happens in programming that you dive headfirst into the implementation only to end up with a convoluted, unclear interface, precisely because in traditional programming the cognitive effort all goes into the implementation and the interface is secondary. Here instead everything is flipped.&lt;/p&gt;
&lt;p&gt;A very important rule in TDD is to &lt;strong&gt;proceed in small steps&lt;/strong&gt;. We shouldn’t write a thousand tests and then move on to implementation. You write a single test, it fails, and then our goal is to make the test pass by implementing the necessary code. Why all this? Essentially for two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;We know perfectly well what our goal is: making the only failing test pass&lt;/strong&gt;. This way the project can be as complex as we like, but by setting only a small goal everything becomes simple; &lt;em&gt;divide et impera&lt;/em&gt; always works!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;We write the bare minimum to make the test pass&lt;/strong&gt;. How many of us have started writing mountains of code because “You never know”, or because our mind thought of a thousand cases that nobody ever asked for? In TDD this doesn’t happen; every single line of code was written to make a test pass. If we write anything else we’re doing it wrong.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now that we’ve told ourselves we must proceed in small steps, let’s actually write the code that will make our test green. First of all let’s verify that it fails.&lt;/p&gt;
&lt;p&gt;In the console we write &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As output we have something like this.&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;The TypeScript transpiler rightly complains that the word-counter class doesn’t exist.&lt;/p&gt;
&lt;p&gt;Now let’s write the bare minimum to make the test pass. Let’s create the class and the method 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;Let’s run the test with &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;. And this is the result:&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;We did it! But I imagine you noticed that I cheated. The method I wrote always returns 1, regardless of the text passed. But this isn’t wrong in TDD because &lt;strong&gt;our goal is to make the tests pass as soon as possible with the bare minimum&lt;/strong&gt;. If I managed to cheat, it means the test isn’t thorough enough to verify the correct functioning of the program.
Now let’s fix it by writing a test that forces us to consider the &lt;em&gt;text&lt;/em&gt; input. In the &lt;code class=&quot;language-text&quot;&gt;src/__tests__/word-counter.ts&lt;/code&gt; file let’s add&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;Running the tests, this test indeed fails&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;Now let’s change the implementation of &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; so as to make the test pass&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;Both tests are OK! …But there’s one thing we haven’t tested: what happens if the word to search for is all lowercase but the text is uppercase? &lt;strong&gt;We don’t know and we don’t even bother finding out, we just write a test to be sure&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Let’s add the 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;Running the tests it fails… So let’s fix it!&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;All good, again. But we haven’t considered text where the word ends with a comma or any punctuation mark. New 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;New implementation to handle this failing 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;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;All green! In short, now it’s quite clear how to create a class in TDD. We’ve seen that &lt;strong&gt;it’s a continuous ping pong of failing tests and implementation that fixes the failure&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But this ping pong, in addition to the benefits we wrote about earlier, also brings others:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It iterates the development of complex apps through simple steps, incrementally&lt;/strong&gt;: it’s obvious that we started with a very simple implementation, and then, through small steps, we arrived at having a method that handles numerous cases we might not even have thought of initially.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Previously written tests remain, the implementation changes continuously&lt;/strong&gt;: maybe through this example it’s not very noticeable, but every time we added a new test and changed the implementation, we were certain that &lt;strong&gt;even the previously written tests continue to work&lt;/strong&gt;. This certainty is fundamental when we have to do heavy refactors of methods; without TDD this certainty, most of the time, doesn’t exist. So people tend not to modify existing code; they add code “around” it to avoid touching something “that already works” and therefore avoid &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_regression&quot;&gt;software regressions&lt;/a&gt;. This behavior works but only for a short period; the code easily loses readability, becomes confusing and obscure, and here’s the famous &lt;a href=&quot;https://en.wikipedia.org/wiki/Technical_debt&quot;&gt;technical debt&lt;/a&gt;! I’m sure you’ve already had code like that in your hands and it’s not fun.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All the features we need are tested&lt;/strong&gt;: this is free with TDD. We write the test first and then the implementation, so by necessity it’s true.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By now we feel satisfied with our &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; class. Actually there would be another case to test. For example&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What happens if we pass &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; to the two parameters?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Should we add a test for this case too? The answer is &lt;em&gt;it depends&lt;/em&gt;. If we know that our code doesn’t need to handle &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt;, we can also skip it. Many might counter that this way the code isn’t robust, but actually our goal isn’t to handle every case in the world; we need to create a class that’s OK for our project. So &lt;strong&gt;we should try to stay focused on the initial goal&lt;/strong&gt;; this way we don’t complicate the code with cases that never happen and we don’t waste time writing useless code and tests.&lt;/p&gt;
&lt;p&gt;Now that we’re satisfied with our &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt;, let’s move on to the next class.&lt;/p&gt;
&lt;h2&gt;TextFetcher class&lt;/h2&gt;
&lt;p&gt;This class solves part 2 of our goal. That is, it downloads a web page and retrieves the text from it.
By now we know how it works and, loaded like a spring, we use the same procedure we used with &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Let’s think about the TextFetcher interface: I imagine using it like this &lt;code class=&quot;language-text&quot;&gt;new TextFetcher().getContent(url)&lt;/code&gt; and it returns a &lt;code class=&quot;language-text&quot;&gt;Promise&amp;lt;string&gt;&lt;/code&gt;, in short it returns a string asynchronously (we can’t have it synchronous because the HTTP call to retrieve the content from a URL is slow). Here a prerequisite I wrote earlier comes into play: asynchronous programming in JavaScript/TypeScript. If you want to fully understand the examples I’m going to write, I recommend the readings I included in the prerequisites section.&lt;/li&gt;
&lt;li&gt;Let’s write the test to test the future implementation.&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;If we open the URL I put in the test we can see it’s the &lt;code class=&quot;language-text&quot;&gt;README.md&lt;/code&gt; of the repository I’m using to create this app.&lt;/p&gt;
&lt;p&gt;Inside it there’s the word WordCounter. Our test verifies that the &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; instance actually downloads the README and returns its content. In the test I only look for the word &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; and not exactly the content because the README could change, but at least the project name I hope will always remain!&lt;/p&gt;
&lt;p&gt;Now let’s try to make the test pass (without cheating so as not to weigh down the discussion too much). To make the HTTP call that downloads the file, I use a very famous library in Node.js which is &lt;a href=&quot;https://github.com/axios/axios&quot;&gt;Axios&lt;/a&gt;. For this reason we install it among our dependencies&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;Let’s write a possible implementation 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;We’ve essentially created and exported the &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; class, created the asynchronous method &lt;code class=&quot;language-text&quot;&gt;async getContent&lt;/code&gt;, in the implementation we use &lt;code class=&quot;language-text&quot;&gt;axios&lt;/code&gt; to download the content of the &lt;code class=&quot;language-text&quot;&gt;url&lt;/code&gt;, we asynchronously wait for it to download the content using the &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; keyword, and finally we take the content of the response using the &lt;code class=&quot;language-text&quot;&gt;data&lt;/code&gt; property.&lt;/p&gt;
&lt;p&gt;Let’s run the tests with &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; and everything works!&lt;/p&gt;
&lt;p&gt;But I don’t know if you smell a little “burning” too… If you noticed, I put a URL in the test that fetches a resource external to our program, which could change, could be inaccessible because our PC is offline. All this would influence our test, making it fail even though the code is actually correct.&lt;/p&gt;
&lt;p&gt;Remember that &lt;strong&gt;unit tests must be fast and must not depend on external factors&lt;/strong&gt;. The HTTP call can be slow due to the connection or even fail due to possible changes or disconnections.&lt;/p&gt;
&lt;p&gt;How can we solve this problem? We’ll &lt;a href=&quot;https://en.wikipedia.org/wiki/Mock_object&quot;&gt;mock&lt;/a&gt; the HTTP call.&lt;/p&gt;
&lt;p&gt;To do this we need another external library: &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;Let’s modify the 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;This is the content of the web page&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;Through &lt;code class=&quot;language-text&quot;&gt;MockAdapter&lt;/code&gt; we hook into the &lt;code class=&quot;language-text&quot;&gt;axios&lt;/code&gt; library, so as to create fake HTTP calls. With &lt;code class=&quot;language-text&quot;&gt;mock.onGet(&quot;/fake-url&quot;).reply(200, content);&lt;/code&gt; we create a fake HTTP response through the &lt;code class=&quot;language-text&quot;&gt;/fake-url&lt;/code&gt; address with the value of the &lt;code class=&quot;language-text&quot;&gt;content&lt;/code&gt; variable as content. Finally we test that the response is actually &lt;code class=&quot;language-text&quot;&gt;content&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Running the tests everything works and this time we can test offline too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mocking HTTP calls external to the various URLs or to external microservices is fundamental to having a good unit test suite&lt;/strong&gt;. We can’t call real resources during unit tests, also because these resources probably only exist in the production environment and we don’t want to pollute the production content with tests.&lt;/p&gt;
&lt;h2&gt;CounterApp class&lt;/h2&gt;
&lt;p&gt;This is the last class we’re going to build. Its goal is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Invoke &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; to retrieve the text from the URL.&lt;/li&gt;
&lt;li&gt;Invoke &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; to count how many times the word to search for is contained in the downloaded text.&lt;/li&gt;
&lt;li&gt;Return the number returned by &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;In the unit tests of a class we don’t want to test the implementation of its dependencies too&lt;/strong&gt;. In our case we don’t want to test &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; again. We’ve already tested these classes well. For this reason we’ll mock these dependencies a bit like we did for HTTP calls.&lt;/p&gt;
&lt;p&gt;Mocking the external dependencies of a class brings the following advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;We avoid a failure in the dependency also failing the tests of the class we’re testing&lt;/strong&gt;. Ideally an error in the code should make only one test fail, and not all the parts that depend on it too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We therefore need a library called &lt;a href=&quot;https://github.com/NagRock/ts-mockito&quot;&gt;ts-mockito&lt;/a&gt; which is inspired by the famous Mock library for Java called &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;It makes it easy to create special cases&lt;/strong&gt;: imagine we need to correctly test the handling of an exception, and generating this exception requires a very particular situation. If we mock, we can inject a mock that generates this exception without having to recreate this special situation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s put what we’ve said into practice. The first step is to install &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;Let’s write the test in the new 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;Retrieved text&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;In the initialization we create the mocks of our two classes &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt;; with the line &lt;code class=&quot;language-text&quot;&gt;new CounterApp(instance(mockTextFetcher), instance(mockWordCounter))&lt;/code&gt; we insert the instances of our mocks into the constructor of the &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt; class. This technique of “injecting” the dependencies used directly into its constructor pairs well with frameworks that use &lt;a href=&quot;https://en.wikipedia.org/wiki/Dependency_injection&quot;&gt;dependency injection&lt;/a&gt;. If this last sentence I wrote is pure gibberish, don’t worry. The message that must get across is this: &lt;strong&gt;it’s good practice to require in the &lt;a href=&quot;https://en.wikipedia.org/wiki/Constructor_(object-oriented_programming)&quot;&gt;constructor&lt;/a&gt; the external dependencies the class needs to work correctly&lt;/strong&gt;. This is true for two reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It clearly indicates to the programmer using your class which dependencies it needs to perform its function.&lt;/li&gt;
&lt;li&gt;It makes testing the class in question easy, because in the constructor we can inject mocked instances, as in our case.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The part inside the test &lt;code class=&quot;language-text&quot;&gt;it(&quot;should get parameters and return the count&quot;, ...)&lt;/code&gt; should be fairly self-explanatory: I create the variables I expect to use and then I use &lt;a href=&quot;https://github.com/NagRock/ts-mockito&quot;&gt;ts-mockito&lt;/a&gt; to make the appropriate assertions. For example with &lt;code class=&quot;language-text&quot;&gt;when(mockTextFetcher.getContent(providedUrl)).thenReturn(Promise.resolve(fakeContent));&lt;/code&gt; it means: “when the class calls &lt;code class=&quot;language-text&quot;&gt;textFetcher&lt;/code&gt; using the &lt;code class=&quot;language-text&quot;&gt;getContent&lt;/code&gt; method with the &lt;code class=&quot;language-text&quot;&gt;providedUrl&lt;/code&gt; parameter, return a &lt;code class=&quot;language-text&quot;&gt;Promise&lt;/code&gt; resolved with the value &lt;code class=&quot;language-text&quot;&gt;fakeContent&lt;/code&gt;”. The &lt;code class=&quot;language-text&quot;&gt;when(...).thenReturn(...)&lt;/code&gt; functionality helps us bypass the real implementation of the mocked classes and return a value we decide.&lt;/p&gt;
&lt;p&gt;This way we’re testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;That the &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt; class calls the methods of the &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; classes with the correct parameters, through the various &lt;code class=&quot;language-text&quot;&gt;when(...).thenReturn(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;That the &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt; class returns the correct number through &lt;code class=&quot;language-text&quot;&gt;expect(...).toBe(...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s run the tests with &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt;. Of course it fails; now let’s implement the class in the new 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;We’ve created a constructor that inserts the instances of &lt;code class=&quot;language-text&quot;&gt;TextFetcher&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; into the private variables &lt;code class=&quot;language-text&quot;&gt;textFetcher&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;wordCounter&lt;/code&gt; (the constructor is empty; it seems to do nothing, but the dirty work is being done by the &lt;a href=&quot;https://www.stevefenton.co.uk/2013/04/stop-manually-assigning-typescript-constructor-parameters/&quot;&gt;private keyword&lt;/a&gt;). Then we implemented the asynchronous method &lt;code class=&quot;language-text&quot;&gt;countWordFromUrl&lt;/code&gt; which does nothing but download the content from the URL and then count the number of times the word we’re looking for appears and return it.&lt;/p&gt;
&lt;p&gt;Let’s try with &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; and everything is indeed OK!&lt;/p&gt;
&lt;h2&gt;Real test&lt;/h2&gt;
&lt;p&gt;Now that we’ve finally reached our goal, programming entirely in TDD, let’s try a real test.&lt;/p&gt;
&lt;p&gt;Let’s create the &lt;code class=&quot;language-text&quot;&gt;src/index.ts&lt;/code&gt; file where I’ll insert a small script to try it all out.&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;I created a small &lt;code class=&quot;language-text&quot;&gt;testApp&lt;/code&gt; function that creates my &lt;code class=&quot;language-text&quot;&gt;CounterApp&lt;/code&gt; class with the necessary dependencies, and I try to count how many times the word &lt;code class=&quot;language-text&quot;&gt;WordCounter&lt;/code&gt; appears in the &lt;a href=&quot;https://raw.githubusercontent.com/matitalatina/word-counter/master/README.md&quot;&gt;README.md&lt;/a&gt; page of my repository for this project.
To start the program I need to transpile TypeScript into JavaScript, because as we know Node.js can’t read TypeScript directly. To solve this I’ll use the &lt;a href=&quot;https://github.com/TypeStrong/ts-node&quot;&gt;ts-node&lt;/a&gt; library.&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;Now that it’s installed, let’s start our script like this&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;The result is this:&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;It works!!!&lt;/p&gt;
&lt;h2&gt;Project maintenance&lt;/h2&gt;
&lt;p&gt;We’ve finished our small TDD project. But a real project worth its salt is never “finished”; it must be maintained and improved every day. Another advantage I appreciated after a few months of TDD development is the drastically reduced time in terms of debugging or production bugs. So &lt;strong&gt;the time spent writing tests is far outweighed by the time saved from debugging the product&lt;/strong&gt;. Try it to believe it!
But don’t think that bugs no longer exist using TDD. There are far fewer of them but they do happen from time to time. When they happen we must always remember to &lt;strong&gt;write the test that manifests the bug before fixing the bug&lt;/strong&gt;. This way we keep using TDD, but above all we have the guarantee that the bug won’t manifest again even if we heavily modify the code in the future.&lt;/p&gt;
&lt;h2&gt;When to use TDD&lt;/h2&gt;
&lt;p&gt;Now that we’ve seen what TDD is, a question may naturally arise: &lt;strong&gt;when should you use TDD?&lt;/strong&gt; Here it’s better to make a distinction: &lt;strong&gt;if I have to choose between TDD and classic unit tests, from personal experience I’d always choose TDD&lt;/strong&gt;. The classic approach has never brought me any benefit over TDD. The only “advantage” I’ve seen is that the classic approach lets you not test everything, but honestly I don’t consider that an advantage precisely because it creates dangerous holes that nullify much of the benefits we found in this guide.&lt;/p&gt;
&lt;p&gt;If instead the choice is between TDD and only the implementation without unit tests, the discussion changes.
These are certainly the cases where TDD (or at least unit tests) should be used.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Backend systems: when you have clients (mobile apps, microservices etc.) that rely on our system, it’s fundamental that the backend works perfectly.&lt;/li&gt;
&lt;li&gt;“Mission critical” parts: if we have components that must work and are crucial to delivering our service, we can’t afford to have bugs or go on trust.&lt;/li&gt;
&lt;li&gt;Components that are difficult to test “live”: if it takes me 5 minutes just to test a special case once, better to spend them creating a test that at least I’ll always have and a &lt;code class=&quot;language-text&quot;&gt;npm test&lt;/code&gt; is enough to recheck.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;When instead is TDD not needed and you can go with implementation only?&lt;/strong&gt; It sounds like heresy but I’ve found some cases where implementation alone is enough and more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When our implementation is easily testable “live”: ever heard of live-reloading? With web apps or even in hybrid app development with &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; or &lt;a href=&quot;https://facebook.github.io/react-native/&quot;&gt;React Native&lt;/a&gt;, you can implement and immediately view the output. This is a very powerful tool that enormously speeds up development, but above all the time between implementation and the final result is zero. What’s the point of writing tests if I just save the code and immediately see the final result and can try it?&lt;/li&gt;
&lt;li&gt;When we can afford some freedom, the specifications are still fuzzy and our client is in close contact with development: it has happened to me to develop literally with the client who could give me feedback almost in real time. If the environment is very informal/conversational, it’s possible to create an entire project without writing a single line of test and the client is happy anyway, even if maybe from time to time they call you to report a bug. The important thing is that you can fix it quickly so that the client can appreciate your speed in fixing it.&lt;/li&gt;
&lt;li&gt;When the project is an experiment: sometimes it happens to create a project just to understand whether a certain thing can work. Or you implement a small variation for A/B testing, or you develop something temporary to work around an equally temporary problem. In these cases we’ll never appreciate the benefits of TDD, because the time spent on tests won’t be compensated by the time saved from debugging or fixing bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The message that must get across is this: evaluate your case and act accordingly. &lt;strong&gt;TDD is the solution to many problems, but not to all of them&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;First of all I apologize if while reading this guide maybe the concept of “it’s simpler than you’d think” didn’t come across much.
But don’t forget that here you’ve seen numerous concepts which, if it’s the first time you’ve seen them, take a little time to digest. If maybe you missed the concepts you learned in this article, here’s a small summary for you:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Initialization of a project in Node.js, use of the &lt;code class=&quot;language-text&quot;&gt;npm&lt;/code&gt; package manager.&lt;/li&gt;
&lt;li&gt;Adding TypeScript with an integrated linter.&lt;/li&gt;
&lt;li&gt;Using Jest for testing.&lt;/li&gt;
&lt;li&gt;Asynchronous programming with the &lt;code class=&quot;language-text&quot;&gt;async&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;await&lt;/code&gt; keywords introduced in ECMAScript 2017.&lt;/li&gt;
&lt;li&gt;Using mocking libraries, when and why to use them.&lt;/li&gt;
&lt;li&gt;Test Driven Development.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At first TDD seems like a brake, like all new things, but once you get comfortable, everything becomes faster and even more fun! It’s always nice to reach the end of the day and see your project growing together with the tests that increase and are all green… &lt;em&gt;except one&lt;/em&gt;! Yes indeed: &lt;strong&gt;at the end of the day, if the project isn’t finished, we write a failing test before leaving&lt;/strong&gt;. This is a piece of advice that’s very effective for resuming work. This way we perfectly remember what we were doing when we return to work. The failed test will tell us exactly what we left behind.&lt;/p&gt;
&lt;p&gt;I hope this article has made you want to try this fascinating technique which, at first glance, may seem almost absurd, but once adopted, enormously increases the quality of the code and consequently also the quality of the final product.&lt;/p&gt;
&lt;p&gt;If you want to see TDD in action with Spring Boot you can read my article that talks about &lt;a href=&quot;/en/how-to-develop-rest-apis-in-tdd-with-spring-boot&quot;&gt;how to develop RESTful APIs in TDD with Spring Boot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[11 lessons I learned working in startups]]></title><description><![CDATA[I’ve been working in startups for almost 4 years now. I’m convinced that a startup is a great choice for a student fresh out of university…]]></description><link>https://www.mattianatali.it/en/11-lessons-i-learned-working-in-startups/</link><guid isPermaLink="false">https://www.mattianatali.it/en/11-lessons-i-learned-working-in-startups/</guid><pubDate>Sat, 21 Apr 2018 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;I’ve been working in startups for almost 4 years now. I’m convinced that a startup is a great choice for a student fresh out of university, because they are very dynamic environments: given their unstable nature you are “forced” to adapt, you learn something new every day and so it’s a great opportunity to grow personally together with the company.&lt;/p&gt;
&lt;p&gt;Since I’m now changing work environment, it’s time to sum up. In this post I’ll tell you what I learned working in startups, in my case &lt;a href=&quot;http://wavein.ch/&quot;&gt;wavein.ch&lt;/a&gt; and &lt;a href=&quot;https://cloudacademy.com&quot;&gt;Cloud Academy&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Your boss wants solutions, not problems&lt;/h2&gt;
&lt;p&gt;In startups, your superiors are often the same people who wrote the code before you, so the temptation to ask them for help is very high. But remember that their role has changed now, so they have a thousand other things on their minds. In fact they rely on you to complete the task you’ve been assigned. &lt;strong&gt;Instead of asking for help, you need to ask them what decision to make&lt;/strong&gt;. The correct flow is that they ask you to do X, you analyze the problem and bring solutions with the pros and cons of each one, and finally the superior decides which solution to pursue and takes responsibility for it. This way everyone is happy: you know exactly what to do, the superior has spent little time and received only the information they cared about.&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;The wavein.ch office&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;Keep track of what you’re doing&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Transparency in startups is essential&lt;/strong&gt;: you obviously know very well what you’re working on, which bug is driving you crazy… But all this isn’t so obvious to the rest of the world. I used &lt;a href=&quot;https://www.jetbrains.com/youtrack/&quot;&gt;YouTrack&lt;/a&gt; and &lt;a href=&quot;https://www.atlassian.com/software/jira&quot;&gt;Jira&lt;/a&gt; as &lt;a href=&quot;https://en.wikipedia.org/wiki/Issue_tracking_system&quot;&gt;issue tracking systems&lt;/a&gt;; there’s nothing worse than having fiery days at work and an empty board. This can be a problem for you because you’re unable to show others what you’re working on, but above all it’s a problem for the Product Manager who will never be able to schedule work correctly, won’t have any visibility on possible delays and finally can’t prioritize work correctly. The same goes for blocked tasks: &lt;strong&gt;always put in writing what you’re working on&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;Workstation&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;Each of us is different&lt;/h2&gt;
&lt;p&gt;We have a character, our own personality: for this reason we often behave the same way with everyone. But we forget that others are all different too: there are those who are more outgoing, those who get offended easily, those who are shy, those who get angry over nothing, etc. &lt;strong&gt;We can’t behave the same way with everyone indiscriminately&lt;/strong&gt;. And worse still &lt;strong&gt;we can’t expect others to adapt to our character&lt;/strong&gt;, it will never work!&lt;/p&gt;
&lt;p&gt;In my opinion it’s our job to bring out the best in everyone by leveraging each person’s qualities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The person loves helping others&lt;/em&gt;: let them help you! They can surely always teach you something.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;They get offended easily&lt;/em&gt;: try not to make useless jokes, keep a more professional / detached profile.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The person gets fired up easily and hates “being wrong”&lt;/em&gt;: if you already have the solution to a problem in mind and just want confirmation, don’t explain the macro problem to them right away. Otherwise they’ll give you their solution and won’t want to discuss it anymore. Instead try to break it down into small problems where the solutions are obvious and are the ones you adopted. Finally all these solutions will lead to your definitive solution by logical consequence.&lt;/p&gt;
&lt;p&gt;If this person starts to heat up, don’t start mimicking their tone… Otherwise it’s just an escalation of tones that will only end badly. Don’t be afraid to interrupt the discussion without a solution if you see it’s going nowhere.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;They love making dirty jokes and like to “friendly insult” others&lt;/em&gt;: play along! Don’t take yourself too seriously. Very often if they openly make fun of you it’s just because they want to have a laugh with you. If you’re not used to it, it’s really hard to digest at first, but then you stop noticing and actually enjoy it. In the end you understand when someone does it just for fun or because they hold a grudge against you.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;You don’t particularly like a person&lt;/em&gt;: the worst thing you can do is burn all bridges around them. You have to spend your daily life with them and so it doesn’t help anyone. Instead try to avoid the behavior that bothers them if someone tells you about it. Otherwise try to always behave well with them: help them and don’t stick too close, so that slowly they’ll understand they shouldn’t have anything against you. If it doesn’t work… Well, so be it; always try not to give them good reasons to hate you, it’s the only thing you can do in these cases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;They’re shy&lt;/em&gt;: they’ll never come to ask you for help or advice. Every now and then reach out, so that they open up too. This way you can both work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;They’re a buck-passer&lt;/em&gt;: “Sorry, could you do this for me? I know you worked on it recently.”, “I know nothing about this stuff, can you do it since I know you know about it?“. Helping is one thing, doing other people’s work for them is another. You have your own goals too, try to stay focused on yours.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, these are just small examples and behaving differently with different people doesn’t mean being fake. In my opinion it’s the only way to live peacefully with many people in your working daily life.&lt;/p&gt;
&lt;h2&gt;It’s okay to say No&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Work is like water: it flows where it’s done&lt;/em&gt;. So you have to be careful about saying too many yeses, otherwise all the work ends up on you and then you have two very serious problems: you risk burnout because you don’t have a moment to breathe, and on top of that they accuse you of being the bottleneck! It’s important to help others, to do extra work, but it’s more important to finish your assigned tasks. For the company it’s important to respect its plan; if you fail to meet the original timelines, all this will have repercussions on the planning and this will have a negative repercussion on the whole company. The fewer people there are, the more visible the consequences. So &lt;strong&gt;you shouldn’t be afraid to say ‘No’&lt;/strong&gt; to those who ask you to do more extra work. First do your own, then, if there’s time left, accept extra work.
Other important ‘No’s are the technical ones. It’s not rare for tasks to come down from above that, from a technical or usability point of view, make no sense at all. In these cases &lt;strong&gt;it’s our duty to say ‘No’ and give our reasons&lt;/strong&gt;: it’s the developer who can understand the consequences of exotic requirements (technical debt, murky logic from the start, excessive UX complexity, etc.).&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;Me and the CloudAcademy team working seriously&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;A failure is truly a failure only if you learn nothing from it&lt;/h2&gt;
&lt;p&gt;Now I’ll say something nobody likes to hear. Everyone fails at something: I’ve made mistakes and I’ll make more, it’s impossible to do everything perfectly in your career. Be wary of those who tell you “I’ve never made mistakes / I’ve never failed / Honestly I don’t remember any mistakes I made in the past”. They’re just making fun of you or lying to themselves, because we, especially Italians, hate failing and above all hate admitting it.&lt;/p&gt;
&lt;p&gt;But &lt;strong&gt;making mistakes is an integral part of learning&lt;/strong&gt;. Experience is nothing more than a collection of mistakes you’ve taken home and are ready not to repeat. That’s why those who say they’ve never made mistakes are lying; it means they’ve either never done anything or never had a truly challenging task.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The sooner you recognize a mistake, the sooner you can fix it&lt;/strong&gt;. The sooner you fix it, the less damage you do. If a path is leading nowhere, or is becoming harder than expected, stop… Take a deep breath, analyze the situation and see if it’s worth continuing. Otherwise it’s time to ask a colleague for an opinion and then announce the problem to your superior (possibly with some solutions in hand). Then you make the necessary corrections.&lt;/p&gt;
&lt;p&gt;You’ll see that by doing so nobody can tell you anything, they’ll appreciate your ability to foresee even greater damage, you take note of what went wrong so as not to repeat the same mistake in the future and you carry on happy to have avoided a possible disaster.&lt;/p&gt;
&lt;p&gt;The alternative to all this? Tell everyone everything is fine, keep going your own way, try to make the best of a bad situation, buy time to try to keep something that’s dead alive, buy more time, despair, throw in the towel and say you’re working on something stupid that can’t work, blaming the cleaning lady just to avoid taking responsibility… Nobody will appreciate it; on the contrary they’ll understand they can’t rely on you, so avoid it.&lt;/p&gt;
&lt;p&gt;Failing isn’t nice, but it happens. So if it has to happen, let it happen as soon as possible.&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;Classic photo with the Golden Gate Bridge in 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;Asking for help is a weapon, not a weakness&lt;/h2&gt;
&lt;p&gt;Unfortunately for many, asking for help is almost a personal defeat, while others don’t do it to avoid taking up too much time of the person who makes themselves available to help. But &lt;strong&gt;asking for a hand&lt;/strong&gt; from those who know more about a certain product, piece of code or technology is essential:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;You reach the goal sooner&lt;/strong&gt;. Asking a question and getting an answer takes a few minutes. Trying to understand a piece of code written by others, looking for an answer online for a very specific case takes hours.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You really understand how the platform works&lt;/strong&gt;. Unfortunately in startups documentation leaves something to be desired, so very often you end up reading the code directly. Some parts can be obscure to understand simply because the real reason isn’t made explicit. It’s not rare to find horrible hacks in the middle of the code to solve specific cases that only one person knows about… And that person may no longer be at the company! If they’re there, I recommend one thing: go ask.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You avoid writing blunders&lt;/strong&gt;: I’ve seen people who, just to avoid asking or understanding how a part of the product works, completely “bypassed” that part by writing a very similar one. This is evil, because you create two pieces of code that coexist, it’s not clear why, and of course it makes the code unmaintainable. Or others who solved a problem only on the surface because “hey, I don’t touch code written by others!“… This too is absolute evil: this way you can destroy the architecture in a few weeks. Rather, ask whoever wrote the code and then solve it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You learn faster!&lt;/strong&gt; Even from a personal point of view it’s much better to ask for help: you learn much faster and hearing how other developers reason is the best way to improve yourself…&lt;/li&gt;
&lt;li&gt;You need help too… What? You’re thinking you’re the best and you have nothing to learn, especially from your colleagues? Well, everyone who thinks that way is the one who grows the least and falls behind, because they think they have nothing left to learn and stay stuck with their knowledge. Literally anyone can teach us something, even the most junior person in the company, because simply every person has their own, unique, personal background.&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;Me and Zacco working happily&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;Nobody cares about perfect code&lt;/h2&gt;
&lt;p&gt;Here’s a lesson that can hurt those who come fresh out of university. In the academic world the most important thing is writing perfect code, having the most abstract code possible so that it easily adapts to any use case. Nobody looks at your code until the final exam and so you can work in complete tranquility. There’s just one small detail… In the university world you have a lot of time available, in startups you don’t. The feature you’ve been asked for is blocking other developers, stakeholders want your part ready and deployed yesterday. So &lt;strong&gt;it’s not the goodness of your code that’s evaluated, but your execution&lt;/strong&gt;. The speed with which you complete your task.&lt;/p&gt;
&lt;p&gt;So how do you make good code coexist with execution speed? Through &lt;strong&gt;iterations&lt;/strong&gt;: write the bare minimum to reach the goal, don’t complicate things with strange constructs. Writing the bare minimum is very different from writing bad code: keep following best practices, keep the code as clean as possible, keep evaluating that the more shortcuts you take the more maintainability you have to sacrifice. But don’t worry about the problem before it happens, because maybe that problem will never come… And if it ever does, you iterate, but at least your original feature is already on the market and can be validated by the customer.&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;Reach your goals, period&lt;/h2&gt;
&lt;p&gt;Another lesson I learned the hard way, and that I received like a spinning kick to the gums. As soon as I joined Cloud Academy everything was a new world, I was eager to do things and I was really fired up. One of the first tasks assigned to me was automating the generation of static files on the frontend. While doing it I had the brilliant idea of also making an extra improvement that unfortunately I don’t remember now. I went to my superior to show him my progress: after telling him where I had got to, I also explained my improvement and what we could do more thanks to it. While I was explaining he abruptly interrupted me with a “Why the hell should I care?“… Total embarrassment, 5 seconds of silence… All I managed to say was an “Ah…“.&lt;/p&gt;
&lt;p&gt;I was used to &lt;a href=&quot;http://wavein.ch/&quot;&gt;wavein.ch&lt;/a&gt; having much more room to maneuver, but simply because we were smaller and I was almost my own boss. So everything I did, good or bad, went in the direction I deemed right. But in a startup you have “well-defined” tasks. If you have assigned tasks you have to do those and do the minimum to reach that goal. Everything else isn’t looked upon favorably, it’s seen as wasted time. Remember that &lt;strong&gt;time is the scarcest resource in a startup&lt;/strong&gt;. So be careful with unrequested features; even if they may be a great improvement for you, others might not care “one damn bit”.&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;A startup is not a family&lt;/h2&gt;
&lt;p&gt;A startup is not a family. You need to keep that well in mind. We like &lt;strong&gt;meritocracy&lt;/strong&gt;, we want it everywhere, but we must also be able to accept the flip side of the coin.&lt;/p&gt;
&lt;p&gt;Now I’ll explain what a working relationship is for me, in the most meritocratic and cynical version possible: I get paid to offer a certain service to the company. Through my service, the company acquires value. If the value generated by my service is higher than my salary, the company has every interest in keeping me. The higher this delta is, the more the company “loves me”; if this delta is too marked I can ask for a raise and the company should recognize it. If it doesn’t give it to me, I have every right to look around to see if someone else recognizes my value.
If instead the delta is negative it means the company no longer benefits from paying me and so it has every right to let me go. Finally there’s one last option: the company no longer has funds, so it starts laying off the people with a less marked delta, that is, those who generate less value for the company.&lt;/p&gt;
&lt;p&gt;Using this clean, meritocratic, cynical-as-you-want version, you can’t remain “burned” by a possible layoff. These are purely logical and rational things.&lt;/p&gt;
&lt;p&gt;But we’re not machines and so there are a lot of other variables at play that can deeply affect people’s sensitivity: the whole delta story is fine, but is it better to lay off a young person with no dependent children or lay off a person with a family and 3 children even if they generate less value for the company? Is it better to keep working for the company I work for even if they pay me little, where I’ve made a lot of friends and I feel good, or change jobs and go where they pay me more?&lt;/p&gt;
&lt;p&gt;I’ve met people who experienced a layoff very badly because they felt “betrayed” by the company. But in my opinion there’s little to get angry about: nobody likes laying people off, and the choice of who to lay off is something I think would distress anyone.&lt;/p&gt;
&lt;p&gt;I experienced first-hand what it means to be laid off from one day to the next. Nevertheless I remained on excellent terms with those who laid me off because, being in a startup, I knew very well that money doesn’t grow on trees: I understood the real reasons and so I was able to effectively separate the &lt;strong&gt;working relationship from friendship&lt;/strong&gt;. &lt;strong&gt;They are two things that coexist together, but they certainly aren’t the same thing&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With this I’m not saying you can’t make friends at work. On the contrary, at work you meet wonderful people and friendships are born that last for years even outside work. I’m just saying that &lt;strong&gt;I don’t have a job because I’m friends with someone, but because I’m generating value for the company&lt;/strong&gt; and it is able to recognize this generated value. If you keep this aspect in mind, in my opinion it’s easier to accept a layoff.&lt;/p&gt;
&lt;h2&gt;Don’t exasperate the work environment&lt;/h2&gt;
&lt;p&gt;“Is it possible, Natali, that you never get angry?“. Actually I get angry too, but I simply try not to show it. We spend a good part of the day at work and so it’s important that we keep the environment as calm as possible, even if anger is always around the corner. Over these years I’ve fundamentally learned these two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Getting angry is useless&lt;/strong&gt;. Unfortunately it happens to see people who claim to be right simply by shouting or visibly showing irritation. The important thing is to stay calm anyway, wait a few seconds before answering and, if the situation really doesn’t calm down, it’s better to end the conversation and postpone it when the tones are calmer… Also because the problem isn’t solved in these situations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You get nothing with force&lt;/strong&gt;: nobody will do you a favor/task under duress, you have to motivate people, not force them. I’ve been lucky enough to see three types of leadership: those who force you, those who “threaten” you and those who instead motivate you to do things. The best results of course are obtained with the last one. Exasperating the work environment to get something is never a solution; maybe it can work in the short term, but in the long term it can only give rise to a much more serious problem: sending &lt;a href=&quot;https://en.wikipedia.org/wiki/Turnover_(employment)&quot;&gt;turnover&lt;/a&gt; through the roof. The problem is that forcing or threatening a person is simple, motivating is not at all. And that’s why it’s important to choose the various leaders in the company well… Not everyone is able to do it.&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;Personal training is essential&lt;/h2&gt;
&lt;p&gt;Did you think that once you finished your studies you could say goodbye to studying? Well, in IT it’s only the beginning! &lt;strong&gt;IT is a continuous evolution; if you stand still even for just two years you’re automatically cut out&lt;/strong&gt;. For many this is a condemnation, but for me it’s the most interesting part of the job. You never stop learning and you can tangibly see a continuous evolution in your work and in yourself… Repetitive work ends up being boring!
To train yourself there’s only the embarrassment of choice: from e-learning platforms, small projects, to meetups organized by passionate people who really put their soul into what they do.&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I hope this post can be helpful to those who are afraid to start a working career, especially in a startup. It’s certainly a good gym to learn quickly, but I’m sure it can be a bit scary for those who have never worked in one.&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;Farewell aperitif at 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;If you’re young I can’t recommend anything other than working in these environments: you have fun, you meet truly wonderful people who share your same passion and you’re never bored!&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to fix software regressions using git bisect]]></title><description><![CDATA[You added a feature to the software and it went to production. After a few weeks the Product Owner tells you it no longer works. Don’t panic…]]></description><link>https://www.mattianatali.it/en/how-to-fix-software-regressions-using-git-bisect/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-fix-software-regressions-using-git-bisect/</guid><pubDate>Mon, 15 Jan 2018 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;You added a feature to the software and it went to production. After a few weeks the Product Owner tells you it no longer works. Don’t panic. Using only &lt;a href=&quot;https://en.wikipedia.org/wiki/Git_(software)&quot;&gt;Git&lt;/a&gt; you can fix everything in a few minutes!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Anyone can run into a &lt;a href=&quot;https://en.wikipedia.org/wiki/Software_regression&quot;&gt;software regression&lt;/a&gt;&lt;/strong&gt; and it’s never pleasant. I’ve seen many developers who, in a case like this, start trying to reproduce the bug locally and furiously re-read the code hoping to fix the bug. If many hands work on the code, &lt;strong&gt;finding the bug can be anything but simple&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Using this naive approach &lt;strong&gt;we’re not exploiting all the information we have&lt;/strong&gt;: we &lt;em&gt;are certain&lt;/em&gt; that the feature &lt;em&gt;used to&lt;/em&gt; work correctly. So something happened in the meantime that surely broke our part of the code. So why look for this change manually when Git can do the dirty work for us in very few steps? &lt;strong&gt;Git can tell us precisely &lt;em&gt;what&lt;/em&gt; happened, &lt;em&gt;when&lt;/em&gt;, &lt;em&gt;who&lt;/em&gt; did it and &lt;em&gt;why&lt;/em&gt;&lt;/strong&gt; (if the developer who introduced the bug wrote a decent commit message).&lt;/p&gt;
&lt;h2&gt;git bisect&lt;/h2&gt;
&lt;p&gt;Well yes, Git offers exactly this feature. Not everyone takes advantage of it but in cases like this it’s extremely powerful. It’s the &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; command.&lt;/p&gt;
&lt;p&gt;To cut a long story short, you define two commits: the first is a “buggy” commit, that is, one that presents the problem, the second is a healthy commit, where the problem didn’t exist yet. Git then shows a commit that’s in the middle and it’s up to us to tell Git whether it works or not. Git at this point shows another commit that’s always in the middle between the buggy commit and the healthy one. You keep going like this until Git shows us the commit that introduced the bug.&lt;/p&gt;
&lt;p&gt;It seems like a very long process but it isn’t: in fact, with each check we halve the number of commits between the good one and the buggy one. For example, if we have 1000 commits separating our two reference commits, we find the one that introduced the problem in log_2(1000) ~ 10 steps!&lt;/p&gt;
&lt;h2&gt;Practical example&lt;/h2&gt;
&lt;p&gt;As an example I used a &lt;a href=&quot;http://8ball.mattianatali.it&quot;&gt;small project of mine&lt;/a&gt; that I had created to learn some concepts about &lt;a href=&quot;https://reactjs.org/&quot;&gt;React&lt;/a&gt;. Let’s suppose we want to know who added the particle effect to the page.
During the &lt;code class=&quot;language-text&quot;&gt;git bisect&lt;/code&gt; procedure we label as &lt;code class=&quot;language-text&quot;&gt;bad&lt;/code&gt; every time the project has the &lt;code class=&quot;language-text&quot;&gt;src/components/atoms/ParticlesBackground&lt;/code&gt; folder. While all the commits that don’t have it will be &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;Let’s start! First we clone the project and enter it with the terminal.&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;Now we start the search&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;Starting the program we notice that the &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; branch has the &lt;code class=&quot;language-text&quot;&gt;src/components/atoms/ParticlesBackground&lt;/code&gt; folder. So we label the commit as &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;Then we go back in Git’s history far enough to no longer find the folder in question. In our case going back 10 commits is enough.&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! Now the folder is gone! So we can label it as &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;Now Git will change commit and move exactly to a point halfway between the commits labeled as &lt;code class=&quot;language-text&quot;&gt;good&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;bad&lt;/code&gt;. It notifies you with the following message.&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;Keep typing &lt;code class=&quot;language-text&quot;&gt;git bisect good&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;git bisect bad&lt;/code&gt; until you’ve analyzed about 4 steps.&lt;/p&gt;
&lt;p&gt;In our specific case it will be:&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;Finally, when Git has identified the commit we were looking for, it tells you like this:&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;The commit message alone gives us the intuition that Git hit the bullseye (“Add particles”)! But we don’t trust it, so let’s actually see what was done in this commit: take the commit id (&lt;code class=&quot;language-text&quot;&gt;b7b5d042a8cba637c56cc52401dcd61ec785d9b4&lt;/code&gt;) and type:&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;scrolling through the commit we notice the part&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;
+...
+```

which is exactly the part we were looking for! So ultimately now we know that Mattia Natali added this part on Monday, November 6, 2017 at 22:24.


## Conclusions

Imagine now doing this for a bug that&apos;s driving you crazy; it&apos;s very powerful because it tells you exactly who did it and what was changed. This way you can ask the commit author for clarification and know exactly the change that created the bug.

Maybe you won&apos;t need `git bisect` every day, but it&apos;s right to keep it in mind because it&apos;s certain that **sooner or later it will come in handy** and it will save you a lot of time.

See you next time!&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[How to be productive with the terminal]]></title><description><![CDATA[If you’re reading this blog post I imagine you’re more or less in the same situation as me. You’re a developer and you have 8 hours a day to…]]></description><link>https://www.mattianatali.it/en/how-to-be-productive-with-the-terminal/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-be-productive-with-the-terminal/</guid><pubDate>Fri, 06 Oct 2017 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;If you’re reading this blog post I imagine you’re more or less in the same situation as me. You’re a developer and you have 8 hours a day to work: in this span of time you have to review other people’s code, attend meetings, manage your millions of issues and maybe even other people’s, help those who ask you for help, think about how to reach your goals and finally program what you’ve thought of.&lt;/p&gt;
&lt;p&gt;Doing all these things and staying within the set 8 daily hours is hard without disappointing anyone’s expectations. So, as good engineers/developers, you’re trying to optimize everything.&lt;/p&gt;
&lt;p&gt;In this blog post I’ll explain how I tried to optimize my time spent in front of the terminal. I’ll focus especially on the Mac operating system, which is the one I currently work on.&lt;/p&gt;
&lt;p&gt;In this guide I don’t want to explain how to use the terminal. That’s a prerequisite for me. My goal is to share with you many little tricks that will save you time in your working daily life so that you can focus more on the activity that actually brings value: programming.&lt;/p&gt;
&lt;h1&gt;The basics&lt;/h1&gt;
&lt;h2&gt;Let’s speed up the cursor&lt;/h2&gt;
&lt;p&gt;Let’s start with a small optimization that’s as simple as it is effective, even before opening the terminal. Many times in the terminal or in your IDE you need to move the cursor. By holding down the arrow keys the cursor moves until you release the key. Well, nothing new so far. The exasperating thing is how slowly this cursor moves! Many people I see, to go fast, start pressing the arrows compulsively or simply wait precious seconds until the cursor moves to the desired position.&lt;/p&gt;
&lt;p&gt;A simple optimization everyone should do is to &lt;strong&gt;decrease the time before key repetition starts and the interval between one repetition and the next&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To do it it’s very simple. On Mac go to Settings -&gt; Keyboard -&gt; Keyboard tab. Set &lt;em&gt;Key Repeat&lt;/em&gt; to &lt;em&gt;Fast&lt;/em&gt; and &lt;em&gt;Delay Until Repeat&lt;/em&gt; to &lt;em&gt;Short&lt;/em&gt;. Now try it and the difference will be huge. I know at first the cursor seems too fast, but then you get used to it and never go back!&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;Keyboard settings, let&amp;#39;s speed up the cursor!&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;This advice applies in general to every program. &lt;strong&gt;If you often use the same function, try to learn its keyboard shortcut&lt;/strong&gt;. It’s definitely faster not to lift your fingers from the keyboard. It happens that the shortcut can’t exist for your function; fortunately most of the time you can create it in the settings. I recommend spending some of your time creating these shortcuts: you’ll save precious time in the long run.&lt;/p&gt;
&lt;h2&gt;iTerm&lt;/h2&gt;
&lt;p&gt;The Mac terminal is good, but if you want even more you can use &lt;a href=&quot;https://www.iterm2.com&quot;&gt;iTerm&lt;/a&gt;. Basically it’s like the native terminal but it has the following additional features that will increase your productivity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Improved search&lt;/strong&gt;: press &lt;code class=&quot;language-text&quot;&gt;cmd + F&lt;/code&gt; and open search mode. Type the keyword to search and it will immediately highlight your word in the terminal. Using &lt;code class=&quot;language-text&quot;&gt;cmd + G&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;cmd + shift + G&lt;/code&gt; you can search for the next or previous word.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Split panels&lt;/strong&gt;: you can split the view both vertically (&lt;code class=&quot;language-text&quot;&gt;cmd + D&lt;/code&gt;) and horizontally (&lt;code class=&quot;language-text&quot;&gt;cmd + shift + D&lt;/code&gt;) so you can have more terminals on a single page. Very useful if you have multiple programs running and need to monitor them at the same time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Customizable profiles&lt;/strong&gt;: with a profile you can completely customize the terminal such as colors, shortcuts. If you spend a lot of time connected to remote machines it’s easy to get confused between the various open tabs. A great way to avoid making a mess is to use different profiles for machines with different purposes. Our good DevOp uses this technique daily: for the production machine he has a beautiful bright red background, so he clearly understands to be careful and not stay there too long. For the stage environment it’s blue, the rest black background.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you’re curious about iTerm I recommend reading the &lt;a href=&quot;https://www.iterm2.com/features.html&quot;&gt;other noteworthy features&lt;/a&gt;, but above all trying it!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Everyday business&lt;/h2&gt;
&lt;p&gt;Here’s a list of tricks I use daily in the terminal. I wrote all the ones that come to mind; some will be obvious to those who live all day in front of the terminal, others I hope not ?.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;tab&lt;/code&gt;: Just a few letters of what you want to type are enough, then press &lt;code class=&quot;language-text&quot;&gt;tab&lt;/code&gt; for autocompletion. This is very useful for example when navigating between tabs.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;sudo !!&lt;/code&gt;: how many times have you typed &lt;code class=&quot;language-text&quot;&gt;apt-get install&lt;/code&gt; without giving root permissions? Many, after reading the error message, press &lt;code class=&quot;language-text&quot;&gt;up arrow&lt;/code&gt; and then move the cursor to the beginning of the command and finally insert the word &lt;code class=&quot;language-text&quot;&gt;sudo&lt;/code&gt; to become root… What a waste of time! Just type &lt;code class=&quot;language-text&quot;&gt;sudo !!&lt;/code&gt; and boom! Done. Basically &lt;code class=&quot;language-text&quot;&gt;!!&lt;/code&gt; is replaced with the previous command and that’s exactly what we wanted.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt;: returns to your home. Why type &lt;code class=&quot;language-text&quot;&gt;cd ~&lt;/code&gt; or worse &lt;code class=&quot;language-text&quot;&gt;cd ../../../../../&lt;/code&gt; to go back home if &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt; is enough?&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;cd -&lt;/code&gt;: returns to the previous directory. Very similar is the &lt;code class=&quot;language-text&quot;&gt;git checkout -&lt;/code&gt; command: it checks out the branch we were working on previously.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;lsof -i :&amp;lt;PORT&gt;&lt;/code&gt;: Mac only. This command is used to identify the program that’s using port &lt;code class=&quot;language-text&quot;&gt;&amp;lt;PORT&gt;&lt;/code&gt;. Very useful when a program gets stuck in the background and you desperately need the port free. Once you’ve run the program just take note of the program’s PID and then &lt;code class=&quot;language-text&quot;&gt;kill &amp;lt;PID&gt;&lt;/code&gt;. Now the port is free!&lt;/li&gt;
&lt;li&gt;Concatenating commands: why stare at a command until it finishes and then run the next one? Using &lt;code class=&quot;language-text&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;;&lt;/code&gt; you can concatenate multiple commands. &lt;code class=&quot;language-text&quot;&gt;&amp;amp;&amp;amp;&lt;/code&gt; runs the second command only if the first finished successfully, while &lt;code class=&quot;language-text&quot;&gt;;&lt;/code&gt; runs it regardless.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ctrl + c&lt;/code&gt;: used to close applications but also to quickly delete what we’re typing.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ctrl + a&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;ctrl + e&lt;/code&gt;: move the cursor to the beginning and end of the command we’re typing respectively.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ctrl+l&lt;/code&gt;: clears the terminal, much faster than typing &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;: takes the last argument of the previous command. Very useful in cases like these
&lt;code class=&quot;language-text&quot;&gt;mkdir -p i/am/creating/a/new/folder/ &amp;amp;&amp;amp; cd !$&lt;/code&gt;
As you may have guessed I’m creating a folder, and once created I enter it without having to type the whole path again.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;man &amp;lt;APPLICATION&gt;&lt;/code&gt;: how many times has it happened that you didn’t remember the options of a command and went online to look for the documentation? No need to go online! Just type &lt;code class=&quot;language-text&quot;&gt;man&lt;/code&gt; followed by the application and you’ll have all the documentation at hand without googling.&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;Example of &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; and &lt;code class=&quot;language-text&quot;&gt;cmd + w&lt;/code&gt;: open and close a new terminal tab respectively. If you notice these commands are “universal”, that is, they also work with browser tabs, finder tabs, your favorite text editor, etc.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;open .&lt;/code&gt;: opens the folder we’re in in Finder.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Navigating commands and auditing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;last&lt;/code&gt;: shows who is connected to the machine with the terminal or who connected previously.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;w&lt;/code&gt;: very similar to &lt;code class=&quot;language-text&quot;&gt;last&lt;/code&gt;. Shows the people currently connected to the machine.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;up arrow&lt;/code&gt;: inserts the previously executed command. Very useful to review the command or modify it in case of a typo. If you keep pressing &lt;code class=&quot;language-text&quot;&gt;up arrow&lt;/code&gt; you go back in the history.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;history&lt;/code&gt;: shows all executed commands. Together with the &lt;code class=&quot;language-text&quot;&gt;grep&lt;/code&gt; command it’s very easy to search for a command. For example, had you started an app using &lt;code class=&quot;language-text&quot;&gt;runserver&lt;/code&gt; but don’t remember all the options by heart? Just type a piece of the command, in our case we type &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;: it’s called &lt;em&gt;reverse-i-search&lt;/em&gt; and it means “search the past for a command similar to this”. In short it’s like the previous command only even faster. For example we can press &lt;code class=&quot;language-text&quot;&gt;ctrl + r&lt;/code&gt; and then type &lt;code class=&quot;language-text&quot;&gt;runserver&lt;/code&gt; to have the command we were looking for in the terminal. If the command you were looking for isn’t the last one but a previous one, keep pressing &lt;code class=&quot;language-text&quot;&gt;ctrl + r&lt;/code&gt; until you find the desired command again!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Let’s go further!&lt;/h2&gt;
&lt;h3&gt;Fuck!&lt;/h3&gt;
&lt;p&gt;Everyone happens to mistype some command: when we make a typo and see the terminal answer us with a no, the first thing we think is “fuck”. With &lt;a href=&quot;https://github.com/nvbn/thefuck&quot;&gt;thefuck&lt;/a&gt; we can vent our anger productively!
This app is as simple as it is brilliant. If we mistype a command, we just type &lt;code class=&quot;language-text&quot;&gt;fuck&lt;/code&gt; in the terminal; this way this app proposes the previous command written correctly. See it as an &lt;strong&gt;automatic corrector for the terminal&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;How thefuck works&quot;&gt;&lt;/p&gt;
&lt;p&gt;Installation is very simple: having installed &lt;a href=&quot;https://brew.sh/&quot;&gt;Homebrew&lt;/a&gt; we just type&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;Good! Now if you mistype some command get angry and type &lt;code class=&quot;language-text&quot;&gt;fuck&lt;/code&gt; and you’ll be more productive!&lt;/p&gt;
&lt;h3&gt;Zsh&lt;/h3&gt;
&lt;p&gt;We often find bash as the default installed shell. If you want that extra gear I recommend using Zsh together with the Oh My Zsh! plugin. This combo will allow you to be more productive for the following reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Improved folder autocompletion&lt;/strong&gt;: better navigation between the proposed choices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autocompletion for the most used programs&lt;/strong&gt;: Git, Docker, npm, Django are the Oh My Zsh plugins I use, but &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins&quot;&gt;there are many others&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;Fully customizable themes&lt;/a&gt;&lt;/strong&gt;: there are many ready-to-use themes, you’ll surely find one that satisfies your personal taste. My favorite is &lt;code class=&quot;language-text&quot;&gt;eastwood&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Greater Git integration&lt;/strong&gt;: as soon as we enter a folder containing a project versioned with Git, we can notice that the branch we’re on is shown and also a small alert when we haven’t committed and pushed all our code. Thanks to these little aids we’ll save many &lt;code class=&quot;language-text&quot;&gt;git status&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved search of previous commands&lt;/strong&gt;: type only the beginning of a command, then pressing &lt;code class=&quot;language-text&quot;&gt;up arrow&lt;/code&gt; shows you the previously used command that starts exactly the same way.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Installation&lt;/h4&gt;
&lt;p&gt;If you want to install Zsh with Oh My Zsh! these are the steps to follow:&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;Now restart the shell; to use Zsh just type &lt;code class=&quot;language-text&quot;&gt;zsh&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you want Zsh to become your default shell then type&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;Changing the theme&lt;/h4&gt;
&lt;p&gt;Zsh configuration files are in the &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt; file. With your favorite editor modify the &lt;code class=&quot;language-text&quot;&gt;ZSH_THEME&lt;/code&gt; variable. If you don’t know which theme to choose, you can use &lt;code class=&quot;language-text&quot;&gt;random&lt;/code&gt; mode: this way every time you open a shell you’ll have a different theme. When you find one you like, take the name of the theme that appears at startup and write it in the aforementioned variable.&lt;/p&gt;
&lt;p&gt;As I said before, I’m using &lt;code class=&quot;language-text&quot;&gt;eastwood&lt;/code&gt;. It has very relaxing colors and doesn’t distract too much compared to other themes.&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;Zsh Eastwood theme&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;Changing the plugins&lt;/h4&gt;
&lt;p&gt;Also in the &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt; file we can find the &lt;code class=&quot;language-text&quot;&gt;plugins&lt;/code&gt; variable. You can see plugins as improvements in autocompletion for applications you often use in the terminal.&lt;/p&gt;
&lt;p&gt;I currently use this configuration.&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;I remind you to separate the plugins with a space and not with a comma. Of course &lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins&quot;&gt;Zsh offers many other plugins&lt;/a&gt;, choose the bare minimum because they could slow down the terminal startup.&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;Aliases, aliases everywhere!&lt;/h3&gt;
&lt;p&gt;In the terminal you can add aliases to speed up the execution of one or more commands. If you notice that you &lt;strong&gt;always type the same command&lt;/strong&gt; (or even a series of commands) then it means it’s time to &lt;strong&gt;add an alias&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Adding an alias is simple: you need to add them in the &lt;code class=&quot;language-text&quot;&gt;~/.bash_profile&lt;/code&gt; file if you use bash or &lt;code class=&quot;language-text&quot;&gt;~/.zshrc&lt;/code&gt; if you use Zsh.
The syntax to add one is the following:&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;Here are some of my aliases as an example:&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;: running &lt;code class=&quot;language-text&quot;&gt;gbd&lt;/code&gt; (Git Branch Delete) will delete all local Git branches of the project contained in the folder. Only run it if you’re sure of what you’re doing!&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;: running &lt;code class=&quot;language-text&quot;&gt;pycc&lt;/code&gt; (pyc clean) will recursively delete all compiled Python files present in the folder. Very useful when refactoring in Python and we fear that the compiled files no longer match the source code.&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;: running &lt;code class=&quot;language-text&quot;&gt;yda &amp;lt;YOUTUBE_URL&gt;&lt;/code&gt; (YouTube Download Audio) will download the audio file of a YouTube video. This command only works if you followed my guide on &lt;a href=&quot;/en/how-to-download-youtube-videos-with-the-terminal/&quot;&gt;how to download a video from 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;: running &lt;code class=&quot;language-text&quot;&gt;ddev &amp;lt;DOCKER_COMPOSE_COMMAND&gt;&lt;/code&gt; (Docker dev) you can give any command to your Docker Compose without worrying about the folder you’re in. Without this command I was always forced to go to my Docker Compose project folder &lt;code class=&quot;language-text&quot;&gt;cd &amp;lt;PATH_TO_DOCKER_COMPOSE_PROJECT&gt;&lt;/code&gt; and then type &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;… All wasted time!&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;: if you have a project you work on daily I recommend creating an alias to reach it quickly. As a convention I use the initial letter &lt;code class=&quot;language-text&quot;&gt;c&lt;/code&gt; which recalls the &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt; command and then the project name.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Git&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Git also supports its own internal alias mechanism&lt;/strong&gt;. Open or create the &lt;code class=&quot;language-text&quot;&gt;~/.gitconfig&lt;/code&gt; file. Inside it let’s add&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;As you can guess we added the alias section and added two new git aliases.
Once we’ve restarted the terminal we can use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;git st&lt;/code&gt;: a modified version of &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;: shows the commit tree.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course these are two of my commands but nobody forbids you from creating your own!&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;Command &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;Access to a remote machine can also be sped up. I imagine the machines you connect to remotely are always the same, and typing &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; in the terminal every time is long, tedious and hard to remember. It’s a whole other story if we could connect simply by typing &lt;code class=&quot;language-text&quot;&gt;ssh &amp;lt;ALIAS&gt;&lt;/code&gt; where &lt;code class=&quot;language-text&quot;&gt;&amp;lt;ALIAS&gt;&lt;/code&gt; is the name we gave to the remote machine. All this is possible thanks to the &lt;code class=&quot;language-text&quot;&gt;~/.ssh/config&lt;/code&gt; configuration file. If the file isn’t present, you can create it by typing &lt;code class=&quot;language-text&quot;&gt;touch ~/.ssh/config&lt;/code&gt;. Through this file &lt;strong&gt;we can save remote connections and recall them via an alias&lt;/strong&gt;, without necessarily rewriting all the parameters every time.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;~/.ssh/config&lt;/code&gt; file has the following syntax:&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;Replace the variables written between angle brackets with your parameters: this way instead of typing&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;now you just type&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;much, much faster and more immediate.
In the configuration file the &lt;code class=&quot;language-text&quot;&gt;HostName&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;User&lt;/code&gt; fields are mandatory, the rest are optional. You can add more Hosts if you have different machines you access remotely.&lt;/p&gt;
&lt;p&gt;The available SSH parameters aren’t only these; if you need advanced features like tunneling I recommend reading the &lt;a href=&quot;https://www.ssh.com/ssh/config/&quot;&gt;official SSH Config File guide&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;Example of remote connection using 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;Curiosities&lt;/h3&gt;
&lt;p&gt;These commands aren’t related to productivity, but they’re still noteworthy.&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;: did you know the Mac can talk and you can make it talk through the terminal? By combining this command with &lt;code class=&quot;language-text&quot;&gt;ssh&lt;/code&gt; we can make a Mac talk even remotely. So nobody forbids us from sending a love message to our girlfriend through the command &lt;code class=&quot;language-text&quot;&gt;ssh girlfriend@&amp;lt;IP_ADDRESS&gt; say &apos;I love you!&apos;&lt;/code&gt;, try it and observe her reaction! (Spoiler: she won’t appreciate it, I can assure you ?).&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;yes&lt;/code&gt;: if you have a temporary chilblain and need a heat source, then I recommend starting &lt;code class=&quot;language-text&quot;&gt;yes&lt;/code&gt; from the terminal. This command does nothing but send the CPU to 100%!&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;I hope all these tricks of mine help you in your daily life to reach your work goals in the shortest time possible. There will surely be millions of other tips and tricks I’m not aware of: if I learn others I’ll try to add them here so I can share them with you.&lt;/p&gt;
&lt;p&gt;See you soon, good work and see you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to download YouTube videos with the terminal]]></title><description><![CDATA[You’ve just found a beautiful video on YouTube and you absolutely want to download it, or you want to download only the audio part of the…]]></description><link>https://www.mattianatali.it/en/how-to-download-youtube-videos-with-the-terminal/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-download-youtube-videos-with-the-terminal/</guid><pubDate>Sun, 17 Sep 2017 15:10:47 GMT</pubDate><content:encoded>&lt;p&gt;You’ve just found a beautiful video on YouTube and you absolutely want to download it, or you want to download only the audio part of the video to add it to your music playlist? The terminal doesn’t scare you? Good, then this guide is for you!&lt;/p&gt;
&lt;p&gt;There are a lot of online sites that do these things: full of ads, sometimes they don’t even work and usually they give very little customization on what to download. I got tired of relying on these external programs and decided to do everything “at home”.&lt;/p&gt;
&lt;p&gt;This guide is based on the Mac OS operating system. But with small adjustments it’s possible to follow it on Windows and Linux too, since the programs I’ll use are multi-platform.&lt;/p&gt;
&lt;h1&gt;Preparation&lt;/h1&gt;
&lt;p&gt;Basically to achieve the goal we need 3 programs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://brew.sh/index_en.html&quot;&gt;Homebrew&lt;/a&gt;&lt;/strong&gt;: the best application manager for Mac. With this software installing the other two will be a walk in the park.&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;: when it comes to audio/video conversion it’s the reference point. Free, open source, cross platform, powerful… What more could you ask for?&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;: the program that does the dirty work of downloading the video from YouTube.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;Now that we know what we need, let’s proceed with installing these programs!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Let’s open the Mac terminal.&lt;/li&gt;
&lt;li&gt;Let’s install 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;Let’s install 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;Let’s install 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;Good! Now we have everything we need to download all the YouTube videos we want!&lt;/p&gt;
&lt;h1&gt;Let’s start!&lt;/h1&gt;
&lt;p&gt;As an example I’ll use the video by Gigi D’Agostino that he just uploaded online. I recommend watching and listening to it: the sobriety of his films is unmatched :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;Automatic mode&lt;/h2&gt;
&lt;p&gt;Let’s start with the simplest thing: downloading the video without wasting too much time!&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Let’s go to YouTube, open the video and copy the URL. In our case it’s &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;Let’s open the terminal and type &lt;code class=&quot;language-text&quot;&gt;youtube-dl &lt;/code&gt; and paste the URL from the previous step. So
&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;
you’ll notice that when pasting, some &lt;code class=&quot;language-text&quot;&gt;\&lt;/code&gt; are added before &lt;code class=&quot;language-text&quot;&gt;?&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;=&lt;/code&gt;. Don’t worry, they are escape characters that are necessary and that the terminal adds automatically.&lt;/li&gt;
&lt;li&gt;Let’s wait and it’s done! In the folder we’re in we’ll have the video!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Choosing the video format&lt;/h2&gt;
&lt;p&gt;Ok Ok, maybe you don’t like the downloaded format or you want one with lower quality… To do this type:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Let’s add the &lt;code class=&quot;language-text&quot;&gt;-F&lt;/code&gt; option which shows us all the available formats
&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;We’ll have a nice list of available formats. Let’s choose the one we like best and take note of the &lt;code class=&quot;language-text&quot;&gt;format code&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To download the chosen version we just need to add &lt;code class=&quot;language-text&quot;&gt;-f &amp;lt;format_code&gt;&lt;/code&gt; where &lt;code class=&quot;language-text&quot;&gt;&amp;lt;format_code&gt;&lt;/code&gt; is the code chosen in the previous step. So, for example, if we wanted to download the version
&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;
we’d just type.
&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;Extracting the audio track&lt;/h2&gt;
&lt;p&gt;To get only the audio track we just need to choose the format code that has &lt;code class=&quot;language-text&quot;&gt;audio only&lt;/code&gt; in the &lt;code class=&quot;language-text&quot;&gt;resolution&lt;/code&gt; column. In our video, if we show the list of available formats we can notice that there are these audio tracks&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;Very likely the audio format isn’t the one we want. So we need an audio conversion. Youtube-dl uses ffmpeg to perform the conversion.
For example if we wanted an audio file in &lt;code class=&quot;language-text&quot;&gt;.m4a&lt;/code&gt; format with a bitrate of &lt;code class=&quot;language-text&quot;&gt;160k&lt;/code&gt; we’d just type&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;Where the options mean&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;-x&lt;/strong&gt;: extract the audio track from the video.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;—audio-format m4a&lt;/strong&gt;: the format to download, or to convert if not present in the list, is m4a. The available formats are &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;: desired audio track bitrate.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Downloading multiple videos or a playlist&lt;/h2&gt;
&lt;p&gt;Now that we know how to download a video in the perfect format for us, why not apply the same settings to multiple videos at once? It’s very simple! Just add more URLs in our terminal separated by a space. For example we can type&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;to have both videos converted into audio tracks.&lt;/p&gt;
&lt;p&gt;If instead we wanted to download a playlist instead of a single video we just need to insert the playlist URL!&lt;/p&gt;
&lt;h2&gt;Making our life easier with aliases&lt;/h2&gt;
&lt;p&gt;When I want to download songs from YouTube, I usually always use the same settings. And typing &lt;code class=&quot;language-text&quot;&gt;youtube-dl -x --audio-format m4a --audio-quality &amp;lt;URL&gt;&lt;/code&gt; every time is a pain as well as hard to remember. It would be much better if you could just type &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; stands for Youtube Download Audio). The good news is that you can!&lt;/p&gt;
&lt;p&gt;Let’s open the terminal and enter&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;What does this command do?&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;: write the new alias at the bottom of the &lt;code class=&quot;language-text&quot;&gt;~/.bash_profile&lt;/code&gt; file. This way, every time we open a new terminal we’ll have this alias ready to use.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;amp;&amp;amp; source !$&lt;/code&gt;: after writing the new alias, reload the &lt;code class=&quot;language-text&quot;&gt;~/.bash_profile&lt;/code&gt; file in the terminal, so that the new alias is available in the current terminal too.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, if we want to download any song from YouTube it will be very simple.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Let’s search for the video on YouTube, copy the URL.&lt;/li&gt;
&lt;li&gt;Let’s open the terminal and type &lt;code class=&quot;language-text&quot;&gt;yda &amp;lt;URL&gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Done!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;I want to know more!&lt;/h2&gt;
&lt;p&gt;Youtube-dl doesn’t only have these settings, these are just the ones I use. If you want to know more just type &lt;code class=&quot;language-text&quot;&gt;youtube-dl --help&lt;/code&gt;. This way you’ll have all, but really all, the settings of this program and I assure you there are a lot of them!&lt;/p&gt;
&lt;h1&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;I hope this guide has given you one more tool to download the YouTube videos you care about most, without needing online sites full of ads that work once in a while.
I also hope that now you’ve grasped the potential of the terminal, an application used daily by developers, but unjustly snubbed by many!&lt;/p&gt;
&lt;p&gt;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to play videogames from two or three eras ago]]></title><description><![CDATA[During these holidays I got a moment of nostalgia for the old, very old videogames from the ’90s that I used to play on my first PC, an…]]></description><link>https://www.mattianatali.it/en/how-to-play-videogames-from-two-or-three-eras-ago/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-play-videogames-from-two-or-three-eras-ago/</guid><pubDate>Mon, 02 Jan 2017 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;During these holidays I got a moment of nostalgia for the old, very old videogames from the ’90s that I used to play on my first PC, an ancient Compaq Presario with a 133MHz CPU.&lt;/p&gt;
&lt;p&gt;It seems impossible but it’s still possible to play these videogames without too many compatibility problems thanks to &lt;a href=&quot;http://www.dosbox.com/&quot;&gt;DOSBox&lt;/a&gt;. This program is nothing more than an emulator of the DOS operating system: in the ’90s many games supported this operating system and so we can take advantage of that.&lt;/p&gt;
&lt;p&gt;In this guide I’ll explain how to play some videogames that marked my childhood.&lt;/p&gt;
&lt;h2&gt;Let’s install DOSBox&lt;/h2&gt;
&lt;p&gt;First of all you need to install &lt;a href=&quot;http://www.dosbox.com/&quot;&gt;DOSBox&lt;/a&gt;; I recommend using Windows as the operating system… On Mac I have some performance problems… It seems absurd but that’s how it is :D. The installation is nothing special: just go to the download section of the website and download the package and install it like any common software. Once this step is done we’re ready to dive into the past!&lt;/p&gt;
&lt;h2&gt;Grand Prix Circuit&lt;/h2&gt;
&lt;p&gt;Let’s start with a very simple game. &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;First we need to &lt;a href=&quot;http://www.bestoldgames.net/eng/old-games/grand-prix-circuit.php&quot;&gt;download the game&lt;/a&gt;. Download the package and extract the files from the &lt;code class=&quot;language-text&quot;&gt;.zip&lt;/code&gt; archive into a folder, for example &lt;code class=&quot;language-text&quot;&gt;C:\games\gp\&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Mounting the volume&lt;/h3&gt;
&lt;p&gt;Now let’s start DOSBox. A command prompt appears, which is nothing more than the classic DOS shell.
The first thing to do is mount the volume where our game lives. In simpler words we need to give DOSBox a &lt;code class=&quot;language-text&quot;&gt;C:\&lt;/code&gt; volume, a portion of memory, that has access to the game. Without this operation DOSBox can’t read any data from our hard disk precisely because the volumes (&lt;code class=&quot;language-text&quot;&gt;C:\&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;D:\&lt;/code&gt; etc.) that Windows uses are completely different from the ones DOSBox uses.
To do this operation just type 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:\games\&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we’ve mounted our &lt;code class=&quot;language-text&quot;&gt;games&lt;/code&gt; folder as volume &lt;code class=&quot;language-text&quot;&gt;C&lt;/code&gt;, we can access it through 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;You can see that now DOSBox shows &lt;code class=&quot;language-text&quot;&gt;C:\&gt;&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;Z:\&gt;&lt;/code&gt; precisely because it’s inside our newly created volume. Basically now in DOSBox we’re in the &lt;code class=&quot;language-text&quot;&gt;C:\games\&lt;/code&gt; folder of our PC.&lt;/p&gt;
&lt;h3&gt;Starting the game&lt;/h3&gt;
&lt;p&gt;Now let’s use another DOS command:&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;this command shows all the files and folders contained in the path we’re in. Our &lt;code class=&quot;language-text&quot;&gt;gp&lt;/code&gt; folder should appear. To access it we use the command&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;Now we’re in the folder where the Grand Prix Circuit we just downloaded is. To start the game we just need to run the command&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;Congratulations! Now you can have fun playing a great game that made history!&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;Good, so far we’ve learned to do the following things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download the game and start DOSBox.&lt;/li&gt;
&lt;li&gt;Mount the &lt;code class=&quot;language-text&quot;&gt;games&lt;/code&gt; directory to give DOSBox a portion of memory from our PC.&lt;/li&gt;
&lt;li&gt;Navigate between folders in DOS using the &lt;code class=&quot;language-text&quot;&gt;cd&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;dir&lt;/code&gt; commands. This guide doesn’t aim to teach you how to use this operating system so I’ve been quite brief. If you want to know more you can &lt;a href=&quot;http://www.myw0.com/2010/1635/list-of-dos-commands-cheat-sheet-for-dos/&quot;&gt;read up via this link&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Start the game.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These steps work for a good part of the old videogames, but there are others that require installation or inserting the CD-ROM to play. The next game falls exactly into this case.&lt;/p&gt;
&lt;h2&gt;Ignition&lt;/h2&gt;
&lt;p&gt;I really like this game a lot! It reminds me of the hours spent with my cousin many years ago!&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;The startup mode is similar to the previous one, except that in this case we need to install the game as if we had a 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;Let’s download the game&lt;/a&gt; and extract the archive into &lt;code class=&quot;language-text&quot;&gt;C:\games\ign\&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Mounting the volumes&lt;/h3&gt;
&lt;p&gt;Let’s mount the &lt;code class=&quot;language-text&quot;&gt;C:&lt;/code&gt; volume with the same command used before&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:\games\&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let’s insert the Ignition CD-ROM! How? More or less like mounting a classic 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:\games\ign\ -t cdrom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case we’re telling DOSBox to show our &lt;code class=&quot;language-text&quot;&gt;c:\games\ign\&lt;/code&gt; folder, where the downloaded game is, as if it were a CD-ROM.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;Now let’s enter the CD and start the installation&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;At this point the installation will start. Choose your language and keep pressing next.&lt;/p&gt;
&lt;h3&gt;Starting the game&lt;/h3&gt;
&lt;p&gt;Now we’re ready to play. Type these three commands and have fun!&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[How to download songs from SoundCloud in a few simple clicks]]></title><description><![CDATA[SoundCloud, for those who don’t know it, is a great website that allows musicians to collaborate, promote and distribute their music…]]></description><link>https://www.mattianatali.it/en/how-to-download-songs-from-soundcloud-in-a-few-clicks/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-download-songs-from-soundcloud-in-a-few-clicks/</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;, for those who don’t know it, is a great website that allows musicians to collaborate, promote and distribute their music.&lt;/p&gt;
&lt;p&gt;Unfortunately it doesn’t allow songs to be downloaded, but by using Google Chrome’s &lt;a href=&quot;https://support.google.com/dfp_premium/answer/4497389?hl=en&quot;&gt;developer tools&lt;/a&gt; it’s very easy to bypass this restriction.&lt;/p&gt;
&lt;h2&gt;Instructions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Go to &lt;a href=&quot;https://soundcloud.com/&quot;&gt;SoundCloud&lt;/a&gt;&lt;/strong&gt; using Google Chrome, and open the page of the song you want to download.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Open the &lt;a href=&quot;https://support.google.com/dfp_premium/answer/4497389?hl=en&quot;&gt;developer tools&lt;/a&gt;&lt;/strong&gt; by pressing &lt;code class=&quot;language-text&quot;&gt;F12&lt;/code&gt; on Windows or &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; on Mac. Click on the Network tab. In this section, click on the sixth icon from the left. This will open the timeline of the various downloads the browser is making.&lt;/li&gt;
&lt;li&gt;Now you’re ready to intercept the &lt;code class=&quot;language-text&quot;&gt;.mp3&lt;/code&gt; file to download! &lt;strong&gt;Start the song&lt;/strong&gt; in the browser. As soon as the song starts you’ll see some downloads starting on the timeline, one line will surely catch your attention because it will be much longer than the others. This line represents the song in &lt;code class=&quot;language-text&quot;&gt;.mp3&lt;/code&gt; format.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Select the song from the timeline&lt;/strong&gt;. To do that, just drag the mouse over a small piece of the line; I recommend picking a part where this line is isolated so you don’t get the selection wrong.&lt;/li&gt;
&lt;li&gt;Once you’ve selected the download in the timeline, the entry for your track will appear at the bottom. Right-click it and click on &lt;strong&gt;“Open link in new tab”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;That’s it! Now you have your track in &lt;code class=&quot;language-text&quot;&gt;.mp3&lt;/code&gt;! Click on &lt;code class=&quot;language-text&quot;&gt;File&lt;/code&gt;-&gt;&lt;code class=&quot;language-text&quot;&gt;Save as...&lt;/code&gt; and &lt;strong&gt;enjoy the song&lt;/strong&gt; wherever and whenever you want!&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Video tutorial&lt;/h2&gt;
&lt;p&gt;Do 6 steps seem too many? I assure you that once you get the hang of it you can download whatever you want in less than 2 seconds. Here are the 6 steps wrapped up in a short 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;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to improve your photos with Nik Collection]]></title><description><![CDATA[Digital has revolutionized quite a few industries, including photography. I entered this world right at the moment of transition… and I must…]]></description><link>https://www.mattianatali.it/en/how-to-improve-your-photos-with-nik-collection/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-improve-your-photos-with-nik-collection/</guid><pubDate>Thu, 11 Aug 2016 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Digital has revolutionized quite a few industries, including photography. I entered this world right at the moment of transition… and I must say I really don’t miss the old film roll.&lt;/p&gt;
&lt;p&gt;A great advantage of digital photography is certainly the fascinating world of &lt;strong&gt;post-production&lt;/strong&gt;. Photography purists hate it, veterans of the old film roll think it’s an abomination.
For me, on the other hand, it has become a phase almost as important as the shot itself: with post-production you can completely change a mediocre photo and turn it into a unique shot, add dynamism, give character to an insipid photo.&lt;/p&gt;
&lt;p&gt;This little guide will teach you exactly that (or so we hope): the photo I’ll use was taken in France and it’s the very famous Notre Dame de Paris.&lt;/p&gt;
&lt;h2&gt;Before we start&lt;/h2&gt;
&lt;p&gt;To follow this guide you need professional software: I used &lt;strong&gt;&lt;a href=&quot;http://www.adobe.com/products/photoshop.html&quot;&gt;Adobe Photoshop&lt;/a&gt;&lt;/strong&gt;. You can also use &lt;a href=&quot;https://support.apple.com/aperture&quot;&gt;Aperture&lt;/a&gt; or &lt;a href=&quot;http://www.adobe.com/products/photoshop-lightroom.html&quot;&gt;Lightroom&lt;/a&gt;. These programs cost a lot: the first thing to do is buy them or hope your company has a license for you, or that some friend of yours is particularly kind and passes you one of their license slots (Photoshop can be used on up to 3 PCs with a single license).&lt;/p&gt;
&lt;p&gt;This guide doesn’t aim to teach you how to use these programs; let’s say having at least a basic knowledge of them is a prerequisite.&lt;/p&gt;
&lt;p&gt;The star software of this guide, however, is this collection of plugins that rely on them: &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;Until last year this suite cost about $500, and in my opinion it was worth every penny. Now instead Google has decided to make it &lt;strong&gt;free&lt;/strong&gt;!&lt;/p&gt;
&lt;h2&gt;Choosing the photo&lt;/h2&gt;
&lt;p&gt;The first thing to do is choose which shot you intend to improve / modify. One thing must be clear: &lt;strong&gt;post-production can work miracles but there’s a limit to everything&lt;/strong&gt;. If the initial photo is bad, it’s likely that even under heavy retouching it will still be bad. Post-production enhances the content, but if the initial value is zero it’s hard for something sensational to come out. So always try to take the best possible shot to have a good starting point.
My photo is this one: I took it with my LG G3, not a DSLR, just a 3-year-old smartphone. During my stay in Paris I didn’t have anything better, but it still has great potential.
&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;Once the photo is chosen you have to decide what to do: maybe if you don’t know what Nik Collection can do, this step will be a bit difficult for you.
My goal in this photo is to enhance the cathedral, make the details stand out and give a dramatic tone, typical of cathedrals, to the whole scene.&lt;/p&gt;
&lt;h2&gt;Let’s get to know Nik Collection&lt;/h2&gt;
&lt;p&gt;Now that we’ve decided our starting point and our goal, it’s time to get to know the tools at our disposal.&lt;/p&gt;
&lt;p&gt;If you haven’t already, download &lt;a href=&quot;https://www.google.com/nikcollection/&quot;&gt;Nik Collection&lt;/a&gt; and install it. Photoshop must already be present on your PC.&lt;/p&gt;
&lt;p&gt;Once installed, if you start Photoshop, you can see a small new box where you can choose the various plugins that make up this suite:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dfine:&lt;/strong&gt; it’s the first plugin to start. Its job is to remove noise from photos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analog Efex Pro:&lt;/strong&gt; simulates the effect of old films and old cameras that made history with their particular effects. Do you remember Instagram filters? Well, you’ve grasped what this plugin can do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Color Efex Pro:&lt;/strong&gt; if you want to correct some tints, create effects that have to do with colors, this plugin is perfect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Silver Efex Pro:&lt;/strong&gt; very useful if you want to create a monochromatic image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Viveza:&lt;/strong&gt; great if you want to modify only specific parts of the photo, highlight subjects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HDR Efex Pro:&lt;/strong&gt; to create an &lt;a href=&quot;https://en.wikipedia.org/wiki/High_dynamic_range_imaging&quot;&gt;HDR image&lt;/a&gt;. Without getting too technical, to create a real HDR image you need multiple shots of the same subject using different exposures. But this plugin manages to achieve the same result even from a single image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sharpener Pro:&lt;/strong&gt; its job is to make details stand out and make the image less blurry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If for some reason the Nik Collection box doesn’t appear, you can find all these programs in the top menu under &lt;em&gt;Filters&lt;/em&gt; &gt; &lt;em&gt;Nik Collection&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Let’s remove the noise&lt;/h2&gt;
&lt;p&gt;Now it’s time to start! The first step I always take is removing noise from the photo. If the shot was taken with a camera that isn’t particularly powerful, like my smartphone, this step is practically mandatory. Noise, even if imperceptible, is amplified during the editing steps. So cleaning the image from these disturbances is very important.&lt;/p&gt;
&lt;p&gt;This step is very simple. Load the image into Photoshop, start &lt;strong&gt;Dfine&lt;/strong&gt;. As you open it you can notice that it does some magic and removes noise automatically. It might seem like nothing has changed; actually to appreciate Dfine’s work it’s useful to zoom the image to 100%. To do that double-click the image; finally, at the top left, where it says &lt;em&gt;Views&lt;/em&gt;, you have three display modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single image view:&lt;/strong&gt; the default view. You only see the final output.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Split view:&lt;/strong&gt; you can see the image before and after applying the filter at the same time. You can also move the red line to have a quick comparison between the two versions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Side by side preview:&lt;/strong&gt; basically you’ll have the two images, before and after applying the filter, side by side.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you’ve been able to appreciate the changes, press &lt;em&gt;OK&lt;/em&gt;. So you can move on to the next step.&lt;/p&gt;
&lt;h2&gt;HDR Efex Pro, it’s your turn!&lt;/h2&gt;
&lt;p&gt;Now it’s time to add a touch of HDR to the image. HDR stands for &lt;a href=&quot;https://en.wikipedia.org/wiki/High_dynamic_range_imaging&quot;&gt;High Dynamic Range&lt;/a&gt; and it’s a photographic technique that allows you to show more details than a normal photograph. Do you remember those situations where you take a photo of an environment that has both particularly bright and dark spots? It happens that the very bright part comes out as just a nice white patch and the dark part as a black patch. HDR manages to overcome these problems.
This is just to give you an idea of what HDR is; you’d need to write a guide just on this… But it’s better to get back to our image!&lt;/p&gt;
&lt;p&gt;Always from the Nik Collection box, in the &lt;em&gt;HDR Efex Pro&lt;/em&gt; section choose &lt;em&gt;Tone Mapping (Single Image)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;On the left side you can find the &lt;strong&gt;Preset Library&lt;/strong&gt;, in it there are already some great &lt;strong&gt;starting points&lt;/strong&gt;. I chose &lt;em&gt;Deep 1&lt;/em&gt; which is in the &lt;em&gt;Realistic&lt;/em&gt; library.&lt;/p&gt;
&lt;p&gt;Once you’ve chosen the starting point you can focus on the part on the right of the window. Here you can find a sea of configurations to modify every single aspect of the filter. The macro areas are these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tone Compression:&lt;/strong&gt; here are all the settings that only concern the HDR effect. Surely this is where you find the settings that radically change the appearance of your image.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tonality:&lt;/strong&gt; here you can find the classic image settings like exposure, shadows, highlights, contrast, etc. An option I particularly like is &lt;em&gt;structure&lt;/em&gt;. By increasing it you can notice how the image becomes particularly defined. Be careful not to overdo it because in addition to enhancing details it also enhances noise. That’s why I strongly recommended removing it with Dfine… Now the chickens come home to roost!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Finishing:&lt;/strong&gt; it’s the post-production of the post-production effect! I mean, it’s the final touches you can make before leaving this plugin. From this area I added a small vignetting effect. Near the &lt;em&gt;Vignette&lt;/em&gt; text there’s a small selection menu. I chose &lt;em&gt;Lens 2&lt;/em&gt;. The vignetting effect does nothing more than darken the edges of the image (or lighten them). It’s a great way to guide the observer’s attention. In this case my intent is to enhance the cathedral.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case too I haven’t gone into too much detail. My advice is to play and try all the various features yourself. Only this way can you master this suite… By using it!&lt;/p&gt;
&lt;p&gt;Here’s the final result after this step.&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;Let’s correct the colors&lt;/h2&gt;
&lt;p&gt;Now the image has a much more dramatic tone than the original, it suits a cathedral very well. The details of the structure have been highlighted, we can be satisfied with our work! There’s just one small problem… The cathedral has become a canary! It’s too saturated and so we need to remove some saturation from the cathedral.&lt;/p&gt;
&lt;p&gt;To do this let’s start &lt;strong&gt;Color Efex Pro&lt;/strong&gt;. The window that opens should be familiar by now: only the starting filters on the left and the settings on the right change.&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;The filter we’ll use to desaturate the image is called &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Bleach_bypass&quot;&gt;Bleach Bypass&lt;/a&gt;&lt;/em&gt;. Let’s select it from the available filters and we immediately notice the changes on the image.&lt;/p&gt;
&lt;p&gt;So far we’ve applied the filters &lt;em&gt;to the whole image&lt;/em&gt;; in this case we want to apply it only &lt;em&gt;to the cathedral&lt;/em&gt; without affecting the rest.&lt;/p&gt;
&lt;h3&gt;Say hello to control points!&lt;/h3&gt;
&lt;p&gt;To solve this problem we need to learn a very important feature that I’ve kept hidden from you until now. &lt;strong&gt;Control points&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;These &lt;em&gt;“control points”&lt;/em&gt; &lt;strong&gt;allow you to apply the filter only to specific areas&lt;/strong&gt;. Let’s immediately try using one. On the right side look for the &lt;em&gt;Control Points&lt;/em&gt; function; here you can notice two buttons: the first shows a circle with a ”+” next to it and the other a ”-“. The difference between the two is that the first adds a point with 100% opacity, the second with 0%. In other words the first applies the filter at the selected point, the second removes it.&lt;/p&gt;
&lt;p&gt;We need to apply the filter at the point we select. So we need to press the button with the ”+“. Once pressed, move the cursor over the cathedral; you’ll notice that the cursor symbol has become a sort of crosshair; click on the cathedral. Nik Collection is smart enough to understand that you want to apply the filter only to the selected point, so it removes the filter from the rest of the image and leaves it only on the control point.&lt;/p&gt;
&lt;p&gt;Once the control point is placed you can notice that there’s a small circle on the image with two sliders. The first determines the &lt;em&gt;range&lt;/em&gt; of the control point, the second its opacity. Obviously the larger the range, the more our filter will affect a larger portion of the image, and the more we increase the opacity the more the difference is noticeable (in our case it’s already at 100%).&lt;/p&gt;
&lt;p&gt;Since the control point has a circular range, I recommend adding many small points rather than having one big one to have more control over it.&lt;/p&gt;
&lt;p&gt;But how do we understand the real range of a control point? In fact &lt;strong&gt;Nik Collection applies the filter intelligently&lt;/strong&gt;: even though the range is circular, you don’t notice the point where it stops applying these corrections. Precisely because Nik’s strong point is its algorithms for creating the application masks. This sentence is probably gibberish for those who aren’t familiar with Photoshop, but it will be clear shortly.
To understand what I wrote let’s go back to Color Efex Pro; in the &lt;em&gt;Control Points&lt;/em&gt; section we can notice the list of our added points. Each entry in this list is made up of 4 points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Checkbox to enable the control point.&lt;/li&gt;
&lt;li&gt;Its name.&lt;/li&gt;
&lt;li&gt;The percentage of the image affected.&lt;/li&gt;
&lt;li&gt;Checkbox to show the application point (its mask).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s check this last checkbox of any control point we’ve added. The image becomes monochromatic and from here we can actually see the &lt;strong&gt;real application point&lt;/strong&gt; of the selected control point’s filter. Black indicates that the filter hasn’t been applied, white where it has been applied, the various intermediate shades indicate a different opacity of the application.&lt;/p&gt;
&lt;p&gt;Add all the control points necessary to “make the cathedral white”; this way you’ll apply the filter only to the cathedral. Here’s my white cathedral, a sign that I’m applying the bleach bypass filter only to it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameColorMask-1470935624170.jpg&quot; alt=&quot;Filter application points&quot;&gt;&lt;/p&gt;
&lt;p&gt;In my opinion control points are the real strong point of Nik Collection. To create the same mask using only Photoshop, instead of taking 5 minutes, it would have taken us hours!&lt;/p&gt;
&lt;p&gt;Once we’ve made sure the filter is applied only to the cathedral, we can uncheck the checkboxes of the control points’ masks and go back to viewing the normal image.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameMod-1470935662758.jpg&quot; alt=&quot;Final result&quot;&gt;&lt;/p&gt;
&lt;p&gt;Finally here we are!&lt;/p&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;Here’s the final result next to our original image:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/NotreDameComparison-1470935678418.jpg&quot; alt=&quot;Comparison&quot;&gt;&lt;/p&gt;
&lt;p&gt;I hope this guide has given you a vague idea of the potential of this plugin suite. Obviously this is just the tip of the tip of the iceberg: my intent isn’t to explain the suite and all its commands, but to apply it in a real use case.&lt;/p&gt;
&lt;p&gt;If you feel like learning more, I strongly recommend this introductory video tutorial… It’s in English and lasts an hour… But it’s really worth it!&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;See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[How to remove viruses from your computer]]></title><description><![CDATA[“Hi! How are you? Listen, I think I have a virus on my PC, can you take a look at it?” The variations of this sentence are endless, but more…]]></description><link>https://www.mattianatali.it/en/how-to-remove-viruses-from-your-computer/</link><guid isPermaLink="false">https://www.mattianatali.it/en/how-to-remove-viruses-from-your-computer/</guid><pubDate>Sun, 07 Aug 2016 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;“Hi! How are you? Listen, I think I have a virus on my PC, can you take a look at it?”&lt;/p&gt;
&lt;p&gt;The variations of this sentence are endless, but more or less almost all the people who call me to get a hand with this problem start like that.&lt;/p&gt;
&lt;p&gt;Today I’ll explain what you can do to solve this problem on your own, without spending a penny and without even needing any special skills.&lt;/p&gt;
&lt;h2&gt;There are viruses and viruses&lt;/h2&gt;
&lt;p&gt;Before starting, it’s better to know at least a little about the various types of viruses you might run into. In my opinion it’s useful to understand the error messages your antivirus shows you when it finds something unusual.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Malware:&lt;/strong&gt; this is anything that can harm your PC. So it’s the macro category that contains all the entries below… In fact I should have written “There are malware and malware”, but whatever, you get the idea!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Virus:&lt;/strong&gt; malware that is able to self-replicate and infect other users through USB sticks or removable media.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Worm:&lt;/strong&gt; similar to a virus but it infects other PCs through the network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trojan:&lt;/strong&gt; it shows up as useful software, but in reality it literally opens a door for an attacker to steal your sensitive data or take control of your PC. It really is a Trojan horse!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spyware:&lt;/strong&gt; spies on what you do on your PC and sells this information on the black market.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Adware:&lt;/strong&gt; fills your PC with unwanted advertising.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keylogger:&lt;/strong&gt; records the keys you press hoping you type some credentials or, even better, your credit card number.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backdoor:&lt;/strong&gt; if the attacker manages to install this stuff, they can use your PC to do several things on the network: for example send emails or connect your PC to a website to overload it and cause an outage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rootkit:&lt;/strong&gt; these are very hard to find; if you have one it’s as if the attacker had your PC in their house. They can simply do whatever they want remotely.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scareware:&lt;/strong&gt; these are malware that scare you, telling you that your PC has millions of problems and that you should pay them to fix everything. Too bad the real problem is the program itself pretending to help you. Most of the time people catch this type of malware.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cryptolocker:&lt;/strong&gt; it has been very popular recently. Basically, once started, it begins to encrypt all your documents and when it’s done it asks you for a ransom. If you want your documents back you have to pay!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Prevention above all!&lt;/h2&gt;
&lt;p&gt;Disclaimer: I don’t use &lt;strong&gt;antivirus&lt;/strong&gt;, in my opinion it’s possible to live without it too. The important thing is to be careful and know what you’re starting… Always! If instead you don’t feel safe, then it’s better to install some antivirus that can cover your distractions &lt;em&gt;in real time&lt;/em&gt;. Finally, if you already have malware on your PC then &lt;strong&gt;install it&lt;/strong&gt; immediately. I usually install &lt;a href=&quot;http://www.bitdefender.com/solutions/free.html&quot;&gt;Bitdefender&lt;/a&gt; on the PCs I fix. There are really very few options and it does its job.
Once installed, run a &lt;strong&gt;full scan of the PC&lt;/strong&gt; and hope it manages to solve your problem.&lt;/p&gt;
&lt;h2&gt;Uninstalling the malware&lt;/h2&gt;
&lt;p&gt;The antivirus does two things well: keeping &lt;em&gt;viruses&lt;/em&gt; away before they can do damage and removing them if they happen to already be inside your PC. The problem is that they are only very good at one category, &lt;em&gt;viruses&lt;/em&gt; precisely. But as you read a moment ago, there are a myriad of malware that don’t fall into this category.
If your malware is still there bothering you, you need something else… Maybe even just a little something else… Sometimes all it really takes is &lt;strong&gt;uninstalling the app&lt;/strong&gt; that’s bothering you without needing any special software.&lt;/p&gt;
&lt;p&gt;Doing this step is very simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read the name of the app that opens and bothers you.&lt;/li&gt;
&lt;li&gt;Go to &lt;em&gt;Control Panel&lt;/em&gt; &gt; &lt;em&gt;Programs and Features&lt;/em&gt; &gt; look for the app name and uninstall it.&lt;/li&gt;
&lt;li&gt;If it happens to tell you the app is in use, close it. If you can’t close it, open the &lt;em&gt;task manager&lt;/em&gt; by pressing &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;. Go to the processes tab and terminate the app in question.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These steps can vary significantly depending on the version of Windows you have.&lt;/p&gt;
&lt;h2&gt;Broad-spectrum antibiotics&lt;/h2&gt;
&lt;p&gt;I imagine that if you’re reading here it means your dear malware loves you very much and is still there on your PC making your day hell. Good! Now it’s time to use two pieces of software: &lt;strong&gt;&lt;a href=&quot;https://www.malwarebytes.com/&quot;&gt;Malwarebytes&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href=&quot;http://www.bleepingcomputer.com/download/adwcleaner/&quot;&gt;AdwCleaner&lt;/a&gt;&lt;/strong&gt;.
I call these two pieces of software &lt;em&gt;broad-spectrum antibiotics&lt;/em&gt; precisely because that’s what they do: they try to remove any malware and therefore manage to remove more junk than a normal antivirus.&lt;/p&gt;
&lt;p&gt;I recommend starting with Malwarebytes. &lt;a href=&quot;http://download.cnet.com/malwarebytes-anti-malware/windows.html?hlndr=1&amp;#x26;part=dl-x&amp;#x26;lang=en&quot;&gt;Download it&lt;/a&gt;, install it (you don’t need the premium version), update its database and finally run a full scan. All these steps should be simple so I won’t dwell on them too much.
&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;Once the scan is finished, it has probably found something; follow the steps and remove what it found. Finally it will ask you to restart the PC. Do it.&lt;/p&gt;
&lt;p&gt;Now it’s time for the second piece of software: &lt;strong&gt;AdwCleaner&lt;/strong&gt;.
Here too the steps are simple. &lt;a href=&quot;http://www.bleepingcomputer.com/download/adwcleaner/&quot;&gt;Download it&lt;/a&gt;, install it and finally start it.
&lt;img src=&quot;https://mattianataliblog.s3.amazonaws.com/2016/Aug/adwcleaner_001-1470564066850.jpg&quot; alt=&quot;AdwCleaner&quot;&gt;
The screen is very simple: first press &lt;em&gt;Scan&lt;/em&gt; to start the scan. Then, once it’s done, press &lt;em&gt;Clean&lt;/em&gt; to start the cleaning. Finally it will ask you to restart the PC. In this case too, do as it says.&lt;/p&gt;
&lt;h2&gt;A little experience never hurts&lt;/h2&gt;
&lt;p&gt;At this point I hope your problems are over. If instead your malware is still there then it’s time to &lt;strong&gt;call a technician&lt;/strong&gt; because the easy-to-use tools are finished and an expert hand is needed. All you can do is save what can be saved and pick up the phone to ask for help.&lt;/p&gt;
&lt;h2&gt;Last resort&lt;/h2&gt;
&lt;p&gt;Actually there is still one &lt;em&gt;small&lt;/em&gt; thing you can do on your own, even though it’s quite dangerous: you can &lt;strong&gt;attempt a full reset&lt;/strong&gt; of your PC.
Over the years resetting a PC has become a very simple process and in my opinion it’s a step that has become within everyone’s reach.&lt;/p&gt;
&lt;p&gt;The first thing you must do is &lt;strong&gt;save your data&lt;/strong&gt;, and by save I mean to an external hard drive, a removable drive such as a USB stick. In short, save it outside the PC to be sure you don’t do any damage.&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;Reset this PC - Windows 10&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you have Windows 10 the steps are simple: go to &lt;em&gt;Settings&lt;/em&gt; &gt; &lt;em&gt;Update &amp;#x26; Security&lt;/em&gt; &gt; &lt;em&gt;Reset this PC&lt;/em&gt; &gt; &lt;em&gt;Get started&lt;/em&gt; and you can choose between these options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep my files&lt;/strong&gt;: maybe try this option first. This way your data is safe, but Windows 10 will be reset and your applications will be deleted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restore factory settings&lt;/strong&gt;: this option is the most effective because it makes your PC like new.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remove everything&lt;/strong&gt;: choose this option if you can’t find the previous entry.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;I hope this guide helped you solve your little problem on your own… In the end there’s also a nice satisfaction in solving problems without anyone’s help, right :)?
See you next time!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Welcome!]]></title><description><![CDATA[Here I am, on the Eurocity heading to Switzerland, obviously stopped because of the works at the Monza station. For this very reason I…]]></description><link>https://www.mattianatali.it/en/welcome-2016/</link><guid isPermaLink="false">https://www.mattianatali.it/en/welcome-2016/</guid><pubDate>Wed, 03 Aug 2016 07:03:47 GMT</pubDate><content:encoded>&lt;p&gt;Here I am, on the Eurocity heading to Switzerland, obviously stopped because of the &lt;a href=&quot;http://www.trenord.it/it/media-news/avvisi/linea-chiasso-como-monza-milano.aspx&quot;&gt;works at the Monza station&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For this very reason I decided to spend the time I pass on trains writing this little blog of mine (and creating it too).&lt;/p&gt;
&lt;p&gt;I haven’t quite decided yet what or how much I’ll write. Probably many articles will be guides to solve the millions of problems I occasionally solve for those who “hire” me as a computer technician. Or something else, I really don’t know yet. For now I’ve had fun creating this little blog. Now only the content is missing! :)&lt;/p&gt;</content:encoded></item></channel></rss>