<?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: Derek Hopper</title>
    <description>The latest articles on DEV Community by Derek Hopper (@derekjhopper).</description>
    <link>https://dev.to/derekjhopper</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%2F49275%2F23ed61d9-1614-4aad-8e35-182c9430ad97.jpg</url>
      <title>DEV Community: Derek Hopper</title>
      <link>https://dev.to/derekjhopper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/derekjhopper"/>
    <language>en</language>
    <item>
      <title>Build a simple Vue calendar without webpack</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Wed, 26 Aug 2020 01:03:42 +0000</pubDate>
      <link>https://dev.to/derekjhopper/build-a-simple-vue-calendar-without-webpack-561a</link>
      <guid>https://dev.to/derekjhopper/build-a-simple-vue-calendar-without-webpack-561a</guid>
      <description>&lt;p&gt;I needed a calendar (or a date picker) for a product I'm working on. In the past, I would have always reached for a library.&lt;/p&gt;

&lt;p&gt;A calendar isn't usually something I want to maintain myself and the features in a library typically cover many different use cases. However, in this case, I wanted to see what I could build in a couple hours.&lt;/p&gt;

&lt;p&gt;So, let's build a calendar with Vue. We'll use a single HTML file. We won't use webpack or babel. We won't need to compile or install anything at all.&lt;/p&gt;

&lt;p&gt;Here's what the end product will look like.&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QxVmxJTL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/EgCNYDuWkAAxR2q.png" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dj5-S5X2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1004713760752218113/hm7Gld-b_normal.jpg" alt="Derek profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Derek
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="comment-mentioned-user" href="https://dev.to/derekjhopper"&gt;@derekjhopper&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4t6ys1m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      First time using &lt;a href="https://t.co/EMQfdooZTh"&gt;date-fns.org&lt;/a&gt; and I was able to cobble together a working calendar component in Vue in a couple hours. A delightful experience.&lt;br&gt;&lt;br&gt;In the past, I would always reach for a library because I thought calendars were too complex to manage myself. 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:21 PM - 22 Aug 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1297192294895026182" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-reply-action.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1297192294895026182" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-retweet-action.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      0
      &lt;a href="https://twitter.com/intent/like?tweet_id=1297192294895026182" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://practicaldev-herokuapp-com.freetls.fastly.net/assets/twitter-like-action.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
      0
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;We'll start with this template. It contains everything we'll be using to get the job done.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://tailwindcss.com"&gt;tailwind&lt;/a&gt;: a utility-first CSS framework&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vuejs.org"&gt;vue&lt;/a&gt;: a JavaScript framework for building user interfaces&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://date-fns.org"&gt;date-fns&lt;/a&gt;: a date utility library&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://lodash.com/"&gt;lodash&lt;/a&gt;: a utility library
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&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;title&amp;gt;&lt;/span&gt;Calendar.vue&lt;span class="nt"&gt;&amp;lt;/title&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://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css"&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;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/vue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js"&lt;/span&gt;
    &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha512-F+u8eWHrfY8Xw9BLzZ8rG/0wIvs0y+JyRJrXjp3VjtFPylAEEGwKbua5Ip/oiVhaTDaDs4eU2Xtsxjs/9ag2bQ=="&lt;/span&gt;
    &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"py-12"&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;"container mx-auto flex justify-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;id=&lt;/span&gt;&lt;span class="s"&gt;"calendar"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-1/3 rounded border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="ni"&gt;&amp;amp;nbsp;&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;script&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#calendar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&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;p&gt;To start, it's helpful to think about how a calendar can be represented in a data structure. This is how I thought it could look.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;august2020&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&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="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&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;I wanted a data structure that could easily map to DOM elements. If we look at &lt;code&gt;august2020&lt;/code&gt;, we can see how each array could be a row in the calendar and each value inside the array could map to a &lt;code&gt;div&lt;/code&gt;. &lt;code&gt;null&lt;/code&gt; values would be an empty &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The challenge is that we need to build this data structure anytime the month is changed. A month can start and end on any day of the week, so we need to come up with an algorithm.&lt;/p&gt;

&lt;p&gt;Let's get started.&lt;/p&gt;

&lt;p&gt;We're going to need three functions. One to get the first day of the month, one to get the last day of the month, and one to get the number of days in the month. We'll use those functions to determine where to start drawing our calendar. In other words, how many empty elements do we need before we draw 1 and how many empty elements do we need after we draw 31.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#calendar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// August 1, 2020&lt;/span&gt;
    &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;startOfMonth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;endOfMonth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;daysInMonth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDaysInMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;dateFns&lt;/code&gt; object is provided by date-fns. The functions we're calling do what you'd expect them to do (awesome, right?).&lt;/p&gt;

&lt;p&gt;Once we have the beginning and the end of the month, we have enough to build the &lt;code&gt;august2020&lt;/code&gt; data structure shown above. What we'll be building are the weeks of August 2020. We'll use the weeks to display the month of August 2020 on the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"py-12"&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;"container mx-auto flex justify-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;id=&lt;/span&gt;&lt;span class="s"&gt;"calendar"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-1/3 rounded border"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;section&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"(week, weekIndex) in weeks"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"weekIndex"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border-t"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"(day, dayIndex) in week"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"`${weekIndex}-${dayIndex}`"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 p-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                {{day &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; day.getDate()}}
              &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/section&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;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;el&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#calendar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// August 1, 2020&lt;/span&gt;
        &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;computed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;startOfMonth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;endOfMonth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endOfMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;daysInMonth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDaysInMonth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;weeks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;firstDayOfWeek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startOfMonth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;days&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

          &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;firstDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;

          &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;daysInMonth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;

          &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;lastDayOfWeek&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;endOfMonth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;lastDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;

          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&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="p"&gt;})&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The result of the above code looks like this. Let's break it down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wIwDeWp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ggr93twdwh2jwly62pm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wIwDeWp2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/0ggr93twdwh2jwly62pm.png" alt="A basic calendar built with Vue for August 2020"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we determine the first day of the week (August 2020 starts on a Saturday), we can figure out how many blanks we need. In this case, we need six blanks. A loop that goes from 0 to 5 will give us just that. At this point, the &lt;code&gt;days&lt;/code&gt; array looks like this: &lt;code&gt;[null, null, null, null, null, null]&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;firstDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;At this point, we can add days 1-31 since we know there are 31 days in August. A loop that goes from 1 to 31 can get the job done. Instead of using integers, we push in &lt;code&gt;Date&lt;/code&gt; objects. We use &lt;code&gt;dateFns.setDate(this.date, i)&lt;/code&gt; to get a new date object set to the value of &lt;code&gt;i&lt;/code&gt;. This will come in handy for other purposes.&lt;/p&gt;

&lt;p&gt;After this look executes, &lt;code&gt;days&lt;/code&gt; is an array with 6 null values followed by the integers 1 to 31.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;daysInMonth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&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;Finally, once we're done with that, we can use the last day of the month to determine how many blanks we need to fill in the rest of the calendar. August 2020 ends on a Monday, so we need to fill in five blanks to finish. A loop that goes from 0 to 4 is here to help.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;lastDayOfWeek&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&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;days&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&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;Now, let's add some labels. To do that, we need a little HTML and a formatting function. We want to display August 2020 at the top with labels for each day of the week.&lt;/p&gt;

&lt;p&gt;We'll add the following to our Vue template directly above the &lt;code&gt;&amp;lt;section&amp;gt;&lt;/code&gt; for displaying the weeks and days.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-grow text-center text-lg font-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{month}}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex bg-gray-100 border-t text-gray-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;S&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;M&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;T&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;W&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;R&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;F&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-1 text-center border-r last:border-r-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;S&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And the function for &lt;code&gt;month&lt;/code&gt; is a simple one as well. Again, &lt;code&gt;dateFns&lt;/code&gt; is provided by date-fns and we use its format function. &lt;code&gt;'MMMM YYYY'&lt;/code&gt; just says give us a string representation of the date that looks like August 2020.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MMMM YYYY&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Doing that gets us to this point. Here's what the calendar looks like n ow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U4JgZYNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hjw5l1augdssv5b0zfwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U4JgZYNF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/hjw5l1augdssv5b0zfwp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The last thing we need to do is allow ourselves to navigate to the previous and next months. This is the fun part. Everything we've done so far is setting us up to use Vue's most powerful feature: reactivity.&lt;/p&gt;

&lt;p&gt;Whenever &lt;code&gt;date&lt;/code&gt; changes, Vue will re-use the code we already wrote and draw a new calendar based on the new date. So if we change the date to be July 2020, we'll get a July 2020 calendar drawn for us. Let's do it.&lt;/p&gt;

&lt;p&gt;First, we need a couple links to click on. We need a link that says "Previous" and a link that says "Next". Something like this will do just fine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ml-4 flex-shrink cursor-pointer text-gray-800 underline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Previous&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-grow text-center text-lg font-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{month}}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ml-4 flex-shrink cursor-pointer text-gray-800 underline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you might be able to tell, these links don't do anything. We don't have them hooked up to Vue at all, but that's easy enough - let's do it. We'll need a method and then tell the links to call that method when clicked. The previous link will decrement the month by 1 and the next link will increment the month by 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nx"&gt;methods&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;changeMonth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;by&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;dateFns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addMonths&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;by&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="c1"&gt;// ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;v-on:click=&lt;/span&gt;&lt;span class="s"&gt;"changeMonth(-1)"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ml-4 flex-shrink cursor-pointer text-gray-800 underline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Previous&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex-grow text-center text-lg font-bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{month}}&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;v-on:click=&lt;/span&gt;&lt;span class="s"&gt;"changeMonth(1)"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"ml-4 flex-shrink cursor-pointer text-gray-800 underline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Next&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;When we click on the previous link, Vue calls our function with -1 as the argument. Then our function adds -1 months to the current date (which is August 1, 2020). This tells Vue to re-render our component with July 2020 as the current date. We're done.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VWSAP44E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q1njjr5a66x7vv5geyfo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VWSAP44E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/q1njjr5a66x7vv5geyfo.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jsfiddle.net/rdcv3h96/"&gt;If you'd like to view the full version, check it out on JSFiddle.&lt;/a&gt; Feel free to copy and paste this to your local machine and play around with it.&lt;/p&gt;

&lt;p&gt;If you found this helpful, &lt;a href="https://twitter.com/derekjhopper"&gt;follow me on Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Using SQL with ActiveRecord for performance gains</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Sat, 22 Aug 2020 00:52:01 +0000</pubDate>
      <link>https://dev.to/derekjhopper/don-t-forget-you-can-use-sql-to-get-things-done-3ae4</link>
      <guid>https://dev.to/derekjhopper/don-t-forget-you-can-use-sql-to-get-things-done-3ae4</guid>
      <description>&lt;p&gt;While working on a side project, I had a need to count items by day of the month. While this can likely be achieved in Ruby, I reached for SQL instead.&lt;/p&gt;

&lt;p&gt;I have a table called &lt;code&gt;journal_entries&lt;/code&gt;. It has the following columns.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Column   |              Type              | Collation | Nullable |                   Default
------------+--------------------------------+-----------+----------+---------------------------------------------
 id         | bigint                         |           | not null | nextval('journal_entries_id_seq'::regclass)
 journal_id | bigint                         |           |          |
 body       | text                           |           | not null |
 created_at | timestamp(6) without time zone |           | not null |
 updated_at | timestamp(6) without time zone |           | not null |
 metadata   | jsonb                          |           | not null | '"{}"'::jsonb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For a given &lt;code&gt;journal&lt;/code&gt;, I wanted to count the number of journal entries per day. To do that, I ended up with a method called &lt;code&gt;entries_by_day&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;entries_by_day&lt;/span&gt;
  &lt;span class="n"&gt;journal&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;journal_entries&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;created_at: &lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"extract(day from created_at AT TIME ZONE '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formatted_offset&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;')::int"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For the most part, this is a normal ActiveRecord query. We're querying for a journal's journal entries within a given interval. In our case, an interval would be something like July 1, 2020 to July 31, 2020.&lt;/p&gt;

&lt;p&gt;Then, we use the &lt;code&gt;group&lt;/code&gt; method &lt;a href="https://guides.rubyonrails.org/active_record_querying.html#group"&gt;which is pretty cool&lt;/a&gt;. This translates to a &lt;code&gt;GROUP BY&lt;/code&gt; in SQL. To group the rows, we use the &lt;code&gt;extract&lt;/code&gt; function provided by PostgreSQL (&lt;a href="https://www.postgresql.org/docs/8.1/functions-datetime.html"&gt;documentation&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;What we're saying is this. Give me the day (1, 2, 3, ..., 31) based on the timestamp. If the timestamp is &lt;code&gt;2020-08-11 19:05:59.508883&lt;/code&gt;, &lt;code&gt;extract&lt;/code&gt; would give us &lt;code&gt;11&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What we end up with is a &lt;code&gt;Hash&lt;/code&gt; with the days as keys and the count as values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This has the advantage of offloading performance concerns to the database. PostgreSQL can typically do these types of operations faster.&lt;/p&gt;

&lt;p&gt;If we were to attempt the same in Ruby, we would need to query for all of the records within the month of July. Then, we'd have to use Ruby's &lt;code&gt;group_by&lt;/code&gt; method to finish the job.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Heroku is still the best way to start a hobby project</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Sun, 16 Aug 2020 15:02:04 +0000</pubDate>
      <link>https://dev.to/derekjhopper/heroku-is-still-the-best-way-to-start-a-hobby-project-3cg4</link>
      <guid>https://dev.to/derekjhopper/heroku-is-still-the-best-way-to-start-a-hobby-project-3cg4</guid>
      <description>&lt;p&gt;The most important step when you start a project is to get it deployed somewhere, anywhere. Running your code in your local development environment is great, but getting your deployment workflow setup is the holy grail.&lt;/p&gt;

&lt;p&gt;When I started a hobby project about a month ago, I searched and searched for Heroku alternatives. In the past, I knew Heroku had a tendency to be costly. Heroku can also lack flexibility in certain situations.&lt;/p&gt;

&lt;p&gt;After what seemed like an exhaustive search, I gave up. There are alternatives to Heroku, but nothing caught my eye. I had used AWS Elastic Beanstalk for a product in the past, but the initial setup took hours I didn't want to spend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ultimately, here's what I wanted in a service
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Automated deployment when merging to master&lt;/li&gt;
&lt;li&gt;Automated deployment when the tests pass&lt;/li&gt;
&lt;li&gt;One click setup of the database, Redis&lt;/li&gt;
&lt;li&gt;Process monitoring for Sidekiq&lt;/li&gt;
&lt;li&gt;Easy, simple cron&lt;/li&gt;
&lt;li&gt;Easy, simple scaling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To this day, Heroku still checks all those boxes. Even more so, everything has improved since I last used Heroku.&lt;/p&gt;

&lt;p&gt;I booted up my Heroku account and started looking around. To my surprise, there was a lot I could scale up for free.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I got out of Heroku
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A small PostgreSQL database&lt;/li&gt;
&lt;li&gt;A small Redis instance&lt;/li&gt;
&lt;li&gt;Cron&lt;/li&gt;
&lt;li&gt;A single web dyno&lt;/li&gt;
&lt;li&gt;A single Sidekiq dyno&lt;/li&gt;
&lt;li&gt;Automated deployments integrated with CircleCI&lt;/li&gt;
&lt;li&gt;Bonus: Free Mailgun&lt;/li&gt;
&lt;li&gt;Bonus: Free Sentry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gPiUDnmf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6914m8c9j2jyorw703v4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gPiUDnmf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/6914m8c9j2jyorw703v4.png" alt="Heroku Dynos &amp;amp; Add-ons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I did all of this with minimal configuration. I didn't write any YAML. I don't deploy via the terminal. I don't worry about processes being killed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The only annoyance is dynos going to sleep.&lt;/strong&gt; Since the product I'm building isn't in production yet, that's not a big deal.&lt;/p&gt;

&lt;p&gt;However, what I do have is a complete deployment workflow and somewhere to ship my code automatically. Instead of worrying about DevOps, I can focus on building. That's worth a lot to me.&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>Don't be a meanie when contributing to open source</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Thu, 02 Jul 2020 01:23:58 +0000</pubDate>
      <link>https://dev.to/derekjhopper/don-t-be-a-meanie-when-contributing-to-open-source-4omh</link>
      <guid>https://dev.to/derekjhopper/don-t-be-a-meanie-when-contributing-to-open-source-4omh</guid>
      <description>&lt;p&gt;In 2019, I replied to a post here on DEV about &lt;a href="https://dev.to/derekjhopper/comment/87d1"&gt;contributing to open source&lt;/a&gt;. After a year (and 10 years of COVID), it feels like a good time to share those tips again and expand on what I wrote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give thanks
&lt;/h2&gt;

&lt;p&gt;Whether you're reporting an issue or opening a pull request, thank the author(s) for their work. To me, this becomes especially important if you're using their code in one of your projects.&lt;/p&gt;

&lt;p&gt;This is a great time to thank them for making your life easier. Use this as a chance to start off on the right foot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read their contribution guidelines
&lt;/h2&gt;

&lt;p&gt;Many projects these days have a few places to help you get started.&lt;/p&gt;

&lt;p&gt;First, look for a file named CONTRIBUTING.md and read it. Often, this file will include information on how to report issues, open pull requests, and other ways you may be able to contribute.&lt;/p&gt;

&lt;p&gt;Second, watch out for CODE_OF_CONDUCT.md and read it carefully. Think of this file as a primer before you communicate to anyone on the project. Be mindful and stay within the rules of the project.&lt;/p&gt;

&lt;p&gt;Lastly, use DEV as an example. Here's the &lt;a href="https://github.com/thepracticaldev/dev.to/blob/master/CONTRIBUTING.md"&gt;CONTRIBUTING.md&lt;/a&gt; and &lt;a href="https://github.com/thepracticaldev/dev.to/blob/master/CODE_OF_CONDUCT.md"&gt;CODE_OF_CONDUCT.md&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsure? Open an issue and discuss it
&lt;/h2&gt;

&lt;p&gt;If the CONTRIBUTING.md file doesn't explain what the project is open to accepting, use an issue to propose your change. Politely ask the project if it's something they'd be interested.&lt;/p&gt;

&lt;p&gt;This can apply to bug fixes and is gravely important for new features. If you don't want to be disappointed, don't spend time working on a feature the project may not be interested in accepting. Some projects simply don't accept new features anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find a bug? Provide a failing test case
&lt;/h2&gt;

&lt;p&gt;The best way to communicate a bug is to either provide a failing test case or the steps to reproduce it.&lt;/p&gt;

&lt;p&gt;If you know the language the project is written in, fork the repository and write a test proving the bug you're reporting. Give a link to your fork when opening the issue.&lt;/p&gt;

&lt;p&gt;If you don't know the language or you're unsure of how to write the test, try to give as much information as possible. Explain how to reproduce it. This is a good time to check the CONTRIBUTING.md file where they may have a template for reporting issues.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make yourself available
&lt;/h2&gt;

&lt;p&gt;Once you open an issue or pull request, don't go radio silent. Be ready to respond in a timely manner if the maintainers have questions.&lt;/p&gt;

&lt;p&gt;Your work is much more likely to be accepted if you're willing to work with the maintainers to make it so. Maintaining an open source project is a time consuming endeavor. Anytime you can save the maintainers is a job well done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Follow the conventions
&lt;/h2&gt;

&lt;p&gt;This is a guideline you can use anywhere where software is developed. Try to stay within the conventions of the project.&lt;/p&gt;

&lt;p&gt;If the project uses four spaces for indentation, use four spaces - not two. If the project uses tabs instead of spaces, use spaces - just kidding, use tabs.&lt;/p&gt;

&lt;p&gt;This even goes as far as how tests are written. Try to follow the patterns laid out by the project. This increases the likelihood of your code being merged.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explain as much as possible
&lt;/h2&gt;

&lt;p&gt;Once you've worked hard to finish a pull request, try to be a good writer and explainer. Share why you did things a certain way. If you're unsure of a particular section, point that out.&lt;/p&gt;

&lt;p&gt;Your goal should be to make it easy on the maintainers of the project. Don't be afraid to point out rough sections of the code or parts that may not make sense to the next person that reads it.&lt;/p&gt;

&lt;p&gt;Imagine the maintainer knows nothing about what you did.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be nice
&lt;/h2&gt;

&lt;p&gt;Finally, nobody is going to get mad at you for being nice. Someone that's easy to work with is usually better than someone that's not.&lt;/p&gt;

&lt;p&gt;It's common for open source maintainers to do their work in the moonlight. Be a pal and avoid getting frustrated if things take longer than you think they should. Ask if there's anything you can do to help the process along.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about you?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Do you have any examples of issues you've reported or pull requests you've opened and you followed some of these guidelines?&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>github</category>
    </item>
    <item>
      <title>How to choose the right HTTP status code</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Wed, 24 Jun 2020 00:07:41 +0000</pubDate>
      <link>https://dev.to/derekjhopper/status-codes-have-consequences-more-often-than-you-think-56a6</link>
      <guid>https://dev.to/derekjhopper/status-codes-have-consequences-more-often-than-you-think-56a6</guid>
      <description>&lt;p&gt;Take a look at the following code. It's a jQuery &lt;code&gt;$.ajax&lt;/code&gt; request asking for a cast member of The Office.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/status/Michael&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="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;If the response includes an error property, the request is considered an error and we alert the user. Otherwise, a message is shown about the character.&lt;/p&gt;

&lt;p&gt;This works. However, it's a little contradictory and some might consider it a code smell. After all, we're handling errors inside the &lt;code&gt;success&lt;/code&gt; callback. This is a clue that something should likely be changed on the server.&lt;/p&gt;

&lt;p&gt;Since we have to handle both cases within the &lt;code&gt;success&lt;/code&gt; callback, we have a fairly good idea the server is returning a &lt;code&gt;20x&lt;/code&gt; status code for both successful and bad requests. Taking a peek at the server, this is what we might see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StatusesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="no"&gt;CHARACTERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Michael"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Dwight"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Angela"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;CHARACTERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is a character on The Office."&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="s2"&gt;"Oops. There's an error."&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is the JavaScript we would like to write. We'd like to use both a &lt;code&gt;success&lt;/code&gt; and an &lt;code&gt;error&lt;/code&gt; callback. This code reads a little better now. We can clearly see what happens when a request is successful or a request has an error. We don't have to concern ourselves with a conditional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/status/Michael&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jqXHR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;jqXHR&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;responseJSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once the server returns a &lt;code&gt;404 Not Found&lt;/code&gt;, we can start using the &lt;code&gt;error&lt;/code&gt; callback. We might update the server to look like this. Notice how we've added a status to both cases.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StatusesController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="no"&gt;CHARACTERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Michael"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;show&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;CHARACTERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is a character on The Office."&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :ok&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="s2"&gt;"Oops. There's an error."&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :not_found&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Previously, as we know, the server was returning a &lt;code&gt;200 OK&lt;/code&gt; status code for both cases. After our update, &lt;code&gt;:ok&lt;/code&gt; refers to the status code of &lt;code&gt;200 OK&lt;/code&gt; while &lt;code&gt;:not_found&lt;/code&gt; refers to &lt;code&gt;404 Not Found&lt;/code&gt;. This allows our &lt;code&gt;$.ajax&lt;/code&gt; call to route the response to the corresponding callback based on the response's status code.&lt;/p&gt;

&lt;p&gt;This short example illustrates the importance of status codes and how a status code can affect anyone developing against it. When you're thinking about the implementation for a new endpoint or route, take a moment to think about what status code makes sense. A status code can have an effect on many things.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to watch out for
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Other developers
&lt;/h3&gt;

&lt;p&gt;As you saw in our example, a status code can have an influence on how a frontend developer builds against the backend. Oftentimes, we need to fetch data from the backend and the status codes can influence how this is done.&lt;/p&gt;

&lt;p&gt;If a status code is unexpected, you might see a weird bug. If we didn't know our server was returning a &lt;code&gt;200 OK&lt;/code&gt; for both successful and bad requests, our customers might run into interesting scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;Picking the wrong status code can provide clues to an attacker. For example, returning a status code other than 404 may give an attacker a clue that a given resource exists on the server.&lt;/p&gt;

&lt;p&gt;Take a look at this excerpt from the &lt;a href="https://developer.github.com/v3/#authentication"&gt;GitHub API documentation on authentication&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are two ways to authenticate through GitHub API v3. Requests that require authentication will return 404 Not Found, instead of 403 Forbidden, in some places. This is to prevent the accidental leakage of private repositories to unauthorized users.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we give out clues that a private resource exists, we begin to lose trust with our customers.&lt;/p&gt;

&lt;h3&gt;
  
  
  SEO
&lt;/h3&gt;

&lt;p&gt;If you have public endpoints, be careful when changing the status code. Using the wrong one can yield unexpected results.&lt;/p&gt;

&lt;p&gt;When introducing a redirect, it's considered best practice to use &lt;code&gt;301 Moved Permanently&lt;/code&gt;. A search engine will pass along any link juice to the new URL. If you use a &lt;code&gt;302 Found&lt;/code&gt;, it might not.&lt;/p&gt;

&lt;p&gt;Take a peek at respected literature on &lt;a href="https://moz.com/learn/seo/http-status-codes"&gt;SEO and status codes&lt;/a&gt; if you're in doubt or you'd just like to learn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;p&gt;If you're curious about status codes and what to do in certain situations, referencing popular frameworks is a good start. Take a look at what they're doing and consider how it may apply to your situation. Learning from others is key to growing your knowledge.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/heartcombo/responders"&gt;responders&lt;/a&gt; gem (which was extracted and removed from Rails 5.0) has a suite of tests illustrating how you could use status codes in your application.&lt;/p&gt;

&lt;p&gt;In this test, you can see &lt;code&gt;201 Created&lt;/code&gt; is expected when the request results in a resource being created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_using_resource_for_post_with_xml_yields_created_on_success&lt;/span&gt;
  &lt;span class="n"&gt;with_test_route_set&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application/xml"&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="ss"&gt;:using_resource&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="s2"&gt;"application/xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;media_type&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;name&amp;gt;david&amp;lt;/name&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="s2"&gt;"http://www.example.com/customers/13"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;location&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To handle an error, the test expects &lt;code&gt;422 Unprocessable Entity&lt;/code&gt;. It might be a good idea to use this status code when the user encounters a validation error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_using_resource_for_post_with_xml_yields_unprocessable_entity_on_failure&lt;/span&gt;
  &lt;span class="n"&gt;with_test_route_set&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="vi"&gt;@request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application/xml"&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;name: :invalid&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="no"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;any_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stubs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="ss"&gt;:using_resource&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="s2"&gt;"application/xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;media_type&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="mi"&gt;422&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;
    &lt;span class="n"&gt;assert_equal&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_xml&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;
    &lt;span class="n"&gt;assert_nil&lt;/span&gt; &lt;span class="vi"&gt;@response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;location&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Reference Material
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes"&gt;Wikipedia: List of HTTP status codes&lt;/a&gt;: A raw list of standard status codes.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status"&gt;Mozilla: HTTP response status codes&lt;/a&gt;: Explains the common use cases for each status code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;What's your experience with status codes? Have you been a part of any interesting debugging sessions with status codes?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>How have you used static site generators to creatively simplify things?</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Wed, 12 Dec 2018 17:11:46 +0000</pubDate>
      <link>https://dev.to/derekjhopper/how-have-you-used-static-site-generators-to-creatively-simplify-things-1gfo</link>
      <guid>https://dev.to/derekjhopper/how-have-you-used-static-site-generators-to-creatively-simplify-things-1gfo</guid>
      <description>&lt;p&gt;If what you normally use to build applications is a framework like Ruby on Rails, it becomes easy to use that tool for everything. Simple is often better. Sometimes using a static site generator is the better long-term option.&lt;/p&gt;

&lt;p&gt;Do you use static site generators like jekyll or gatsbyjs to do neat things? What use cases have you found best served by static site generators?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Thank You, 10 Open Source Projects that Helped Build a Business</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Wed, 21 Nov 2018 17:19:39 +0000</pubDate>
      <link>https://dev.to/derekjhopper/thank-you-10-open-source-projects-that-helped-build-a-business-4ndo</link>
      <guid>https://dev.to/derekjhopper/thank-you-10-open-source-projects-that-helped-build-a-business-4ndo</guid>
      <description>&lt;p&gt;Many of us likely benefit from the countless hours of effort put forth by open source contributors. We build businesses, serve customers, and learn so much standing on the shoulders of significant and valuable contributions by people who don't often get the recognition they deserve.&lt;/p&gt;

&lt;p&gt;If you're building software on the web, it's almost a certainty you've used software written by someone else. I hope this list will remind you to reflect on the open source software you use to build your apps and your businesses.&lt;/p&gt;

&lt;p&gt;Finally, in the spirit of giving thanks, here are 10 open source projects we've used to build a business. These projects help us solve problems for customers so they can run their business successfully. Without these projects, we wouldn't be able to do some of the things we're doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. rspec
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/rspec/rspec" rel="noopener noreferrer"&gt;https://github.com/rspec/rspec&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without rspec, we'd be lost. It's our setup of choice to write tests. It's the major tool that helps us keep our application stable and avoid major regressions. The &lt;a href="https://github.com/rspec/rspec/commit/ad41fa1106fd104769385975f285b81f108a1b65" rel="noopener noreferrer"&gt;first rspec commit&lt;/a&gt; was back in 2009 and will celebrate a 10 year anniversary next year. How many projects has rspec influenced over the years?&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/dchelimsky" rel="noopener noreferrer"&gt;dchelimsky&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. devise
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/plataformatec/devise" rel="noopener noreferrer"&gt;https://github.com/plataformatec/devise&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At the core of almost every application today is sign up and log in. There are so many concerns to think about from how authentication is implemented to properly handling security. We wanted to let the library with years of development handle this for us.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/josevalim" rel="noopener noreferrer"&gt;josevalim&lt;/a&gt; and &lt;a href="https://github.com/carlosantoniodasilva" rel="noopener noreferrer"&gt;carlosantoniodasilva&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. user_impersonate2
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/userimpersonate/user_impersonate2" rel="noopener noreferrer"&gt;https://github.com/userimpersonate/user_impersonate2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is one of our favorite tools to help support customers. It allows us to view the application as the customer sees it. It's highly valuable and has saved us days of time over the years. Oftentimes it's the things that appear simple that help us the most.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/drnic" rel="noopener noreferrer"&gt;drnic&lt;/a&gt; and &lt;a href="https://github.com/rcook" rel="noopener noreferrer"&gt;rcook&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. activeadmin
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/activeadmin/activeadmin" rel="noopener noreferrer"&gt;https://github.com/activeadmin/activeadmin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Speaking of customer support, we couldn't do a lot of the things we do without activeadmin. Much of our customer support is handled by performing tasks inside an activeadmin based admin panel. We do everything from pausing subscriptions to updating data for customers. An admin panel is certainly something you could build on your own, but why do that when you have a great tool like activeadmin.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/gregbell" rel="noopener noreferrer"&gt;gregbell&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. wicked_pdf
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mileszs/wicked_pdf" rel="noopener noreferrer"&gt;https://github.com/mileszs/wicked_pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is one of my favorites. Generating PDFs on your own is something most people will never want to do. We use wicked_pdf to generate signed injury waivers for the businesses we support. I'm so happy I didn't have to learn much about PDF generation to build it. This is a classic example of being thankful for the years of knowledge and experience involved with a project like wicked_pdf.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/mileszs" rel="noopener noreferrer"&gt;mileszs&lt;/a&gt;. Indiana represent!&lt;/p&gt;

&lt;h2&gt;
  
  
  6. gibbon
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/amro/gibbon" rel="noopener noreferrer"&gt;https://github.com/amro/gibbon&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We integrate with Mailchimp and we rely on a gem for that. Rolling your own gem isn't typically a great decision when such a great library exists to handle everything. Gibbon has helped us build a system that manages lists for many different businesses and send campaigns to millions of people. Hundreds of thousands of API calls have passed through this gem for us.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/amro" rel="noopener noreferrer"&gt;amro&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. delayed_job_web
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/ejschmitt/delayed_job_web" rel="noopener noreferrer"&gt;https://github.com/ejschmitt/delayed_job_web&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having a web interface to monitor your background workers doesn't seem like much, but it seriously helps. Even though the work was inspired by resque's web interface, it still provides a lot of value to us. We use it to investigate issues with our job queue and generally keep an eye on things.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/ejschmitt" rel="noopener noreferrer"&gt;ejschmitt&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  8. paperclip
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/thoughtbot/paperclip" rel="noopener noreferrer"&gt;https://github.com/thoughtbot/paperclip&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although paperclip is now deprecated in favor of ActiveStorage, it's served us well. We've used paperclip to handle file attachments in all sorts of places. Our customers attach documents to user accounts and we've used it to keep track of waivers I previously mentioned. We'll be moving away from it in the future, but it's saved us plenty of headache over the years.&lt;/p&gt;

&lt;p&gt;Thank you, everyone at &lt;a href="https://github.com/thoughtbot" rel="noopener noreferrer"&gt;thoughtbot&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. omniauth-stripe-connect
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/isaacsanders/omniauth-stripe-connect" rel="noopener noreferrer"&gt;https://github.com/isaacsanders/omniauth-stripe-connect&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Strategies for omniauth are always helpful. By using it, we don't have to learn much about the specifics of the way Stripe implements oauth. Our customers have connected hundreds of Stripe accounts via this gem and we couldn't be happier.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/isaacsanders" rel="noopener noreferrer"&gt;isaacsanders&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. ransack
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/activerecord-hackery/ransack" rel="noopener noreferrer"&gt;https://github.com/activerecord-hackery/ransack&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One feature our customers love is the ability to search for all sorts of things about their students. We haven't felt a need to implement elasticsearch just yet, so we use ransack instead.&lt;/p&gt;

&lt;p&gt;Thank you, &lt;a href="https://github.com/ernie" rel="noopener noreferrer"&gt;ernie&lt;/a&gt; and &lt;a href="https://github.com/jonatack" rel="noopener noreferrer"&gt;jonatack&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Although I only listed a few people specifically, these projects have hundreds of contributors. That's the beauty of open source; every little thing helps. To all of those contributors out there, thank you. When we work together, we can make the software world a better place.&lt;/p&gt;

&lt;p&gt;My hope with this list is to encourage you to look at your own software and the open source projects it relies on. Take a moment to think about these people who have influenced your own projects and your own businesses and companies.&lt;/p&gt;

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

</description>
      <category>webdev</category>
      <category>opensource</category>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>What tips do you have for homebrew users?</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Wed, 31 Oct 2018 15:04:44 +0000</pubDate>
      <link>https://dev.to/derekjhopper/what-tips-do-you-have-for-homebrew-users-bf0</link>
      <guid>https://dev.to/derekjhopper/what-tips-do-you-have-for-homebrew-users-bf0</guid>
      <description>&lt;p&gt;This morning, I recovered 110 GB of disk space thanks to one command.&lt;/p&gt;

&lt;p&gt;I'm a heavy homebrew user. I install packages all the time. On top of that, I brew update and brew upgrade quite often. I like to stay up to date.&lt;/p&gt;

&lt;p&gt;Over the years, I continued to install packages, update, and upgrade them. All the while I was ignoring one important command.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Story
&lt;/h2&gt;

&lt;p&gt;This morning, I was greeted with this alert. Hmmmm... I thought. What could this be?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jciO8Y0n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/635r8fzvxxni7yjqxmo0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jciO8Y0n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/635r8fzvxxni7yjqxmo0.png" alt="The Low Disk Space Alert"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My documents folder had a few gigabytes of data, but that wasn't filling up my entire disk. That's when I started exploring homebrew packages. I realized I had been keeping many, many old homebrew packages around for no reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Command
&lt;/h2&gt;

&lt;p&gt;That's when I ran the command &lt;code&gt;brew cleanup&lt;/code&gt;. Oh boy, I was in for a surprise. My terminal started spitting out line after line of this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--69XUTQv1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y2s2rxw2a99pfhqc657g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--69XUTQv1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y2s2rxw2a99pfhqc657g.png" alt="brew cleanup log"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's a lot of disk space!&lt;/p&gt;

&lt;p&gt;After that completed (which took about 15 minutes), I suddenly had 120 GB of free space to work with. And that got me thinking, what else do I not know about homebrew? Do you have any tips for us homebrew users out there?&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Delaying Decisions Until the Last Possible Moment</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Tue, 25 Sep 2018 16:06:16 +0000</pubDate>
      <link>https://dev.to/derekjhopper/delaying-decisions-until-the-last-possible-moment-3932</link>
      <guid>https://dev.to/derekjhopper/delaying-decisions-until-the-last-possible-moment-3932</guid>
      <description>&lt;p&gt;Let's go back in time. A few years ago, I started a project and immediately reached for Bootstrap. I added it to my asset bundle and got to work.&lt;/p&gt;

&lt;p&gt;I started writing HTML and sprinkling Bootstrap classes on every element. Before long, I had a handful of views tightly coupled to Bootstrap. I was dependent on it. Being dependent on something isn't necessarily a bad thing. After all, Bootstrap has helped push forward tens of thousands of applications on the internet.&lt;/p&gt;

&lt;p&gt;However, there's a problem. I started using Bootstrap before I needed it. Did I need to pick a frontend framework immediately? No. Guess what? Now I'm stuck with it. Unless I want to carefully edit all of my templates or slowly reduce Bootstrap usage to zero, I'm basically stuck using Bootstrap until the end of this application's life.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why wait to make decisions
&lt;/h2&gt;

&lt;p&gt;Picking Bootstrap was one of a handful of decisions I made immediately upon the project starting. Worse yet, picking Bootstrap was a non-critical decision turned critical.&lt;/p&gt;

&lt;p&gt;In other words, Bootstrap is not a core function of the application. It doesn't run business logic. It doesn't perform key functions of the critical work to be done. However, by making Bootstrap an early dependency, it's now key to the frontend. If I compulsively remove it, the frontend turns into a mess.&lt;/p&gt;

&lt;p&gt;Questions like "Should I use React?" and "What CSS framework should I include?" can be left unanswered for awhile. Otherwise, you risk adopting a dependency before it's truly needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of delaying decisions
&lt;/h2&gt;

&lt;p&gt;One way to help you skip decisions about the frontend is to write tests. Without tests, we're kind've forced to build a minimal frontend to verify our work. When you have to build a frontend, you're tempted to reach for dependencies you might not need.&lt;/p&gt;

&lt;p&gt;Starting with tests for business logic can help us avoid the need of a frontend. Instead of using the frontend to verify work, we can run our test suite.&lt;/p&gt;

&lt;p&gt;Let's say we're building the comment feature on dev.to. We want to notify the author when a new comment is posted. Without tests, we might create a new post, add a new comment, then check the author's notifications. That might require us to write a large amount of frontend code. It's possible we'd be making a number of decisions before we have a ton of knowledge about it.&lt;/p&gt;

&lt;p&gt;If we jump the gun and use React for all of this, we might be stuck with it. We might realize later we didn't really need it, but who wants to go back and rebuild what's already built?&lt;/p&gt;

&lt;p&gt;With tests, the story changes. We can ignore the frontend and save it for later. To get started, we'd write a test that creates a new comment. Then, we'd check to ensure the author has a new notification. Verifying our work is running a few tests. No frontend needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  This isn't the only way
&lt;/h2&gt;

&lt;p&gt;This is only an example. Delaying decisions about your frontend isn't something you always have to do. If your application is already based in React, it seems clear you'd continue using it. The same is true with Bootstrap. Once you're using it, the default is to continue using it.&lt;/p&gt;

&lt;p&gt;However, the spirit of delaying decisions is something to adopt. We might be tempted to think a decision is easy and without consequence, but slowing down is a good idea. "Of course we need to use this library," you might say, only to realize later it's not as great as you thought.&lt;/p&gt;

&lt;p&gt;The beauty of delaying decisions is that it can be applied to almost anything. Don't know what you want your backend to be? Build a minimal frontend as you work out the details. Not sure if you want to use Resque, Delayed Job, or Sidekiq? That's cool - you don't need to make that decision early in a project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delaying decisions saves you time
&lt;/h2&gt;

&lt;p&gt;When you make a decision too early and want to change it later, the decision costs you time. If it wasn't a decision that needed to be made, it's a double whammy. Most decisions can be delayed.&lt;/p&gt;

&lt;p&gt;If I would've waited to make a decision on Bootstrap, it would've been easy to adopt another framework. You can get away with building a frontend until you actually need a frontend. At the very least, your frontend can be basic until you need it to be fancy.&lt;/p&gt;

&lt;p&gt;Try something. When you reach your next decision, don't come up with an answer right away. Let the answer simmer and stew in your head. Do I really need to make a decision on this right now? Can I wait until I know more?&lt;/p&gt;

&lt;p&gt;You always have more information tomorrow. Take advantage of that fact.&lt;/p&gt;

</description>
      <category>devtips</category>
      <category>programming</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Not feeling motivated? Don't beat yourself up</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Wed, 19 Sep 2018 21:32:38 +0000</pubDate>
      <link>https://dev.to/derekjhopper/not-feeling-motivated-dont-beat-yourself-up-5ggp</link>
      <guid>https://dev.to/derekjhopper/not-feeling-motivated-dont-beat-yourself-up-5ggp</guid>
      <description>&lt;p&gt;About a month ago, there was a &lt;a href="https://twitter.com/ThePracticalDev/status/1032071484527849472" rel="noopener noreferrer"&gt;#DevDiscuss about how to stay motivated&lt;/a&gt;. Although I've had my struggles, I've never had a huge issue with staying motivated. #DevDiscuss prompted me to think about why.&lt;/p&gt;

&lt;p&gt;I hadn't thought about it. Why do I tend not to have motivation problems? Was I special? I don't think so, but maybe I was doing something to thwart the demotivation demon.&lt;/p&gt;

&lt;p&gt;Motivation can be tricky. Lack of motivation can be an even tougher nut to crack. One day you're motivated, the next day you're not. There are so many factors at play it's hard to keep track. Some of these factors come barreling at you, uncontrolled. Other factors are your own doing.&lt;/p&gt;

&lt;p&gt;When you're feeling unmotivated, don't beat yourself up for it. If you're looking for words of encouragement, turn to the Terminator. &lt;a href="https://np.reddit.com/r/bodybuilding/comments/968445/one_of_my_rules_is_break_the_rules/e3zbth3/?context=4" rel="noopener noreferrer"&gt;Arnold Schwarzenegger was recently asked for some advice&lt;/a&gt; on how to get motivated to hit the gym.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1032076043547561985-558" src="https://platform.twitter.com/embed/Tweet.html?id=1032076043547561985"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1032076043547561985-558');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1032076043547561985&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Don't try to act tough and power through bouts where you're feeling unmotivated. As Arnold says, "Sometimes life is a workout." That's ok. You'll have your tough days and you won't be as productive as you were yesterday.&lt;/p&gt;

&lt;p&gt;Even if you can't be perfect everyday, you can work to mitigate the effects of things that demotivate you. That's why it's important to search for what you can do to help. You won't be able to figure it out in a day.&lt;/p&gt;

&lt;p&gt;Make a little progress each day and you'll slowly improve. Treat yourself like cold brewed coffee, the best type of coffee, made low and slow.&lt;/p&gt;

&lt;p&gt;These are things that help me stay motivated. They might help you too.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Know when to take a break
&lt;/h2&gt;

&lt;p&gt;We all have our limits. I know my productivity decreases after I work on a tough problem. My brain starts to hurt.&lt;/p&gt;

&lt;p&gt;Even though I sit on a Herman Miller chair, sometimes my body still hurts. My neck might be positioned at a weird angle. My eyes sometimes hurt depending on the lighting that day.&lt;/p&gt;

&lt;p&gt;So take breaks. Get up, walk around, and find a glass of water. Let the blood flow throughout your body.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Try to find a balance
&lt;/h2&gt;

&lt;p&gt;If you're passionate about code, great! I'll often work on my own projects or open source after I'm done with my day job. I can't do it every night though.&lt;/p&gt;

&lt;p&gt;I have other hobbies and I think that's great. If you have hobbies outside of tech, I'm happy for you too. Your hobbies might even be loosely related to tech.&lt;/p&gt;

&lt;p&gt;For example, I love playing poker. As you learn more about the game, you realize the parallels between a game of poker and business.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Change it up
&lt;/h2&gt;

&lt;p&gt;Have you ever been in a new car? Remember the smell and how you felt.&lt;/p&gt;

&lt;p&gt;From time to time, your environment loses its new car smell. It's ok to work from another location. If you have a laptop, find a different desk or corner in your building - at least for a couple hours. If you work from home, try a different room or even work outside.&lt;/p&gt;

&lt;p&gt;If you can't work in a different location, even changing little things can work.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1034254963629850624-487" src="https://platform.twitter.com/embed/Tweet.html?id=1034254963629850624"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1034254963629850624-487');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1034254963629850624&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Be lazy for a night
&lt;/h2&gt;

&lt;p&gt;You might have nights where you want to do nothing. Do nothing! Just be lazy. Get away from code and don't even think about it. Sit on the couch and turn your brain off.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Work on the little things
&lt;/h2&gt;

&lt;p&gt;Finally, this is something I'll do on mornings when I feel a little off. I'll work on small tasks to stack some success. It gets the ball moving in the right direction.&lt;/p&gt;

&lt;p&gt;Oftentimes, I'll surprise myself. On a day I thought my productivity would be low, I'll be the most productive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It's ok to feel unmotivated. We've all been there. It's human nature.&lt;/p&gt;

&lt;p&gt;Don't beat yourself up for it. Don't try to be tough. Instead, find ways to help you cope with lack of motivation.&lt;/p&gt;

&lt;p&gt;Work through it slowly. Your long term productivity is more important than a few days of lackluster motivation.&lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>How do you sell refactoring to your team?</title>
      <dc:creator>Derek Hopper</dc:creator>
      <pubDate>Tue, 24 Jul 2018 16:37:28 +0000</pubDate>
      <link>https://dev.to/derekjhopper/how-do-you-sell-refactoring-to-your-team-21a6</link>
      <guid>https://dev.to/derekjhopper/how-do-you-sell-refactoring-to-your-team-21a6</guid>
      <description>&lt;p&gt;Refactoring is often a great thing to do. If you maintain a piece of software for years, chances are you'll refactor somewhat regularly.&lt;/p&gt;

&lt;p&gt;Even though refactoring is a good practice, your team might have plenty of valid reasons why it doesn't want to refactor something. How do you sell them on the idea?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>refactoring</category>
    </item>
  </channel>
</rss>
