<?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: Kalob Taulien</title>
    <description>The latest articles on DEV Community by Kalob Taulien (@kalobtaulien).</description>
    <link>https://dev.to/kalobtaulien</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%2F241219%2F2486d11a-32cb-433d-9640-6370db1c134d.png</url>
      <title>DEV Community: Kalob Taulien</title>
      <link>https://dev.to/kalobtaulien</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kalobtaulien"/>
    <language>en</language>
    <item>
      <title>Deploying a Wagtail 2.16 website to Heroku</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Tue, 08 Feb 2022 19:52:47 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/deploying-a-wagtail-216-website-to-heroku-1iki</link>
      <guid>https://dev.to/kalobtaulien/deploying-a-wagtail-216-website-to-heroku-1iki</guid>
      <description>&lt;p&gt;Deploying Python websites is hard. I don't care what anybody says, it's always been the hardest part about Python development in my opinion. &lt;/p&gt;

&lt;p&gt;So today I'm going to show you how to deploy your Wagtail website to Heroku fairly easily &lt;strong&gt;and for free&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We will be launching a website using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wagtail 2.16 &lt;/li&gt;
&lt;li&gt;Python 3.10 &lt;/li&gt;
&lt;li&gt;Django 4.0 &lt;/li&gt;
&lt;li&gt;Heroku&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;By the end of this tutorial you will have deployed your Wagtail CMS website to the web.&lt;/strong&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Quickly creating a new Wagtail website on your computer
&lt;/h2&gt;

&lt;p&gt;Ultra fast steps to creating a Wagtail 2.16 website on your computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;wagtail
wagtail start your_app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give you most of the file you need. If you already have a Wagtail project then please ignore the above code snippet 😎&lt;/p&gt;

&lt;h2&gt;
  
  
  New project files
&lt;/h2&gt;

&lt;p&gt;You will need a couple files for Heroku to read. The first one is the &lt;code&gt;runtime.txt&lt;/code&gt; file which tells Heroku which version of Python to use. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;runtime.txt&lt;/strong&gt; 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python-3.10.2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking for other Python versions? &lt;a href="https://devcenter.heroku.com/articles/python-support#specifying-a-python-version"&gt;Check them out here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we need a Procfile. This is going to tell Heroku's dynos how to run your website. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Procfile&lt;/strong&gt; 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;web: gunicorn your_app.wsgi --log-file -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;your_app.wsgi&lt;/code&gt; is mapping to the &lt;code&gt;your_app/&lt;/code&gt; folder and the &lt;code&gt;wsgi.py&lt;/code&gt; file. If your project is called &lt;code&gt;my_awesome_app&lt;/code&gt;, then change:&lt;br&gt;
&lt;code&gt;your_app.wsgi&lt;/code&gt; 👉 &lt;code&gt;my_awesome_app.wsgi&lt;/code&gt; &lt;/p&gt;
&lt;h2&gt;
  
  
  Updating your dependencies
&lt;/h2&gt;

&lt;p&gt;We need a few new dependencies for this to work. Open up your &lt;code&gt;requirements.txt&lt;/code&gt; file and add these three packages:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;requirements.txt&lt;/strong&gt; 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-toolbelt
psycopg2
whitenoise
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update Wagtail setting files
&lt;/h2&gt;

&lt;h3&gt;
  
  
  base.py
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;base.py&lt;/code&gt; settings, add the whitenoise middleware below your security middleware, like so:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;base.py&lt;/strong&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="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="s"&gt;'django.middleware.security.SecurityMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'whitenoise.middleware.WhiteNoiseMiddleware'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: You could overwrite your &lt;code&gt;production.py&lt;/code&gt; settings instead of using whitenoise in in &lt;code&gt;base.py&lt;/code&gt; - any settings that go into &lt;code&gt;base.py&lt;/code&gt; are also used in local development, and that's not always what you want to do.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  production.py
&lt;/h3&gt;

&lt;p&gt;By default your &lt;code&gt;production.py&lt;/code&gt; file is relatively empty. That's because Wagtail doesn't know what tools you'll be using in production, so it makes no assumptions. &lt;/p&gt;

&lt;p&gt;We can make some assumptions now that we know we're deploying to Heroku. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;production.py&lt;/strong&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;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;absolute_import&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;unicode_literals&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.base&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dj_database_url&lt;/span&gt;

&lt;span class="n"&gt;DEBUG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

&lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# It's a GOOD idea to lock this down. 
&lt;/span&gt;&lt;span class="n"&gt;ALLOWED_HOSTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&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;DATABASES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'default'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;dj_database_url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Honor the 'X-Forwarded-Proto' header for request.is_secure()
&lt;/span&gt;&lt;span class="n"&gt;SECURE_PROXY_SSL_HEADER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'HTTP_X_FORWARDED_PROTO'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'https'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'SECRET_KEY'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;STATICFILES_STORAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'whitenoise.storage.CompressedManifestStaticFilesStorage'&lt;/span&gt;

&lt;span class="n"&gt;COMPRESS_OFFLINE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;COMPRESS_CSS_FILTERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;'compressor.filters.css_default.CssAbsoluteFilter'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'compressor.filters.cssmin.CSSMinFilter'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;COMPRESS_CSS_HASHING_METHOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'content'&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.local&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Working with Heroku
&lt;/h2&gt;

&lt;p&gt;You'll need the &lt;a href="https://devcenter.heroku.com/articles/heroku-cli"&gt;Heroku CLI tool&lt;/a&gt;. Once you've downloaded and installed the Heroku CLI, open your command line tool and write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;heroku login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login to your Heroku account and you'll be ready to start creating new Heroku apps. &lt;/p&gt;

&lt;p&gt;Next, you'll need Git. If you don't have Git, make sure you download and install it. Git is the version control system we'll be using to tell Heroku we have new code for our future website. Continue once you have Git installed. &lt;/p&gt;

&lt;p&gt;If you are not using git for your project already, initialize a new local repo with (ignore if you are already using git):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"First commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will create a new local repository, add all your files, and create a commit message. &lt;/p&gt;

&lt;p&gt;Then create a new Heroku app and connect it to your new git repo with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;heroku create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then push your committed codebase to Heroku with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push heroku master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now at this point your Wagtail site is in the cloud, but it needs a couple things for the rest of this to work. And this is absolutely vital. &lt;/p&gt;

&lt;p&gt;In Heroku, open your app settings and reveal you config vars. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6W5HISab--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u4ylwa62abvly3a77kaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6W5HISab--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u4ylwa62abvly3a77kaz.png" alt="Reveal config vars" width="880" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then add your Django settings module and secret key. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3y6QwJaK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qylxw6feuowd79i90agu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3y6QwJaK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qylxw6feuowd79i90agu.png" alt="Django settings module" width="880" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DJANGO_SETTINGS_MODULE&lt;/code&gt; should point to your production settings. In the image above you see &lt;code&gt;testapp.settings.production&lt;/code&gt;. That would map to &lt;code&gt;testapp/settings/production.py&lt;/code&gt; - your path will certainly be different from mine. &lt;/p&gt;

&lt;p&gt;Also you can &lt;a href="https://miniwebtool.com/django-secret-key-generator/"&gt;click here to generate a secret key&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I usually restart all my dynos after this just to make sure these environment variables become available to the website.   &lt;/p&gt;

&lt;p&gt;Lastly, you can run each of these commands one by one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;heroku plugins:install heroku-config
heroku config:push
heroku run python manage.py migrate
heroku run python manage.py createcachetable
heroku run python manage.py createsuperuser
heroku ps:scale &lt;span class="nv"&gt;web&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your website is available on the internet! &lt;a href="https://salty-refuge-90377.herokuapp.com/"&gt;Here's the example website I deployed.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anytime you need to deploy new changes, all you need to do is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add yourfile.ext 
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Some new commit message"&lt;/span&gt;
git push heroku master 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Media is not included
&lt;/h2&gt;

&lt;p&gt;Media (files uploaded by the users through the Wagtail admin) are not supported in this tutorial. Heroku doesn't come with file storage and it's best to use something like AWS S3 for that purpose. All your static assets will be served using whitenoise, but your uploaded files won't work - here's a blog post on &lt;a href="https://wagtail.org/blog/amazon-s3-for-media-files/"&gt;getting started with S3 on Heroku with Wagtail&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Did you find this helpful?
&lt;/h2&gt;

&lt;p&gt;If you found this article helpful please let me know on Twitter &lt;a href="https://twitter.com/KalobTaulien"&gt;@KalobTaulien&lt;/a&gt; - I'm always interested in hearing from the Wagtail community. &lt;/p&gt;

</description>
      <category>wagtail</category>
      <category>heroku</category>
      <category>devops</category>
    </item>
    <item>
      <title>Top 5 websites to learn just about anything</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Mon, 17 Jan 2022 19:03:07 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/top-5-websites-to-learn-just-about-anything-584a</link>
      <guid>https://dev.to/kalobtaulien/top-5-websites-to-learn-just-about-anything-584a</guid>
      <description>&lt;h1&gt;
  
  
  Top 5 websites to learn just about anything
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Learning shouldn't stop after high school or college.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whether you're looking to change careers or just learn something new to fight your boredom, there are a lot of great online platforms that can help you learn new and exciting subjects.&lt;/p&gt;

&lt;p&gt;In this article I'm listing the top 5 learning websites and have broken them down into categories.&lt;/p&gt;

&lt;p&gt;Best Selection: Udemy&lt;br&gt;
Best Price: Arbington&lt;br&gt;
Best Celebrity: Masterclass&lt;br&gt;
Best University Courses: Coursera&lt;br&gt;
Best Short Creatives: Skillshare&lt;/p&gt;




&lt;h2&gt;
  
  
  Udemy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.udemy.com/"&gt;https://www.udemy.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Udemy is a super popular learning website that says they have over 150,000 courses to choose from. That's why they've earned the "best selection" title in this article.&lt;br&gt;
Now, I did an audit, and found that over 50,000 classes don't even have one student. So take that 150k with a grain of salt.&lt;/p&gt;

&lt;p&gt;But you'll still find tonnes of high end teachers and courses, ranging from Angela Yu to Colte Steele and Kalob Taulien (that's me!).&lt;/p&gt;

&lt;p&gt;Classes range in price from $20-$200, but frankly not a single person on the web has bought a course from Udemy for $200 in the last 5 years. Don't be fooled by the higher prices, this is just a marketing tactic to make you feel like you're getting a better deal - it's called price anchoring, and it makes Udemy feel like Groupon.&lt;/p&gt;

&lt;p&gt;Udemy will discount their courses down to $10-$15 every couple of weeks so just wait for that deal or lookup coupon codes by Googling "Udemy Coupon"&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can learn just about anything on Udemy&lt;/li&gt;
&lt;li&gt;It's quite affordable if you just take a handful of courses&lt;/li&gt;
&lt;li&gt;30 day money back guarantee on every class&lt;/li&gt;
&lt;li&gt;Certificates included&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Must buy individual classes and their pricing seems like a scheme&lt;/li&gt;
&lt;li&gt;Incredibly toxic for the teachers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Arbington
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://arbington.com/"&gt;https://arbington.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Arbington.com is a new learning platform that has nearly 2,000 classes for a great price (if you subscribe).&lt;br&gt;
They have hundreds of courses ranging from coding and design to watercolor painting, business growth and much more.&lt;/p&gt;

&lt;p&gt;The quality from what I could see was mostly great, too, we were pleased to see they have a standard for quality.&lt;/p&gt;

&lt;p&gt;By the looks of it plenty of top teachers from other platforms that I recognized have started moving over to Arbington. So that's a good sign.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Are you interested in learning how to code?&lt;/strong&gt; Arbington.com is the best place for this. $15/month gives you access to over 200 web development courses. If this were Udemy, that would cost over $2,000.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Classes are all priced at $19.97 so you always know what you're going to be paying for, which is a tad higher than Udemy's discounted prices. But there's also a subscription plan for $15/month that gets you access to every course.&lt;br&gt;
Overall, Arbington earned the best price award in this article for having the best price with the best quality and selection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;They include a subscription for $15/month to access over 1700 classes with a 14 day free trial&lt;/li&gt;
&lt;li&gt;Classes can be individually purchased with a 30 day money back guarantee&lt;/li&gt;
&lt;li&gt;It's very affordable&lt;/li&gt;
&lt;li&gt;Certificates included&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You can subscribe OR buy individual classes which feels a bit confusing at first&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Skillshare
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.skillshare.com/"&gt;https://www.skillshare.com/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Skillshare has the best short creative classes. If you're looking for a tonne of painting, drawing or doodling classes this is the platform for you.&lt;/p&gt;

&lt;p&gt;They say they have over 27,000 classes however a quick audit showed us that's not the real number, it's closer to 19,000. But still, that's A LOT of content and that's why they've earned the Best Short Creative award in this article. They are well known for their super short courses (as short as 10 minutes) so you can power through a dozen classes in a single day if you wanted to.&lt;/p&gt;

&lt;p&gt;They are completely subscription based so you can watch as many classes as you want.&lt;/p&gt;

&lt;p&gt;The quality is pretty good too! Makes sense since artistic people love creating high quality content.&lt;/p&gt;

&lt;p&gt;However they seem to promote their famous teachers more and more, making them feel more like MasterClass and less like a supportive community of creatives. And they have hundreds of "staff picks" which tells us they favor certain teachers and rank others lower, which feels a bit unfair in a marketplace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Huge selection of courses&lt;/li&gt;
&lt;li&gt;Affordable&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pricing seems to change based on the country you're in&lt;/li&gt;
&lt;li&gt;They'll randomly delete thousands of courses which could include a class that you enrolled in and are enjoying&lt;/li&gt;
&lt;li&gt;Support is non-existent&lt;/li&gt;
&lt;li&gt;No certificates&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Coursera
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.coursera.org/"&gt;https://www.coursera.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are looking for university classes to take online, Coursera is the place for you! It's a bit pricier than other learning websites, but you're also getting top-notch education from university teachers.&lt;/p&gt;

&lt;p&gt;There's A LOT to learn, and the classes are all amazing. I've taken a number of classes from Coursera and was never unhappy about it. And was even happy to buy the certificate at the end.&lt;/p&gt;

&lt;p&gt;If you're looking for university credits, however, check out Outlier.org - I haven't tried Outlier but they look truly amazing.&lt;/p&gt;

&lt;p&gt;Most courses come in the form of a cohort, so you start and end on certain dates (not self-paced). Usually that's a good thing, but the courses I've taken never felt like there was a real community or cohort - just deadlines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Highest quality education on the internet.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Less affordable but it's a fair tradeoff for the quality of content you're buying&lt;/li&gt;
&lt;li&gt;If you want a certificate you must pay for it&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  MasterClass
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.masterclass.com/"&gt;https://www.masterclass.com/&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;MasterClass is in a category of its own. I call it "edutainment" - short for education/entertainment.&lt;/p&gt;

&lt;p&gt;You'll be learning from famous people. From cooking to guitar playing and film making. You can even learn from Bill Clinton now!&lt;/p&gt;

&lt;p&gt;The videos you'll be watching are expertly crafted as if HBO were producing them.&lt;/p&gt;

&lt;p&gt;What's cool is you get to spend time with someone who is famous, and possibly someone you look up to.&lt;/p&gt;

&lt;p&gt;Starting at $20/month (and going as high as $30/month) you get access to quite a few classes. It's not thousands of classes, but you'll still be impressed with their selection and the instructors you get to work with.&lt;/p&gt;

&lt;p&gt;Classes are short, though, being roughly 4 hours long. If you're learning something hard, like guitar from Tom Morello, 4 hours won't feel like enough.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Learn from people who actually DO it and have made it&lt;/li&gt;
&lt;li&gt;Affordable&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Cons:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The classes are shorter than expected&lt;/li&gt;
&lt;li&gt;No certificates&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Depending on what you're looking for, there's a type of learning website for you.&lt;/p&gt;

&lt;p&gt;If you're looking to get the best bang for your buck, &lt;a href="https://arbington.com/"&gt;Arbington.com&lt;/a&gt; is the way to go. If you want ultra high quality education then &lt;a href="https://www.coursera.org/"&gt;Coursera&lt;/a&gt; is definitely the best route. And if you want a hybrid of education and entertainment, &lt;a href="https://www.masterclass.com/"&gt;MasterClass&lt;/a&gt; is probably what you're looking for.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to create a PyPi (Python) package</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Thu, 06 Jan 2022 21:04:03 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/how-to-create-a-pypi-python-package-3g52</link>
      <guid>https://dev.to/kalobtaulien/how-to-create-a-pypi-python-package-3g52</guid>
      <description>&lt;p&gt;Have you ever wanted to create a Python package so you can type the following?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;my-awesome-package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If so, this tutorial is for you. &lt;/p&gt;

&lt;h2&gt;
  
  
  1. Getting Poetry
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://python-poetry.org/"&gt;Poetry&lt;/a&gt; is a system package you can use to &lt;strong&gt;very easily&lt;/strong&gt; manage your Python Packages. &lt;/p&gt;

&lt;p&gt;It makes handling your packages super easy. I have 9 Python packages under my name, and this is by far the best solution. &lt;/p&gt;

&lt;p&gt;First, you need to install Poetry on your system. &lt;/p&gt;

&lt;h3&gt;
  
  
  osx / linux / bashonwindows install instructions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  windows powershell install instructions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;(&lt;/span&gt;Invoke-WebRequest &lt;span class="nt"&gt;-Uri&lt;/span&gt; https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py &lt;span class="nt"&gt;-UseBasicParsing&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.Content | python -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://python-poetry.org/docs/#installation"&gt;More details about installation here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you can type &lt;code&gt;poetry --version&lt;/code&gt; to see the version you're running. If this doesn't work for you, try closing and re-opening your terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Creating a Poetry project
&lt;/h2&gt;

&lt;p&gt;In this tutorial we're going to create a new package from scratch. &lt;/p&gt;

&lt;p&gt;Go ahead and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry new test-package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the docs mention, it'll create a new folder with a bunch of files for you that are structured like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test-package
├── pyproject.toml
├── README.rst
├── test_package
│   └── __init__.py
└── tests
    ├── __init__.py
    └── test_test_package.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Adding your code
&lt;/h2&gt;

&lt;p&gt;Create a new file in &lt;code&gt;test-package/test_package/&lt;/code&gt; called &lt;code&gt;myfile.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Your file structure should look like this now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;test-package
├── pyproject.toml
├── README.rst
├── test_package
│   ├── __init__.py
│   └── myfile.py  # &amp;lt;- This is new
└── tests
    ├── __init__.py
    └── test_test_package.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of your code will go in the &lt;code&gt;test_package/&lt;/code&gt; folder. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This folder name will be different if you used a different package name during step 2.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can add any files you want in this folder. This is what get's bundled in your package.&lt;/p&gt;

&lt;p&gt;Now in your &lt;code&gt;myfile.py&lt;/code&gt; file, add this function:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;custom_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;print&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;"Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later we can use this code like so:&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;test_package.myfile&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;custom_function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;👆 We'll get to that later, first we need to build the package. &lt;/p&gt;

&lt;h2&gt;
  
  
  4. Building your package
&lt;/h2&gt;

&lt;p&gt;So far we just have a bunch of code sitting on our computer and if someone else wants to use our code, they need to copy all the files and folders. &lt;/p&gt;

&lt;p&gt;Let's "build" the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will take all your code, bundle it, and put it in a versioned file inside of a &lt;code&gt;/dist/&lt;/code&gt; folder. The file should look something like this: &lt;code&gt;test-package-0.1.0.tar.gz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It will also create a wheel file for you that looks something like this: &lt;code&gt;test_package-0.1.0-py3-none-any.whl&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Testing your code in other virtual environments
&lt;/h2&gt;

&lt;p&gt;Now what I like to do is test my package in a brand new virtual environment. &lt;/p&gt;

&lt;p&gt;Create a new virtual env in a new folder somewhere else on your computer.&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;mkdir &lt;/span&gt;testenv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;testenv 
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv/ 
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: Your virtual env will be created differently if you're on Windows. You can use virtualenv, pipenv, Docker, etc. It just needs to be a fresh environment. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that you're in a new Python environment, copy that .tar.gz from from earlier into this folder. (I usually use the operating systems OS for this, but there's nothing wrong with using &lt;code&gt;cp&lt;/code&gt; to copy the file). The only file in this virtual environment should be your .tar.gz file. &lt;/p&gt;

&lt;p&gt;Now install this file with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;test-package-0.1.0.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming everything went well, let's test this out. &lt;/p&gt;

&lt;p&gt;Open a new Python shell (REPL) with:&lt;br&gt;
&lt;code&gt;python&lt;/code&gt; (on non-Windows) or &lt;code&gt;py&lt;/code&gt; on Windows. And type this out:&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;test_package.myfile&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;custom_function&lt;/span&gt;

&lt;span class="n"&gt;custom_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Kalob"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should print out &lt;code&gt;Hello Kalob!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And just like that, you have create a bundled package. But it's not available for everybody just yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Push it to GitHub
&lt;/h2&gt;

&lt;p&gt;At this stage I like to push my code up to GitHub. &lt;/p&gt;

&lt;p&gt;Because we're making a public package, I tend to make my repo's public as well. No use hiding the source code when it will be easily downloaded from PyPi.org anyway. &lt;/p&gt;

&lt;p&gt;Dont forget to add &lt;code&gt;/dist/&lt;/code&gt; and other files to your .gitignore file. The &lt;code&gt;/dist/&lt;/code&gt; folder is where your bundled code goes when it's built by Poetry. &lt;/p&gt;

&lt;h2&gt;
  
  
  7. Publish the package
&lt;/h2&gt;

&lt;p&gt;Now let's publish this code on PyPi.org. &lt;/p&gt;

&lt;p&gt;First, you need a free &lt;a href="https://pypi.org/"&gt;PyPi.org&lt;/a&gt; account.  You'll need your username and password handy because Poetry will ask for it so it can upload your file to PyPi and associate it with your account. &lt;/p&gt;

&lt;p&gt;Once you have a free PyPi account, go ahead and run this in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will ask for your username and password. Go ahead and type those in. &lt;/p&gt;

&lt;p&gt;And now your package will be on PyPi.org. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: If the package of &lt;code&gt;test-package&lt;/code&gt; already exists, or at one point existed, on PyPi.org you &lt;em&gt;cannot&lt;/em&gt; use the same name. Making your Python packages have unique names is the best way to avoid this problem. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you didn't run into a naming problem, you'll have successfully published a package to PyPi.org! &lt;/p&gt;

&lt;p&gt;Congrats!&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Install your package using pip
&lt;/h2&gt;

&lt;p&gt;Assuming your package is now on PyPi, let's install your package in another project and test it out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;test-package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything should work as expected now. And your code is now easily accessible to every Python developer. 🎉 &lt;/p&gt;

&lt;h2&gt;
  
  
  Example repo
&lt;/h2&gt;

&lt;p&gt;If you'd like to see a simple package I recently created for &lt;a href="https://arbington.com"&gt;Arbington.com&lt;/a&gt; take a look at &lt;a href="https://github.com/arbington/python-vimeo"&gt;python-vimeo on GitHub&lt;/a&gt; and feel free to use any part of that repo. That's why we open sourced it! :) &lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>What type of developer would a startup hire? </title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Tue, 04 Jan 2022 16:39:53 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/what-type-of-developer-would-a-startup-hire-3bbp</link>
      <guid>https://dev.to/kalobtaulien/what-type-of-developer-would-a-startup-hire-3bbp</guid>
      <description>&lt;p&gt;"The world has a shortage of developers."&lt;/p&gt;

&lt;p&gt;You might have heard this before. It's fairly common for people to say this. &lt;/p&gt;

&lt;p&gt;It's kind of true, but not really... &lt;/p&gt;

&lt;p&gt;Here's the truth. &lt;/p&gt;

&lt;p&gt;"The world has a shortage of &lt;strong&gt;[senior]&lt;/strong&gt; developers." &lt;/p&gt;

&lt;p&gt;Because companies don't like hiring junior or intermediate developers because they cost more to get up to speed. &lt;/p&gt;

&lt;p&gt;And the average developer only stays at a job for 2 years.&lt;/p&gt;

&lt;p&gt;But also... senior developers are &lt;em&gt;expensive&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;At &lt;a href="https://arbington.com/"&gt;Arbington.com&lt;/a&gt; we would love to hire a senior developer, but it'd also cost us like $120,000-$150,000 for the best possible candidate. &lt;/p&gt;

&lt;p&gt;And that's not an option at a lot of startups. &lt;/p&gt;

&lt;p&gt;So they hire intermediate developers, if possible. And if that's not an option, then they hire juniors. &lt;/p&gt;

&lt;p&gt;And they'll label the junior job as an "internship". &lt;/p&gt;

&lt;p&gt;Don't be fooled, interns &lt;strong&gt;need&lt;/strong&gt; to make money too. I would never EVER advise anybody to work for free. But minimum wage if it's your first job? Possibly. &lt;/p&gt;

&lt;p&gt;So this begs the question...&lt;/p&gt;

&lt;h2&gt;
  
  
  What are startups looking for in a developer?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Skills&lt;/strong&gt;, of course. Can you code? Great! Are you the worlds best coder? It doesn't matter if you are or if you aren't. &lt;/p&gt;

&lt;p&gt;Not sure what stack they use? Just ask! Tech stacks aren't secrets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;But fullstack is key&lt;/strong&gt; because a full stack developer is basically a backend dev &lt;em&gt;and&lt;/em&gt; a frontend dev at the same time. They aren't usually AMAZING at either, but are super flexible and dangerous with what they're given.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leadership&lt;/strong&gt; attributes. When joining a startup, you're not just a developer - you're a core part of the team! You help develop the future culture of the company, even if you are employee #20. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adaptability&lt;/strong&gt;. Startups move FAST. You need to be able to adjust. If your dream is to work for the government, a startup is absolutely &lt;em&gt;not&lt;/em&gt; for you. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flexible pay&lt;/strong&gt;. Startups are cash-poor, usually. Unless they just raised a few million dollars you're likely looking at a lower pay rate. But you can get &lt;strong&gt;stock options&lt;/strong&gt; - so if you're really in love with what they do as a business, and you think it's going somewhere, stock options are a great way to support the company and get paid at the same time. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A curious personality&lt;/strong&gt; is also vital. Be curious about how to help the startup. Be curious about how to level up your code. Be curious about life in general! Because your curiosity is going to help develop the company culture, and drive you to become an insanely amazing developer. &lt;/p&gt;

&lt;h2&gt;
  
  
  Do you need to be the best? No!
&lt;/h2&gt;

&lt;p&gt;But you do need to have a lot of the soft skills and desire to become better at the technical portions. &lt;/p&gt;

&lt;h2&gt;
  
  
  How do you get in?
&lt;/h2&gt;

&lt;p&gt;I've mentioned this before in a &lt;a href="https://twitter.com/KalobTaulien/status/1465785129826078721"&gt;Twitter thread I wrote&lt;/a&gt;, but I'll say it again: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Resumes are dead. Friends hire friends. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Get to know the founders. Email them, support them, offer them help.. earn your way into their circles. &lt;/p&gt;

&lt;p&gt;Actually, this is just good advice for any job. &lt;/p&gt;

&lt;p&gt;But once they get to know you a little bit they'll be more likely to hire you. &lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Because you aren't seen as a "risk" anymore, but rather you'll be seen as a friend to the company - and a GREAT candidate to hire. &lt;/p&gt;

&lt;p&gt;-&lt;/p&gt;

&lt;p&gt;I hope this was helpful! &lt;/p&gt;

&lt;p&gt;If you found any value in this article I would love if you could share it or follow me here on Dev.to. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to create a Flask app in Python</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Fri, 31 Dec 2021 21:32:04 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/how-to-create-a-flask-app-in-python-3h2d</link>
      <guid>https://dev.to/kalobtaulien/how-to-create-a-flask-app-in-python-3h2d</guid>
      <description>&lt;p&gt;Let's create a &lt;a href="https://flask.palletsprojects.com/en/2.0.x/" rel="noopener noreferrer"&gt;Flask app&lt;/a&gt; from scratch, using Python 3.9 or newer. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: We are not deploying the app, we're just getting started. If you want to deploy a Flask app to Heroku, &lt;a href="https://dev.to/techparida/how-to-deploy-a-flask-app-on-heroku-heb"&gt;check out this article.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll also get started with a basic templating system. Nothing drastic, but something to add custom information to your templates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a virtual environment
&lt;/h2&gt;

&lt;p&gt;There are LOTS of ways to do this, but the simplest way is to use a &lt;code&gt;venv&lt;/code&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="nb"&gt;mkdir &lt;/span&gt;yourproject
&lt;span class="nb"&gt;cd &lt;/span&gt;yourproject/
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv/ 
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Install Flask
&lt;/h2&gt;

&lt;p&gt;Once you are inside your virtual env (the last line from the code above will get you "inside" your venv), 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;pip &lt;span class="nb"&gt;install &lt;/span&gt;flask
pip freeze &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will install Flask in your virtual environment, and create a requirements.txt file for other people to use when installing your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Your main file
&lt;/h2&gt;

&lt;p&gt;Your main file is where your initial code will live. Go ahead and create &lt;code&gt;main.py&lt;/code&gt; and add this to it:&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="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&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;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;h1&amp;gt;Hello world&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, this won't actually &lt;em&gt;do&lt;/em&gt; anything yet. We need to run this code. We'll do that in the next step. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Environment variables and running the app
&lt;/h2&gt;

&lt;p&gt;First, let's set a couple environment variables. This will help tell Flask what to do while we're developing our app.&lt;/p&gt;

&lt;p&gt;In your command line (while inside of your virtual environment) 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;export &lt;/span&gt;&lt;span class="nv"&gt;FLASK_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;development
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flask run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you should see something like this in your terminal:&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="k"&gt;*&lt;/span&gt; Serving Flask app &lt;span class="s1"&gt;'main'&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;lazy loading&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Environment: development
 &lt;span class="k"&gt;*&lt;/span&gt; Debug mode: on
 &lt;span class="k"&gt;*&lt;/span&gt; Running on http://127.0.0.1:5000/ &lt;span class="o"&gt;(&lt;/span&gt;Press CTRL+C to quit&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Restarting with &lt;span class="nb"&gt;stat&lt;/span&gt;
 &lt;span class="k"&gt;*&lt;/span&gt; Debugger is active!
 &lt;span class="k"&gt;*&lt;/span&gt; Debugger PIN: 814-739-543
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Head on over to &lt;a href="http://127.0.0.1:5000/" rel="noopener noreferrer"&gt;http://127.0.0.1:5000/&lt;/a&gt; in a new tab in your browser, and you should see &lt;code&gt;Hello World&lt;/code&gt; in big bold letters. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Adding a template
&lt;/h2&gt;

&lt;p&gt;Templates make life easier. You can write a basic .html file with some Jinja templating in it for dynamic content. But let's start with a simple template.&lt;/p&gt;

&lt;p&gt;Open your &lt;code&gt;main.py&lt;/code&gt; file and change it to look like this:&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="c1"&gt;# main.py 
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template_folder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;templates&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="sh"&gt;'&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;index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;home.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tells Flask to use the &lt;code&gt;templates/&lt;/code&gt; folder as the main folder for templates, and to use &lt;code&gt;home.html&lt;/code&gt; as the main page. You can rename &lt;code&gt;home.html&lt;/code&gt; to anything you like. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: There's A LOT to know when it comes to templating in Jinja, but we aren't going to cover very much right now so we can keep this simple. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now create a new folder beside your main.py file called &lt;code&gt;templates/&lt;/code&gt; and add a child file called &lt;code&gt;home.html&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Your file structure should look like this now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ee0dwe5cswkeu2zdewq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ee0dwe5cswkeu2zdewq.png" alt="File structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And your home.html file should have this in it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;Hello from home.html&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Creating a second view.
&lt;/h2&gt;

&lt;p&gt;In your main.py file, let's create a second "view". This is the route (sometimes called path) to another page. &lt;/p&gt;

&lt;p&gt;This time we'll add something dynamic to the template. &lt;/p&gt;

&lt;p&gt;At the top of &lt;code&gt;main.py&lt;/code&gt; add this import:&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="n"&gt;datetime&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;- Add this line 
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;render_template&lt;/span&gt;
&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And at the bottom for &lt;code&gt;main.py&lt;/code&gt; add these lines:&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="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/time&lt;/span&gt;&lt;span class="sh"&gt;'&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;timetest&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&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;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;render_template&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;time.html&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, add &lt;code&gt;templates/time.html&lt;/code&gt; to your project, and inside of &lt;code&gt;time.html&lt;/code&gt; add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jinja"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;The time is &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;now&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now navigate to &lt;a href="http://127.0.0.1:5000/time" rel="noopener noreferrer"&gt;http://127.0.0.1:5000/time&lt;/a&gt; and it should show your time. And it will update every time the page is refreshed. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: If the time doesn't match your exact time right now, it's because your Flask server thinks it's on a different timezone. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What we did was:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a variable called &lt;code&gt;now&lt;/code&gt; with the current date/time. &lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;, now=now&lt;/code&gt; to the &lt;code&gt;render_template()&lt;/code&gt; function. This adds "context" to your template.&lt;/li&gt;
&lt;li&gt;In your template, you can access &lt;code&gt;{{ now }}&lt;/code&gt; as a dynamic value. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Your project should look like this:
&lt;/h2&gt;

&lt;p&gt;Your project so far should be structured like this:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffu1jw7qygxisj413t7z7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffu1jw7qygxisj413t7z7.png" alt="File structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And all the files I wrote can be found on GitHub here: &lt;a href="https://github.com/KalobTaulien/flask-tutorial" rel="noopener noreferrer"&gt;https://github.com/KalobTaulien/flask-tutorial&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>Building a scraping tool with Python and storing it in Airtable (with real code)</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Thu, 30 Dec 2021 00:27:30 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/building-a-scraping-tool-with-python-and-storing-it-in-airtable-with-real-code-4pbl</link>
      <guid>https://dev.to/kalobtaulien/building-a-scraping-tool-with-python-and-storing-it-in-airtable-with-real-code-4pbl</guid>
      <description>&lt;p&gt;A startup often needs extremely custom tools to achieve its goals. &lt;/p&gt;

&lt;p&gt;At &lt;a href="https://arbington.com"&gt;Arbington.com&lt;/a&gt; we've had to build scraping tools, data analytics tools, and custom email functions. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;None of this required a database. We used files as our "database" but mostly we used Airtable. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Scrapers
&lt;/h2&gt;

&lt;p&gt;Nobody wants to admit it, but scraping is pretty important for gathering huge amounts of useful data. &lt;/p&gt;

&lt;p&gt;It's frowned upon, but frankly, everyone does it. Whether they use an automated tool, or manually sift through thousands of websites to collect email addresses - most organizations do it. &lt;/p&gt;

&lt;p&gt;In fact, scraping is what made the worlds best search engine: Google. &lt;/p&gt;

&lt;p&gt;And in Python, this is REALLY easy. &lt;/p&gt;

&lt;p&gt;The hardest part is reading through various forms of HTML, but even then, we have a tool for that. Let's take a look at an example that I've adjusted so you can scrape my website. &lt;/p&gt;

&lt;p&gt;We'll use &lt;a href="https://kalob.io/teaching/"&gt;https://kalob.io/teaching/&lt;/a&gt; as the example and get all the courses I teach. &lt;/p&gt;

&lt;p&gt;First, we look for a pattern in the DOM. Open up that page, right click, inspect element, and look for all the blue buttons. &lt;/p&gt;

&lt;p&gt;You'll see they all have &lt;code&gt;class="btn btn-primary"&lt;/code&gt;. Interesting, we've found a pattern. Great! We can work with that. &lt;/p&gt;

&lt;p&gt;Now let's just right into the code. And if you're a Python dev, feel free to paste this into your terminal.&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="n"&gt;response&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="s"&gt;"https://kalob.io/teaching/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see the HTML for my website. Now, all we need to do is parse the HTML. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: utf-8 encoding is most commonly used on the internet. So we'll want to decode the HTML we scraped into utf-8 compatible text (in a giant string)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our code now looks like this:&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="n"&gt;response&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="s"&gt;"https://kalob.io/teaching/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you'll see the HTML looks a little nicer now. &lt;/p&gt;

&lt;p&gt;Now here's a big hairy problem: parsing HTML. Some people use &lt;code&gt;attr=""&lt;/code&gt; some people use &lt;code&gt;attr=''&lt;/code&gt; some people use XHTML and some don't. &lt;/p&gt;

&lt;p&gt;So how do we get around this? &lt;/p&gt;

&lt;p&gt;Introducing: Beautiful Soup 4. &lt;/p&gt;

&lt;p&gt;In your Python environment pip install this package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;beautifulsoup4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And your code now looks like this:&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="n"&gt;response&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="s"&gt;"https://kalob.io/teaching/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;bs4&lt;/span&gt;  &lt;span class="c1"&gt;# You'll need to `pip install `
&lt;/span&gt;&lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"html.parser"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Shows the parsed HTML
&lt;/span&gt;&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# Returns &amp;lt;class 'bs4.BeautifulSoup'&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So our &lt;code&gt;soup&lt;/code&gt; variable is no longer a string, but an object. This means we can use object methods on it - like looking for  certain elements in the HTML we scraped. &lt;/p&gt;

&lt;p&gt;Let's put together a list of all the links on this page.&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="n"&gt;response&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="s"&gt;"https://kalob.io/teaching/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;bs4&lt;/span&gt;  &lt;span class="c1"&gt;# You'll need to `pip install `
&lt;/span&gt;&lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"html.parser"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;courses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;courses&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at that.. now we have a list of buttons from the page we scraped at the beginning of this article. &lt;/p&gt;

&lt;p&gt;Lastly, let's loop through them to get the button text and the link:&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;course&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;courses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;course&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="s"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&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="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Listen, I wrote 3 print statements to make this clear - but typically I'd write this in a single line. &lt;/p&gt;

&lt;p&gt;Now we have something to work with! We have the entire HTML element, the &lt;code&gt;href&lt;/code&gt; attribute, and the &lt;code&gt;innerText&lt;/code&gt; without any whitespace. &lt;/p&gt;

&lt;p&gt;The entire script is 9 lines of code and looks like this:&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;import&lt;/span&gt; &lt;span class="nn"&gt;bs4&lt;/span&gt;  &lt;span class="c1"&gt;# You'll need to `pip install `
&lt;/span&gt;
&lt;span class="n"&gt;response&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="s"&gt;"https://kalob.io/teaching/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"html.parser"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;courses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&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;course&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;courses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;print&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;course&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="s"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Moving this data somewhere useful.
&lt;/h2&gt;

&lt;p&gt;You know me, I'm a HUGE fan of Airtable. &lt;/p&gt;

&lt;p&gt;And instead of using local database or a cloud based database, I like to use Airtable so me and my team and work with the data and easily expand the tables if we need to. Like if we needed to add a column to see if a course meetings our criteria to be on Arbington.com. &lt;/p&gt;

&lt;p&gt;For this we use Airtables API and the python package known as &lt;br&gt;
&lt;code&gt;airtable-python-wrapper&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Go ahead an install this through pip.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;airtable-python-wrapper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now before we continue, you'll need a &lt;a href="https://airtable.com/invite/r/JXx8l4fX"&gt;free Airtable account&lt;/a&gt; 👈 that's our referral link. No need to use it, it's just a nice kickback for us for constantly promoting Airtable 😂&lt;/p&gt;

&lt;p&gt;Once you have an account, you need to dig up your app API key, your table API key, and your Base Name. It would look something like this in python:&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;airtable.airtable&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Airtable&lt;/span&gt;

&lt;span class="n"&gt;airtable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Airtable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'appXXXXXXXXX'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Links'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'keyXXXXXXXXXX'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, all we need to do is create a dictionary of Airtable Column Names, and insert the record.&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;import&lt;/span&gt; &lt;span class="nn"&gt;bs4&lt;/span&gt;  &lt;span class="c1"&gt;# You'll need to `pip install `
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;airtable.airtable&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Airtable&lt;/span&gt;

&lt;span class="n"&gt;response&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="s"&gt;"https://kalob.io/teaching/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;soup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bs4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeautifulSoup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"html.parser"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;courses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;soup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"btn btn-primary"&lt;/span&gt;&lt;span class="p"&gt;]})&lt;/span&gt;

&lt;span class="n"&gt;airtable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Airtable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'appXXXXXXXXX'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'Links'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'keyXXXXXXXXXX'&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;course&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;courses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;new_record&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Link"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;course&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="s"&gt;'href'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s"&gt;"Text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&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="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;airtable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming you setup your Airtable columns, table and API keys properly, you should see my website links and URLs appear in your Airtable. &lt;/p&gt;

&lt;p&gt;Now you and your team can scrape webpages and store the data in Airtable for the rest of your team to use! &lt;/p&gt;

&lt;h2&gt;
  
  
  Pulling data out to work with it
&lt;/h2&gt;

&lt;p&gt;Now that all the data we want is in Airtable, we can use the same Python package to pull the data out, work with it, scrape more data, and update each record. &lt;/p&gt;

&lt;p&gt;But that's for another day 😉 &lt;/p&gt;

&lt;h2&gt;
  
  
  Want to learn Python?
&lt;/h2&gt;

&lt;p&gt;If you're looking for online courses, take a look at Arbington.com, &lt;a href="https://arbington.com/search/?q=python"&gt;there are over 40 Python courses&lt;/a&gt; available. &lt;/p&gt;

&lt;p&gt;And it comes with a free 14 day trial to access over 1,500 courses immediately! 🔥 &lt;/p&gt;

</description>
      <category>python</category>
    </item>
    <item>
      <title>What to learn to become a fullstack developer (for beginners)</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Tue, 21 Dec 2021 17:11:11 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/what-to-learn-to-become-a-fullstack-developer-for-beginners-khm</link>
      <guid>https://dev.to/kalobtaulien/what-to-learn-to-become-a-fullstack-developer-for-beginners-khm</guid>
      <description>&lt;h2&gt;
  
  
  Learn to earn in web development
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;In web development there is a lot to learn before you can start to earn. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Getting into web development, or coding/programming of any kind, can take quite a while. &lt;/p&gt;

&lt;p&gt;Learning is the easy part, but landing a job… well that's the hard part! &lt;/p&gt;

&lt;p&gt;But that wasn't always the case. Once upon a time, it was the exact opposite. &lt;/p&gt;

&lt;p&gt;You see, when I first started learning how to code in 1999 all we had were boring books and a few awful websites. &lt;/p&gt;

&lt;p&gt;But nowadays you can just watch videos and the information is downloaded directly into your brain, how awesome is that?! &lt;/p&gt;

&lt;p&gt;But in 2021/2022 we have a problem… there is SO MUCH information we don't know what to follow or believe. &lt;/p&gt;

&lt;p&gt;That's where online courses come to save the day. &lt;/p&gt;

&lt;p&gt;Online coding courses give you the knowledge and practice you need to learn how to code, and they give you the guidance you need to move forward as a web developer looking for a career change. &lt;/p&gt;

&lt;p&gt;What do you need to learn first (in web development)?&lt;br&gt;
 &lt;/p&gt;

&lt;h2&gt;
  
  
  HTML. 
&lt;/h2&gt;

&lt;p&gt;It's easy. You could learn and be REALLY good at HTML in less than a week. &lt;/p&gt;

&lt;p&gt;Every website uses HTML, so this is the first thing you'll want to learn. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/search/?q=html" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm86iopeqmxibin9tv24u.png" alt="Learn HTML"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Then you need to learn CSS. 
&lt;/h2&gt;

&lt;p&gt;CSS is also easy, but it's BIG and has strict rules that aren't always obvious. It should take you about a month to get really good at CSS and to start making beautiful and modern looking websites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/search/?q=css" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvhcqzyv48y0qk90a1mt7.png" alt="Learn CSS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Then you need to learn JavaScript. 
&lt;/h2&gt;

&lt;p&gt;Ugh, JavaScript. &lt;/p&gt;

&lt;p&gt;I say "ugh" because JavaScript is a HUGE ecosystem full of shiny objects that don't matter. Don't learn React first, don't learn Vue first, don't learn jQuery first.. learn plain, vanilla, raw, unfiltered, boring JavaScript first.&lt;/p&gt;

&lt;p&gt;Don't get distracted by all the tools, packages and fun things you can do. Just keep it simple. This can take you between 1–3 months to learn. &lt;/p&gt;

&lt;p&gt;JavaScript is a programming language, whereas CSS and HTML are not programming languages - they are considered markup languages. And the human brain registers a programming language as a different way to think - it's literally like learning a new speaking language. So be patient at this step. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/search/?q=javascript" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F39g3urjt3t1ee9dgqzud.png" alt="Learn JavaScrcipt"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Then you need to learn about APIs. 
&lt;/h2&gt;

&lt;p&gt;Application Programming Interfaces. &lt;/p&gt;

&lt;p&gt;That sounds harder than it actually is. It's honestly just fancy talk for "sending and receiving data from a different computer over the internet". It's like asking your waiter for a drink - you make a request, it shows up, and what you do afterwards is up to you. &lt;/p&gt;

&lt;p&gt;API's should take you about a day to learn the theory. But then another 1–2 weeks for practice. &lt;/p&gt;

&lt;h2&gt;
  
  
  Next up, learn Git &amp;amp; GitHub
&lt;/h2&gt;

&lt;p&gt;Git is a "version control tool". It lets you make changes over time, rewind your work, save it and store it somewhere safe like GitHub.com or GitLab.com. &lt;/p&gt;

&lt;p&gt;It can get REALLY complex really easily, so just learn the basics for now.&lt;/p&gt;

&lt;p&gt;This should take you about a week to learn, but then you should be using Git on every project moving forward for all of time. So you'll get REALLY good at it pretty quickly. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/search/?q=git" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwpf2y9bvlcwff9b50d70.png" alt="Learn Git and GitHub"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lastly, learn a server-side language
&lt;/h2&gt;

&lt;p&gt;Server-side programming languages are the languages you write that exist on the server. That could be Python, PHP, Java, JavaScript, etc. &lt;/p&gt;

&lt;p&gt;I personally like Python because it's powerful, easy to learn, easy to read and write, and it's the worlds #1 most popular programming language - so you know there are jobs related to Python. &lt;/p&gt;

&lt;p&gt;This is similar to learning JavaScript, time-wise at least. It should take 1–3 months to learn a server-side language well enough you can apply for a job. &lt;/p&gt;

&lt;p&gt;If you already know JavaScript quite well, you'll pick up other languages quite easily. So if you already know JavaScript and you're just learning Python, it'll probably take half the time to learn Python, so maybe 2–6 weeks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/search/?q=python" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98d2a7vswm8cw5r96sak.png" alt="Learn Python"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where can you learn all this?
&lt;/h2&gt;

&lt;p&gt;Arbington.com is the place to learn this. Right now it's $15/month to get access to over 150 web development courses, plus another 150 design courses, hundreds of marketing, SEO and analytics courses, and so much more. &lt;/p&gt;

&lt;p&gt;In total you'll get immediate access to over 1,500 courses for just $15/month - and it comes with a free 14 day trial. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/premium/info/" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flqcoadnh1h0nrgbro725.png" alt="Arbington Premium"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Certificates of completion are included in every course!&lt;/p&gt;

&lt;h2&gt;
  
  
  And just like that…
&lt;/h2&gt;

&lt;p&gt;In about 7–10 months you have become a junior fullstack web developer. &lt;/p&gt;

&lt;p&gt;There are a few things we skipped over like learning React.js or Django for Python, but once you know the programming language the frameworks become easier to learn.&lt;/p&gt;

&lt;p&gt;Don't forget to open source all of your work on GitHub to future employers can see your progress!&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Tools I use everyday as a senior web developer 🔧 </title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Mon, 20 Dec 2021 19:20:03 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/tools-i-use-everyday-as-a-senior-web-developer-dko</link>
      <guid>https://dev.to/kalobtaulien/tools-i-use-everyday-as-a-senior-web-developer-dko</guid>
      <description>&lt;p&gt;Hey everyone! &lt;/p&gt;

&lt;p&gt;I'm going to go off track in this article and talk about the tools I use on a regular basis. These are tools or languages that I need as a startup &lt;strong&gt;and&lt;/strong&gt; as a senior web developer. &lt;/p&gt;

&lt;p&gt;At &lt;a href="https://arbington.com/"&gt;Arbington.com&lt;/a&gt; we use all of these tools, too. &lt;/p&gt;

&lt;p&gt;Let's start with the ones you're most likely interested in: developer tools! &lt;/p&gt;

&lt;h2&gt;
  
  
  Developer tools
&lt;/h2&gt;

&lt;p&gt;Every day I work on the code base at my startup. And every day I use these tools.&lt;/p&gt;

&lt;p&gt;This isn't the full list, I'm sure I'm forgetting tools and languages, but these are the immediate ones that come to mind as a full stack web developer. &lt;/p&gt;

&lt;h3&gt;
  
  
  Languages
&lt;/h3&gt;

&lt;p&gt;Everyday I write JavaScript and Python. &lt;/p&gt;

&lt;p&gt;JavaScript, because, well, what's the alternative for client-side coding? Not much, really. So I'm stuck with it and make the best of it. 🤷‍♂️ &lt;/p&gt;

&lt;p&gt;I also use JavaScript in terms of Webpack to compile my JavaScript and CSS. That's server-side JavaScript through Node.js, which isn't exactly the same as browser-based JavaScript. It looks the same, but has a different purpose. &lt;/p&gt;

&lt;p&gt;And Python, because, well, it's powerful, fast, easy to maintain, and the ecosystem has every possible package I could think of. &lt;/p&gt;

&lt;h3&gt;
  
  
  Tools
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The command line!&lt;/strong&gt; Holy smokes is this important. Don't discount it as "and old way of doing things". Modern devs ALL use the command line for everything from running tests, compiling code, accessing servers, and committing code to GitHub. &lt;/p&gt;

&lt;p&gt;Speaking of GitHub, &lt;strong&gt;Git and GitHub&lt;/strong&gt;. I use GitHub to host my repositories, but you can just as easily use BitBucket or GitLab. And I strictly use Git on the command line because that's what servers use - so if I ever need to SSH into a server, I'm well equipped with the knowledge and tools I need to pull down my latest changes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docker&lt;/strong&gt; is another big one. I have multiple projects on my computer that user different versions of Python or Node.js. &lt;/p&gt;

&lt;p&gt;Instead of installing all these different versions (ie. Python 3.6, 3.7, 3.8 and 3.9) I simply use a Docker container that downloads that version and compartmentalizes it in a virtual machine-like instance. If I no longer need it, I just delete it. And it has no effect on my laptop. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developer tools&lt;/strong&gt;, in the scenario of a browser's dev tools. Namely, I use Chrome and Firefox. But all major browsers have dev tools. It's great for debugging JavaScript and Ajax/Fetch requests to see what your server is returning. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VS Code&lt;/strong&gt; is the editor I choose to use. I was late to the game because I used to love Sublime, and Notepad++ before that (is my age showing, yet?). But I'm really happy with VS Code and it has built in support for JavaScript, TypeScript and Python with extensions for a Git GUI, Docker container management, and more. I still prefer the command line for most things, but not everyone is as command-line-focused as I am. &lt;/p&gt;

&lt;p&gt;That's my day-in-day-out set of tools. Pretty simple, right? You don't need much to do a lot these days. &lt;/p&gt;

&lt;p&gt;I also make use of cURL, Vim, ipython, Jupyter notebooks, tmux, Docker compose, the kubernetes command line tool, and plenty of other fun tools. But if I didn't have any of these on a typical day, I'd be OK to carry on. &lt;/p&gt;

&lt;h2&gt;
  
  
  Non-dev tools
&lt;/h2&gt;

&lt;p&gt;I use quite a few non-dev tools in my day to day life. And you probably use a lot of these too. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;G Suite&lt;/strong&gt; or whatever it's called these days - we use this for hosting email and creating internal documents at Arbington.com. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calendly&lt;/strong&gt; is new to my tool belt, and I'm happily paying for it. It hooks into numerous calendars and lets me book times with teachers and students, and send follow up emails. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stripe.com&lt;/strong&gt; for processing payments. I have an article on how to get started with Stripe to accept money from customers through your website. I also use &lt;strong&gt;PayPal&lt;/strong&gt; to pay my vendors, staff, teachers and other misc. expenses. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Airtable&lt;/strong&gt; is a service I would be lost without. It's like Google Sheets, but on steroids! It's powerful, fast, has a great API, and lets me put our teams data into a centralized place to digest, keep track of tasks and clients, and has version history on each record. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dropbox&lt;/strong&gt; for storing files. While we do pay for G Suite, Dropbox just seems friendlier and I don't lose any of my files. It's basically an advanced folder system for the web. Plus it's API lets me gracefully handle large files. Everything from business docs, ideas, and videos - if it's a file, it goes in Dropbox. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slack&lt;/strong&gt;. I know I know, some people are booing me for not using Discord. But Slack is the brand name in business communications, and Discord is known for fun and gaming. We don't pay for Slack yet, but we use it every day to communicate with each other. If you don't have a team slack, definitely try it out. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zoom&lt;/strong&gt; is probably the most popular program for most people these days. In a pandemic, everything goes virtual - meetings, coffees, beers, pair programming... you name it, it's likely on Zoom (or Google Meet). &lt;/p&gt;

</description>
      <category>tooling</category>
      <category>javascript</category>
      <category>python</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Web hosting solutions in a nutshell</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Tue, 14 Dec 2021 23:02:05 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/web-hosting-solutions-in-a-nutshell-2o7e</link>
      <guid>https://dev.to/kalobtaulien/web-hosting-solutions-in-a-nutshell-2o7e</guid>
      <description>&lt;p&gt;There are A LOT of web hosting solutions these days. &lt;/p&gt;

&lt;p&gt;Let's jump into a few of them, and I'll explain some of our setup at &lt;a href="https://arbington.com/"&gt;Arbington.com&lt;/a&gt; along the way. &lt;/p&gt;

&lt;h2&gt;
  
  
  Different types of hosting
&lt;/h2&gt;

&lt;p&gt;There are different types of hosting. Some places give you a little space in a partitioned hard drive, some give you an entire server. &lt;/p&gt;

&lt;p&gt;This largely depends on your budget. But you can host a website for as little as $2/month, or as much as thousands per month. &lt;/p&gt;

&lt;p&gt;And that also, largely, depends on the complexity of your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self hosted options
&lt;/h2&gt;

&lt;p&gt;Personally, I like these options. These come in the form of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS EC2 &lt;/li&gt;
&lt;li&gt;Digital Ocean&lt;/li&gt;
&lt;li&gt;Linode &lt;/li&gt;
&lt;li&gt;Heroku&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are plenty of other providers out there but those are the three most common in my circles. &lt;/p&gt;

&lt;p&gt;You basically get an entire server for as little as $5/month. It's not actually an entire server, is a slice of a server called a "virtual machine". &lt;/p&gt;

&lt;h3&gt;
  
  
  AWS EC2
&lt;/h3&gt;

&lt;p&gt;EC2 is, honestly, amazing! It's very powerful and very affordable. But a lot of people are trying to stay away from Amazon because EC2 hosts like, what, 30% of all websites? &lt;/p&gt;

&lt;p&gt;But if you're an Amazon fan, EC2 is the way to go! &lt;/p&gt;

&lt;h3&gt;
  
  
  Digital Ocean
&lt;/h3&gt;

&lt;p&gt;I'm a big fan of Digital Ocean. Simple interfaces, simple billing, powerful tools, and an overall solid company 👌 &lt;/p&gt;

&lt;p&gt;We use Kubernetes and Docker with an Nginx load balancer all hosted on Digital Ocean. That's pretty advanced, so don't feel like you need to learn everything in this paragraph to get started with Digital Ocean. They have pre-made "boxes" (virtual machines) to get you up and running with services like Django and WordPress super quickly. &lt;/p&gt;

&lt;h3&gt;
  
  
  Linode
&lt;/h3&gt;

&lt;p&gt;I know A LOT of people that use Linode. Personally, I don't use them anymore. They are good! I just prefer Digital Ocean, that's all. &lt;/p&gt;

&lt;h3&gt;
  
  
  Heroku
&lt;/h3&gt;

&lt;p&gt;Heroku is the odd ball here. They are incredibly powerful, very simple, with an intermediate level interface. &lt;/p&gt;

&lt;p&gt;Less command line skills needed, less server management needed, and you can connect GitHub to it to automatically push new updates to your site. It's a dream for people that absolutely hate dealing with servers. &lt;/p&gt;

&lt;h3&gt;
  
  
  The common thread
&lt;/h3&gt;

&lt;p&gt;You typically need to setup everything on your own, including updating Linux (minus Heroku). But with that, you get almost unlimited access to do whatever you want (minus Heroku, again). &lt;/p&gt;

&lt;p&gt;For us at &lt;a href="https://arbington.com/"&gt;Arbington.com&lt;/a&gt; we use Digital Ocean - if you want a free $100 credit just to try it out, &lt;a href="https://m.do.co/c/d47ab4f99521"&gt;use our referral link here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Again, this does mean you're going to learn some server ops skills. And everything is done over the command line. &lt;/p&gt;

&lt;p&gt;So while it's only $5/month, it also means you're in full control - that's both good and bad for most people. &lt;/p&gt;

&lt;p&gt;If you want something a little easier, I would highly recommend looking into Heroku. &lt;/p&gt;

&lt;p&gt;It's an easier learning curve, cheap and you don't have to worry about setting up your own versions of Linux and upgrading them all the time. &lt;/p&gt;

&lt;p&gt;The down side to Heroku is the lack of storage space - so you can't just upload all your photos and hope they'll stay there forever. You'll need something like AWS S3, Cloudflare R2, or Cloudinary to host your images. &lt;/p&gt;

&lt;p&gt;Whereas other services like AWS or Digital Ocean give you the option to select your hard drive size (called a "disk"). If you only need 8gb, great, you only pay for 8gb. If you need 1TB, you can pay for that too (although I would suggest looking at "object stores" like AWS S3 or Digital Oceans equivalent) &lt;/p&gt;

&lt;h2&gt;
  
  
  Other hosting solutions
&lt;/h2&gt;

&lt;p&gt;On the other hand we have "easy" providers. These players are often cheap, but very limited in what you can do. &lt;/p&gt;

&lt;p&gt;And they'll often charge for extras, like SSL certificates (even though they are free to generate using &lt;a href="https://letsencrypt.org/"&gt;Let's Encrypt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And often, these websites are slow to load. These are second tier businesses renting out their hardware. &lt;/p&gt;

&lt;p&gt;But they do come with basic support in most cases. Places like GoDaddy, BlueHost and WPEngine let you easily spin up WordPress sites, for instance. &lt;/p&gt;

&lt;p&gt;And they sometimes come with a cPanel, which is your control panel for your website. &lt;/p&gt;

&lt;p&gt;More often than not, they don't tend to come with any command line support, so you're stuck using SFTP/FTP to upload your files. And if you host an application using Python, this can get REALLY tricky. But it works VERY well for PHP applications. &lt;/p&gt;

&lt;p&gt;Most developers these days prefer to use Git to update their website with a few simple commands, line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh user@your.ip.address
&lt;span class="nb"&gt;cd &lt;/span&gt;YourFolder/
git pull origin main 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But these smaller hosting providers, again, often don't support command line or git integration. &lt;/p&gt;

&lt;h2&gt;
  
  
  Where should you start?
&lt;/h2&gt;

&lt;p&gt;If you've never hosted a website before, I would suggest two things: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If your site is a static site (made with HTML/CSS/JavaScript) then look into GitHub pages. &lt;/li&gt;
&lt;li&gt;If your site needs a backend language, &lt;em&gt;try&lt;/em&gt; one of the easier providers that only use FTP. It's less the learn, and gets you up and running faster. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But once you have that all figured out and you feel comfortable with the basic sites, I highly recommend looking into a self hosted solution with AWS or Digital Ocean. &lt;/p&gt;

&lt;p&gt;If you want a free $100 credit with Digital Ocean just to try things out, use our &lt;a href="https://m.do.co/c/d47ab4f99521"&gt;referral link&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;You'll need to learn more command line, operating system and dev tools like git... but you'll also gain A LOT of experience that's super useful in "the real world", where companies are looking for these skills. &lt;/p&gt;

&lt;h2&gt;
  
  
  Want to learn the command line?
&lt;/h2&gt;

&lt;p&gt;The command line is not to learn at first. But it's POWERFUL! And in most cases, it's faster than learning how to use a GUI (graphic user interface). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/search/?q=command+line"&gt;Check out these 5 command line courses on Arbington.com&lt;/a&gt;. Don't forget, Arbington comes with a free 14 day trial so you can try all of these courses completely risk-free. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Handling Payments with Stripe (the easy way) 💳 </title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Sun, 05 Dec 2021 20:22:29 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/handling-payments-with-stripe-the-easy-way-1g82</link>
      <guid>https://dev.to/kalobtaulien/handling-payments-with-stripe-the-easy-way-1g82</guid>
      <description>&lt;p&gt;At &lt;a href="https://arbington.com"&gt;Arbington.com&lt;/a&gt; we use Stripe.com to handle all of our payments. &lt;/p&gt;

&lt;p&gt;It's secure, fast, and honestly it's a developers dream.&lt;/p&gt;

&lt;p&gt;For this, you should be familiar with Ajax/Fetch requests and being able to work with an API. We use Python on the backend, so we use Stripes's Python API. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We will show some demo code, but you'll need to fill in the blanks.&lt;/strong&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;First, you'll need a Stripe.com account. It's free to setup, and they give you two sets of API keys:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A test pair of public and private keys &lt;/li&gt;
&lt;li&gt;A live pair of public and private keys &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The test keys will make payments to your test account, and toggling between testing data and real payment data is as easy as clicking a toggle button in their dashboard. &lt;/p&gt;

&lt;p&gt;Two things to note about Stripe:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You need a bank account attached to your Stripe account when you start accepting real data. &lt;/li&gt;
&lt;li&gt;You never EVER send credit card numbers or CVV's (the 3 digits on the back) to your server. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;On the frontend (JavaScript) you need to create a token. This token is encrypted and used by your backend so you don't ever need to send credit card information to your server. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Always. use. tokens! Never EVER send a customers raw credit card information to your server. It's unsafe and requires a thing called PCI compliance, which is a headache to obtain and maintain. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The code looks a bit like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://js.stripe.com/v2/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;Stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setPublishableKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your_test_publishable_key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;nameOnCard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Use JavaScript to get the &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cardNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cvc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cardCvc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;exp_month&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cardExpMonth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;exp_year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cardExpYear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;address_line1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;address1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;address_line2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;address2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Optional&lt;/span&gt;
    &lt;span class="na"&gt;address_city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;address_state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;address_country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;usd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;address_zip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;postalCode&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;Stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;stripeResponseHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;stripeResponseHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Problem!&lt;/span&gt;
      &lt;span class="c1"&gt;// Show the error&lt;/span&gt;
      &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&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="c1"&gt;// Token was created!&lt;/span&gt;

      &lt;span class="c1"&gt;// Get the token ID:&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// TODO: Ajax the token to your backend/server&lt;/span&gt;
      &lt;span class="c1"&gt;// Make sure you create a POST request and not a GET request &lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And just like that, you're creating a Stripe token for a credit card. &lt;/p&gt;

&lt;p&gt;You don't need to save this token because a new token will be created every time you submit the payment form. &lt;/p&gt;

&lt;p&gt;Also, on that note, don't &lt;em&gt;actually&lt;/em&gt; wrap your html in a &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; because that could be submitted by accident and could share credit card info in a POST or GET request.&lt;/p&gt;

&lt;p&gt;Oh, and one more thing you'll need: a JavaScript event listener. I typically tie the &lt;code&gt;eventListener&lt;/code&gt; to a button &lt;code&gt;click&lt;/code&gt; event, perform some light frontend validation to make sure fields aren't missing and are formatted correctly. &lt;/p&gt;

&lt;p&gt;After you've sent the token to your backend/server, you can start to process it. &lt;/p&gt;

&lt;p&gt;In this article I'll be using Python because it's the worlds most popular programming language, and we use it at &lt;a href="https://arbington.com"&gt;Arbington.com&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Let's tackle that next. &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a payment in the backend
&lt;/h2&gt;

&lt;p&gt;As mentioned, we'll be using Python. But Stripe has AMAZING documentation and AMAZING support for multiple languages, including PHP, Python, Ruby, .NET, Java, Go, and Node.js. &lt;/p&gt;

&lt;p&gt;Let's take a look at some sample code:&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;stripe&lt;/span&gt;
&lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"sk_test_blah_blah_blah"&lt;/span&gt;

&lt;span class="c1"&gt;# `source` is obtained with Stripe.js this is your "token"
&lt;/span&gt;&lt;span class="n"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Value in pennies, so this is 20.00
&lt;/span&gt;  &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"usd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&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="s"&gt;"token"&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;"A test token payment of $20.00 USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Pro tip:&lt;/em&gt; Wrap the stripe.Charge.create() method in a try/catch block. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's how I typically wrap a charge in Python:&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="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;charge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Charge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Value in pennies, so this is 20.00
&lt;/span&gt;        &lt;span class="n"&gt;currency&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"usd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&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="s"&gt;"token"&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;"A test token payment of $20.00 USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CardError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Since it's a decline, stripe.error.CardError will be caught
&lt;/span&gt;    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvalidRequestError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Invalid parameters were supplied to Stripe's API
&lt;/span&gt;    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Authentication with Stripe's API failed
&lt;/span&gt;    &lt;span class="c1"&gt;# (maybe you changed API keys recently)
&lt;/span&gt;    &lt;span class="c1"&gt;# Log the failed transaction in the users account
&lt;/span&gt;    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StripeError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Display a very generic error to the user
&lt;/span&gt;    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Something else happened, completely unrelated to Stripe
&lt;/span&gt;    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the charge was successful, you'll have a variable called &lt;code&gt;charge&lt;/code&gt; (from the code above) and it'll hold A LOT of useful information you can store for later, including an &lt;code&gt;id&lt;/code&gt; that always starts with &lt;code&gt;ch_&lt;/code&gt; - this can be used later for issuing refunds. &lt;/p&gt;

&lt;p&gt;To see the entire object that Stripe returns, check out &lt;a href="https://stripe.com/docs/api/charges/create"&gt;the Charge.create object in their docs&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;p&gt;With the data from the Charge.create object available you can save the charge &lt;code&gt;id&lt;/code&gt; that Stripe gives you - save it in your database. This isn't considered sensitive information so you can plop it in your database without worries. &lt;/p&gt;

&lt;p&gt;Then in your application, you can check if a user has a recent charge and possibly offer a refund - if your service offers a free trial that is. &lt;/p&gt;

&lt;p&gt;Lastly, check your Stripe dashboard (in test mode) to see if the charge came through successfully. &lt;/p&gt;

&lt;p&gt;If you create too much test data, you can always delete your test data in your Stripe settings. This will only effect your localhost and has no effect on your real life payments once your application is live. &lt;/p&gt;

&lt;h2&gt;
  
  
  Going live
&lt;/h2&gt;

&lt;p&gt;Going live is SUPER easy. &lt;/p&gt;

&lt;p&gt;If your code works in test mode, it WILL work in live mode. All you need to do it swap out your test publishable key and test private key for your live publishable key and live private key. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Remember&lt;/em&gt;: These keys work together. Use both testing keys together, or use both live keys together, but don't mix and match them. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And that's all there is to it. &lt;/p&gt;

&lt;p&gt;Subscriptions are a wee bit trickier, but the concept is the same. If you'd like to learn more about how we handle subscriptions or tying a card to a specific user, let me know in the comments below! &lt;/p&gt;

&lt;h2&gt;
  
  
  Learning JavaScript or Python
&lt;/h2&gt;

&lt;p&gt;Want to learn JavaScript or Python? Great!&lt;/p&gt;

&lt;p&gt;Arbington.com offers over 1,500 online courses from industry experts, all for just $15/month. And it comes with a 14 day free trial. &lt;/p&gt;

&lt;h3&gt;
  
  
  25+ JavaScript courses
&lt;/h3&gt;

&lt;p&gt;Want to learn more JavaScript? That's awesome! At Arbington we have over 25 JavaScript courses to choose from. &lt;a href="https://arbington.com/search/?q=javascript"&gt;Check them out here&lt;/a&gt;. These are all included in your Arbington subscription - so feel free to take them all for as low as $15/month. &lt;/p&gt;

&lt;h3&gt;
  
  
  40+ Python courses
&lt;/h3&gt;

&lt;p&gt;Want to learn more Python? That's even more awesome! I personally LOVE Python! And at Arbington &lt;a href="https://arbington.com/search/?q=python"&gt;we have &lt;strong&gt;over 40&lt;/strong&gt; Python courses&lt;/a&gt;. These are also all included in your monthly subscription. &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>python</category>
    </item>
    <item>
      <title>How we use API's at Arbington.com</title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Tue, 30 Nov 2021 15:49:34 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/how-we-use-apis-at-arbingtoncom-3n5i</link>
      <guid>https://dev.to/kalobtaulien/how-we-use-apis-at-arbingtoncom-3n5i</guid>
      <description>&lt;p&gt;Let's talk about APIs. This is a subject I feel like every developer needs to know about. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this article we'll be talking about the API's we use at &lt;a href="https://arbington.com"&gt;Arbington.com&lt;/a&gt;, why we use them, and how they make our lives easier.&lt;/strong&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What's on the menu?
&lt;/h2&gt;

&lt;p&gt;Here's a list of API's we'll talk about in this article. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stripe for receiving payments&lt;/li&gt;
&lt;li&gt;MailChimp and Sendy.co for sending emails&lt;/li&gt;
&lt;li&gt;Airtable for slicing and dicing data and keeping track of tasks&lt;/li&gt;
&lt;li&gt;Dropbox for importing videos from server to server to bypass slow user upload speeds &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;boto3&lt;/code&gt; for AWS S3 management. &lt;/li&gt;
&lt;li&gt;CloudFlare for video streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  But first, what is an API?
&lt;/h3&gt;

&lt;p&gt;I'm going to avoid telling you what it stands for, because it doesn't matter. &lt;/p&gt;

&lt;p&gt;What does matter is how they work and why they exist. &lt;/p&gt;

&lt;p&gt;So.. computers have lots of different programming languages and different ways to communicate with each other. You're likely reading this article on dev.to using a standard browser, which uses the HTTP protocol to send and receive data. (That's an oversimplification) &lt;/p&gt;

&lt;p&gt;With all that variation from computer to computer comes the need to be able to talk to each other, make requests from other computers, and ask them to do things for us. &lt;/p&gt;

&lt;h3&gt;
  
  
  What you need to know.
&lt;/h3&gt;

&lt;p&gt;API's have different ways to make requests. The most common for us is a RESTful API. That means we make explicit requests to a certain computer (called an endpoint) and sometimes pass data to that endpoint to guide the other computer in its task. &lt;/p&gt;

&lt;p&gt;These often look like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET&lt;/code&gt; requests. They GET information and are typically read-only. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST&lt;/code&gt; requests. They SEND information in other to create some data on another computer &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE&lt;/code&gt; requests. They DELETE information on another computer. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT/PATCH&lt;/code&gt; requests. They make updates to existing information on another computer. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have a rad 40 minute course that goes into more depth about RESTful APIs on Arbington. &lt;a href="https://arbington.com/courses/restful-apis-and-how-to-understand-apis/"&gt;Check it out here.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Payments with Stripe
&lt;/h3&gt;

&lt;p&gt;Hands down the best API I've ever used. It's simple, supports lots of languages and most importantly the documentation is easy to ready and search through. &lt;/p&gt;

&lt;p&gt;While they offer a bunch of no-code solutions, we prefer to get our hands dirty and handle payments directly. By getting in there and using the Stripe API, we can create subscriptions on the fly when a user does a thing (clicks a page or fills out a form, for instance), and modify existing prices with coupon codes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stripe makes life better because...&lt;/strong&gt;&lt;br&gt;
We can accept one-time payments and monthly subscriptions with just a few lines of code. And it's secure! No storing credit card information on our servers and that's great because it's one less thing we need to deal with. &lt;/p&gt;

&lt;h3&gt;
  
  
  Email with Mailchimp
&lt;/h3&gt;

&lt;p&gt;We aren't using this A LOT but we've used it a handful of times to take lists of users that have opted in to our mailing list, and put them all into a Mailchimp list. &lt;/p&gt;

&lt;p&gt;We do the same with Sendy.co. We also host our own campaign management system called Sendy - it uses Amazon SES and gives us 50,000 free emails per day. It comes with a very light endpoint, but not API client - so we wrote our own using Python and the &lt;code&gt;requests&lt;/code&gt; Python package. &lt;/p&gt;

&lt;p&gt;If you've ever gotten an email from us, chances are you went through this API process to send data from our website to our email sending website where the team can write dedicated emails and updates to you. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mailchimp and Sendy.co makes life better because...&lt;/strong&gt;&lt;br&gt;
We can easily send emails to people expecting to hear from us. &lt;/p&gt;

&lt;h3&gt;
  
  
  Data analysis and collection with Airtable
&lt;/h3&gt;

&lt;p&gt;My second favorite tool: Airtable. We use &lt;a href="https://airtable-python-wrapper.readthedocs.io/en/airtable-python-wrapper/"&gt;airtable-python-wrapper&lt;/a&gt; to make basic API requests to send data to Airtable for internal use (like tracking courses) and occasionally to pull data down from Airtable. &lt;/p&gt;

&lt;p&gt;In the last post I talked about scraping 10s of thousands of data points and putting them in Airtable. Well, occasionally we need to pull that data out - so we use their API for that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Airtable makes life better because...&lt;/strong&gt;&lt;br&gt;
It's easier than Google Sheets, has a nice API to work with huge amounts of data, and it's easier to work with the data once it's in Airtable than using Excel. (But it's pricy for big teams with big data) &lt;/p&gt;

&lt;h3&gt;
  
  
  Files with Dropbox
&lt;/h3&gt;

&lt;p&gt;My third favorite tool, but frankly their API is overly complicated. It's ultra powerful, but not very friendly for devs that are new to the Dropbox API. &lt;/p&gt;

&lt;p&gt;We use this to move files to and from servers. &lt;/p&gt;

&lt;p&gt;Have you ever had to upload a video and it took AGES to finish? &lt;/p&gt;

&lt;p&gt;We have also run into that. And it sucks. It's a lot of waiting around and slowing down your internet so you can't do very much while it's happening. &lt;/p&gt;

&lt;p&gt;Thankfully I have gig internet - aka super fast lightning power mode internet - so I can upload insanely fast. And I put everything into Dropbox. &lt;/p&gt;

&lt;p&gt;Using the Dropbox API my team can click through the folders (on our site, not on Dropbox.com) and import entire folders worth of content. &lt;/p&gt;

&lt;p&gt;It creates a unique download link for each video and then a background server can download the file and upload it to wherever it needs to go. In this case, it goes to S3 or CloudFlare. More on those in just a second. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dropbox makes life better because...&lt;/strong&gt;&lt;br&gt;
It lets us move large video files from one server to another without human interference. It makes slow uploads a non-problem for us. &lt;/p&gt;

&lt;h3&gt;
  
  
  More files with AWS S3
&lt;/h3&gt;

&lt;p&gt;Ok, I'm not the biggest fan of S3. Frankly, it's expensive compared to other solutions. But it's also one of the oldest unlimited object stores out there and has a decent API. We use &lt;code&gt;boto3&lt;/code&gt; (a Python package) to upload files to S3, and to securely download them too. &lt;/p&gt;

&lt;p&gt;Once a Dropbox file is put into S3, we get a unique URL for video. Then we use CloudFlare Stream's API to copy the video to CloudFlare Stream, where they'll transcode the video and store it for us. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S3 makes life better because...&lt;/strong&gt;&lt;br&gt;
We can store unlimited files in there and securely pull out files when we need them. &lt;/p&gt;

&lt;h3&gt;
  
  
  Video streaming with CloudFlare Stream
&lt;/h3&gt;

&lt;p&gt;CloudFlare Stream is how we host our videos. It's powerful, relatively inexpensive and handles a lot of video encoding pain points we didn't want to handle in the early days. &lt;/p&gt;

&lt;p&gt;And it comes with a "copy" feature - pass it a URL and it'll download the video. So we pass it an S3 or Dropbox URL and it magically appears in CloudFlare Stream. &lt;/p&gt;

&lt;p&gt;We use plain Python and the &lt;code&gt;requests&lt;/code&gt; library to make this happen. &lt;/p&gt;

&lt;p&gt;Then we have a background server polling CloudFlare for updates to tell us when a video is done encoding and it's ready for playback. (Or if there was an error) &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CloudFlare makes life better because...&lt;/strong&gt;&lt;br&gt;
Honestly, I'm a HUGE fan of CloudFlare. Use them for as much as you can! But CloudFlare Stream makes video encoding super easy and we don't have to worry about a custom video player.&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal APIs
&lt;/h3&gt;

&lt;p&gt;We have a lot of endpoints that can only be accessed through Ajax/Fetch requests using JavaScript. These use RESTful API methods: GET to get data, POST to create data, and DELETE to delete data. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Internal APIs make life better because...&lt;/strong&gt;&lt;br&gt;
We can use JavaScript to change/add/delete data without refreshing the page. Some pages are heavy with assets and queries, and this lets the user take an action without reloading the page. &lt;/p&gt;

&lt;h2&gt;
  
  
  Master APIs
&lt;/h2&gt;

&lt;p&gt;I actually have a best selling course to teach you about RESTful APIs. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://arbington.com/courses/restful-apis-and-how-to-understand-apis/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UYGHtKnX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9q6v0ypu79i9od0erxxb.jpg" alt="Restful API crash course" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn all the things!
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://arbington.com/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nKoazo5s--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mr8ujryc524ygu92qbcz.png" alt="Arbington.com" width="880" height="185"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;APIs are important to learn, but so is learning a solid programming language like Python or JavaScript (or Java, C, C#, etc). &lt;/p&gt;

&lt;p&gt;Whichever programming language you think you should learn, take a look for those courses on &lt;a href="https://arbington.com/categories/subcategory/web-development/"&gt;Arbington.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Up next...
&lt;/h2&gt;

&lt;p&gt;Let's talk about handling payments with Stripe, and why you should 100% use Stripe instead of any other service. &lt;/p&gt;

</description>
      <category>startup</category>
      <category>api</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Automate everything... until you can't. </title>
      <dc:creator>Kalob Taulien</dc:creator>
      <pubDate>Tue, 23 Nov 2021 01:43:44 +0000</pubDate>
      <link>https://dev.to/kalobtaulien/automate-everything-until-you-cant-38h3</link>
      <guid>https://dev.to/kalobtaulien/automate-everything-until-you-cant-38h3</guid>
      <description>&lt;p&gt;Lots of people talk about tech taking their jobs and automating humans out of a job. &lt;/p&gt;

&lt;p&gt;And while that's sometimes true, there are a few subjects where people can't be replaced.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is an article about how we use tech to automate big tasks at &lt;a href="https://arbington.com"&gt;Arbington.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But, once again, not everything can be automated (or can be automated but very poorly). &lt;/p&gt;

&lt;h2&gt;
  
  
  Automating big tasks
&lt;/h2&gt;

&lt;p&gt;At Arbington.com we deal with a lot of scale. We have over 49,000 videos, over 4,500 hours of content, over 1,500 courses and lists of 10's of thousands of businesses, teachers and students to reach out to. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I asked you to manually gather a list of 40,000 businesses in North America, could you compile that list with contact details in less than 3 days? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer to the above question is obviously &lt;strong&gt;no&lt;/strong&gt;. People just can't operate that fast. &lt;/p&gt;

&lt;p&gt;But computers can. &lt;/p&gt;

&lt;p&gt;Using &lt;strong&gt;Python&lt;/strong&gt; and less than 50 lines of code I was able to find business listing sites all over the web, scrape them, and collect data from each page. &lt;/p&gt;

&lt;p&gt;This is all free information that's accessible to everybody. It's just A LOT of information.&lt;/p&gt;

&lt;p&gt;And computers are good at doing one task over and over, for as long as they have reason to continue doing it. Whether that's scraping, checking if a site is down, or serving a website to thousands of views per minute. &lt;/p&gt;

&lt;h3&gt;
  
  
  Tools we use
&lt;/h3&gt;

&lt;p&gt;Instead of hiring a small army of people to collect all the data we wanted, we wrote a small Python script that uses &lt;code&gt;requests&lt;/code&gt; and Beautiful Soup 4 to get the page and parse the HTML. Then we used simple &lt;code&gt;for&lt;/code&gt; loops to loop through all the data, and a handful of &lt;code&gt;if&lt;/code&gt; statements to validate some basic data. &lt;/p&gt;

&lt;p&gt;Then we put all that finalized data into a huge Python list and used &lt;a href="https://airtable-python-wrapper.readthedocs.io/en/airtable-python-wrapper/"&gt;&lt;code&gt;airtable-python-wrapper&lt;/code&gt;&lt;/a&gt;,&lt;br&gt;
Python and Airtable to bulk insert data into one of our tables. &lt;/p&gt;

&lt;p&gt;The whole process took about 20 minutes to write code (and solve little bugs that came up with inconsistent data) and about 3 hours to run. &lt;/p&gt;

&lt;p&gt;Once the code was written, we pointed it at a website and said, "Fly my beautiful butterfly, fly". &lt;/p&gt;

&lt;p&gt;And then we waited. &lt;/p&gt;

&lt;p&gt;If there's enough demand, maybe I'll post one of our scraping scripts to show you how we created a bot to gather and parse data, and put it into a useable table on Airtable. Leave a comment below if that interests you. &lt;/p&gt;

&lt;h3&gt;
  
  
  Learn Python. It's easy, and fun!
&lt;/h3&gt;

&lt;p&gt;As a side note, if you're not familiar with Python you might want to consider learning it. It's the worlds #1 most popular coding language now. &lt;/p&gt;

&lt;p&gt;And at Arbington.com we &lt;a href="https://arbington.com/search/?q=python"&gt;have over 35 python courses&lt;/a&gt;. Take them all for free with a 14 day free trial and then it's just $15/month after that. For 35 courses on Udemy that's going to be over $350. I'll let you do the math and comparison on that 😉 &lt;/p&gt;

&lt;h3&gt;
  
  
  Human data is messy though
&lt;/h3&gt;

&lt;p&gt;People, AKA: humans, are messy. We don't format phone numbers or email addresses the in a standardized way. People write:&lt;br&gt;
&lt;code&gt;test at gmail.com&lt;/code&gt;, &lt;code&gt;test @ gmail . com&lt;/code&gt;, &lt;code&gt;test [at] gmail [dot] com&lt;/code&gt;, and about a zillion other ways of trying to avoid spam bots from collecting their email addresses, phone numbers, business names, addresses, and so on. &lt;/p&gt;

&lt;p&gt;First, we had to find a few directories that had relatively clean data in a consistent format. &lt;/p&gt;

&lt;p&gt;Then we put all the data in Airtable and found the outliers with a simple filter and search. That looks like filtering for &lt;code&gt;" "&lt;/code&gt; (a space) in an email address, for example. &lt;/p&gt;

&lt;p&gt;Then, manually, we went and cleaned up the data so it was consistent for the entire team. From there, it became a people-focused task: emailing prospects one by one and answering questions. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We literally have hundreds of thousands of contacts now. And 95% of the data was collected through automated methods.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What would have taken a team of people MONTHS to achieve, took us a matter of days. &lt;/p&gt;

&lt;h2&gt;
  
  
  We still need people
&lt;/h2&gt;

&lt;p&gt;Once we had all the data from our automated tasks, we needed to fill the gaps. &lt;/p&gt;

&lt;p&gt;Not every business lists a phone number, email address or physical address. Not every portfolio website has an email address. And when they do, it's formatting incorrectly. &lt;/p&gt;

&lt;p&gt;This is where people come in. &lt;/p&gt;

&lt;p&gt;Instead of trying to code an automated tool that could account for every type of email address (including images) we simply said, "humans are better for this." &lt;/p&gt;

&lt;p&gt;Humans have unparalleled pattern recognition. We can match an email address just by looking at it without reading it. Even with all the variations of email addresses out there. &lt;/p&gt;

&lt;p&gt;So we went and manually collected the missing data. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;People are simple better at tasks that involve creativity or advanced pattern recognition. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Could we have automated this? Absolutely. But it'd have taken us a long time to create a cool tool that would ultimately be thrown away. &lt;/p&gt;

&lt;h3&gt;
  
  
  Opportunity happens when people connect
&lt;/h3&gt;

&lt;p&gt;The next big hurdle that tech couldn't solve was a simple conversation with our potential business partners. &lt;/p&gt;

&lt;p&gt;We couldn't just email 40,000 businesses with one message. Businesses are unique, like people, and we needed to cater to each business differently. &lt;/p&gt;

&lt;p&gt;Again, this is where people come in. &lt;/p&gt;

&lt;p&gt;People can handle objections, consider situations, understand when to sell and when to back off, and customize each response to be friendly and helpful. &lt;/p&gt;

&lt;p&gt;Automation can't do that. &lt;/p&gt;

&lt;p&gt;Yes, of course it's a lot more work to hire a team of people to do this, but the end result is a much higher ROI than if we automated everything. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Automation can't replace people&lt;/strong&gt; - that's the point I'm driving here. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When it comes to communication, creativity and empathy we simply cannot automate most of that (some exceptions apply, of course) &lt;/p&gt;

&lt;h2&gt;
  
  
  Should you fear losing your job as a dev, or being automated out before you land a job as a developer?
&lt;/h2&gt;

&lt;p&gt;Nope. Absolutely not. &lt;/p&gt;

&lt;p&gt;Sure, there are lots of no-code solutions out there. And when starting a startup, definitely take that approach! It'll save you a lot of pain of coding your own solutions, dealing with bugs and edge cases that users bring up. &lt;/p&gt;

&lt;p&gt;But at the end of the day, your app/website/business has custom logic that likely can't be completely automated and will absolutely require human input. &lt;/p&gt;

&lt;p&gt;Maybe in 2100 we'll have to open this conversation again, but for now you're safe as a developer. &lt;/p&gt;

&lt;p&gt;For now, you can learn all your automation coding needs on &lt;a href="https://arbington.com/"&gt;Arbington.com&lt;/a&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;💴 $15/month&lt;/li&gt;
&lt;li&gt;🏫 14 day free trial &lt;/li&gt;
&lt;li&gt;👩‍🏫 1,500+ courses &lt;/li&gt;
&lt;li&gt;🔥 Certificate of Completion included in every premium courses&lt;/li&gt;
&lt;li&gt;Check out &lt;a href="https://airtable.com"&gt;Airtable.com&lt;/a&gt; - we love this service so much we don't even want to get paid for referring them. ♥️ &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next? API's!
&lt;/h2&gt;

&lt;p&gt;In the next article I'll talk about the API's we use, how we use them, and why we use them. It'll be pretty dev-heavy - so if web development is your cup of tea, stick around for that one. &lt;/p&gt;

</description>
      <category>startup</category>
      <category>performance</category>
      <category>scale</category>
      <category>python</category>
    </item>
  </channel>
</rss>
