<?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: Matthew Cale</title>
    <description>The latest articles on DEV Community by Matthew Cale (@mattcale).</description>
    <link>https://dev.to/mattcale</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%2F145918%2F050a51ab-7006-4a81-bb90-e8806142b86f.jpeg</url>
      <title>DEV Community: Matthew Cale</title>
      <link>https://dev.to/mattcale</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mattcale"/>
    <language>en</language>
    <item>
      <title>Go</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Thu, 27 Mar 2025 03:49:38 +0000</pubDate>
      <link>https://dev.to/mattcale/go-476i</link>
      <guid>https://dev.to/mattcale/go-476i</guid>
      <description></description>
      <category>emptystring</category>
    </item>
    <item>
      <title>FDLD - Fatigue Driven Lack of Development</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Mon, 06 Jan 2025 22:39:05 +0000</pubDate>
      <link>https://dev.to/mattcale/fdld-fatigue-driven-lack-of-development-2deb</link>
      <guid>https://dev.to/mattcale/fdld-fatigue-driven-lack-of-development-2deb</guid>
      <description>&lt;h2&gt;
  
  
  What Is This?
&lt;/h2&gt;

&lt;p&gt;This is an article that takes a look at the reasons developers might feel too fatigued to start researching something new and what I did to solve some of these issues. The specific solutions may or may not be useful to your use case, but I do have a suspicion that this sense of fatigue may be pervasive enough in our industry that on some level the themes will connect with a good many developers. &lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I whine in this article. I am also solution oriented I think, &lt;strong&gt;but&lt;/strong&gt;  still... the whine in this article is strong. If you have an (understandable) aversion to whining you've been warned!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Not all of the problems or solutions in this article will make sense to you&lt;/strong&gt;. I swear this comes from a place of reasonable competence with technology and I'd probably be happy to discuss the reasons why I went with particular solutions,  but I likely won't take the time to address it in the article itself because &lt;strong&gt;a point by point comparison of potential solutions to these problems isn't what I'm interested in here.&lt;/strong&gt; What I am interested in addressing is the larger theme of how small annoyances if left unaddressed can pile up to a point where something that was once fun no longer is.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Very Familiar Story 📖
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Hi Im Matt the developer 👾, and I just saw that &lt;a href="https://deno.com/blog/v2.0" rel="noopener noreferrer"&gt;Deno hit 2.0&lt;/a&gt; and I read the blog and &lt;strong&gt;boy-oh-boy it looks neato-toledo&lt;/strong&gt;! Well, at my job I only use Python and Node and the powers that be (you know silly people with odd amounts of cash) have no interest in me using an unproven, semi-unknown coding language on their very expensive production servers and I can't think of an internal tool I could justify using it on (I probably could I'm very creative but you get the point). Well what do I do to get myself interested in using this new very cool looking piece of tech 🤨 I know! I'll make a side project... And there it is... &lt;strong&gt;the fatigue&lt;/strong&gt; 😱&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are anything like me when you make a test/toy project you don't &lt;em&gt;intentionally&lt;/em&gt; make it poorly. You try to think of your project, no matter how &lt;strong&gt;toy-ish&lt;/strong&gt; as a &lt;strong&gt;real&lt;/strong&gt; piece of software. This is a practice reinforced by many of the teachers I respect and the tools these days sort of push you in this direction anyway, but then you end up in the following traps that lead me, and maybe you too, to saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ehhh I'm not even gonna bother...&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For me the following internal conversation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Oh &lt;code&gt;&amp;lt;insert-technology-here&amp;gt;&lt;/code&gt; looks really cool. Maybe I'll make a little project with it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Oh yeah that's right making the sorts of toy projects that I'm interested in with &lt;code&gt;&amp;lt;insert-technology-here&amp;gt;&lt;/code&gt; is gonna lead to me dealing with &lt;code&gt;&amp;lt;see-traps-below&amp;gt;&lt;/code&gt;. I won't even bother.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;has become so commonplace that I have found my passion for technology in general diminishing and that's &lt;strong&gt;sad&lt;/strong&gt;. As any sort of professional in any field knows, the day in and day out of a job is &lt;strong&gt;never always fun&lt;/strong&gt;. So what keeps us from disliking our jobs is the experience of personal growth and mastery in our craft, and when obstacles consistently arise that block these edifying experiences you can look up and find that a job you used to be passionate about has somehow beneath your feet become mundane and soul-sucking. No one wants this! So let's talk it through and see if we can figure out what exactly these issues are &lt;strong&gt;and&lt;/strong&gt; see if we can create something to counteract the passion sapping issues that prevent me (and maybe you too) from learning about what's happening in the genuinely exciting field of technology. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Traps 🪤
&lt;/h2&gt;

&lt;p&gt;So what are these recurring issues anyway? Well for &lt;strong&gt;me&lt;/strong&gt; there are a few broad categories. Since the ideas here are meant as a basis for solutions rather than the core of this article I'll likely just gloss them, but the issues here may be familiar to you and so you likely don't need them explained to you in deep detail and if these aren't the exact same traps you are familiar with consider trying as I am to define what traps &lt;strong&gt;you are&lt;/strong&gt; experiencing and see if you can create solutions using a similar methodology. &lt;/p&gt;

&lt;p&gt;The Traps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tedium / Perfectionism&lt;/li&gt;
&lt;li&gt;Security / Financial Risk&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The Software Industry / Hucksterisms / Nonsense&lt;/em&gt; 🤣&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Tedium / Perfectionism Trap 😑
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: A lot of work goes into everything around a piece of technology that isn't the technology itself, but it is an "entry fee" to using it. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This first one is the one where I usually stop and go on a walk. &lt;/p&gt;

&lt;p&gt;Continuing on with the example above the process might look something like this: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oh look Deno 2.0 came out.&lt;/li&gt;
&lt;li&gt;Oh wow this seems cool I want to try out Deno now!&lt;/li&gt;
&lt;li&gt;What sort of toy project should I make 🤔&lt;/li&gt;
&lt;li&gt;Ummm... Well I am mostly a web dev so I will try out the &lt;a href="https://fresh.deno.dev/" rel="noopener noreferrer"&gt;Fresh 🍋&lt;/a&gt; framework to make something simple like an app where a user can log their mood (why not 🦀)&lt;/li&gt;
&lt;li&gt;Ok cool I have an idea let's fire up Zed (or VSCode 😴) and try this thing out 🛑&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stop Right Here&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Do you realize what you just signed up for for like the &lt;strong&gt;MILLIONTH time&lt;/strong&gt;? The first thing you are gonna do if you are new to this process is make a web page for logging a mood only to &lt;strong&gt;very&lt;/strong&gt; quickly realize that in order for this app to be meaningful it's going to need users, which means a place to store them, which means a database, which means passwords and authentication and authorization, and it means database setup scripts, and probably it means a docker compose config, and it means designing a schema no matter how simple, it also means migration processes for your database, I can go on and on I promise 😵‍💫&lt;/p&gt;

&lt;p&gt;So the first &lt;strong&gt;trap&lt;/strong&gt; for me is the following decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I accept that this toy app doesn't really make sense in the real world and I can't actually leverage a lot of the intent of the tool because the tool isn't MEANT to be used improperly and so my impression of the tool will never be complete because I didn't ACTUALLY try to use the tool as prescribed and instead hacked something together that has some very confusing sharp edges.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I create all the necessary plumbing for the &lt;strong&gt;MILLIONTH time&lt;/strong&gt; knowing that it's for a toy I don't intend to actually use and further knowing that none of the work in setting up even a very simple user management system from a database point of view translates to me getting familiar with the technology I actually found interesting in the first place!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've done both lots of times... Sometimes I strike the right balance of valid set up to learning about a new topic, but &lt;strong&gt;most&lt;/strong&gt; of the time I find myself going "Why I am setting up a User schema in a Postgres DB again? Oh yeah that's right Deno 2.0 was released... and me remembering how to declare tables in Postgres is... relevant... somehow"&lt;/p&gt;

&lt;h3&gt;
  
  
  The Tedium / Perfectionism Solution 💁‍♂️
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: Look for opportunities to automate "just enough" to remove the chores that suck the joy out of learning!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we have a pretty solid grasp on the kinda yucky choice laid out above... Well, how can we solve it?&lt;/p&gt;

&lt;p&gt;My brain very quickly says: Automate Something!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks 🧠 I agree!&lt;/strong&gt; But knowing what to automate and what not to is &lt;em&gt;kinda&lt;/em&gt; an art so let's think about what precisely I will find myself wanting very regularly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A containerized database of some sort Postgres is fine &lt;/li&gt;
&lt;li&gt;A table in said database with a users table properly configured for just about ANY application.

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt;, &lt;code&gt;updated_at&lt;/code&gt;, &lt;code&gt;activated_at&lt;/code&gt;,  &lt;code&gt;deactivated_at&lt;/code&gt;, &lt;code&gt;hash&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;first_name&lt;/code&gt;, &lt;code&gt;last_name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;phone_number&lt;/code&gt;, &lt;code&gt;country_code&lt;/code&gt;, &lt;code&gt;extra&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;With that schema I can probably get a decent way towards making any app&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Bolierplate statements in SQL for: Insert, Updating, Finding, and Removing (optional) users&lt;/li&gt;

&lt;li&gt;Scripts to backup and restore the database instance. &lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;With these desires in mind I created &lt;a href="https://github.com/matty-cakes/users-table" rel="noopener noreferrer"&gt;matty-cale/users-table&lt;/a&gt; which is a very portable Makefile and a couple of SQL scripts thats will &lt;strong&gt;hopefully&lt;/strong&gt; strike a balance ⚖️ for me that I find useful. In total it's about 70 LOC in a Makefile and the SQL is about 10 LOC. Pretty small. You should be able to grok pretty much all of it in about 15 minutes which I think saves you about 10 minutes of dev time the first time and potentially more the more you use it. &lt;/p&gt;

&lt;p&gt;This doesn't solve your auth boilerplate, but that's gonna be driven by your code and is an exercise you can't get away from regardless, BUT at least you don't have to worry about the following chores anymore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up shell scripts to automate the creation of your DB&lt;/li&gt;
&lt;li&gt;Creating SQL statements for creating the users table&lt;/li&gt;
&lt;li&gt;Creating SQL statements for inserting users into the users table&lt;/li&gt;
&lt;li&gt;Creating scripts to back up or restore a database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope this inspires you to look for the tedious chores that keep &lt;strong&gt;you&lt;/strong&gt; from starting a project and automate them away using &lt;strong&gt;simple and portable solutions!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Security / Financial Risk Trap 💰
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: Home networks are error prone and insecure, and Cloud Services cruelly don't like to make billing transparent or simple to control (because they are greedy).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok, cool so with one or more little automations taking care of the tedium problem what else consistently blocks me from trying out some new piece of technology?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment!&lt;/strong&gt; So when I create a project no matter how simple &lt;strong&gt;I want to put that thing on the internet&lt;/strong&gt; and there has never been a better time to "just get something out there" than now, &lt;strong&gt;BUT&lt;/strong&gt; the world doesn't (typically) cater to the little guy (we lack money and that makes people uninterested it seems). What am I talking about most specifically? &lt;/p&gt;

&lt;p&gt;Spend limits! &lt;/p&gt;

&lt;p&gt;What I mean by this is a VERY simple feature that states something to the tune of "If my bill reaches X value please unplug all my services" until I manually address it. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; Could this heavy handed feature possibly hurt large apps? &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Sure, but you wouldn't have to turn it on.  &lt;/p&gt;

&lt;p&gt;However none of the big guys offer this obviously simple feature and what's more even though there are loads of posts on the internet about this topic they seemingly never call out that it's a highly requested feature and this drives me nuts! Here are some random way you can find out how the big guys address this issue.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/35352075/does-aws-cloud-provides-an-option-to-cap-the-billing-amount" rel="noopener noreferrer"&gt;AWS&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.reddit.com/r/googlecloud/comments/wupv7s/comment/ilb7nz6/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button" rel="noopener noreferrer"&gt;GCP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.reddit.com/r/digital_ocean/comments/ey91ix/comment/fgmspuy/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button" rel="noopener noreferrer"&gt;DigitalOcean (kind of a medium guy)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what else can we do? Well, maybe we could host it from an extra laptop we have sitting around and then make sure that we REALLY understand network security because we are about to open up our home network to everyone on the planet 😵‍💫&lt;/p&gt;

&lt;h3&gt;
  
  
  The Security / Financial Risk Solution 💁‍♂️
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: Use &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;fly.io&lt;/a&gt; with pre-paid credits.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This one was actually really simple... for me at least...&lt;/p&gt;

&lt;p&gt;So, for the big guys, if this is your preference for several very understandable reasons, both GCP and AWS allow you to automate this process by round about means where you can use one service to monitor your billing and then another service / set of services to perform operations that take your services down. This definitely feels like a middle finger to users but there you are.&lt;/p&gt;

&lt;p&gt;However as of this writing I did find one really terrific solution that works really well for me trying to launch projects in a safe and understandable way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's: &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;fly.io&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.fly.io/t/how-can-i-place-a-billing-limit-on-my-account/4267/2" rel="noopener noreferrer"&gt;They have pay ahead billing (starting at $25)&lt;/a&gt;. The peace of mind that I could likely run for a very long time enjoying all of the services I want to try out for this one time cost (&lt;strong&gt;yay one time costs&lt;/strong&gt;) is incredibly valuable to someone of my disposition. And if you run out? Well, yeah they shut down your stuff, but they won't just let you rack up an enormous bill that you then have to beg them to remove if your toy app ever gets attacked by some jerk, or (a more likely story) you accidentally allow some script you didn't really understand to create a bunch of really expensive operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fly.io" rel="noopener noreferrer"&gt;fly.io&lt;/a&gt;, while not as feature rich as AWS or GCP provides everything I (and likely you) need to deliver production ready experiences if your side project ever becomes something you want to &lt;strong&gt;really&lt;/strong&gt; try out and I'm supremely grateful for it. Thanks &lt;a href="https://fly.io" rel="noopener noreferrer"&gt;fly.io&lt;/a&gt; and feel free to send me swag 😉&lt;/p&gt;

&lt;h3&gt;
  
  
  The Software Industry / Hucksterisms / Nonsense Trap 🤡
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: The software industry is changing. The way we work and how we are managed is changing. It can be hard to get excited about growing as a technologist in this environment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok, so the final trap is something that has become more noticeable in the last few years for me in the industry. There is a general sense of anxiety about what we (software developers) do and how we do it. This anxiety is fed by several different factors: impending AI industry takeover, financial pressures on specific software companies, large scale economic issues, and natural developments that lead to software companies becoming more like traditional companies as time moves on and technology becomes better understood and therefore more systematically monetized.&lt;/p&gt;

&lt;p&gt;Any one of these elements may, on any given day, be louder or quieter, but the overall effect is the same. Our industry and therefore our way of life is changing. I count myself incredibly lucky to have come into the field when I did. I came in at a time when many companies were trying to launch their first attempts at a SaaS offering and there was so many unknowns that the "Research" side of the "Research and Development" departments were given a great deal of deference. This is not the feeling I have about the industry as it stands now. &lt;/p&gt;

&lt;p&gt;The most popular large scale web apps while still vastly unique in their composition and quality do seem to be coalescing around particular product principles that do seem to have real staying power. This shift away from (more) equal parts Research and Development, and towards a much greater emphasis on Development means that much of the joy of discovery and the personal satisfaction of finding a novel solution to a problem is fading. This is sad for those of us who see our jobs as both Researchers and Developers. But what are we to do?&lt;/p&gt;

&lt;h3&gt;
  
  
  The Software Industry / Hucksterisms / Nonsense Trap
&lt;/h3&gt;

&lt;p&gt;💁‍♂️&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TLDR: Keep your eyes open for what inspires you and allow yourself the space to reflect and fix what's really bugging you. Maybe all the small things you fix will create the world you want to be in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So how do we overcome this issue of the industry changing and no longer valuing the same sorts of behaviors that it previously valued? &lt;strong&gt;Honestly, I don't know.&lt;/strong&gt; I don't think there is anything for it. The future is coming and the only thing we can ever say for certain is that tomorrow will be different than today. I know this is not really a solution, but at least it's a human's honest assessment (and that can feel rare these days). &lt;/p&gt;

&lt;p&gt;I think that something that helped me was writing this article. I was so inspired and interested in the work that went into Deno 2.0 and &lt;strong&gt;I was so saddened by the realization that due to my fatigue I wasn't even going to try it out&lt;/strong&gt; that I got a chance to reflect here on why I feel this way. Sometimes it's that I just need to take 45 minutes to an hour to write a Makefile so I can remove the elements of learning that have become mundane and annoying. Sometimes it's that I need to do more research on what product offerings are out there that fit my needs. Sometimes it's that I need to be inspired enough by my peers that I take a second to investigate my apathy and fatigue and try to solve it. &lt;/p&gt;

&lt;p&gt;For now, if you need me I'm gonna be seeing if I can scrap together something fun using Deno and Fresh, and trying to keep my chin up as I wait to see what the future holds. Stay safe out there and be open to being inspired.&lt;/p&gt;

&lt;p&gt;Credits: &lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@philipsfuture?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Philip Oroni&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-blue-object-with-a-wavy-design-on-it-pyLYcOvX7sQ?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>growth</category>
      <category>reflections</category>
      <category>hobbies</category>
      <category>coding</category>
    </item>
    <item>
      <title>PyEnv &amp; Poetry - BFFs 💖</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Sat, 27 May 2023 17:51:01 +0000</pubDate>
      <link>https://dev.to/mattcale/pyenv-poetry-bffs-20k6</link>
      <guid>https://dev.to/mattcale/pyenv-poetry-bffs-20k6</guid>
      <description>&lt;h2&gt;
  
  
  What is this?
&lt;/h2&gt;

&lt;p&gt;This is a resource made, admittedly mostly for myself, that will allow me to recall a method of Python dev environment management &lt;strong&gt;I don't dislike&lt;/strong&gt;. It covers the use of two distinct but important Python environment helpers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PyEnv (&lt;a href="https://github.com/pyenv/pyenv"&gt;Docs&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;Uses path shims to help you manage several versions of Python simultaneously.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Poetry (&lt;a href="https://python-poetry.org/"&gt;Docs&lt;/a&gt;)

&lt;ul&gt;
&lt;li&gt;A dependency manager that feels similar in my approximation to a tool like &lt;code&gt;yarn&lt;/code&gt; or &lt;code&gt;npm&lt;/code&gt; from the Node world, and automates certain tasks (venv creation and activation for example).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why make this / why read this?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You find that managing Python projects in a clean, repeatable, and predictable way is less simple (or less fun) than you have found the process to be in other languages. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How do I use / read this?
&lt;/h2&gt;

&lt;p&gt;This is a technical guide not an in depth explanation (though that may be forthcoming) and so I expect this guide to be used primarily as a way to kick start your memory on how to set up Python projects in a way you don't dislike. Best of luck 🍀&lt;/p&gt;




&lt;h2&gt;
  
  
  Pre-Reqs 🫸
&lt;/h2&gt;

&lt;p&gt;These steps are to be done once per machine and if you've already accomplished these steps you may skip this section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install PyEnv &amp;amp; A Modern Python Version 🐍
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew update
brew &lt;span class="nb"&gt;install &lt;/span&gt;pyenv
pyenv &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# pyenv 2.3.15&lt;/span&gt;

pyenv &lt;span class="nb"&gt;install &lt;/span&gt;3.10.7
&lt;span class="c"&gt;# Wait for a bit for install to finish...&lt;/span&gt;

pyenv shell 3.10.7
python &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="c"&gt;# Python 3.10.7 🎉&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Optional: Set A System Wide Python Version&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyenv global 3.10.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install Poetry ✍️
&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://install.python-poetry.org | python3 -
poetry &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Optional: Tell poetry to create virtual environments in the current project directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry config virtualenvs.in-project &lt;span class="nb"&gt;true
&lt;/span&gt;poetry config virtualenvs.in-project
&lt;span class="c"&gt;# true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Steps 🧭
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Make a new project directory
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;Desktop/Code/personal/python
&lt;span class="nb"&gt;mkdir &lt;/span&gt;planet-express-api
&lt;span class="nb"&gt;cd &lt;/span&gt;planet-express-api 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Set a Python version for this project directory
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyenv &lt;span class="nb"&gt;local &lt;/span&gt;3.10.7
python &lt;span class="nt"&gt;--version&lt;/span&gt; 
&lt;span class="c"&gt;# 3.10.7&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; .python-version
&lt;span class="c"&gt;# 3.10.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; This command will create a file that &lt;code&gt;pyenv&lt;/code&gt; looks for in the current working directory (the folder you are in) whose content will tell pyenv which Python version to use.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a poetry project
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Leave off the -n flag if you wish to add precise data &lt;/span&gt;
&lt;span class="c"&gt;# to the pyproject.toml file poetry creates.&lt;/span&gt;
poetry init &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;pyproject.toml
&lt;span class="c"&gt;# pyproject.toml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Initialize and start your Virtual Environment using poetry
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;poetry shell
&lt;span class="c"&gt;# Creating virtualenv planet-express-api&lt;/span&gt;
&lt;span class="c"&gt;# bash -c planet-express-api/.venv/bin/activate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Test it by adding a dependency
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Add a dependency&lt;/span&gt;
poetry add pendulum 

&lt;span class="c"&gt;# Start a Python REPL&lt;/span&gt;
python 

&lt;span class="c"&gt;# Use the dependency&lt;/span&gt;
import pendulum
now &lt;span class="o"&gt;=&lt;/span&gt; pendulum.now&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Europe/Paris"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
now.to_iso8601_string&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="c"&gt;# '2023-05-27T19:40:17.452958+02:00'&lt;/span&gt;
&lt;span class="c"&gt;# Use `ctrl + d` to exit the REPL &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Stop using the virtual environment
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Exit the virtual environment&lt;/span&gt;
deactivate

&lt;span class="c"&gt;# Start a Python REPL&lt;/span&gt;
python

&lt;span class="c"&gt;# Validate the dependency is not available&lt;/span&gt;
import pendulum
ModuleNotFoundError: No module named &lt;span class="s1"&gt;'pendulum'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: To get back into the virtual environment just use &lt;code&gt;poetry shell&lt;/code&gt; again.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this article you have used PyEnv and Poetry together to create a project in a desired version of Python (&lt;code&gt;pyenv&lt;/code&gt;) whose dependencies and virtual environment are managed by a single robust tool (&lt;code&gt;poetry&lt;/code&gt;) &lt;strong&gt;cheers to you&lt;/strong&gt; 🍻&lt;/p&gt;

</description>
      <category>python</category>
      <category>pyenv</category>
      <category>poetry</category>
      <category>environment</category>
    </item>
    <item>
      <title>Dockerize &amp; Backup A Postgres Database</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Wed, 17 Nov 2021 01:06:57 +0000</pubDate>
      <link>https://dev.to/mattcale/dockerize-backup-a-postgres-database-2b1l</link>
      <guid>https://dev.to/mattcale/dockerize-backup-a-postgres-database-2b1l</guid>
      <description>&lt;h2&gt;
  
  
  What is this?
&lt;/h2&gt;

&lt;p&gt;This is a technical guide for doing common management tasks with a Postgres database running in Docker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why make this?
&lt;/h2&gt;

&lt;p&gt;As a quick reference for taking database backups and restoring them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Run The Postgres Image
&lt;/h3&gt;

&lt;p&gt;Docker makes it incredibly easy to get going with a Postgres database with persistent storage. Let's try it out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's just run the Postgres container pointing its volume location to a spot on disk we like. For me that's: &lt;em&gt;~/docker/volumes/postgres&lt;/em&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
docker run &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--name&lt;/span&gt; pg-db &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;shiny_metal_pass &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-p&lt;/span&gt; 6543:5432 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres:/var/lib/postgresql/data &lt;span class="se"&gt;\&lt;/span&gt;
 postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Let's dissect this line by line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker run&lt;/code&gt; -- Runs a specified image (in our case it's &lt;code&gt;postgres&lt;/code&gt;, see last line of command). &lt;a href="https://docs.docker.com/engine/reference/run/" rel="noopener noreferrer"&gt;Source&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--name pg-db&lt;/code&gt; -- Sets the name of the container running the postgres image. &lt;a href="https://docs.docker.com/engine/reference/run/#name---name" rel="noopener noreferrer"&gt;Source&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-e POSTGRES_PASSWORD=shiny_metal_pass&lt;/code&gt; -- Sets an environment variable which will be the default password for the superuser. Note: This should be a secret 🤫. &lt;a href="https://hub.docker.com/_/postgres" rel="noopener noreferrer"&gt;Source&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt; -- Detach from the terminal instance. i.e. run in the background.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p 6543:5432&lt;/code&gt; -- Map the local machine's port &lt;code&gt;6543&lt;/code&gt; to the container's port &lt;code&gt;5432&lt;/code&gt;. So from our machine to connect we will use 6543 which in turn will hit the port in the container running on 5432.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v $HOME/docker/volumes/postgres:/var/lib/postgresql/data&lt;/code&gt; -- Map any data created in the container at &lt;code&gt;/var/lib/postgresql/data&lt;/code&gt; to a desired location on local disk: &lt;code&gt;$HOME/docker/volumes/postgres&lt;/code&gt;. &lt;a href="https://hub.docker.com/_/postgres" rel="noopener noreferrer"&gt;Source&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;postgres&lt;/code&gt; -- The name of the image in Docker hub we want to create a container from. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;When I run it I see the following&lt;/p&gt;&lt;/li&gt;

&lt;/ul&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%2Fi.ibb.co%2F2Y63BN4%2Fdt-pgdb-001-create-container.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%2Fi.ibb.co%2F2Y63BN4%2Fdt-pgdb-001-create-container.png" alt="create-container"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When I check our volume location (note: for me this was an empty location prior to invoking the command above) I see this:&lt;/li&gt;
&lt;/ul&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%2Fi.ibb.co%2FS5m3Bh1%2Fdt-pgdb-002-check-mount.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%2Fi.ibb.co%2FS5m3Bh1%2Fdt-pgdb-002-check-mount.png" alt="check-mount"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, let's see if we can connect to our database. I am using &lt;a href="https://tableplus.com/" rel="noopener noreferrer"&gt;TablePlus&lt;/a&gt; but the same concepts apply with any general purpose database IDE or &lt;code&gt;psql&lt;/code&gt; (&lt;a href="https://www.postgresql.org/docs/13/app-psql.html" rel="noopener noreferrer"&gt;found here&lt;/a&gt;). For me the connection looks like this:&lt;/li&gt;
&lt;/ul&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%2Fi.ibb.co%2Ftx1DZZr%2Fdt-pgdb-003-connect-sql.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%2Fi.ibb.co%2Ftx1DZZr%2Fdt-pgdb-003-connect-sql.png" alt="connect-sql"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;And when we connect we can run the following to get a lay of the land.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- From a SQL Editor (PSQL / TablePlus Session)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;datname&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_database&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- RESULTS:&lt;/span&gt;
&lt;span class="c1"&gt;-- postgres&lt;/span&gt;
&lt;span class="c1"&gt;-- template1&lt;/span&gt;
&lt;span class="c1"&gt;-- template0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create Some Persistent Data
&lt;/h3&gt;

&lt;p&gt;So, we've got a database! What now? &lt;strong&gt;Well let's store some data in it!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start by creating a new database called &lt;code&gt;todo_it_well&lt;/code&gt;. You guessed it this, YATA (&lt;em&gt;yet another todo app&lt;/em&gt;). This time we are doing it in SQL later we will also show you how to use the &lt;code&gt;createdb&lt;/code&gt; tool.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- From a SQL Editor&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;DATABASE&lt;/span&gt; &lt;span class="n"&gt;todo_it_well&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- Query 1 OK: CREATE DATABASE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Switch to our new database. For me, in TablePlus, this just means editing my connection to use &lt;code&gt;todo_it_well&lt;/code&gt; instead of &lt;code&gt;postgres&lt;/code&gt; for the chosen database.&lt;/li&gt;
&lt;/ul&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%2Fi.ibb.co%2FLdt7ybj%2Fdt-pgdb-004-connect-todo-sql.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%2Fi.ibb.co%2FLdt7ybj%2Fdt-pgdb-004-connect-todo-sql.png" alt="connect-todo-sql"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next, create some tables. We will, for this demonstration, create a &lt;code&gt;users&lt;/code&gt; table and &lt;code&gt;tasks&lt;/code&gt; table so that users can track their tasks or "todos". The only &lt;em&gt;almost&lt;/em&gt; complex bit of this is declaring a relationship between tasks and users. This post is not about SQL so don't think too hard on these commands for now just know that they make a viable todo application.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- From a SQL Editor&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"user"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
   &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
   &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nv"&gt;"password"&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;display_name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"task"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
   &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
   &lt;span class="n"&gt;owner_id&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;completed_on&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;removed_on&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;fk_owner&lt;/span&gt; 
    &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;owner_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="nv"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- Query 1 OK: CREATE TABLE&lt;/span&gt;
&lt;span class="c1"&gt;-- Query 2 OK: CREATE TABLE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Before we finish this step let's create some real data in here! Let's insert some users first and then some tasks for them!
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- From a SQL Editor&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="nv"&gt;"user"&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"display_name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'matt@email.fun'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password-gasworld'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'matt-the-magic-monkey'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'jennie@yahoo.fun'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'password-sassworld'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'dat-girl-jen'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'timothy24@email.fun'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'pw-vw'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'yo-boi-tom-o-tee'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;-- users created with ids: 1, 2 and 3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next, the tasks:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- From a SQL Editor&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="nv"&gt;"task"&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"owner_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;VALUES&lt;/span&gt; 
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'read this awesome post'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'tech'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'do dishes'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'read chapter of lotr'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'lit'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'sign up to volunteer'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'call brother'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'make grocery list'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'health'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'rake leaves'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'house'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Validate that our data looks as expected:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- From a SQL Editor&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
   &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
   &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
   &lt;span class="nv"&gt;"user"&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; 
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;
   &lt;span class="nv"&gt;"task"&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
   &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
   &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completed_on&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- RESULTS:&lt;/span&gt;
&lt;span class="c1"&gt;-- display_name description&lt;/span&gt;
&lt;span class="c1"&gt;-- dat-girl-jen read chapter of lotr&lt;/span&gt;
&lt;span class="c1"&gt;-- dat-girl-jen sign up to volunteer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create A Backup
&lt;/h3&gt;

&lt;p&gt;So here we are with some valuable customer data that we &lt;strong&gt;really&lt;/strong&gt; do not wanna lose. A good practice for any developer is to take regular (hopefully automated) database backups. Doing this in Postgres isn't too hard so let's get to it. I should state there are several ways to do this. This is just one of many ways to get this job done. I &lt;em&gt;think&lt;/em&gt; it is the most straightforward way; though, there are definitely faster ways.&lt;/p&gt;

&lt;p&gt;This approach consists of issuing a set of commands to the container that could likely be CRON &lt;em&gt;job-ified&lt;/em&gt; without too much effort.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First let's create a &lt;em&gt;backups&lt;/em&gt; directory at a spot that we share with our container's filesystem and our host machine:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; pg-db bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'mkdir /var/lib/postgresql/data/backups'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This command (run from the host machine) executes a command (&lt;code&gt;-c&lt;/code&gt;) &lt;code&gt;mkdir&lt;/code&gt; on the container and creates a directory called &lt;em&gt;backups&lt;/em&gt; which is located at the spot on the container that is shared with the host machine. You can verify this on the host by running:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres | &lt;span class="nb"&gt;grep &lt;/span&gt;backups
&lt;span class="c"&gt;# my machine outputs: backups&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next, let's create our backup
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; pg-db bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'pg_dump todo_it_well -U postgres  --file=/var/lib/postgresql/data/backups/todo_it_well_db-$(date +%Y-%m-%d).sql'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's breakdown this command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker exec -t pg-db bash -c&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;We tell Docker we want to run a command on the &lt;code&gt;pg-db&lt;/code&gt; container&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;pg_dump todo_it_well -U postgres&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;We invoke the &lt;code&gt;pg_dump&lt;/code&gt; tool on the container telling it to target the &lt;code&gt;todo_it_well&lt;/code&gt; db and run commands as the &lt;code&gt;postgres&lt;/code&gt; user.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;code&gt;--file=/var/lib/postgresql/data/backups/todo_it_well_db-$(date +%Y-%m-%d).sql&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This is the spot on the container we want to place our back up at and as you can see it is the shared backups directory we just made. There is a little &lt;code&gt;date&lt;/code&gt; logic that interpolates the current date as YEAR-MONTH-DAY.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;If this went as planned we should have made our database backup and we can verify it on our host machine by running:&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres/backups
&lt;span class="c"&gt;# my machine outputs: todo_it_well_db-2021-11-07.sql&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres/backups/todo_it_well_db-2021-11-07.sql
&lt;span class="c"&gt;# output includes: -- PostgreSQL database dump&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you see some SQL in your output then &lt;strong&gt;congratulations&lt;/strong&gt;! You have successfully created a database backup and your data strategy for your awesome app is just the tiniest bit more durable. 🎉&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Drop Data And Restore It
&lt;/h3&gt;

&lt;p&gt;Great, so our data has been backed up! This means that you can restore folks back to a particular point in time when things were as they should be. So long as you have an application that can reliably serve this data (ruminates on articles using &lt;a href="https://github.com/pressly/goose" rel="noopener noreferrer"&gt;Goose&lt;/a&gt; to accomplish database versioning) you can restore functionality and value to your users. &lt;/p&gt;

&lt;p&gt;BUT, backing up your data is only half the battle. Actually restoring it is another matter. Let's practice the act of restoring our data. &lt;/p&gt;

&lt;p&gt;First, I should confess that this article commits a sin of simplicity in that I wanted to get going as simply as possible. You more than likely &lt;strong&gt;should not&lt;/strong&gt; place your backups in the exact same spot as the rest of your mounted volume data, but it was useful in getting us going faster. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;So to start, we are going to put our backup temporarily out of this spot so that we can &lt;em&gt;pretend&lt;/em&gt; we had mounted two volumes:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="c"&gt;# Let's move our data to our home directory and pretend this is where we safely mounted our backups when starting the container, ok?&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres/backups/todo_it_well_db-2021-11-07.sql &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;$HOME&lt;/span&gt;/todo_it_well_db-2021-11-07.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next, verify that our data is where we expect it to be:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;todo_it_well_db-2021-11-07.sql
&lt;span class="c"&gt;# my machine outputs todo_it_well_db-2021-11-07.sql&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Ok cool, we are &lt;em&gt;pretending&lt;/em&gt; the we have a spot outside the normal Postgres files where we keep our data safely backed up. &lt;strong&gt;Now, the fun part.&lt;/strong&gt;  OMG! We just got &lt;strong&gt;attacked&lt;/strong&gt; 😰. All records were destroyed by the evil hacker! Let's stop our container and delete all of our persistent data.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="c"&gt;# Stop the container forcibly&lt;/span&gt;
docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; pg-db
&lt;span class="c"&gt;# Delete our persistent data&lt;/span&gt;
&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Verify the data is indeed gone.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres
&lt;span class="c"&gt;# my machine outputs: No such file or directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now we have discovered the attack and want to bring our application back online. So we start up our container as before:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
docker run &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;--name&lt;/span&gt; pg-db &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;shiny_metal_pass &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-p&lt;/span&gt; 6543:5432 &lt;span class="se"&gt;\&lt;/span&gt;
 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/docker/volumes/postgres:/var/lib/postgresql/data &lt;span class="se"&gt;\&lt;/span&gt;
 postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;However, sadly, our data, including our database, is gone and we cannot connect to the &lt;strong&gt;todo_it_well&lt;/strong&gt; database. &lt;/li&gt;
&lt;/ul&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%2Fi.ibb.co%2FCvmWsXc%2Fdt-pgdb-005-connect-fail-sql.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%2Fi.ibb.co%2FCvmWsXc%2Fdt-pgdb-005-connect-fail-sql.png" alt="connect-fail-sql"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fear not&lt;/strong&gt;, 🦸‍♀️ we have a backup! Simply copy the backup into the container:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
docker &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/todo_it_well_db-2021-11-07.sql pg-db:/var
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Next, you will need to recreate the database (so your backup data has a place to restore to):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; pg-db bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"createdb &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
-h localhost &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
-p 5432 &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
-U postgres &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
todo_it_well"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Finally, run the &lt;code&gt;psql&lt;/code&gt; SQL file command and take a deep breath, you are recovering from a &lt;strong&gt;very stressful attack&lt;/strong&gt; 😉.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-t&lt;/span&gt; pg-db bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s2"&gt;"psql &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
-U postgres &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
-d todo_it_well &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
-f /var/todo_it_well_db-2021-11-07.sql"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Lastly, let's verify that our data was properly restored by running our query from earlier:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- From a SQL Editor&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; 
   &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
   &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; 
   &lt;span class="nv"&gt;"user"&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; 
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;
   &lt;span class="nv"&gt;"task"&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
   &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
   &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completed_on&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- RESULTS&lt;/span&gt;
&lt;span class="c1"&gt;-- display_name description&lt;/span&gt;
&lt;span class="c1"&gt;-- dat-girl-jen read chapter of lotr&lt;/span&gt;
&lt;span class="c1"&gt;-- dat-girl-jen sign up to volunteer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There you have it! You have done a ton! You set up a dockerized Postgres DB, you created your schemas and planted some data in your database, you took a back up of the data and then restored the data from back up after losing it. You rock 🎸. &lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;There are some issues with our set up and certainly there are some ease of use and durability improvements we could make, but this is a fully working solution. Some of the areas we should checkout:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom Dockerfile that includes a backups location.&lt;/li&gt;
&lt;li&gt;A run command that references the previously mentioned backups location mount. &lt;/li&gt;
&lt;li&gt;A cron job run on the host or on the container that creates backups.&lt;/li&gt;
&lt;li&gt;A secure, but accessible spot for these backups to stored. Maybe DigitalOcean Spaces, why not 🦀?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://graspingtech.com/docker-compose-postgresql/" rel="noopener noreferrer"&gt;https://graspingtech.com/docker-compose-postgresql/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://simkimsia.com/how-to-restore-database-dumps-for-postgres-in-docker-container/" rel="noopener noreferrer"&gt;https://simkimsia.com/how-to-restore-database-dumps-for-postgres-in-docker-container/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/40632228/input-file-appears-to-be-a-text-format-dump-please-use-psql" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/40632228/input-file-appears-to-be-a-text-format-dump-please-use-psql&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.tutorialspoint.com/postgresql/postgresql_create_database.htm" rel="noopener noreferrer"&gt;https://www.tutorialspoint.com/postgresql/postgresql_create_database.htm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>web</category>
      <category>docker</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Dockerfile For A Python Playground On Ubuntu</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Wed, 08 Sep 2021 17:18:50 +0000</pubDate>
      <link>https://dev.to/mattcale/dockerfile-for-a-python-playground-on-ubuntu-4d69</link>
      <guid>https://dev.to/mattcale/dockerfile-for-a-python-playground-on-ubuntu-4d69</guid>
      <description>&lt;h2&gt;
  
  
  What is this?
&lt;/h2&gt;

&lt;p&gt;This is a tutorial on getting a supremely simple Python3 playground running on an Ubuntu Docker container. Like my &lt;a href="https://dev.to/mattcale/simple-ubuntu-docker-playground-23g2"&gt;first tutorial on Ubuntu and Docker&lt;/a&gt; this &lt;strong&gt;is not extremely useful&lt;/strong&gt;, but it &lt;strong&gt;is extremely simple&lt;/strong&gt; and that goes a long way in a field where things can get very tricky very fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why make this?
&lt;/h2&gt;

&lt;p&gt;To keep it in a spot I remember and to share simple things with others. &lt;strong&gt;In the future you might be glad you have a starting point for tinkering with Python and Ubuntu together Matt!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a directory and Dockerfile &lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="c"&gt;# From the terminal &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;ubuntu-python-playground &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;ubuntu-python-playground &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;Dockerfile


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Open the Dockerfile in a text editor (use VSCode if you're a human and use Vim if you're 3xtra l33t) and fill it in with the requirements for getting Python to run on an Ubuntu container.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Using the Ubuntu image (our OS)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:latest&lt;/span&gt;
&lt;span class="c"&gt;# Update package manager (apt-get) &lt;/span&gt;
&lt;span class="c"&gt;# and install (with the yes flag `-y`)&lt;/span&gt;
&lt;span class="c"&gt;# Python and Pip&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    python3.8 &lt;span class="se"&gt;\
&lt;/span&gt;    python3-pip


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Make your new fancy image&lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="c"&gt;# From the terminal &lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; ubuntu-python-playground-img &lt;span class="nb"&gt;.&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Run the image interactively and get a Python playground set up &lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="c"&gt;# Run the image / make a container jump into it&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu-python-playground-img bash
&lt;span class="c"&gt;# Install some libraries that do fun things&lt;/span&gt;
pip3 &lt;span class="nb"&gt;install &lt;/span&gt;Requests Pygments
&lt;span class="c"&gt;# Open the Python REPL&lt;/span&gt;
python3


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Once you're in the Python REPL feel free to run some totally bomb python code 🐍. Since we installed some fun packages in the step before consider trying them out!&lt;/li&gt;
&lt;/ul&gt;

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

&lt;span class="c1"&gt;# There will be a little &amp;gt;&amp;gt;&amp;gt; symbol 
# this indicates you're in the Python REPL
&lt;/span&gt;
&lt;span class="c1"&gt;# Get some cool libs imported
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pygments&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;highlight&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pygments.lexers.data&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JsonLexer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pygments.formatters&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TerminalFormatter&lt;/span&gt;

&lt;span class="c1"&gt;# Get and format some JSON
&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://jsonplaceholder.typicode.com/users/2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;highlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&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="nc"&gt;JsonLexer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;TerminalFormatter&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Enjoy 🙋‍♀️&lt;/li&gt;
&lt;/ul&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%2F31ent7wu06pqbqoz5fiv.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%2F31ent7wu06pqbqoz5fiv.png" alt="Screen Shot 2021-09-08 at 11.26.55 AM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative Approach
&lt;/h2&gt;

&lt;p&gt;This works well for running Python in the REPL, but what if I wanted to write the Python code in my text editor, but run it on the container?&lt;/p&gt;

&lt;p&gt;Well, with a few changes to the Dockerfile you can! To do this we will copy and paste the Python code example above into a file called &lt;code&gt;script.py&lt;/code&gt; so our &lt;em&gt;ubuntu-python-playground&lt;/em&gt; directory from before now has two files in it. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Dockerfile&lt;/em&gt; (the one we have been working with)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;script.py&lt;/em&gt; (the code we previously ran in the REPL)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once our script.py file is in place we will just make some changes to the Dockerfile and re-run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps For Alternative Approach
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Change the Dockerfile to look like this:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;

&lt;span class="c"&gt;# Using the Ubuntu image (our OS)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:latest&lt;/span&gt;
&lt;span class="c"&gt;# Update package manager (apt-get) &lt;/span&gt;
&lt;span class="c"&gt;# and install (with the yes flag `-y`)&lt;/span&gt;
&lt;span class="c"&gt;# Python and Pip&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    python3.8 &lt;span class="se"&gt;\
&lt;/span&gt;    python3-pip

&lt;span class="c"&gt;# =====&lt;/span&gt;
&lt;span class="c"&gt;# The new stuff is below&lt;/span&gt;
&lt;span class="c"&gt;# =====&lt;/span&gt;

&lt;span class="c"&gt;# Install our Python dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;Requests Pygments

&lt;span class="c"&gt;# Copy our script into the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; script.py /script.py&lt;/span&gt;

&lt;span class="c"&gt;# Run the script when the image is run&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["python3", "/script.py"]&lt;/span&gt;



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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Build and run the new image&lt;/li&gt;
&lt;/ul&gt;

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

docker build &lt;span class="nt"&gt;-t&lt;/span&gt; ubuntu-python-playground-img &lt;span class="nb"&gt;.&lt;/span&gt;
docker run ubuntu-python-playground-img 


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Enjoy 🙋‍♀️&lt;/li&gt;
&lt;/ul&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%2F4oobgavyt3qxrz63dz3i.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%2F4oobgavyt3qxrz63dz3i.png" alt="Screen Shot 2021-09-08 at 12.13.04 PM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources For Extra Learning
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/engine/reference/builder/#run" rel="noopener noreferrer"&gt;What is Docker RUN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run" rel="noopener noreferrer"&gt;Best Practices for Docker RUN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.python-guide.org/starting/install3/linux/" rel="noopener noreferrer"&gt;Basic Linux Python Install Instructions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>ubuntu</category>
      <category>tutorial</category>
      <category>mcdau</category>
    </item>
    <item>
      <title>Simple Ubuntu Docker Playground</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Tue, 07 Sep 2021 19:50:41 +0000</pubDate>
      <link>https://dev.to/mattcale/simple-ubuntu-docker-playground-23g2</link>
      <guid>https://dev.to/mattcale/simple-ubuntu-docker-playground-23g2</guid>
      <description>&lt;h1&gt;
  
  
  What is this?
&lt;/h1&gt;

&lt;p&gt;This is a tutorial on doing Ubuntu stuffs in Docker. It is intended to be a starting off point for doing common things in pretty much any image that can run &lt;code&gt;bash&lt;/code&gt; or &lt;code&gt;sh&lt;/code&gt;. Other tutorials will lean on this on this foundation.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why make this?
&lt;/h1&gt;

&lt;p&gt;To keep it in a spot I remember and to share simple things with others.&lt;/p&gt;

&lt;h1&gt;
  
  
  Steps
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Run the Ubuntu image with the &lt;code&gt;-i&lt;/code&gt; and &lt;code&gt;-t&lt;/code&gt; flags. &lt;a href="https://docs.docker.com/engine/reference/commandline/run/" rel="noopener noreferrer"&gt;See documentation for more detail&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Run the image directly rather than exec into a container&lt;/span&gt;
docker run &lt;span class="nt"&gt;--name&lt;/span&gt; ubuntu-playground &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Optional, verify your new container is running in a separate terminal window. This is a bit redundant since your terminal shell just switched, but it's good to be thorough!
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;span class="c"&gt;# ubuntu-playground will be in the NAMES column&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install and run some stuff
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# From prompt inside container&lt;/span&gt;
apt-get update
apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; curl jq
curl https://jsonplaceholder.typicode.com/users/1 | jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Profit 🤑&lt;/li&gt;
&lt;/ul&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%2Fhe2i87dhrmogxf1y3ijr.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%2Fhe2i87dhrmogxf1y3ijr.png" alt="Screen Shot 2021-09-07 at 2.35.58 PM"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ubuntu</category>
      <category>tutorial</category>
      <category>mcdau</category>
    </item>
    <item>
      <title>Making A Delightful Personal Page - P2: Complete Content and Make It Pugly!</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Mon, 12 Oct 2020 17:16:31 +0000</pubDate>
      <link>https://dev.to/mattcale/making-a-delightful-personal-page-p2-complete-content-and-make-it-pugly-kkd</link>
      <guid>https://dev.to/mattcale/making-a-delightful-personal-page-p2-complete-content-and-make-it-pugly-kkd</guid>
      <description>&lt;h2&gt;
  
  
  Welcome Back!
&lt;/h2&gt;

&lt;p&gt;In this series we are creating a delightful to develop, and pleasant to look at homepage that contains &lt;strong&gt;0 runtime dependencies&lt;/strong&gt; (CSS or JS libs/frameworks). To make this process fun and simple we are employing a small number of developer tools such as Pug, Stylus, NPM Scripts, Gulp, and Surge.&lt;/p&gt;

&lt;p&gt;In the last section we covered the creation of our project, creating our first deployment asset (a single HTML page), and got it deployed out to the internet. We also threw in some temporary styles just so we could start sharing something 🆒 as quickly as possible.&lt;/p&gt;

&lt;p&gt;In this post we are going to split out our &lt;em&gt;src&lt;/em&gt; content from our &lt;em&gt;dist&lt;/em&gt; content, (by this we mean we will introduce the concept of keeping our development assets distinct from our deployment assets),  convert our HTML markup to &lt;a href="https://pugjs.org/api/getting-started.html"&gt;Pug&lt;/a&gt; markup, and add the rest of our content to our site.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aside: Why use Pug?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Optional: read only if you are interested in this technology choice.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A very fair sentiment at this point is "why throw in an additional technology? If the point is to make it simple then use as few dependencies as possible.". My response to this feedback is that we are not aiming to make the simplest possible solution. We are intending to make the most delightful or pleasant developer experience. &lt;/p&gt;

&lt;p&gt;To be sure, &lt;strong&gt;simplicity is an aspect of developer satisfaction and should be heavily weighed&lt;/strong&gt;, but in my particular case (and I'd bet in yours) there are other aspects to contend with. Here are a few items that I think make Pug shine as a developer tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is &lt;strong&gt;pleasant to look&lt;/strong&gt; at, and is &lt;strong&gt;highly expressive&lt;/strong&gt; without being overly verbose. Check out this simple comparison of the exact same markup. You get approximately 20% less code. In a small example this may not mean much, but over time that can amount to a significant amount of code that you can forego including.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pug&lt;/span&gt;
&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card text-center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="nx"&gt;clever&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;
  &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;Dale&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
    &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-content&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;Happy&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;stopped&lt;/span&gt; &lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- HTML --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card text-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;A clever header&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hello Dale!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Happy you stopped by!&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It is &lt;strong&gt;modular&lt;/strong&gt;, and &lt;strong&gt;extensible&lt;/strong&gt;. As projects grow the idea of being able to logically separate and eventually re-use UI components or at least work on them in cognitive isolation is very valuable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It &lt;strong&gt;enforces a consistent format&lt;/strong&gt;. This is something the coding world is really coming around to. Python does it, Go's formatting tool &lt;code&gt;fmt&lt;/code&gt; does it, and a thousand linters the world over do it, albeit, in a bespoke fashion. &lt;strong&gt;An opinionated format reduces cognitive load, and reduces bike shedding.&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, Pug helps make my code more elegant, consistent, and extensible than it would have been otherwise, and to me using Pug is just plain fun! &lt;/p&gt;

&lt;p&gt;If you really dislike it there is nothing stopping you from just creating the markup in HTML and finding a different way to place it in the &lt;em&gt;dist&lt;/em&gt; directory for deployment. I understand that folks like their tools and don't judge. I clearly like mine 😌&lt;/p&gt;

&lt;h2&gt;
  
  
  Pug Primer
&lt;/h2&gt;

&lt;p&gt;If you haven't worked with Pug before it is an HTML templating language. That means you will write files with a &lt;code&gt;.pug&lt;/code&gt; extension and compile them into HTML files. We will not be employing most of the power that Pug offers in this tutorial as we mostly just want to enjoy the conciseness and expressiveness of the language, but all of the power is there if you feel like taking your page to the next level. For this tutorial all you need it know is the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Whitespace is meaningful!&lt;/strong&gt; This means that if items are not properly indented they will either not compile at all (usually with a helpful error message) or compile in unexpected ways. Let's look at a  very simple example.&lt;/p&gt;

&lt;p&gt;Notice the use of whitespace in the following valid Pug markup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;There&lt;/span&gt;
  &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;am&lt;/span&gt; &lt;span class="nx"&gt;so&lt;/span&gt; &lt;span class="nx"&gt;glad&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;stopped&lt;/span&gt; &lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;span class="nx"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rights&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;small&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;rights&lt;/span&gt; &lt;span class="nx"&gt;reserved&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above will correctly compile to the following HTML:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hello There&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;I am so glad you stopped by!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;footer&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;'rights'&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;small&amp;gt;&lt;/span&gt;all rights reserved&lt;span class="nt"&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Transition to Pug
&lt;/h2&gt;

&lt;p&gt;The first thing we are going to do is "mature" our project a bit by &lt;strong&gt;creating some separation for our concerns&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;We are going to create a &lt;em&gt;src&lt;/em&gt; (also known as "source") directory that contains our raw, uncompiled project files and assets, and we are going to run scripts against these items that transform and copy them to places inside the &lt;em&gt;dist&lt;/em&gt; directory. This process is often called compilation and is how the development of large projects usually occurs. You write will clean, possibly commented, human readable code and the compilation process will create valid, machine runnable code. &lt;/p&gt;

&lt;p&gt;In our particular project we are going to compile &lt;code&gt;.pug&lt;/code&gt; files (located in the &lt;em&gt;src&lt;/em&gt; directory) into &lt;code&gt;.html&lt;/code&gt; (located in the &lt;em&gt;dist&lt;/em&gt; directory) files.&lt;/p&gt;

&lt;p&gt;So let's get started!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In your project's root directory let's install the Pug compiler.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; pug-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Great, now let's set up our &lt;em&gt;src&lt;/em&gt; directory with our &lt;code&gt;.pug&lt;/code&gt; source code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal &lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Now, let's make our first source Pug file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal &lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;src/index.pug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have a Pug file let's get it filled in with our code in its current state state. Recall, that we have our current deployment asset at &lt;em&gt;dist/index.html&lt;/em&gt;. Let's copy the contents of that file into Pug. There are a number of online tools that can do this and here's an &lt;a href="https://www.npmjs.com/package/html2pug"&gt;NPM package&lt;/a&gt; that will do it too. For brevity, feel free to copy mine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In src/index.pug&lt;/span&gt;
&lt;span class="nx"&gt;doctype&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;
&lt;span class="nx"&gt;head&lt;/span&gt;
    &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UTF-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;viewport&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;width=device-width, initial-scale=1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://fonts.googleapis.com/css2?family=Cabin:ital,wght@0,400;0,500;1,400&amp;amp;display=swap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stylesheet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
        &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cabin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sans&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="nx"&gt;rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;justify&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="nx"&gt;vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;welcome&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;welcome&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sugar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;font&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;italic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="nx"&gt;Dale&lt;/span&gt; &lt;span class="nx"&gt;Gribble&lt;/span&gt;
&lt;span class="nx"&gt;body&lt;/span&gt; 
    &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;row&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;column hero&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;welcome-info&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;Dale&lt;/span&gt; &lt;span class="nx"&gt;Gribble&lt;/span&gt;
                &lt;span class="nx"&gt;h2&lt;/span&gt; &lt;span class="nx"&gt;Exterminator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Treasure&lt;/span&gt; &lt;span class="nx"&gt;Hunter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Alientologist&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="nx"&gt;x1F47D&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sugar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;If&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;apos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;re&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;CIA&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;have&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;tell&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;BTW, I know you can elide tags like &lt;code&gt;div&lt;/code&gt; and &lt;code&gt;attrs&lt;/code&gt; like &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;, but I think the above strikes a balance of clarity and brevity. You are welcome to elide these elements if you wish&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Awesome we have some seriously 💣 looking markup here. Now, let's &lt;strong&gt;compile&lt;/strong&gt; that bad boy! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add a new NPM script that looks like this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In package.json&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compile-views&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pug src --out dist&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;And give it a whirl!
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In the terminal&lt;/span&gt;
npm run compile-views
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If everything went as planned there should be an &lt;em&gt;index.html&lt;/em&gt; file in your &lt;em&gt;dist&lt;/em&gt; directory with exactly the same contents as before; only this time it's been minified (per the Pug compiler's default settings). Check it out in the browser to make sure everything still looks as you'd expect it to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XM_NHe3L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/0beso52yq5xuqs8ih0ra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XM_NHe3L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/0beso52yq5xuqs8ih0ra.png" alt="Same-But-All-Pugly" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From now on when we want to see our result we will first need to compile our views. Later on we will add a task runner that makes this occur every-time the &lt;em&gt;src/index.pug&lt;/em&gt; file is saved, but for now this shouldn't be too cumbersome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Completing our Markup
&lt;/h2&gt;

&lt;p&gt;Now, we are going to finish up creating our content. We already have the &lt;code&gt;hero&lt;/code&gt; section that covers the entire view-height when someone first visits our page, now let's give interested viewers a little more information about ourselves through 2 &lt;em&gt;"Question &amp;amp; Answer"&lt;/em&gt; rows. Place the &lt;code&gt;div.row&lt;/code&gt; elements at the same indentation level as the &lt;code&gt;div.row&lt;/code&gt; we already have. Recall, that indentation is important in Pug. If you are confused you can always check out the tutorial repo under the tutorial 2 release to see how I did mine.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's add the rows and see how it looks!
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In src/index.pug&lt;/span&gt;
&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;row&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;column q-and-a work&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;question&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;h3&lt;/span&gt; &lt;span class="nx"&gt;What&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;work&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
        &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;Well&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;at&lt;/span&gt; &lt;span class="nx"&gt;Dales&lt;/span&gt; &lt;span class="nx"&gt;Dead&lt;/span&gt; &lt;span class="nx"&gt;Bug&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;operate&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;assassin&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;assassins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Make&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;mistake&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ants&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;spiders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mosquitos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;wasps&lt;/span&gt; &lt;span class="nx"&gt;want&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="nx"&gt;dead&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;am&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;guardian&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;all&lt;/span&gt; &lt;span class="nx"&gt;humanity&lt;/span&gt; &lt;span class="nx"&gt;against&lt;/span&gt; &lt;span class="nx"&gt;these&lt;/span&gt; &lt;span class="nx"&gt;dubious&lt;/span&gt; &lt;span class="nx"&gt;foes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;row&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;column q-and-a fun&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;question&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;h3&lt;/span&gt; &lt;span class="nx"&gt;What&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="nx"&gt;you&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;fun&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
        &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;answer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;hunt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;fish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;play&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;lot&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;golf&lt;/span&gt; &lt;span class="nx"&gt;and&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;drink&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;alley&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt; &lt;span class="nx"&gt;friends&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Also&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;am&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;president&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;Arlen&lt;/span&gt; &lt;span class="nx"&gt;gun&lt;/span&gt; &lt;span class="nx"&gt;club&lt;/span&gt; &lt;span class="nx"&gt;which&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;alright&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;I&lt;/span&gt; &lt;span class="nx"&gt;guess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Compile it and check it out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oEliMY3q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/4hznegql8az5gcv4y3c7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oEliMY3q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/4hznegql8az5gcv4y3c7.png" alt="Q-And-A-Unstyled" width="800" height="658"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hmmm, it does have our new content, but it isn't very pretty. We haven't yet gotten to our doing basic styles yet (hype for upcoming post), but because we don't want folks seeing something ugly let's add just a tiny bit more temporary styling to the &lt;em&gt;src/index.pug&lt;/em&gt; &lt;code&gt;head&lt;/code&gt; section.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In src/index.pug&lt;/span&gt;
&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="c1"&gt;// Other styles elided&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;and&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;550&lt;/span&gt;&lt;span class="nx"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;flex&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;justify&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;around&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;center&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;ul&gt;
&lt;li&gt;Great, let's compile it and check it out again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8F_laFmQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/l1r686vtg6woz8le1eua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8F_laFmQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/l1r686vtg6woz8le1eua.png" alt="Q-And-A-Temp-Styled" width="800" height="658"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, alright! We've got a page with enough content to be useful! Release it out to the world using the same deployment script as last time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In the terminal&lt;/span&gt;
npm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out your live site. That's pretty 🆒, huh?&lt;/p&gt;

&lt;p&gt;In this post we transitioned our markup to &lt;strong&gt;Pug which is a lovely, and powerful templating language&lt;/strong&gt; that can be used to keep your project pleasant, and maintainable as it grows. &lt;/p&gt;

&lt;p&gt;We added the rest of the site's content (&lt;em&gt;at least for a good little bit&lt;/em&gt;) and added some temporary styling to it so that we could feel happy about deploying it. &lt;/p&gt;

&lt;p&gt;We also transitioned to a more mature pattern of keeping our source code separate from our distribution code by introducing the &lt;em&gt;src&lt;/em&gt; directory where we write our human readable Pug that we then "compile" into our minified HTML in the &lt;em&gt;dist&lt;/em&gt; directory.&lt;/p&gt;

&lt;p&gt;In our next post we will be introduced to using Gulp for an even more pleasant developer experience. Try to give yourself a break here. Excited to see you in the next section 🤠 &lt;/p&gt;

&lt;p&gt;Will post link when it's ready!&lt;/p&gt;

</description>
      <category>html</category>
      <category>pug</category>
      <category>tutorial</category>
      <category>matthewcalecom</category>
    </item>
    <item>
      <title>Making A Delightful Personal Page - P1: Introduction and Instant Gratification</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Mon, 12 Oct 2020 17:14:54 +0000</pubDate>
      <link>https://dev.to/mattcale/making-a-delightful-personal-page-p1-introduction-and-instant-gratification-57in</link>
      <guid>https://dev.to/mattcale/making-a-delightful-personal-page-p1-introduction-and-instant-gratification-57in</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hello! Welcome to my walkthrough of how to make a delightful personal page. In this series you will be able to read along and quickly build a lovely little homepage that is 💯 runtime dependency free, and is also a 💯 delight to develop by using modern and elegant developer tools written in Node.js.&lt;/p&gt;

&lt;p&gt;The page we will be making is a clone of my personal page, &lt;a href="http://matthewcale.com"&gt;http://matthewcale.com&lt;/a&gt;. The tools we will employ and get a reasonable introduction to are: NPM scripts (for basic task running), &lt;a href="https://pugjs.org/api/getting-started.html"&gt;Pug&lt;/a&gt; (for HTML), &lt;a href="https://stylus-lang.com/"&gt;Stylus&lt;/a&gt; (for CSS), &lt;a href="https://gulpjs.com/"&gt;Gulp&lt;/a&gt; (for advanced task running) and &lt;a href="https://surge.sh/"&gt;Surge&lt;/a&gt; (for hosting). We will use these tools to create a &lt;strong&gt;pleasant&lt;/strong&gt; to read, &lt;strong&gt;fun&lt;/strong&gt; to develop, and &lt;strong&gt;simple&lt;/strong&gt; to deploy website that requires no CSS* or Javascript libraries, which means that its footprint is tiny and that the amount of cognitive load it takes to develop is miniscule.&lt;/p&gt;

&lt;p&gt;I wrote this to be approachable for developers of all skill levels, while not being tedious for more advanced devs. If things were markedly unclear or miserably tedious let me know. I may not be able to please everyone, but understanding what readers want is important to me. Thank you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Aside, Why Make This?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Optional, read only if you are interested as to "why" I made this tutorial.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As developers we are tasked with knowing how to do a great many things and these things are often incredibly complex and require a (pretty) rigid structure. We need this rigidity in order to make massive projects that can easily scale both in the number of end consumers and in the number of active developers.  &lt;/p&gt;

&lt;p&gt;Frameworks exist to make this rigidity and boilerplate less off-putting and easier to understand and as such developers employ these frameworks to reduce the burden of hand rolling rigid structures. A good example is Bootstrap. Many development teams employ Bootstrap (or another CSS library like it) to keep from writing their own CSS components. This is a great idea! General pages, that users interact with (forms) and consume information from (dashboards) follow an &lt;strong&gt;expected format&lt;/strong&gt; and Bootstrap has made these &lt;strong&gt;expected formats&lt;/strong&gt; much easier to make. &lt;/p&gt;

&lt;p&gt;There is however, another type of page that exists on the internet that &lt;strong&gt;CSS frameworks, by the nature of that selfsame useful rigidity fall short&lt;/strong&gt; in being as useful for, and that is the bespoke "pretty" or "artistic" page (like the one we are making here). Don't get me  wrong, the frameworks usually have the ability to make these pages as well, and offer their own advantages to seasoned users of those frameworks, but they were &lt;strong&gt;not written for this purpose&lt;/strong&gt;. So, while they can be used to make these pages I have found that it feels much more natural to let frameworks tackle the common problems and let humans tackle creating artsy pages. That is what these pages are essentially, little artwork installations. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, what I set out to do was see how easily and pleasantly I could create a (hopefully) lovely page with no frameworks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What I discovered is that, with the help of a few developer tools, creating pages whose primary aim is to be lovely can be quite pleasant and I wanted to share my approach. &lt;/p&gt;

&lt;h2&gt;
  
  
  Instant Gratification
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;To start, let's get a cool page up online!&lt;/strong&gt; This page will not be our final product, but will be a good place to start getting familiar with &lt;strong&gt;three&lt;/strong&gt; of the technologies we intend to use and will give you a project setup that you can easily keep building upon. So let's get after it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Tools you need
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js installed&lt;/li&gt;
&lt;li&gt;A basic code editor, like &lt;a href="https://atom.io/"&gt;Atom&lt;/a&gt;, &lt;a href="https://code.visualstudio.com/"&gt;VSCode&lt;/a&gt;, or &lt;a href="https://www.sublimetext.com/"&gt;Sublime&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A terminal program (like Terminal or iTerm)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Verify your installation&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
matt.cale&lt;span class="nv"&gt;$ &lt;/span&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
v12.16.3
matt.cale&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nt"&gt;--version&lt;/span&gt;
6.14.4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Project Setup Steps
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create project directory
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="c"&gt;# Idea: Use "jane-doe" instead of "dale-gribble" in your command &lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/Desktop/dale-gribble.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Initialize the project
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="c"&gt;# Idea: Use "jane-doe" instead of "dale-gribble" in your command &lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/Desktop/dale-gribble.com &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The command, &lt;code&gt;npm init -y&lt;/code&gt;, will create the &lt;em&gt;package.json&lt;/em&gt; file required for Node and NPM (Node's dependency management tool) to treat your project like a Node module thus allowing you to install the required dev-only dependencies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install Surge.sh as a &lt;em&gt;"developer dependency"&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
npm i &lt;span class="nt"&gt;--save-dev&lt;/span&gt; surge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; A &lt;em&gt;"developer dependency"&lt;/em&gt; is a code library or program / application that makes the creation of other libraries or applications easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Your Site's Content Steps
&lt;/h3&gt;

&lt;p&gt;Now that we have a project we can hack on let's get to hacking! Later on we will be using Pug.js to create markup that is more elegant, modular, and extensible, but for now let's just hack some HTML so we can get something decent deployed. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a directory called &lt;em&gt;dist&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;dist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; This will be the directory that we deploy as our static site.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an &lt;em&gt;index.html&lt;/em&gt; file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;dist/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get your HTML boilerplate created as well.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- In your dist/index.html file --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- CSS font link here! --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Dale Gribble&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Content here! --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Get a 🆒 font from &lt;a href="https://fonts.google.com/"&gt;Google Fonts&lt;/a&gt; and place it in the &lt;code&gt;head&lt;/code&gt; section as a stylesheet &lt;code&gt;link&lt;/code&gt;. It's a good idea to get a regular, bold and italic version. Here' mine.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- In your dist/index.html file --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- In between the &amp;lt;head&amp;gt; tags --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.googleapis.com/css2?family=Cabin:ital,wght@0,400;0,500;1,400&amp;amp;display=swap"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have our HTML scaffolded out let's add our first bit of custom content. You can now add any HTML you want to your page, but if you are following along I went with the following format: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name (&lt;code&gt;Dale Gribble&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Identifiers (&lt;code&gt;Exterminator, Treasure Hunter, Alientologist&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Welcome Message (&lt;code&gt;If you're from the CIA you have to tell me! 👽&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside of the &lt;code&gt;body&lt;/code&gt; add the following:&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="c"&gt;&amp;lt;!-- In your dist/index.html file --&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- In between the &amp;lt;body&amp;gt; tags --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"column hero"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"welcome-info"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Dale Gribble&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Exterminator, Treasure Hunter, Alientologist 👽&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;If you're from the CIA you have to tell me!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The content we are going to provide is going to be styled with Flexbox, a styling tool available in plain ol' vanilla CSS. To make this styling easier to understand we are going to split our UI into rows and columns. Sometimes we will have multiple columns, but in this case we just want a row with a single column. The column will contain one item, a &lt;code&gt;welcome-info&lt;/code&gt; container element that contains our content.&lt;/p&gt;

&lt;p&gt;Check it out in the browser, pretty boring, eh? Well, let's add some styling to spruce it up before we go public with it!&lt;/p&gt;

&lt;p&gt;Up between the &lt;code&gt;style&lt;/code&gt; tags in the &lt;code&gt;head&lt;/code&gt; section of your &lt;em&gt;index.html&lt;/em&gt; copy in the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* In your dist/index.html file */&lt;/span&gt;
&lt;span class="c"&gt;/* In between the &amp;lt;style&amp;gt; tags */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;'Cabin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.hero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.welcome-info&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.welcome-info&lt;/span&gt; &lt;span class="nc"&gt;.sugar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;italic&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;The styles are pretty simple, but even so &lt;strong&gt;do not worry if you don't understand something&lt;/strong&gt; I will be covering these styles in more detail in a later section.&lt;/p&gt;

&lt;p&gt;Go ahead and open the &lt;em&gt;index.html&lt;/em&gt; file in a browser, provided you are connected to the internet (&lt;em&gt;for fonts&lt;/em&gt;) you should see the following.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--07Daqk7H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/x36jzha21ugbbbmtvafi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--07Daqk7H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/x36jzha21ugbbbmtvafi.png" alt="local-file" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If yours doesn't look like mine check out the &lt;em&gt;dist/index.html&lt;/em&gt; in the demonstration repo and see if everything is the same there. If you checked and it's all the same please leave me a comment or create an issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy Your Site to The Internet Steps
&lt;/h3&gt;

&lt;p&gt;Great, you have a website that isn't horrible to look at! It also gives a fair amount of information about you, but this isn't useful unless other people can see it, right?&lt;/p&gt;

&lt;p&gt;So how do we get this 💣 site deployed online? Well, remember earlier when you downloaded &lt;code&gt;surge&lt;/code&gt;? Now we are gonna use it!&lt;/p&gt;

&lt;p&gt;Surge is an insanely simple static site (what we just made) hosting platform. To get started we are going to create an NPM script that invokes the &lt;code&gt;surge&lt;/code&gt; program we downloaded.&lt;/p&gt;

&lt;p&gt;A NPM script is a command that is invoked with &lt;code&gt;npm run &amp;lt;script&amp;gt;&lt;/code&gt; and references an entry in the &lt;em&gt;package.json&lt;/em&gt; file's &lt;code&gt;scripts&lt;/code&gt; section. It will use your shell's commands (Ex: Bash). An example script might look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"say-hi"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo hello there"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which when invoked outputs 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;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
npm run say-hi
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;echo &lt;/span&gt;hello there
hello there
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since we downloaded &lt;code&gt;surge&lt;/code&gt; there will be a program that NPM can invoke inside of your &lt;code&gt;node_modules&lt;/code&gt; directory called &lt;code&gt;surge&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All that is required for &lt;code&gt;surge&lt;/code&gt; to work is a directory that contains an &lt;em&gt;index.html&lt;/em&gt; (&lt;em&gt;dist&lt;/em&gt; for us), a file in the same directory called &lt;em&gt;CNAME&lt;/em&gt; that has your desired surge address in it, and an account (email and password). Best of all, it's all free! &lt;/p&gt;

&lt;p&gt;So let's create our deployment process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a file called &lt;em&gt;CNAME&lt;/em&gt; (this file has no extension, like &lt;em&gt;.html&lt;/em&gt; or &lt;em&gt;.txt&lt;/em&gt;) in the &lt;em&gt;dist&lt;/em&gt; directory.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;dist/CNAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Open the &lt;em&gt;CNAME&lt;/em&gt; file and add your desired &lt;code&gt;&amp;lt;site-name&amp;gt;.surge.sh&lt;/code&gt; site name to it. Here's the contents of my &lt;em&gt;CNAME&lt;/em&gt; file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dale-gribble.surge.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point your project structure should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dist
dist/index.html
dist/CNAME
node_modules
package-lock.json
package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create the deployment script in the &lt;em&gt;package.json&lt;/em&gt; scripts. Here's the &lt;code&gt;scripts&lt;/code&gt; section of my &lt;em&gt;package.json&lt;/em&gt; file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;nothing to test&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"surge dist"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time for lift off 🚀! Run your &lt;code&gt;deploy&lt;/code&gt; NPM script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In your terminal&lt;/span&gt;
npm run deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note: Your first time running surge will prompt you for an email password word.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The output for me looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Running as &amp;lt;matt&amp;gt; &lt;span class="o"&gt;(&lt;/span&gt;Student&lt;span class="o"&gt;)&lt;/span&gt;

project: dist
domain: dale-gribble.surge.sh
upload: &lt;span class="o"&gt;[====================]&lt;/span&gt; 100% eta: 0.0s &lt;span class="o"&gt;(&lt;/span&gt;2 files, 1178 bytes&lt;span class="o"&gt;)&lt;/span&gt;
CDN: &lt;span class="o"&gt;[====================]&lt;/span&gt; 100%
IP: &amp;lt;IP&amp;gt;

Success! - Published to dale-gribble.surge.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in a browser, navigate to your &lt;code&gt;site-name.surge.sh&lt;/code&gt;, and see your masterpiece!&lt;/p&gt;

&lt;p&gt;Here's mine!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x06hr3i---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/j6sb8buh61n6zf7hos9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x06hr3i---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/j6sb8buh61n6zf7hos9t.png" alt="deployed" width="800" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wow!&lt;/strong&gt; We just did quite a bit! We made a site, styled it, created a &lt;em&gt;CNAME&lt;/em&gt; (&lt;em&gt;networky&lt;/em&gt;) file, created a deployment script, and published a site to the internet. Let's bask in the glow of all we've done for a while before moving on to &lt;a href="https://dev.to/mattcale/making-a-delightful-personal-page-p2-complete-content-and-make-it-pugly-kkd"&gt;&lt;em&gt;Part Two&lt;/em&gt;&lt;/a&gt; where we will make our markup prettier and more extensible using Pug and another NPM script!&lt;/p&gt;

&lt;p&gt;Thanks for following along. I hope this was fun and educational. If you have any feedback or just wan to say "howdy" please drop me a line below. Have a wonderful day. 🤠  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;*For fonts I will be using some Google Fonts, but this is entirely optional, and suitable fallbacks will be available.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>surge</category>
      <category>tutorial</category>
      <category>matthewcalecom</category>
    </item>
    <item>
      <title>NPM, Gulp, and The Case of The Naughty Global Package</title>
      <dc:creator>Matthew Cale</dc:creator>
      <pubDate>Sat, 25 Jul 2020 00:37:30 +0000</pubDate>
      <link>https://dev.to/mattcale/npm-gulp-and-the-case-of-the-naughty-global-package-389d</link>
      <guid>https://dev.to/mattcale/npm-gulp-and-the-case-of-the-naughty-global-package-389d</guid>
      <description>&lt;p&gt;&lt;strong&gt;Meta TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;--force&lt;/code&gt; would have worked for me 🤷‍♀️&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There is an NPM package named &lt;code&gt;glup-cli&lt;/code&gt; and when you are trying to download &lt;code&gt;gulp-cli&lt;/code&gt; things can get a bit confusing since the makers of &lt;code&gt;glup-cli&lt;/code&gt; also export a bin command called &lt;code&gt;gulp&lt;/code&gt; and create a SYMLINK to the spot that the real &lt;code&gt;gulp-cli&lt;/code&gt; needs to go. This surfaces in the real &lt;code&gt;gulp-cli&lt;/code&gt; being un-installable because something already possesses the SYMLINK for &lt;code&gt;/usr/local/bin/gulp&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Recently, I have been making a little webpage for myself (matthewcale.com), and it's coming along just fine I'd say. I am using Pug (Markup) and Stylus (Styles) and Surge (Hosting) along with some neat CSS animations written by very smart folks from around the net. There are incredible folks who have made me feel like I am coding in the year 4000.&lt;/p&gt;

&lt;p&gt;At the moment everything I am doing is accomplished with NPM scripts, and everything gets done. It is, however, a tiny bit tedious and I'd like to employ a task runner to get things to really sparkle.&lt;/p&gt;

&lt;p&gt;There are a boatload of task runners and bundlers out there. I personally like the amount of control I have using a tool like Gulp and while I haven't used it in a while I still recall it fondly. &lt;/p&gt;

&lt;p&gt;I visited their homepage and found out that since I stopped using it for my normal dev life they have changed it a good bit, and now it is suggested that a user have a local task runner and a global CLI tool installed. Not to worry, &lt;code&gt;npm i -g gulp-cli&lt;/code&gt; to the rescue. Doh! What happened?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mbp-mcale:~ matt.cale&lt;span class="nv"&gt;$ &lt;/span&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; gulp-cli
npm ERR! code EEXIST
npm ERR! syscall symlink
npm ERR! path ../lib/node_modules/gulp-cli/bin/gulp.js
npm ERR! dest /usr/local/bin/gulp
npm ERR! errno &lt;span class="nt"&gt;-17&lt;/span&gt;
npm ERR! EEXIST: file already exists, symlink &lt;span class="s1"&gt;'../lib/node_modules/gulp-cli/bin/gulp.js'&lt;/span&gt; -&amp;gt; &lt;span class="s1"&gt;'/usr/local/bin/gulp'&lt;/span&gt;
npm ERR! File exists: /usr/local/bin/gulp
npm ERR! Remove the existing file and try again, or run npm
npm ERR! with &lt;span class="nt"&gt;--force&lt;/span&gt; to overwrite files recklessly.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🤔 -- Well, what is this now? Something else already exists there? Well, that's fine I will just remove it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mbp-mcale:~ matt.cale&lt;span class="nv"&gt;$ &lt;/span&gt;npm uninstall &lt;span class="nt"&gt;-g&lt;/span&gt; gulp
up to &lt;span class="nb"&gt;date &lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;0.021s
mbp-mcale:~ matt.cale&lt;span class="nv"&gt;$ &lt;/span&gt;npm uninstall &lt;span class="nt"&gt;-g&lt;/span&gt; gulp-cli
up to &lt;span class="nb"&gt;date &lt;/span&gt;&lt;span class="k"&gt;in &lt;/span&gt;0.021s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's try again! Doh! Same error? What the heck?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;cracks knuckles and neck&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's figure this out! to the Googles/Stackoverflows!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Googles: "EEXIST: file already exists, symlink"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A bit of a bust to be honest, one well intentioned gentlemen here was having a different problem and his &lt;a href="https://stackoverflow.com/questions/36634657/how-do-i-fix-this-npm-install-conflict-between-existing-files-symlinks"&gt;solution&lt;/a&gt; was just deleting the items from the package.json and being careful about node versions and environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The mystery thickens!&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;At this point I could try fancier &lt;em&gt;googles&lt;/em&gt;, but I am pretty keen on finding the solution myself. So I dawn my spelunking gear and head to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which gulp &lt;span class="c"&gt;# --&amp;gt; /usr/local/bin/gulp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Cavern One&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mbp-mcale:~ matt.cale&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; /usr/local/bin/gulp
/usr/local/bin/gulp -&amp;gt; ../lib/node_modules/glup-cli/bin/gulp.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait a tick! What the heck is &lt;code&gt;glup-cli&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;As it turns out &lt;code&gt;glup-cli&lt;/code&gt; is, in my opinion, a poorly named (verging on suspicious) package that will take the place of the global &lt;code&gt;gulp&lt;/code&gt; command and instead of running gulp task will, AFAICT, (I didn't run the thing) attempt to scaffold out a basic Express project.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;The project, &lt;strong&gt;to me&lt;/strong&gt;, seems to be a misnomer, but there you have it! Uninstall &lt;code&gt;glup-cli&lt;/code&gt; and install and &lt;code&gt;gulp-cli&lt;/code&gt; and head out being a little less frustrated. 💚&lt;/p&gt;

</description>
      <category>node</category>
      <category>gulp</category>
      <category>npm</category>
      <category>matthewcalecom</category>
    </item>
  </channel>
</rss>
