<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mihai Blebea</title>
    <description>The latest articles on DEV Community by Mihai Blebea (@mihaidev).</description>
    <link>https://dev.to/mihaidev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74496%2F11f00779-b25d-4eca-b7a3-55802bc20765.png</url>
      <title>DEV Community: Mihai Blebea</title>
      <link>https://dev.to/mihaidev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mihaidev"/>
    <language>en</language>
    <item>
      <title>How to build a football live scores notification app with Python?</title>
      <dc:creator>Mihai Blebea</dc:creator>
      <pubDate>Tue, 14 Dec 2021 18:32:09 +0000</pubDate>
      <link>https://dev.to/mihaidev/how-to-build-a-football-live-scores-notification-app-with-python-4750</link>
      <guid>https://dev.to/mihaidev/how-to-build-a-football-live-scores-notification-app-with-python-4750</guid>
      <description>&lt;p&gt;If you are like me, you must spend a lot of time coding...&lt;/p&gt;

&lt;p&gt;I would like to spend more time watching sports or going outside to play football. But we are developers and that keeps us busy during the weekends.&lt;/p&gt;

&lt;p&gt;But you don't have to choose one or the other. Now you can enjoy both of them.&lt;/p&gt;

&lt;p&gt;In this article, I will show you the steps necessary to build a real-time football score notification app.&lt;/p&gt;

&lt;p&gt;This will most likely work better on Linux OS, but you can easily adapt this for Windows or macOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the biggest problem we will have to overcome?
&lt;/h2&gt;

&lt;p&gt;To be completely honest with you, this is not my first stab at building this, but I always found myself stuck when I tried to get the real-time football scores.&lt;/p&gt;

&lt;p&gt;We have a couple of options to overcome this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;scrape the live scores from Google&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;follow a Twitter stream and get the scores in real-time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;use a &lt;a href="https://bit.ly/3DYWFbs"&gt;FREE API&lt;/a&gt; that provides us the scores without any fuss&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hmmm, hard decisions... but let's go with the last option as it's the most convenient and easy to implement.&lt;/p&gt;

&lt;p&gt;Why would we spend weeks trying to build a scraper? Or deal with the Google algorithm built to block us from scraping the results.&lt;/p&gt;

&lt;p&gt;To solve this issue, just use this FREE API that I found on RapidAPI called &lt;a href="https://bit.ly/3DYWFbs"&gt;Football Live Score&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All you need to do is just &lt;a href="https://bit.ly/3DYWFbs"&gt;create a FREE account&lt;/a&gt; and they will provide you with a token that you can use to access any API on their platform.&lt;/p&gt;

&lt;p&gt;The Football Live Score API provides three endpoints at the moment, but if you read this in the "future" you may see more as this is a well-supported community.&lt;/p&gt;

&lt;p&gt;They currently support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;GET &lt;code&gt;/matches&lt;/code&gt; which provides a list of matches for the day with live updates just keep in mind you will receive matches that are not in progress&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GET &lt;code&gt;/matches/updates&lt;/code&gt; contains the same games but they are filtered by latest updates. We are going to use this one as it provides only the matches that changed scores from the last query, so we don't need to handle that complexity or store the matches on our side&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GET &lt;code&gt;/leagues&lt;/code&gt; provides the matches for today but sorted by league&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The platform in itself is very good as it allows you to test the API right on their website before including it in your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bit.ly/3DYWFbs"&gt;Check it out here!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What programming language will we use?
&lt;/h2&gt;

&lt;p&gt;My first choice would be Golang, but recently I've spent a lot of time playing around with Python and... WOW... it just works.&lt;/p&gt;

&lt;p&gt;There are so many good libraries in Python that make it the best choice for a quick project like our football live scores notifier.&lt;/p&gt;

&lt;p&gt;We should start by checking your local Python version, so just run this command in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;--version&lt;/span&gt;

// Mine returns Python 3.10.0 and that is good &lt;span class="k"&gt;for &lt;/span&gt;now
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If your's have an older version, it would be better to update your Python to at least 3.9.0.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the project structure
&lt;/h2&gt;

&lt;p&gt;Let's start by creating our folder structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;|-- football_updates
    |-- execute.sh
    |-- src
        |-- poll.py
        |-- installer.py
        |-- notify.py
        |-- last_update.py
    |-- assets
        |-- alarm.wav
        |-- icon.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is all that we need for now.&lt;/p&gt;

&lt;p&gt;Let's get our hands dirty and start coding it.&lt;/p&gt;

&lt;p&gt;To make sure we have all our dependencies for our project and not pollute the global scope, we will need to create a virtual environment for our script.&lt;/p&gt;

&lt;p&gt;Navigate inside your main foot folder (in my case it's &lt;code&gt;/football_updates&lt;/code&gt;) and run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv virtualenv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a virtual env in a folder called &lt;code&gt;virtualenv&lt;/code&gt;. Of course, you can change this by providing a different last param to the command above.&lt;/p&gt;

&lt;p&gt;Now let's install our dependencies.&lt;/p&gt;

&lt;p&gt;We will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;crontab // for interacting with crontab and making our lives a bit easier when installing the script&lt;/li&gt;
&lt;li&gt;notifypy // for triggering linux notifications&lt;/li&gt;
&lt;li&gt;requests&lt;/li&gt;
&lt;li&gt;python-dotenv // for managing the envs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install all these just run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ./virtualenv/bin/activate &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./virtualenv/bin/pip3 &lt;span class="nb"&gt;install &lt;/span&gt;crontab notifypy requests python-dotenv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; deactivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool, now we should be all set to start building our script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the notifications script
&lt;/h2&gt;

&lt;p&gt;This will mostly work for Linux and the Gnome distribution but there are some other options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;send a notification on Telegram&lt;/li&gt;
&lt;li&gt;post an update on Twitter&lt;/li&gt;
&lt;li&gt;send an email or SMS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For simplicity, I will trigger the updates as a desktop notification.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;code&gt;/src&lt;/code&gt; folder and create a file called &lt;code&gt;notify.py&lt;/code&gt; that should look like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;./src/notify.py&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;notifypy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Notify&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt;

&lt;span class="c1"&gt;# Get the base path to our folder so we can trigger this from the crontab without path conflicts
&lt;/span&gt;&lt;span class="n"&gt;FOLDER_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Lock down the path to our static resources
&lt;/span&gt;&lt;span class="n"&gt;AUDIO_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;FOLDER_PATH&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/../assets/alarm.wav"&lt;/span&gt;
&lt;span class="n"&gt;ICON_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;FOLDER_PATH&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/../assets/icon.png"&lt;/span&gt;

&lt;span class="c1"&gt;# Main method for our script
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Football updates"&lt;/span&gt; &lt;span class="c1"&gt;# Change this to suit your needs
&lt;/span&gt;    &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;audio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AUDIO_FILE&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ICON_FILE&lt;/span&gt;
    &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Add this to be able to trigger this as an executable script. Mainly for testing
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"demo title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"demo body"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Oki, now it's time to test this.&lt;/p&gt;

&lt;p&gt;You can simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 ./src/notify.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you would get an error complaining that the notifypy module cannot be found in our dependencies. We were so close...&lt;/p&gt;

&lt;p&gt;But don't worry, this is expected.&lt;/p&gt;

&lt;p&gt;The issue is that we are trying to call our script using the default local python interpreter. But it doesn't know about our virtual environment dependencies and modules.&lt;/p&gt;

&lt;p&gt;To make this work, we need to use the interpreter from the virtual env.&lt;/p&gt;

&lt;p&gt;Let's create a simple &lt;code&gt;execute.sh&lt;/code&gt; script in our root folder that will allow us to call any script with the virtual env interpreter.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;./execute.sh&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PYTHONDONTWRITEBYTECODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="c"&gt;# Add this to not create a __pycache__ folder&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PWD&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c"&gt;# Add our path to the PYTHONPATH, you can skip this&lt;/span&gt;
&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="s2"&gt;"./virtualenv/bin/python3 src/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.py &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="p"&gt;@&lt;/span&gt;:2&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the path we are using to call our Python interpreter &lt;code&gt;./virtualenv/bin/python3&lt;/code&gt;. This is the one from the virtual env.&lt;/p&gt;

&lt;p&gt;Next, we pass our file and the rest of the terminal arguments but omit the name of the file.&lt;/p&gt;

&lt;p&gt;To test our notify script, we need to make our &lt;code&gt;execute.sh&lt;/code&gt; script executable by doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ./execute.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run this and get a demo notification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./execute.sh notify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did you get the notification? You should now see the popup.&lt;/p&gt;

&lt;p&gt;Don't forget to add the &lt;code&gt;./assets/alarm.wav&lt;/code&gt; and &lt;code&gt;./assets/icon.png&lt;/code&gt; to make it look and sound like a real notification.&lt;/p&gt;

&lt;p&gt;This step is completed, so let's move to the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Store the last request timestamp
&lt;/h2&gt;

&lt;p&gt;If we use the default endpoint &lt;code&gt;/matches&lt;/code&gt;, this will return all the live scores in real-time.&lt;/p&gt;

&lt;p&gt;But we won't know which one was updated from our last request. If you build a website where the live scores are displayed, this will not be an issue. &lt;/p&gt;

&lt;p&gt;But for this project, we just want to get the matches that changed between our requests.&lt;/p&gt;

&lt;p&gt;To do this, we will call &lt;code&gt;/matches/updates&lt;/code&gt; and will provide the &lt;code&gt;last_update&lt;/code&gt; query param that contains the timestamp of the last request.&lt;/p&gt;

&lt;p&gt;Navigate in the &lt;code&gt;src&lt;/code&gt; folder and create the &lt;code&gt;/last_update.py&lt;/code&gt; file:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;./src/last_update.py&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="n"&gt;FOLDER_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;FILE_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;FOLDER_PATH&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/../last_update.txt"&lt;/span&gt; &lt;span class="c1"&gt;# this is the path to the temp file
&lt;/span&gt;
&lt;span class="c1"&gt;# This stores the last update, if none is provided, it will just use the current timestamp
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store_last_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_update&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_update&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;last_update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_current_timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"w"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_update&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# This will return the last update as a string from the file
# If the file does not exist, it will just return the current timestamp
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_last_update&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;is_file&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;get_current_timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Just an utility function to return the current timestamp in the same format everytime
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_current_timestamp&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating the brains of the script
&lt;/h2&gt;

&lt;p&gt;It's time to get down to business and write the brains of our script.&lt;/p&gt;

&lt;p&gt;Just create a &lt;code&gt;./src/poll.py&lt;/code&gt; file and add this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;./src/poll.py&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;notify&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;trigger&lt;/span&gt; &lt;span class="c1"&gt;# Notice this is our module, not the notifypy
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dotenv&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dotenv_values&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;last_update&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_last_update&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;store_last_update&lt;/span&gt;

&lt;span class="c1"&gt;# Base url of our RapidAPI
&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://football-live-scores3.p.rapidapi.com"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="c1"&gt;# Get all the match updates from the API, loop over them and call the send_notification function on each
&lt;/span&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;send_notification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;match_generator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_matches&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="c1"&gt;# Add your RapidAPI key to the headers
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"x-rapidapi-host"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"football-live-scores3.p.rapidapi.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"x-rapidapi-key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;YOUR_RAPIDAPI_KEY&amp;gt;"&lt;/span&gt; &lt;span class="c1"&gt;# add your private token that you receive form RapidAPI
&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Get all the matches updates and deal with the status codes
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_matches&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;last_update_ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_last_update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/matches/updates?last_update=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;last_update_ts&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_headers&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_auth&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Made request to url &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;"last_update_timestamp"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# if the key is not in the response for some reason, just use the current timestamp
&lt;/span&gt;        &lt;span class="n"&gt;store_last_update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;store_last_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"last_update_timestamp"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;"data"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Write a simple generator that accepts the source as a callable function to retrieve the matches
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;match_generator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"home_team"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s"&gt;"away_team"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"teams"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s"&gt;"home_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="s"&gt;"away_score"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"score"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Call send_notifications with the match from the API and parse it to compose the notification
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_notification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;home_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"home_team"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;away_team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"away_team"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;home_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"home_score"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;away_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"away_score"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Found match update &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;home_team&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;home_score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;away_score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;away_team&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Update &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;home_team&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;away_team&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;home_team&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;home_score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;away_score&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;away_team&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Add this to be able to call the script from the crontab
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now test the above by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./execute.sh poll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may get none, one, or many notifications based on your current date and time. It all depends if there is any match in progress.&lt;/p&gt;

&lt;p&gt;It's also up to the players to score a goal in the same time that you are testing this. &lt;/p&gt;

&lt;p&gt;Not much you can do about this...&lt;/p&gt;

&lt;p&gt;Let's move to the next step and add the poll script to our crontab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make our script easier to install on your laptop
&lt;/h2&gt;

&lt;p&gt;To make our lives easier, let's encapsulate the logic of installing and removing the script in one single file.&lt;/p&gt;

&lt;p&gt;Just create a &lt;code&gt;./src/install.py&lt;/code&gt; and add this to it:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;./src/install.py&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;crontab&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CronTab&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;getpass&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pathlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;argparse&lt;/span&gt;

&lt;span class="c1"&gt;# Add a comment so you know what this does in the future. This will be added to the crontab entry
# Also it will allow us to find and remove the entry in the future.
&lt;/span&gt;&lt;span class="n"&gt;COMMENT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"will run the football updates scraper"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;iter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_comment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;COMMENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;COMMENT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;install&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Get the path to our root folder
&lt;/span&gt;    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# This is the command that we want to run ever 5 minutes to get updates from the API
&lt;/span&gt;    &lt;span class="c1"&gt;# You can alter this to get more frequent updates
&lt;/span&gt;    &lt;span class="c1"&gt;# Notice that we send the crontab logs to our root folder in the cron.log file
&lt;/span&gt;    &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/../virtualenv/bin/python3 &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/poll.py &amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/../cron.log 2&amp;gt;&amp;amp;1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;COMMENT&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;minute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;every&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;COMMENT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Use the argparse lib to easy pass a flag to our script
&lt;/span&gt;    &lt;span class="c1"&gt;# If we call the script without any arguments, it will create an entry in the crontab
&lt;/span&gt;    &lt;span class="c1"&gt;# if we call this will a -u flag, it will remove the entry from crontab
&lt;/span&gt;    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"installer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"%(prog)s [options]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"install the application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"-u"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"--uninstall"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;dest&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"uninstall"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"store_true"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"uninstall the application"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;cron&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CronTab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getuser&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="c1"&gt;# If the flag -u is passed to the script, it will uninstall the crontab entry
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uninstall&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cron&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are all set now. &lt;/p&gt;

&lt;p&gt;To install the football updates notifier, just call this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./execute.sh &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To easily remove it and stop the updates, just call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./execute.sh &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now all you need to do is wait for somebody to score a goal, and you will get a notification with the live score update.&lt;/p&gt;

&lt;p&gt;If you want more information or just read the docs for the &lt;a href="https://bit.ly/3DYWFbs"&gt;Football Live Scores API&lt;/a&gt; on RapidAPI just &lt;a href="https://bit.ly/3DYWFbs"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to see the full code, just download it from my Github repo: &lt;a href="https://github.com/MihaiBlebea/football_updates"&gt;MihaiBlebea/football_updates&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>rapidapi</category>
      <category>football</category>
    </item>
    <item>
      <title>Why SHOULD you use the Repository Pattern in your project? And how to do it, the easy way…</title>
      <dc:creator>Mihai Blebea</dc:creator>
      <pubDate>Sun, 02 Jun 2019 09:26:14 +0000</pubDate>
      <link>https://dev.to/mihaidev/why-should-you-use-the-repository-pattern-in-your-project-and-how-to-do-it-the-easy-way-12ij</link>
      <guid>https://dev.to/mihaidev/why-should-you-use-the-repository-pattern-in-your-project-and-how-to-do-it-the-easy-way-12ij</guid>
      <description>&lt;p&gt;The last thing you need is another pattern to worry about…&lt;/p&gt;

&lt;p&gt;Why can’t we just write code in a plain simple way?&lt;/p&gt;

&lt;p&gt;Well… if you ask me, patterns have a very important role in software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Patterns VS Simple code
&lt;/h2&gt;

&lt;p&gt;There is no such thing as plain simple code.&lt;/p&gt;

&lt;p&gt;Even if you don’t know any patterns, you still use one every time you write code. It’s called “spaghetti code pattern” 😊&lt;/p&gt;

&lt;p&gt;Yes, it might sound delicious after some long coding hours in the middle of the night, but believe me, it's a developer’s worst nightmare.&lt;/p&gt;

&lt;p&gt;Patterns are your best friend because they help you organize your code in a way that is clear to read, flexible to extends and easy to reason with.&lt;/p&gt;

&lt;p&gt;Patterns can make your life a lot easier and can improve the speed at which you can add more features to your project in the future.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;So what is the Base Repository pattern supposed to do?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How does it look like?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And what are his main benefits?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Base Repository pattern brings in a layer of abstraction implemented between your models (domain logic) and persistence layer (database).&lt;/p&gt;

&lt;p&gt;It helps you decouple the models from the persistence layer, so in the future, you can easily change the database tables without affecting the logic of your app.&lt;/p&gt;

&lt;p&gt;You can even change your whole database implementation, your models should still not care about that.&lt;/p&gt;

&lt;p&gt;Talking about some ungrateful domain models, right? 😊&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s look at some code, so you can grasp the concept better
&lt;/h2&gt;

&lt;p&gt;I will use Typescript for this, mostly because it brings strong types and interfaces to javascript. And also because I use it every day in my job. 😊&lt;/p&gt;

&lt;p&gt;If you don’t know much about Typescript, I suggest you read this first: Typescript is Javascript with superpowers&lt;/p&gt;

&lt;p&gt;Now, let’s take a look back, down the memory lane…&lt;/p&gt;

&lt;p&gt;This is how I used to persist models into the database:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { User } from './../models'

let user = new User('Bob', 'Smith', 29, 'front end developer')

user.persiste()

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And inside the User model:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { myslqConnection } from './mysql-connection'
export default class User
{
   private _firstName : string
   private _lastName : string
   private _age : number
   private _job : string
   constructor(
       firstName : string, 
       lastName : string, 
       age : number, 
       job : string
   ){
       this._firstName = firstName
       this._lastName  = lastName
       this._age       = age
       this._job       = job
   }
   persist()
   {
      // Somehow you need to pass in the configs for connecting to the database
      return myslqConnection.query(`
              INSERT INTO users 
              (first_name, last_name, age, job) 
              VALUES (?)`, [
          this.firstName, 
          this.lastName, 
          this.age, 
          this.job ])
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This doesn’t look right.&lt;/p&gt;

&lt;p&gt;Here are some reasons why this is an absolute disaster:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I was mixing the model as in business logic with the persistence layer. Obs: The User model should not know how it is persisted in the database because it doesn’t care about that. This ungrateful User models, they don’t care about anything… 😊&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I was implementing the connection to the database in the actual model, which is a bad thing if you ever want to change the credentials.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are a lot of other reasons why this implementation is bad, but I won’t bore you with the details…&lt;/p&gt;

&lt;p&gt;If you want to see how I fixed all these problems with the Repository Pattern, then check out the full article on Medium: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@mihaiblebea/why-should-you-use-the-repository-pattern-in-your-project-and-how-to-do-it-the-easy-way-2076e0889e2b"&gt;https://medium.com/@mihaiblebea/why-should-you-use-the-repository-pattern-in-your-project-and-how-to-do-it-the-easy-way-2076e0889e2b&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>patterns</category>
      <category>repositorypattern</category>
    </item>
    <item>
      <title>How to write code that will last 1000 years in just 3 steps? …or close to that</title>
      <dc:creator>Mihai Blebea</dc:creator>
      <pubDate>Fri, 31 May 2019 07:25:50 +0000</pubDate>
      <link>https://dev.to/mihaidev/how-to-write-code-that-will-last-1000-years-in-just-3-steps-or-close-to-that-472l</link>
      <guid>https://dev.to/mihaidev/how-to-write-code-that-will-last-1000-years-in-just-3-steps-or-close-to-that-472l</guid>
      <description>&lt;p&gt;Do you want your code to endure the test of time?&lt;/p&gt;

&lt;p&gt;Some of you may say: YES. But the reality is that code is a living, breathing organism…&lt;/p&gt;

&lt;h2&gt;
  
  
  The code should be:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Flexible enough so you can replace aging parts with never modules as technology evolves and…&lt;/li&gt;
&lt;li&gt;Scalable enough that you can add more features later down the road.
Then why do we want to write code that will last a thousand years?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exactly because of the 2 points above.&lt;/p&gt;

&lt;p&gt;We need to write code that we will understand later, that we can extend with endless features and that we can pass on to other developers to carry on when we are long gone… from the company (not dead).&lt;/p&gt;

&lt;p&gt;As a lead developer, I manage a highly motivated team composed of developers with different coding styles and every one of them wants to put a personal mark on the company’s product.&lt;/p&gt;

&lt;p&gt;That means that each developer will code in a particular way, some using Promises instead of Async/Await or tabs instead of spaces… not that I encourage you to do that.&lt;/p&gt;

&lt;p&gt;So because of that, I built a 3 step process to ensure that the code we are writing will be flexible and scalable enough to stand the test of time.&lt;/p&gt;

&lt;p&gt;I will explain the whole process here, so you can apply it in your own coding and become a better developer.&lt;/p&gt;

&lt;p&gt;Just stay with me for the next 3–5 minutes and you will master the art of writing quality code. Still, don’t forget to get off the tube if you get too focused on this article 😂😂😂.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1. Write code that a human will understand
&lt;/h2&gt;

&lt;p&gt;Code is made to be understood by computers… or is it?&lt;/p&gt;

&lt;p&gt;Tell me what this code does:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function parseData(result) {
  let items = result.data
  let response = items.forEach((obj)=&amp;gt; {
    return obj.filter((key)=&amp;gt; {
      return ['title', 'img'].includes(key)
    })
  })
  return response
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;How long did you take to figure it out?&lt;/p&gt;

&lt;p&gt;Now multiply that with 30 different functions in a single file that makes no sense for any other developer who didn’t write this…&lt;/p&gt;

&lt;p&gt;It can make any small task take 10x times longer, for no actual reason at all.&lt;/p&gt;

&lt;p&gt;How about this next one?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function extractTitleImgFromPosts(blogPosts)
{
  return blogPosts.forEach((post)=&amp;gt; {
    return post.filter((part)=&amp;gt; {
      return ['title', 'img'].includes(part)
    })
  })
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Oki, maybe I didn’t take the best example possible, but I think you get my point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion:
&lt;/h3&gt;

&lt;p&gt;Write code that you can understand later, so you can make even the most complicated tasks in the future seem like a walk in the park.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to implement this step?
&lt;/h3&gt;

&lt;p&gt;First, write the code keeping in mind that you must understand what you wrote when you will be asked to debug it.&lt;/p&gt;

&lt;p&gt;Use clear names for variables and functions. Do not use “item”, “part”, “key” or any letter to represent variables. Keep in mind that some functions need to be generic enough to be used in other contexts so don’t overdo it.&lt;/p&gt;

&lt;p&gt;Then, create the PR and ask the guy who is reviewing your code to explain it to you in plain English… or whatever language you are using there 😂😂😂.&lt;/p&gt;

&lt;p&gt;If he takes a long time to do it, asks for your help or tries to pass the review to another team member, then you need to refactor your code to make it last in the future.&lt;/p&gt;

&lt;p&gt;But this will take more time, right? Yes, could be the case, but think about how much time and unslept nights you will save in the future.&lt;/p&gt;

&lt;p&gt;If you want to find out more and master this step, I recommend you google D.D.D’s “Ubiquitous language”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Want to read the full article?
&lt;/h2&gt;

&lt;p&gt;Just jump to my Medium account and see the other 2 steps that will improve your code.&lt;/p&gt;

&lt;p&gt;Click here: &lt;a href="https://medium.com/@mihaiblebea/how-to-write-code-that-will-last-1000-years-in-just-3-steps-or-close-to-that-866a6218f0b6"&gt;How to write code that will last 1000 years in just 3 steps?&lt;/a&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>node</category>
      <category>developers</category>
    </item>
    <item>
      <title>How much time would you give to the javascript frameworks?</title>
      <dc:creator>Mihai Blebea</dc:creator>
      <pubDate>Tue, 08 Jan 2019 23:46:30 +0000</pubDate>
      <link>https://dev.to/mihaidev/how-much-time-would-you-give-to-the-havascript-frameworks-403o</link>
      <guid>https://dev.to/mihaidev/how-much-time-would-you-give-to-the-havascript-frameworks-403o</guid>
      <description>&lt;p&gt;How much time do you think it will take for the native web components to take the place of the big 3 javascript frameworks? From an arhitecture point of view I think javascript frameworks are a bad decision. Commiting to a framework means that your app becomes dependent on that framework, when it should really be the other way around. What do you think?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://link.medium.com/BeOVAIp3jT"&gt;https://link.medium.com/BeOVAIp3jT&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>vue</category>
      <category>angular</category>
      <category>webcomponents</category>
    </item>
  </channel>
</rss>
