<?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: Stephen Charles Weiss</title>
    <description>The latest articles on DEV Community by Stephen Charles Weiss (@stephencweiss).</description>
    <link>https://dev.to/stephencweiss</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%2F96520%2F6f9a7191-011c-4351-b7d4-3eb6528f5920.jpeg</url>
      <title>DEV Community: Stephen Charles Weiss</title>
      <link>https://dev.to/stephencweiss</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stephencweiss"/>
    <language>en</language>
    <item>
      <title>Configuring The AWS CLI</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Tue, 28 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/configuring-the-aws-cli-1mm7</link>
      <guid>https://dev.to/stephencweiss/configuring-the-aws-cli-1mm7</guid>
      <description>&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we can configure the AWS CLI, we need to gather a few pieces of information first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Access key ID&lt;/li&gt;
&lt;li&gt;Secret Access Key ID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you do not have these, you can generate them by going to the Identity and Access Management (IAM) service in your AWS Console.From there, select Access management &amp;gt; Users in the menu.&lt;/p&gt;

&lt;p&gt;Select the user for which you’d like to configure the AWS CLI.&lt;/p&gt;

&lt;p&gt;Select Security credentials and then under Access keys select “Create access key”.&lt;/p&gt;

&lt;p&gt;This is the only time you’ll be able to view the &lt;code&gt;Secret Access Key ID&lt;/code&gt; so be sure to write it down or download the CSV.&lt;/p&gt;

&lt;p&gt;Now that we have these IDs, we’re ready to proceed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple Use Case: One User
&lt;/h2&gt;

&lt;p&gt;If you only have one user that you need to configure, you can use the default process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws configure
AWS Access Key ID [None]: &amp;lt;Your Access Key ID&amp;gt;
AWS Secret Access Key [None]: &amp;lt;Your Secret Access Key ID&amp;gt;
Default region name [None]: us-west-2
Default output format [None]: json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will store the settings in the default profile which is used every time an AWS CLI command is run &lt;em&gt;unless otherwise specified&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Command Line Options
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;aws configure&lt;/code&gt; can take three different options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;--region&lt;/code&gt; - referencing the AWS region to send data to. It defaults to the closest, however can be specified, e.g., &lt;code&gt;us-east-1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--output&lt;/code&gt; - specifies the format of the output. Options are &lt;code&gt;json&lt;/code&gt;, &lt;code&gt;yaml&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt;, and &lt;code&gt;table&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--profile&lt;/code&gt; - adds a named profile to the AWS CLI configuration.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Multiple Users
&lt;/h2&gt;

&lt;p&gt;Imagine we have two users we need to switch between on a single machine (maybe they’re in different regions): &lt;code&gt;user1&lt;/code&gt; and &lt;code&gt;user2&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can configure them with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws configure --profile user1 --region us-east-1 --output json
$ aws configure --profile user2 --region us-west-2 --output json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;(Not shown is adding the Access and Secret Access Key IDs.)&lt;/p&gt;

&lt;p&gt;Now, when we need to run an AWS CLI command, we can do so like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws s3 ls
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;to use the default user or with a specified profile like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ aws s3 ls --profile user1
$ aws s3 ls --profile user2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>aws</category>
    </item>
    <item>
      <title>AWS IAM In 30 Seconds</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Tue, 28 Apr 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/aws-iam-in-30-seconds-2i6l</link>
      <guid>https://dev.to/stephencweiss/aws-iam-in-30-seconds-2i6l</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Preamble:&lt;/em&gt; I am exploring different areas of AWS and am finding the jargon overwhelming. To help myself, I’ll be writing up summaries of some of the different services I come across, what they are, some core concepts, and links to resources for future reference.&lt;/p&gt;

&lt;p&gt;All entries in the series are tagged with &lt;code&gt;aws in 30 seconds&lt;/code&gt; and can be found &lt;a href="https://stephencharlesweiss.comblog/tags/aws-in-30-seconds/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.aws.training/learningobject/video?id=16448"&gt;Introduction to AWS Identity and Access Management | AWS Training&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;High level: Identity &amp;amp; Access Management (IAM) is a service provided by AWS to manage individual and group access to AWS resources. This is accomplished by authenticating and authorizing users based on IAM users, roles and/or groups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;There are three different ways that a user can authenticate (a prerequisite to accessing any AWS resources):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;AWS CLI&lt;/li&gt;
&lt;li&gt;AWS SDKs&lt;/li&gt;
&lt;li&gt;AWS Management Console.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Authorization
&lt;/h2&gt;

&lt;p&gt;By default, all resources are private to a user’s account. To grant permissions IAM users and groups must be granted access via IAM policies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policies
&lt;/h2&gt;

&lt;p&gt;An IAM Policy is a JSON document that records the effects, actions, resources and optional conditions for what API calls a policy holder may invoke.&lt;/p&gt;

&lt;p&gt;Anything not &lt;em&gt;explicitly&lt;/em&gt; listed is not permitted. Here’s a sample policy: &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FleTIr-8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/scweiss1/image/upload/v1588091883/code-comments/aws-iam-30-seconds/sample-iam-policy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FleTIr-8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/scweiss1/image/upload/v1588091883/code-comments/aws-iam-30-seconds/sample-iam-policy.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Roles
&lt;/h2&gt;

&lt;p&gt;In addition to Groups, Policies, and Users, there are also IAM Roles.&lt;/p&gt;

&lt;p&gt;Roles are similar to Users in that they can be used to determine which resources are accessible, however they are &lt;em&gt;not&lt;/em&gt; uniquely associated with an individual and they have no standard login credentials.&lt;/p&gt;

&lt;p&gt;They are used to delegate access to a user temporarily. When a user assumes a role, they give up their own permissions and take on the permissions of the role.&lt;/p&gt;

&lt;p&gt;Utilizing IAM Roles avoids the need to modify a specific user’s permissions each time a change is required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Putting this into practice. Imagine setting up the permissions for an organization.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an IAM Group or groups&lt;/li&gt;
&lt;li&gt;Create IAM Policy (or policies) and assign them to the group(s)&lt;/li&gt;
&lt;li&gt;Create IAM Users for each individual and assign them to their respective IAM GroupIn this way, user permissions are efficiently managed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a user only needs temporary access to certain resources, IAM Roles are a good bet. They are also helpful in avoiding embedding credentials directly into an application.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/introduction.html"&gt;AWS Identity &amp;amp; Access Management User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id.html"&gt;IAM Identities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html"&gt;IAM in the context of s3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>iam</category>
    </item>
    <item>
      <title>Memoization: A Primer</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Mon, 02 Mar 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/memoization-a-primer-4h5a</link>
      <guid>https://dev.to/stephencweiss/memoization-a-primer-4h5a</guid>
      <description>&lt;h2&gt;
  
  
  Preamble
&lt;/h2&gt;

&lt;p&gt;I’ve been spending more time with them lately as a way to remind myself of some of the parts of programming I don’t have a chance to interact with on a daily basis. As with most things, when I learn things, or want to remember them, I write them down.&lt;/p&gt;

&lt;p&gt;I’ll likely write a few and &lt;a href="//stephencharlesweiss.com/tags/cs-fundamentals/"&gt;post them on my website, all tagged with &lt;code&gt;CS Fundamentals&lt;/code&gt;&lt;/a&gt; to make them easier to find.&lt;/p&gt;

&lt;p&gt;Today’s topic is memoization. In this post, we’ll be looking at two classic problems to understand how to identify good candidates for a memoized approach. Later, we’ll explore different memoization techniques to understand how they provide value.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Memoization?
&lt;/h2&gt;

&lt;p&gt;Let’s begin with a definition. From Wikipedia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In computing, memoization or memoisation is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again. Memoization has also been used in other contexts (and for purposes other than speed gains), such as in simple mutually recursive descent parsing.[1] Although related to caching, memoization refers to a specific case of this optimization, distinguishing it from forms of caching such as buffering or page replacement. In the context of some logic programming languages, memoization is also known as tabling.[2]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  When Is Memoization Useful?
&lt;/h2&gt;

&lt;p&gt;So, to memoize is to remember. What are we remembering? When is it useful?&lt;/p&gt;

&lt;p&gt;To memoize a function is to remember the output given a set of inputs. It’s useful whenever we find ourselves doing the same calculation multiple times.&lt;sup&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;It’s an optimization strategy to reduce the time complexity (&lt;a href="https://rob-bell.net/2009/06/a-beginners-guide-to-big-o-notation/"&gt;described with Big O notation&lt;/a&gt;) of an algorithm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawbacks Of Memoization
&lt;/h2&gt;

&lt;p&gt;Memoization is the trade off of space for speed. When a computer “remembers” it does so by storing that value in memory.&lt;/p&gt;

&lt;p&gt;At some point, that memory could grow unwieldly. Not discussed here is when or how to start cleaning up the cache though two common strategies are Least Recently Used (LRU) and Least Frequently Used (LFU). &lt;a href="https://stackoverflow.com/a/29225598"&gt;This conversation on Stack Overflow provides a nice example of the differences between LRU and LFU&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examples: Fibonacci And Factorials
&lt;/h3&gt;

&lt;p&gt;For the rest of this post, we’ll be exploring memoization by examining what is required to find the n&lt;sup&gt;th&lt;/sup&gt; number in the &lt;a href="https://en.wikipedia.org/wiki/Fibonacci_number"&gt;Fibonacci sequence&lt;/a&gt; and calculating the n&lt;sup&gt;th&lt;/sup&gt; &lt;a href="https://en.wikipedia.org/wiki/Factorial"&gt;factorial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Fibonacci sequence is defined as the value of the sum of the previous two numbers and the first two values in the sequence are 1. This can be written as:&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="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;previousLow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;previousHigh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&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;let&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;2&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;num&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tempHigh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;previousHigh&lt;/span&gt;
    &lt;span class="nx"&gt;previousHigh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;previousHigh&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;previousLow&lt;/span&gt;
    &lt;span class="nx"&gt;previousLow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tempHigh&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;previousHigh&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Calculating a factorial is accomplished by multiplying all non-negative numbers less than or equal to the desired number.&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="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&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="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="c1"&gt;// convention states that 0! is 1&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;
    &lt;span class="nx"&gt;num&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These implementations actually have a lot going for them. They’re fairly efficient (from a time complexity perspective, they’re both O(n) and keep space requirements to a minimum by discarding past calculations).&lt;/p&gt;

&lt;p&gt;Memoization, however, is a tactice of &lt;a href="https://en.wikipedia.org/wiki/Dynamic_programming"&gt;dynamic programming&lt;/a&gt; - which, simply stated, is the practice of reducing a problem into sub-problems and solving them recursively.&lt;/p&gt;

&lt;p&gt;Those sub-problems are: the sum of the two previous numbers for the Fibonacci sequence, and multiplying a number by one less than the number for factorials.&lt;sup&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Using Dynamic Programming, we can refactor these functions into their recrusive forms. That can look like the following:&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="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;num&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&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;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="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// convention states that 0! is 1&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In refactoring to a recursive solution, we traded simpler logic for potentially more function calls.&lt;/p&gt;

&lt;p&gt;If we diagram the function calls to calculate the fifth number in the fibonacci sequence vs the fifth factorial, the differences will become apparent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                                    fibonacci(5)
                                       _____________/ \____________
                           fibonacci(4) fibfibonacci(3)
                        __/ \__ / \
            fibonacci(3) fibonacci(2) fibonacci(2) fibonacci(1)
           / \ / \ / \
    fibonacci(2) fibonacci(1) fibonacci(1) fibonacci(0) fibonacci(1) fibonacci(0)
   / \
fibonacci(1) fibonacci(0)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Similaraly, calculating the fourth &lt;code&gt;factorial&lt;/code&gt;, you might wind up with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    factorial(5)
    / \
   5 factorial(4)
               / \
              4 factorial (3)
                        / \
                       3 factorial (2)
                                 / \
                                2 factorial (1)
                                          / \
                                         1 factorial (0)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In calculating a fibonacci number, we make the same call multiple times.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;function&lt;/th&gt;
&lt;th&gt;# of calls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;fib(5)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fib(4)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fib(3)&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fib(2)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fib(1)&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fib(0)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Said another way, the time complexity of calculating a fibonacci number with this algorithm is exponential. Each additional step (approximately) &lt;em&gt;doubles&lt;/em&gt; the number of steps required to solve it. This would be written as O(2&lt;sup&gt;n&lt;/sup&gt;) where &lt;code&gt;n&lt;/code&gt; is the sequence we’re seeking.&lt;sup&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Wouldn’t it be nice if we could &lt;em&gt;remember&lt;/em&gt; the value of &lt;code&gt;fib(1)&lt;/code&gt; so that we don’t have to make the call again? Or even better, once we solve &lt;code&gt;fib(3)&lt;/code&gt;, we could eliminate an entire branch of the call tree!&lt;/p&gt;

&lt;p&gt;That’s what memoization can offer. We’ll get to this in a moment.&lt;/p&gt;

&lt;p&gt;What about factorial? We don’t have that same repetition and the time complexity reflects that too. It continues to grows &lt;em&gt;linearlly&lt;/em&gt; with the number we’re seeking to calculate. That is, it’s still O(n).&lt;/p&gt;

&lt;p&gt;The value of memoization here won’t be reducing calls the &lt;em&gt;first&lt;/em&gt; time, but &lt;em&gt;subsequent&lt;/em&gt; calls. Imagine calling &lt;code&gt;factorial(3)&lt;/code&gt; or &lt;code&gt;factorial(6)&lt;/code&gt; next? If the computer remembered its previous calculations, it could immediately retrieve the answer for &lt;code&gt;factorial(3)&lt;/code&gt; (which was needed to calculate &lt;code&gt;factorial(5)&lt;/code&gt;) and &lt;code&gt;factorial(6)&lt;/code&gt; would be reduced to &lt;code&gt;6 * factorial(5)&lt;/code&gt; (where it can look up &lt;code&gt;factorial(5)&lt;/code&gt; immediately too).&lt;/p&gt;

&lt;p&gt;Now that we’ve seen examples of refactoring a problem into a recursive solution and identified areas where momoization might be useful, let’s talk about strategies!&lt;/p&gt;

&lt;h2&gt;
  
  
  Strategies For Memoization
&lt;/h2&gt;

&lt;p&gt;Practically, to memoize a function means that each time a calculation is performed, its result is stored in a persistent state that future calls can access. Let’s call that state a cache.&lt;/p&gt;

&lt;p&gt;We have options when it comes to creating the cache. Two we’ll look at are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Refactor to create a cache and an internal function for calculating as necessary&lt;/li&gt;
&lt;li&gt;Use a generalized memoization function which creates a closure with a cache present&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The problem itself can provide a suggestion about the appropriate approach, but both take advantage of storing previously calculated results in a cache.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aside On Cache Implementation
&lt;/h3&gt;

&lt;p&gt;How you implement the cache is up to you, though its helpful to consider the characteristics of different data structures for picking. For example, dictionaries is a great choice because of the ability to look up values in constant time (as opposed to a list where you might have to iterate over each item).&lt;sup&gt;4&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal Recursion With Cache
&lt;/h3&gt;

&lt;p&gt;By internal recursion, I mean create a new function that can be accessed by our &lt;code&gt;fibonacci&lt;/code&gt; function. This “internal” function holds all of the recursive logic, but the signature is modified to receive a cache that we define in our enclosing function.&lt;/p&gt;

&lt;p&gt;This would be useful in the case of the Fibonacci sequence where our recursive approach created multiple redundant calls. It might look like (&lt;a href="https://repl.it/@stephencweiss/memoizedFib"&gt;interactive repl here&lt;/a&gt;):&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="nx"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&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;calculateFibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;calculateFibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;num&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="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="nx"&gt;calculateFibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;calculateFibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&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;By creating the cache and passing it along to the new &lt;code&gt;calculateFibonacci&lt;/code&gt; function, we can add a check &lt;em&gt;first&lt;/em&gt; on the cache. If it’s present, we can skip right along to return the value.&lt;/p&gt;

&lt;p&gt;Notice, however, that this provides no benefit for &lt;code&gt;factorial&lt;/code&gt; because there’s no redundancy in the calls. We’ll need a different approach to gain benefits for that. Let’s look at that now.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generalized Memoization Function
&lt;/h3&gt;

&lt;p&gt;If the situation is such that we’ll be making the same computationally expensive call over and over, another opportunity is to memoize the results of the call itself so that if you see it again, the computer won’t need to crunch through it over and over.&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="nx"&gt;memoization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;args&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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;It’s worth noting that this solution only helps us with the case where we’re calling the &lt;em&gt;same&lt;/em&gt; function over and over.&lt;/p&gt;

&lt;p&gt;For example. If we tweaked the factorial function to print each time it’s called, like so:&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="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`factorial called with --&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;num&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;num&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// convention states that 0! is 1&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And then calling it multiple times, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memoizedFactorial&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memoizedFactorial&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memoizedFactorial&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;memoizedFactorial&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We’d see a series of calls for each invocation &lt;em&gt;except&lt;/em&gt; the final &lt;code&gt;memoizedFactorial&lt;/code&gt; because we will have already stored the call of &lt;code&gt;factorial&lt;/code&gt; with the argument(s) of &lt;code&gt;5&lt;/code&gt; in the cache:&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;// factorial called with --&amp;gt; 5&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 4&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 3&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 2&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 1&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 0&lt;/span&gt;
&lt;span class="c1"&gt;// 120&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 6&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 5&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 4&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 3&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 2&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 1&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 0&lt;/span&gt;
&lt;span class="c1"&gt;// 720&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 3&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 2&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 1&lt;/span&gt;
&lt;span class="c1"&gt;// factorial called with --&amp;gt; 0&lt;/span&gt;
&lt;span class="c1"&gt;// 6&lt;/span&gt;
&lt;span class="c1"&gt;// 120&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;a href="https://repl.it/@stephencweiss/generalMemoFactorial"&gt;Here’s a repl if you’d like to play with it for yourself.&lt;/a&gt; Included in the repl is &lt;a href="https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L10540"&gt;Lodash’s &lt;code&gt;memoize&lt;/code&gt; function&lt;/a&gt;, which you’ll see performs similarly, though, unsurprisingly, includes additional features and optimizations - more on these in the advanced usage section.&lt;sup&gt;5&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Combined Approach
&lt;/h3&gt;

&lt;p&gt;These two approaches (the internal and the general) can be combined to create even greater savings, though it requires a slightly more bespoke approach.&lt;/p&gt;

&lt;p&gt;Because the cache is generated &lt;em&gt;outside&lt;/em&gt; of the scope of the target function, we’ll need to pass it in as an argument. And then we’ll need to continue to forward it along all the way down.&lt;/p&gt;

&lt;p&gt;Our generalized memoization function looks very similar to our previous one, though we’re now passing along the cache into the bound function:&lt;sup&gt;6&lt;/sup&gt;&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="nx"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
  &lt;span class="k"&gt;return&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;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;arguments&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&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="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;val&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;This allows us to memoize the internal calls and store them in the same cache - similarly to how we memoized the Fibonacci sequence earlier:&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="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;// convention states that 0! is 1&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;num&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;num&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;cache&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;num&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, each call - both the initial call and every recursive invocation will be stored in the cache on its first appearance. (&lt;a href="https://repl.it/@stephencweiss/memoizedFactorial"&gt;repl for live testing&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Usage: Multiple Arguments
&lt;/h2&gt;

&lt;p&gt;One potential trip up when it comes to memoization can occur when the function takes multiple arguments. Our generalized memoization solution actually handles this case, but our internal one doesn’t.&lt;/p&gt;

&lt;p&gt;Can you spot the difference?&lt;/p&gt;

&lt;p&gt;It’s how the keys are generated.&lt;/p&gt;

&lt;p&gt;Imagine we weren’t memoizing &lt;code&gt;factorial&lt;/code&gt;, but &lt;code&gt;add&lt;/code&gt;, where add is defined as:&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="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this case, we can’t just write:&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="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;b&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&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;What happens when &lt;code&gt;b&lt;/code&gt; changes but &lt;code&gt;a&lt;/code&gt; stays the same? We’d retrieve the wrong result from the cache!&lt;/p&gt;

&lt;p&gt;There are any number of ways to create a key, the only rule is that it needs to be unique to the given arguments of the function. If you’re dealing with strings, numbers, etc. (i.e., &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Primitive"&gt;Primitive data types in Javascript&lt;/a&gt; &lt;em&gt;other than a Symbol&lt;/em&gt;), you might create a concatenated string:&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="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;b&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&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;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&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 data types include objects, or arrays, however, you might need a more custom resolver to create the key.&lt;sup&gt;5&lt;/sup&gt;&lt;/p&gt;

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

&lt;p&gt;That wraps up this primer on memoization. Hopefully you found it useful and learned a thing or two. If anything wasn’t clear (or worse, I am mistaken on any detail) - please let me know!&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dzone.com/articles/memoization-make-recursive-algorithms-efficient"&gt;Memoization: Make Recursive Algorithms Efficient | DZone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://inlehmansterms.net/2015/03/01/javascript-memoization/"&gt;JavaScript Function Memoization | In Lehman’s Terms&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/12133754/whats-the-difference-between-recursion-memoization-dynamic-programming"&gt;What’s the Difference Between Recursion, Memoization, and Dynamic Programming? | StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/6164629/what-is-the-difference-between-bottom-up-and-top-down"&gt;What’s the Difference Between Bottom Up and Top Down? | StackOverflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cs.stackexchange.com/questions/2644/is-there-a-difference-between-top-down-and-bottom-up-dynamic-programming"&gt;Is there a difference between top down and bottom up dynamic programming? | StackExchange&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Footnotes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;sup&gt;1&lt;/sup&gt; This type of solution in which a larger problem is broken down into smaller pieces is called Dynamic Programming. Memoization is one tactic used to improve the performance of a solution using dynamic programming.&lt;/li&gt;
&lt;li&gt;
&lt;sup&gt;2&lt;/sup&gt; Both of these sequences also have base cases which are important and which we’ll get to in a moment.&lt;/li&gt;
&lt;li&gt;
&lt;sup&gt;3&lt;/sup&gt; &lt;a href="https://stackoverflow.com/a/360773"&gt;A more precise Big O calculation would actually be O(1.6&lt;sup&gt;n&lt;/sup&gt;)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;sup&gt;4&lt;/sup&gt; A POJO (plain-old Javascript object) is an easily accessible implementation of a Dictionary with constant time lookup. For an implementation that’s likely closer to other languages, look into &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map"&gt;Map&lt;/a&gt; which has the benefit of:

&lt;ol&gt;
&lt;li&gt;Being iterable,&lt;/li&gt;
&lt;li&gt;Having guaranteed key order,&lt;/li&gt;
&lt;li&gt;Built in getters/setters,&lt;/li&gt;
&lt;li&gt;Can handle keys of any value (not just Strings or Symbols).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;sup&gt;5&lt;/sup&gt; In reviewing the Lodash implementation of memoize, I was most impressed by how &lt;a href="https://github.com/jdalton"&gt;John-David Dalton&lt;/a&gt; and the community addressed the issue of multiple arguments with an optional second argument of a custom resolver. The documentation didn’t offer an example of how it might be used, but fortunately &lt;a href="https://justinnoel.dev/"&gt;Justin Noel&lt;/a&gt; already wrote a post detailing it &lt;a href="https://justinnoel.dev/2019/06/06/lodash-memoize-with-a-resolver/"&gt;how to use a custom resolver with Lodash’s memoize&lt;/a&gt;. The crux is:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lodash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;memoizedAdd&lt;/span&gt; &lt;span class="o"&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;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The resolver creates a unique key for each combination of arguments (a and b in this case) by joining them together with a &lt;code&gt;-&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;sup&gt;6&lt;/sup&gt; For demonstration purposes, this time I refactored slightly to use an anonymous function definition instead of an anonymous arrow function. Two differences emerge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Function definitions have an arguments array which can be used to collect any arguments passed to a function. Function declarations do not have this, however they have the rest operator, which is why we used &lt;code&gt;...args&lt;/code&gt; in the previous example.&lt;/li&gt;
&lt;li&gt;We need to bind the context when using the function definition. This is because context of &lt;code&gt;this&lt;/code&gt; is set at invocation for function definitions, whereas it’s set at definition for arrow functions. The &lt;code&gt;.apply&lt;/code&gt; in this example binds it to the context in which it’s defined so that later, when it’s invoked, it will still have access to the cache.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>memoization</category>
      <category>fundamentals</category>
    </item>
    <item>
      <title>Global Themes, Variants, And Modes With Styled-Components</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Mon, 10 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/global-themes-variants-and-modes-with-styled-components-197b</link>
      <guid>https://dev.to/stephencweiss/global-themes-variants-and-modes-with-styled-components-197b</guid>
      <description>&lt;p&gt;If I were to list my strengths, web design wouldn’t top the list. None the less, I like learning about it and know that I’ll continue to improve over time by chipping away.&lt;/p&gt;

&lt;p&gt;One thing I’ve been struggling with since adding a dark mode to my site (I look forward to making this a much more &lt;em&gt;pleasant&lt;/em&gt; experience soon), was how the mode was intended to interact with the global theme. And then what happens if you want variants for components?&lt;/p&gt;

&lt;p&gt;I put together a &lt;a href="https://codesandbox.io/s/adoring-shannon-0yt60?fontsize=14&amp;amp;hidenavigation=1&amp;amp;theme=dark"&gt;CodeSandBox&lt;/a&gt; to play around with the concepts.&lt;/p&gt;

&lt;p&gt;Because it’s such a simple single page, I can see how all of the pieces come together and interact. It’s also made clear why my coworker, Justin Connor, put together a library called &lt;code&gt;styled-variants&lt;/code&gt;!&lt;/p&gt;

&lt;p&gt;Dealing with variants can &lt;em&gt;quickly&lt;/em&gt; become a hassle - particularly if you’re duplicating the logic between modes.&lt;/p&gt;

&lt;p&gt;The full code is below.&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;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./styles.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ThemeProvider&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;styled-components&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;powderblue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;72px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;72px&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;buttonVariant&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;light&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;boxShadowColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;teal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;boxShadowColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;grey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;boxShadowColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;secondary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;boxShadowColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;orange&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="s2"&gt;`
  background-color: &lt;/span&gt;&lt;span class="p"&gt;${({&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
  font-size: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
  color: &lt;/span&gt;&lt;span class="p"&gt;${({&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&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;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt;&lt;span class="s2"&gt;`
  box-shadow: 0.25rem 0.25rem
    &lt;/span&gt;&lt;span class="p"&gt;${({&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;variant&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;boxShadowColor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Wrapper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;styled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="s2"&gt;`
  background-color: &lt;/span&gt;&lt;span class="p"&gt;${({&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;;
  padding: 1rem;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMode&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&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;setMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nextMode&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ThemeProvider&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Wrapper&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Title&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;CodeSandbox&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;The&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h2&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;
          &lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;variant&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;buttonVariant&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Toggle&lt;/span&gt; &lt;span class="nx"&gt;Mode&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Wrapper&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ThemeProvider&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Another Angle To Understand Global State With React: Next.js</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Sun, 09 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/another-angle-to-understand-global-state-with-react-next-js-bg0</link>
      <guid>https://dev.to/stephencweiss/another-angle-to-understand-global-state-with-react-next-js-bg0</guid>
      <description>&lt;p&gt;Recently, I was playing around with &lt;a href="https://nextjs.org/"&gt;Next.js&lt;/a&gt; (simply referred to as Next from here on) to see how a framework might make building React applications simpler.&lt;/p&gt;

&lt;p&gt;When I got to the &lt;code&gt;_app.js&lt;/code&gt; page a light bulb went off. The page illustrates &lt;em&gt;how&lt;/em&gt; React applications manage global state.&lt;/p&gt;

&lt;p&gt;First, let’s understand the problem we’re trying to solve: If you refresh a page running a React application, all of the state is blown away.&lt;/p&gt;

&lt;p&gt;That means that React applications need to provide the appearance of navigating to different pages, updating the URL, creating a history, etc. &lt;em&gt;without&lt;/em&gt; actually loading a brand new page. (Coincidentally, this helped me understand why a good router is so important.)&lt;/p&gt;

&lt;p&gt;Now, coming back to Next, let’s examine the &lt;code&gt;_app.js&lt;/code&gt; component. This is provided by default by Next, but can be &lt;a href="https://nextjs.org/docs/advanced-features/custom-app"&gt;overridden with a custom file as needed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That’s what I’m doing here:&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="nx"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&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="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;m on every page!&amp;lt;/p&amp;gt;
      &amp;lt;Component {...pageProps} /&amp;gt;
    &amp;lt;/&amp;gt;
  )
}

export default MyApp
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Yeah, it’s not much. I’m simply adding a paragraph tag &lt;em&gt;before&lt;/em&gt; every &lt;code&gt;&amp;lt;Component&amp;gt;&lt;/code&gt; is rendered.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;Component&amp;gt;&lt;/code&gt; is the &lt;code&gt;page&lt;/code&gt; that’s loaded. &lt;code&gt;pageProps&lt;/code&gt; are any props passed along to the &lt;code&gt;Component&lt;/code&gt; - it’s an empty object if not using &lt;code&gt;getInitialProps&lt;/code&gt;.&lt;sup&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The effect, however, is that when we navigate between pages, the state that exists in &lt;code&gt;MyApp&lt;/code&gt; persists - &lt;em&gt;it&lt;/em&gt; is not being rerendered.&lt;/p&gt;

&lt;p&gt;To see this, here’s an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/gfkM9D5o7pjHUTjhdC/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/gfkM9D5o7pjHUTjhdC/giphy.gif" alt="React reload"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice in the video that the &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; doesn’t change or get reloaded even though the page contents change?&lt;/p&gt;

&lt;p&gt;If we were to put our state management, global styles, etc. at this level then, they can be loaded once and persist even while different pages are loaded underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnotes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;sup&gt;1&lt;/sup&gt; &lt;a href="https://nextjs.org/docs/api-reference/data-fetching/getInitialProps"&gt;&lt;code&gt;.getInitialProps&lt;/code&gt;&lt;/a&gt; is part of the Next API to asynchronously fetch data and then feed it to &lt;code&gt;props&lt;/code&gt;. The big catch on using it is that it will disable &lt;a href="https://nextjs.org/docs/advanced-features/automatic-static-optimization"&gt;Automatic Static Optimization&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
    </item>
    <item>
      <title>Git Commit Archeology: Digging In With Grep And Pickaxe</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Wed, 05 Feb 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/git-commit-archeology-digging-in-with-grep-and-pickaxe-52e0</link>
      <guid>https://dev.to/stephencweiss/git-commit-archeology-digging-in-with-grep-and-pickaxe-52e0</guid>
      <description>&lt;p&gt;In his talk &lt;a href="https://tekin.co.uk/2019/02/a-talk-about-revision-histories"&gt;“A Branch In Time”&lt;/a&gt; (&lt;a href="https://stephencharlesweiss.com/blog/2020-02-06/write-better-commits/"&gt;which I wrote about previously&lt;/a&gt;), Tekin Süleyman discussed how an engineer can explore the git history to understand the context of changes (assuming her peers wrote meaningful commit messages).&lt;/p&gt;

&lt;p&gt;Two tools that left me slackjawed when I saw them in action were &lt;code&gt;grep&lt;/code&gt; and the &lt;code&gt;pickaxe&lt;/code&gt;.&lt;sup&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I’ve been playing with both over the past few weeks and wanted to jot down the &lt;em&gt;how&lt;/em&gt; so that I wouldn’t forget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grep
&lt;/h2&gt;

&lt;p&gt;If the team is writing useful commit messages, then grep’ing them will be a valuable exercise.&lt;sup&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Git’s &lt;code&gt;grep&lt;/code&gt; option in the &lt;code&gt;git log&lt;/code&gt; allows searching of the entire commit history.&lt;/p&gt;

&lt;p&gt;From the manual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--grep=&amp;lt;pattern&amp;gt;
   Limit the commits output to ones with log message that matches the specified pattern (regular expression). With more than one --grep=&amp;lt;pattern&amp;gt;, commits whose message matches any of the given patterns are chosen (but see --all-match).
   When --show-notes is in effect, the message from the notes is matched as if it were part of the log message.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For example, looking through the commit history on this site for&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git log --grep "feat:"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I can see a full list of all of the commits which include &lt;code&gt;feat&lt;/code&gt; in the subject &lt;em&gt;or&lt;/em&gt; body.&lt;/p&gt;

&lt;p&gt;This is particularly useful if used in conjunction with &lt;a href="https://stephencharlesweiss.com/blog/2020-02-22/semantic-versioning-and-conventional-commits"&gt;Conventional Commits&lt;/a&gt; or some other standard commit template.&lt;/p&gt;

&lt;p&gt;As the manual suggests, you can also stack patterns to match.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git log --grep "feat:" --grep "major"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;By default, the patterns are inclusive, however, they can be made exclusionary (that is all required) with the inclusion of the &lt;code&gt;--all-match&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git log --grep "feat:" --grep "major" --all-match
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Pickaxe
&lt;/h2&gt;

&lt;p&gt;I think of the Pickaxe like grep, but for the diff itself. The &lt;a href="https://www.git-scm.com/docs/gitdiffcore#_diffcore_pickaxe_for_detecting_addition_deletion_of_specified_string"&gt;pickaxe actually comes from &lt;code&gt;diffcore&lt;/code&gt;&lt;/a&gt; (the family of commands that are used to compare two files), but is available for use within the &lt;code&gt;git log&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Specifically, the two standard ways to use the pickaxe are with the &lt;code&gt;-S&lt;/code&gt; and the &lt;code&gt;-G&lt;/code&gt; flags.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-S&lt;/code&gt; takes a string as an argument&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-G&lt;/code&gt; takes a regular expression&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this sounds intimidating. In practice it’s not.&lt;/p&gt;

&lt;p&gt;One key difference between the two options and noted in the manual is the scope of concern for the two options. Whereas the &lt;code&gt;-G&lt;/code&gt; looks for changes in the pattern, the &lt;code&gt;-S&lt;/code&gt; seems to be concerned only with the &lt;em&gt;number&lt;/em&gt; of changes of the pattern.&lt;/p&gt;

&lt;p&gt;From the manual:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To illustrate the difference between -S —pickaxe-regex and -G, consider a commit with the following diff in the same file:&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+ return !regexec(regexp, two-&amp;gt;ptr, 1, &amp;amp;regmatch, 0);
...
- hit = !regexec(regexp, mf2.ptr, 1, &amp;amp;regmatch, 0);
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;While git log -G”regexec(regexp” will show this commit, git log -S”regexec(regexp” —pickaxe-regex will not (because the number of occurrences of that string did not change).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Secret Weapon: Patch
&lt;/h2&gt;

&lt;p&gt;While &lt;code&gt;grep&lt;/code&gt; and the &lt;code&gt;pickaxe&lt;/code&gt; are useful tools - they’re made even more useful with the &lt;code&gt;--patch&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;By default, the returned results for a search with &lt;code&gt;git log&lt;/code&gt; is… just that: the git log.&lt;/p&gt;

&lt;p&gt;However, you can see the full diff if you include the &lt;code&gt;--patch&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;This is another good opportunity to see the differences between &lt;code&gt;--grep&lt;/code&gt;, &lt;code&gt;-S&lt;/code&gt; and &lt;code&gt;-G&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log --grep="cachePublic: true" --patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This returns &lt;em&gt;nothing&lt;/em&gt;. There are no git &lt;em&gt;commit&lt;/em&gt; messages (subject or body) with this string included in them.&lt;/p&gt;

&lt;p&gt;What about the &lt;code&gt;-S&lt;/code&gt; option though?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log -S"cachePublic: true," --patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This returns the full commit message (in this case, there wasn’t much of one) and the changed file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;commit e01fcf867905f4bcb3eb5ad8c961524547a782eb (origin/285/caching-netlify-builds, 285/caching-netlify-builds)
Author: Stephen &amp;lt;stephencweiss@gmail.com&amp;gt;
Date: Wed Dec 18 13:20:07 2019 -0600

    add netlify cache

diff --git a/gatsby-config.js b/gatsby-config.js
index 93d491e..c29b253 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -12,6 +12,12 @@ module.exports = {
   },
   plugins: [
     'gatsby-plugin-styled-components',
+ {
+ resolve: 'gatsby-plugin-netlify-cache',
+ options: {
+ cachePublic: true,
+ }
+ },
     {
       resolve: `gatsby-source-filesystem`,
       options: {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, there’s the &lt;code&gt;-G&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log -G"cachePublic: true," --patch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Like the &lt;code&gt;-S&lt;/code&gt; option, this returns the full commit message and the changed file(s). However, in this case it also pulled back a &lt;em&gt;second&lt;/em&gt; commit where the number of times &lt;code&gt;cachPublic: true,&lt;/code&gt; was present didn’t change, but it was reformatted: &lt;sup&gt;3&lt;/sup&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;commit ee201712e254bfd300b77057344994c1c1bd7663
Author: Stephen &amp;lt;stephencweiss@gmail.com&amp;gt;
Date: Thu Dec 19 09:35:37 2019 -0600

    adding global styles with styled-components

diff --git a/gatsby-config.js b/gatsby-config.js
index bacedc4..96f74db 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -15,8 +15,8 @@ module.exports = {
     {
       resolve: 'gatsby-plugin-netlify-cache',
       options: {
- cachePublic: true,
- }
+ cachePublic: true,
+ },
     },
     {
       resolve: `gatsby-source-filesystem`,
@@ -100,21 +100,21 @@ module.exports = {
       resolve: `gatsby-plugin-feed`,
       options: {
         feeds: [
- {
- serialize: ({ query: { site, allMarkdownRemark } }) =&amp;gt; {
- return allMarkdownRemark.edges.map(edge =&amp;gt; {
- return Object.assign({}, edge.node.frontmatter, {
- date: edge.node.frontmatter.date,
- publish: edge.node.frontmatter.publish,
- updated: edge.node.frontmatter.updated,
- draft: edge.node.frontmatter.draft,
- url: site.siteMetadata.siteUrl + edge.node.fields.slug,
- guid: site.siteMetadata.siteUrl + edge.node.fields.slug,
- custom_elements: [{ 'content:encoded': edge.node.html }],
- })
- })
- },
- query: `
+ {
+ serialize: ({ query: { site, allMarkdownRemark } }) =&amp;gt; {
+ return allMarkdownRemark.edges.map(edge =&amp;gt; {
+ return Object.assign({}, edge.node.frontmatter, {
+ date: edge.node.frontmatter.date,
+ publish: edge.node.frontmatter.publish,
+ updated: edge.node.frontmatter.updated,
+ draft: edge.node.frontmatter.draft,
+ url: site.siteMetadata.siteUrl + edge.node.fields.slug,
+ guid: site.siteMetadata.siteUrl + edge.node.fields.slug,
+ custom_elements: [{ 'content:encoded': edge.node.html }],
+ })
+ })
+ },
+ query: `
                   {
                     allMarkdownRemark(
                       limit: 1000,
@@ -137,9 +137,9 @@ module.exports = {
                     }
                   }
                 `,
- output: '/rss.xml',
- title: 'Code-Comments RSS Feed',
- },
+ output: '/rss.xml',
+ title: 'Code-Comments RSS Feed',
+ },
         ],
       },
     },
@@ -210,14 +210,14 @@ module.exports = {
         ],
       },
     },
- `gatsby-plugin-offline`,
- `gatsby-plugin-react-helmet`,
     {
- resolve: `gatsby-plugin-typography`,
+ resolve: `gatsby-plugin-styled-components`,
       options: {
- pathToConfigModule: `src/utils/typography`,
+ displayName: true,
       },
     },
+ `gatsby-plugin-offline`,
+ `gatsby-plugin-react-helmet`,
     {
       resolve: `@gatsby-contrib/gatsby-plugin-elasticlunr-search`,
       options: {

commit e01fcf867905f4bcb3eb5ad8c961524547a782eb (origin/285/caching-netlify-builds, 285/caching-netlify-builds)
Author: Stephen &amp;lt;stephencweiss@gmail.com&amp;gt;
Date: Wed Dec 18 13:20:07 2019 -0600

    add netlify cache

diff --git a/gatsby-config.js b/gatsby-config.js
index 93d491e..c29b253 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -12,6 +12,12 @@ module.exports = {
   },
   plugins: [
     'gatsby-plugin-styled-components',
+ {
+ resolve: 'gatsby-plugin-netlify-cache',
+ options: {
+ cachePublic: true,
+ }
+ },
     {
       resolve: `gatsby-source-filesystem`,
       options: {
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;p&gt;Writing good commit messages is hard(er than not). It requires time and effort. However, the total cost is not that high. Practices like Conventional Commits and templates can make the writing easier. Best of all, useful commit messages help you and your team nearly immediately. Even more so if you learn about the tools that make digging through them easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnotes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;sup&gt;1&lt;/sup&gt; See the &lt;a href="https://www.git-scm.com/docs/git-log#Documentation/git-log.txt--Sltstringgt"&gt;manual entry for &lt;code&gt;git log&lt;/code&gt; for a full list of what’s available&lt;/a&gt;. An interesting note is the difference between the &lt;code&gt;-G&lt;/code&gt; and the &lt;code&gt;-S&lt;/code&gt; options.&lt;/li&gt;
&lt;li&gt;
&lt;sup&gt;2&lt;/sup&gt; It’s so easy to forget, but &lt;code&gt;grep&lt;/code&gt; is an acronym for ”_g_lobally search a _r_egular _e_xpression and _p_rint”. &lt;a href="https://en.wikipedia.org/wiki/Grep"&gt;Read more about the history of &lt;code&gt;grep&lt;/code&gt; on Wikipedia&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;sup&gt;3&lt;/sup&gt; Worth noting that &lt;em&gt;if&lt;/em&gt; the &lt;code&gt;grep&lt;/code&gt; had returned anything with the &lt;code&gt;--patch&lt;/code&gt;, it would be the entire change set (which makes sense as it’s looking at the commit message, not at any particular modified file).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>grep</category>
    </item>
    <item>
      <title>Building an XKCD Daily Digest</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Sat, 25 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/building-an-xkcd-daily-digest-55dk</link>
      <guid>https://dev.to/stephencweiss/building-an-xkcd-daily-digest-55dk</guid>
      <description>&lt;p&gt;I love &lt;a href="https://www.xkcd.com"&gt;Randall Munroe’s XKCD&lt;/a&gt;, but going to his site every day is potentially problematic because it’s so easy to get sucked down the rabbit hole of clicking “random” over and over and over.&lt;/p&gt;

&lt;p&gt;At the same time, he’s been writing comics for years and I haven’t kept up. I wondered if there wasn’t some way that I could pull five, &lt;em&gt;just five&lt;/em&gt; images into my site every day for a digest of sorts.&lt;/p&gt;

&lt;p&gt;Over time I would catch up, but I wouldn’t have to worry about fighting the gravitational pull that is XKCD.com.&lt;/p&gt;

&lt;p&gt;So, I set about building this (which is live on this site at &lt;code&gt;/xkcd&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Some of the decisions I made up front on how the page would look and interact:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Comics would have the Title and the Image, nothing else displayed (similar to XCKD’s native experience, however with fewer buttons)&lt;/li&gt;
&lt;li&gt;The carousel would navigate through five, “randomly” chosen comics&lt;/li&gt;
&lt;li&gt;To avoid the temptation of hitting the refresh button to get a &lt;em&gt;different&lt;/em&gt; five, the randomness would be limited to the &lt;em&gt;day&lt;/em&gt; of viewing.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The building process turned out to be quite informative and full of stumbling blocks.&lt;/p&gt;

&lt;p&gt;Below, I highlight a few of them and the final result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Images
&lt;/h2&gt;

&lt;p&gt;Step one to building this gallery was to actually be able to get the images. Here’s where I hit my first stumbling block.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://xkcd.com/json.html"&gt;XKCD site has a page dedicated to programmatic access&lt;/a&gt; of comics.&lt;/p&gt;

&lt;p&gt;Seems straightforward enough. I tested the end point in Postman.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/3d17c799225443c38eb4d6a90f83564b/ad63e/xkcd-postman.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e3njHkfR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stephencharlesweiss.com/static/3d17c799225443c38eb4d6a90f83564b/b9e4f/xkcd-postman.png" alt="xkcd postman"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voila.&lt;/p&gt;

&lt;p&gt;Unfortunately, this site is built on Gatsby, a statically site generator. One consequence of this is that I do not have access to a server in the traditional sense.&lt;/p&gt;

&lt;p&gt;This is problematic only in that when I tried to make the same API call from the client, I received a CORS error.&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;// /pages/xkcd.jsx&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;XKCDGallery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://xkcd.com/info.0.json`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&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="s2"&gt;`oh no -&amp;gt; `&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&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;Returned the console error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Access to fetch at &lt;span class="s1"&gt;'https://xkcd.com/info.0.json'&lt;/span&gt; from origin &lt;span class="s1"&gt;'http://localhost:8000'&lt;/span&gt; has been blocked by CORS policy: No &lt;span class="s1"&gt;'Access-Control-Allow-Origin'&lt;/span&gt; header is present on the requested resource. If an opaque response serves your needs, &lt;span class="nb"&gt;set &lt;/span&gt;the request&lt;span class="s1"&gt;'s mode to '&lt;/span&gt;no-cors&lt;span class="s1"&gt;' to fetch the resource with CORS disabled.
&amp;gt; index.js:2177 oh no -&amp;gt; TypeError: Failed to fetch
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I tried multiple different configurations on my request call. I tried JSONP. Nothing seemed to work.&lt;/p&gt;

&lt;p&gt;Based on everything I read, in order for this to work, I’d need access to XKCD’s servers to white list my IP or allow cross origin requests.&lt;/p&gt;

&lt;p&gt;Since &lt;em&gt;that&lt;/em&gt; wasn’t going to happen, I needed an alternative solution. This is where &lt;a href="https://twitter.com/NicolasMarcora"&gt;Nicolas Marcora&lt;/a&gt; jumped in to save the day and pointed me to &lt;a href="https://www.npmjs.com/package/cors-anywhere"&gt;&lt;code&gt;cors-anywhere&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A&lt;/em&gt; solution is to simply use the demo&lt;sup&gt;1&lt;/sup&gt;:&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;// /pages/xkcd.jsx&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;XKCDGallery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxyUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://cors-anywhere.herokuapp.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxiedRequest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;proxyUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Requested-With&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wololo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;comic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;}))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&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="s2"&gt;`oh no --&amp;gt; `&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proxiedGet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;proxiedRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;proxiedGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://xkcd.com/info.0.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&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;&lt;a href="///static/3d17c799225443c38eb4d6a90f83564b/ad63e/xkcd-postman.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e3njHkfR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stephencharlesweiss.com/static/3d17c799225443c38eb4d6a90f83564b/b9e4f/xkcd-postman.png" alt="xkcd-postman results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whew! I now have results. I can proceed to the next step!&lt;/p&gt;

&lt;h2&gt;
  
  
  Predictable Results
&lt;/h2&gt;

&lt;p&gt;One of the quirks I introduced in my design was that I wanted to be able to get the &lt;em&gt;same&lt;/em&gt; images every time I hit the page for an entire day.&lt;/p&gt;

&lt;p&gt;That meant I couldn’t just use &lt;code&gt;Math.rand()&lt;/code&gt; to pull down five images. So, how &lt;em&gt;could&lt;/em&gt; I do this?&lt;/p&gt;

&lt;p&gt;Hashing!&lt;/p&gt;

&lt;p&gt;When I first learned about hashing functions, my mind was blown. The quick summary is that they reliably transform data to always get to the same result. The variables are the input and the size of the hash. If you know that (and the hashing function), you can derive the answer.&lt;/p&gt;

&lt;p&gt;Notably, this is &lt;em&gt;not&lt;/em&gt; encryption. It can be reversed. There’s no concept of a public/private key.&lt;/p&gt;

&lt;p&gt;A simple hashing function might look like this:&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="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="k"&gt;return&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;let&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;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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="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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;charCodeAt&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="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;char&lt;/span&gt;
    &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="c1"&gt;// Convert to 32bit integer&lt;/span&gt;
    &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&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;hash&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is one I have kept around from a course I took a while back, but it turns out to be a fairly common one. In researching hashing functions I found this post on &lt;a href="https://dev.to/wp/?p=55"&gt;http://mediocredeveloper.com&lt;/a&gt; which walks through each step of a nearly identical function.&lt;/p&gt;

&lt;p&gt;Armed with a hashing function, I now needed to &lt;em&gt;bound&lt;/em&gt; it. If I didn’t, when I requested a comic, it might not exist.&lt;/p&gt;

&lt;p&gt;Randall is prolific, but he’s not written an infinite number of comics.&lt;/p&gt;

&lt;p&gt;In fact, we actually already discovered the total number of available comics. The proxied request above was for the most recent comic, but in the body of the response, we see the &lt;code&gt;num&lt;/code&gt; property. This turns out to correspond to the sequential indicator Randall has chosen to identify his comics.&lt;/p&gt;

&lt;p&gt;With that information, we can write another function to make sure that we stay between 1 and the maximum.&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="nx"&gt;boundedHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;hashedVal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hashedVal&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;max&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A few quick notes about this implementation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I’m okay with conflicts. This is a fun project and if I get a collision (i.e. two different hashes that end up occupying the same value), then I’ll see the comic twice.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;Math.max&lt;/code&gt; is an error guard as trying to find the comic with &lt;code&gt;num = 0&lt;/code&gt; will throw an error. I could swallow this later, however, again, for the purposes here, this is acceptable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Encapsulating The Logic In A Hook
&lt;/h2&gt;

&lt;p&gt;At this point, I have all the pieces I need to actually retrieve a number of images. Can I do it in a way that makes consuming them in a component relatively painless?&lt;/p&gt;

&lt;p&gt;Normally best practice is to extract reusuable hooks and it’s &lt;em&gt;very&lt;/em&gt; unlikely that I will reuse this hook elsewhere. However, I decided to extract it anyway. Why? Because it keeps my view component logic &lt;em&gt;very&lt;/em&gt; simple.&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;// /hooks/useXkcd.jsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;useAsync&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-use&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;boundedHash&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/hashFn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;proxiedGet&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/proxiedrequest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;TODAY&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Details re: XKCD's JSON: https://xkcd.com/json.html
 * */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;useXkcd&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;comicQty&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;latestComicNumber&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;proxiedGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://xkcd.com/info.0.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchRequestedImages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;comicQty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxComic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;latestComicNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="nx"&gt;images&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;fetchComic&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// get the current comic&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;let&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;comicQty&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetchComic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;boundedHash&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="nx"&gt;TODAY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxComic&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="nx"&gt;images&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;img&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;images&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchComic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;comicId&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;proxiedGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`http://xkcd.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;comicId&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;comicId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;``&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;info.0.json`&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`http://xkcd.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;comicId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="c1"&gt;// Want to be sure to provide a way back to xkcd&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&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="s2"&gt;`fetchComics --&amp;gt; `&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useAsync&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;return&lt;/span&gt; &lt;span class="nx"&gt;fetchRequestedImages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;comicQty&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;isError&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="na"&gt;xkcdComics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&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;What this hook does in a nut shell is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Exposes a very simple surface area to the consumer: how many comics do you want back?&lt;/li&gt;
&lt;li&gt;It handles all of the logic for fetching a collection that will match that request.&lt;/li&gt;
&lt;li&gt;It wraps it all in a &lt;code&gt;useAsync&lt;/code&gt; hook from &lt;code&gt;react-use&lt;/code&gt; to make sure to communicate whether the data is ready to render or not.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;How simple does that make my view component? Well, let’s look:&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;// /pages/xkcd.jsx&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;XKCDGallery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;xkcdComics&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useXkcd&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;comicQty&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isError&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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;eek&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nx"&gt;an&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="o"&gt;!&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Layout&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;XKCD&lt;/span&gt; &lt;span class="nx"&gt;Daily&lt;/span&gt; &lt;span class="nx"&gt;Digest&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Title&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CenteredLoader&lt;/span&gt; &lt;span class="o"&gt;/&amp;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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ImageCarousel&lt;/span&gt; &lt;span class="nx"&gt;images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;xkcdComics&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)}&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* ... */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Layout&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Pretty nice! This takes us to the final stage of the exercise - &lt;em&gt;displaying&lt;/em&gt; the data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying The Comics
&lt;/h2&gt;

&lt;p&gt;This posed yet another problem for me. My first attempt was to use the &lt;code&gt;pure-react-carousel&lt;/code&gt; library, however, the results I was getting were hardly ideal (all images were rendered on a single slide).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://sung.codes/"&gt;Sung M. Kim aka Dance2Die&lt;/a&gt; turned me onto &lt;a href="https://github.com/FormidableLabs/nuka-carousel"&gt;&lt;code&gt;nuka-carousel&lt;/code&gt;&lt;/a&gt; which turned out much better for me. It even has keyboard controls and by using a ref (thanks in no small part to Lee Warrick’s article &lt;a href="https://dev.to/leewarrickjr/react-s-useeffect-and-useref-explained-for-mortals-2ddk"&gt;React’s useEffect and useRefs Explained for Mortals&lt;/a&gt; I auto-focus &lt;em&gt;on&lt;/em&gt; the carousel, so keyboard controls are available as soon as the comics load.&lt;/p&gt;

&lt;p&gt;There &lt;em&gt;is&lt;/em&gt; a lingering bug: the carousel doesn’t reserve enough space in the DOM initially for the &lt;em&gt;first&lt;/em&gt; image. Once you move to the &lt;em&gt;next&lt;/em&gt; image, this is resolved. This bug bothers me, but it’s also an opportunity to learn in the future. I’ll be back to fix it soon I hope! (If you know how to fix it, I'd be grateful to hear in the comments!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--htNRBSdq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://stephencharlesweiss.com/xkcd-page-demo-09e555678c156f26bd8a5dd2fd2104e8.gif" alt=""&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Current state of the daily digest!&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Whew! That’s all I’ve got for today. It’s been a weird, wild ride but wow is it cool that I can wake up with an idea, spend a few hours thinking and tinkering, and &lt;a href="https://www.youtube.com/watch?v=0C58ttB2-Qg"&gt;with a little help from my friends&lt;/a&gt; build something that didn’t exist before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnotes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;sup&gt;1&lt;/sup&gt; I’m using the demo proxy for now, however, I plan to migrate to my own version of the cors-anywhere soon using that as a serverless function - that will be a learning experience in its own right! For now, I’m grateful for Rob W, the developer behind &lt;code&gt;cors-anywhere&lt;/code&gt; and his demo environment.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
    </item>
    <item>
      <title>Node Version Management... Automatically</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Fri, 24 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/node-version-management-automatically-1m5d</link>
      <guid>https://dev.to/stephencweiss/node-version-management-automatically-1m5d</guid>
      <description>&lt;p&gt;NVM, the &lt;a href="https://github.com/nvm-sh/nvm"&gt;Node Version Manager&lt;/a&gt;, is an invaluable tool when working on multiple node projects. Instead of manually managing the globally installed version of node, NVM can handle it for you.&lt;/p&gt;

&lt;p&gt;Unfortunately, even with NVM, it’s easy to use the wrong node version when jumping between projects.&lt;/p&gt;

&lt;p&gt;A colleague shared his solution to the problem with me recently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//".bash\_profile"
function cd() {
    builtin cd "$@"
    nvm i 2&amp;gt; /dev/null
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This function, when added to the &lt;code&gt;.bash_profile&lt;/code&gt; (or &lt;code&gt;.zshrc&lt;/code&gt;, etc.), will still perform the change directory as expected (that’s the first line: &lt;code&gt;builtin cd "$@"&lt;/code&gt;), but it will &lt;em&gt;also&lt;/em&gt; look for the presence of an &lt;code&gt;.nvmrc&lt;/code&gt; file in the new directory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Aside: What Is The .NVMRC?
&lt;/h2&gt;

&lt;p&gt;It’s worth taking a moment to discuss the &lt;a href="https://github.com/nvm-sh/nvm#nvmrc"&gt;&lt;code&gt;.nvmrc&lt;/code&gt;&lt;/a&gt; file, it’s function, and what it may look like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can create a .nvmrc file containing a node version number (or any other string that nvm understands; see nvm —help for details) in the project root directory (or any parent directory). Afterwards, nvm use, nvm install, nvm exec, nvm run, and nvm which will use the version specified in the .nvmrc file if no version is supplied on the command line.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, for example, you could have an &lt;code&gt;.nvmrc&lt;/code&gt; for a specific version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//.nvmrc
12
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Or&lt;/em&gt; you could default to the latest LTS version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//.nvmrc
lts/*
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;em&gt;If&lt;/em&gt; there’s an &lt;code&gt;.nvmrc&lt;/code&gt; included in the new directory, the function will execute &lt;code&gt;/dev/null&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;a href="///static/00e7c819144dc010328c2bbae6b72331/c08bc/cd-in-practice.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ssQgvETr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stephencharlesweiss.com/static/00e7c819144dc010328c2bbae6b72331/c08bc/cd-in-practice.png" alt="cd with extra function"&gt;&lt;/a&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;An example of this in use. The directory, &lt;code&gt;personal&lt;/code&gt;, does not have an &lt;code&gt;.nvmrc&lt;/code&gt; file, though &lt;code&gt;onething&lt;/code&gt; does. Upon detecting it, &lt;code&gt;nvm&lt;/code&gt; automatically switched to using the correct &lt;code&gt;node&lt;/code&gt; version.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As noted in the description of the &lt;code&gt;.nvmrc&lt;/code&gt;, it’s presence ensures that &lt;code&gt;nvm i&lt;/code&gt; will use the version specified in the file.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/dev/null&lt;/code&gt; is a specific form of &lt;a href="//../../2019-12-20/angled-brackets-bash-scripting"&gt;redirection within Unix&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this case it’s saying take the &lt;code&gt;stderr&lt;/code&gt; (&lt;code&gt;2&lt;/code&gt;), redirect (&lt;code&gt;&amp;gt;&lt;/code&gt;) to &lt;code&gt;/dev/null&lt;/code&gt;. The &lt;a href="https://askubuntu.com/a/350212"&gt;&lt;code&gt;/dev/null&lt;/code&gt; is a “blackhole”&lt;/a&gt; on unix machines, effectively suppressing any errors generated by running this command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Note
&lt;/h2&gt;

&lt;p&gt;NVM manages node versions &lt;em&gt;within&lt;/em&gt; each terminal session. This is critical because it ensures that you can run two node projects simultaneously even if the node versions are different.&lt;/p&gt;

</description>
      <category>nvm</category>
    </item>
    <item>
      <title>Locate Files Quickly On Your Computer</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Thu, 09 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/locate-files-quickly-on-your-computer-3ndf</link>
      <guid>https://dev.to/stephencweiss/locate-files-quickly-on-your-computer-3ndf</guid>
      <description>&lt;p&gt;I was looking to find all instances of Postgres the other day in order to check the version. A web search led me to &lt;a href="https://linuxize.com/post/how-to-check-postgresql-version/"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Interestingly, while the search came up empty (I believe the file’s been deleted), I did learn about two new commands: &lt;code&gt;locate&lt;/code&gt; and &lt;code&gt;find&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Of the two, I will likely use &lt;code&gt;find&lt;/code&gt; more often because &lt;code&gt;locate&lt;/code&gt; works by building a database that it searches whereas &lt;code&gt;find&lt;/code&gt; simply walks a file hierarchy looking for the search parameters.&lt;/p&gt;

&lt;p&gt;The first time you run &lt;code&gt;locate&lt;/code&gt;, you may be greeted by a message similar to this one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WARNING: The locate database (/var/db/locate.database) does not exist.To create the database, run the following command:&lt;/p&gt;

&lt;p&gt;sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist&lt;/p&gt;

&lt;p&gt;Please be aware that the database can take some time to generate; oncethe database has been created, this message will no longer appear.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Find is simpler (though it may require super user permissions).&lt;/p&gt;

&lt;h2&gt;
  
  
  Find Example Usage
&lt;/h2&gt;

&lt;p&gt;Here’s one example of searching your file system using the &lt;code&gt;find&lt;/code&gt; utility:&lt;/p&gt;

&lt;p&gt;In this case, I was interested in all locations for Postgres on my machine and I used the glob pattern &lt;code&gt;*/&lt;/code&gt; to search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ sudo find /usr -wholename '*/bin/postgres*'
/usr/local/bin/postgres
/usr/local/Cellar/postgresql/12.1/bin/postgres
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ét voila! A new way to quickly locate files on a computer!&lt;/p&gt;

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

&lt;p&gt;Manual pages posted below for posterity.&lt;/p&gt;

&lt;blockquote&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME
find -- walk a file hierarchy

SYNOPSIS
find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]
find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]

DESCRIPTION
The find utility recursively descends the directory tree for each path listed, evaluating an expression (composed of the ``primaries'' and ``operands'' listed below) in terms of each file in the tree.

The options are as follows:

-E Interpret regular expressions followed by -regex and -iregex primaries as extended (modern) regular expressions rather than basic regular expressions (BRE's). The re_format(7) manual page fully describes
both formats.

-H Cause the file information and file type (see stat(2)) returned for each symbolic link specified on the command line to be those of the file referenced by the link, not the link itself. If the referenced
file does not exist, the file information and type will be for the link itself. File information of all symbolic links not on the command line is that of the link itself.

-L Cause the file information and file type (see stat(2)) returned for each symbolic link to be those of the file referenced by the link, not the link itself. If the referenced file does not exist, the file
information and type will be for the link itself.

This option is equivalent to the deprecated -follow primary.

-P Cause the file information and file type (see stat(2)) returned for each symbolic link to be those of the link itself. This is the default.

-X Permit find to be safely used in conjunction with xargs(1). If a file name contains any of the delimiting characters used by xargs(1), a diagnostic message is displayed on standard error, and the file is
skipped. The delimiting characters include single (`` ' '') and double (`` " '') quotes, backslash (``\''), space, tab and newline characters.

However, you may wish to consider the -print0 primary in conjunction with ``xargs -0'' as an effective alternative.

-d Cause find to perform a depth-first traversal, i.e., directories are visited in post-order and all entries in a directory will be acted on before the directory itself. By default, find visits directories
in pre-order, i.e., before their contents. Note, the default is not a breadth-first traversal.

This option is equivalent to the -depth primary of IEEE Std 1003.1-2001 (``POSIX.1''). The -d option can be useful when find is used with cpio(1) to process files that are contained in directories with
unusual permissions. It ensures that you have write permission while you are placing files in a directory, then sets the directory's permissions as the last thing.

-f Specify a file hierarchy for find to traverse. File hierarchies may also be specified as the operands immediately following the options.

-s Cause find to traverse the file hierarchies in lexicographical order, i.e., alphabetical order within each directory. Note: `find -s' and `find | sort' may give different results.

-x Prevent find from descending into directories that have a device number different than that of the file from which the descent began.

This option is equivalent to the deprecated -xdev primary.

PRIMARIES
All primaries which take a numeric argument allow the number to be preceded by a plus sign (``+'') or a minus sign (``-''). A preceding plus sign means ``more than n'', a preceding minus sign means ``less than n''
and neither means ``exactly n''.

-Bmin n
True if the difference between the time of a file's inode creation and the time find was started, rounded up to the next full minute, is n minutes.

-Bnewer file
Same as -newerBm.

-Btime n[smhdw]
If no units are specified, this primary evaluates to true if the difference between the time of a file's inode creation and the time find was started, rounded up to the next full 24-hour period, is n
24-hour periods.

If units are specified, this primary evaluates to true if the difference between the time of a file's inode creation and the time find was started is exactly n units. Please refer to the -atime primary
description for information on supported time units.

-acl May be used in conjunction with other primaries to locate files with extended ACLs. See acl(3) for more information.

-amin n
True if the difference between the file last access time and the time find was started, rounded up to the next full minute, is n minutes.

-anewer file
Same as -neweram.
&lt;/code&gt;&lt;/pre&gt;



&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME
locate -- find filenames quickly

SYNOPSIS
locate [-0Scims] [-l limit] [-d database] pattern ...

DESCRIPTION
The locate program searches a database for all pathnames which match the specified pattern. The database is recomputed periodically (usually weekly or daily), and contains the pathnames of all files which are pub-
licly accessible.

Shell globbing and quoting characters (``*'', ``?'', ``\'', ``['' and ``]'') may be used in pattern, although they will have to be escaped from the shell. Preceding any character with a backslash (``\'') elimi-
nates any special meaning which it may have. The matching differs in that no characters must be matched explicitly, including slashes (``/'').

As a special case, a pattern containing no globbing characters (``foo'') is matched as though it were ``*foo*''.

Historically, locate only stored characters between 32 and 127. The current implementation store any character except newline (`\n') and NUL (`\0'). The 8-bit character support does not waste extra space for
plain ASCII file names. Characters less than 32 or greater than 127 are stored in 2 bytes.

The following options are available:

-0 Print pathnames separated by an ASCII NUL character (character code 0) instead of default NL (newline, character code 10).

-S Print some statistics about the database and exit.

-c Suppress normal output; instead print a count of matching file names.

-d database
Search in database instead of the default file name database. Multiple -d options are allowed. Each additional -d option adds the specified database to the list of databases to be searched.

The option database may be a colon-separated list of databases. A single colon is a reference to the default database.

$ locate -d $HOME/lib/mydb: foo

will first search string ``foo'' in $HOME/lib/mydb and then in /var/db/locate.database.

$ locate -d $HOME/lib/mydb::/cdrom/locate.database foo

will first search string ``foo'' in $HOME/lib/mydb and then in /var/db/locate.database and then in /cdrom/locate.database.

$ locate -d db1 -d db2 -d db3 pattern

is the same as

$ locate -d db1:db2:db3 pattern

or

$ locate -d db1:db2 -d db3 pattern

If - is given as the database name, standard input will be read instead. For example, you can compress your database and use:

$ zcat database.gz | locate -d - pattern

This might be useful on machines with a fast CPU and little RAM and slow I/O. Note: you can only use one pattern for stdin.

-i Ignore case distinctions in both the pattern and the database.

-l number Limit output to number of file names and exit.

-m Use mmap(2) instead of the stdio(3) library. This is the default behavior and is faster in most cases.

-s Use the stdio(3) library instead of mmap(2).

ENVIRONMENT
LOCATE_PATH path to the locate database if set and not empty, ignored if the -d option was specified.

FILES
/var/db/locate.database locate database
/usr/libexec/locate.updatedb Script to update the locate database
/System/Library/LaunchDaemons/com.apple.locate.plist Job that starts the database rebuild

SEE ALSO
find(1), whereis(1), which(1), fnmatch(3), locate.updatedb(8)

Woods, James A., "Finding Files Fast", ;login, 8:1, pp. 8-10, 1983.
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

</description>
      <category>locate</category>
      <category>find</category>
      <category>unix</category>
      <category>shell</category>
    </item>
    <item>
      <title>Marty Cagan on Rewrites, Headroom, And 20%-Time</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Tue, 07 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/marty-cagan-on-rewrites-headroom-and-20-time-1n30</link>
      <guid>https://dev.to/stephencweiss/marty-cagan-on-rewrites-headroom-and-20-time-1n30</guid>
      <description>&lt;p&gt;In 2007, Marty Cagan wrote a blog called &lt;a href="https://svpg.com/engineering-wants-to-rewrite/"&gt;“Engineering Wants to Rewrite!”&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s a good example of how product and engineering can work together to keep a business moving forward, even while “rebuilding the engine mid-flight.”&lt;/p&gt;

&lt;p&gt;The key takeaways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;100% focus on new features can doom a company.&lt;/li&gt;
&lt;li&gt;&amp;lt;20% focus on “headroom” is overly optimistic.&lt;/li&gt;
&lt;li&gt;Engineers, conservative naturally, are wildly optimistic about rewrites. Plan accordingly. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copying the post in full below for posterity:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  Engineering Wants to Rewrite!
&lt;/h1&gt;

&lt;p&gt;by Marty Cagan&lt;br&gt;
Mar 29, 2007&lt;/p&gt;

&lt;p&gt;Few words are more dreaded by product managers than being told by engineering: “No more new features! We need to stop and rewrite! Our code base is a mess, it can’t keep up with the number of users, it’s a house of cards, we can’t maintain it, the site is a dog!”&lt;/p&gt;

&lt;p&gt;This situation has happened to too many companies, and continues to happen. It happened to eBay in 1999, and the company came far closer to collapsing than most people ever realized. It happened to Friendster a few years ago and opened the door for MySpace. It happened to Netscape during the browser wars with Microsoft, and everyone knows who won. The truth is that most companies never recover from this. It is a really bad situation to find yourself in.&lt;/p&gt;

&lt;p&gt;When a company does get into this situation, everyone typically blames engineering. But in my experience, the harsh truth is that it’s usually the fault of product management. The reason is that for the past years the product managers have been pounding the engineering organization to deliver as many features as the engineering team possibly can produce. The result is that at some point, if you neglect the infrastructure, all software will reach the point where it can no longer support the functionality it needs to.&lt;/p&gt;

&lt;p&gt;During this rewrite, you’re forced to stop forward progress as far as what the customers see. You might think that the rewrite will only take a few months (more about that below) but invariably it takes far longer, and you are forced to sit by and watch your customers leave you for your competitors.&lt;/p&gt;

&lt;p&gt;If you haven’t yet reached this situation, here’s what you need to do to make sure you never do. You need to allocate a percentage of your engineering capacity to what at eBay we called “headroom”. The idea is to avoid slamming your head into ceilings. You do this by creating room – headroom – room for growth in the user base, growth in transactions, growth in functionality.&lt;/p&gt;

&lt;p&gt;The deal with engineering goes like this. Product management takes 20% of the capacity right off the top and gives this to engineering to spend as they see fit – they might use it to rewrite, rearchitect or refactor problematic parts of the code base, or to swap out data base systems, improve system performance – whatever they believe is necessary to avoid ever having to come to the team and say “we need to stop and rewrite.” If you’re in really bad shape today, you might need to make this 30% or even more of the resources. I get nervous when I find teams that think they can get away with much less than 20%.&lt;/p&gt;

&lt;p&gt;If you are currently in this situation, the truth is that your company may not survive this. But if you are to have a chance of pulling through, you’ll need to first do a realistic schedule and timeline for making the necessary changes that engineering identifies.&lt;/p&gt;

&lt;p&gt;Most of the time, an experienced engineering team will come up with estimates that are on the slightly conservative side. The exception to this rule is this case of rewrites. Here the estimates are often wildly optimistic. You must make informed decisions in this situation, so you have to go through every line item on the schedule to make sure that the dates are realistic.&lt;/p&gt;

&lt;p&gt;Second, if there’s any way humanly possible to break up the rewrite into chunks to be done incrementally, you should absolutely do so. Even though the rewrite might now stretch over two years instead of 9 months, if you can find a way to continue to make forward progress on user visible functionality, even if it’s only with 25% to 50% of the capacity, this is incredibly important.&lt;/p&gt;

&lt;p&gt;Third, since you’ll only have very limited ability to deliver user visible functionality, you will need to pick the right features, and make sure you do define them right.&lt;/p&gt;

&lt;p&gt;After eBay’s near-death experience, they made sure they wouldn’t put the company at risk again. They immediately began another rewrite, this time well in advance of issues. In fact, due to their very rapid growth, they ended up rewriting a third time, this time translating the entire site into a different programming language and architecture, and they did this massive multi-million line rewrite over several years, and most importantly, without impacting the user base and at the same time managing to deliver record amounts of new functionality. It’s the most impressive example of “rebuilding the engine mid-flight” that I know of.&lt;/p&gt;

&lt;p&gt;But definitely the best strategy for dealing with this situation is to not get to this point. You need to pay your taxes and remember to dedicate at least 20% to headroom. If you haven’t had this discussion with your engineering counterpart, you should do so today.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>product</category>
    </item>
    <item>
      <title>GraphQL Fragments: Reuse and Variables</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Mon, 06 Jan 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/graphql-fragments-reuse-and-variables-4l4n</link>
      <guid>https://dev.to/stephencweiss/graphql-fragments-reuse-and-variables-4l4n</guid>
      <description>&lt;p&gt;After thinking more about Lee Byron’s talk and some of the uses for fragments&lt;sup&gt;1&lt;/sup&gt;, I still had some questions. Specifically - &lt;em&gt;how&lt;/em&gt; do you reuse them effectively?&lt;/p&gt;

&lt;p&gt;It’s one thing to break down complicated queries into smaller fragments (as Lee did in his talk), but it’s another to actually reuse those query fragments across the app.&lt;/p&gt;

&lt;p&gt;While researching, I also found the use of variables with fragments simple and elegant.&lt;/p&gt;

&lt;p&gt;I’ll look at both below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reusing Fragments
&lt;/h2&gt;

&lt;p&gt;At the end of the day, GraphQL fragments are template literals assigned to a variable. In Javascript, that means they can be passed around just like any other variable. Depending on the environment you’re in, the convention may be slightly different.&lt;/p&gt;

&lt;p&gt;For example, the &lt;a href="https://www.apollographql.com/docs/react/data/fragments/#reusing-fragments"&gt;Apollo&lt;/a&gt; convention is to place fragments within an object named &lt;code&gt;[something].fragment&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;graphql-tag&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;CommentsPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
    fragment CommentsPageComment on Comment {
      id
      postedBy {
        login
        html_url
      }
      createdAt
      content
    }
  `&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;Then, to use this, would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SUBMIT_COMMENT_MUTATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  mutation SubmitComment($repoFullName: String!, $commentContent: String!) {
    submitComment(repoFullName: $repoFullName, commentContent: $commentContent) {
      ...CommentsPageComment
    }
  }
  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CommentsPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;COMMENT_QUERY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;gql&lt;/span&gt;&lt;span class="s2"&gt;`
  query Comment($repoName: String!) {
    # ...
    entry(repoFullName: $repoName) {
      # ...
      comments {
        ...CommentsPageComment
      }
      # ...
    }
  }
  &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CommentsPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fragments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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 interesting thing to note about Apollo’s implementation is the use of the &lt;code&gt;...Name&lt;/code&gt; for the fragment &lt;em&gt;and&lt;/em&gt; the inclusion of the &lt;code&gt;gql&lt;/code&gt; template literal (&lt;code&gt;${CommentsPage.fragments.comment}&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.gatsbyjs.org/docs/using-graphql-fragments/#creating-and-using-a-fragment"&gt;Gatsby’s approach&lt;/a&gt; is somewhat different and is a result of the architecture of a Gatsby site which allows defining GraphQL fragments in components, but only returns data to queries within Pages.&lt;/p&gt;

&lt;p&gt;In the example from the Gatsby docs then, we:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a component with a GraphQL fragment (the fragment is exported and available as &lt;code&gt;SiteInformation&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Import the component into a Page and use the fragment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The example (taken from the Gatsby site linked above):&lt;/p&gt;

&lt;p&gt;"src/components/IndexPost.jsx"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gatsby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;props&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;return&lt;/span&gt; &lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
  fragment SiteInformation on Site {
    siteMetadata {
      title
      siteDescription
    }
  }
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then used like so:&lt;/p&gt;

&lt;p&gt;"src/pages/main.jsx"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gatsby&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;IndexPost&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../components/IndexPost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&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;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteMetadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteDescription&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/*
        Or you can pass all the data from the fragment
        back to the component that defined it
      */&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IndexPost&lt;/span&gt; &lt;span class="nx"&gt;siteInformation&lt;/span&gt;&lt;span class="o"&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="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;siteMetadata&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
  query {
    site {
      ...SiteInformation
    }
  }
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As of now, my questions that remain to be tested include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why does Apollo require the &lt;code&gt;${FragmentName}&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Can I export and use a fragment that’s defined as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;siteInfoFragment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graphql&lt;/span&gt;&lt;span class="s2"&gt;`
  fragment SiteNformation on Site {
    siteMetadata {
      title
      siteDescription
    }
  }
`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Right now, I’m still learning the theory of fragments and… I like them in theory. However, I need more experience with them and to date, my apps which use GraphQL simply haven’t called for the complexity. So, this is preliminary research and I’m excited to revisit when there’s an actual need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Variables With Fragments
&lt;/h2&gt;

&lt;p&gt;While researching how to pass fragments around, I also found the answer to a question I didn’t realize I had: how to use variables with fragments.&lt;/p&gt;

&lt;p&gt;I found the answer in the &lt;a href="https://graphql.org/learn/queries/#using-variables-inside-fragments"&gt;GraphQL docs&lt;/a&gt;, which provide a nice example of how to use variables with fragments. Before looking at their implementation, let’s examine a more generic query to see how it compares:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HeroComparison&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;firstComparison&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPIRE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;friendsConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;secondComparison&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;JEDI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;friendsConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, the client would provide a value for the variable &lt;code&gt;first&lt;/code&gt; (which defaults to 3), and that is then passed along to both the &lt;code&gt;firstComparison&lt;/code&gt; and &lt;code&gt;secondComparison&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using Fragments, we can simplify this and reduce the duplicative code while &lt;em&gt;still&lt;/em&gt; using variables as we would expect. Here’s what the GraphQL docs suggest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HeroComparison&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;leftComparison&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMPIRE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;comparisonFields&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;rightComparison&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;episode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;JEDI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="n"&gt;comparisonFields&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;fragment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;comparisonFields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Character&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;friendsConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;totalCount&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;edges&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key point is that, just as in the original query, the variable passed into the query is propagated all the way down and is accessible by the fragments.&lt;/p&gt;

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

&lt;p&gt;When it comes to fragments, it turns out that the way to pass them around and reuse them or to use variables is exactly how I’d expect to do it. That’s pretty fantastic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnotes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;sup&gt;1&lt;/sup&gt; I wrote about it &lt;a href="//../../2020-01-04/graphql-fragments/"&gt;here&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=pLvrZPSzHxo"&gt;here’s Lee’s original talk&lt;/a&gt;. [return]&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>graphql</category>
      <category>fragments</category>
    </item>
    <item>
      <title>Fixing My Embargo: Setting up a Cron Job</title>
      <dc:creator>Stephen Charles Weiss</dc:creator>
      <pubDate>Fri, 27 Dec 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/stephencweiss/fixing-my-embargo-setting-up-a-cron-job-5ea7</link>
      <guid>https://dev.to/stephencweiss/fixing-my-embargo-setting-up-a-cron-job-5ea7</guid>
      <description>&lt;p&gt;I wrote previously about &lt;a href="//stephencharlesweiss.com/blog/2019-10-16/gatsby-simple-embargo"&gt;setting up a simple embargo&lt;/a&gt; on my Gatsby site in the past. Even when I first implemented it, however, I knew that there’d be a better solution in the future.&lt;/p&gt;

&lt;p&gt;As a reminder: Gatsby sites are static. In my case, the builds included all of the posts for my blog. Consequently, when I wrote a post and added it to my site - when the site built it was visible.&lt;/p&gt;

&lt;p&gt;The purpose of the embargo was to create space between when I wrote a new post and when it would appear. The original solution solved this by simply hiding the posts on the front end. I wanted a better solution however. For that, I reached for an old standby: the cron job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is A Cron Job
&lt;/h2&gt;

&lt;p&gt;Cron is a utility that is used for scheduling commands or programs to execute at a specific time. Named for Chronos, the diety of time, these scheduled commands are referred to as “Cron Jobs”.&lt;/p&gt;

&lt;p&gt;Common uses of cron jobs include backups, monitoring, and maintenance.&lt;/p&gt;

&lt;p&gt;The syntax for cron jobs is a little peculiar, but there’s a logic to it that just takes some familiarity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ┏━━━━━━━━━━━━ minute (0 - 59)
 ┃ ┏━━━━━━━━━━ hour (0 - 23)
 ┃ ┃ ┏━━━━━━━━ day of month (1 - 31)
 ┃ ┃ ┃ ┏━━━━━━ month (1-12)
 ┃ ┃ ┃ ┃ ┏━━━━ day of week (0 - 6) or use names;
 ┃ ┃ ┃ ┃ ┃ 0 and 7 are Sunday, 1 is Monday,
 ┃ ┃ ┃ ┃ ┃ 2 is Tuesday, etc.
 ┃ ┃ ┃ ┃ ┃
 * * * * * &amp;lt;command to execute&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Some great examples of different schedules can be found on &lt;a href="https://www.ostechnix.com/a-beginners-guide-to-cron-jobs/"&gt;ostechnix.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Netlify Build Hooks
&lt;/h2&gt;

&lt;p&gt;Now that we know a bit about cron jobs, we want to talk about which command to execute.&lt;/p&gt;

&lt;p&gt;In this particular case, we’ll be using &lt;a href="https://docs.netlify.com/configure-builds/build-hooks/#app"&gt;Netlify Build Hooks&lt;/a&gt; as I’m using Netlify to build and deploy my site.&lt;/p&gt;

&lt;p&gt;Triggering a build requires only a POST request sent to the URL specified by a token.&lt;/p&gt;

&lt;p&gt;To add a build hook, we log into Netlify, select the site and choose Settings.&lt;/p&gt;

&lt;p&gt;Then, on the left, select “Build &amp;amp; Deploy” and scroll down to “Build Hooks”. Select “Add build hook”. From here, we can name the hook.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BGjaxziO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./build-hooks-configure.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BGjaxziO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./build-hooks-configure.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once saved, Netlify will produce a token we can use to trigger a build. The token should be considered sensitive and should be kept private (similar to an API key).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i2qgNmzc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./build-hooks-result.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i2qgNmzc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/v1/./build-hooks-result.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that we have a build hook, we need to schedule the invocation of it. For that, we’ll use a cron job via GitHub Actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Recently out of a beta, &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt; are a new feature from Github to automate software workflows.&lt;/p&gt;

&lt;p&gt;To get the action set up, we will need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a workflow &lt;code&gt;.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add the secret&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Adding GitHub Workflows
&lt;/h3&gt;

&lt;p&gt;Github actions are managed by the presence of a &lt;code&gt;.yml&lt;/code&gt; file in a directory in your project &lt;code&gt;.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here’s the my &lt;code&gt;nightly-build.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Daily Build
on:
  schedule:
    - cron: ‘0 8 * * *’ # 0 minute, 8th hour, every day of the month, every month, every day of the week (UTC)*
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Netlify Build Hook
        run: curl -s -X POST -d {} “https://api.netlify.com/build_hooks/${TOKEN}”
        env:
          TOKEN: ${{ secrets.NETLIFY_DAILY_CRON_HOOK }}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Remember that a cron job has two parts: a schedule and a command. In this yaml file, I’ve defined a schedule as the 0th minute of every 8th hour, every day of the month, every month, and every day of the week.&lt;sup&gt;1&lt;/sup&gt;&lt;a id="fn1"&gt;&lt;/a&gt; The job is to run the &lt;code&gt;curl&lt;/code&gt; and send the POST to Netlify.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;Regarding yaml files generally: they’re space sensitive. My first attempt resulted in an error, “YAML mapping values are not allowed in this context”. Investigating it led me to this &lt;a href="https://stackoverflow.com/questions/31313452/yaml-mapping-values-are-not-allowed-in-this-context"&gt;StackOverflow conversation&lt;/a&gt; and ultimately &lt;a href="http://www.yamllint.com/"&gt;http://www.yamllint.com/&lt;/a&gt; - a great tool for validating yaml files.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;curl&lt;/code&gt; is the same as what Netlify suggested - though I spefcified a TOKEN which takes a value &lt;code&gt;secrets.NETLIFY_DAILY_CRON_HOOK&lt;/code&gt;. That secret hasn’t yet been defined. In fact, that’s the final step.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Adding A Secret
&lt;/h2&gt;

&lt;p&gt;Though we’ve referenced a variable in our &lt;code&gt;.yml&lt;/code&gt; file, we now need to define it.&lt;/p&gt;

&lt;p&gt;To do so, in the repository, select settings and then “Secrets” on the left.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/f7aa1ec8982e730c1b67b4af357de963/4117f/github-secrets.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z5yPYivv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stephencharlesweiss.com/static/f7aa1ec8982e730c1b67b4af357de963/b9e4f/github-secrets.png" alt="github secrets"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, the secret is taken directly from Netlify as the string that follows &lt;code&gt;/build_hooks/&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;And with that, I have a new build process. Suddenly, my website builds every day at 8am which frees me to focus on the parts of writing and running this site that I enjoy and begin to automate the other stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Footnotes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;sup&gt;1&lt;/sup&gt; Though it’s scheduled at 8am, it’s important to remember that the time is local to the computer &lt;em&gt;running&lt;/em&gt; the command. In this case, that means wherever the Netlify servers are.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Additional resources that I found helpful include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.voorhoede.nl/en/blog/scheduling-netlify-deploys-with-github-actions/"&gt;Scheduling Netlify Deploys With Github Actions | Voorhoede&lt;/a&gt; - This was a great tutorial that proved a great starting point to understanding these actions.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/about-github-actions"&gt;About GitHub Actions - GitHub Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/categories/automating-your-workflow-with-github-actions"&gt;Automating your workflow with GitHub Actions - GitHub Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://help.github.com/en/articles/events-that-trigger-workflows"&gt;Events that trigger workflows - GitHub Help&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.netlify.com/blog/2018/11/07/automate-your-netlify-sites-with-zapier/"&gt;Automate your Netlify sites with Zapier | Netlify&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cron</category>
      <category>githubactions</category>
    </item>
  </channel>
</rss>
